source: trunk/LMDZ.COMMON/libf/evolution/pem.F90 @ 4066

Last change on this file since 4066 was 4065, checked in by jbclement, 2 weeks ago

PEM:
Major refactor following the previous ones (r3989 and r3991) completing the large structural reorganization and cleanup of the PEM codebase. This revision introduces newly designed modules, standardizes interfaces with explicit ini/end APIs and adds native NetCDF I/O together with explicit PCM/PEM adapters. In detail:

  • Some PEM models were corrected or improved:
    • Frost/perennial ice semantics are clarified via renaming;
    • Soil temperature remapping clarified, notably by removing the rescaling of temperature deviation;
    • Geothermal flux for the PCM is computed based on the PEM state;
  • New explicit PEM/PCM adapters ("set_*"/"build4PCM_*") to decouple PEM internal representation from PCM file layouts and reconstruct consistent fields returned to the PCM;
  • New explicit build/teardown routines that centralize allocation and initialization ordering, reducing accidental use of uninitialized data and making the model lifecycle explicit;
  • Add native read/write helpers for NetCDF that centralize all low-level NetCDF interactions with major improvements (and more simplicity) compared to legacy PEM/PCM I/O (see the modules "io_netcdf" and "output"). They support reading, creation and writing of "diagevol.nc" (renamed from "diagpem.nc") and start/restart files;
  • Provide well-focused modules ("numerics"/"maths"/"utility"/"display") to host commonly-used primitives:
    • "numerics" defines numerical types and constants for reproducibility, portability across compilers and future transitions (e.g. quadruple precision experiments);
    • "display" provides a single controlled interface for runtime messages, status output and diagnostics, avoiding direct 'print'/'write' to enable silent mode, log redirection, and MPI-safe output in the future.
    • "utility" (new module) hosts generic helpers used throughout the code (e.g. "int2str" or "real2str");
  • Add modules "clim_state_init"/"clim_state_rec" which provide robust read/write logic for "start/startfi/startpem", including 1D fallbacks, mesh conversions and dimension checks. NetCDF file creation is centralized and explicit. Restart files are now self-consistent and future-proof, requiring changes only to affected variables;
  • Add module "atmosphere" which computes pressure fields, reconstructs potential temperature and air mass. It also holds the whole logic to define sigma or hybrid coordinates for altitudes;
  • Add module "geometry" to centrilize dimensions logic and grid conversions routines (including 2 new ones "dyngrd2vect"/"vect2dyngrd");
  • Add module "slopes" to isolate slopes handling;
  • Add module "surface" to isolate surface management. Notably, albedo and emissivity are now fully reconstructed following the PCM settings;
  • Add module "allocation" to check the dimension initialization and centrilize allocation/deallocation;
  • Finalize module decomposition and renaming to consolidate domain-based modules, purpose-based routines and physics/process-based variables;
  • The main program now drives a clearer sequence of conceptual steps (initialization / reading / evolution / update / build / writing) and fails explicitly instead of silently defaulting;
  • Ice table logic is made restart-safe;
  • 'Open'/'read' intrinsic logic is made safe and automatic;
  • Improve discoverability and standardize the data handling (private vs protected vs public);
  • Apply consistent documentation/header style already introduced;
  • Update deftank scripts to reflect new names and launch wrappers;

This revision is a structural milestone aiming to be behavior-preserving where possible. It has been tested via compilation and short integration runs. However, due to extensive renames, moves, and API changes, full validation is still ongoing.
Note: the revision includes one (possibly two) easter egg hidden in the code for future archaeologists of the PEM. No physics were harmed.
JBC

