source: trunk/LMDZ.COMMON/libf/evolution/surf_ice.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: 13.5 KB
Line 
1MODULE surf_ice
2!-----------------------------------------------------------------------
3! NAME
4!     surf_ice
5!
6! DESCRIPTION
7!     Surface ice management.
8!
9! AUTHORS & DATE
10!     JB Clement, 12/2025
11!
12! NOTES
13!
14!-----------------------------------------------------------------------
15
16! DEPENDENCIES
17! ------------
18use numerics, only: dp, qp, di, k4
19
20! DECLARATION
21! -----------
22implicit none
23
24! PARAMETERS
25! ----------
26real(dp),                                 parameter :: rho_co2ice = 1650._dp ! Density of CO2 ice [kg.m-3]
27real(dp),                                 parameter :: rho_h2oice = 920._dp  ! Density of H2O ice [kg.m-3]
28real(dp),                                 protected :: threshold_h2oice_cap  ! Threshold to consider H2O ice as infinite reservoir [kg.m-2]
29real(dp),                                 protected :: h2oice_huge_ini       ! Initial value for huge reservoirs of H2O ice [kg/m^2]
30logical(k4), dimension(:),   allocatable, protected :: is_h2o_perice_PCM     ! Flag for the presence of perennial H2O ice in the PCM at the beginning [kg.m-2]
31real(dp),    dimension(:,:), allocatable, protected :: co2_perice_PCM        ! Perennial CO2 ice in the PCM at the beginning [kg.m-2]
32
33contains
34!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
35
36!=======================================================================
37SUBROUTINE ini_surf_ice()
38!-----------------------------------------------------------------------
39! NAME
40!     ini_surf_ice
41!
42! DESCRIPTION
43!     Initialize surface ice arrays.
44!
45! AUTHORS & DATE
46!     JB Clement 12/2025
47!
48! NOTES
49!
50!-----------------------------------------------------------------------
51
52! DEPENDENCIES
53! ------------
54use geometry, only: ngrid, nslope
55
56! DECLARATION
57! -----------
58implicit none
59
60! CODE
61! ----
62if (.not. allocated(is_h2o_perice_PCM)) allocate(is_h2o_perice_PCM(ngrid))
63if (.not. allocated(co2_perice_PCM)) allocate(co2_perice_PCM(ngrid,nslope))
64is_h2o_perice_PCM(:) = .false.
65co2_perice_PCM(:,:) = 0._dp
66
67END SUBROUTINE ini_surf_ice
68!=======================================================================
69
70!=======================================================================
71SUBROUTINE end_surf_ice()
72!-----------------------------------------------------------------------
73! NAME
74!     end_surf_ice
75!
76! DESCRIPTION
77!     Deallocate surface ice arrays.
78!
79! AUTHORS & DATE
80!     JB Clement, 12/2025
81!
82! NOTES
83!
84!-----------------------------------------------------------------------
85
86! DECLARATION
87! -----------
88implicit none
89
90! CODE
91! ----
92if (allocated(is_h2o_perice_PCM)) deallocate(is_h2o_perice_PCM)
93if (allocated(co2_perice_PCM)) deallocate(co2_perice_PCM)
94
95END SUBROUTINE end_surf_ice
96!=======================================================================
97
98!=======================================================================
99SUBROUTINE set_surf_ice_config(threshold_h2oice_cap_in,h2oice_huge_ini_in)
100!-----------------------------------------------------------------------
101! NAME
102!     set_surf_ice_config
103!
104! DESCRIPTION
105!     Setter for 'surf_ice' configuration parameters.
106!
107! AUTHORS & DATE
108!     JB Clement, 02/2026
109!
110! NOTES
111!
112!-----------------------------------------------------------------------
113
114! DEPENDENCIES
115! ------------
116use utility,  only: real2str
117use display,  only: print_msg, LVL_NFO
118use stoppage, only: stop_clean
119
120! DECLARATION
121! -----------
122implicit none
123
124! ARGUMENTS
125! ---------
126real(dp), intent(in) :: threshold_h2oice_cap_in, h2oice_huge_ini_in
127
128! CODE
129! ----
130threshold_h2oice_cap = threshold_h2oice_cap_in
131h2oice_huge_ini = h2oice_huge_ini_in
132call print_msg('threshold_h2oice_cap = '//real2str(threshold_h2oice_cap),LVL_NFO)
133call print_msg('h2oice_huge_ini      = '//real2str(h2oice_huge_ini),LVL_NFO)
134if (threshold_h2oice_cap < 0._dp) call stop_clean(__FILE__,__LINE__,'''threshold_h2oice_cap'' must be positive or null!',1)
135if (h2oice_huge_ini < 0._dp) call stop_clean(__FILE__,__LINE__,'''h2oice_huge_ini'' must be positive or null!',1)
136
137END SUBROUTINE set_surf_ice_config
138!=======================================================================
139
140!=======================================================================
141SUBROUTINE set_co2_perice_PCM(co2_perice_PCM_in)
142!-----------------------------------------------------------------------
143! NAME
144!     set_co2_perice_PCM
145!
146! DESCRIPTION
147!     Setter for 'co2_perice_PCM'.
148!
149! AUTHORS & DATE
150!     JB Clement, 12/2025
151!
152! NOTES
153!
154!-----------------------------------------------------------------------
155
156! DECLARATION
157! -----------
158implicit none
159
160! ARGUMENTS
161! ---------
162real(dp), dimension(:,:), intent(in) :: co2_perice_PCM_in
163
164! CODE
165! ----
166co2_perice_PCM(:,:) = co2_perice_PCM_in(:,:)
167
168END SUBROUTINE set_co2_perice_PCM
169!=======================================================================
170
171!=======================================================================
172SUBROUTINE set_is_h2o_perice_PCM(is_h2o_perice_PCM_in)
173!-----------------------------------------------------------------------
174! NAME
175!     set_is_h2o_perice_PCM
176!
177! DESCRIPTION
178!     Setter for 'is_h2o_perice_PCM'.
179!
180! AUTHORS & DATE
181!     JB Clement, 12/2025
182!
183! NOTES
184!
185!-----------------------------------------------------------------------
186
187! DECLARATION
188! -----------
189implicit none
190
191! ARGUMENTS
192! ---------
193real(dp), dimension(:), intent(in) :: is_h2o_perice_PCM_in
194
195! CODE
196! ----
197where(is_h2o_perice_PCM_in > 0.5_dp)
198    is_h2o_perice_PCM = .true.
199else where
200    is_h2o_perice_PCM = .false.
201end where
202
203END SUBROUTINE set_is_h2o_perice_PCM
204!=======================================================================
205
206!=======================================================================
207SUBROUTINE build4PCM_perice(h2o_ice,co2_ice,is_h2o_perice,h2o_ice4PCM,co2_ice4PCM)
208!-----------------------------------------------------------------------
209! NAME
210!     build4PCM_perice
211!
212! DESCRIPTION
213!     Reconstructs perennial ice and frost for the PCM.
214!
215! AUTHORS & DATE
216!     JB Clement, 12/2025
217!
218! NOTES
219!
220!-----------------------------------------------------------------------
221
222! DEPENDENCIES
223! ------------
224use geometry, only: ngrid
225use frost,    only: h2o_frost4PCM
226use slopes,   only: subslope_dist, def_slope_mean
227use maths,    only: pi
228use display,  only: print_msg, LVL_NFO
229
230! DECLARATION
231! -----------
232implicit none
233
234! ARGUMENTS
235! ---------
236real(dp),    dimension(:,:), intent(inout) :: h2o_ice, co2_ice
237logical(k4), dimension(:),   intent(out)   :: is_h2o_perice            ! H2O perennial ice flag
238real(dp),    dimension(:,:), intent(out)   :: h2o_ice4PCM, co2_ice4PCM ! Ice for PCM
239
240! LOCAL VARIABLES
241! ---------------
242integer(di) :: i
243
244! CODE
245! ----
246call print_msg('> Building surface ice/frost for the PCM',LVL_NFO)
247co2_ice4PCM(:,:) = co2_ice(:,:)
248h2o_ice4PCM(:,:) = 0._dp ! Because in the Mars PCM, only the variation of perennial H2O ice is monitored, not the absolute quantity
249do i = 1,ngrid
250    ! Is H2O ice still considered as an infinite reservoir for the PCM?
251    if (sum(h2o_ice(i,:)*subslope_dist(i,:)/cos(pi*def_slope_mean(:)/180._dp)) > threshold_h2oice_cap) then
252        ! There is enough ice to be considered as an infinite reservoir
253        is_h2o_perice(i) = .true.
254    else
255        ! Too little ice to be considered as an infinite reservoir so ice is transferred to the frost
256        is_h2o_perice(i) = .false.
257        h2o_frost4PCM(i,:) = h2o_frost4PCM(i,:) + h2o_ice(i,:)
258        h2o_ice(i,:) = 0._dp
259    end if
260end do
261
262END SUBROUTINE build4PCM_perice
263!=======================================================================
264
265!=======================================================================
266SUBROUTINE evolve_co2ice(co2_ice,d_co2ice,zshift_surf)
267!-----------------------------------------------------------------------
268! NAME
269!     evolve_co2ice
270!
271! DESCRIPTION
272!     Compute the evolution of CO2 ice over one year.
273!
274! AUTHORS & DATE
275!     R. Vandemeulebrouck
276!     L. Lange
277!     JB Clement, 2023-2025
278!
279! NOTES
280!
281!-----------------------------------------------------------------------
282
283! DEPENDENCIES
284! ------------
285use geometry,  only: ngrid, nslope
286use evolution, only: dt
287use display,   only: print_msg, LVL_NFO
288
289! DECLARATION
290! -----------
291implicit none
292
293! ARGUMENTS
294! ---------
295real(dp), dimension(:,:), intent(inout) :: co2_ice
296real(dp), dimension(:,:), intent(inout) :: d_co2ice
297real(dp), dimension(:,:), intent(out)   :: zshift_surf
298
299! LOCAL VARIABLES
300! ---------------
301real(dp), dimension(ngrid,nslope) :: co2_ice_old ! Old density of CO2 ice
302
303! CODE
304! ----
305! Evolution of CO2 ice for each physical point
306call print_msg('> Evolution of CO2 ice',LVL_NFO)
307
308co2_ice_old = co2_ice
309co2_ice = co2_ice + d_co2ice*dt
310where (co2_ice < 0._dp)
311    co2_ice = 0._dp
312    d_co2ice = -co2_ice_old/dt
313end where
314
315zshift_surf = d_co2ice*dt/rho_co2ice
316
317END SUBROUTINE evolve_co2ice
318!=======================================================================
319
320!=======================================================================
321SUBROUTINE evolve_h2oice(delta_h2o_ads,delta_icetable,h2o_ice,d_h2oice,zshift_surf,stopcrit)
322!-----------------------------------------------------------------------
323! NAME
324!     evolve_h2oice
325!
326! DESCRIPTION
327!     Compute the evolution of H2O ice over one year.
328!
329! AUTHORS & DATE
330!     R. Vandemeulebrouck
331!     L. Lange
332!     JB Clement, 2023-2025
333!
334! NOTES
335!
336!-----------------------------------------------------------------------
337
338! DEPENDENCIES
339! ------------
340use geometry,      only: ngrid, nslope
341use evolution,     only: dt
342use stopping_crit, only: stopping_crit_h2o, stopFlags
343use display,       only: print_msg, LVL_NFO
344
345! DECLARATION
346! -----------
347implicit none
348
349! ARGUMENTS
350! ---------
351real(dp), dimension(:),   intent(in)    :: delta_h2o_ads, delta_icetable
352real(dp), dimension(:,:), intent(inout) :: h2o_ice, d_h2oice
353type(stopFlags),          intent(inout) :: stopcrit
354real(dp), dimension(:,:), intent(out)   :: zshift_surf
355
356! LOCAL VARIABLES
357! ---------------
358real(qp)                          :: S_atm_2_h2o, S_h2o_2_atm, S_atm_2_h2oice, S_h2oice_2_atm ! H2O balance variables
359real(dp), dimension(ngrid,nslope) :: d_h2oice_new                                             ! Tendencies computed to keep balance
360
361! CODE
362! ----
363call print_msg('> Evolution of H2O ice',LVL_NFO)
364
365if (ngrid == 1) then ! In 1D
366    where (d_h2oice(:,:) < 0._dp .and. abs(d_h2oice(:,:)*dt) > h2o_ice(:,:)) ! Not enough ice to sublimate everything
367        ! We sublimate what we can
368        d_h2oice_new(:,:) = h2o_ice(:,:)/dt
369        ! It means the tendency is zero next time
370        d_h2oice(:,:) = 0._dp
371    else where
372        d_h2oice_new(:,:) = d_h2oice(:,:)
373    end where
374else ! In 3D
375    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)
376    if (stopcrit%stop_code() > 0) return
377    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)
378end if
379
380h2o_ice = h2o_ice + d_h2oice_new*dt
381zshift_surf = d_h2oice_new*dt/rho_h2oice
382
383END SUBROUTINE evolve_h2oice
384!=======================================================================
385
386!=======================================================================
387SUBROUTINE 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)
388!-----------------------------------------------------------------------
389! NAME
390!     balance_h2oice_reservoirs
391!
392! DESCRIPTION
393!     Balance H2O flux from and into atmosphere across reservoirs.
394!
395! AUTHORS & DATE
396!     JB Clement, 2025
397!
398! NOTES
399!
400!-----------------------------------------------------------------------
401
402! DEPENDENCIES
403! ------------
404use evolution, only: dt
405use geometry,  only: ngrid, nslope
406
407! DECLARATION
408! -----------
409implicit none
410
411! ARGUMENTS
412! ---------
413real(qp),                 intent(in)    :: S_atm_2_h2o, S_h2o_2_atm, S_atm_2_h2oice, S_h2oice_2_atm
414real(dp), dimension(:,:), intent(in)    :: h2o_ice
415real(dp), dimension(:,:), intent(inout) :: d_h2oice
416real(dp), dimension(:,:), intent(out)   :: d_h2oice_new
417
418! LOCAL VARIABLES
419! ---------------
420integer(di) :: i, islope
421real(qp)    :: S_target, S_target_subl_h2oice, S_target_cond_h2oice, S_ghostice ! Balance variables
422real(dp)    :: d_target
423
424! CODE
425! ----
426S_target = (S_atm_2_h2o + S_h2o_2_atm)/2._dp
427S_target_cond_h2oice = S_atm_2_h2oice + S_target - S_atm_2_h2o
428S_target_subl_h2oice = S_h2oice_2_atm + S_target - S_h2o_2_atm
429
430d_h2oice_new = 0._dp
431S_ghostice = 0._qp
432do i = 1,ngrid
433    do islope = 1,nslope
434        if (d_h2oice(i,islope) > 0._dp) then ! Condensing
435            d_h2oice_new(i,islope) = d_h2oice(i,islope)*real(S_target_cond_h2oice/S_atm_2_h2oice,dp)
436        else if (d_h2oice(i,islope) < 0._dp) then ! Sublimating
437            d_target = d_h2oice(i,islope)*real(S_target_subl_h2oice/S_h2oice_2_atm,dp)
438            if (abs(d_target*dt) <= h2o_ice(i,islope)) then ! Enough ice to sublimate everything
439                d_h2oice_new(i,islope) = d_target
440            else ! Not enough ice to sublimate everything
441                ! We sublimate what we can
442                d_h2oice_new(i,islope) = h2o_ice(i,islope)/dt
443                ! It means the tendency is zero next time
444                d_h2oice(i,islope) = 0._dp
445                ! We compute the amount of H2O ice that we could not make sublimate
446                S_ghostice = S_ghostice + abs(d_target*dt) - h2o_ice(i,islope)
447            end if
448        end if
449    end do
450end do
451
452! We need to remove this ice unable to sublimate from places where ice condensed in order to keep balance
453where (d_h2oice_new > 0._dp) d_h2oice_new = d_h2oice_new*real((S_target_cond_h2oice - S_ghostice)/S_target_cond_h2oice,dp)
454
455END SUBROUTINE balance_h2oice_reservoirs
456!=======================================================================
457
458END MODULE surf_ice
Note: See TracBrowser for help on using the repository browser.