source: trunk/LMDZ.COMMON/libf/dyn3d_common/disvert.F90 @ 1403

Last change on this file since 1403 was 1391, checked in by emillour, 10 years ago

Common dynamical core:
Updates in the dynamics to keeup up with updates in LMDZ5
(up to LMDZ5 trunk rev 2200):

  • compilation:
  • create_make_gcm : added processing of .f & .f90 files (not just .F and .F90)
  • makelmdz: add "mix" option for -io (ouptut with both IOIPSL and XIOS)
  • makelmdz_fcm: add "mix" option for -io
  • filtrez:
  • acc.F and eigen.F : add "implicit none" and variable declarations
  • bibio:
  • handle_err_m.F90: replace "stop" with call to abort_gcm()
  • i1mach.F, j4save.F: add "implicit none" and variable declarations
  • xercnt.F, xermsg.F, xerprn.F, xersve.F, xgetua.F: add "implicit none" and variable declarations
  • dyn3d_common:
  • disvert.F90 : added comments on meaning of "pa" variable
  • grid_atob.F : better control on level of default ouputs
  • infotrac.F90: update Earth-specific stuff (nqo water tracers)
  • interpre.F: correction on the size of input array w
  • juldate.F, massbar.F, ppm3d.F, ran1.F: add "implicit none" and variable declarations
  • sortvarc.F: code cleanup
  • iniacademic.F90: cleanup and extra sanity check.
  • dyn3d:
  • abort_gcm.F: additions for XIOS
  • conf_gcm.F90: transformed to free form from conf_gcm.F
  • gcm.F: added test to check that iphysiq is a multiple of iperiod
  • getparam.F90, guidz_mod.F: update from LMDZ5
  • integrd.F: replace stop with call_abort()
  • dyn3dpar:
  • abort_gcm.F: minor cleanup
  • gcm.F: added test to check that iphysiq is a multiple of iperiod
  • getparam.F90, guide_p_mod.F90: update from LMDZ5
  • integrd_p.F: abort with call_abort when there is negative surface pressure
  • leapfrog_p.F: add INCA specific stuff to keep up with current LMDZ5
  • conf_gcm.F90: transformed to free form from conf_gcm.F

EM

