source: LMDZ5/branches/testing/libf/dyn3d_common/disvert.F90 @ 2056

Last change on this file since 2056 was 2056, checked in by Laurent Fairhead, 10 years ago

Merged trunk changes r1997:2055 into testing branch

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