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

Last change on this file since 4110 was 4110, checked in by jbclement, 4 days ago

PEM:

  • Introduction of a configurable display/logging system with options 'out2term', 'out2log', 'verbosity_lvl'. All messages now use verbosity levels ('LVL_NFO', 'LVL_WRN', 'LVL_ERR' and 'LVL_DBG').
  • Code encapsulation improvements with systematic privacy/protection of module variables.
  • Addition of workflow safety checks for required executables, dependencies (e.g. 'ncdump'), input files and callphys keys.
  • Renaming of PEM starting and diagnostic files ("startevol.nc" into "startevo.nc", "diagevol.nc" into "diagevo.nc").

JBC

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