File size: 14.8 KB
Line 
1! $Id: disvert.F90 1645 2012-07-30 16:01:50Z lguez $
2
3SUBROUTINE disvert()
4
5  ! Auteur : P. Le Van
6
7#ifdef CPP_IOIPSL
8  use ioipsl, only: getin
9#else
10  USE ioipsl_getincom, only: getin
11#endif
12  use new_unit_m, only: new_unit
13  use assert_m, only: assert
14
15  IMPLICIT NONE
16
17  include "dimensions.h"
18  include "paramet.h"
19  include "comvert.h"
20  include "comconst.h"
21  include "iniprint.h"
22  include "logic.h"
23
24!-------------------------------------------------------------------------------
25! Purpose: Vertical distribution functions for LMDZ.
26!          Triggered by the levels number llm.
27!-------------------------------------------------------------------------------
28! Read    in "comvert.h":
29
30! pa !--- vertical coordinate is close to a PRESSURE COORDINATE FOR P
31! < 0.3 * pa (relative variation of p on a model level is < 0.1 %)
32
33! preff                      !--- REFERENCE PRESSURE                 (101325 Pa)
34! Written in "comvert.h":
35! ap(llm+1), bp(llm+1)       !--- Ap, Bp HYBRID COEFFICIENTS AT INTERFACES
36! aps(llm),  bps(llm)        !--- Ap, Bp HYBRID COEFFICIENTS AT MID-LAYERS
37! dpres(llm)                 !--- PRESSURE DIFFERENCE FOR EACH LAYER
38! presnivs(llm)              !--- PRESSURE AT EACH MID-LAYER
39! scaleheight                !--- VERTICAL SCALE HEIGHT            (Earth: 8kms)
40! nivsig(llm+1)              !--- SIGMA INDEX OF EACH LAYER INTERFACE
41! nivsigs(llm)               !--- SIGMA INDEX OF EACH MID-LAYER
42!-------------------------------------------------------------------------------
43! Local variables:
44  REAL sig(llm+1), dsig(llm)
45  REAL sig0(llm+1), zz(llm+1)
46  REAL zk, zkm1, dzk1, dzk2, z, k0, k1
47
48  INTEGER l, unit
49  REAL dsigmin
50  REAL vert_scale,vert_dzmin,vert_dzlow,vert_z0low,vert_dzmid,vert_z0mid,vert_h_mid,vert_dzhig,vert_z0hig,vert_h_hig
51
52  REAL alpha, beta, deltaz
53  REAL x
54  character(len=*),parameter :: modname="disvert"
55
56  character(len=24):: vert_sampling
57  ! (allowed values are "param", "tropo", "strato" and "read")
58
59  !-----------------------------------------------------------------------
60
61  WRITE(lunout,*) TRIM(modname)//" starts"
62
63  ! default scaleheight is 8km for earth
64  scaleheight=8.
65
66  vert_sampling = merge("strato", "tropo ", ok_strato) ! default value
67  call getin('vert_sampling', vert_sampling)
68  WRITE(lunout,*) TRIM(modname)//' vert_sampling = ' // vert_sampling
69  if (llm==39 .and. vert_sampling=="strato") then
70     dsigmin=0.3 ! Vieille option par défaut pour CMIP5
71  else
72     dsigmin=1.
73  endif
74  call getin('dsigmin', dsigmin)
75  WRITE(LUNOUT,*) trim(modname), 'Discretisation verticale DSIGMIN=',dsigmin
76
77
78  select case (vert_sampling)
79  case ("param")
80     ! On lit les options dans sigma.def:
81     OPEN(99, file='sigma.def', status='old', form='formatted')
82     READ(99, *) scaleheight ! hauteur d'echelle 8.
83     READ(99, *) deltaz ! epaiseur de la premiere couche 0.04
84     READ(99, *) beta ! facteur d'acroissement en haut 1.3
85     READ(99, *) k0 ! nombre de couches dans la transition surf
86     READ(99, *) k1 ! nombre de couches dans la transition haute
87     CLOSE(99)
88     alpha=deltaz/(llm*scaleheight)
89     write(lunout, *)trim(modname),':scaleheight, alpha, k0, k1, beta', &
90                               scaleheight, alpha, k0, k1, beta
91
92     alpha=deltaz/tanh(1./k0)*2.
93     zkm1=0.
94     sig(1)=1.
95     do l=1, llm
96        sig(l+1)=(cosh(l/k0))**(-alpha*k0/scaleheight) &
97             *exp(-alpha/scaleheight*tanh((llm-k1)/k0) &
98                  *beta**(l-(llm-k1))/log(beta))
99        zk=-scaleheight*log(sig(l+1))
100
101        dzk1=alpha*tanh(l/k0)
102        dzk2=alpha*tanh((llm-k1)/k0)*beta**(l-(llm-k1))/log(beta)
103        write(lunout, *)l, sig(l+1), zk, zk-zkm1, dzk1, dzk2
104        zkm1=zk
105     enddo
106
107     sig(llm+1)=0.
108
109     bp(: llm) = EXP(1. - 1. / sig(: llm)**2)
110     bp(llmp1) = 0.
111
112     ap = pa * (sig - bp)
113  case("sigma")
114     DO l = 1, llm
115        x = 2*asin(1.) * (l - 0.5) / (llm + 1)
116        dsig(l) = dsigmin + 7.0 * SIN(x)**2
117     ENDDO
118     dsig = dsig / sum(dsig)
119     sig(llm+1) = 0.
120     DO l = llm, 1, -1
121        sig(l) = sig(l+1) + dsig(l)
122     ENDDO
123
124     bp(1)=1.
125     bp(2: llm) = sig(2:llm)
126     bp(llmp1) = 0.
127     ap(:)=0.
128  case("tropo")
129     DO l = 1, llm
130        x = 2*asin(1.) * (l - 0.5) / (llm + 1)
131        dsig(l) = dsigmin + 7.0 * SIN(x)**2
132     ENDDO
133     dsig = dsig / sum(dsig)
134     sig(llm+1) = 0.
135     DO l = llm, 1, -1
136        sig(l) = sig(l+1) + dsig(l)
137     ENDDO
138
139     bp(1)=1.
140     bp(2: llm) = EXP(1. - 1. / sig(2: llm)**2)
141     bp(llmp1) = 0.
142
143     ap(1)=0.
144     ap(2: llm + 1) = pa * (sig(2: llm + 1) - bp(2: llm + 1))
145  case("strato")
146     DO l = 1, llm
147        x = 2*asin(1.) * (l - 0.5) / (llm + 1)
148        dsig(l) =(dsigmin + 7. * SIN(x)**2) &
149             *(0.5*(1.-tanh(1.*(x-asin(1.))/asin(1.))))**2
150     ENDDO
151     dsig = dsig / sum(dsig)
152     sig(llm+1) = 0.
153     DO l = llm, 1, -1
154        sig(l) = sig(l+1) + dsig(l)
155     ENDDO
156
157     bp(1)=1.
158     bp(2: llm) = EXP(1. - 1. / sig(2: llm)**2)
159     bp(llmp1) = 0.
160
161     ap(1)=0.
162     ap(2: llm + 1) = pa * (sig(2: llm + 1) - bp(2: llm + 1))
163  case("strato_correct")
164!==================================================================
165! Fredho 2014/05/18, Saint-Louis du Senegal
166! Cette version de la discretisation strato est corrige au niveau
167! du passage des sig aux ap, bp
168! la version precedente donne un coude dans l'epaisseur des couches
169! vers la tropopause
170!==================================================================
171
172
173     DO l = 1, llm
174        x = 2*asin(1.) * (l - 0.5) / (llm + 1)
175        dsig(l) =(dsigmin + 7. * SIN(x)**2) &
176             *(0.5*(1.-tanh(1.*(x-asin(1.))/asin(1.))))**2
177     ENDDO
178     dsig = dsig / sum(dsig)
179     sig0(llm+1) = 0.
180     DO l = llm, 1, -1
181        sig0(l) = sig0(l+1) + dsig(l)
182     ENDDO
183     sig=racinesig(sig0)
184
185     bp(1)=1.
186     bp(2:llm)=EXP(1.-1./sig(2: llm)**2)
187     bp(llmp1)=0.
188
189     ap(1)=0.
190     ap(2:llm)=pa*(sig(2:llm)-bp(2:llm))
191     ap(llm+1)=0.
192
193  CASE("strato_custom0")
194!=======================================================
195! Version Transitoire
196    ! custumize strato distribution with specific alpha & beta values and function
197    ! depending on llm (experimental and temporary)!
198    SELECT CASE (llm)
199      CASE(55)
200        alpha=0.45
201        beta=4.0
202      CASE(63)
203        alpha=0.45
204        beta=5.0
205      CASE(71)
206        alpha=3.05
207        beta=65.
208      CASE(79)
209        alpha=3.20
210        ! alpha=2.05 ! FLOTT 79 (PLANTE)
211        beta=70.
212    END SELECT
213    ! Or used values provided by user in def file:
214    CALL getin("strato_alpha",alpha)
215    CALL getin("strato_beta",beta)
216   
217    ! Build geometrical distribution
218    scaleheight=7.
219    zz(1)=0.
220    IF (llm==55.OR.llm==63) THEN
221      DO l=1,llm
222        z=zz(l)/scaleheight
223        zz(l+1)=zz(l)+0.03+z*1.5*(1.-TANH(z-0.5))+alpha*(1.+TANH(z-1.5))     &
224                            +5.0*EXP((l-llm)/beta)
225      ENDDO
226    ELSEIF (llm==71) THEN !.OR.llm==79) THEN      ! FLOTT 79 (PLANTE)
227      DO l=1,llm
228        z=zz(l)
229        zz(l+1)=zz(l)+0.02+0.88*TANH(z/2.5)+alpha*(1.+TANH((z-beta)/15.))
230      ENDDO
231    ELSEIF (llm==79) THEN
232      DO l=1,llm
233        z=zz(l)
234        zz(l+1)=zz(l)+0.02+0.80*TANH(z/3.8)+alpha*(1+TANH((z-beta)/17.))     &
235                            +0.03*TANH(z/.25)
236      ENDDO
237    ENDIF ! of IF (llm==55.OR.llm==63) ...
238   
239
240    ! Build sigma distribution
241    sig0=EXP(-zz(:)/scaleheight)
242    sig0(llm+1)=0.
243!    sig=ridders(sig0)
244    sig=racinesig(sig0)
245   
246    ! Compute ap() and bp()
247    bp(1)=1.
248    bp(2:llm)=EXP(1.-1./sig(2:llm)**2)
249    bp(llm+1)=0.
250    ap=pa*(sig-bp)
251
252  CASE("strato_custom")
253!===================================================================
254! David Cugnet, François Lott, Lionel Guez, Ehouoarn Millour, Fredho
255! 2014/05
256! custumize strato distribution
257! Al the parameter are given in km assuming a given scalehigh
258    vert_scale=7.     ! scale hight
259    vert_dzmin=0.02   ! width of first layer
260    vert_dzlow=1.     ! dz in the low atmosphere
261    vert_z0low=8.     ! height at which resolution recches dzlow
262    vert_dzmid=3.     ! dz in the mid atmsophere
263    vert_z0mid=70.    ! height at which resolution recches dzmid
264    vert_h_mid=20.    ! width of the transition
265    vert_dzhig=11.    ! dz in the high atmsophere
266    vert_z0hig=80.    ! height at which resolution recches dz
267    vert_h_hig=20.    ! width of the transition
268!===================================================================
269
270    call getin('vert_scale',vert_scale)
271    call getin('vert_dzmin',vert_dzmin)
272    call getin('vert_dzlow',vert_dzlow)
273    call getin('vert_z0low',vert_z0low)
274    CALL getin('vert_dzmid',vert_dzmid)
275    CALL getin('vert_z0mid',vert_z0mid)
276    call getin('vert_h_mid',vert_h_mid)
277    call getin('vert_dzhig',vert_dzhig)
278    call getin('vert_z0hig',vert_z0hig)
279    call getin('vert_h_hig',vert_h_hig)
280
281    scaleheight=vert_scale ! for consistency with further computations
282    ! Build geometrical distribution
283    zz(1)=0.
284    DO l=1,llm
285       z=zz(l)
286       zz(l+1)=zz(l)+vert_dzmin+vert_dzlow*TANH(z/vert_z0low)+                &
287&      (vert_dzmid-vert_dzlow)* &
288&           (TANH((z-vert_z0mid)/vert_h_mid)-TANH((-vert_z0mid)/vert_h_mid)) &
289&     +(vert_dzhig-vert_dzmid-vert_dzlow)*                                  &
290&           (TANH((z-vert_z0hig)/vert_h_hig)-TANH((-vert_z0hig)/vert_h_hig))
291    ENDDO
292
293
294!===================================================================
295! Comment added Fredho 2014/05/18, Saint-Louis, Senegal
296! From approximate z to ap, bp, so that p=ap+bp*p0 and p/p0=exp(-z/H)
297! sig0 is p/p0
298! sig is an intermediate distribution introduce to estimate bp
299! 1.   sig0=exp(-z/H)
300! 2.   inversion of sig0=(1-pa/p0)*sig+(1-pa/p0)*exp(1-1/sig**2)
301! 3.   bp=exp(1-1/sig**2)
302! 4.   ap deduced from  the combination of 2 and 3 so that sig0=ap/p0+bp
303!===================================================================
304
305    sig0=EXP(-zz(:)/vert_scale)
306    sig0(llm+1)=0.
307    sig=racinesig(sig0)
308    bp(1)=1.
309    bp(2:llm)=EXP(1.-1./sig(2:llm)**2)
310    bp(llm+1)=0.
311    ap=pa*(sig-bp)
312
313  case("read")
314     ! Read "ap" and "bp". First line is skipped (title line). "ap"
315     ! should be in Pa. First couple of values should correspond to
316     ! the surface, that is : "bp" should be in descending order.
317     call new_unit(unit)
318     open(unit, file="hybrid.txt", status="old", action="read", &
319          position="rewind")
320     read(unit, fmt=*) ! skip title line
321     do l = 1, llm + 1
322        read(unit, fmt=*) ap(l), bp(l)
323     end do
324     close(unit)
325     call assert(ap(1) == 0., ap(llm + 1) == 0., bp(1) == 1., &
326          bp(llm + 1) == 0., "disvert: bad ap or bp values")
327  case default
328     call abort_gcm("disvert", 'Wrong value for "vert_sampling"', 1)
329  END select
330
331  DO l=1, llm
332     nivsigs(l) = REAL(l)
333  ENDDO
334
335  DO l=1, llmp1
336     nivsig(l)= REAL(l)
337  ENDDO
338
339  write(lunout, *)  trim(modname),': BP '
340  write(lunout, *) bp
341  write(lunout, *)  trim(modname),': AP '
342  write(lunout, *) ap
343
344  write(lunout, *) 'Niveaux de pressions approximatifs aux centres des'
345  write(lunout, *)'couches calcules pour une pression de surface =', preff
346  write(lunout, *) 'et altitudes equivalentes pour une hauteur d echelle de '
347  write(lunout, *) scaleheight,' km'
348  DO l = 1, llm
349     dpres(l) = bp(l) - bp(l+1)
350     presnivs(l) = 0.5 *( ap(l)+bp(l)*preff + ap(l+1)+bp(l+1)*preff )
351     write(lunout, *)'PRESNIVS(', l, ')=', presnivs(l), ' Z ~ ', &
352          log(preff/presnivs(l))*scaleheight &
353          , ' DZ ~ ', scaleheight*log((ap(l)+bp(l)*preff)/ &
354          max(ap(l+1)+bp(l+1)*preff, 1.e-10))
355  ENDDO
356
357  write(lunout, *) trim(modname),': PRESNIVS '
358  write(lunout, *) presnivs
359
360CONTAINS
361
362!-------------------------------------------------------------------------------
363!
364FUNCTION ridders(sig) RESULT(sg)
365!
366!-------------------------------------------------------------------------------
367  IMPLICIT NONE
368!-------------------------------------------------------------------------------
369! Purpose: Search for s solving (Pa/Preff)*s+(1-Pa/Preff)*EXP(1-1./s**2)=sg
370! Notes:   Uses Ridders' method, quite robust. Initial bracketing: 0<=sg<=1.
371! Reference: Ridders, C. F. J. "A New Algorithm for Computing a Single Root of a
372!       Real Continuous Function" IEEE Trans. Circuits Systems 26, 979-980, 1979
373!-------------------------------------------------------------------------------
374! Arguments:
375  REAL, INTENT(IN)  :: sig(:)
376  REAL              :: sg(SIZE(sig))
377!-------------------------------------------------------------------------------
378! Local variables:
379  INTEGER :: it, ns, maxit
380  REAL :: c1, c2, x1, x2, x3, x4, f1, f2, f3, f4, s, xx, distrib
381!-------------------------------------------------------------------------------
382  ns=SIZE(sig); maxit=9999
383  c1=Pa/Preff; c2=1.-c1
384  DO l=1,ns
385    xx=HUGE(1.)
386    x1=0.0; f1=distrib(x1,c1,c2,sig(l))
387    x2=1.0; f2=distrib(x2,c1,c2,sig(l))
388    DO it=1,maxit
389      x3=0.5*(x1+x2); f3=distrib(x3,c1,c2,sig(l))
390      s=SQRT(f3**2-f1*f2);                 IF(s==0.) EXIT
391      x4=x3+(x3-x1)*(SIGN(1.,f1-f2)*f3/s); IF(ABS(10.*LOG(x4-xx))<=1E-5) EXIT
392      xx=x4; f4=distrib(x4,c1,c2,sig(l));  IF(f4==0.) EXIT
393      IF(SIGN(f3,f4)/=f3) THEN;      x1=x3; f1=f3; x2=xx; f2=f4
394      ELSE IF(SIGN(f1,f4)/=f1) THEN; x2=xx; f2=f4
395      ELSE IF(SIGN(f2,f4)/=f2) THEN; x1=xx; f1=f4
396      ELSE; CALL abort_gcm("ridders",'Algorithm failed (which is odd...')
397      END IF
398      IF(ABS(10.*LOG(ABS(x2-x1)))<=1E-5) EXIT       !--- ERROR ON SIG <= 0.01m           
399    END DO
400    IF(it==maxit+1) WRITE(lunout,'(a,i3)')'WARNING in ridder: failed to converg&
401     &e for level ',l
402    sg(l)=xx
403  END DO
404  sg(1)=1.; sg(ns)=0.
405
406END FUNCTION ridders
407
408FUNCTION racinesig(sig) RESULT(sg)
409!
410!-------------------------------------------------------------------------------
411  IMPLICIT NONE
412!-------------------------------------------------------------------------------
413! Fredho 2014/05/18
414! Purpose: Search for s solving (Pa/Preff)*sg+(1-Pa/Preff)*EXP(1-1./sg**2)=s
415! Notes:   Uses Newton Raphson search
416!-------------------------------------------------------------------------------
417! Arguments:
418  REAL, INTENT(IN)  :: sig(:)
419  REAL              :: sg(SIZE(sig))
420!-------------------------------------------------------------------------------
421! Local variables:
422  INTEGER :: it, ns, maxit
423  REAL :: c1, c2, x1, x2, x3, x4, f1, f2, f3, f4, s, xx, distrib
424!-------------------------------------------------------------------------------
425  ns=SIZE(sig); maxit=100
426  c1=Pa/Preff; c2=1.-c1
427  DO l=2,ns-1
428    sg(l)=sig(l)
429    DO it=1,maxit
430       f1=exp(1-1./sg(l)**2)*(1.-c1)
431       sg(l)=sg(l)-(c1*sg(l)+f1-sig(l))/(c1+2*f1*sg(l)**(-3))
432    ENDDO
433!   print*,'SSSSIG ',sig(l),sg(l),c1*sg(l)+exp(1-1./sg(l)**2)*(1.-c1)
434  ENDDO
435  sg(1)=1.; sg(ns)=0.
436
437END FUNCTION racinesig
438
439
440
441
442END SUBROUTINE disvert
443
444!-------------------------------------------------------------------------------
445
446FUNCTION distrib(x,c1,c2,x0) RESULT(res)
447!
448!-------------------------------------------------------------------------------
449! Arguments:
450  REAL, INTENT(IN) :: x, c1, c2, x0
451  REAL             :: res
452!-------------------------------------------------------------------------------
453  res=c1*x+c2*EXP(1-1/(x**2))-x0
454
455END FUNCTION distrib
456
457
458
Note: See TracBrowser for help on using the repository browser.