Canoe
Comprehensive Atmosphere N' Ocean Engine
qe_moist_convection.f90
Go to the documentation of this file.
2 
3 !16/02/09
4 
5 use simple_sat_vapor_pres_mod, only: escomp, descomp
6 
7 use constants_mod, only: grav, rdgas, rvgas, kappa, latent_heat, &
8  cp_air, cp_vapor, cp_water
9 
10 implicit none
11 private
12 
14 
15 !real(8) :: tau_bm = 7200.
16 
17 real(8), public, parameter :: d622 = rdgas/rvgas
18 real(8), public, parameter :: d378 = 1.-d622
19 real(8), public, parameter :: d608 = d378/d622
20 !##==============================================
21 !##==============================================
22 contains
23 
24 subroutine compute_geopotential(t, q, p_half, p_full, z_full, z_half)
25 
26 real(8), intent(in), dimension(:) :: t, q, p_full
27 real(8), intent(in), dimension(:) :: p_half
28 real(8), intent(out), dimension(:) :: z_full
29 real(8), intent(out), dimension(:) :: z_half
30 
31 integer :: n, k
32 real(8) :: virtual_t
33 
34 n = size(t)
35 z_half(n+1) = 0.
36  !virtual_t = t * (1. + d608 * q)
37  !for k in range(len(z_full) - 1, 0, -1):
38  do k = n, 2, -1
39  virtual_t = t(k) * (1. + d608 * q(k))
40  z_half(k) = z_half(k+1) + rdgas* virtual_t *&
41  (log(p_half(k+1) / p_half(k)))
42 
43  z_full(k) = z_half(k+1) + rdgas* virtual_t *&
44  (log(p_half(k+1) / p_full(k)))
45  end do
46 
47  virtual_t = t(1) * (1. + d608 * q(1))
48  z_full(1) = z_half(2) + rdgas* virtual_t *&
49  (log(p_half(2) / p_full(1)))
50  z_half(1) = 0.
51  !return z_full, z_half
52 end subroutine compute_geopotential
53 !##==============================================
54 !hc = 1.
55 !do_evap = False
56 
57 subroutine qsat(T,p, qs)
58 
59 real(8), intent(in) :: t, p
60 real(8), intent(out) :: qs
61 real(8) :: esat
62  call escomp(t, esat)
63  qs = 1.
64  if (esat .le. p) qs = d622 * esat / (p - d378 * esat)
65  !return qs
66 end subroutine qsat
67 
68 subroutine dqsatdt(T,p,dqs)
69 
70 real(8), intent(in) :: T, p
71 real(8), intent(out):: dqs
72 real(8) :: esat, desat
73  call escomp(t, esat)
74  call descomp(t, desat)
75  dqs = 1.e6
76  if ( esat .le. p) dqs = d622 * p / (p - d378 * esat)**2 * desat
77 end subroutine dqsatdt
78 
79 !#considering liquid in the air
80 subroutine rsat(T,p, rs)
81 
82 real(8), intent(in) :: T, p
83 real(8), intent(out):: rs
84 real(8) :: esat
85  call escomp(t, esat)
86  rs = 0. !-1e5
87  if (esat .le. p) rs = d622 * esat / (p - esat)
88 end subroutine rsat
89 
90 subroutine drsatdt(T,p, drs)
91 
92 real(8), intent(in) :: T, p
93 real(8), intent(out):: drs
94 real(8) :: esat, desat
95  call escomp(t, esat)
96  call descomp(t, desat)
97  if ( esat .le. p) drs = d622 * p / (p - esat)**2 * desat
98 end subroutine drsatdt
99 
100 subroutine ff(dT, dp1, dp2, p1, p2, Dry_m, kini, x, val, lmass1,lmass2)
101 real(8), intent(in) :: dT, dp1, dp2, p1, p2, Dry_m, kini, x
102 real(8), intent(out):: val, lmass1, lmass2
103 real(8) :: t1n, t2n, yy, r1n, r2n, lh, rt1, rt2, &
104  dmass1, dmass2, kfin
105 
106 t2n = x - dt
107 t1n = x !t2n + dT
108 call rsat(t1n, p1, r1n)
109 call rsat(t2n, p2, r2n)
110 yy = (dp1/(1.+r1n) + dp2/(1.+r2n))/dry_m -1.
111 rt1 = r1n + yy * (1.+r1n)
112 rt2 = r2n + yy * (1.+r2n)
113 
114 dmass1 = dp1 / (1.+rt1) !*(rt1 - r1n)
115 dmass2 = dp2 / (1.+rt2) !*(rt2 - r2n)
116 lmass1 = dp1 / (1.+rt1) *(rt1 - r1n)
117 lmass2 = dp2 / (1.+rt2) *(rt2 - r2n)
118 
119 !final moist enthalpy
120 kfin = cp_air * (dmass2*t2n+dmass1*t1n) + &
121  cp_water*(dmass2*rt2*t2n + dmass1*rt1*t1n)
122 call latent_heat(t2n, lh)
123 kfin = kfin + lh*dmass2*r2n
124 call latent_heat(t1n, lh)
125 kfin = kfin + lh*dmass1*r1n
126 !print *, kfin
127 
128 val = kfin - kini
129 
130 end subroutine ff
131 
132 subroutine newtsolve_ff(dT, dp1, dp2, &
133  q1, q2, T1, T2, p1, p2, T1new, T2new, lmass1, lmass2)
134 real(8), intent(in) :: dT, dp1, dp2, q1, q2, T1, T2, &
135  p1, p2
136 real(8), intent(out):: T1new, T2new, lmass1, lmass2
137 real(8) :: x, val, x1, val1, x2, val2, deriv
138 real(8) :: Dry_m, kini, lh
139 real(8) :: epss = 1.e-7
140 integer :: nmax = 100, n
141 
142 !Dry air mass in the two layers
143 dry_m = dp1*(1.-q1) + dp2*(1. - q2)
144 !initial moist enthalpy
145 kini = cp_air * (dp2*(1-q2)*t2+dp1*(1-q1)*t1) + &
146  cp_water*(dp2*q2*t2 + dp1*q1*t1)
147 call latent_heat(t2, lh)
148 kini = kini + lh*dp2*q2
149 call latent_heat(t1, lh)
150 kini = kini + lh*dp1*q1
151 
152  x = t1 !2
153  x1 = x - 0.1
154  val = 10.
155  n = 0
156  do while (abs(val) .gt. 1.e-3)
157  call ff(dt, dp1, dp2, p1, p2, dry_m, kini, x, val, lmass1,lmass2)
158 
159  x1 = x + epss
160  call ff(dt, dp1, dp2, p1, p2, dry_m, kini, x1, val1, lmass1,lmass2)
161  x2 = x - epss
162  call ff(dt, dp1, dp2, p1, p2, dry_m, kini, x2, val2, lmass1,lmass2)
163  deriv = (val1 - val2) / 2./ epss
164  !deriv = (val1 - val) / (x1 - x)
165  !x1 = x
166  x = x - val / deriv
167  !print *, val, deriv, x
168 
169  n = n+1
170  if (n > nmax) then
171  print *, 'does not converge', x, lmass1
172  lmass1 = -1e5
173  exit
174  end if
175  end do
176 
177  t2new = x - dt
178  t1new = x !+ dT
179  call ff(dt, dp1, dp2, p1, p2, dry_m, kini, x, val, lmass1, lmass2)
180  !print *, 'final: ', val, deriv, x
181 
182  call rsat(t1new, p1, val1)
183  if (val1 .le. 0) lmass1 = -1e5
184 end subroutine newtsolve_ff
185 
186 !=====================================================================
187 
188 subroutine compute_k(tin,qin,phalf, k)
189 
190 real(8), intent(in), dimension(:) :: tin, qin
191 real(8), intent(in), dimension(:) :: phalf
192 real(8), intent(out) :: k
193 real(8) :: kpum
194 integer :: i
195  k = 0.
196  do i = 1, size(tin)
197  kpum = (cp_air*(1 - qin(i)) + cp_vapor*qin(i))*tin(i)
198  k = k + kpum * (phalf(i+1) - phalf(i)) / grav
199  end do
200  !return sum(k* (phalf[1:] - phalf[:-1])/cons.grav)
201 end subroutine compute_k
202 
203 !#initial profile
204 subroutine dlnpdlnt_initial(lnT,lnp, slope)
205 
206 real(8), intent(in) :: lnT, lnp
207 real(8), intent(out):: slope
208 real(8) :: T, p, qs, D, rs, pa, es, A, B, C, ll
209 
210  t = exp(lnt)
211  p = exp(lnp)
212 
213  call qsat(t,p, qs)
214  call latent_heat(t, ll)
215  d = ll / (rvgas * t)
216 
217  if (qs .eq. 1) then
218  slope = d
219  else
220  rs = qs / (1. - qs)
221  pa = p / (rs /d622 + 1.)
222  es = p - pa
223  a = ll * rs / rdgas / t
224  b = rs * (cp_vapor / cp_air + &
225  (ll / rvgas / t-1.) * ll / cp_air / t)
226  c = 1. / (kappa * (1. + a) / (1. + b)) !#dlnpa / dlnT
227 
228  slope = (pa * c + es * d) / p
229  end if
230 end subroutine dlnpdlnt_initial
231 
232 
233 subroutine rk4_f(x0, y0, dx, nx, x, y)
234 
235 real(8), intent(in) :: x0, y0, dx
236 integer, intent(in) :: nx
237 real(8), intent(out), dimension(nx+1) :: x, y
238 integer :: n
239 real(8) :: k1, k2, k3, k4
240 
241 x(1) = x0
242 y(1) = y0
243 
244 do n = 1, nx
245  call dlnpdlnt_initial(x(n), y(n), k1)
246  call dlnpdlnt_initial(x(n) + dx/2., y(n) + dx/2.*k1, k2)
247  call dlnpdlnt_initial(x(n) + dx/2., y(n) + dx/2.*k2, k3)
248  call dlnpdlnt_initial(x(n) + dx, y(n) + dx *k3, k4)
249  x(n+1) = x(n) + dx
250  y(n+1) = y(n) + dx/6.*(k1+k4 + 2.*(k2+k3))
251 end do
252 end subroutine rk4_f
253 
254 subroutine warm_start(ts, pd, nx, psg, tt, lnpp, qs)
255 real(8), intent(in) :: ts, pd
256 integer, intent(in) :: nx
257 real(8), intent(out):: psg
258 real(8), intent(out), dimension(nx+1) :: tt, lnpp, qs
259 integer :: i
260 real(8) :: psc, x1, x2, dx
261 real(8), dimension(nx+1) :: lntlist, lnplist, lntt, pp
262 
263  call escomp(ts, psc)
264  psg = pd + psc !sat.escomp(ts)
265 
266  x1 = log(ts)
267  x2 = log(20.)
268  !nx = 400
269  dx = (x2 - x1) /nx
270  call rk4_f(x1, log(psg), dx, nx, lntlist, lnplist)
271  do i = 1, nx+1
272  lntt(i) = lntlist(nx+2-i)
273  lnpp(i) = lnplist(nx+2-i)
274  end do
275  tt = exp(lntt)
276  pp = exp(lnpp)
277  do i = 1, nx+1
278  call qsat(tt(i), pp(i), qs(i))
279  end do
280  !lntlist = [x1]
281  !lnplist = [np.log(psg)]
282  !int_g = integrator(dlnpdlnT_initial, x1, np.log(psg), dx)
283  !for i in range(nx):
284  !lnt, lnp = int_g.next()
285  !lntlist.append(lnt)
286  !lnplist.append(lnp)
287  !lntlist.reverse()
288  !lnplist.reverse()
289  !lntt = np.array(lntlist)
290  !lnpp = np.array(lnplist)
291  !tt = np.exp(lntt)
292  !pp = np.exp(lnpp)
293  !qs = tt *1.
294  !for i in range(len(tt)):
295  ! qs[i] = cond.qsat(tt[i], pp[i])
296 
297  !return psg, tt, lnpp, qs
298 end subroutine warm_start
299 
300 !#==================================================================
301 subroutine dlnpdlnt(T,p, slope)
302 
303 real(8), intent(in) :: T, p
304 real(8), intent(out):: slope
305 real(8) :: qs, lh, D, rs, pa, es, A, B, C
306 
307  call qsat(t,p, qs)
308  call latent_heat(t, lh)
309  d = lh / (rvgas * t)
310 
311  if (qs .eq. 1) then
312  slope = d
313  else
314  rs = qs / (1. - qs)
315  pa = p / (rs /d622 + 1.)
316  es = p - pa
317  a = lh * rs / rdgas / t
318  b = rs * (cp_vapor / cp_air + &
319  (lh / rvgas / t-1.) * lh / cp_air / t)
320  c = 1. / (kappa * (1. + a) / (1. + b)) !#dlnpa / dlnT
321  slope = (pa * c + es * d) / p
322  end if
323 end subroutine dlnpdlnt
324 
325 subroutine convec(T1,P1,P2,PH, T2)
326 
327 real(8), intent(in) :: T1, P1, P2, PH
328 real(8), intent(out):: T2
329 real(8) :: lr1, TH, lr2
330  call dlnpdlnt(t1,p1, lr1)
331 
332  th = t1 * (ph/p1)**(1./lr1)
333 
334  call dlnpdlnt(th,ph, lr2)
335 
336  t2 = t1 * (p2 / p1)**(1./lr2)
337 end subroutine convec
338  !return T2
339 !##==============================================
340 subroutine moist_convection(tin, qin, p_full_in, p_half_in, &
341  rain, Tref, qref, p_full, p_half, Ep, rain_profile)
342 
343 real(8), intent(in), dimension(:) :: tin, qin, p_full_in
344 real(8), intent(in), dimension(:) :: p_half_in
345 real(8), intent(out) :: rain, ep
346 real(8), intent(out), dimension(:) :: tref, qref, p_full, rain_profile
347 real(8), intent(out), dimension(:) :: p_half
348 
349 !real(8) :: k1, kk1, k2, k3
350 real(8) :: t1, p1, p2, ph, t2
351 real(8) :: q1, q2, deltap1, deltap2, fq
352 real(8) :: cp1,cp2, cp3, cp4, deltat
353 real(8) :: dtref, t1new, t2new
354 real(8) :: dp, lmass, tcon, dpn, kappa2
355 real(8) :: lh, lmass1, lmass2
356 
357 real(8), allocatable, dimension(:) :: pfulln, kappa1, zf
358 real(8), allocatable, dimension(:) :: phalfn, zh
359 
360 integer :: iter1, k, i, n, j, nc
361 
362  n = size(tin)
363  allocate(pfulln(n))
364  allocate(kappa1(n))
365  allocate(zf(n))
366  allocate(phalfn(n+1))
367  allocate(zh(n+1))
368  ep = 0.
369  rain = 0.
370 ! Ep_2 = 0. !check energy conservation
371 
372  tref = tin *1.
373  qref = qin *1.
374  p_full = p_full_in *1.
375  p_half = p_half_in *1.
376  rain_profile = 0.
377 
378  do iter1 = 1, 1 !20 !5
379  do k = size(p_full), 2, -1
380  t1 = tref(k)
381  p1 = p_full(k)
382  p2 = p_full(k-1)
383  ph = p_half(k)
384  call convec(t1, p1, p2, ph, t2)
385  !call compute_k(Tref, qref, p_half, k1)
386 
387  if (tref(k-1) .lt. t2) then
388  deltap1 = p_half(k+1) - p_half(k)
389  deltap2 = p_half(k) - p_half(k-1)
390  dtref = t1 - t2
391 
392  call newtsolve_ff(dtref, deltap1, deltap2, &
393  qref(k), qref(k-1), tref(k), tref(k-1), &
394  p_full(k), p_full(k-1),t1new, t2new,lmass1,lmass2)
395 
396  if (lmass1 .lt. 0) then !do shallow convection ??
397  call qsat(t1 ,p1, q1)
398  call qsat(t2 ,p2, q2)
399  fq = (qref(k) * deltap1 + qref(k-1)*deltap2) &
400  / (q1*deltap1 + q2 * deltap2)
401  q1 = q1 * fq
402  q2 = q2 * fq
403  cp2 = cp_air * deltap2 * (1 - qref(k-1)) + &
404  cp_vapor * deltap2 * qref(k-1)
405  cp1 = cp_air * deltap1 * (1 - qref(k)) + &
406  cp_vapor * deltap1 * qref(k)
407  cp4 = cp_air * deltap2 * (1 - q2) + &
408  cp_vapor * deltap2 * q2
409  cp3 = cp_air * deltap1 * (1 - q1) + &
410  cp_vapor * deltap1 * q1
411  deltat = -(cp3*t1 - cp1*tref(k) + cp4*t2 - cp2*tref(k-1)) &
412  / (cp4 + cp3)
413  tref(k) = t1 + deltat
414  tref(k-1) = t2 + deltat
415  qref(k) = q1
416  qref(k-1) = q2
417 
418  else
419  if (t1new .gt. 400.) print *, "too warm"
420  tref(k) = t1new
421  tref(k-1) = t2new
422  call qsat(tref(k), p_full(k), qref(k))
423  call qsat(tref(k-1), p_full(k-1), qref(k-1)) !new qsat after removal
424 
425  !#condensation in the (k)th layer
426  tcon = t1new
427  lmass = lmass1
428  i = k!-1
429  dp = p_half(i+1) - p_half(i)
430  kappa1 = (rdgas * (1 - qref) + rvgas * qref) &
431  / (cp_air*(1-qref) + cp_vapor* qref)
432  pfulln = p_full *1.
433  phalfn = p_half *1.
434 
435  !call compute_k(Tref, qref, p_half, k2)
436  !do j = 1, n
437  ! if (j .eq. i) then
438  ! zf(j) = (cp_air*(1 - qref(j)) + &
439  ! cp_vapor*(1 - qref(j))*rs + &
440  ! cp_water*(1 - qref(j))*rl)*Tref(j)
441  ! else
442  ! zf(j) = (cp_air*(1 - qref(j)) + &
443  ! cp_vapor*qref(j))*Tref(j)
444  ! end if
445  !end do
446  !k2 = sum(zf(1:n)*(p_half(2:n+1) - p_half(1:n))/grav)
447 ! #compute geopotential after condensation
448  call compute_geopotential(tref, qref, p_half, p_full, zf, zh)
449 
450  !#new pressure levels
451  dpn = dp - lmass
452  p_half(i+1:n+1) = p_half(i+1:n+1) - dp + dpn
453  pfulln(i) = p_full(i) - lmass* (p_full(i) - p_half(i)) / dp
454  kappa2 = kappa1(i)
455  tref(i) = tref(i) * (pfulln(i) / p_full(i))**kappa2
456  if (i .lt. n) then
457  pfulln(i+1:n) = p_full(i+1:n) - dp + dpn
458  tref(i+1:n) = tref(i+1:n) * &
459  (pfulln(i+1:n) / p_full(i+1:n))**kappa1(i+1:n)
460  end if
461  p_full = pfulln *1.
462 
463  rain = rain + lmass / grav
464 
465  rain_profile(i) = rain_profile(i) + lmass / grav
466 
467  ep = ep + cp_water * tcon * lmass / grav &
468  + lmass * zf(i) / grav ! (zh(i) + zh(i+1))/2. / grav
469 
470  !#condensation in the (k-1)th layer
471  tcon = t2new
472  lmass = lmass2
473  i = k-1
474  dp = p_half(i+1) - p_half(i)
475  pfulln = p_full *1.
476  phalfn = p_half *1.
477 
478  !call compute_k(Tref, qref, p_half, k2)
479  !do j = 1, n
480  ! if (j .eq. i) then
481  ! zf(j) = (cp_air*(1 - qref(j)) + &
482  ! cp_vapor*(1 - qref(j))*rs + &
483  ! cp_water*(1 - qref(j))*rl)*Tref(j)
484  ! else
485  ! zf(j) = (cp_air*(1 - qref(j)) + &
486  ! cp_vapor*qref(j))*Tref(j)
487  ! end if
488  !end do
489  !k2 = sum(zf(1:n)*(p_half(2:n+1) - p_half(1:n))/grav)
490 ! #compute geopotential after condensation
491  call compute_geopotential(tref, qref, p_half, p_full, zf, zh)
492 
493  !#new pressure levels
494  dpn = dp - lmass
495  p_half(i+1:n+1) = p_half(i+1:n+1) - dp + dpn
496  pfulln(i) = p_full(i) - lmass* (p_full(i) - p_half(i)) / dp
497  kappa2 = kappa1(i)
498  tref(i) = tref(i) * (pfulln(i) / p_full(i))**kappa2
499  if (i .lt. n) then
500  pfulln(i+1:n) = p_full(i+1:n) - dp + dpn
501  tref(i+1:n) = tref(i+1:n) * &
502  (pfulln(i+1:n) / p_full(i+1:n))**kappa1(i+1:n)
503  end if
504  p_full = pfulln *1.
505 
506  rain = rain + lmass / grav
507 
508  rain_profile(i) = rain_profile(i) + lmass / grav
509 
510  ep = ep + cp_water * tcon * lmass / grav &
511  + lmass * zf(i) / grav ! (zh(i) + zh(i+1))/2. / grav
512 
513  nc = i
514 
515  end if !moist convection
516  end if
517  end do
518  end do
519 
520  !print *, i
521 ! if (nc .gt. 1) then
522 ! call cold_trap(Tref, qref, p_half, p_full, nc)
523 ! end if
524 
525 end subroutine moist_convection
526 
527 
528 subroutine cold_trap(t, q, phalf, pfull, nc)
529 real(8), intent(inout), dimension(:) :: t, q
530 real(8), intent(in), dimension(:) :: phalf
531 real(8), intent(in), dimension(:) :: pfull
532 integer, intent(in) :: nc
533 
534 real(8) :: q2
535 integer :: i
536 
537 do i = nc-1, 1, -1
538  call qsat(t(i), pfull(i), q2)
539  if (q2 .gt. q(i+1)) exit
540  q(i) = q2
541 end do
542 
543 q(1:i) = q(i+1)
544 end subroutine cold_trap
545 
546 
547  !return rain, Tref, qref, p_full, p_half, Ep, Ep_2 , rain_profile
548 
549 end module qe_moist_convection_mod
subroutine convec(T1, P1, P2, PH, T2)
subroutine ff(dT, dp1, dp2, p1, p2, Dry_m, kini, x, val, lmass1, lmass2)
subroutine dqsatdt(T, p, dqs)
subroutine, public qsat(T, p, qs)
subroutine newtsolve_ff(dT, dp1, dp2, q1, q2, T1, T2, p1, p2, T1new, T2new, lmass1, lmass2)
subroutine, public moist_convection(tin, qin, p_full_in, p_half_in, rain, Tref, qref, p_full, p_half, Ep, rain_profile)
real(8), parameter, public d608
subroutine, public compute_k(tin, qin, phalf, k)
subroutine dlnpdlnt(T, p, slope)
subroutine dlnpdlnt_initial(lnT, lnp, slope)
subroutine cold_trap(t, q, phalf, pfull, nc)
subroutine rk4_f(x0, y0, dx, nx, x, y)
subroutine, public warm_start(ts, pd, nx, psg, tt, lnpp, qs)
subroutine rsat(T, p, rs)
real(8), parameter, public d622
subroutine drsatdt(T, p, drs)
subroutine compute_geopotential(t, q, p_half, p_full, z_full, z_half)
real(8), parameter, public d378