File size: 28.3 KB
Line 
1PROGRAM pem
2!-----------------------------------------------------------------------
3! NAME
4!     pem
5!
6! DESCRIPTION
7!     Main entry point for the Planetary Evolution Model (PEM).
8!
9! AUTHORS & DATE
10!     R. Vandemeulebrouck, 22/07/2022
11!     L. Lange, 22/07/2022
12!     JB Clement, 2023-2025
13!
14! NOTES
15!
16!-----------------------------------------------------------------------
17
18! DEPENDENCIES
19! ------------
20! Common modules
21use job_timelimit_mod, only: timelimit, antetime, timewall
22use parse_args_mod,    only: parse_args
23! PEM modules
24use allocation,         only: ini_allocation, end_allocation
25use atmosphere,         only: ps_PCM, evolve_pressure, CO2cond_ps_PCM, build4PCM_atmosphere
26use clim_state_init,    only: read_start, read_startfi, read_startpem
27use clim_state_rec,     only: write_restart, write_restartfi, write_restartpem
28use config,             only: read_rundef
29use display,            only: print_ini, print_end, print_msg
30use evolution,          only: n_yr_run, n_yr_sim, nmax_yr_sim, nmax_yr_run, dt, idt, r_plnt2earth_yr, pem_ini_date
31use geometry,           only: ngrid, nslope, nday, nsoil_PCM, nsoil, cell_area, total_surface, nlayer
32use glaciers,           only: h2oice_flow, co2ice_flow, flow_co2glaciers, flow_h2oglaciers
33use ice_table,          only: icetable_equilibrium, icetable_dynamic, icetable_depth, icetable_thickness, ice_porefilling, evolve_ice_table
34use info,               only: read_info, update_info
35use layered_deposits,   only: layering, do_layering, del_layering, evolve_layering, ptrarray, layering2surfice, surfice2layering
36use maths,              only: pi
37use numerics,           only: dp, qp, di, li, k4, minieps, minieps_qp
38use orbit,              only: evol_orbit, read_orbitpm, compute_maxyr_orbit, update_orbit
39use output,             only: write_diagevol, dim_ngrid, dim_nsoil
40use physics,            only: g
41use slopes,             only: subslope_dist, def_slope_mean
42use soil,               only: do_soil, set_soil, TI, build4PCM_soil
43use soil_temp,          only: tsoil_PCM, shift_tsoil2surf, evolve_soil_temp
44use soil_therm_inertia, only: update_soil_TI
45use sorption,           only: do_sorption, compute_totmass_adsorbed, evolve_regolith_adsorption
46use stopping_crit,      only: stopFlags, stopping_crit_pressure, stopping_crit_h2o, stopping_crit_h2oice, stopping_crit_co2ice
47use surface,            only: emissivity_PCM, build4PCM_surf_rad_prop
48use surf_ice,           only: evolve_co2ice, evolve_h2oice, balance_h2oice_reservoirs, build4PCM_perice
49use surf_temp,          only: tsurf_PCM, adapt_tsurf2disappearedice, build4PCM_tsurf
50use tendencies,         only: evolve_tend_co2, evolve_tend_h2o
51use tracers,            only: adapt_tracers2pressure, build4PCM_tracers, nq
52use utility,            only: real2str
53use xios_data,          only: load_xios_data
54
55! DECLARATION
56! -----------
57implicit none
58
59! LOCAL VARIABLES
60! ---------------
61! Utility-related:
62integer(li)               :: cr     ! Number of clock ticks per second (count rate)
63integer(li)               :: c1, c2 ! Counts of processor clock
64character(:), allocatable :: num    ! To write slope variables
65integer(di)               :: i, islope
66! Pressure-related:
67real(dp), dimension(:),   allocatable :: ps_avg          ! Average surface pressure [Pa]
68real(dp), dimension(:),   allocatable :: ps_dev          ! Deviation of surface pressure [Pa]
69real(dp), dimension(:,:), allocatable :: ps_ts           ! Surface pressure timeseries [Pa]
70real(dp)                              :: ps_avg_glob_ini ! Global average pressure at initialization [Pa]
71real(dp)                              :: ps_avg_glob_old ! Global average pressure of previous time step [Pa]
72real(dp)                              :: ps_avg_glob     ! Global average pressure of current time step [Pa]
73real(dp), dimension(:),   allocatable :: ps4PCM          ! Surface pressure reconstruction to feed back into PCM [Pa]
74real(dp), dimension(:,:), allocatable :: teta4PCM        ! Potential temperature reconstruction to feed back into PCM [K]
75real(dp), dimension(:,:), allocatable :: air_mass4PCM    ! Air mass reconstruction to feed back into PCM [kg]
76real(dp)                              :: pa4PCM          ! Transition pressure (for hybrid coord.) [Pa]
77real(dp)                              :: preff4PCM       ! Reference pressure [Pa]
78! Ice-related:
79real(dp),    dimension(:,:), allocatable :: h2o_ice                    ! H2O ice [kg.m-2]
80real(dp),    dimension(:,:), allocatable :: co2_ice                    ! CO2 ice [kg.m-2]
81real(dp)                                 :: h2oice_sublim_coverage_ini ! Initial surface area of sublimating H2O ice [m2]
82real(dp)                                 :: co2ice_sublim_coverage_ini ! Initial surface area of sublimating CO2 ice [m2]
83logical(k4), dimension(:,:), allocatable :: is_h2oice_ini              ! Initial location of H2O ice
84logical(k4), dimension(:,:), allocatable :: is_co2ice_ini              ! Initial location of CO2 ice
85logical(k4), dimension(:,:), allocatable :: is_co2ice_flow             ! Flag for location of CO2 glacier flow
86logical(k4), dimension(:,:), allocatable :: is_h2oice_flow             ! Flag for location of H2O glacier flow
87real(dp),    dimension(:,:), allocatable :: h2o_ice4PCM                ! H2O ice reconstruction to feed back into PCM [kg.m-2]
88real(dp),    dimension(:,:), allocatable :: co2_ice4PCM                ! CO2 ice reconstruction to feed back into PCM [kg.m-2]
89logical(k4), dimension(:),   allocatable :: is_h2o_perice              ! Location of H2O infinite reservoir, called 'watercaptag' in PCM
90logical(k4), dimension(:,:), allocatable :: is_co2ice_disappeared      ! Flag to check if CO2 ice disappeared at the previous timestep
91! Surface-related:
92real(dp), dimension(:,:), allocatable :: tsurf_avg           ! Average surface temperature [K]
93real(dp), dimension(:,:), allocatable :: tsurf_avg_yr1       ! Average surface temperature of the second to last PCM run [K]
94real(dp), dimension(:,:), allocatable :: tsurf_dev           ! Deviation of surface temperature [K]
95real(dp), dimension(:,:), allocatable :: h2o_surfdensity_avg ! Average water surface density [kg/m^3]
96real(dp), dimension(:,:), allocatable :: zshift_surf         ! Elevation shift for the surface [m]
97real(dp), dimension(:,:), allocatable :: zlag                ! Newly built lag thickness [m]
98real(dp), dimension(:,:), allocatable :: albedo4PCM          ! Albedo reconstruction to feed back into PCM
99real(dp), dimension(:,:), allocatable :: emissivity4PCM      ! Emissivity reconstruction to feed back into PCM
100real(dp), dimension(:,:), allocatable :: tsurf4PCM           ! Surface temperature reconstruction to feed back into PCM [K]
101! Soil-related:
102real(dp), dimension(:,:,:),   allocatable :: tsoil_avg                ! Average soil temperature [K]
103real(dp), dimension(:,:,:),   allocatable :: tsoil_dev                ! Deviation pf soil temperature [K]
104real(dp), dimension(:,:,:,:), allocatable :: tsoil_ts                 ! Soil temperature timeseries [K]
105real(dp), dimension(:,:,:,:), allocatable :: tsoil_ts_old             ! Soil temperature timeseries at the previous time step [K]
106real(dp), dimension(:,:,:),   allocatable :: h2o_soildensity_avg      ! Average of soil water soil density [kg/m^3]
107real(dp), dimension(:),       allocatable :: delta_co2_ads            ! Quantity of CO2 exchanged due to adsorption/desorption [kg/m^2]
108real(dp), dimension(:),       allocatable :: delta_h2o_ads            ! Quantity of H2O exchanged due to adsorption/desorption [kg/m^2]
109real(qp)                                  :: totmass_adsh2o           ! Total mass of H2O exchanged because of adsorption/desorption [kg]
110real(dp), dimension(:,:,:),   allocatable :: inertiesoil4PCM          ! Soil thermal inertia reconstruction to feed back into PCM [SI]
111real(dp), dimension(:,:,:),   allocatable :: tsoil4PCM                ! Average soil temperature reconstruction to feed back into PCM [K]
112real(dp), dimension(:,:),     allocatable :: flux_geo4PCM             ! Geothermal flux reconstruction to feed back into PCM [W/m2]
113real(dp), dimension(:,:,:),   allocatable :: h2o_ads_reg              ! H2O adsorbed in the regolith [kg/m^2]
114real(dp), dimension(:,:,:),   allocatable :: co2_ads_reg              ! CO2 adsorbed in the regolith [kg/m^2]
115real(dp), dimension(:,:),     allocatable :: icetable_depth_old       ! Old depth of the ice table [m]
116real(dp), dimension(:),       allocatable :: delta_icetable ! Total mass of the H2O that has sublimated / condenses from the ice table [kg]
117! Tracer-related:
118real(dp), dimension(:,:),   allocatable :: q_co2_ts     ! CO2 mass mixing ratio in the first layer [kg/kg]
119real(dp), dimension(:,:),   allocatable :: q_co2_ts_ini ! Initial CO2 mass mixing ratio in the first layer [kg/kg]
120real(dp), dimension(:,:),   allocatable :: q_h2o_ts     ! H2O mass mixing ratio in the first layer [kg/kg]
121real(dp), dimension(:,:,:), allocatable :: q4PCM        ! Tracers reconstruction to feed back into PCM [kg/kg]
122! Tendency-related:
123real(dp), dimension(:,:), allocatable :: d_co2ice     ! Tendency of perennial CO2 ice [kg/m2/y]
124real(dp), dimension(:,:), allocatable :: d_co2ice_ini ! Tendency of perennial CO2 ice at the beginning [kg/m2/y]
125real(dp), dimension(:,:), allocatable :: d_h2oice     ! Tendency of perennial H2O ice [kg/m2/y]
126real(dp), dimension(:,:), allocatable :: d_h2oice_new ! Adjusted tendency of perennial H2O ice to keep balance between donor and recipient [kg/m2/y]
127! Layering-related:
128type(layering), dimension(:,:), allocatable :: layerings_map    ! Layering for each grid point and slope
129type(ptrarray), dimension(:,:), allocatable :: current          ! Current active stratum in the layering
130real(dp),       dimension(:,:), allocatable :: h2oice_depth     ! Depth of subsurface ice layer
131real(dp),       dimension(:,:), allocatable :: h2oice_depth_old ! Old depth of subsurface ice layer
132logical(k4),    dimension(:,:), allocatable :: new_str, new_lag ! Flags for the layering algorithm
133! Evolution-related:
134real(dp)        :: nmax_yr_runorb ! Maximum number of years for the run due to orbital parameters
135type(stopFlags) :: stopcrit       ! Stopping criteria
136! Balance-related
137real(qp) :: totmass_co2ice, totmass_atmco2, totmass_adsco2             ! Current total CO2 masses (surface ice|atmospheric|adsorbed)
138real(qp) :: totmass_co2ice_ini, totmass_atmco2_ini, totmass_adsco2_ini ! Initial total CO2 masses (surface ice|atmospheric|adsorbed)
139real(qp) :: totmass_ini                                                ! Initial total CO2 mass [kg]
140real(qp) :: S_atm_2_h2o, S_h2o_2_atm, S_atm_2_h2oice, S_h2oice_2_atm   ! Variables to balance H2O ice reservoirs
141
142! CODE
143! ----
144! Pre-processing step
145!~~~~~~~~~~~~~~~~~~~~
146! Elapsed time with system clock
147call system_clock(count_rate = cr)
148call system_clock(c1)
149
150! Parse command-line options
151call parse_args()
152
153! Initialization
154! ~~~~~~~~~~~~~~
155! Header
156call print_ini()
157
158! Allocate module arrays
159call ini_allocation()
160
161! Read the duration information of the simulation
162call read_info()
163
164! Read the PEM parameters
165call read_rundef()
166
167! Read the orbital parameters
168call read_orbitpm(n_yr_sim)
169
170! Read the "start.nc"
171call read_start()
172
173! Read the "startfi.nc"
174call read_startfi()
175
176! Read the PCM data given by XIOS
177allocate(ps_avg(ngrid),ps_ts(ngrid,nday))
178allocate(tsurf_avg(ngrid,nslope),tsurf_avg_yr1(ngrid,nslope),h2o_surfdensity_avg(ngrid,nslope))
179allocate(tsoil_avg(ngrid,nsoil,nslope),tsoil_ts(ngrid,nsoil,nslope,nday),h2o_soildensity_avg(ngrid,nsoil,nslope))
180allocate(q_h2o_ts(ngrid,nday),q_co2_ts(ngrid,nday))
181allocate(d_h2oice(ngrid,nslope),d_co2ice(ngrid,nslope))
182
183call load_xios_data(ps_avg,ps_ts,tsurf_avg,tsurf_avg_yr1,tsoil_avg,tsoil_ts,h2o_surfdensity_avg,h2o_soildensity_avg, &
184                    q_h2o_ts,q_co2_ts,d_h2oice,d_co2ice)
185
186! Initiate soil settings and TI
187if (do_soil) call set_soil(TI)
188
189! Compute the deviation from the average
190allocate(ps_dev(ngrid),tsurf_dev(ngrid,nslope),tsoil_dev(ngrid,nsoil_PCM,nslope))
191ps_dev(:) = ps_PCM(:) - ps_avg(:)
192tsurf_dev(:,:) = tsurf_PCM(:,:) - tsurf_avg(:,:)
193tsoil_dev(:,:,:) = tsoil_PCM(:,:,:) - tsoil_avg(:,1:nsoil_PCM,:)
194
195! Compute global surface pressure
196ps_avg_glob = sum(cell_area*ps_avg)/total_surface
197
198! Compute the accepted maximum number of years due to orbital parameters (if needed)
199call compute_maxyr_orbit(n_yr_sim,nmax_yr_runorb)
200
201! Read the "startpem.nc"
202allocate(h2o_ice(ngrid,nslope),co2_ice(ngrid,nslope))
203allocate(h2o_ads_reg(ngrid,nsoil,nslope),co2_ads_reg(ngrid,nsoil,nslope),delta_h2o_ads(ngrid),delta_co2_ads(ngrid))
204allocate(layerings_map(ngrid,nslope))
205call read_startpem(tsurf_avg_yr1,tsurf_avg,ps_avg_glob_ini,ps_ts,q_co2_ts,q_h2o_ts,h2o_surfdensity_avg,d_h2oice,d_co2ice,h2o_ice,co2_ice, &
206                   tsoil_avg,h2o_soildensity_avg,icetable_depth,icetable_thickness,ice_porefilling,layerings_map,                         &
207                   h2o_ads_reg,co2_ads_reg,delta_h2o_ads,delta_co2_ads)
208deallocate(tsurf_avg_yr1)
209
210! Save initial set-up useful for the next computations
211call print_msg('> Saving some initial climate state variables')
212allocate(d_co2ice_ini(ngrid,nslope),q_co2_ts_ini(ngrid,nday))
213allocate(is_h2oice_ini(ngrid,nslope),is_co2ice_ini(ngrid,nslope))
214ps_avg_glob_ini = ps_avg_glob
215d_co2ice_ini(:,:) = d_co2ice(:,:)
216q_co2_ts_ini(:,:) = q_co2_ts(:,:)
217h2oice_sublim_coverage_ini = 0._dp
218co2ice_sublim_coverage_ini = 0._dp
219is_h2oice_ini(:,:) = .false.
220is_co2ice_ini(:,:) = .false.
221totmass_co2ice_ini = 0._qp
222totmass_atmco2_ini = 0._qp
223totmass_adsco2_ini = 0._qp
224totmass_adsh2o = 0._qp
225do i = 1,ngrid
226    totmass_atmco2_ini = totmass_atmco2_ini + cell_area(i)*ps_avg(i)/g
227    do islope = 1,nslope
228        totmass_co2ice_ini = totmass_co2ice_ini + co2_ice(i,islope)*cell_area(i)*subslope_dist(i,islope)/cos(pi*def_slope_mean(islope)/180._dp)
229        if (co2_ice(i,islope) > 0._dp) then
230            is_co2ice_ini(i,islope) = .true.
231            if (d_co2ice(i,islope) < 0._dp) co2ice_sublim_coverage_ini = co2ice_sublim_coverage_ini + cell_area(i)*subslope_dist(i,islope)/cos(pi*def_slope_mean(islope)/180._dp)
232        end if
233        if (h2o_ice(i,islope) > 0._dp) then
234            is_h2oice_ini(i,islope) = .true.
235            if (d_co2ice(i,islope) < 0._dp) h2oice_sublim_coverage_ini = h2oice_sublim_coverage_ini + cell_area(i)*subslope_dist(i,islope)/cos(pi*def_slope_mean(islope)/180._dp)
236        end if
237    end do
238end do
239call print_msg("Initial global average pressure [Pa] = "//real2str(ps_avg_glob_ini))
240call print_msg("Initial surface area of sublimating CO2 ice [m2] = "//real2str(co2ice_sublim_coverage_ini))
241call print_msg("Initial surface area of sublimating H2O ice [m2] = "//real2str(h2oice_sublim_coverage_ini))
242if (do_sorption) call compute_totmass_adsorbed(h2o_ads_reg,co2_ads_reg,totmass_adsco2_ini,totmass_adsh2o)
243
244! Main evolution loop
245! ~~~~~~~~~~~~~~~~~~~
246call print_msg('')
247call print_msg('********* Evolution *********')
248if (do_layering) then
249    allocate(h2oice_depth(ngrid,nslope),h2oice_depth_old(ngrid,nslope),new_str(ngrid,nslope),new_lag(ngrid,nslope),current(ngrid,nslope))
250    new_str = .true.
251    new_lag = .true.
252    do islope = 1,nslope
253        do i = 1,ngrid
254            current(i,islope)%p => layerings_map(i,islope)%top
255        end do
256    end do
257    ! Conversion to surface ice
258    call layering2surfice(layerings_map,h2o_ice,co2_ice,h2oice_depth)
259    ! We put the sublimating tendency coming from subsurface ice into the overall tendency
260    !where (h2oice_depth > 0. .and. zdqsdif_ssi_tot < -minieps) d_h2oice = zdqsdif_ssi_tot
261end if
262if (nslope == 1) then ! No slope
263    allocate(character(0) :: num)
264else ! Using slopes
265    allocate(character(8) :: num)
266end if
267allocate(delta_icetable(ngrid),icetable_depth_old(ngrid,nslope),is_co2ice_disappeared(ngrid,nslope))
268is_co2ice_disappeared(:,:) = .false.
269delta_icetable(:) = 0._dp
270n_yr_run = 0
271idt = 0
272do while (n_yr_run < min(nmax_yr_runorb,nmax_yr_run) .and. n_yr_sim < nmax_yr_sim)
273    call print_msg('**** Iteration of the PEM leg (Planetary years): '//real2str(n_yr_run + dt))
274    ! Evolve global surface pressure
275    call evolve_pressure(d_co2ice,delta_co2_ads,do_sorption,ps_avg_glob_old,ps_avg_glob,ps_avg)
276
277    ! Adapt tracers according to global surface pressure
278    call adapt_tracers2pressure(ps_avg_glob_old,ps_avg_glob,ps_ts,q_h2o_ts,q_co2_ts)
279
280    ! Evolve surface ice
281    allocate(zshift_surf(ngrid,nslope),zlag(ngrid,nslope))
282    if (do_layering) then
283        h2oice_depth_old(:,:) = h2oice_depth(:,:)
284        do islope = 1,nslope
285            do i = 1,ngrid
286                call evolve_layering(layerings_map(i,islope),d_co2ice(i,islope),d_h2oice_new(i,islope),new_str(i,islope),zshift_surf(i,islope),new_lag(i,islope),zlag(i,islope),current(i,islope)%p)
287                !call print_layering(layerings_map(i,islope))
288            end do
289        end do
290        ! Conversion to surface ice
291        call layering2surfice(layerings_map,h2o_ice,co2_ice,h2oice_depth)
292
293    else
294        zlag(:,:) = 0._dp
295        call evolve_h2oice(delta_h2o_ads,delta_icetable,h2o_ice,d_h2oice,zshift_surf,stopcrit)
296        call evolve_co2ice(co2_ice,d_co2ice,zshift_surf)
297    end if
298
299    if (do_layering) then
300        allocate(d_h2oice_new(ngrid,nslope))
301        call stopping_crit_h2o(delta_h2o_ads,delta_icetable,h2o_ice,d_h2oice,S_atm_2_h2o,S_h2o_2_atm,S_atm_2_h2oice,S_h2oice_2_atm,stopcrit)
302        call balance_h2oice_reservoirs(S_atm_2_h2o,S_h2o_2_atm,S_atm_2_h2oice,S_h2oice_2_atm,h2o_ice,d_h2oice,d_h2oice_new)
303        deallocate(d_h2oice_new)
304    end if
305
306    ! Flow glaciers according to surface ice
307    if (co2ice_flow) then
308        allocate(is_co2ice_flow(ngrid,nslope))
309        call flow_co2glaciers(q_co2_ts,ps_ts,ps_avg_glob_old,ps_avg_glob,co2_ice,is_co2ice_flow)
310    end if
311    if (h2oice_flow) then
312        allocate(is_h2oice_flow(ngrid,nslope))
313        call flow_h2oglaciers(tsurf_avg,h2o_ice,is_h2oice_flow)
314    end if
315    if (do_layering) call surfice2layering(h2o_ice,co2_ice,layerings_map)
316
317    ! Adapt surface temperature if surface ice disappeared
318    call adapt_tsurf2disappearedice(co2_ice,is_co2ice_ini,is_co2ice_disappeared,tsurf_avg)
319    !call adapt_tsurf2disappearedice(h2o_ice,is_h2oice_ini,tsurf_avg)
320
321    if (do_soil) then
322        ! Shift soil temperature to surface
323        call shift_tsoil2surf(ngrid,nsoil,nslope,zshift_surf,zlag,tsurf_avg,tsoil_avg)
324
325        ! Evolve soil temperature
326        allocate(tsoil_ts_old(ngrid,nsoil,nslope,nday))
327        call evolve_soil_temp(tsoil_avg,tsurf_avg,tsoil_ts,tsoil_ts_old,h2o_soildensity_avg)
328
329        ! Evolve ice table
330        call evolve_ice_table(h2o_ice,h2o_surfdensity_avg,h2o_soildensity_avg,tsoil_avg,tsurf_avg,delta_icetable,q_h2o_ts, &
331                              ps_avg,icetable_depth,icetable_thickness,ice_porefilling,icetable_depth_old)
332
333        ! Update soil thermal properties according to ice table and soil temperature
334        call update_soil_TI(d_h2oice,h2o_ice,ps_avg_glob,icetable_depth,icetable_thickness,ice_porefilling,icetable_equilibrium,icetable_dynamic,TI)
335
336        ! Evolve adsorbed species
337        if (do_sorption) then
338            call evolve_regolith_adsorption(d_h2oice,d_co2ice,h2o_ice,co2_ice,tsoil_avg,TI,ps_ts,q_h2o_ts,q_co2_ts,h2o_ads_reg,co2_ads_reg,delta_h2o_ads,delta_co2_ads)
339            call compute_totmass_adsorbed(h2o_ads_reg,co2_ads_reg,totmass_adsco2,totmass_adsh2o)
340        else
341            totmass_adsh2o = 0._dp
342            totmass_adsco2 = 0._dp
343        end if
344    end if ! do_soil
345    deallocate(zshift_surf,zlag)
346
347    ! Output the results
348    call print_msg('> Standard outputs')
349    call write_diagevol('ps_avg_glob','Global average pressure','Pa',ps_avg_glob)
350    do islope = 1,nslope
351        if (nslope /= 1) then
352            num = '  '
353            write(num,'(i2.2)') islope
354            num = '_slope'//num
355        end if
356        call write_diagevol('h2oice'//num,'H2O ice','kg.m-2',h2o_ice(:,islope),(/dim_ngrid/))
357        call write_diagevol('co2ice'//num,'CO2 ice','kg.m-2',co2_ice(:,islope),(/dim_ngrid/))
358        call write_diagevol('d_h2oice'//num,'H2O ice tendency','kg.m-2.yr-1',d_h2oice(:,islope),(/dim_ngrid/))
359        call write_diagevol('d_co2ice'//num,'CO2 ice tendency','kg.m-2.yr-1',d_co2ice(:,islope),(/dim_ngrid/))
360        if (co2ice_flow) then
361            call write_diagevol('Flow_co2ice'//num,'CO2 ice flow location','T/F',merge(1._dp,0._dp,is_co2ice_flow(:,islope)),(/dim_ngrid/))
362            deallocate(is_co2ice_flow)
363        end if
364        if (h2oice_flow) then
365            call write_diagevol('Flow_h2oice'//num,'H2O ice flow location','T/F',merge(1._dp,0._dp,is_h2oice_flow(:,islope)),(/dim_ngrid/))
366            deallocate(is_h2oice_flow)
367        end if
368        call write_diagevol('tsurf'//num,'Surface temperature','K',tsurf_avg(:,islope),(/dim_ngrid/))
369        if (do_soil) then
370            if (icetable_equilibrium) then
371                call write_diagevol('icetable_depth'//num,'Ice table depth','m',icetable_depth(:,islope),(/dim_ngrid/))
372                call write_diagevol('icetable_thick'//num,'Ice table thickness','m',icetable_thickness(:,islope),(/dim_ngrid/))
373            else if (icetable_dynamic) then
374                call write_diagevol('icetable_depth'//num,'Ice table depth','m',icetable_depth(:,islope),(/dim_ngrid/))
375                call write_diagevol('ice_porefilling'//num,'Ice pore filling','-',ice_porefilling(:,:,islope),(/dim_ngrid,dim_nsoil/))
376            end if
377            call write_diagevol('tsoil_avg'//num,'Soil temperature','K',tsoil_avg(:,:,islope),(/dim_ngrid,dim_nsoil/))
378            call write_diagevol('inertiesoil'//num,'Thermal inertia','SI',TI(:,:,islope),(/dim_ngrid,dim_nsoil/))
379            if (do_sorption) then
380                call write_diagevol('co2_ads_reg'//num,'CO2 adsorbed in regolith','kg.m-2',co2_ads_reg(:,:,islope),(/dim_ngrid,dim_nsoil/))
381                call write_diagevol('h2o_ads_reg'//num,'H2O adsorbed in regolith','kg.m-2',h2o_ads_reg(:,:,islope),(/dim_ngrid,dim_nsoil/))
382            end if
383        end if
384    end do
385
386    ! Checking mass balance for CO2
387    if (abs(CO2cond_ps_PCM - 1._dp) < minieps) then
388        totmass_co2ice = 0._dp
389        totmass_atmco2 = 0._dp
390        do i = 1,ngrid
391            totmass_atmco2 = totmass_atmco2 + cell_area(i)*ps_avg(i)/g
392            do islope = 1,nslope
393                totmass_co2ice = totmass_co2ice + co2_ice(i,islope)*cell_area(i)*subslope_dist(i,islope)/cos(pi*def_slope_mean(islope)/180.)
394            end do
395        end do
396        totmass_ini = max(totmass_atmco2_ini + totmass_co2ice_ini + totmass_adsco2_ini,minieps_qp) ! To avoid division by 0
397        call print_msg(" > Relative total CO2 mass balance = "//real2str(100._qp*(totmass_atmco2 + totmass_co2ice + totmass_adsco2 - totmass_atmco2_ini - totmass_co2ice_ini - totmass_adsco2_ini)/totmass_ini)//' %')
398        if (abs((totmass_atmco2 + totmass_co2ice + totmass_adsco2 - totmass_atmco2_ini - totmass_co2ice_ini - totmass_adsco2_ini)/totmass_ini) > 0.01_qp) then
399            call print_msg('  /!\ Warning: mass balance is not conserved!')
400            totmass_ini = max(totmass_atmco2_ini,minieps_qp) ! To avoid division by 0
401            call print_msg('       Atmospheric CO2 mass balance = '//real2str(100._qp*(totmass_atmco2 - totmass_atmco2_ini)/totmass_ini)//' %')
402            totmass_ini = max(totmass_co2ice_ini,minieps_qp) ! To avoid division by 0
403            call print_msg('       CO2 ice mass balance         = '//real2str(100._qp*(totmass_co2ice - totmass_co2ice_ini)/totmass_ini)//' %')
404            totmass_ini = max(totmass_adsco2_ini,minieps_qp) ! To avoid division by 0
405            call print_msg('       Adsorbed CO2 mass balance    = '//real2str(100._qp*(totmass_adsco2 - totmass_adsco2_ini)/totmass_ini)//' %')
406        end if
407    end if
408
409    ! Evolve the tendencies
410    call evolve_tend_co2(d_co2ice_ini,co2_ice,emissivity_PCM,q_co2_ts_ini,q_co2_ts,ps_ts,ps_avg_glob_ini,ps_avg_glob,d_co2ice)
411!~     call print_msg("> Updating the H2O sub-surface ice tendency due to lag layer")
412!~     if (do_layering) then
413!~         do i = 1,ngrid
414!~             do islope = 1,nslope
415!~                 if (is_h2oice_sublim_ini(i,islope) .and. h2oice_depth(i,islope) > 0._dp) call evolve_tend_h2o(h2oice_depth_old(i,islope),h2oice_depth(i,islope),tsurf_avg(i,islope),tsoil_ts_old(i,:,islope,:),tsoil_ts(i,:,islope,:),d_h2oice(i,islope))
416!~             end do
417!~         end do
418!    else
419!        do i = 1,ngrid
420!            do islope = 1,nslope
421!                call evolve_tend_h2o(icetable_depth_old(i,islope),icetable_depth(i,islope),tsurf_avg(i,islope),tsoil_ts_old(i,:,islope,:),tsoil_ts(i,:,islope,:),d_h2oice(i,islope))
422!            end do
423!        end do
424!~     end if
425
426    ! Increment time
427    n_yr_run = n_yr_run + dt
428    n_yr_sim = n_yr_sim + dt
429    idt = idt + 1
430
431    ! Check the stopping criteria
432    call print_msg("> Checking the stopping criteria")
433    call stopping_crit_pressure(ps_avg_glob_ini,ps_avg_glob,stopcrit)
434    call stopping_crit_h2oice(h2oice_sublim_coverage_ini,h2o_ice,d_h2oice,stopcrit)
435    call stopping_crit_co2ice(co2ice_sublim_coverage_ini,co2_ice,d_co2ice,stopcrit)
436    call system_clock(c2)
437    if (stopcrit%stop_code() == 0 .and. n_yr_run >= nmax_yr_run) stopcrit%nmax_yr_run_reached = .true.
438    if (stopcrit%stop_code() == 0 .and. n_yr_run >= nmax_yr_runorb) stopcrit%nmax_yr_runorb_reached = .true.
439    if (stopcrit%stop_code() == 0 .and. n_yr_sim >= nmax_yr_sim) stopcrit%nmax_yr_sim_reached = .true.
440    if (stopcrit%stop_code() == 0 .and. timewall .and. real(c2 - c1,dp)/real(cr,dp) >= timelimit - antetime) stopcrit%time_limit_reached = .true.
441    if (stopcrit%is_any_set()) then
442        call print_msg(stopcrit%stop_message())
443        exit
444    else
445        call print_msg('**** This run has achieved '//real2str(n_yr_run)//' Planetary years.')
446        call print_msg('**** The chained simulation has achieved '//real2str(n_yr_sim)//' Planetary years.')
447        call print_msg('**** This run is continuing!')
448        call print_msg('****')
449    end if
450end do ! End of the evolution loop
451deallocate(is_co2ice_disappeared)
452
453! Finalization
454! ~~~~~~~~~~~~
455call print_msg('')
456call print_msg('********* Finalization *********')
457! Update orbital parameters
458if (evol_orbit) call update_orbit(n_yr_sim,n_yr_run)
459
460! Build ice for the PCM
461allocate(h2o_ice4PCM(ngrid,nslope),co2_ice4PCM(ngrid,nslope),is_h2o_perice(ngrid))
462call build4PCM_perice(h2o_ice,co2_ice,is_h2o_perice,h2o_ice4PCM,co2_ice4PCM)
463
464! Build surface temperature for the PCM
465allocate(tsurf4PCM(ngrid,nslope))
466call build4PCM_tsurf(tsurf_avg,tsurf_dev,tsurf4PCM)
467
468! Build soil for the PCM
469if (do_soil) then
470    allocate(tsoil4PCM(ngrid,nsoil_PCM,nslope),inertiesoil4PCM(ngrid,nsoil_PCM,nslope),flux_geo4PCM(ngrid,nslope))
471    call build4PCM_soil(tsoil_avg,tsoil_dev,inertiesoil4PCM,tsoil4PCM,flux_geo4PCM)
472end if
473
474! Build atmosphere for the PCM
475allocate(ps4PCM(ngrid),teta4PCM(ngrid,nlayer),air_mass4PCM(ngrid,nlayer))
476call build4PCM_atmosphere(ps_avg,ps_dev,ps_avg_glob,ps_avg_glob_ini,ps4PCM,pa4PCM,preff4PCM,teta4PCM,air_mass4PCM)
477
478! Build tracers for the PCM
479allocate(q4PCM(ngrid,nlayer,nq))
480call build4PCM_tracers(ps4PCM,q4PCM)
481
482! Build surface radiative properties state for the PCM
483allocate(albedo4PCM(ngrid,nslope),emissivity4PCM(ngrid,nslope))
484call build4PCM_surf_rad_prop(h2o_ice,co2_ice,albedo4PCM,emissivity4PCM)
485
486! Write the "startpem.nc"
487call write_restartpem(h2o_ice,co2_ice,tsoil_avg,TI,icetable_depth,icetable_thickness,ice_porefilling,h2o_ads_reg,co2_ads_reg,layerings_map)
488
489! Write the "startfi.nc"
490call write_restartfi(is_h2o_perice,h2o_ice4PCM,co2_ice4PCM,tsurf4PCM,tsoil4PCM,inertiesoil4PCM,albedo4PCM,emissivity4PCM,flux_geo4PCM)
491
492! Write the "start.nc"
493call write_restart(ps4PCM,pa4PCM,preff4PCM,tsurf4PCM,q4PCM,teta4PCM,air_mass4PCM)
494
495! Update the duration information of the simulation
496call update_info(n_yr_run,stopcrit%stop_code(),n_yr_sim,nmax_yr_sim)
497
498! Deallocation
499deallocate(emissivity4PCM,albedo4PCM)
500deallocate(q4PCM)
501deallocate(ps4PCM,teta4PCM,air_mass4PCM)
502if (do_soil) deallocate(tsoil4PCM,inertiesoil4PCM,flux_geo4PCM)
503deallocate(tsurf4PCM)
504deallocate(co2_ice4PCM,h2o_ice4PCM,is_h2o_perice)
505deallocate(num)
506if (do_layering) then
507    deallocate(h2oice_depth,h2oice_depth_old,new_str,new_lag,current)
508    do islope = 1,nslope
509        do i = 1,ngrid
510            call del_layering(layerings_map(i,islope))
511        end do
512    end do
513end if
514deallocate(layerings_map)
515deallocate(h2o_ads_reg,co2_ads_reg)
516deallocate(h2o_ice,co2_ice,is_h2oice_ini,is_co2ice_ini)
517deallocate(ps_avg,ps_dev,ps_ts)
518deallocate(tsurf_avg,tsurf_dev,h2o_surfdensity_avg)
519deallocate(tsoil_avg,tsoil_dev,tsoil_ts,tsoil_ts_old,h2o_soildensity_avg)
520deallocate(q_h2o_ts,q_co2_ts,q_co2_ts_ini)
521deallocate(d_h2oice,d_co2ice,d_co2ice_ini)
522deallocate(delta_h2o_ads,delta_co2_ads,delta_icetable,icetable_depth_old)
523call end_allocation()
524
525! Footer
526call system_clock(c2)
527call print_end(n_yr_run,real((c2 - c1),dp)/real(cr,dp),r_plnt2earth_yr,pem_ini_date,n_yr_sim)
528
529END PROGRAM pem
Note: See TracBrowser for help on using the repository browser.