source: trunk/LMDZ.COMMON/libf/evolution/config.F90 @ 4134

Last change on this file since 4134 was 4134, checked in by jbclement, 9 days ago

PEM:

  • Add a periodic backup based on a single wrapper which builds PCM-compatible climate state and writes "restart" files.
  • Remove condition "if (.not. allocated(*))" for more strict safeguard.

JBC

File size: 15.0 KB
Line 
1MODULE config
2!-----------------------------------------------------------------------
3! NAME
4!     config
5!
6! DESCRIPTION
7!     Read and apply parameters for a PEM run from run_pem.def.
8!
9! AUTHORS & DATE
10!     R. Vandemeulebrouck
11!     JB Clement, 2023-2025
12!
13! NOTES
14!
15!-----------------------------------------------------------------------
16
17! DEPENDENCIES
18! ------------
19use numerics, only: dp, di, k4, minieps
20
21! DECLARATION
22! -----------
23implicit none
24
25character(7),  parameter, private :: rundef_name = 'run.def'
26character(11), parameter, private :: runPCMdef_name = 'run_pcm.def'
27character(12), parameter          :: callphys_name = 'callphys.def'
28
29contains
30!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
31
32!=======================================================================
33SUBROUTINE read_rundef()
34!-----------------------------------------------------------------------
35! NAME
36!     read_rundef
37!
38! DESCRIPTION
39!     Read PEM runtime configuration from getin keys, then set
40!     module-scoped parameters accordingly.
41!
42! AUTHORS & DATE
43!     R. Vandemeulebrouck
44!     JB Clement, 2023-2025
45!
46! NOTES
47!
48!-----------------------------------------------------------------------
49
50! DEPENDENCIES
51! ------------
52#ifdef CPP_IOIPSL
53use IOIPSL,           only: getin
54#else
55! If not using IOIPSL, we still need to use (a local version of) getin
56use ioipsl_getincom,  only: getin
57#endif
58use evolution,        only: set_evolution_config
59use backup,           only: set_backup_config
60use stopping_crit,    only: set_stopping_crit_config
61use soil,             only: set_soil_config
62use sorption,         only: set_sorption_config
63use glaciers,         only: set_glaciers_config
64use surf_ice,         only: set_surf_ice_config
65use ice_table,        only: set_ice_table_config
66use layered_deposits, only: set_layered_deposits_config
67use output,           only: set_output_config
68use orbit,            only: set_orbit_config
69use atmosphere,       only: set_atmosphere_config
70use stoppage,         only: stop_clean
71use display,          only: print_msg, LVL_NFO
72
73! DECLARATION
74! -----------
75implicit none
76
77! LOCAL VARIABLES
78! ---------------
79logical(k4) :: here, evo_orbit_l, evo_obl_l, evo_ecc_l, evo_lsp_l, do_soil_l, reg_thprop_dependp_l, do_sorption_l, hybrid
80logical(k4) :: icetable_equilibrium_l, icetable_dynamic_l, h2oice_flow_l, co2ice_flow_l, do_layering_l, impose_dust_ratio_l
81integer(di) :: output_rate_l, backup_rate_l
82integer(di) :: pem_ini_earth_date ! Initial year (in Earth years) of the PEM workflow defined in "run.def"
83real(dp)    :: dt_l, nmax_yr_run_l, h2oice_crit_l, co2ice_crit_l, ps_crit_l, max_change_obl_l, max_change_ecc_l, max_change_lsp_l
84real(dp)    :: flux_geo_l, depth_breccia_l, depth_bedrock_l, threshold_h2oice_cap_l, h2oice_huge_ini_l, d_dust_l, dust2ice_ratio_l
85
86! CODE
87! ----
88inquire(file = rundef_name,exist = here)
89if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//rundef_name//'" (PEM)!',1)
90call print_msg('> Reading "'//rundef_name//'"',LVL_NFO)
91
92! Outputs
93! ~~~~~~~
94output_rate_l = 1_di ! Default value: every year
95call getin('output_rate',output_rate_l)
96
97! Orbital parameters
98! ~~~~~~~~~~~~~~~~~~
99evo_orbit_l = .false.
100call getin('evo_orbit',evo_orbit_l)
101
102pem_ini_earth_date = 0_di
103call getin('pem_ini_earth_date',pem_ini_earth_date)
104
105evo_obl_l = .true.
106call getin('evo_obl',evo_obl_l)
107
108evo_ecc_l = .true.
109call getin('evo_ecc',evo_ecc_l)
110
111evo_lsp_l = .true.
112call getin('evo_lsp',evo_lsp_l)
113
114dt_l = 1._dp
115call getin('dt',dt_l)
116
117backup_rate_l = 0_di
118call getin('backup_rate',backup_rate_l)
119
120! Stopping criteria
121! ~~~~~~~~~~~~~~~~~
122nmax_yr_run_l = 100000000._dp
123call getin('nmax_yr_run',nmax_yr_run_l)
124
125h2oice_crit_l = 0.2_dp
126call getin('h2oice_crit',h2oice_crit_l)
127
128co2ice_crit_l = 0.2_dp
129call getin('co2ice_crit',co2ice_crit_l)
130
131ps_crit_l = 0.15_dp
132call getin('ps_crit',ps_crit_l)
133
134max_change_obl_l = 1._dp
135call getin('max_change_obl',max_change_obl_l)
136
137max_change_ecc_l = 5.e-3_dp
138call getin('max_change_ecc',max_change_ecc_l)
139
140max_change_lsp_l = 20._dp
141call getin('max_change_lsp',max_change_lsp_l)
142
143! Subsurface
144! ~~~~~~~~~~
145do_soil_l = .true.
146call getin('do_soil',do_soil_l)
147
148do_sorption_l = .false.
149call getin('do_sorption',do_sorption_l)
150
151reg_thprop_dependp_l = .false.
152call getin('reg_thprop_dependp',reg_thprop_dependp_l)
153
154flux_geo_l = 0._dp
155call getin('flux_geo',flux_geo_l)
156
157depth_breccia_l = 10._dp
158call getin('depth_breccia',depth_breccia_l)
159
160depth_bedrock_l = 1000._dp
161call getin('depth_bedrock',depth_bedrock_l)
162
163icetable_equilibrium_l = .true.
164call getin('icetable_equilibrium',icetable_equilibrium_l)
165
166icetable_dynamic_l = .false.
167call getin('icetable_dynamic',icetable_dynamic_l)
168
169! Ice management
170! ~~~~~~~~~~~~~~
171h2oice_huge_ini_l = 9200._dp ! [kg/m^2]; Default = 10 m
172call getin('h2oice_huge_ini',h2oice_huge_ini_l)
173
174threshold_h2oice_cap_l = 460._dp ! kg.m-2 (= 0.5 m)
175call getin('threshold_h2oice_cap',threshold_h2oice_cap_l)
176
177h2oice_flow_l = .true.
178call getin('h2oice_flow',h2oice_flow_l)
179
180co2ice_flow_l = .true.
181call getin('co2ice_flow',co2ice_flow_l)
182
183! Layering
184! ~~~~~~~~
185do_layering_l = .false.
186call getin('do_layering',do_layering_l)
187
188d_dust_l = 5.78e-2_dp ! kg.m-2.y-1 (= 1.e-9 kg.m-2.s-1)
189call getin('d_dust',d_dust_l)
190
191impose_dust_ratio_l = .false.
192call getin('impose_dust_ratio',impose_dust_ratio_l)
193
194dust2ice_ratio_l = 0.01_dp
195call getin('dust2ice_ratio',dust2ice_ratio_l)
196
197! Setters
198call set_output_config(output_rate_l)
199call set_orbit_config(evo_orbit_l,evo_obl_l,evo_ecc_l,evo_lsp_l,max_change_obl_l,max_change_ecc_l,max_change_lsp_l)
200call set_evolution_config(pem_ini_earth_date,dt_l,nmax_yr_run_l)
201call set_backup_config(backup_rate_l)
202call set_stopping_crit_config(h2oice_crit_l,co2ice_crit_l,ps_crit_l)
203call set_soil_config(do_soil_l,reg_thprop_dependp_l,flux_geo_l,depth_breccia_l,depth_bedrock_l)
204call set_sorption_config(do_sorption_l)
205call set_ice_table_config(icetable_equilibrium_l,icetable_dynamic_l)
206call set_surf_ice_config(threshold_h2oice_cap_l,h2oice_huge_ini_l)
207call set_glaciers_config(h2oice_flow_l,co2ice_flow_l)
208call set_layered_deposits_config(do_layering_l,impose_dust_ratio_l,d_dust_l,dust2ice_ratio_l)
209
210! Read "run_pcm.def" parameters
211hybrid = .true. ! Default
212call get_hybrid(hybrid)
213call set_atmosphere_config(hybrid)
214
215! Read the "callphys.def"
216call read_callphys() ! To get 'CO2cond_ps'
217
218! Check incompatibilities
219call check_config_incompatibility()
220
221END SUBROUTINE read_rundef
222!=======================================================================
223
224!=======================================================================
225SUBROUTINE check_config_incompatibility()
226!-----------------------------------------------------------------------
227! NAME
228!     check_config_incompatibility
229!
230! DESCRIPTION
231!     Check incompatibilities in the PEM runtime configuration.
232!
233! AUTHORS & DATE
234!     JB Clement, 02/2026
235!
236! NOTES
237!
238!-----------------------------------------------------------------------
239
240! DEPENDENCIES
241! ------------
242use stoppage,  only: stop_clean
243use soil,      only: do_soil, reg_thprop_dependp, flux_geo
244use sorption,  only: do_sorption
245use orbit,     only: evo_orbit
246use evolution, only: pem_ini_date
247use ice_table, only: icetable_equilibrium, icetable_dynamic
248use display,   only: print_msg, LVL_WRN
249
250! DECLARATION
251! -----------
252implicit none
253
254! CODE
255! ----
256! Warnings (possible incompatibilities)
257if (evo_orbit .and. abs(pem_ini_date) < minieps) call print_msg('''evo_orbit = .true.'' but the initial date of the PEM is set to 0!',LVL_WRN)
258
259! Errors (true incompatibilities)
260if (.not. do_soil) then
261    if (icetable_equilibrium .or. icetable_dynamic) call stop_clean(__FILE__,__LINE__,'ice table must be used when do_soil = true!',1)
262    if (abs(flux_geo) > minieps) call stop_clean(__FILE__,__LINE__,'soil is not activated but flux_geo /= 0!',1)
263    if (reg_thprop_dependp) call stop_clean(__FILE__,__LINE__,'regolith properties vary according to Ps only when soil = true!',1)
264    if (do_sorption) call stop_clean(__FILE__,__LINE__,'do_soil must be true when do_sorption = true!',1)
265end if
266
267END SUBROUTINE check_config_incompatibility
268!=======================================================================
269
270!=======================================================================
271SUBROUTINE read_callphys()
272!-----------------------------------------------------------------------
273! NAME
274!     read_callphys
275!
276! DESCRIPTION
277!     Read physics runtime configuration from getin keys, then set
278!     module-scoped parameters accordingly.
279!
280! AUTHORS & DATE
281!     JB Clement, 01/2026
282!
283! NOTES
284!     To work, it needs that "run_pem.def" hols a line with
285!     "INCLUDEDEF=callphys.def".
286!-----------------------------------------------------------------------
287
288! DEPENDENCIES
289! ------------
290#ifdef CPP_IOIPSL
291use IOIPSL,          only: getin
292#else
293! If not using IOIPSL, we still need to use (a local version of) getin
294use ioipsl_getincom, only: getin
295#endif
296use stoppage,        only: stop_clean
297use display,         only: print_msg, LVL_NFO
298use atmosphere,      only: set_CO2cond_ps_PCM
299
300! DECLARATION
301! -----------
302implicit none
303
304! LOCAL VARIABLES
305! ---------------
306logical(k4) :: here
307real(dp)    :: CO2cond_ps_PCM_l
308
309! CODE
310! ----
311inquire(file = callphys_name,exist = here)
312if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//callphys_name//'"!',1)
313call print_msg('> Reading "'//callphys_name//'"',LVL_NFO)
314
315CO2cond_ps_PCM_l = 1._dp
316call getin("CO2cond_ps",CO2cond_ps_PCM_l)
317call set_CO2cond_ps_PCM(CO2cond_ps_PCM_l)
318
319END SUBROUTINE read_callphys
320!=======================================================================
321
322!=======================================================================
323SUBROUTINE get_hybrid(hybrid)
324!-----------------------------------------------------------------------
325! NAME
326!     get_hybrid
327!
328! DESCRIPTION
329!     Get the key definition in "run_pcm.def".
330!
331! AUTHORS & DATE
332!     JB Clement, 12/2025
333!
334! NOTES
335!
336!-----------------------------------------------------------------------
337
338! DEPENDENCIES
339! ------------
340use stoppage, only: stop_clean
341use display,  only: print_msg, LVL_NFO, LVL_WRN
342use utility,  only: bool2str
343
344! DECLARATION
345! -----------
346implicit none
347
348! ARGUMENTS
349! ---------
350logical(k4), intent(inout) :: hybrid
351
352! LOCAL VARIABLES
353! ---------------
354integer(di)    :: ierr, funit, eq_pos
355logical(k4)    :: here, found, hybrid_in
356character(256) :: line
357character(128) :: key, res
358
359! CODE
360! ----
361inquire(file = runPCMdef_name,exist = here)
362if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//runPCMdef_name//'"!',1)
363call print_msg('> Reading "'//runPCMdef_name//'"',LVL_NFO)
364open(newunit = funit,file = runPCMdef_name,status = 'old',form = 'formatted',action = 'read',iostat = ierr)
365if (ierr /= 0) call stop_clean(__FILE__,__LINE__,'error opening file "'//runPCMdef_name//'"!',ierr)
366
367found = .false.
368hybrid_in = hybrid
369do
370    ! Read the line
371    read(funit,'(a)',iostat = ierr) line
372    if (ierr /= 0) exit
373
374    ! Skip empty lines and comments
375    if (trim(line) == '') cycle
376    if (line(1:1) == '#' .or. line(1:1) == '!') cycle
377
378    ! Get the position of equal sign
379    eq_pos = index(line,'=')
380    if (eq_pos == 0) cycle
381
382    ! Get the key and its value/result
383    key = adjustl(trim(line(:eq_pos - 1)))
384    res = adjustl(trim(line(eq_pos + 1:)))
385
386    ! Check the key
387    if (trim(key) == 'hybrid') then
388        read(res,*,iostat = ierr) hybrid
389        if (ierr == 0) found = .true.
390        exit
391    end if
392end do
393
394close(funit)
395
396if (.not. found) call print_msg('Key ''hybrid'' not found in the file "'//runPCMdef_name//'"!',LVL_WRN)
397if (hybrid .eqv. hybrid_in) call print_msg('USING DEFAULTS : hybrid = '//bool2str(hybrid_in),LVL_NFO)
398
399END SUBROUTINE get_hybrid
400!=======================================================================
401
402!=======================================================================
403SUBROUTINE read_control_data()
404!-----------------------------------------------------------------------
405! NAME
406!     read_control_data
407!
408! DESCRIPTION
409!     Read 'controle' data in "startfi.nc".
410!
411! AUTHORS & DATE
412!     JB Clement, 01/2026
413!
414! NOTES
415!
416!-----------------------------------------------------------------------
417
418! DEPENDENCIES
419! ------------
420use io_netcdf, only: open_nc, close_nc, startfi_name, get_dim_nc, get_var_nc
421use physics,   only: init_physics
422use orbit,     only: init_orbit
423use soil,      only: volcapa
424use stoppage,  only: stop_clean
425use display,   only: print_msg, LVL_NFO
426
427! DECLARATION
428! -----------
429implicit none
430
431! LOCAL VARIABLES
432! ---------------
433integer(di)                         :: nindex ! Size of dimension 'index'
434real(dp), dimension(:), allocatable :: controle
435
436! CODE
437! ----
438call print_msg('> Reading control data ("'//startfi_name//'")',LVL_NFO)
439! Open the "startfi.nc" file
440call open_nc(startfi_name,'read')
441
442! Get the dimension size of 'index'
443call get_dim_nc('index',nindex)
444
445! Get 'controle'
446allocate(controle(nindex))
447call get_var_nc('controle',controle)
448
449! Close the file
450call close_nc(startfi_name)
451
452! Initialize physical data
453!     Arguments order: rad, g, mugaz, rcp
454call print_msg('    > Initializing physical constants',LVL_NFO)
455call init_physics(controle(5),controle(7),controle(8),controle(9))
456
457! Initialize soil data
458call print_msg('    > Initializing soil parameters',LVL_NFO)
459volcapa = controle(35)
460if (abs(volcapa) < minieps) call stop_clean(__FILE__,__LINE__,'volcapa is 0 in "'//startfi_name//'"!',1)
461
462! Initialize orbital data
463!     Arguments order: Obliquity, Perihelion, Aphelion, Date of perihelion, Year length, Sol length
464call print_msg('    > Initializing orbital characteristics of the planet',LVL_NFO)
465call init_orbit(controle(18),controle(15),controle(16),controle(17),controle(14),controle(10))
466
467deallocate(controle)
468
469END SUBROUTINE read_control_data
470!=======================================================================
471
472!=======================================================================
473SUBROUTINE read_display_config()
474!-----------------------------------------------------------------------
475! NAME
476!     read_display_config
477!
478! DESCRIPTION
479!     Read PEM runtime configuration for display from getin keys, then
480!     set module-scoped parameters accordingly.
481!
482! AUTHORS & DATE
483!     JB Clement, 03/2026
484!
485! NOTES
486!
487!-----------------------------------------------------------------------
488
489! DEPENDENCIES
490! ------------
491#ifdef CPP_IOIPSL
492use IOIPSL,           only: getin
493#else
494! If not using IOIPSL, we still need to use (a local version of) getin
495use ioipsl_getincom,  only: getin
496#endif
497use stoppage,         only: stop_clean
498use display,          only: set_display_config, LVL_NFO
499
500! DECLARATION
501! -----------
502implicit none
503
504! LOCAL VARIABLES
505! ---------------
506logical(k4) :: here, out2term_l, out2log_l
507integer(di) :: verbosity_lvl_l
508
509! CODE
510! ----
511inquire(file = rundef_name,exist = here)
512if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//rundef_name//'" (PEM)!',1)
513
514! Display
515! ~~~~~~~
516out2term_l = .true.
517call getin('out2term',out2term_l)
518
519out2log_l = .false.
520call getin('out2log',out2log_l)
521
522verbosity_lvl_l = LVL_NFO
523call getin('verbosity_lvl',verbosity_lvl_l)
524
525! Setter
526call set_display_config(out2term_l,out2log_l,verbosity_lvl_l)
527
528END SUBROUTINE read_display_config
529!=======================================================================
530
531END MODULE config
Note: See TracBrowser for help on using the repository browser.