1 | MODULE convection |
---|
2 | |
---|
3 | #include "use_logging.h" |
---|
4 | |
---|
5 | IMPLICIT NONE |
---|
6 | |
---|
7 | CONTAINS |
---|
8 | |
---|
9 | PURE SUBROUTINE sigma_levels(ngrid, nlay, i, pplev, ppopsk, sig, dsig, sdsig) |
---|
10 | INTEGER, INTENT(IN) :: ngrid, nlay, i |
---|
11 | REAL, INTENT(IN) :: pplev(ngrid,nlay+1), ppopsk(ngrid,nlay) |
---|
12 | REAL, INTENT(OUT) :: sig(nlay+1), dsig(nlay), sdsig(nlay) |
---|
13 | ! Calcul des niveaux sigma sur cette colonne |
---|
14 | INTEGER :: l |
---|
15 | DO l=1,nlay+1 |
---|
16 | sig(l)=pplev(i,l)/pplev(i,1) |
---|
17 | ENDDO |
---|
18 | DO l=1,nlay |
---|
19 | dsig(l)=sig(l)-sig(l+1) |
---|
20 | sdsig(l)=ppopsk(i,l)*dsig(l) |
---|
21 | ENDDO |
---|
22 | END SUBROUTINE sigma_levels |
---|
23 | |
---|
24 | SUBROUTINE adjust_onecolumn(ngrid, nlay, i, sig, dsig, sdsig, zu2, zv2, zh2) |
---|
25 | INTEGER, INTENT(IN) :: ngrid, nlay, i |
---|
26 | REAL, INTENT(OUT) :: sig(nlay+1), sdsig(nlay), dsig(nlay) |
---|
27 | REAL, INTENT(INOUT) :: zu2(ngrid,nlay), zv2(ngrid,nlay), zh2(ngrid,nlay) |
---|
28 | |
---|
29 | INTEGER :: l,l1,l2 |
---|
30 | LOGICAL :: extend |
---|
31 | REAL :: zhm,zsm,zum,zvm,zalpha |
---|
32 | |
---|
33 | l2=1 |
---|
34 | DO WHILE( l2<nlay ) |
---|
35 | l2 = l2+1 |
---|
36 | ! starting from l1=l2, we shall extend l1..l2 downwards and upwards |
---|
37 | ! until zhm = potential temperature mass-weighted over l1..l2 be |
---|
38 | ! higher than pot. temp. at level l1-1 |
---|
39 | ! and lower than pot. temp. at level l2+1 |
---|
40 | ! for this we incrementally compute zsm = mass of layers l1 .. l2 and zhm |
---|
41 | zsm = sdsig(l2) |
---|
42 | zhm = zh2(i, l2) |
---|
43 | l1 = l2 |
---|
44 | extend = .TRUE. |
---|
45 | DO WHILE(extend) |
---|
46 | ! extend downwards if l1>1 and zhm is lower than layer l1-1 |
---|
47 | extend = .FALSE. |
---|
48 | IF (l1 > 1) THEN |
---|
49 | IF (zhm < zh2(i, l1-1)) extend = .TRUE. |
---|
50 | END IF |
---|
51 | IF(extend) THEN |
---|
52 | l1 = l1-1 |
---|
53 | zsm = zsm + sdsig(l1) |
---|
54 | zhm = zhm + sdsig(l1) * (zh2(i, l1) - zhm) / zsm |
---|
55 | CYCLE |
---|
56 | END IF |
---|
57 | ! extend upwards if l2<nlay and zhm is higher than layer l2+1 |
---|
58 | extend=.FALSE. |
---|
59 | IF (l2 < nlay) THEN |
---|
60 | IF (zh2(i, l2+1) < zhm) extend=.TRUE. |
---|
61 | END IF |
---|
62 | IF(extend) THEN |
---|
63 | l2 = l2+1 |
---|
64 | zsm = zsm + sdsig(l2) |
---|
65 | zhm = zhm + sdsig(l2) * (zh2(i, l2) - zhm) / zsm |
---|
66 | END IF |
---|
67 | END DO |
---|
68 | |
---|
69 | ! at this point the profile l1-1 (l1 ...l2) l2+1 is stable |
---|
70 | |
---|
71 | IF(l1<l2) THEN |
---|
72 | WRITELOG(*,*) 'Mixing between layers ',l1,l2 |
---|
73 | LOG_DBG('convadj') |
---|
74 | ! perform the mixing of layers l1...l2 : |
---|
75 | ! * potential temperature is fully mixed, ie replaced by mass-weighted average |
---|
76 | ! * momentum u,v is mixed with weight zalpha, i.e. u:=zalpha*mean(u)+(1-zalpha)*u |
---|
77 | ! where zalpha = sum( abs(theta-mean(theta))*dsig) / mean(theta)*sum(dsig) |
---|
78 | ! for large deviations of theta from its mean, this formula could in principe yield zalpha>1. |
---|
79 | zalpha=0. |
---|
80 | zum=0. |
---|
81 | zvm=0. |
---|
82 | DO l = l1, l2 |
---|
83 | zalpha=zalpha+ABS(zh2(i,l)-zhm)*dsig(l) |
---|
84 | zh2(i, l) = zhm |
---|
85 | ! we must use compute zum, zvm from zu2, zv2 to conserve momentum (see below) |
---|
86 | zum=zum+dsig(l)*zu2(i,l) |
---|
87 | zvm=zvm+dsig(l)*zv2(i,l) |
---|
88 | END DO |
---|
89 | zalpha=zalpha/(zhm*(sig(l1)-sig(l2+1))) |
---|
90 | zum=zum/(sig(l1)-sig(l2+1)) |
---|
91 | zvm=zvm/(sig(l1)-sig(l2+1)) |
---|
92 | IF(zalpha.GT.1.) THEN |
---|
93 | WRITELOG(*,*) 'zalpha=',zalpha |
---|
94 | CALL log_gridpoint(i) |
---|
95 | LOG_WARN('convadj') |
---|
96 | STOP |
---|
97 | END IF |
---|
98 | IF(zalpha.LT.1.e-5) zalpha=1.e-5 |
---|
99 | ! zum, zvm are mass-weighted averages of zu2, zv2 => mixing preserves total momentum |
---|
100 | DO l=l1,l2 |
---|
101 | zu2(i,l)=zu2(i,l)+zalpha*(zum-zu2(i,l)) |
---|
102 | zv2(i,l)=zv2(i,l)+zalpha*(zvm-zv2(i,l)) |
---|
103 | ENDDO |
---|
104 | END IF |
---|
105 | |
---|
106 | END DO |
---|
107 | |
---|
108 | END SUBROUTINE adjust_onecolumn |
---|
109 | |
---|
110 | SUBROUTINE convadj(ngrid,nlay,ptimestep, & |
---|
111 | & pplay,pplev,ppopsk, & |
---|
112 | & pu,pv,ph, & |
---|
113 | & pdufi,pdvfi,pdhfi, & |
---|
114 | & pduadj,pdvadj,pdhadj) |
---|
115 | |
---|
116 | !======================================================================= |
---|
117 | ! |
---|
118 | ! dry convective adjustment |
---|
119 | ! h = pot. temp. , static instability if ph(above)<ph(below) |
---|
120 | ! tendencies pdfX are first added to profiles pX, X=u,v,h, yieldig pX2 |
---|
121 | ! adjustment is performed on profiles pX2 |
---|
122 | ! then the difference between adjusted and non-adujsted profiles |
---|
123 | ! is converted back as tendencies |
---|
124 | ! |
---|
125 | !======================================================================= |
---|
126 | |
---|
127 | INTEGER, INTENT(IN) :: ngrid,nlay |
---|
128 | REAL, INTENT(IN) :: ptimestep |
---|
129 | REAL, INTENT(IN) :: pplay(ngrid,nlay), pplev(ngrid,nlay+1), ppopsk(ngrid,nlay) |
---|
130 | REAL, INTENT(IN) :: ph(ngrid,nlay), pu(ngrid,nlay), pv(ngrid,nlay), & |
---|
131 | & pdhfi(ngrid,nlay), pdufi(ngrid,nlay), pdvfi(ngrid,nlay) |
---|
132 | REAL, INTENT(OUT) :: pdhadj(ngrid,nlay), pduadj(ngrid,nlay), pdvadj(ngrid,nlay) |
---|
133 | |
---|
134 | ! local: |
---|
135 | REAL sig(nlay+1),sdsig(nlay),dsig(nlay) |
---|
136 | REAL zu(ngrid,nlay), zv(ngrid,nlay), zh(ngrid,nlay) |
---|
137 | REAL zu2(ngrid,nlay), zv2(ngrid,nlay), zh2(ngrid,nlay) |
---|
138 | LOGICAL vtest(ngrid) |
---|
139 | INTEGER jadrs(ngrid) |
---|
140 | INTEGER jcnt, ig, l, jj |
---|
141 | |
---|
142 | ! Add physics tendencies to u,v,h |
---|
143 | DO l=1,nlay |
---|
144 | DO ig=1,ngrid |
---|
145 | zh(ig,l)=ph(ig,l)+pdhfi(ig,l)*ptimestep |
---|
146 | zu(ig,l)=pu(ig,l)+pdufi(ig,l)*ptimestep |
---|
147 | zv(ig,l)=pv(ig,l)+pdvfi(ig,l)*ptimestep |
---|
148 | END DO |
---|
149 | END DO |
---|
150 | zu2(:,:)=zu(:,:) |
---|
151 | zv2(:,:)=zv(:,:) |
---|
152 | zh2(:,:)=zh(:,:) |
---|
153 | |
---|
154 | !----------------------------------------------------------------------- |
---|
155 | ! detection des profils a modifier: |
---|
156 | ! --------------------------------- |
---|
157 | ! si le profil est a modifier |
---|
158 | ! (i.e. ph(niv_sup) < ph(niv_inf) ) |
---|
159 | ! alors le tableau "vtest" est mis a .TRUE. ; |
---|
160 | ! sinon, il reste a sa valeur initiale (.FALSE.) |
---|
161 | ! cette operation est vectorisable |
---|
162 | |
---|
163 | vtest(:)=.FALSE. |
---|
164 | DO l=2,nlay |
---|
165 | DO ig=1,ngrid |
---|
166 | IF(zh2(ig,l).LT.zh2(ig,l-1)) vtest(ig)=.TRUE. |
---|
167 | END DO |
---|
168 | END DO |
---|
169 | |
---|
170 | !---------------------------------- |
---|
171 | ! Ajustement des profils instables |
---|
172 | ! -------------------------------- |
---|
173 | |
---|
174 | DO ig=1,ngrid |
---|
175 | IF(vtest(ig)) THEN |
---|
176 | CALL sigma_levels(ngrid, nlay, ig, pplev, ppopsk, sig, dsig, sdsig) |
---|
177 | CALL adjust_onecolumn(ngrid, nlay, ig, sig, dsig, sdsig, zu2, zv2, zh2) |
---|
178 | ENDIF |
---|
179 | END DO |
---|
180 | |
---|
181 | DO l=1,nlay |
---|
182 | DO ig=1,ngrid |
---|
183 | pdhadj(ig,l)=(zh2(ig,l)-zh(ig,l))/ptimestep |
---|
184 | pduadj(ig,l)=(zu2(ig,l)-zu(ig,l))/ptimestep |
---|
185 | pdvadj(ig,l)=(zv2(ig,l)-zv(ig,l))/ptimestep |
---|
186 | END DO |
---|
187 | END DO |
---|
188 | |
---|
189 | END SUBROUTINE convadj |
---|
190 | |
---|
191 | END MODULE convection |
---|