source: LMDZ6/branches/Amaury_dev/libf/dyn3d_common/disvert.F90 @ 5119

Last change on this file since 5119 was 5118, checked in by abarral, 4 months ago

Replace iniprint.h by lmdz_iniprint.f90
(lint) along the way

  • 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: 15.1 KB
Line 
1! $Id: disvert.F90 5118 2024-07-24 14:39:59Z abarral $
2
3SUBROUTINE disvert()
4
5  USE ioipsl, ONLY: getin
6  USE lmdz_new_unit, ONLY: new_unit
7  USE lmdz_assert, ONLY: assert
8  USE comvert_mod, ONLY: ap, bp, aps, bps, nivsigs, nivsig, dpres, presnivs, &
9                         pseudoalt, pa, preff, scaleheight, presinter
10  USE logic_mod, ONLY: ok_strato
11  USE lmdz_iniprint, ONLY: lunout, prt_level
12
13  IMPLICIT NONE
14
15  include "dimensions.h"
16  include "paramet.h"
17
18!-------------------------------------------------------------------------------
19! Purpose: Vertical distribution functions for LMDZ.
20!          Triggered by the levels number llm.
21!-------------------------------------------------------------------------------
22! Read    in "comvert_mod":
23
24! pa !--- vertical coordinate is close to a PRESSURE COORDINATE FOR P
25! < 0.3 * pa (relative variation of p on a model level is < 0.1 %)
26
27! preff                      !--- REFERENCE PRESSURE                 (101325 Pa)
28! Written in "comvert_mod":
29! ap(llm+1), bp(llm+1)       !--- Ap, Bp HYBRID COEFFICIENTS AT INTERFACES
30! aps(llm),  bps(llm)        !--- Ap, Bp HYBRID COEFFICIENTS AT MID-LAYERS
31! dpres(llm)                 !--- PRESSURE DIFFERENCE FOR EACH LAYER
32! presnivs(llm)              !--- PRESSURE AT EACH MID-LAYER
33! presinter(llm+1)           !--- PRESSURE AT EACH INTERFACE
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     aps(l) =  0.5 *( ap(l) +ap(l+1))
346     bps(l) =  0.5 *( bp(l) +bp(l+1))
347     presnivs(l) = 0.5 *( ap(l)+bp(l)*preff + ap(l+1)+bp(l+1)*preff )
348     pseudoalt(l) = log(preff/presnivs(l))*scaleheight
349     WRITE(lunout, *)'PRESNIVS(', l, ')=', presnivs(l), ' Z ~ ', &
350          pseudoalt(l) &
351          , ' DZ ~ ', scaleheight*log((ap(l)+bp(l)*preff)/ &
352          max(ap(l+1)+bp(l+1)*preff, 1.e-10))
353  ENDDO
354  DO l=1, llmp1
355     presinter(l)= ( ap(l)+bp(l)*preff)
356     WRITE(lunout, *)'PRESINTER(', l, ')=', presinter(l)
357  ENDDO
358
359  WRITE(lunout, *) trim(modname),': PRESNIVS '
360  WRITE(lunout, *) presnivs
361
362CONTAINS
363
364!-------------------------------------------------------------------------------
365
366FUNCTION ridders(sig) RESULT(sg)
367
368!-------------------------------------------------------------------------------
369  IMPLICIT NONE
370!-------------------------------------------------------------------------------
371! Purpose: Search for s solving (Pa/Preff)*s+(1-Pa/Preff)*EXP(1-1./s**2)=sg
372! Notes:   Uses Ridders' method, quite robust. Initial bracketing: 0<=sg<=1.
373! Reference: Ridders, C. F. J. "A New Algorithm for Computing a Single Root of a
374!       Real Continuous Function" IEEE Trans. Circuits Systems 26, 979-980, 1979
375!-------------------------------------------------------------------------------
376! Arguments:
377  REAL, INTENT(IN)  :: sig(:)
378  REAL              :: sg(SIZE(sig))
379!-------------------------------------------------------------------------------
380! Local variables:
381  INTEGER :: it, ns, maxit
382  REAL :: c1, c2, x1, x2, x3, x4, f1, f2, f3, f4, s, xx, distrib
383!-------------------------------------------------------------------------------
384  ns=SIZE(sig); maxit=9999
385  c1=Pa/Preff; c2=1.-c1
386  DO l=1,ns
387    xx=HUGE(1.)
388    x1=0.0; f1=distrib(x1,c1,c2,sig(l))
389    x2=1.0; f2=distrib(x2,c1,c2,sig(l))
390    DO it=1,maxit
391      x3=0.5*(x1+x2); f3=distrib(x3,c1,c2,sig(l))
392      s=SQRT(f3**2-f1*f2);                 IF(s==0.) EXIT
393      x4=x3+(x3-x1)*(SIGN(1.,f1-f2)*f3/s); IF(ABS(10.*LOG(x4-xx))<=1E-5) EXIT
394      xx=x4; f4=distrib(x4,c1,c2,sig(l));  IF(f4==0.) EXIT
395      IF(SIGN(f3,f4)/=f3) THEN;      x1=x3; f1=f3; x2=xx; f2=f4
396      ELSE IF(SIGN(f1,f4)/=f1) THEN; x2=xx; f2=f4
397      ELSE IF(SIGN(f2,f4)/=f2) THEN; x1=xx; f1=f4
398      ELSE; CALL abort_gcm("ridders",'Algorithm failed (which is odd...', 1)
399      END IF
400      IF(ABS(10.*LOG(ABS(x2-x1)))<=1E-5) EXIT       !--- ERROR ON SIG <= 0.01m           
401    END DO
402    IF(it==maxit+1) WRITE(lunout,'(a,i3)')'WARNING in ridder: failed to converg&
403  e for level ',l
404    sg(l)=xx
405  END DO
406  sg(1)=1.; sg(ns)=0.
407
408END FUNCTION ridders
409
410FUNCTION racinesig(sig) RESULT(sg)
411
412!-------------------------------------------------------------------------------
413  IMPLICIT NONE
414!-------------------------------------------------------------------------------
415! Fredho 2014/05/18
416! Purpose: Search for s solving (Pa/Preff)*sg+(1-Pa/Preff)*EXP(1-1./sg**2)=s
417! Notes:   Uses Newton Raphson search
418!-------------------------------------------------------------------------------
419! Arguments:
420  REAL, INTENT(IN)  :: sig(:)
421  REAL              :: sg(SIZE(sig))
422!-------------------------------------------------------------------------------
423! Local variables:
424  INTEGER :: it, ns, maxit
425  REAL :: c1, c2, x1, x2, x3, x4, f1, f2, f3, f4, s, xx, distrib
426!-------------------------------------------------------------------------------
427  ns=SIZE(sig); maxit=100
428  c1=Pa/Preff; c2=1.-c1
429  DO l=2,ns-1
430    sg(l)=sig(l)
431    DO it=1,maxit
432       f1=exp(1-1./sg(l)**2)*(1.-c1)
433       sg(l)=sg(l)-(c1*sg(l)+f1-sig(l))/(c1+2*f1*sg(l)**(-3))
434    ENDDO
435!   PRINT*,'SSSSIG ',sig(l),sg(l),c1*sg(l)+exp(1-1./sg(l)**2)*(1.-c1)
436  ENDDO
437  sg(1)=1.; sg(ns)=0.
438
439END FUNCTION racinesig
440
441
442
443
444END SUBROUTINE disvert
445
446!-------------------------------------------------------------------------------
447
448FUNCTION distrib(x,c1,c2,x0) RESULT(res)
449
450!-------------------------------------------------------------------------------
451! Arguments:
452  REAL, INTENT(IN) :: x, c1, c2, x0
453  REAL             :: res
454!-------------------------------------------------------------------------------
455  res=c1*x+c2*EXP(1-1/(x**2))-x0
456
457END FUNCTION distrib
458
459
Note: See TracBrowser for help on using the repository browser.