3 ! Updated to CESM1.0.3 (CAM5.1.01) by Balwinder.Singh@pnnl.gov
5 ! Common block and statement functions for saturation vapor pressure
6 ! look-up procedure, J. J. Hack, February 1990
8 ! Ported to WRF by William.Gustafson@pnl.gov, Nov. 2009
9 ! Updated to version from CESM1_0_1, Nov. 2010
10 ! Updated to version CESM1.0.3 (CAM5.1.01)- Balwinder.Singh@pnnl.gov
15 use shr_kind_mod, only: r8 => shr_kind_r8
17 use abortutils, only: endrun
18 use cam_logfile, only: iulog
20 use module_cam_support, only: endrun, iulog
30 public gestbl ! Initialization subroutine
31 public estblf ! saturation pressure table lookup
32 public aqsat ! Returns saturation vapor pressure
34 public aqsatd ! Same as aqsat, but also returns a temperature derivitive
36 public vqsatd ! Vector version of aqsatd
37 public fqsatd ! Function version of vqsatd
38 public qsat_water ! saturation mixing ration with respect to liquid water
40 public vqsat_water ! vector version of qsat_water
41 public qsat_ice ! saturation mixing ration with respect to ice
42 public vqsat_ice ! vector version of qsat_ice
47 public vqsatd2_water ! Variant of vqsatd_water to print out dqsdT
48 public vqsatd2_water_single ! Single value version of vqsatd2_water
56 public hlatv, tmin, hlatf, rgasv, pcf, cp, epsqs, ttrice
60 integer plenest ! length of saturation vapor pressure table
61 parameter (plenest=250)
63 ! Table of saturation vapor pressure values es from tmin degrees
64 ! to tmax+1 degrees k in one degree increments. ttrice defines the
65 ! transition region where es is a combination of ice & water values
67 real(r8) estbl(plenest) ! table values of saturation vapor pressure
68 real(r8) tmin ! min temperature (K) for table
69 real(r8) tmax ! max temperature (K) for table
70 real(r8) ttrice ! transition range from es over H2O to es over ice
71 real(r8) pcf(6) ! polynomial coeffs -> es transition water to ice
72 real(r8) epsqs ! Ratio of h2o to dry air molecular weights
73 real(r8) rgasv ! Gas constant for water vapor
74 real(r8) hlatf ! Latent heat of vaporization
75 real(r8) hlatv ! Latent heat of fusion
76 real(r8) cp ! specific heat of dry air
77 real(r8) tmelt ! Melting point of water (K)
78 logical icephs ! false => saturation vapor press over water only
82 real(r8) function estblf( td )
84 ! Saturation vapor pressure table lookup
86 real(r8), intent(in) :: td ! Temperature for saturation lookup
88 real(r8) :: e ! intermediate variable for es look-up
92 e = max(min(td,tmax),tmin) ! partial pressure
95 estblf = (tmin+ai-e+1._r8)* &
96 estbl(i)-(tmin+ai-e)* &
100 subroutine gestbl(tmn ,tmx ,trice ,ip ,epsil , &
101 latvap ,latice ,rh2o ,cpair ,tmeltx )
102 !-----------------------------------------------------------------------
105 ! Builds saturation vapor pressure table for later lookup procedure.
108 ! Uses Goff & Gratch (1946) relationships to generate the table
109 ! according to a set of free parameters defined below. Auxiliary
110 ! routines are also included for making rapid estimates (well with 1%)
111 ! of both es and d(es)/dt for the particular table configuration.
115 !-----------------------------------------------------------------------
117 use spmd_utils, only: masterproc
119 use module_cam_support, only: masterproc
120 use module_cam_gffgch
122 !------------------------------Arguments--------------------------------
126 real(r8), intent(in) :: tmn ! Minimum temperature entry in es lookup table
127 real(r8), intent(in) :: tmx ! Maximum temperature entry in es lookup table
128 real(r8), intent(in) :: epsil ! Ratio of h2o to dry air molecular weights
129 real(r8), intent(in) :: trice ! Transition range from es over range to es over ice
130 real(r8), intent(in) :: latvap ! Latent heat of vaporization
131 real(r8), intent(in) :: latice ! Latent heat of fusion
132 real(r8), intent(in) :: rh2o ! Gas constant for water vapor
133 real(r8), intent(in) :: cpair ! Specific heat of dry air
134 real(r8), intent(in) :: tmeltx ! Melting point of water (K)
136 !---------------------------Local variables-----------------------------
138 real(r8) t ! Temperature
139 integer n ! Increment counter
140 integer lentbl ! Calculated length of lookup table
141 integer itype ! Ice phase: 0 -> no ice phase
142 ! 1 -> ice phase, no transition
143 ! -x -> ice phase, x degree transition
144 logical ip ! Ice phase logical flag
146 !-----------------------------------------------------------------------
148 ! Set es table parameters
150 tmin = tmn ! Minimum temperature entry in table
151 tmax = tmx ! Maximum temperature entry in table
152 ttrice = trice ! Trans. range from es over h2o to es over ice
153 icephs = ip ! Ice phase (true or false)
155 ! Set physical constants required for es calculation
164 lentbl = INT(tmax-tmin+2.000001_r8)
165 if (lentbl .gt. plenest) then
166 write(iulog,9000) tmax, tmin, plenest
168 call wrf_message(iulog)
170 call endrun ('GESTBL') ! Abnormal termination
173 ! Begin building es table.
174 ! Check whether ice phase requested.
175 ! If so, set appropriate transition range for temperature
178 if (ttrice /= 0.0_r8) then
190 call gffgch(t,estbl(n),itype)
193 do n=lentbl+1,plenest
194 estbl(n) = -99999.0_r8
197 ! Table complete -- Set coefficients for polynomial approximation of
198 ! difference between saturation vapor press over water and saturation
199 ! pressure over ice for -ttrice < t < 0 (degrees C). NOTE: polynomial
200 ! is valid in the range -40 < t < 0 (degrees C).
202 ! --- Degree 5 approximation ---
204 pcf(1) = 5.04469588506e-01_r8
205 pcf(2) = -5.47288442819e+00_r8
206 pcf(3) = -3.67471858735e-01_r8
207 pcf(4) = -8.95963532403e-03_r8
208 pcf(5) = -7.78053686625e-05_r8
210 ! --- Degree 6 approximation ---
212 !-----pcf(1) = 7.63285250063e-02
213 !-----pcf(2) = -5.86048427932e+00
214 !-----pcf(3) = -4.38660831780e-01
215 !-----pcf(4) = -1.37898276415e-02
216 !-----pcf(5) = -2.14444472424e-04
217 !-----pcf(6) = -1.36639103771e-06
220 write(iulog,*)' *** SATURATION VAPOR PRESSURE TABLE COMPLETED ***'
222 call wrf_message(iulog)
228 9000 format('GESTBL: FATAL ERROR *********************************',/, &
229 ' TMAX AND TMIN REQUIRE A LARGER DIMENSION ON THE LENGTH', &
230 ' OF THE SATURATION VAPOR PRESSURE TABLE ESTBL(PLENEST)',/, &
231 ' TMAX, TMIN, AND PLENEST => ', 2f7.2, i3)
233 end subroutine gestbl
235 subroutine aqsat(t ,p ,es ,qs ,ii , &
236 ilen ,kk ,kstart ,kend )
237 !-----------------------------------------------------------------------
240 ! Utility procedure to look up and return saturation vapor pressure from
241 ! precomputed table, calculate and return saturation specific humidity
242 ! (g/g),for input arrays of temperature and pressure (dimensioned ii,kk)
243 ! This routine is useful for evaluating only a selected region in the
247 ! <Describe the algorithm(s) used in the routine.>
248 ! <Also include any applicable external references.>
252 !------------------------------Arguments--------------------------------
256 integer, intent(in) :: ii ! I dimension of arrays t, p, es, qs
257 integer, intent(in) :: kk ! K dimension of arrays t, p, es, qs
258 integer, intent(in) :: ilen ! Length of vectors in I direction which
259 integer, intent(in) :: kstart ! Starting location in K direction
260 integer, intent(in) :: kend ! Ending location in K direction
261 real(r8), intent(in) :: t(ii,kk) ! Temperature
262 real(r8), intent(in) :: p(ii,kk) ! Pressure
266 real(r8), intent(out) :: es(ii,kk) ! Saturation vapor pressure
267 real(r8), intent(out) :: qs(ii,kk) ! Saturation specific humidity
269 !---------------------------Local workspace-----------------------------
271 real(r8) omeps ! 1 - 0.622
272 integer i, k ! Indices
274 !-----------------------------------------------------------------------
276 omeps = 1.0_r8 - epsqs
279 es(i,k) = estblf(t(i,k))
281 ! Saturation specific humidity
283 qs(i,k) = epsqs*es(i,k)/(p(i,k) - omeps*es(i,k))
285 ! The following check is to avoid the generation of negative values
286 ! that can occur in the upper stratosphere and mesosphere
288 qs(i,k) = min(1.0_r8,qs(i,k))
290 if (qs(i,k) < 0.0_r8) then
302 subroutine aqsat_water(t ,p ,es ,qs ,ii , &
303 ilen ,kk ,kstart ,kend )
304 !-----------------------------------------------------------------------
307 ! Utility procedure to look up and return saturation vapor pressure from
308 ! precomputed table, calculate and return saturation specific humidity
309 ! (g/g),for input arrays of temperature and pressure (dimensioned ii,kk)
310 ! This routine is useful for evaluating only a selected region in the
314 ! <Describe the algorithm(s) used in the routine.>
315 ! <Also include any applicable external references.>
319 !------------------------------Arguments--------------------------------
323 integer, intent(in) :: ii ! I dimension of arrays t, p, es, qs
324 integer, intent(in) :: kk ! K dimension of arrays t, p, es, qs
325 integer, intent(in) :: ilen ! Length of vectors in I direction which
326 integer, intent(in) :: kstart ! Starting location in K direction
327 integer, intent(in) :: kend ! Ending location in K direction
328 real(r8), intent(in) :: t(ii,kk) ! Temperature
329 real(r8), intent(in) :: p(ii,kk) ! Pressure
333 real(r8), intent(out) :: es(ii,kk) ! Saturation vapor pressure
334 real(r8), intent(out) :: qs(ii,kk) ! Saturation specific humidity
336 !---------------------------Local workspace-----------------------------
338 real(r8) omeps ! 1 - 0.622
339 integer i, k ! Indices
341 !-----------------------------------------------------------------------
343 omeps = 1.0_r8 - epsqs
346 ! es(i,k) = estblf(t(i,k))
347 es(i,k) = polysvp(t(i,k),0)
349 ! Saturation specific humidity
351 qs(i,k) = epsqs*es(i,k)/(p(i,k) - omeps*es(i,k))
353 ! The following check is to avoid the generation of negative values
354 ! that can occur in the upper stratosphere and mesosphere
356 qs(i,k) = min(1.0_r8,qs(i,k))
358 if (qs(i,k) < 0.0_r8) then
366 end subroutine aqsat_water
370 subroutine aqsatd(t ,p ,es ,qs ,gam , &
371 ii ,ilen ,kk ,kstart ,kend )
372 !-----------------------------------------------------------------------
375 ! Utility procedure to look up and return saturation vapor pressure from
376 ! precomputed table, calculate and return saturation specific humidity
380 ! Differs from aqsat by also calculating and returning
381 ! gamma (l/cp)*(d(qsat)/dT)
382 ! Input arrays temperature and pressure (dimensioned ii,kk).
386 !------------------------------Arguments--------------------------------
390 integer, intent(in) :: ii ! I dimension of arrays t, p, es, qs
391 integer, intent(in) :: ilen ! Vector length in I direction
392 integer, intent(in) :: kk ! K dimension of arrays t, p, es, qs
393 integer, intent(in) :: kstart ! Starting location in K direction
394 integer, intent(in) :: kend ! Ending location in K direction
396 real(r8), intent(in) :: t(ii,kk) ! Temperature
397 real(r8), intent(in) :: p(ii,kk) ! Pressure
402 real(r8), intent(out) :: es(ii,kk) ! Saturation vapor pressure
403 real(r8), intent(out) :: qs(ii,kk) ! Saturation specific humidity
404 real(r8), intent(out) :: gam(ii,kk) ! (l/cp)*(d(qs)/dt)
406 !---------------------------Local workspace-----------------------------
408 logical lflg ! True if in temperature transition region
409 integer i ! i index for vector calculations
411 real(r8) omeps ! 1. - 0.622
412 real(r8) trinv ! Reciprocal of ttrice (transition range)
413 real(r8) tc ! Temperature (in degrees C)
414 real(r8) weight ! Weight for es transition from water to ice
415 real(r8) hltalt ! Appropriately modified hlat for T derivatives
416 real(r8) hlatsb ! hlat weighted in transition region
417 real(r8) hlatvp ! hlat modified for t changes above freezing
418 real(r8) tterm ! Account for d(es)/dT in transition region
419 real(r8) desdt ! d(es)/dT
421 !-----------------------------------------------------------------------
423 omeps = 1.0_r8 - epsqs
426 es(i,k) = estblf(t(i,k))
428 ! Saturation specific humidity
430 qs(i,k) = epsqs*es(i,k)/(p(i,k) - omeps*es(i,k))
432 ! The following check is to avoid the generation of negative qs
433 ! values which can occur in the upper stratosphere and mesosphere
435 qs(i,k) = min(1.0_r8,qs(i,k))
437 if (qs(i,k) < 0.0_r8) then
444 ! "generalized" analytic expression for t derivative of es
445 ! accurate to within 1 percent for 173.16 < t < 373.16
448 if ((.not. icephs) .or. (ttrice.eq.0.0_r8)) go to 10
449 trinv = 1.0_r8/ttrice
454 ! Weighting of hlat accounts for transition from water to ice
455 ! polynomial expression approximates difference between es over
456 ! water and es over ice from 0 to -ttrice (C) (min of ttrice is
457 ! -40): required for accurate estimate of es derivative in transition
458 ! range from ice to water also accounting for change of hlatv with t
459 ! above freezing where constant slope is given by -2369 j/(kg c) =cpv - cw
462 lflg = (tc >= -ttrice .and. tc < 0.0_r8)
463 weight = min(-tc*trinv,1.0_r8)
464 hlatsb = hlatv + weight*hlatf
465 hlatvp = hlatv - 2369.0_r8*tc
466 if (t(i,k) < tmelt) then
472 tterm = pcf(1) + tc*(pcf(2) + tc*(pcf(3) + tc*(pcf(4) + tc*pcf(5))))
476 desdt = hltalt*es(i,k)/(rgasv*t(i,k)*t(i,k)) + tterm*trinv
477 gam(i,k) = hltalt*qs(i,k)*p(i,k)*desdt/(cp*es(i,k)*(p(i,k) - omeps*es(i,k)))
478 if (qs(i,k) == 1.0_r8) gam(i,k) = 0.0_r8
484 ! No icephs or water to ice transition
489 ! Account for change of hlatv with t above freezing where
490 ! constant slope is given by -2369 j/(kg c) = cpv - cw
492 hlatvp = hlatv - 2369.0_r8*(t(i,k)-tmelt)
494 hlatsb = hlatv + hlatf
498 if (t(i,k) < tmelt) then
503 desdt = hltalt*es(i,k)/(rgasv*t(i,k)*t(i,k))
504 gam(i,k) = hltalt*qs(i,k)*p(i,k)*desdt/(cp*es(i,k)*(p(i,k) - omeps*es(i,k)))
505 if (qs(i,k) == 1.0_r8) gam(i,k) = 0.0_r8
510 end subroutine aqsatd
512 subroutine vqsatd(t ,p ,es ,qs ,gam , &
514 !-----------------------------------------------------------------------
517 ! Utility procedure to look up and return saturation vapor pressure from
518 ! precomputed table, calculate and return saturation specific humidity
519 ! (g/g), and calculate and return gamma (l/cp)*(d(qsat)/dT). The same
520 ! function as qsatd, but operates on vectors of temperature and pressure
526 !------------------------------Arguments--------------------------------
530 integer, intent(in) :: len ! vector length
531 real(r8), intent(in) :: t(len) ! temperature
532 real(r8), intent(in) :: p(len) ! pressure
536 real(r8), intent(out) :: es(len) ! saturation vapor pressure
537 real(r8), intent(out) :: qs(len) ! saturation specific humidity
538 real(r8), intent(out) :: gam(len) ! (l/cp)*(d(qs)/dt)
540 !--------------------------Local Variables------------------------------
542 logical lflg ! true if in temperature transition region
544 integer i ! index for vector calculations
546 real(r8) omeps ! 1. - 0.622
547 real(r8) trinv ! reciprocal of ttrice (transition range)
548 real(r8) tc ! temperature (in degrees C)
549 real(r8) weight ! weight for es transition from water to ice
550 real(r8) hltalt ! appropriately modified hlat for T derivatives
552 real(r8) hlatsb ! hlat weighted in transition region
553 real(r8) hlatvp ! hlat modified for t changes above freezing
554 real(r8) tterm ! account for d(es)/dT in transition region
555 real(r8) desdt ! d(es)/dT
557 !-----------------------------------------------------------------------
559 omeps = 1.0_r8 - epsqs
563 ! Saturation specific humidity
565 qs(i) = epsqs*es(i)/(p(i) - omeps*es(i))
567 ! The following check is to avoid the generation of negative
568 ! values that can occur in the upper stratosphere and mesosphere
570 qs(i) = min(1.0_r8,qs(i))
572 if (qs(i) < 0.0_r8) then
578 ! "generalized" analytic expression for t derivative of es
579 ! accurate to within 1 percent for 173.16 < t < 373.16
582 if ((.not. icephs) .or. (ttrice.eq.0.0_r8)) go to 10
583 trinv = 1.0_r8/ttrice
586 ! Weighting of hlat accounts for transition from water to ice
587 ! polynomial expression approximates difference between es over
588 ! water and es over ice from 0 to -ttrice (C) (min of ttrice is
589 ! -40): required for accurate estimate of es derivative in transition
590 ! range from ice to water also accounting for change of hlatv with t
591 ! above freezing where const slope is given by -2369 j/(kg c) = cpv - cw
594 lflg = (tc >= -ttrice .and. tc < 0.0_r8)
595 weight = min(-tc*trinv,1.0_r8)
596 hlatsb = hlatv + weight*hlatf
597 hlatvp = hlatv - 2369.0_r8*tc
598 if (t(i) < tmelt) then
604 tterm = pcf(1) + tc*(pcf(2) + tc*(pcf(3) + tc*(pcf(4) + tc*pcf(5))))
608 desdt = hltalt*es(i)/(rgasv*t(i)*t(i)) + tterm*trinv
609 gam(i) = hltalt*qs(i)*p(i)*desdt/(cp*es(i)*(p(i) - omeps*es(i)))
610 if (qs(i) == 1.0_r8) gam(i) = 0.0_r8
614 ! No icephs or water to ice transition
618 ! Account for change of hlatv with t above freezing where
619 ! constant slope is given by -2369 j/(kg c) = cpv - cw
621 hlatvp = hlatv - 2369.0_r8*(t(i)-tmelt)
623 hlatsb = hlatv + hlatf
627 if (t(i) < tmelt) then
632 desdt = hltalt*es(i)/(rgasv*t(i)*t(i))
633 gam(i) = hltalt*qs(i)*p(i)*desdt/(cp*es(i)*(p(i) - omeps*es(i)))
634 if (qs(i) == 1.0_r8) gam(i) = 0.0_r8
639 end subroutine vqsatd
642 subroutine vqsatd_water(t ,p ,es ,qs ,gam , &
645 !------------------------------Arguments--------------------------------
649 integer, intent(in) :: len ! vector length
650 real(r8), intent(in) :: t(len) ! temperature
651 real(r8), intent(in) :: p(len) ! pressure
656 real(r8), intent(out) :: es(len) ! saturation vapor pressure
657 real(r8), intent(out) :: qs(len) ! saturation specific humidity
658 real(r8), intent(out) :: gam(len) ! (l/cp)*(d(qs)/dt)
661 !--------------------------Local Variables------------------------------
664 integer i ! index for vector calculations
666 real(r8) omeps ! 1. - 0.622
667 real(r8) hltalt ! appropriately modified hlat for T derivatives
669 real(r8) hlatsb ! hlat weighted in transition region
670 real(r8) hlatvp ! hlat modified for t changes above freezing
671 real(r8) desdt ! d(es)/dT
673 !-----------------------------------------------------------------------
675 omeps = 1.0_r8 - epsqs
677 es(i) = polysvp(t(i),0)
679 ! Saturation specific humidity
681 qs(i) = epsqs*es(i)/(p(i) - omeps*es(i))
683 ! The following check is to avoid the generation of negative
684 ! values that can occur in the upper stratosphere and mesosphere
686 qs(i) = min(1.0_r8,qs(i))
688 if (qs(i) < 0.0_r8) then
694 ! No icephs or water to ice transition
698 ! Account for change of hlatv with t above freezing where
699 ! constant slope is given by -2369 j/(kg c) = cpv - cw
701 hlatvp = hlatv - 2369.0_r8*(t(i)-tmelt)
703 if (t(i) < tmelt) then
708 desdt = hltalt*es(i)/(rgasv*t(i)*t(i))
709 gam(i) = hltalt*qs(i)*p(i)*desdt/(cp*es(i)*(p(i) - omeps*es(i)))
710 if (qs(i) == 1.0_r8) gam(i) = 0.0_r8
715 end subroutine vqsatd_water
717 function polysvp (T,type)
718 ! Compute saturation vapor pressure by using
719 ! function from Goff and Gatch (1946)
721 ! Polysvp returned in units of pa.
722 ! T is input in units of K.
723 ! type refers to saturation with respect to liquid (0) or ice (1)
735 ! Goff Gatch equation (good down to -100 C)
737 polysvp = 10._r8**(-9.09718_r8*(273.16_r8/t-1._r8)-3.56654_r8* &
738 log10(273.16_r8/t)+0.876793_r8*(1._r8-t/273.16_r8)+ &
739 log10(6.1071_r8))*100._r8
743 ! Goff Gatch equation, uncertain below -70 C
746 polysvp = 10._r8**(-7.90298_r8*(373.16_r8/t-1._r8)+ &
747 5.02808_r8*log10(373.16_r8/t)- &
748 1.3816e-7_r8*(10._r8**(11.344_r8*(1._r8-t/373.16_r8))-1._r8)+ &
749 8.1328e-3_r8*(10._r8**(-3.49149_r8*(373.16_r8/t-1._r8))-1._r8)+ &
750 log10(1013.246_r8))*100._r8
757 integer function fqsatd(t ,p ,es ,qs ,gam , len )
758 !-----------------------------------------------------------------------
760 ! This is merely a function interface vqsatd.
761 !------------------------------Arguments--------------------------------
763 integer, intent(in) :: len ! vector length
764 real(r8), intent(in) :: t(len) ! temperature
765 real(r8), intent(in) :: p(len) ! pressure
767 real(r8), intent(out) :: es(len) ! saturation vapor pressure
768 real(r8), intent(out) :: qs(len) ! saturation specific humidity
769 real(r8), intent(out) :: gam(len) ! (l/cp)*(d(qs)/dt)
771 call vqsatd(t ,p ,es ,qs ,gam , len )
776 real(r8) function qsat_water(t,p)
777 ! saturation mixing ratio w/respect to liquid water
778 real(r8) t ! temperature
779 real(r8) p ! pressure (Pa)
780 real(r8) es ! saturation vapor pressure (Pa)
781 real(r8) ps, ts, e1, e2, f1, f2, f3, f4, f5, f
782 ! real(r8) t0inv ! 1/273.
783 ! data t0inv/0.003663/
785 ! es = 611.*exp(hlatv/rgasv*(t0inv-1./t))
789 e1 = 11.344_r8*(1.0_r8 - t/ts)
790 e2 = -3.49149_r8*(ts/t - 1.0_r8)
791 f1 = -7.90298_r8*(ts/t - 1.0_r8)
792 f2 = 5.02808_r8*log10(ts/t)
793 f3 = -1.3816_r8*(10.0_r8**e1 - 1.0_r8)/10000000.0_r8
794 f4 = 8.1328_r8*(10.0_r8**e2 - 1.0_r8)/1000.0_r8
796 f = f1 + f2 + f3 + f4 + f5
797 es = (10.0_r8**f)*100.0_r8
799 qsat_water = epsqs*es/(p-(1.-epsqs)*es) ! saturation w/respect to liquid only
800 if(qsat_water < 0.) qsat_water = 1.
802 end function qsat_water
804 subroutine vqsat_water(t,p,qsat_water,len)
805 ! saturation mixing ratio w/respect to liquid water
806 integer, intent(in) :: len
807 real(r8) t(len) ! temperature
808 real(r8) p(len) ! pressure (Pa)
809 real(r8) qsat_water(len)
810 real(r8) es ! saturation vapor pressure (Pa)
811 real(r8), parameter :: t0inv = 1._r8/273._r8
817 es = 611._r8*exp(coef*(t0inv-1./t(i)))
818 qsat_water(i) = epsqs*es/(p(i)-(1.-epsqs)*es) ! saturation w/respect to liquid only
819 if(qsat_water(i) < 0.) qsat_water(i) = 1.
824 end subroutine vqsat_water
826 real(r8) function qsat_ice(t,p)
827 ! saturation mixing ratio w/respect to ice
828 real(r8) t ! temperature
829 real(r8) p ! pressure (Pa)
830 real(r8) es ! saturation vapor pressure (Pa)
831 real(r8), parameter :: t0inv = 1._r8/273._r8
832 es = 611.*exp((hlatv+hlatf)/rgasv*(t0inv-1./t))
833 qsat_ice = epsqs*es/(p-(1.-epsqs)*es) ! saturation w/respect to liquid only
834 if(qsat_ice < 0.) qsat_ice = 1.
836 end function qsat_ice
838 subroutine vqsat_ice(t,p,qsat_ice,len)
839 ! saturation mixing ratio w/respect to liquid water
840 integer,intent(in) :: len
841 real(r8) t(len) ! temperature
842 real(r8) p(len) ! pressure (Pa)
843 real(r8) qsat_ice(len)
844 real(r8) es ! saturation vapor pressure (Pa)
845 real(r8), parameter :: t0inv = 1._r8/273._r8
849 coef = (hlatv+hlatf)/rgasv
851 es = 611.*exp(coef*(t0inv-1./t(i)))
852 qsat_ice(i) = epsqs*es/(p(i)-(1.-epsqs)*es) ! saturation w/respect to liquid only
853 if(qsat_ice(i) < 0.) qsat_ice(i) = 1.
858 end subroutine vqsat_ice
861 ! Below two subroutines (vqsatd2_water,vqsatd2_water_single) are by Sungsu
862 ! Replace 'gam -> dqsdt'
865 subroutine vqsatd2_water(t ,p ,es ,qs ,dqsdt , &
868 !------------------------------Arguments--------------------------------
872 integer, intent(in) :: len ! vector length
873 real(r8), intent(in) :: t(len) ! temperature
874 real(r8), intent(in) :: p(len) ! pressure
879 real(r8), intent(out) :: es(len) ! saturation vapor pressure
880 real(r8), intent(out) :: qs(len) ! saturation specific humidity
881 ! real(r8), intent(out) :: gam(len) ! (l/cp)*(d(qs)/dt)
883 real(r8), intent(out) :: dqsdt(len) ! (d(qs)/dt)
887 !--------------------------Local Variables------------------------------
890 integer i ! index for vector calculations
892 real(r8) omeps ! 1. - 0.622
893 real(r8) hltalt ! appropriately modified hlat for T derivatives
895 real(r8) hlatsb ! hlat weighted in transition region
896 real(r8) hlatvp ! hlat modified for t changes above freezing
897 real(r8) desdt ! d(es)/dT
900 real(r8) gam(len) ! (l/cp)*(d(qs)/dt)
904 !-----------------------------------------------------------------------
906 omeps = 1.0_r8 - epsqs
908 es(i) = polysvp(t(i),0)
910 ! Saturation specific humidity
912 qs(i) = epsqs*es(i)/(p(i) - omeps*es(i))
914 ! The following check is to avoid the generation of negative
915 ! values that can occur in the upper stratosphere and mesosphere
917 qs(i) = min(1.0_r8,qs(i))
919 if (qs(i) < 0.0_r8) then
925 ! No icephs or water to ice transition
929 ! Account for change of hlatv with t above freezing where
930 ! constant slope is given by -2369 j/(kg c) = cpv - cw
932 hlatvp = hlatv - 2369.0_r8*(t(i)-tmelt)
934 if (t(i) < tmelt) then
939 desdt = hltalt*es(i)/(rgasv*t(i)*t(i))
940 gam(i) = hltalt*qs(i)*p(i)*desdt/(cp*es(i)*(p(i) - omeps*es(i)))
941 if (qs(i) == 1.0_r8) gam(i) = 0.0_r8
943 dqsdt(i) = (cp/hltalt)*gam(i)
949 end subroutine vqsatd2_water
951 subroutine vqsatd2_water_single(t ,p ,es ,qs ,dqsdt)
953 !------------------------------Arguments--------------------------------
958 real(r8), intent(in) :: t ! temperature
959 real(r8), intent(in) :: p ! pressure
964 real(r8), intent(out) :: es ! saturation vapor pressure
965 real(r8), intent(out) :: qs ! saturation specific humidity
966 ! real(r8), intent(out) :: gam ! (l/cp)*(d(qs)/dt)
968 real(r8), intent(out) :: dqsdt ! (d(qs)/dt)
972 !--------------------------Local Variables------------------------------
975 integer i ! index for vector calculations
977 real(r8) omeps ! 1. - 0.622
978 real(r8) hltalt ! appropriately modified hlat for T derivatives
980 real(r8) hlatsb ! hlat weighted in transition region
981 real(r8) hlatvp ! hlat modified for t changes above freezing
982 real(r8) desdt ! d(es)/dT
985 real(r8) gam ! (l/cp)*(d(qs)/dt)
989 !-----------------------------------------------------------------------
991 omeps = 1.0_r8 - epsqs
995 ! Saturation specific humidity
997 qs = epsqs*es/(p - omeps*es)
999 ! The following check is to avoid the generation of negative
1000 ! values that can occur in the upper stratosphere and mesosphere
1004 if (qs < 0.0_r8) then
1010 ! No icephs or water to ice transition
1014 ! Account for change of hlatv with t above freezing where
1015 ! constant slope is given by -2369 j/(kg c) = cpv - cw
1017 hlatvp = hlatv - 2369.0_r8*(t-tmelt)
1024 desdt = hltalt*es/(rgasv*t*t)
1025 gam = hltalt*qs*p*desdt/(cp*es*(p - omeps*es))
1026 if (qs == 1.0_r8) gam = 0.0_r8
1028 dqsdt = (cp/hltalt)*gam
1034 end subroutine vqsatd2_water_single
1037 subroutine vqsatd2(t ,p ,es ,qs ,dqsdt , &
1039 !-----------------------------------------------------------------------
1040 ! Sungsu : This is directly copied from 'vqsatd' but 'dqsdt' is output
1041 ! instead of gam for use in Sungsu's equilibrium stratiform
1042 ! macrophysics scheme.
1045 ! Utility procedure to look up and return saturation vapor pressure from
1046 ! precomputed table, calculate and return saturation specific humidity
1047 ! (g/g), and calculate and return gamma (l/cp)*(d(qsat)/dT). The same
1048 ! function as qsatd, but operates on vectors of temperature and pressure
1054 !------------------------------Arguments--------------------------------
1058 integer, intent(in) :: len ! vector length
1059 real(r8), intent(in) :: t(len) ! temperature
1060 real(r8), intent(in) :: p(len) ! pressure
1064 real(r8), intent(out) :: es(len) ! saturation vapor pressure
1065 real(r8), intent(out) :: qs(len) ! saturation specific humidity
1066 ! real(r8), intent(out) :: gam(len) ! (l/cp)*(d(qs)/dt)
1068 real(r8), intent(out) :: dqsdt(len) ! (d(qs)/dt)
1072 !--------------------------Local Variables------------------------------
1074 logical lflg ! true if in temperature transition region
1076 integer i ! index for vector calculations
1078 real(r8) omeps ! 1. - 0.622
1079 real(r8) trinv ! reciprocal of ttrice (transition range)
1080 real(r8) tc ! temperature (in degrees C)
1081 real(r8) weight ! weight for es transition from water to ice
1082 real(r8) hltalt ! appropriately modified hlat for T derivatives
1084 real(r8) hlatsb ! hlat weighted in transition region
1085 real(r8) hlatvp ! hlat modified for t changes above freezing
1086 real(r8) tterm ! account for d(es)/dT in transition region
1087 real(r8) desdt ! d(es)/dT
1090 real(r8) gam(len) ! (l/cp)*(d(qs)/dt)
1093 !-----------------------------------------------------------------------
1095 omeps = 1.0_r8 - epsqs
1097 es(i) = estblf(t(i))
1099 ! Saturation specific humidity
1101 qs(i) = epsqs*es(i)/(p(i) - omeps*es(i))
1103 ! The following check is to avoid the generation of negative
1104 ! values that can occur in the upper stratosphere and mesosphere
1106 qs(i) = min(1.0_r8,qs(i))
1108 if (qs(i) < 0.0_r8) then
1114 ! "generalized" analytic expression for t derivative of es
1115 ! accurate to within 1 percent for 173.16 < t < 373.16
1118 if ((.not. icephs) .or. (ttrice.eq.0.0_r8)) go to 10
1119 trinv = 1.0_r8/ttrice
1122 ! Weighting of hlat accounts for transition from water to ice
1123 ! polynomial expression approximates difference between es over
1124 ! water and es over ice from 0 to -ttrice (C) (min of ttrice is
1125 ! -40): required for accurate estimate of es derivative in transition
1126 ! range from ice to water also accounting for change of hlatv with t
1127 ! above freezing where const slope is given by -2369 j/(kg c) = cpv - cw
1130 lflg = (tc >= -ttrice .and. tc < 0.0_r8)
1131 weight = min(-tc*trinv,1.0_r8)
1132 hlatsb = hlatv + weight*hlatf
1133 hlatvp = hlatv - 2369.0_r8*tc
1134 if (t(i) < tmelt) then
1140 tterm = pcf(1) + tc*(pcf(2) + tc*(pcf(3) + tc*(pcf(4) + tc*pcf(5))))
1144 desdt = hltalt*es(i)/(rgasv*t(i)*t(i)) + tterm*trinv
1145 gam(i) = hltalt*qs(i)*p(i)*desdt/(cp*es(i)*(p(i) - omeps*es(i)))
1146 if (qs(i) == 1.0_r8) gam(i) = 0.0_r8
1148 dqsdt(i) = (cp/hltalt)*gam(i)
1153 ! No icephs or water to ice transition
1157 ! Account for change of hlatv with t above freezing where
1158 ! constant slope is given by -2369 j/(kg c) = cpv - cw
1160 hlatvp = hlatv - 2369.0_r8*(t(i)-tmelt)
1162 hlatsb = hlatv + hlatf
1166 if (t(i) < tmelt) then
1171 desdt = hltalt*es(i)/(rgasv*t(i)*t(i))
1172 gam(i) = hltalt*qs(i)*p(i)*desdt/(cp*es(i)*(p(i) - omeps*es(i)))
1173 if (qs(i) == 1.0_r8) gam(i) = 0.0_r8
1175 dqsdt(i) = (cp/hltalt)*gam(i)
1181 end subroutine vqsatd2
1184 ! Below routine is by Sungsu
1186 subroutine vqsatd2_single(t ,p ,es ,qs ,dqsdt)
1187 !-----------------------------------------------------------------------
1188 ! Sungsu : This is directly copied from 'vqsatd' but 'dqsdt' is output
1189 ! instead of gam for use in Sungsu's equilibrium stratiform
1190 ! macrophysics scheme.
1193 ! Utility procedure to look up and return saturation vapor pressure from
1194 ! precomputed table, calculate and return saturation specific humidity
1195 ! (g/g), and calculate and return gamma (l/cp)*(d(qsat)/dT). The same
1196 ! function as qsatd, but operates on vectors of temperature and pressure
1202 !------------------------------Arguments--------------------------------
1206 real(r8), intent(in) :: t ! temperature
1207 real(r8), intent(in) :: p ! pressure
1211 real(r8), intent(out) :: es ! saturation vapor pressure
1212 real(r8), intent(out) :: qs ! saturation specific humidity
1213 ! real(r8), intent(out) :: gam ! (l/cp)*(d(qs)/dt)
1215 real(r8), intent(out) :: dqsdt ! (d(qs)/dt)
1219 !--------------------------Local Variables------------------------------
1221 logical lflg ! true if in temperature transition region
1223 ! integer i ! index for vector calculations
1225 real(r8) omeps ! 1. - 0.622
1226 real(r8) trinv ! reciprocal of ttrice (transition range)
1227 real(r8) tc ! temperature (in degrees C)
1228 real(r8) weight ! weight for es transition from water to ice
1229 real(r8) hltalt ! appropriately modified hlat for T derivatives
1231 real(r8) hlatsb ! hlat weighted in transition region
1232 real(r8) hlatvp ! hlat modified for t changes above freezing
1233 real(r8) tterm ! account for d(es)/dT in transition region
1234 real(r8) desdt ! d(es)/dT
1237 real(r8) gam ! (l/cp)*(d(qs)/dt)
1240 !-----------------------------------------------------------------------
1242 omeps = 1.0_r8 - epsqs
1248 ! Saturation specific humidity
1250 qs = epsqs*es/(p - omeps*es)
1252 ! The following check is to avoid the generation of negative
1253 ! values that can occur in the upper stratosphere and mesosphere
1257 if (qs < 0.0_r8) then
1264 ! "generalized" analytic expression for t derivative of es
1265 ! accurate to within 1 percent for 173.16 < t < 373.16
1268 if ((.not. icephs) .or. (ttrice.eq.0.0_r8)) go to 10
1269 trinv = 1.0_r8/ttrice
1273 ! Weighting of hlat accounts for transition from water to ice
1274 ! polynomial expression approximates difference between es over
1275 ! water and es over ice from 0 to -ttrice (C) (min of ttrice is
1276 ! -40): required for accurate estimate of es derivative in transition
1277 ! range from ice to water also accounting for change of hlatv with t
1278 ! above freezing where const slope is given by -2369 j/(kg c) = cpv - cw
1281 lflg = (tc >= -ttrice .and. tc < 0.0_r8)
1282 weight = min(-tc*trinv,1.0_r8)
1283 hlatsb = hlatv + weight*hlatf
1284 hlatvp = hlatv - 2369.0_r8*tc
1291 tterm = pcf(1) + tc*(pcf(2) + tc*(pcf(3) + tc*(pcf(4) + tc*pcf(5))))
1295 desdt = hltalt*es/(rgasv*t*t) + tterm*trinv
1296 gam = hltalt*qs*p*desdt/(cp*es*(p - omeps*es))
1297 if (qs == 1.0_r8) gam = 0.0_r8
1299 dqsdt = (cp/hltalt)*gam
1304 ! No icephs or water to ice transition
1311 ! Account for change of hlatv with t above freezing where
1312 ! constant slope is given by -2369 j/(kg c) = cpv - cw
1314 hlatvp = hlatv - 2369.0_r8*(t-tmelt)
1316 hlatsb = hlatv + hlatf
1325 desdt = hltalt*es/(rgasv*t*t)
1326 gam = hltalt*qs*p*desdt/(cp*es*(p - omeps*es))
1327 if (qs == 1.0_r8) gam = 0.0_r8
1329 dqsdt = (cp/hltalt)*gam
1336 end subroutine vqsatd2_single
1339 end module wv_saturation