source: trunk/LMDZ.COMMON/libf/evolution/NS_fast_subs_univ.F90 @ 3525

Last change on this file since 3525 was 3493, checked in by jbclement, 3 weeks ago

PEM:

  • Renaming of Norbert Schorghofer's subroutines with the prefix 'NS_';
  • Making the extension of all NS's subroutines as '.F90';
  • Deletion of the wrapper subroutine;
  • Making the initialization, variables management and arguments of the main subroutine for the dynamic computation of ice table to be more suitable.

JBC

File size: 11.2 KB
Line 
1!*****************************************************
2! Commonly used subroutines for fast method
3! written by Norbert Schorghofer 2007-2011
4!*****************************************************
5
6pure function zint(y1,y2,z1,z2)
7  ! interpolate between two values, y1*y2<0
8  implicit none
9  real(8), intent(IN) :: y1,y2,z1,z2
10  real(8) zint
11  zint = (y1*z2 - y2*z1)/(y1-y2)
12end function zint
13
14
15
16pure function equildepth(nz, z, rhosatav, rhosatav0, avrho1)
17!***********************************************************************
18!  returns equilibrium depth for given ice content
19!  this is not the true (final) equilibrium depth
20!***********************************************************************
21  use allinterfaces, except_this_one => equildepth
22  implicit none
23  integer, intent(IN) :: nz
24  real(8), intent(IN) :: z(nz), rhosatav(nz)
25  real(8), intent(IN) :: rhosatav0, avrho1
26  integer i, typeE
27  real(8) equildepth  ! =zdepthE
28  !real(8), external :: zint  ! defined in allinterfaces.mod
29 
30  typeE = -9; equildepth = -9999.
31  do i=1,nz
32     if (rhosatav(i) <= avrho1) then
33        typeE=i
34        exit
35     endif
36  enddo
37  if (typeE>1) then ! interpolate
38     equildepth=zint(avrho1-rhosatav(typeE-1),avrho1-rhosatav(typeE),z(typeE-1),z(typeE))
39  end if
40  if (typeE==1) equildepth=zint(avrho1-rhosatav0,avrho1-rhosatav(1),0.d0,z(1))
41  if (equildepth>z(nz)) equildepth=-9999.   ! happens very rarely
42end function equildepth
43
44
45
46subroutine depths_avmeth(typeT, nz, z, rhosatav, rhosatav0, rlow, avrho1,  &
47     & porefill, typeF, zdepthF, B, ypp, typeG, zdepthG)
48!***********************************************************************
49!  returns interface depth and ypp
50!  also returns lower geothermally limited boundary, if applicable
51!
52!  this is a crucial subroutine
53!
54!  B = Diff*bigstep/(porosity*icedensity)  [SI units]
55!***********************************************************************
56  use allinterfaces, except_this_one => depths_avmeth
57  implicit none
58  integer, intent(IN) :: nz, typeT
59  real(8), intent(IN), dimension(nz) :: z, rhosatav, porefill
60  real(8), intent(IN) :: rhosatav0, rlow, avrho1
61  integer, intent(OUT) :: typeF  ! index of depth below which filling occurs
62  real(8), intent(INOUT) :: zdepthF
63  real(8), intent(IN) :: B
64  real(8), intent(OUT) :: ypp(nz), zdepthG
65  integer, intent(INOUT) :: typeG  ! positive on input when Fgeotherm>0
66
67  integer i, typeP, nlb, newtypeG
68  real(8) eta(nz), Jpump1, help(nz), yp(nz), zdepthFold, ap_one, ap(nz)
69  real(8) leak, cumfill, cumfillabove
70
71  if (typeT<0) then
72     nlb = nz
73     do i=1,nz
74        eta(i) = constriction(porefill(i))
75     enddo
76  else
77     !nlb = typeT-1
78     nlb = typeT ! changed 2010-09-29
79     do i=1,typeT-1
80        eta(i) = constriction(porefill(i))
81     enddo
82     do i=typeT,nz
83        eta(i)=0.
84     enddo
85  end if
86
87!-fill depth
88  zdepthFold = zdepthF
89  typeF = -9;  zdepthF = -9999.
90  call deriv1(z,nz,rhosatav,rhosatav0,rlow,yp)  ! yp also used below
91  do i=1,nlb
92     Jpump1 = (rhosatav(i)-avrho1)/z(i)  ! <0 when stable
93     ! yp is always <0
94     help(i) = Jpump1 - eta(i)*yp(i)
95     leak = porefill(i)/B*(z(i)-zdepthFold)/(18./8314.)
96     !help(i) = help(i)-leak   ! optional
97     if (help(i) <= 0.) then
98        typeF=i
99        !print *,'#',typeF,Jpump1,eta(typeF)*yp(typeF),leak
100        exit
101     endif
102  enddo
103  if (typeF>1) zdepthF = zint(help(typeF-1),help(typeF),z(typeF-1),z(typeF))
104  if (typeF==1) zdepthF=z(1)
105
106
107!-depth to shallowest perennial ice
108  typeP = -9
109  do i=1,nz
110     if (porefill(i)>0.) then
111        typeP = i  ! first point with ice
112        exit
113     endif
114  enddo
115
116!-calculate ypp
117  !call deriv1(z,nz,rhosatav,rhosatav0,rlow,yp)
118  call deriv1(z,nz,eta(:),1.d0,eta(nz-1),ap)
119  if (typeP>0 .and. typeP<nz-2) then
120     ap_one=deriv1_onesided(typeP,z,nz,eta(:))
121     ! print *,typeP,ap(typeP),ap_one
122     ap(typeP)=ap_one
123  endif
124  call deriv2_simple(z,nz,rhosatav(1:nz),rhosatav0,rlow,ypp(:))
125  !call deriv2_full(z,nz,eta(:),rhosatav(:),1.d0,rhosatav0,rhosatav(nz-1),ypp(:))
126  !write(40,*) rhosatav
127  !write(41,*) yp
128  !write(42,*) ypp
129  ypp(:) = ap(:)*yp(1:)+eta(:)*ypp(:)
130  !write(43,*) ypp
131  !write(44,*) eta(1:nz)
132  !write(45,*) (rhosatav(:)-avrho1)/z(:)
133  ypp(:) = ypp(:)*18./8314.
134  ! ypp values beyond nlb should not be used
135
136!-geothermal stuff
137  if (typeT>0) typeG=-9
138  if (typeG<0) zdepthG=-9999.
139  if (typeG>0 .and. typeT<0) then
140     typeG=-9
141     do i=2,nz
142        if (yp(i)>0.) then  ! first point with reversed flux
143           typeG=i
144           zdepthG=zint(yp(i-1),yp(i),z(i-1),z(i))
145           !zdepthG=z(typeG)
146           exit
147        endif
148     enddo
149  else
150     typeG = -9
151  endif
152  if (typeG>0 .and. typeT<0) then
153     cumfillabove = colint(porefill(:)/eta(:),z,nz,typeG-1,nz)
154     newtypeG = -9
155     do i=typeG,nz
156        if (minval(eta(i:nz))<=0.) cycle  ! eta=0 means completely full
157        cumfill=colint(porefill(:)/eta(:),z,nz,i,nz)
158        if (cumfill<yp(i)*18./8314.*B) then  ! usually executes on i=typeG
159           if (i>typeG) then
160              write(34,*) '# adjustment to geotherm depth by',i-typeG
161              zdepthG = zint(yp(i-1)*18./8314.*B-cumfillabove, &  ! no good
162                   &        yp(i)*18./8314.*B-cumfill,z(i-1),z(i))
163              if (zdepthG>z(i) .or. zdepthG<z(i-1)) write(34,*) &
164                   & '# WARNING: zdepthG interpolation failed',i,z(i-1),zdepthG,z(i)
165              newtypeG=i
166           endif
167           ! otherwise leave zdepthG untouched
168           exit
169        endif
170        cumfillabove = cumfill
171     enddo
172     if (newtypeG>0) typeG=newtypeG
173  end if
174  ! if typeG>0, then all ice at and below typeG should be erased
175end subroutine depths_avmeth
176
177
178
179pure function constriction(porefill)
180! specify constriction function here, 0<=eta<=1
181  implicit none
182  real(8), intent(IN) :: porefill
183  real(8) eta, constriction
184  if (porefill<=0.) eta = 1.
185  if (porefill>0. .and. porefill<1.) then
186     ! eta = 1.
187     ! eta = 1-porefill
188     eta = (1-porefill)**2  ! Hudson et al., JGR, 2009
189  endif
190  if (porefill>=1.) eta = 0.
191  constriction = eta
192end function constriction
193
194
195
196pure subroutine icechanges_poreonly(nz,z,typeF,typeG,avdrhoP,ypp,B,porefill)
197  use allinterfaces, except_this_one => icechanges_poreonly
198  implicit none
199  integer, intent(IN) :: nz, typeF, typeG
200  real(8), intent(IN) :: z(nz), ypp(nz), avdrhoP, B
201  real(8), intent(INOUT) :: porefill(nz)
202  integer j, erase, newtypeP, ub
203  real(8) integ
204 
205  !----retreat
206  ! avdrhoP>0 is outward loss from zdepthP
207  ! avdrhoP<0 means gain at zdepthP or no ice anywhere
208  if (avdrhoP>0.) then
209     erase=0
210     do j=1,nz
211        if (typeF>0 .and. j>=typeF) exit ! don't retreat beyond typeF
212        integ = colint(porefill(1:nz)*z(1:nz),z(1:nz),nz,1,j)
213        erase = j
214        if (integ>B*avdrhoP*18./8314.) exit
215     end do
216     if (erase>0) porefill(1:erase)=0.
217  endif
218
219  ! new depth
220  newtypeP = -9
221  do j=1,nz
222     if (porefill(j)>0.) then
223        newtypeP = j  ! first point with ice
224        exit
225     endif
226  enddo
227
228  !----diffusive filling
229  ub = typeF
230  if (newtypeP>0 .and. typeF>0 .and. newtypeP<ub) ub=newtypeP
231  if (ub>0) then 
232     do j=ub,nz
233        ! B=Diff/(porosity*icedensity)*86400*365.24*bigstep
234        porefill(j) = porefill(j) + B*ypp(j)
235        if (porefill(j)<0.) porefill(j)=0.
236        if (porefill(j)>1.) porefill(j)=1.
237     enddo
238  end if
239 
240  !----enact bottom boundary
241  if (typeG>0) porefill(typeG:nz)=0.
242 
243end subroutine icechanges_poreonly
244
245
246
247pure subroutine icechanges(nz,z,typeF,avdrho,avdrhoP,ypp, &
248     & Diff,porosity,icefrac,bigstep,zdepthT,porefill,typeG)
249!***********************************************************
250! advances ice table, advances interface, grows pore ice
251!
252! a crucial subroutine
253!***********************************************************
254  use miscparameters, only : icedensity
255  use allinterfaces, except_this_one => icechanges
256  implicit none
257  integer, intent(IN) :: nz, typeF, typeG
258  real(8), intent(IN) :: z(nz), ypp(nz), avdrho, avdrhoP
259  real(8), intent(IN) :: Diff, porosity, icefrac, bigstep
260  real(8), intent(INOUT) :: zdepthT, porefill(nz)
261  integer j, erase, newtypeP, ub, typeP, typeT
262  real(8) B, beta, integ
263
264  B = Diff*bigstep*86400.*365.24/(porosity*icedensity)
265
266  ! advance ice table, avdrho>0 is retreat
267  if (zdepthT>=0. .and. avdrho>0.) then
268     typeP=-9999; typeT=-9999
269     do j=1,nz
270        if (z(j)>zdepthT) then
271           typeT=j
272           exit
273        endif
274     enddo
275     do j=1,nz
276        if (porefill(j)>0.) then
277           typeP=j
278           exit
279        endif
280     enddo
281     if (typeP==typeT) then   ! new 2011-09-01
282        beta = (1-icefrac)/(1-porosity)/icefrac
283        beta = Diff*bigstep*beta*86400*365.24/icedensity
284        zdepthT = sqrt(2*beta*avdrho*18./8314. + zdepthT**2)
285     endif
286  endif
287  if (zdepthT>z(nz)) zdepthT=-9999.
288 
289  ! advance interface, avdrhoP>0 is loss from zdepthP
290  if (avdrhoP>0.) then
291     erase=0
292     do j=1,nz
293        if (typeF>0 .and. j>=typeF) exit ! don't retreat beyond typeF
294        if (zdepthT>=0. .and. z(j)>zdepthT) exit
295        integ = colint(porefill(1:nz)*z(1:nz),z(1:nz),nz,1,j)
296        erase = j
297        if (integ>B*avdrhoP*18./8314.) exit
298     end do
299     if (erase>0) porefill(1:erase)=0.
300  endif
301
302  ! new depth
303  newtypeP = -9
304  do j=1,nz
305     if (zdepthT>=0. .and. z(j)>zdepthT) exit
306     if (porefill(j)>0.) then
307        newtypeP = j  ! first point with pore ice
308        exit
309     endif
310  enddo
311
312  ! diffusive filling
313  ub = typeF
314  if (newtypeP>0 .and. typeF>0 .and. newtypeP<ub) ub=newtypeP
315  if (ub>0) then 
316     do j=ub,nz
317        porefill(j) = porefill(j) + B*ypp(j)
318        if (porefill(j)<0.) porefill(j)=0.
319        if (porefill(j)>1.) porefill(j)=1.
320        if (zdepthT>=0. .and. z(j)>zdepthT) exit
321     enddo
322  end if
323
324  ! below icetable
325  if (zdepthT>=0.) then
326     do j=1,nz
327        if (z(j)>zdepthT) porefill(j) = icefrac/porosity
328     enddo
329  else
330     ! geothermal lower boundary
331     if (typeG>0) porefill(typeG:nz)=0.
332  end if
333end subroutine icechanges
334
335
336subroutine assignthermalproperties(nz,thIn,rhoc, &
337     &    ti,rhocv,typeT,icefrac,porosity,porefill)
338!*********************************************************
339! assign thermal properties of soil
340!*********************************************************
341  implicit none
342  integer, intent(IN) :: nz
343  integer, intent(IN), optional :: typeT
344  real(8), intent(IN), optional :: icefrac
345  real(8), intent(IN) :: thIn, rhoc
346  real(8), intent(IN), optional :: porosity, porefill(nz)
347  real(8), intent(OUT) :: ti(nz), rhocv(nz)
348  integer j
349  real(8) newrhoc, newti, fill
350  real(8), parameter :: NULL=0.
351
352  ti(1:nz) = thIn
353  rhocv(1:nz) = rhoc
354  if (typeT>0) then
355     call soilthprop(porosity,NULL,rhoc,thIn,2,newrhoc,newti,icefrac)
356     rhocv(typeT:nz) = newrhoc
357     ti(typeT:nz) = newti
358  endif
359  do j=1,nz
360     fill = porefill(j)   ! off by half point
361     if (fill>0. .and. (typeT<0 .or. (typeT>0 .and. j<typeT))) then
362        call soilthprop(porosity,fill,rhoc,thIn,1,rhocv(j),ti(j),NULL)
363     endif
364  enddo
365end subroutine assignthermalproperties
366
367
368
369subroutine compactoutput(unit,porefill,nz)
370  implicit none
371  integer, intent(IN) :: unit,nz
372  real(8), intent(IN) :: porefill(nz)
373  integer j
374  do j=1,nz
375     if (porefill(j)==0.) then
376        write(unit,'(1x,f2.0)',advance='no') porefill(j)
377     else
378        write(unit,'(1x,f7.5)',advance='no') porefill(j)
379     endif
380  enddo
381  write(unit,"('')")
382end subroutine compactoutput
383
Note: See TracBrowser for help on using the repository browser.