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

Last change on this file was 4180, checked in by jbclement, 9 hours ago

PEM:

  • Rework layering-related logic, especially clarify interactions between surface and subsurface water tendencies and disable CO2 lag resistance (inconsistent without updating pressure and mass balance + PCM).
  • Prevent simultaneous activation of layering and ice flows.
  • Add warning when flux_geo /= 0 while soil is disabled.
  • Add new utility function "is_lvl_enabled" for displaying.
  • Replace deprecated 'minieps' with 'eps'/'tol'.

JBC

File size: 15.4 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, eps
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/m2 (= 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/m2/y (= 1.e-9 kg/m2/s)
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 glaciers,         only: h2oice_flow, co2ice_flow
249use layered_deposits, only: do_layering
250use display,          only: print_msg, LVL_WRN
251
252! DECLARATION
253! -----------
254implicit none
255
256! CODE
257! ----
258! Warnings (possible incompatibilities)
259if (evo_orbit .and. abs(pem_ini_date) < eps) call print_msg('''evo_orbit = .true.'' but the initial date of the PEM is set to 0!',LVL_WRN)
260if (abs(flux_geo) > eps .and. .not. do_soil) call print_msg('soil is not activated but flux_geo /= 0!',LVL_WRN)
261
262! Errors (true incompatibilities)
263if (.not. do_soil) then
264    if (icetable_equilibrium .or. icetable_dynamic) call stop_clean(__FILE__,__LINE__,'ice table must be used when do_soil = true!',1)
265    if (reg_thprop_dependp) call stop_clean(__FILE__,__LINE__,'regolith properties vary according to Ps only when soil = true!',1)
266    if (do_sorption) call stop_clean(__FILE__,__LINE__,'do_soil must be true when do_sorption = true!',1)
267end if
268if (do_layering .and. h2oice_flow) call stop_clean(__FILE__,__LINE__,'layering and H2O ice flow cannot be activated at the same time!',1)
269if (do_layering .and. co2ice_flow) call stop_clean(__FILE__,__LINE__,'layering and CO2 ice flow cannot be activated at the same time!',1)
270
271END SUBROUTINE check_config_incompatibility
272!=======================================================================
273
274!=======================================================================
275SUBROUTINE read_callphys()
276!-----------------------------------------------------------------------
277! NAME
278!     read_callphys
279!
280! DESCRIPTION
281!     Read physics runtime configuration from getin keys, then set
282!     module-scoped parameters accordingly.
283!
284! AUTHORS & DATE
285!     JB Clement, 01/2026
286!
287! NOTES
288!     To work, it needs that "run_pem.def" hols a line with
289!     "INCLUDEDEF=callphys.def".
290!-----------------------------------------------------------------------
291
292! DEPENDENCIES
293! ------------
294#ifdef CPP_IOIPSL
295use IOIPSL,          only: getin
296#else
297! If not using IOIPSL, we still need to use (a local version of) getin
298use ioipsl_getincom, only: getin
299#endif
300use stoppage,        only: stop_clean
301use display,         only: print_msg, LVL_NFO
302use atmosphere,      only: set_CO2cond_ps_PCM
303
304! DECLARATION
305! -----------
306implicit none
307
308! LOCAL VARIABLES
309! ---------------
310logical(k4) :: here
311real(dp)    :: CO2cond_ps_PCM_l
312
313! CODE
314! ----
315inquire(file = callphys_name,exist = here)
316if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//callphys_name//'"!',1)
317call print_msg('> Reading "'//callphys_name//'"',LVL_NFO)
318
319CO2cond_ps_PCM_l = 1._dp
320call getin("CO2cond_ps",CO2cond_ps_PCM_l)
321call set_CO2cond_ps_PCM(CO2cond_ps_PCM_l)
322
323END SUBROUTINE read_callphys
324!=======================================================================
325
326!=======================================================================
327SUBROUTINE get_hybrid(hybrid)
328!-----------------------------------------------------------------------
329! NAME
330!     get_hybrid
331!
332! DESCRIPTION
333!     Get the key definition in "run_pcm.def".
334!
335! AUTHORS & DATE
336!     JB Clement, 12/2025
337!
338! NOTES
339!
340!-----------------------------------------------------------------------
341
342! DEPENDENCIES
343! ------------
344use stoppage, only: stop_clean
345use display,  only: print_msg, LVL_NFO, LVL_WRN
346use utility,  only: bool2str
347
348! DECLARATION
349! -----------
350implicit none
351
352! ARGUMENTS
353! ---------
354logical(k4), intent(inout) :: hybrid
355
356! LOCAL VARIABLES
357! ---------------
358integer(di)    :: ierr, funit, eq_pos
359logical(k4)    :: here, found, hybrid_in
360character(256) :: line
361character(128) :: key, res
362
363! CODE
364! ----
365inquire(file = runPCMdef_name,exist = here)
366if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//runPCMdef_name//'"!',1)
367call print_msg('> Reading "'//runPCMdef_name//'"',LVL_NFO)
368open(newunit = funit,file = runPCMdef_name,status = 'old',form = 'formatted',action = 'read',iostat = ierr)
369if (ierr /= 0) call stop_clean(__FILE__,__LINE__,'error opening file "'//runPCMdef_name//'"!',ierr)
370
371found = .false.
372hybrid_in = hybrid
373do
374    ! Read the line
375    read(funit,'(a)',iostat = ierr) line
376    if (ierr /= 0) exit
377
378    ! Skip empty lines and comments
379    if (trim(line) == '') cycle
380    if (line(1:1) == '#' .or. line(1:1) == '!') cycle
381
382    ! Get the position of equal sign
383    eq_pos = index(line,'=')
384    if (eq_pos == 0) cycle
385
386    ! Get the key and its value/result
387    key = adjustl(trim(line(:eq_pos - 1)))
388    res = adjustl(trim(line(eq_pos + 1:)))
389
390    ! Check the key
391    if (trim(key) == 'hybrid') then
392        read(res,*,iostat = ierr) hybrid
393        if (ierr == 0) found = .true.
394        exit
395    end if
396end do
397
398close(funit)
399
400if (.not. found) call print_msg('Key ''hybrid'' not found in the file "'//runPCMdef_name//'"!',LVL_WRN)
401if (hybrid .eqv. hybrid_in) call print_msg('USING DEFAULTS : hybrid = '//bool2str(hybrid_in),LVL_NFO)
402
403END SUBROUTINE get_hybrid
404!=======================================================================
405
406!=======================================================================
407SUBROUTINE read_control_data()
408!-----------------------------------------------------------------------
409! NAME
410!     read_control_data
411!
412! DESCRIPTION
413!     Read 'controle' data in "startfi.nc".
414!
415! AUTHORS & DATE
416!     JB Clement, 01/2026
417!
418! NOTES
419!
420!-----------------------------------------------------------------------
421
422! DEPENDENCIES
423! ------------
424use io_netcdf, only: open_nc, close_nc, startfi_name, get_dim_nc, get_var_nc
425use physics,   only: init_physics
426use orbit,     only: init_orbit
427use soil,      only: volcapa
428use stoppage,  only: stop_clean
429use display,   only: print_msg, LVL_NFO
430
431! DECLARATION
432! -----------
433implicit none
434
435! LOCAL VARIABLES
436! ---------------
437integer(di)                         :: nindex ! Size of dimension 'index'
438real(dp), dimension(:), allocatable :: controle
439
440! CODE
441! ----
442call print_msg('> Reading control data ("'//startfi_name//'")',LVL_NFO)
443! Open the "startfi.nc" file
444call open_nc(startfi_name,'read')
445
446! Get the dimension size of 'index'
447call get_dim_nc('index',nindex)
448
449! Get 'controle'
450allocate(controle(nindex))
451call get_var_nc('controle',controle)
452
453! Close the file
454call close_nc(startfi_name)
455
456! Initialize physical data
457!     Arguments order: rad, g, mugaz, rcp
458call print_msg('> Initializing physical constants',LVL_NFO)
459call init_physics(controle(5),controle(7),controle(8),controle(9))
460
461! Initialize soil data
462call print_msg('> Initializing soil parameters',LVL_NFO)
463volcapa = controle(35)
464if (abs(volcapa) < eps) call stop_clean(__FILE__,__LINE__,'volcapa is 0 in "'//startfi_name//'"!',1)
465
466! Initialize orbital data
467!     Arguments order: Obliquity, Perihelion, Aphelion, Date of perihelion, Year length, Sol length
468call print_msg('> Initializing orbital characteristics of the planet',LVL_NFO)
469call init_orbit(controle(18),controle(15),controle(16),controle(17),controle(14),controle(10))
470
471deallocate(controle)
472
473END SUBROUTINE read_control_data
474!=======================================================================
475
476!=======================================================================
477SUBROUTINE read_display_config()
478!-----------------------------------------------------------------------
479! NAME
480!     read_display_config
481!
482! DESCRIPTION
483!     Read PEM runtime configuration for display from getin keys, then
484!     set module-scoped parameters accordingly.
485!
486! AUTHORS & DATE
487!     JB Clement, 03/2026
488!
489! NOTES
490!
491!-----------------------------------------------------------------------
492
493! DEPENDENCIES
494! ------------
495#ifdef CPP_IOIPSL
496use IOIPSL,           only: getin
497#else
498! If not using IOIPSL, we still need to use (a local version of) getin
499use ioipsl_getincom,  only: getin
500#endif
501use stoppage,         only: stop_clean
502use display,          only: set_display_config, LVL_NFO
503
504! DECLARATION
505! -----------
506implicit none
507
508! LOCAL VARIABLES
509! ---------------
510logical(k4) :: here, out2term_l, out2log_l
511integer(di) :: verbosity_lvl_l
512
513! CODE
514! ----
515inquire(file = rundef_name,exist = here)
516if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//rundef_name//'" (PEM)!',1)
517
518! Display
519! ~~~~~~~
520out2term_l = .true.
521call getin('out2term',out2term_l)
522
523out2log_l = .false.
524call getin('out2log',out2log_l)
525
526verbosity_lvl_l = LVL_NFO
527call getin('verbosity_lvl',verbosity_lvl_l)
528
529! Setter
530call set_display_config(out2term_l,out2log_l,verbosity_lvl_l)
531
532END SUBROUTINE read_display_config
533!=======================================================================
534
535END MODULE config
Note: See TracBrowser for help on using the repository browser.