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

Last change on this file since 4134 was 4134, checked in by jbclement, 3 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: 9.6 KB
Line 
1MODULE backup
2!-----------------------------------------------------------------------
3! NAME
4!     backup
5!
6! DESCRIPTION
7!     Build and write PEM/PCM restart files, with optional backups.
8!
9! AUTHORS & DATE
10!     JB Clement, 03/2026
11!
12! NOTES
13!
14!-----------------------------------------------------------------------
15
16! DEPENDENCIES
17! ------------
18use numerics, only: dp, di, k4
19
20! DECLARATION
21! -----------
22implicit none
23
24! PARAMETERS
25! ----------
26integer(di), protected :: backup_rate = 0_di ! Backup rate in PEM timesteps (0 disables intermediate backups)
27
28contains
29!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
30
31!=======================================================================
32SUBROUTINE set_backup_config(backup_rate_in)
33!-----------------------------------------------------------------------
34! NAME
35!     set_backup_config
36!
37! DESCRIPTION
38!     Setter for backup configuration parameters.
39!
40! AUTHORS & DATE
41!     JB Clement, 03/2026
42!
43! NOTES
44!
45!-----------------------------------------------------------------------
46
47! DEPENDENCIES
48! ------------
49use utility,  only: int2str
50use display,  only: print_msg, LVL_NFO
51use stoppage, only: stop_clean
52
53! DECLARATION
54! -----------
55implicit none
56
57! ARGUMENTS
58! ---------
59integer(di), intent(in) :: backup_rate_in
60
61! CODE
62! ----
63backup_rate = backup_rate_in
64call print_msg('backup_rate = '//int2str(backup_rate),LVL_NFO)
65if (backup_rate < 0) call stop_clean(__FILE__,__LINE__,'''backup_rate'' must be >= 0!',1)
66
67END SUBROUTINE set_backup_config
68!=======================================================================
69
70!=======================================================================
71SUBROUTINE save_clim_state(h2o_ice,co2_ice,tsurf_avg,tsurf_dev,tsoil_avg,tsoil_dev,ps_avg,ps_dev,ps_avg_glob,ps_avg_glob_ini, &
72                           icetable_depth,icetable_thickness,ice_porefilling,h2o_ads_reg,co2_ads_reg,layerings_map,backup_idt)
73!-----------------------------------------------------------------------
74! NAME
75!     save_clim_state
76!
77! DESCRIPTION
78!     Build PCM-compatible state and write "restartevo", "restartfi"
79!     and "restart" files. Optionally create timestep-tagged backups.
80!
81! AUTHORS & DATE
82!     JB Clement, 03/2026
83!
84! NOTES
85!
86!-----------------------------------------------------------------------
87
88! DEPENDENCIES
89! ------------
90use geometry,         only: ngrid, nslope, nsoil_PCM, nlayer
91use soil,             only: do_soil, TI, build4PCM_soil
92use surface,          only: build4PCM_surf_rad_prop
93use surf_ice,         only: build4PCM_perice
94use surf_temp,        only: build4PCM_tsurf
95use atmosphere,       only: build4PCM_atmosphere
96use tracers,          only: build4PCM_tracers, nq
97use clim_state_rec,   only: write_restart, write_restartfi, write_restartpem
98use layered_deposits, only: layering
99
100! DECLARATION
101! -----------
102implicit none
103
104! ARGUMENTS
105! ---------
106real(dp),       dimension(:),     intent(in)    :: ps_avg, ps_dev
107real(dp),                         intent(in)    :: ps_avg_glob, ps_avg_glob_ini
108real(dp),       dimension(:,:),   intent(in)    :: tsurf_avg, tsurf_dev, icetable_depth, icetable_thickness
109real(dp),       dimension(:,:,:), intent(in)    :: tsoil_avg, tsoil_dev, ice_porefilling, h2o_ads_reg, co2_ads_reg
110type(layering), dimension(:,:),   intent(in)    :: layerings_map
111integer(di), optional,            intent(in)    :: backup_idt
112real(dp),       dimension(:,:),   intent(inout) :: h2o_ice, co2_ice
113
114! LOCAL VARIABLES
115! ---------------
116real(dp),    dimension(:,:),   allocatable :: h2o_ice4PCM, co2_ice4PCM, tsurf4PCM, flux_geo4PCM, albedo4PCM, emissivity4PCM
117real(dp),    dimension(:,:),   allocatable :: teta4PCM, air_mass4PCM
118real(dp),    dimension(:,:,:), allocatable :: tsoil4PCM, inertiesoil4PCM, q4PCM
119real(dp),    dimension(:),     allocatable :: ps4PCM
120real(dp)                                   :: pa4PCM, preff4PCM
121logical(k4), dimension(:),     allocatable :: is_h2o_perice
122
123! CODE
124! ----
125! Build ice for the PCM
126allocate(h2o_ice4PCM(ngrid,nslope),co2_ice4PCM(ngrid,nslope),is_h2o_perice(ngrid))
127call build4PCM_perice(h2o_ice,co2_ice,is_h2o_perice,h2o_ice4PCM,co2_ice4PCM)
128
129! Build surface temperature for the PCM
130allocate(tsurf4PCM(ngrid,nslope))
131call build4PCM_tsurf(tsurf_avg,tsurf_dev,tsurf4PCM)
132
133! Build soil for the PCM
134if (do_soil) then
135    allocate(tsoil4PCM(ngrid,nsoil_PCM,nslope),inertiesoil4PCM(ngrid,nsoil_PCM,nslope),flux_geo4PCM(ngrid,nslope))
136    call build4PCM_soil(tsoil_avg,tsoil_dev,inertiesoil4PCM,tsoil4PCM,flux_geo4PCM)
137end if
138
139! Build atmosphere for the PCM
140allocate(ps4PCM(ngrid),teta4PCM(ngrid,nlayer),air_mass4PCM(ngrid,nlayer))
141call build4PCM_atmosphere(ps_avg,ps_dev,ps_avg_glob,ps_avg_glob_ini,ps4PCM,pa4PCM,preff4PCM,teta4PCM,air_mass4PCM)
142
143! Build tracers for the PCM
144allocate(q4PCM(ngrid,nlayer,nq))
145call build4PCM_tracers(ps4PCM,q4PCM)
146
147! Build surface radiative properties state for the PCM
148allocate(albedo4PCM(ngrid,nslope),emissivity4PCM(ngrid,nslope))
149call build4PCM_surf_rad_prop(h2o_ice,co2_ice,albedo4PCM,emissivity4PCM)
150
151! Write restart files
152call write_restartpem(h2o_ice,co2_ice,tsoil_avg,TI,icetable_depth,icetable_thickness,ice_porefilling,h2o_ads_reg,co2_ads_reg,layerings_map)
153call write_restartfi(is_h2o_perice,h2o_ice4PCM,co2_ice4PCM,tsurf4PCM,tsoil4PCM,inertiesoil4PCM,albedo4PCM,emissivity4PCM,flux_geo4PCM)
154call write_restart(ps4PCM,pa4PCM,preff4PCM,q4PCM,teta4PCM,air_mass4PCM)
155
156if (present(backup_idt)) then
157    if (backup_idt > 0) call backup_restarts(backup_idt)
158end if
159
160! Deallocation
161if (allocated(emissivity4PCM)) deallocate(emissivity4PCM)
162if (allocated(albedo4PCM)) deallocate(albedo4PCM)
163if (allocated(q4PCM)) deallocate(q4PCM)
164if (allocated(ps4PCM)) deallocate(ps4PCM)
165if (allocated(teta4PCM)) deallocate(teta4PCM)
166if (allocated(air_mass4PCM)) deallocate(air_mass4PCM)
167if (allocated(tsoil4PCM)) deallocate(tsoil4PCM)
168if (allocated(inertiesoil4PCM)) deallocate(inertiesoil4PCM)
169if (allocated(flux_geo4PCM)) deallocate(flux_geo4PCM)
170if (allocated(tsurf4PCM)) deallocate(tsurf4PCM)
171if (allocated(co2_ice4PCM)) deallocate(co2_ice4PCM)
172if (allocated(h2o_ice4PCM)) deallocate(h2o_ice4PCM)
173if (allocated(is_h2o_perice)) deallocate(is_h2o_perice)
174
175END SUBROUTINE save_clim_state
176!=======================================================================
177
178!=======================================================================
179SUBROUTINE backup_restarts(idt)
180!-----------------------------------------------------------------------
181! NAME
182!     backup_restarts
183!
184! DESCRIPTION
185!     Duplicate restart files to timestep-tagged backup files.
186!
187! AUTHORS & DATE
188!     JB Clement, 03/2026
189!
190! NOTES
191!
192!-----------------------------------------------------------------------
193
194! DEPENDENCIES
195! ------------
196use geometry,  only: ngrid
197use io_netcdf, only: start_name, start1D_name, startfi_name, startevo_name
198use display,   only: print_msg, LVL_NFO
199use utility,   only: int2str
200
201! DECLARATION
202! -----------
203implicit none
204
205! ARGUMENTS
206! ---------
207integer(di), intent(in) :: idt
208
209! LOCAL VARIABLES
210! ---------------
211character(:), allocatable :: suffix
212
213! CODE
214! ----
215suffix = '_ts'//int2str(idt)
216
217call print_msg('> Backup at dt = '//int2str(idt),LVL_NFO)
218call copy_restart_if_present('re'//startevo_name,suffix2filename(startevo_name,suffix))
219call copy_restart_if_present('re'//startfi_name,suffix2filename(startfi_name,suffix))
220if (ngrid == 1) then
221    call copy_restart_if_present('re'//start1D_name,suffix2filename(start1D_name,suffix))
222else
223    call copy_restart_if_present('re'//start_name,suffix2filename(start_name,suffix))
224end if
225
226END SUBROUTINE backup_restarts
227!=======================================================================
228
229!=======================================================================
230SUBROUTINE copy_restart_if_present(src_name,dst_name)
231!-----------------------------------------------------------------------
232! NAME
233!     copy_restart_if_present
234!
235! DESCRIPTION
236!     Copy file if present. Used for restart backup files.
237!
238! AUTHORS & DATE
239!     JB Clement, 03/2026
240!
241! NOTES
242!
243!-----------------------------------------------------------------------
244
245! DEPENDENCIES
246! ------------
247use stoppage, only: stop_clean
248
249! DECLARATION
250! -----------
251implicit none
252
253! ARGUMENTS
254! ---------
255character(*), intent(in) :: src_name, dst_name
256
257! LOCAL VARIABLES
258! ---------------
259logical(k4) :: here
260integer(di) :: cstat
261
262! CODE
263! ----
264inquire(file = src_name,exist = here)
265if (.not. here) return
266
267call execute_command_line('cp '//src_name//' '//dst_name,cmdstat = cstat)
268if (cstat > 0) then
269    call stop_clean(__FILE__,__LINE__,'command execution failed!',1)
270else if (cstat < 0) then
271    call stop_clean(__FILE__,__LINE__,'command execution not supported!',1)
272end if
273
274END SUBROUTINE copy_restart_if_present
275!=======================================================================
276
277!=======================================================================
278FUNCTION suffix2filename(filename,suffix_in) RESULT(name_out)
279!-----------------------------------------------------------------------
280! NAME
281!     suffix2filename
282!
283! DESCRIPTION
284!     Insert suffix before the extension of a filename.
285!
286! AUTHORS & DATE
287!     JB Clement, 03/2026
288!
289! NOTES
290!
291!-----------------------------------------------------------------------
292
293! DECLARATION
294! -----------
295implicit none
296
297! ARGUMENTS
298! ---------
299character(*), intent(in) :: filename, suffix_in
300
301! LOCAL VARIABLES
302! ---------------
303character(:), allocatable :: name_out
304integer(di)               :: ipos
305
306! CODE
307! ----
308ipos = index(filename,'.',back = .true.)
309if (ipos > 0) then
310    name_out = filename(:ipos - 1)//suffix_in//filename(ipos:)
311else
312    name_out = filename//suffix_in
313end if
314
315END FUNCTION suffix2filename
316!=======================================================================
317
318END MODULE backup
Note: See TracBrowser for help on using the repository browser.