source: trunk/LMDZ.COMMON/libf/evolution/subsurface_ice.F90 @ 3989

Last change on this file since 3989 was 3989, checked in by jbclement, 5 weeks ago

PEM:
Massive structural refactor of the PEM codebase for improved readability, consistency and maintainability. The goal is to modernize, standardize and consolidate the code while removing legacy complexity. In detail, this change:

  • Performs large-scale cleanup removing unused code, obsolete routines, duplicated functionality and deprecated initialization logic;
  • Removes "*_mod" wrappers;
  • Replaces mixed naming conventions with clearer variable names, domain-based file/module names and purpose-based routine names;
  • Adds native reading/writing capabilities to the PEM removing the cumbersome dependency on Mars PCM subroutines;
  • Centralizes soil/ice/orbital/PEM configuration logic into dedicated modules;
  • Simplifies routines and updates calls/interfaces to match the new structure.

This refactor significantly clarifies the codebase and provides a cleaner foundation for forthcoming developments.
JBC

File size: 29.6 KB
Line 
1MODULE subsurface_ice
2
3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4!!!
5!!! Purpose:  Retreat and growth of subsurface ice on Mars
6!!!           orbital elements remain constant
7!!!
8!!!
9!!! Author: EV, updated NS MSIM dynamical program for the PEM
10!!!         Taken from Norbert Schorgofer's code
11!!!
12!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
13
14implicit none
15
16  ! parameters for thermal model
17  ! they are only used in the subroutines below
18  real(8), parameter :: dt = 0.02  ! in units of Mars solar days
19  !real(8), parameter :: Fgeotherm = 0.
20  real(8), parameter :: Fgeotherm = 0 !0.028  ! [W/m^2]
21  real(8), parameter :: Lco2frost=6.0e5, co2albedo=0.60, co2emiss=1.
22  real(8), parameter :: emiss0 = 1.  ! emissivity of dry surface
23  integer, parameter :: EQUILTIME =15 ! [Mars years]
24
25  integer, parameter :: NMAX = 1000
26
27contains
28
29
30!=======================================================================
31!============================ dyn_ss_ice_m =============================
32!=======================================================================
33
34
35SUBROUTINE dyn_ss_ice_m(ssi_depth_in,T1,Tb,nz,thIn,p0,pfrost,porefill_in,porefill,ssi_depth)
36
37!***********************************************************************
38! Retreat and growth of subsurface ice on Mars
39! orbital elements remain constant
40!***********************************************************************
41  use constants_marspem_mod, only: sec_per_sol
42  use phys_constants,        only: pi
43  implicit none
44  integer, parameter :: NP=1   ! # of sites
45  integer nz, i, k, iloop
46  real(8)  zmax, delta, z(NMAX), icetime, porosity, icefrac
47  real(8), dimension(NP) ::  albedo, thIn, rhoc
48  real(8), dimension(NP) :: pfrost, p0
49  real(8) newti, stretch, newrhoc, ecc, omega, eps, timestep
50  real(8)  ssi_depth_in, ssi_depth, T1
51  real(8), dimension(NP) :: zdepthF, zdepthE, zdepthT, zdepthG
52  real(8), dimension(nz,NP) :: porefill, porefill_in
53  real(8), dimension(nz) :: Tb
54  real(8), dimension(NP) :: Tmean1, Tmean3, avrho1
55  real(8) tmax, tlast, avrho1prescribed(NP), l1
56  real(8), external :: smartzfac
57
58  !if (iargc() /= 1) then
59  !   stop 'USAGE: icages ext'
60  !endif
61  !call getarg( 1, ext )
62
63  if (NP>100) stop 'subroutine icelayer_mars cannot handle this many sites'
64
65  ! parameters that never ever change
66  porosity = 0.4d0  ! porosity of till
67  !rhoc(:) = 1500.*800.  ! will be overwritten
68  icefrac = 0.98
69  tmax = 1
70  tlast = 0.
71  avrho1prescribed(:) = pfrost/T1  ! <0 means absent
72  albedo=0.23
73  !avrho1prescribed(:) = 0.16/200.  ! units are Pa/K
74
75  !open(unit=21,file='lats.'//ext,action='read',status='old',iostat=ierr)
76  !if (ierr /= 0) then
77  !   print *,'File lats.'//ext,'not found'
78  !   stop
79  !endif
80  do k=1,NP
81     !read(21,*) latitude(k),albedo(k),thIn(k),htopo(k)
82     ! empirical relation from Mellon & Jakosky
83     rhoc(k) = 800.*(150.+100.*sqrt(34.2+0.714*thIn(k)))
84  enddo
85  !close(21)
86
87  ! set eternal grid
88  zmax = 25.
89  !zfac = smartzfac(nz,zmax,6,0.032d0)
90  !call setgrid(nz,z,zmax,zfac)
91  l1=2.e-4
92  do iloop=0,nz - 1
93    z(iloop + 1) = l1*(1+iloop**2.9*(1-exp(-real(iloop)/20.)))
94  enddo
95
96
97  !open(unit=30,file='z.'//ext,action='write',status='unknown')
98  !write(30,'(999(f8.5,1x))') z(1:nz)
99  !close(30)
100
101  !ecc = ecc_in;  eps = obl_in*d2r;  omega = Lp_in*d2r   ! today
102  ! total atmospheric pressure
103  !p0(:) = 600.
104  ! presently 520 Pa at zero elevation (Smith & Zuber, 1998)
105 ! do k=1,NP
106 !    p0(k)=520*exp(-htopo(k)/10800.)
107 ! enddo
108  timestep = 1 ! must be integer fraction of 1 ka
109  icetime = -tmax-timestep  ! earth years
110
111  ! initializations
112  !Tb = -9999.
113  zdepthF(:) = -9999.
114
115  !zdepthT(1:NP) = -9999.   ! reset again below
116 ! zdepthT(1:NP) = 0.
117
118 ! print *,'RUNNING MARS_FAST'
119 ! print *,'Global model parameters:'
120 ! print *,'nz=',nz,' zfac=',zfac,'zmax=',zmax
121 ! print *,'porosity=',porosity
122 ! print *,'starting at time',icetime,'years'
123 ! print *,'time step=',timestep,'years'
124 ! print *,'eps=',eps/d2r,'ecc=',ecc,'omega=',omega/d2r
125 ! print *,'number of sites=',NP
126 ! print *,'Site specific parameters:'
127  do k=1,NP
128     if (NP>1) print *,'  Site ',k
129 !    print *,'  latitude (deg)',latitude(k),' rho*c (J/m^3/K)',rhoc(k),' thIn=',thIn(k)
130 !    print *,'  total pressure=',p0(k),'partial pressure=',pfrost(k)
131     delta = thIn(k)/rhoc(k)*sqrt(sec_per_sol/pi)
132 !    print *,'  skin depths (m)',delta,delta*sqrt(solsperyear)
133     call soilthprop(porosity,1.d0,rhoc(k),thIn(k),1,newrhoc,newti,icefrac)
134     stretch = (newti/thIn(k))*(rhoc(k)/newrhoc)
135     do i=1,nz
136        if (z(i)<delta) cycle
137 !       print *,'  ',i-1,' grid points within diurnal skin depth'
138        exit
139     enddo
140 !    print *,'  ',zmax/(sqrt(solsperyear)*delta),'times seasonal dry skin depth'
141 !    print *,'  ',zmax/(sqrt(solsperyear)*delta*stretch),'times seasonal filled skin depth'
142 !    print *,'  Initial ice depth=',zdepthT(k)
143 !    print *
144  enddo
145 ! call outputmoduleparameters
146 ! print *
147
148  ! open and name all output files
149!  open(unit=34,file='subout.'//ext,action='write',status='unknown')
150!  open(unit=36,file='depthF.'//ext,action='write',status='unknown')
151!  open(unit=37,file='depths.'//ext,action='write',status='unknown')
152
153 ! print *,'Equilibrating initial temperature'
154 ! do i=1,4
155 !    call icelayer_mars(0d0,nz,NP,thIn,rhoc,z,porosity,pfrost,Tb,zdepthF, &
156 !      &  zdepthE,porefill(1:nz,:),Tmean1,Tmean3,zdepthG, &
157 !      &  latitude,albedo,p0,ecc,omega,eps,icefrac,zdepthT,avrho1, &
158 !      &  avrho1prescribed)
159 ! enddo
160
161  !print *,'History begins here'
162 porefill(1:nz,1:NP) =  porefill_in(1:nz,1:NP)
163  zdepthT(1:NP) = ssi_depth_in
164  do
165  !print *,'Zt0=  ',ZdepthT
166     call icelayer_mars(timestep,nz,NP,thIn,rhoc,z,porosity,pfrost,Tb,zdepthF, &
167          & zdepthE,porefill,Tmean1,Tmean3,zdepthG, &
168          & albedo,p0,icefrac,zdepthT,avrho1, &
169          & avrho1prescribed)
170     icetime = icetime+timestep
171   !  print *,'T_after=  ',Tb(:)
172 !    print *,'z=  ',z(:)
173 !    print *,'Zt=  ',ZdepthT
174     ssi_depth=ZdepthT(1)
175    ! if (abs(mod(icetime/100.,1.d0))<1.e-3) then ! output every 1000 years
176    !    do k=1,NP
177         !write(36,*) icetime,latitude(k),zdepthF(k),porefill(1:nz,k)
178           ! compact output format
179 !          write(36,'(f10.0,2x,f7.3,1x,f11.5,1x)',advance='no') &
180 !               & icetime,latitude(k),zdepthF(k)
181 !          call compactoutput(36,porefill(:,k),nz)
182 !          write(37,501) icetime,latitude(k),zdepthT(k), &
183 !               & Tmean1(k),Tmean3(k),zdepthG(k),avrho1(k)
184  !      enddo
185  !   endif
186!     print *,icetime
187     if (icetime>=tlast) exit
188  enddo
189
190 ! close(34)
191 ! close(36); close(37)
192
193!501 format (f10.0,2x,f7.3,2x,f10.4,2(2x,f6.2),2x,f9.3,2x,g11.4)
194
195end subroutine dyn_ss_ice_m
196
197!=======================================================================
198
199subroutine soilthprop(porosity,fill,rhocobs,tiobs,layertype, &
200     &     newrhoc,newti,icefrac)
201!***********************************************************************
202! soilthprop: assign thermal properties of icy soil or dirty ice
203!
204!     porositiy = void space / total volume
205!     rhof = density of free ice in space not occupied by regolith [kg/m^3]
206!     fill = rhof/icedensity <=1 (only relevant for layertype 1)
207!     rhocobs = heat capacity per volume of dry regolith [J/m^3]
208!     tiobs = thermal inertia of dry regolith [SI-units]
209!     layertype: 1=interstitial ice, 2=pure ice or ice with dirt
210!                3=pure ice, 4=ice-cemented soil, 5=custom values
211!     icefrac: fraction of ice in icelayer (only relevant for layertype 2)
212!     output are newti and newrhoc
213!***********************************************************************
214  implicit none
215  integer, intent(IN) :: layertype
216  real(8), intent(IN) :: porosity, fill, rhocobs, tiobs
217  real(8), intent(OUT) :: newti, newrhoc
218  real(8), intent(IN) :: icefrac
219  real(8) kobs, cice, icedensity, kice
220  !parameter (cice=2000.d0, icedensity=926.d0, kice=2.4d0) ! unaffected by scaling
221  parameter (cice=1540.d0, icedensity=927.d0, kice=3.2d0) ! at 198 Kelvin
222  real(8) fA, ki0, ki, k
223  real(8), parameter :: kw=3. ! Mellon et al., JGR 102, 19357 (1997)
224
225  kobs = tiobs**2/rhocobs
226  ! k, rhoc, and ti are defined in between grid points
227  ! rhof and T are defined on grid points
228
229  newrhoc = -9999.
230  newti  = -9999.
231
232  select case (layertype)
233  case (1) ! interstitial ice
234     newrhoc = rhocobs + porosity*fill*icedensity*cice
235     if (fill>0.) then
236        !--linear addition (option A)
237        k = porosity*fill*kice + kobs
238        !--Mellon et al. 1997 (option B)
239        ki0 = porosity/(1/kobs-(1-porosity)/kw)
240        fA = sqrt(fill)
241        ki = (1-fA)*ki0 + fA*kice
242        !k = kw*ki/((1-porosity)*ki+porosity*kw)
243     else
244        k = kobs
245     endif
246     newti = sqrt(newrhoc*k)
247
248  case (2)  ! massive ice (pure or dirty ice)
249     newrhoc = rhocobs*(1.-icefrac)/(1.-porosity) + icefrac*icedensity*cice
250     k = icefrac*kice + (1.-icefrac)*kw
251     newti = sqrt(newrhoc*k)
252
253  case (3)  ! all ice, special case of layertype 2, which doesn't use porosity
254     newrhoc = icedensity*cice
255     k = kice
256     newti = sqrt(newrhoc*k)
257
258  case (4)  ! pores completely filled with ice, special case of layertype 1
259     newrhoc = rhocobs + porosity*icedensity*cice
260     k = porosity*kice + kobs ! option A, end-member case of type 1, option A
261     !k = kw*kice/((1-porosity)*kice+porosity*kw) ! option B, harmonic average
262     newti = sqrt(newrhoc*k)
263
264  case (5)  ! custom values
265     ! values from Mellon et al. (2004) for ice-cemented soil
266     newrhoc = 2018.*1040.
267     k = 2.5
268     newti = sqrt(newrhoc*k)
269
270  case default
271     error stop 'invalid layer type'
272
273  end select
274
275end subroutine soilthprop
276
277
278!=======================================================================
279
280      real*8 function frostpoint(p)
281!     inverse of psv
282!     input is partial pressure [Pascal]
283!     output is temperature [Kelvin]
284      implicit none
285      real*8 p
286
287!-----inverse of parametrization 1
288!      real*8 DHmelt,DHvap,DHsub,R,pt,Tt
289!      parameter (DHmelt=6008.,DHvap=45050.)
290!      parameter (DHsub=DHmelt+DHvap)
291!      parameter (R=8.314,pt=6.11e2,Tt=273.16)
292!      frostpoint = 1./(1./Tt-R/DHsub*log(p/pt))
293
294!-----inverse of parametrization 2
295!     inverse of eq. (2) in Murphy & Koop (2005)
296      real*8 A,B
297      parameter (A=-6143.7, B=28.9074)
298      frostpoint = A / (log(p) - B)
299
300!-----approximate inverse of parametrization 3
301!     eq. (8) in Murphy & Koop (2005)
302!      frostpoint = (1.814625*log(p) + 6190.134)/(29.120 - log(p))
303
304      end function frostpoint
305
306
307!=======================================================================
308!=========================== fast_subs_mars ============================
309!=======================================================================
310
311
312!*****************************************************
313! Subroutines for fast method
314! written by Norbert Schorghofer 2007-2011
315!*****************************************************
316
317
318subroutine icelayer_mars(bigstep,nz,NP,thIn,rhoc,z,porosity,pfrost, &
319     & Tb,zdepthF,zdepthE,porefill,Tmean1,Tmean3,zdepthG, &
320     & albedo,p0,icefrac,zdepthT,avrho1, &
321     & avrho1prescribed)
322!*************************************************************************
323! bigstep = time step [Earth years]
324! latitude  [degree]
325!*************************************************************************
326  use ice_table,      only: rho_ice
327  !use omp_lib
328  implicit none
329  integer, intent(IN) :: nz, NP
330  real(8), intent(IN) :: bigstep
331  real(8), intent(IN) :: thIn(NP), rhoc(NP), z(NMAX), porosity, pfrost(NP)
332  real(8), intent(INOUT) :: porefill(nz,NP), zdepthF(NP), zdepthT(NP)
333  real(8), intent(INOUT) :: Tb(nz)
334  real(8), intent(OUT), dimension(NP) :: zdepthE, Tmean1, Tmean3, zdepthG
335  real(8), intent(IN), dimension(NP) ::  albedo, p0
336  real(8), intent(IN) ::  icefrac
337  real(8), intent(OUT) :: avrho1(NP)
338  real(8), intent(IN), optional :: avrho1prescribed(NP)  ! <0 means absent
339
340  integer k, typeF, typeG, typeT, j, jump, typeP
341  real(8) fracIR, fracDust, ti(NMAX), rhocv(NMAX)
342  real(8) Diff, ypp(nz), avdrho(NP), avdrhoP(NP), B, deltaz
343  real(8), SAVE :: avdrho_old(100), zdepth_old(100)  ! NP<=100
344  logical mode2
345
346  avdrho_old = 1. ! initialization
347
348  !$omp parallel &
349  !$omp    private(Diff,fracIR,fracDust,B,typeT,j,ti,rhocv,typeF,jump,typeG)
350  !$omp do
351  do k=1,NP   ! big loop
352
353     Diff = 4e-4*600./p0(k)
354     fracIR = 0.04*p0(k)/600.; fracDust = 0.02*p0(k)/600.
355     B = Diff*bigstep*86400.*365.24/(porosity*927.)
356     !B = Diff*bigstep*86400.*365.24/(porosity*rho_ice(Tb(),'h2o'))
357
358     typeT = -9
359     if (zdepthT(k)>=0. .and. zdepthT(k)<z(nz)) then
360        do j=1,nz
361           if (z(j)>zdepthT(k)) then ! ice
362              typeT = j  ! first point in ice
363              exit
364           endif
365        enddo
366     endif
367
368   !  call assignthermalproperties(nz,thIn(k),rhoc(k),ti,rhocv, &
369   !       & typeT,icefrac,porosity,porefill(:,k))
370
371     !----run thermal model
372     call ajsub_mars(typeT, albedo(k), pfrost(k), nz, z, &
373          &     ti, rhocv, fracIR, fracDust, p0(k), &
374          &     avdrho(k), avdrhoP(k), avrho1(k), Tb(k), zdepthE(k), typeF, &
375          &     zdepthF(k), ypp, porefill(:,k), Tmean1(k), Tmean3(k), B, &
376          &     typeG, zdepthG(k), avrho1prescribed(k))
377
378     if (typeF*zdepthF(k)<0.) stop 'error in icelayer_mars'
379     ! diagnose
380     if (zdepthT(k)>=0.) then
381        jump = 0
382        do j=1,nz
383           if (zdepth_old(k)<z(j) .and. zdepthT(k)>z(j)) jump = jump+1
384        enddo
385     else
386        jump = -9
387     endif
388     if (zdepthT(k)>=0. .and. avdrho(k)*avdrho_old(k)<0.) then
389        write(34,*) '# zdepth arrested'
390        if (jump>1) write(34,*) '# previous step was too large',jump
391     endif
392!     write(34,'(f8.3,1x,f6.2,1x,f11.5,2(1x,g11.4),1x,i3)') &
393!          &        bigstep,latitude(k),zdepthT(k),avdrho(k),avdrhoP(k),jump
394     zdepth_old(k) = zdepthT(k)
395     avdrho_old(k) = avdrho(k)
396
397!----mode 2 growth
398     typeP = -9;  mode2 = .FALSE.
399     do j=1,nz
400        if (porefill(j,k)>0.) then
401           typeP = j  ! first point with ice
402           exit
403        endif
404     enddo
405     if (typeT>0 .and. typeP>2 .and. zdepthE(k)>0.) then
406        if (porefill(typeP,k)>=1. .and. porefill(typeP-1,k)==0. .and. &
407             & zdepthE(k)<z(typeP) .and. &
408             & z(typeP)-zdepthE(k)>2*(z(typeP)-z(typeP-1))) then  ! trick that avoids oscillations
409           deltaz = -avdrhoP(k)/z(typeP)*18./8314.*B  ! conservation of mass
410           if (deltaz>z(typeP)-z(typeP-1)) then  ! also implies avdrhoP<0.
411              mode2 = .TRUE.
412           endif
413        endif
414     endif
415
416     !call icechanges_poreonly(nz,z,typeF,typeG,avdrhoP(k),ypp,B,porefill(:,k))
417     call icechanges(nz,z(:),typeF,avdrho(k),avdrhoP(k),ypp(:), &
418          & Diff,porosity,icefrac,bigstep,zdepthT(k),porefill(:,k),typeG)
419     if (typeP>2) then
420     if (mode2 .and. porefill(typeP,k)>=1. .and. porefill(typeP-1,k)==0.) then  ! nothing changed
421        porefill(typeP-1,k)=1.  ! paste a layer
422   !     write(34,*) '# mode 2 growth occurred',typeP,typeF,typeT
423     endif
424     endif
425
426  enddo  ! end of big loop
427  !$omp end do
428  !$omp end parallel
429end subroutine icelayer_mars
430
431
432
433subroutine ajsub_mars(typeT, albedo0, pfrost, nz, z, ti, rhocv, &
434     &     fracIR, fracDust, patm, avdrho, avdrhoP, avrho1, &
435     &     Tb, zdepthE, typeF, zdepthF, ypp, porefill, Tmean1, Tmean3, &
436     &     B, typeG, zdepthG, avrho1prescribed)
437!***********************************************************************
438!  A 1D thermal model that returns various averaged quantities
439!
440!  Tb<0 initializes temperatures
441!  Tb>0 initializes temperatures with Tb
442!***********************************************************************
443  use constants_marspem_mod, only: sols_per_my, sec_per_sol
444  implicit none
445  integer, intent(IN) :: nz, typeT
446!  real(8), intent(IN) :: latitude  ! in radians
447  real(8), intent(IN) :: albedo0, pfrost, z(NMAX)
448  real(8), intent(IN) :: ti(NMAX), rhocv(NMAX), fracIR, fracDust, patm
449  real(8), intent(IN) ::  porefill(nz)
450  real(8), intent(OUT) :: avdrho, avdrhoP  ! difference in annual mean vapor density
451  real(8), intent(OUT) :: avrho1  ! mean vapor density on surface
452  real(8), intent(INOUT) :: Tmean1
453  real(8), intent(INOUT) :: Tb(nz)
454  integer, intent(OUT) :: typeF  ! index of depth below which filling occurs
455  real(8), intent(OUT) :: zdepthE, zdepthF
456  real(8), intent(OUT) :: ypp(nz) ! (d rho/dt)/Diff
457  real(8), intent(OUT) :: Tmean3, zdepthG
458  real(8), intent(IN) :: B  ! just passing through
459  integer, intent(OUT) :: typeG
460  real(8), intent(IN), optional :: avrho1prescribed
461  real(8), parameter :: a = 1.52366 ! Mars semimajor axis in A.U.
462  integer nsteps, n, i, nm, typeP
463  real(8) tmax, time, Qn, Qnp1, tdays
464  real(8) marsR, marsLs, marsDec, HA
465  real(8) Tsurf, Tco2frost, albedo, Fsurf, m, dE, emiss, T(NMAX)
466  real(8) Told(nz), Fsurfold, Tsurfold, Tmean0, avrho2
467  real(8) rhosatav0, rhosatav(nz), rlow
468
469  tmax = EQUILTIME*sols_per_my
470  nsteps = int(tmax/dt)     ! calculate total number of timesteps
471
472  Tco2frost = tfrostco2(patm)
473
474  !if (Tb<=0.) then  ! initialize
475     !Tmean0 = 210.15       ! black-body temperature of planet
476     !Tmean0 = (589.*(1.-albedo0)*cos(latitude)/(pi*emiss0*sigSB))**0.25 ! better estimate
477     !Tmean0 = Tmean0-5.
478     !write(34,*) '# initialized with temperature estimate at',latitude/d2r,'of',Tmean0,'K'
479     !T(1:nz) = Tmean0
480  !else
481     T(1:nz) = Tb
482     ! not so good when Fgeotherm is on
483  !endif
484
485  albedo = albedo0
486  emiss = emiss0
487  do i=1,nz
488     if (T(i)<Tco2frost) T(i)=Tco2frost
489  enddo
490  Tsurf = T(1)
491  m=0.; Fsurf=0.
492
493  nm=0
494  avrho1=0.; avrho2=0.
495  Tmean1=0.; Tmean3=0.
496  rhosatav0 = 0.
497  rhosatav(:) = 0.
498
499  time=0.
500  !call generalorbit(0.d0,a,ecc,omega,eps,marsLs,marsDec,marsR)
501  !HA = 2.*pi*time            ! hour angle
502!  Qn=flux(marsR,marsDec,latitude,HA,albedo,fracir,fracdust,0.d0,0.d0)
503  !Qn = flux_mars77(marsR,marsDec,latitude,HA,albedo,fracir,fracdust)
504  !----loop over time steps
505  do n=0,nsteps-1
506     time = (n+1)*dt         !   time at n+1
507   !  tdays = time*(sec_per_sol/earthDay) ! parenthesis may improve roundoff
508   !  call generalorbit(tdays,a,ecc,omega,eps,marsLs,marsDec,marsR)
509   !  HA = 2.*pi*mod(time,1.d0)  ! hour angle
510!     Qnp1=flux(marsR,marsDec,latitude,HA,albedo,fracir,fracdust,0.d0,0.d0)
511     !Qnp1 = flux_mars77(marsR,marsDec,latitude,HA,albedo,fracir,fracdust)
512
513     Tsurfold = Tsurf
514     Fsurfold = Fsurf
515     Told(1:nz) = T(1:nz)
516     if (m<=0. .or. Tsurf>Tco2frost) then
517       ! call conductionQ(nz,z,dt*sec_per_sol,Qn,Qnp1,T,ti,rhocv,emiss, &
518       !      &           Tsurf,Fgeotherm,Fsurf)
519     endif
520     if (Tsurf<Tco2frost .or. m>0.) then ! CO2 condensation
521        T(1:nz) = Told(1:nz)
522        !call conductionT(nz,z,dt*sec_per_sol,T,Tsurfold,Tco2frost,ti, &
523             !&              rhocv,Fgeotherm,Fsurf)
524        Tsurf = Tco2frost
525    !    dE = (- Qn - Qnp1 + Fsurfold + Fsurf + &
526    !         &      emiss*sigSB*(Tsurfold**4+Tsurf**4)/2.
527        m = m + dt*sec_per_sol*dE/Lco2frost
528     endif
529     if (Tsurf>Tco2frost .or. m<=0.) then
530        albedo = albedo0
531        emiss = emiss0
532     else
533        albedo = co2albedo
534        emiss = co2emiss
535     endif
536     !Qn=Qnp1
537
538     if (time>=tmax-sols_per_my) then
539        Tmean1 = Tmean1 + Tsurf
540        Tmean3 = Tmean3 + T(nz)
541        avrho1 = avrho1 + min(psv(Tsurf),pfrost)/Tsurf
542        rhosatav0 = rhosatav0 + psv(Tsurf)/Tsurf
543        do i=1,nz
544           rhosatav(i) = rhosatav(i) + psv(T(i))/T(i)
545        enddo
546        nm = nm+1
547     endif
548
549  enddo  ! end of time loop
550
551  avrho1 = avrho1/nm
552  if (present(avrho1prescribed)) then
553     if (avrho1prescribed>=0.) avrho1=avrho1prescribed
554  endif
555  Tmean1 = Tmean1/nm; Tmean3 = Tmean3/nm
556  rhosatav0 = rhosatav0/nm; rhosatav(:)=rhosatav(:)/nm
557  if (typeT>0) then
558     avrho2 = rhosatav(typeT)
559  else
560     avrho2 = rhosatav(nz) ! no ice
561  endif
562  avdrho = avrho2-avrho1
563  typeP = -9
564  do i=1,nz
565     if (porefill(i)>0.) then
566        typeP = i  ! first point with ice
567        exit
568     endif
569  enddo
570  if (typeP>0) then
571     avdrhoP = rhosatav(typeP) - avrho1
572  else
573     avdrhoP = -9999.
574  end if
575
576  zdepthE = equildepth(nz, z, rhosatav, rhosatav0, avrho1)
577
578  if (Fgeotherm>0.) then
579     !Tb = Tmean1
580     typeG = 1   ! will be overwritten by depths_avmeth
581     rlow = 2*rhosatav(nz)-rhosatav(nz-1)
582  else
583     !Tb = T(nz)
584     typeG = -9
585     rlow = rhosatav(nz-1)
586  endif
587  call depths_avmeth(typeT, nz, z, rhosatav(:), rhosatav0, rlow, avrho1,  &
588       & porefill(:), typeF, zdepthF, B, ypp(:), typeG, zdepthG)
589
590end subroutine ajsub_mars
591
592
593
594real*8 function tfrostco2(p)
595!     the inverse of function psvco2
596!     input is pressure in Pascal, output is temperature in Kelvin
597implicit none
598real*8 p
599tfrostco2 = 3182.48/(23.3494+log(100./p))
600end function
601
602!=======================================================================
603
604      real*8 function psv(T)
605!     saturation vapor pressure of H2O ice [Pascal]
606!     input is temperature [Kelvin]
607      implicit none
608      real*8 T
609
610!-----parametrization 1
611!      real*8 DHmelt,DHvap,DHsub,R,pt,Tt,C
612!      parameter (DHmelt=6008.,DHvap=45050.)
613!      parameter (DHsub=DHmelt+DHvap) ! sublimation enthalpy [J/mol]
614!      parameter (R=8.314,pt=6.11e2,Tt=273.16)
615!      C = (DHsub/R)*(1./T - 1./Tt)
616!      psv = pt*exp(-C)
617
618!-----parametrization 2
619!     eq. (2) in Murphy & Koop, Q. J. R. Meteor. Soc. 131, 1539 (2005)
620!     differs from parametrization 1 by only 0.1%
621      real*8 A,B
622      parameter (A=-6143.7, B=28.9074)
623      psv = exp(A/T+B)  ! Clapeyron
624
625!-----parametrization 3
626!     eq. (7) in Murphy & Koop, Q. J. R. Meteor. Soc. 131, 1539 (2005)
627!     psv = exp(9.550426 - 5723.265/T + 3.53068*log(T) - 0.00728332*T)
628
629      end function psv
630
631
632!=======================================================================
633!=========================== fast_subs_univ ============================
634!=======================================================================
635
636
637!*****************************************************
638! Commonly used subroutines for fast method
639! written by Norbert Schorghofer 2007-2011
640!*****************************************************
641
642pure function zint(y1,y2,z1,z2)
643  ! interpolate between two values, y1*y2<0
644  implicit none
645  real(8), intent(IN) :: y1,y2,z1,z2
646  real(8) zint
647  zint = (y1*z2 - y2*z1)/(y1-y2)
648end function zint
649
650
651
652pure function equildepth(nz, z, rhosatav, rhosatav0, avrho1)
653!***********************************************************************
654!  returns equilibrium depth for given ice content
655!  this is not the true (final) equilibrium depth
656!***********************************************************************
657  implicit none
658  integer, intent(IN) :: nz
659  real(8), intent(IN) :: z(nz), rhosatav(nz)
660  real(8), intent(IN) :: rhosatav0, avrho1
661  integer i, typeE
662  real(8) equildepth  ! =zdepthE
663  !real(8), external :: zint  ! defined in allinterfaces.mod
664
665  typeE = -9; equildepth = -9999.
666  do i=1,nz
667     if (rhosatav(i) <= avrho1) then
668        typeE=i
669        exit
670     endif
671  enddo
672  if (typeE>1) then ! interpolate
673     equildepth=zint(avrho1-rhosatav(typeE-1),avrho1-rhosatav(typeE),z(typeE-1),z(typeE))
674  end if
675  if (typeE==1) equildepth=zint(avrho1-rhosatav0,avrho1-rhosatav(1),0.d0,z(1))
676  if (equildepth>z(nz)) equildepth=-9999.   ! happens very rarely
677end function equildepth
678
679
680
681subroutine depths_avmeth(typeT, nz, z, rhosatav, rhosatav0, rlow, avrho1,  &
682     & porefill, typeF, zdepthF, B, ypp, typeG, zdepthG)
683!***********************************************************************
684!  returns interface depth and ypp
685!  also returns lower geothermally limited boundary, if applicable
686!
687!  this is a crucial subroutine
688!
689!  B = Diff*bigstep/(porosity*icedensity)  [SI units]
690!***********************************************************************
691  use math_toolkit, only: deriv2_simple, deriv1_onesided, deriv1, colint
692  use ice_table,    only: constriction
693  implicit none
694  integer, intent(IN) :: nz, typeT
695  real(8), intent(IN), dimension(nz) :: z, rhosatav, porefill
696  real(8), intent(IN) :: rhosatav0, rlow, avrho1
697  integer, intent(OUT) :: typeF  ! index of depth below which filling occurs
698  real(8), intent(INOUT) :: zdepthF
699  real(8), intent(IN) :: B
700  real(8), intent(OUT) :: ypp(nz), zdepthG
701  integer, intent(INOUT) :: typeG  ! positive on input when Fgeotherm>0
702
703  integer i, typeP, nlb, newtypeG
704  real(8) eta(nz), Jpump1, help(nz), yp(nz), zdepthFold, ap_one, ap(nz)
705  real(8) leak, cumfill, cumfillabove
706
707  if (typeT<0) then
708     nlb = nz
709     do i=1,nz
710        eta(i) = constriction(porefill(i))
711     enddo
712  else
713     !nlb = typeT-1
714     nlb = typeT ! changed 2010-09-29
715     do i=1,typeT-1
716        eta(i) = constriction(porefill(i))
717     enddo
718     do i=typeT,nz
719        eta(i)=0.
720     enddo
721  end if
722
723!-fill depth
724  zdepthFold = zdepthF
725  typeF = -9;  zdepthF = -9999.
726  call deriv1(z,nz,rhosatav,rhosatav0,rlow,yp)  ! yp also used below
727  do i=1,nlb
728     Jpump1 = (rhosatav(i)-avrho1)/z(i)  ! <0 when stable
729     ! yp is always <0
730     help(i) = Jpump1 - eta(i)*yp(i)
731     leak = porefill(i)/B*(z(i)-zdepthFold)/(18./8314.)
732     !help(i) = help(i)-leak   ! optional
733     if (help(i) <= 0.) then
734        typeF=i
735        !print *,'#',typeF,Jpump1,eta(typeF)*yp(typeF),leak
736        exit
737     endif
738  enddo
739  if (typeF>1) zdepthF = zint(help(typeF-1),help(typeF),z(typeF-1),z(typeF))
740  if (typeF==1) zdepthF=z(1)
741
742
743!-depth to shallowest perennial ice
744  typeP = -9
745  do i=1,nz
746     if (porefill(i)>0.) then
747        typeP = i  ! first point with ice
748        exit
749     endif
750  enddo
751
752!-calculate ypp
753  !call deriv1(z,nz,rhosatav,rhosatav0,rlow,yp)
754  call deriv1(z,nz,eta(:),1.d0,eta(nz-1),ap)
755  if (typeP>0 .and. typeP<nz-2) then
756     call deriv1_onesided(typeP,z,nz,eta(:),ap_one)
757     ! print *,typeP,ap(typeP),ap_one
758     ap(typeP)=ap_one
759  endif
760  call deriv2_simple(z,nz,rhosatav(1:nz),rhosatav0,rlow,ypp(:))
761  !call deriv2_full(z,nz,eta(:),rhosatav(:),1.d0,rhosatav0,rhosatav(nz-1),ypp(:))
762  !write(40,*) rhosatav
763  !write(41,*) yp
764  !write(42,*) ypp
765  ypp(:) = ap(:)*yp(1:)+eta(:)*ypp(:)
766  !write(43,*) ypp
767  !write(44,*) eta(1:nz)
768  !write(45,*) (rhosatav(:)-avrho1)/z(:)
769  ypp(:) = ypp(:)*18./8314.
770  ! ypp values beyond nlb should not be used
771
772!-geothermal stuff
773  if (typeT>0) typeG=-9
774  if (typeG<0) zdepthG=-9999.
775  if (typeG>0 .and. typeT<0) then
776     typeG=-9
777     do i=2,nz
778        if (yp(i)>0.) then  ! first point with reversed flux
779           typeG=i
780           zdepthG=zint(yp(i-1),yp(i),z(i-1),z(i))
781           !zdepthG=z(typeG)
782           exit
783        endif
784     enddo
785  else
786     typeG = -9
787  endif
788  if (typeG>0 .and. typeT<0) then
789     call colint(porefill(:)/eta(:),z,nz,typeG-1,nz,cumfillabove)
790     newtypeG = -9
791     do i=typeG,nz
792        if (minval(eta(i:nz))<=0.) cycle  ! eta=0 means completely full
793        call colint(porefill(:)/eta(:),z,nz,i,nz,cumfill)
794        if (cumfill<yp(i)*18./8314.*B) then  ! usually executes on i=typeG
795           if (i>typeG) then
796              write(34,*) '# adjustment to geotherm depth by',i-typeG
797              zdepthG = zint(yp(i-1)*18./8314.*B-cumfillabove, &  ! no good
798                   &        yp(i)*18./8314.*B-cumfill,z(i-1),z(i))
799              if (zdepthG>z(i) .or. zdepthG<z(i-1)) write(34,*) &
800                   & '# WARNING: zdepthG interpolation failed',i,z(i-1),zdepthG,z(i)
801              newtypeG=i
802           endif
803           ! otherwise leave zdepthG untouched
804           exit
805        endif
806        cumfillabove = cumfill
807     enddo
808     if (newtypeG>0) typeG=newtypeG
809  end if
810  ! if typeG>0, then all ice at and below typeG should be erased
811end subroutine depths_avmeth
812
813
814
815pure subroutine icechanges(nz,z,typeF,avdrho,avdrhoP,ypp, &
816     & Diff,porosity,icefrac,bigstep,zdepthT,porefill,typeG)
817!***********************************************************
818! advances ice table, advances interface, grows pore ice
819!
820! a crucial subroutine
821!***********************************************************
822  use math_toolkit, only: colint
823  use ice_table,    only: rho_ice
824  implicit none
825  integer, intent(IN) :: nz, typeF, typeG
826  real(8), intent(IN) :: z(nz), ypp(nz), avdrho, avdrhoP
827  real(8), intent(IN) :: Diff, porosity, icefrac, bigstep
828  real(8), intent(INOUT) :: zdepthT, porefill(nz)
829  integer j, erase, newtypeP, ub, typeP, typeT
830  real(8) B, beta, integ
831
832  B = Diff*bigstep*86400.*365.24/(porosity*927.)
833  !B = Diff*bigstep*86400.*365.24/(porosity*rho_ice(T,'h2o'))
834
835  ! advance ice table, avdrho>0 is retreat
836  if (zdepthT>=0. .and. avdrho>0.) then
837     typeP=-9999; typeT=-9999
838     do j=1,nz
839        if (z(j)>zdepthT) then
840           typeT=j
841           exit
842        endif
843     enddo
844     do j=1,nz
845        if (porefill(j)>0.) then
846           typeP=j
847           exit
848        endif
849     enddo
850     if (typeP==typeT) then   ! new 2011-09-01
851        beta = (1-icefrac)/(1-porosity)/icefrac
852        beta = Diff*bigstep*beta*86400*365.24/927.
853        !beta = Diff*bigstep*beta*86400*365.24/rho_ice(T,'h2o')
854        zdepthT = sqrt(2*beta*avdrho*18./8314. + zdepthT**2)
855     endif
856  endif
857  if (zdepthT>z(nz)) zdepthT=-9999.
858
859  ! advance interface, avdrhoP>0 is loss from zdepthP
860  if (avdrhoP>0.) then
861     erase=0
862     do j=1,nz
863        if (typeF>0 .and. j>=typeF) exit ! don't retreat beyond typeF
864        if (zdepthT>=0. .and. z(j)>zdepthT) exit
865        call colint(porefill(1:nz)*z(1:nz),z(1:nz),nz,1,j,integ)
866        erase = j
867        if (integ>B*avdrhoP*18./8314.) exit
868     end do
869     if (erase>0) porefill(1:erase)=0.
870  endif
871
872  ! new depth
873  newtypeP = -9
874  do j=1,nz
875     if (zdepthT>=0. .and. z(j)>zdepthT) exit
876     if (porefill(j)>0.) then
877        newtypeP = j  ! first point with pore ice
878        exit
879     endif
880  enddo
881
882  ! diffusive filling
883  ub = typeF
884  if (newtypeP>0 .and. typeF>0 .and. newtypeP<ub) ub=newtypeP
885  if (ub>0) then
886     do j=ub,nz
887        porefill(j) = porefill(j) + B*ypp(j)
888        if (porefill(j)<0.) porefill(j)=0.
889        if (porefill(j)>1.) porefill(j)=1.
890        if (zdepthT>=0. .and. z(j)>zdepthT) exit
891     enddo
892  end if
893
894  ! below icetable
895  if (zdepthT>=0.) then
896     do j=1,nz
897        if (z(j)>zdepthT) porefill(j) = icefrac/porosity
898     enddo
899  else
900     ! geothermal lower boundary
901     if (typeG>0) porefill(typeG:nz)=0.
902  end if
903end subroutine icechanges
904
905END MODULE subsurface_ice
Note: See TracBrowser for help on using the repository browser.