source: trunk/LMDZ.COMMON/libf/evolution/xios_data.F90 @ 4065

Last change on this file since 4065 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: 8.9 KB
Line 
1MODULE xios_data
2!-----------------------------------------------------------------------
3! NAME
4!     xios_data
5!
6! DESCRIPTION
7!     Read XIOS output data and process it for PEM initialization.
8!
9! AUTHORS & DATE
10!     JB Clement, 2025
11!
12! NOTES
13!
14!-----------------------------------------------------------------------
15
16! DEPENDENCIES
17! ------------
18use numerics, only: dp, di, k4
19
20! DECLARATION
21! -----------
22implicit none
23
24contains
25!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
26
27!=======================================================================
28SUBROUTINE load_xios_data(ps_avg,ps_ts,tsurf_avg,tsurf_avg_yr1,tsoil_avg,tsoil_ts,h2o_surfdensity_avg,h2o_soildensity_avg, &
29                          q_h2o_ts,q_co2_ts,d_h2oice,d_co2ice)
30!-----------------------------------------------------------------------
31! NAME
32!     load_xios_data
33!
34! DESCRIPTION
35!     Reads yearly and daily XIOS data, computes frost and ice tendencies.
36!
37! AUTHORS & DATE
38!     JB Clement, 2025
39!
40! NOTES
41!
42!-----------------------------------------------------------------------
43
44! DEPENDENCIES
45! ------------
46use geometry,   only: ngrid, nslope, nsoil, nsoil_PCM, nday, lonlat2vect, nlon, nlat
47use io_netcdf,  only: xios_day_name2, xios_yr_name1, xios_yr_name2, open_nc, close_nc, get_var_nc, get_dim_nc
48use soil,       only: do_soil
49use tendencies, only: compute_tend
50use frost,      only: compute_frost4PCM
51use stoppage,   only: stop_clean
52use display,    only: print_msg
53use utility,    only: real2str
54
55! DECLARATION
56! -----------
57implicit none
58
59! ARGUMENTS
60! ---------
61real(dp), dimension(:),       intent(out) :: ps_avg
62real(dp), dimension(:,:),     intent(out) :: tsurf_avg, tsurf_avg_yr1, h2o_surfdensity_avg, d_h2oice, d_co2ice, ps_ts, q_h2o_ts, q_co2_ts
63real(dp), dimension(:,:,:),   intent(out) :: tsoil_avg, h2o_soildensity_avg
64real(dp), dimension(:,:,:,:), intent(out) :: tsoil_ts
65
66! LOCAL VARIABLES
67! ---------------
68logical(k4)                                  :: here
69integer(di)                                  :: islope, isoil, iday
70real(dp), dimension(:,:),     allocatable    :: var_read_2d
71real(dp), dimension(:,:,:),   allocatable    :: var_read_3d
72real(dp), dimension(:,:,:,:), allocatable    :: var_read_4d
73character(:),                 allocatable    :: num ! To read slope variables
74real(dp), dimension(ngrid,nslope,2)          :: min_h2operice, min_co2perice, min_h2ofrost, min_co2frost
75real(dp), dimension(ngrid,nsoil,nslope,nday) :: h2o_soildensity_ts
76! CODE
77! ----
78! Initialization
79min_h2operice(:,:,:) = 0._dp
80min_co2perice(:,:,:) = 0._dp
81min_h2ofrost(:,:,:) = 0._dp
82min_co2frost(:,:,:) = 0._dp
83if (nslope == 1) then ! No slope
84    allocate(character(0) :: num)
85else ! Using slopes
86    allocate(character(8) :: num)
87end if
88
89!~~~~~~~~~~~~~~~~~~~~~~~~ Year 1 - Yearly data ~~~~~~~~~~~~~~~~~~~~~~~~~
90inquire(file = xios_yr_name1,exist = here)
91if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//xios_yr_name1//'"!',1)
92
93! Open the NetCDF file of XIOS outputs
94call print_msg('> Reading "'//xios_yr_name1//'"')
95call open_nc(xios_yr_name1,'read')
96
97! Allocate and read the variables
98allocate(var_read_2d(nlon,nlat),var_read_3d(nlon,nlat,nsoil_PCM))
99do islope = 1,nslope
100    if (nslope /= 1) then
101        num = '  '
102        write(num,'(i2.2)') islope
103        num = '_slope'//num
104    end if
105    call get_var_nc('co2ice'//num,var_read_2d)          ; call lonlat2vect(nlon,nlat,ngrid,var_read_2d,min_co2frost(:,islope,1))
106    call get_var_nc('h2o_ice_s'//num,var_read_2d)       ; call lonlat2vect(nlon,nlat,ngrid,var_read_2d,min_h2ofrost(:,islope,1))
107    call get_var_nc('watercap'//num,var_read_2d)        ; call lonlat2vect(nlon,nlat,ngrid,var_read_2d,min_h2operice(:,islope,1))
108    call get_var_nc('perennial_co2ice'//num,var_read_2d); call lonlat2vect(nlon,nlat,ngrid,var_read_2d,min_co2perice(:,islope,1))
109    call get_var_nc('tsurf'//num,var_read_2d)           ; call lonlat2vect(nlon,nlat,ngrid,var_read_2d,tsurf_avg_yr1(:,islope))
110end do
111
112! Close the NetCDF file of XIOS outputs
113call close_nc(xios_yr_name1)
114
115!~~~~~~~~~~~~~~~~~~~~~~~~ Year 2 - Yearly data ~~~~~~~~~~~~~~~~~~~~~~~~~
116inquire(file = xios_yr_name2,exist = here)
117if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//xios_yr_name2//'"!',1)
118! Open the NetCDF file of XIOS outputs
119call print_msg('> Reading "'//xios_yr_name2//'"')
120call open_nc(xios_yr_name2,'read')
121
122! Allocate and read the variables
123call get_var_nc('ps',var_read_2d); call lonlat2vect(nlon,nlat,ngrid,var_read_2d,ps_avg)
124do islope = 1,nslope
125    if (nslope /= 1) then
126        num='  '
127        write(num,'(i2.2)') islope
128        num = '_slope'//num
129    end if
130    call get_var_nc('tsurf'//num,var_read_2d)           ; call lonlat2vect(nlon,nlat,ngrid,var_read_2d,tsurf_avg(:,islope))
131    call get_var_nc('co2ice'//num,var_read_2d)          ; call lonlat2vect(nlon,nlat,ngrid,var_read_2d,min_co2frost(:,islope,2))
132    call get_var_nc('h2o_ice_s'//num,var_read_2d)       ; call lonlat2vect(nlon,nlat,ngrid,var_read_2d,min_h2ofrost(:,islope,2))
133    call get_var_nc('watercap'//num,var_read_2d)        ; call lonlat2vect(nlon,nlat,ngrid,var_read_2d,min_h2operice(:,islope,2))
134    call get_var_nc('perennial_co2ice'//num,var_read_2d); call lonlat2vect(nlon,nlat,ngrid,var_read_2d,min_co2perice(:,islope,2))
135    if (do_soil) then
136        call get_var_nc('soiltemp'//num,var_read_3d)
137        do isoil = 1,nsoil_PCM
138            call lonlat2vect(nlon,nlat,ngrid,var_read_3d(:,:,isoil),tsoil_avg(:,isoil,islope))
139        end do
140        do isoil = nsoil_PCM + 1,nsoil
141            tsoil_avg(:,isoil,islope) = tsoil_avg(:,nsoil_PCM,islope) ! Explicit initialization because dimension with size nsoil > nsoil_PCM
142        end do
143        call get_var_nc('waterdensity_surface'//num,var_read_2d); call lonlat2vect(nlon,nlat,ngrid,var_read_2d,h2o_surfdensity_avg(:,islope))
144    end if
145end do
146! Close the NetCDF file of XIOS outputs
147call close_nc(xios_yr_name2)
148
149!~~~~~~~~~~~~~~~~~~~~~~~~~ Year 2 - Daily data ~~~~~~~~~~~~~~~~~~~~~~~~~
150inquire(file = xios_day_name2,exist = here)
151if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//xios_day_name2//'"!',1)
152! Open the NetCDF file of XIOS outputs
153call print_msg('> Reading "'//xios_day_name2//'"')
154call open_nc(xios_day_name2,'read')
155
156! Allocate and read the variables
157deallocate(var_read_2d,var_read_3d)
158allocate(var_read_3d(nlon,nlat,nday),var_read_4d(nlon,nlat,nsoil_PCM,nday))
159call get_var_nc('ps',var_read_3d)
160do iday = 1,nday
161    call lonlat2vect(nlon,nlat,ngrid,var_read_3d(:,:,iday),ps_ts(:,iday))
162end do
163call get_var_nc('h2o_layer1',var_read_3d)
164do iday = 1,nday
165    call lonlat2vect(nlon,nlat,ngrid,var_read_3d(:,:,iday),q_h2o_ts(:,iday))
166end do
167call get_var_nc('co2_layer1',var_read_3d)
168do iday = 1,nday
169    call lonlat2vect(nlon,nlat,ngrid,var_read_3d(:,:,iday),q_co2_ts(:,iday))
170end do
171if (do_soil) then
172    do islope = 1,nslope
173        if (nslope /= 1) then
174            num='  '
175            write(num,'(i2.2)') islope
176            num = '_slope'//num
177        end if
178        call get_var_nc('soiltemp'//num,var_read_4d)
179        do iday = 1,nday
180            do isoil = 1,nsoil_PCM
181                call lonlat2vect(nlon,nlat,ngrid,var_read_4d(:,:,isoil,iday),tsoil_ts(:,isoil,islope,iday))
182            end do
183            do isoil = nsoil_PCM + 1,nsoil
184                tsoil_ts(:,isoil,islope,iday) = tsoil_ts(:,nsoil_PCM,islope,iday) ! Explicit initialization because dimension with size nsoil > nsoil_PCM
185            end do
186        end do
187        call get_var_nc('waterdensity_soil'//num,var_read_4d)
188        do iday = 1,nday
189            do isoil = 1,nsoil_PCM
190                call lonlat2vect(nlon,nlat,ngrid,var_read_4d(:,:,isoil,iday),h2o_soildensity_ts(:,isoil,islope,iday))
191            end do
192            do isoil = nsoil_PCM + 1,nsoil
193                h2o_soildensity_ts(:,isoil,islope,iday) = h2o_soildensity_ts(:,nsoil_PCM,islope,iday) ! Explicit initialization because dimension with size nsoil > nsoil_PCM
194            end do
195        end do
196    end do
197    h2o_soildensity_avg(:,:,:) = sum(h2o_soildensity_ts,4)/nday
198end if
199deallocate(var_read_3d,var_read_4d,num)
200
201! Close the NetCDF file of XIOS outputs
202call close_nc(xios_day_name2)
203
204!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
205! Compute frost from yearly minima
206call compute_frost4PCM(min_h2ofrost(:,:,2),min_co2frost(:,:,2))
207
208!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
209! Compute ice tendencies from yearly minima
210call print_msg('> Computing surface ice tendencies')
211call compute_tend(min_h2operice + min_h2ofrost,d_h2oice)
212call print_msg('H2O ice tendencies [kg/m2/yr] (min|max): '//real2str(minval(d_h2oice))//' | '//real2str(maxval(d_h2oice)))
213call compute_tend(min_co2perice + min_co2frost,d_co2ice)
214call print_msg('CO2 ice tendencies [kg/m2/yr] (min|max): '//real2str(minval(d_co2ice))//' | '//real2str(maxval(d_co2ice)))
215
216END SUBROUTINE load_xios_data
217!=======================================================================
218
219END MODULE xios_data
Note: See TracBrowser for help on using the repository browser.