source: trunk/LMDZ.COMMON/libf/evolution/ice_table_mod.F90 @ 3203

Last change on this file since 3203 was 3082, checked in by jbclement, 21 months ago

PEM:

  • Correction of a bug in the initialization of constants. The correct modules are now used: 'comcstfi_h' (and no longer 'comconst_mod'!) in the general case and 'comcstfi_mod' in the case of generic model;
  • Addition of the variable 'ecritpem' in "run_PEM.def" to set the frequency of outputs in the "diagfi.nc". By default, 'ecritpem = 1' which means there is one output at each PEM year.

JBC

File size: 17.9 KB
Line 
1module ice_table_mod
2
3  implicit none
4
5!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
6!!!
7!!! Purpose: Ice table (pore-filling) variables and methods to compute it (dynamic and static)
8!!! Author:  LL, 02/2023
9!!!
10!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
11
12  LOGICAL,SAVE :: icetable_equilibrium                    ! Boolean to say if the PEM needs to recompute the icetable depth when at  equilibrium
13  LOGICAL,SAVE :: icetable_dynamic                        ! Boolean to say if the PEM needs to recompute the icetable depth (dynamic method)
14  real,save,allocatable  :: porefillingice_depth(:,:)    ! ngrid x nslope: Depth of the ice table [m]
15  real,save,allocatable  :: porefillingice_thickness(:,:)    ! ngrid x nslope: Thickness of the ice table [m]
16
17  contains
18
19
20  subroutine ini_ice_table_porefilling(ngrid,nslope)
21 
22    implicit none
23    integer,intent(in) :: ngrid ! number of atmospheric columns
24    integer,intent(in) :: nslope ! number of slope within a mesh
25
26    allocate(porefillingice_depth(ngrid,nslope))
27    allocate(porefillingice_thickness(ngrid,nslope))
28
29  end subroutine ini_ice_table_porefilling
30
31  subroutine end_ice_table_porefilling
32
33    implicit none
34    if (allocated(porefillingice_depth)) deallocate(porefillingice_depth)
35    if (allocated(porefillingice_thickness)) deallocate(porefillingice_thickness)
36
37  end subroutine end_ice_table_porefilling
38
39!!! --------------------------------------
40
41   SUBROUTINE computeice_table_equilibrium(ngrid,nslope,nsoil_PEM,watercaptag,rhowatersurf_ave,rhowatersoil_ave,regolith_inertia,ice_table_beg,ice_table_thickness)
42!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
43!!!
44!!! Purpose: Compute the ice table depth (pore-filling) knowing the yearly average water
45!!! density at the surface and at depth.
46!!! Computations are made following the methods in Schorgofer et al., 2005
47!!! This subroutine only gives the ice table at equilibrium and does not consider exchange with the atmosphere
48!!!
49!!! Author: LL
50!!!
51!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
52    use math_mod,only: findroot
53    USE comsoil_h_PEM, only: mlayer_PEM,layer_PEM                  ! Depth of the vertical grid
54    USE soil_thermalproperties_mod, only: ice_thermal_properties
55    implicit none
56!   inputs
57! -----------
58    integer,intent(in) :: ngrid,nslope,nsoil_PEM                   ! Size of the physical grid, number of subslope, number of soil layer in the PEM
59    logical,intent(in) :: watercaptag(ngrid)                       ! Boolean to check the presence of a perennial glacier
60    real,intent(in) :: rhowatersurf_ave(ngrid,nslope)              ! Water density at the surface, yearly averaged [kg/m^3]
61    real,intent(in) :: rhowatersoil_ave(ngrid,nsoil_PEM,nslope)    ! Water density at depth, computed from clapeyron law's (Murchy and Koop 2005), yearly averaged  [kg/m^3]
62    real,intent(in) :: regolith_inertia(ngrid,nslope)              ! Thermal inertia of the regolith layer [SI]
63!   Ouputs
64! -----------
65    real,intent(out) :: ice_table_beg(ngrid,nslope)               ! ice table depth [m]
66    real,intent(out) :: ice_table_thickness(ngrid,nslope)         ! ice table thickness [m]
67!   Local
68! -----------
69    real :: z1,z2                                                  ! intermediate variables used when doing a linear interpolation between two depths to find the root
70    integer ig, islope,isoil,isoilend                              ! loop variables
71    real :: diff_rho(nsoil_PEM)                                    ! difference of water vapor density between the surface and at depth [kg/m^3]
72    real  :: ice_table_end                                         ! depth of the end of the ice table  [m]
73    real :: previous_icetable_depth(ngrid,nslope)                  ! Ice table computed at previous ice depth [m]
74    real :: stretch                                                ! stretch factor to improve the convergence of the ice table
75    real :: wice_inertia                                           ! Water Ice thermal Inertia [USI]   
76!   Code
77! -----------
78
79     previous_icetable_depth(:,:) = ice_table_beg(:,:)
80     do ig = 1,ngrid
81      if(watercaptag(ig)) then
82         ice_table_beg(ig,:) = 0.
83         ice_table_thickness(ig,:) = layer_PEM(nsoil_PEM) ! Let's assume an infinite ice table (true when geothermal flux is set to 0.)
84      else
85        do islope = 1,nslope
86           ice_table_beg(ig,islope) = -1.
87           ice_table_thickness(ig,islope) = 0.
88         do isoil = 1,nsoil_PEM
89           diff_rho(isoil) = rhowatersurf_ave(ig,islope) - rhowatersoil_ave(ig,isoil,islope)
90         enddo
91         if(diff_rho(1) > 0) then                                   ! ice is at the surface
92           ice_table_beg(ig,islope) = 0.
93               do isoilend = 2,nsoil_PEM-1
94                 if((diff_rho(isoilend).gt.0).and.(diff_rho(isoilend+1).lt.0.)) then
95                  call findroot(diff_rho(isoilend),diff_rho(isoilend+1),mlayer_PEM(isoilend),mlayer_PEM(isoilend+1),ice_table_end)
96                  ice_table_thickness(ig,islope) = ice_table_end - ice_table_beg(ig,islope)
97                  exit
98                 endif
99               enddo
100         else
101           do isoil = 1,nsoil_PEM -1                                ! general case, we find the ice table depth by doing a linear approximation between the two depth, and then solve the first degree equation to find the root
102             if((diff_rho(isoil).lt.0).and.(diff_rho(isoil+1).gt.0.)) then
103               call findroot(diff_rho(isoil),diff_rho(isoil+1),mlayer_PEM(isoil),mlayer_PEM(isoil+1),ice_table_beg(ig,islope))
104               ! Now let's find the end of the ice table
105               ice_table_thickness(ig,islope) = layer_PEM(nsoil_PEM) ! Let's assume an infinite ice table (true when geothermal flux is set to 0.)
106               do isoilend = isoil+1,nsoil_PEM-1
107                 if((diff_rho(isoilend).gt.0).and.(diff_rho(isoilend+1).lt.0.)) then
108                  call findroot(diff_rho(isoilend),diff_rho(isoilend+1),mlayer_PEM(isoilend),mlayer_PEM(isoilend+1),ice_table_end)
109                  ice_table_thickness(ig,islope) = ice_table_end - ice_table_beg(ig,islope)
110                  exit
111                 endif
112               enddo
113             endif !diff_rho(z) <0 & diff_rho(z+1) > 0
114           enddo
115          endif ! diff_rho(1) > 0
116        enddo
117       endif ! watercaptag
118      enddo
119
120! Small trick to speed up the convergence, Oded's idea.
121      do islope = 1,nslope
122        do ig = 1,ngrid
123         if((ice_table_beg(ig,islope).gt.previous_icetable_depth(ig,islope)).and.(previous_icetable_depth(ig,islope).ge.0)) then
124            call ice_thermal_properties(.false.,1.,regolith_inertia(ig,islope),wice_inertia)
125            stretch = (regolith_inertia(ig,islope)/wice_inertia)**2
126
127            ice_table_thickness(ig,islope) = ice_table_thickness(ig,islope) + (ice_table_beg(ig,islope) - &
128            previous_icetable_depth(ig,islope)+(ice_table_beg(ig,islope) - previous_icetable_depth(ig,islope))/stretch)
129            ice_table_beg(ig,islope) = previous_icetable_depth(ig,islope)+(ice_table_beg(ig,islope) - previous_icetable_depth(ig,islope))/stretch
130         endif
131        enddo
132      enddo
133
134      RETURN
135      END
136
137!!! --------------------------------------
138
139
140   SUBROUTINE compute_massh2o_exchange_ssi(ngrid,nslope,nsoil_PEM,former_ice_table_thickness,new_ice_table_thickness,ice_table_depth,tsoil,delta_m_h2o)
141!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
142!!!
143!!! Purpose: Compute the mass of H2O that has sublimated from the ice table / condensed
144!!!
145!!! Author: LL
146!!!
147!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
148    use comsoil_h_PEM, only: mlayer_PEM
149    use comslope_mod, only: subslope_dist,def_slope_mean
150    use constants_marspem_mod,only:porosity
151#ifndef CPP_STD
152    use comcstfi_h,   only: pi
153#else
154    use comcstfi_mod, only: pi
155#endif
156
157    implicit none
158!   inputs
159! -----------
160    integer,intent(in) :: ngrid,nslope,nsoil_PEM                   ! Size of the physical grid, number of subslope, number of soil layer in the PEM
161    real,intent(in) :: former_ice_table_thickness(ngrid,nslope)    ! ice table thickness at the former iteration [m]
162    real,intent(in) :: new_ice_table_thickness(ngrid,nslope)       ! ice table thickness at the current iteration [m]
163    real,intent(out) :: ice_table_depth(ngrid,nslope)              ! ice table depth [m]
164    real,intent(in) :: tsoil(ngrid,nsoil_PEM,nslope)               ! Soil temperature [K]
165!   outputs
166! -----------
167    real,intent(out) :: delta_m_h2o(ngrid)                         ! Mass of H2O ice that has been condensed on the ice table / sublimates from the ice table [kg/m^2]
168
169! local
170    real :: rho(ngrid,nslope)                                      ! density of water ice [kg/m^3]
171    integer :: ig,islope,ilay,iref                                 ! loop index 
172    real :: Tice(ngrid,nslope)                                     ! ice temperature [k]
173!   Code
174! -----------
175   rho(:,:) = 0.
176   Tice(:,:) = 0.
177!1. First let's compute Tice using a linear interpolation between the mlayer level
178   do ig = 1,ngrid
179      do islope = 1,nslope
180         if(ice_table_depth(ig,islope).gt.0.) then
181            if (ice_table_depth(ig,islope).lt. 1e-10) then
182               Tice(ig,islope) = tsoil(ig,1,islope)
183            else
184               iref=0 ! initialize iref
185               do ilay=1,nsoil_PEM ! loop on layers to find the beginning of the ice table
186                  if (ice_table_depth(ig,islope).ge.mlayer_PEM(ilay)) then
187                     iref=ilay ! pure regolith layer up to here
188                  else
189                  ! correct iref was obtained in previous cycle
190                     exit
191                  endif
192               enddo
193               if(iref.eq.nsoil_PEM) then
194                  Tice(ig,islope) = tsoil(ig,nsoil_PEM,islope)
195               else
196                  Tice(ig,islope) = (tsoil(ig,iref+1,islope) - tsoil(ig,iref,islope))/(mlayer_PEM(iref+1) - mlayer_PEM(iref))* &
197                                    (ice_table_depth(ig,islope) - mlayer_PEM(iref)) +  tsoil(ig,iref,islope)           
198               endif         
199               rho(ig,islope) = -3.5353e-4*Tice(ig,islope)**2+   0.0351* Tice(ig,islope) +  933.5030 ! Rottgers, 2012
200            endif
201         endif
202      enddo
203   enddo     
204
205         
206!2. Let's compute the amount of ice that has sublimated in each subslope
207   do ig = 1,ngrid
208      do islope = 1,nslope
209        delta_m_h2o(ig)  = delta_m_h2o(ig) +  porosity*rho(ig,islope)*(new_ice_table_thickness(ig,islope) - former_ice_table_thickness(ig,islope)) & ! convention > 0. <=> it condenses 
210                           *subslope_dist(ig,islope)/cos(def_slope_mean(islope)*pi/180.)
211      enddo
212   enddo
213
214   return
215end subroutine
216
217!!! --------------------------------------
218
219   SUBROUTINE find_layering_icetable(porefill,psat_soil,psat_surf,pwat_surf,psat_bottom,B,index_IS,depth_filling,index_filling,index_geothermal,depth_geothermal,dz_etadz_rho)
220!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
221!!!
222!!! Purpose: Compute layering between dry soil, pore filling ice, and ice sheet based on Schorgofer, Icarus (2010). Adapted from NS MSIM
223!!!
224!!! Author: LL
225!!!
226!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
227use comsoil_h_PEM,only: nsoilmx_PEM,mlayer_PEM
228use math_mod, only: deriv1,deriv1_onesided,colint,findroot,deriv2_simple
229implicit none
230! inputs
231! ------
232
233real,intent(in) :: porefill(nsoilmx_PEM) ! Fraction of pore space filled with ice [Unitless] 0 <= f <= 1 for pore ice
234real,intent(in) :: psat_soil(nsoilmx_PEM) ! Soil water pressure at saturation, yearly averaged [Pa]
235real,intent(in) :: psat_surf ! surface water pressure at saturation, yearly averaged [Pa]
236real,intent(in) :: pwat_surf ! Water vapor pressure  at the surface, not necesseraly at saturation, yearly averaged [Pa]
237real,intent(in) :: psat_bottom ! Boundary conditions for soil vapor pressure [Pa]
238real,intent(in) :: B ! constant (Eq. 8 from  Schorgofer, Icarus (2010).)
239integer, intent(in) :: index_IS ! index of the soil layer where the ice sheet begins [1]
240real, intent(inout) :: depth_filling ! depth where pore filling begins [m]
241
242! outputs
243! -------
244integer,intent(out) :: index_filling ! index where the pore filling begins [1]
245integer, intent(out) :: index_geothermal ! index where the ice table stops [1]
246real, intent(out) :: depth_geothermal ! depth where the ice table stops [m]
247real, intent(out) :: dz_etadz_rho(nsoilmx_PEM) ! \partial z(eta \partial z rho), eta is the constriction, used later for pore filling increase
248
249! local
250
251real :: eta(nsoilmx_PEM)  ! constriction
252integer :: ilay ! index for loop
253real :: old_depth_filling ! depth_filling saved
254real :: dz_psat(nsoilmx_PEM) ! first derivative of the vapor pressure at saturationn
255integer :: index_tmp ! for loop
256real :: Jdry ! flux trought the dry layer
257real :: Jsat ! flux trought the ice layer
258real :: Jdry_prevlay,Jsat_prevlay ! same but for the previous ice layer
259integer :: index_firstice ! first index where ice appears (i.e., f > 0)
260real :: dz_eta(nsoilmx_PEM) ! \partial z \eta
261real :: dz_eta_low ! same but evaluated at the interface for ice
262real :: dzz_psat(nsoilmx_PEM) ! \partial \partial psat
263real :: massfillabove,massfillafter ! h2O mass above and after index_geothermal
264
265! constant
266real :: pvap2rho = 18.e-3/8.314
267!
268 
269! 0. Compute constriction over the layer
270! Within the ice sheet, constriction is set to 0. Elsewhere, constriction =  (1-porefilling)**2
271if (index_IS.lt.0) then
272   index_tmp = nsoilmx_PEM
273   do ilay = 1,nsoilmx_PEM
274       call constriction(porefill(ilay),eta(ilay))
275   enddo
276else
277   index_tmp = index_IS
278   do ilay = 1,index_IS-1
279       call constriction(porefill(ilay),eta(ilay))
280   enddo
281   do ilay = index_IS,nsoilmx_PEM
282       eta(ilay) = 0.
283   enddo
284endif
285
286! 1. Depth at which pore filling occurs. We solve Eq. 9 from  Schorgofer, Icarus  (2010)   
287
288old_depth_filling = depth_filling
289
290call deriv1(mlayer_PEM,nsoilmx_PEM,psat_soil,psat_surf,psat_bottom,dz_psat) 
291
292do ilay = 1,index_tmp
293  Jdry = (psat_soil(ilay) - pwat_surf)/mlayer_PEM(ilay) ! left member of Eq. 9 from Schorgofer, Icarus  (2010)
294  Jsat =  eta(ilay)*dz_psat(ilay) !right member of Eq. 9 from Schorgofer, Icarus (2010)
295  if((Jdry - Jsat).le.0) then
296     index_filling = ilay
297     exit
298   endif
299enddo
300
301if(index_filling.eq.1)  depth_filling = mlayer_PEM(1)
302
303if(index_filling.gt.1) then
304    Jdry_prevlay = (psat_soil(index_filling-1) - pwat_surf)/mlayer_PEM(index_filling-1)
305    Jsat_prevlay = eta(index_filling-1)*dz_psat(index_filling-1)
306   call findroot(Jdry-Jsat,Jdry_prevlay-Jsat_prevlay,mlayer_PEM(index_filling),mlayer_PEM(index_filling-1),depth_filling)
307endif
308
309
310! 2. Compute d_z (eta* d_z(rho)) (last term in Eq. 13 of Schorgofer, Icarus (2010))
311
312
313! 2.0 preliminary: depth to shallowest  ice (discontinuity at interface)
314
315index_firstice = -1
316do ilay = 1,nsoilmx_PEM
317   if (porefill(ilay).le.0.) then
318        index_firstice = ilay  ! first point with ice
319        exit
320    endif
321enddo
322
323! 2.1: now we can computeCompute d_z (eta* d_z(rho))
324
325call deriv1(mlayer_PEM,nsoilmx_PEM,eta,1.,eta(nsoilmx_PEM-1),dz_eta)
326
327if ((index_firstice.gt.0).and.(index_firstice.lt.nsoilmx_PEM-2)) then
328     call deriv1_onesided(index_firstice,mlayer_PEM,nsoilmx_PEM,eta,dz_eta(index_firstice))
329endif
330
331call deriv2_simple(mlayer_PEM,nsoilmx_PEM,psat_soil,psat_surf,psat_bottom,dzz_psat)
332dz_etadz_rho(:) = pvap2rho*(dz_eta(:)*dz_psat(:) + eta(:)*dzz_psat(:))
333
334! 3. Ice table boundary due to geothermal heating
335
336if(index_IS.gt.0) index_geothermal = -1
337if(index_geothermal.lt.0) depth_geothermal = -1.
338if((index_geothermal.gt.0).and.(index_IS.lt.0)) then ! Eq. 21 from Schorfoger, Icarus (2010)
339   index_geothermal = -1
340   do ilay=2,nsoilmx_PEM
341        if (dz_psat(ilay).gt.0.) then  ! first point with reversed flux
342           index_geothermal=ilay
343           call findroot(dz_psat(ilay-1),dz_psat(ilay),mlayer_PEM(ilay-1),mlayer_PEM(ilay),depth_geothermal)
344           exit
345        endif
346     enddo
347  else
348     index_geothermal = -1
349  endif
350 if ((index_geothermal.gt.0).and.(index_IS.lt.0)) then !  Eq. 24 from Schorgofer, Icarus (2010)
351     call  colint(porefill(:)/eta(:),mlayer_PEM,nsoilmx_PEM,index_geothermal-1,nsoilmx_PEM,massfillabove)
352     index_tmp = -1
353     do ilay=index_geothermal,nsoilmx_PEM
354        if (minval(eta(ilay:nsoilmx_PEM)).le.0.) cycle  ! eta=0 means completely full
355         call colint(porefill(:)/eta(:),mlayer_PEM,nsoilmx_PEM,ilay,nsoilmx_PEM,massfillafter)
356        if (massfillafter<dz_psat(ilay)*pvap2rho*B) then  ! usually executes on i=typeG
357           if (ilay>index_geothermal) then
358!              write(34,*) '# adjustment to geotherm depth by',ilay-index_geothermal
359              call findroot(dz_psat(ilay-1)*pvap2rho*B-massfillabove, & 
360                   dz_psat(ilay)*pvap2rho*B-massfillafter,mlayer_PEM(ilay-1),mlayer_PEM(ilay),depth_geothermal)
361!               if (depth_geothermal.gt.mlayer_PEM(ilay) .or. depth_geothermal.lt.<mlayer_PEM(ilay-1)) write(34,*)
362!                     '# WARNING: zdepthG interpolation failed',ilay,mlayer_PEM(ilay-1),depth_geothermal,mlayer_PEM(ilay)
363              index_tmp=ilay
364           endif
365           ! otherwise leave depth_geothermal unchanged
366           exit
367        endif
368        massfillabove = massfillafter
369     enddo
370     if (index_tmp.gt.0) index_geothermal = index_tmp
371  end if
372  return
373end subroutine
374
375!!! --------------------------------------
376
377SUBROUTINE constriction(porefill,eta)
378
379        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
380        !!!
381        !!! Purpose: Compute the  constriction of vapor flux by pore ice
382        !!!
383        !!! Author: LL
384        !!!
385        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
386        implicit none
387        real,intent(in) :: porefill ! pore filling fraction
388        real,intent(out) :: eta ! constriction
389
390        !!!
391
392        if (porefill.le.0.) eta = 1.
393        if ((porefill.gt.0.) .and.(porefill.lt.1.)) then
394        eta = (1-porefill)**2  ! Hudson et al., JGR, 2009
395        endif
396        if (porefill.le.1.) eta = 0.
397        return
398        end subroutine
399
400end module
Note: See TracBrowser for help on using the repository browser.