LCOV - code coverage report
Current view: | top level - physics/cam - wv_sat_methods.F90 (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 65 | 169 | 38.5 %
Date: | 2025-01-13 21:54:50 |  | Functions: | 12 | 28 | 42.9 %

              Line data    Source code
           1             : module wv_sat_methods
           2             :
           3             : ! This portable module contains all CAM methods for estimating
           4             : ! the saturation vapor pressure of water.
           5             : !
           6             : ! wv_saturation provides CAM-specific interfaces and utilities
           7             : ! based on these formulae.
           8             : !
           9             : ! Typical usage of this module:
          10             : !
          11             : ! Init:
          12             : ! call wv_sat_methods_init(r8, <constants>, errstring)
          13             : !
          14             : ! Get scheme index from a name string:
          15             : ! scheme_idx = wv_sat_get_scheme_idx(scheme_name)
          16             : ! if (.not. wv_sat_valid_idx(scheme_idx)) <throw some error>
          17             : !
          18             : ! Get pressures:
          19             : ! es = wv_sat_svp_water(t, scheme_idx)
          20             : ! es = wv_sat_svp_ice(t, scheme_idx)
          21             : !
          22             : ! Use ice/water transition range:
          23             : ! es = wv_sat_svp_trice(t, ttrice, scheme_idx)
          24             : !
          25             : ! Note that elemental functions cannot be pointed to, nor passed
          26             : ! as arguments. If you need to do either, it is recommended to
          27             : ! wrap the function so that it can be given an explicit (non-
          28             : ! elemental) interface.
          29             :
          30             : implicit none
          31             : private
          32             : save
          33             :
          34             : integer, parameter :: r8 = selected_real_kind(12) ! 8 byte real
          35             :
          36             : integer, parameter :: VLENS = 128 ! vector length for a GPU kernel
          37             :
          38             : real(r8) :: tmelt   ! Melting point of water at 1 atm (K)
          39             : real(r8) :: h2otrip ! Triple point temperature of water (K)
          40             : real(r8) :: tboil   ! Boiling point of water at 1 atm (K)
          41             :
          42             : real(r8) :: ttrice  ! Ice-water transition range
          43             :
          44             : real(r8) :: epsilo  ! Ice-water transition range
          45             : real(r8) :: omeps   ! 1._r8 - epsilo
          46             :
          47             : ! Indices representing individual schemes
          48             : integer, parameter :: Invalid_idx = -1
          49             : integer, parameter :: GoffGratch_idx = 1
          50             : integer, parameter :: MurphyKoop_idx = 2
          51             : integer, parameter :: Bolton_idx = 3
          52             :
          53             : ! Index representing the current default scheme.
          54             : integer, parameter :: initial_default_idx = GoffGratch_idx
          55             : integer :: default_idx = initial_default_idx
          56             :
          57             : !$acc declare create (epsilo, tmelt, tboil, omeps, h2otrip, ttrice)
          58             :
          59             : public wv_sat_methods_init
          60             : public wv_sat_get_scheme_idx
          61             : public wv_sat_valid_idx
          62             :
          63             : public wv_sat_set_default
          64             : public wv_sat_reset_default
          65             :
          66             : public wv_sat_qsat_water, wv_sat_qsat_water_vect
          67             : public wv_sat_qsat_ice, wv_sat_qsat_ice_vect
          68             :
          69             : public wv_sat_svp_trans, wv_sat_svp_trans_vect
          70             :
          71             : ! pressure -> humidity conversion
          72             : public wv_sat_svp_to_qsat, wv_sat_svp_to_qsat_vect
          73             :
          74             : ! Combined qsat operations
          75             : public wv_sat_qsat_trans
          76             :
          77             : public wv_sat_svp_water, wv_sat_svp_water_vect
          78             : public wv_sat_svp_ice, wv_sat_svp_ice_vect
          79             :
          80             : contains
          81             :
          82             : !---------------------------------------------------------------------
          83             : ! ADMINISTRATIVE FUNCTIONS
          84             : !---------------------------------------------------------------------
          85             :
          86             : ! Get physical constants
          87        1536 : subroutine wv_sat_methods_init(kind, tmelt_in, h2otrip_in, tboil_in, &
          88             :      ttrice_in, epsilo_in, errstring)
          89             :   integer, intent(in) :: kind
          90             :   real(r8), intent(in) :: tmelt_in
          91             :   real(r8), intent(in) :: h2otrip_in
          92             :   real(r8), intent(in) :: tboil_in
          93             :   real(r8), intent(in) :: ttrice_in
          94             :   real(r8), intent(in) :: epsilo_in
          95             :   character(len=*), intent(out)  :: errstring
          96             :
          97        1536 :   errstring = ' '
          98             :
          99        1536 :   if (kind /= r8) then
         100           0 :      write(errstring,*) 'wv_sat_methods_init: ERROR: ', &
         101           0 :           kind,' was input kind but ',r8,' is internal kind.'
         102           0 :      return
         103             :   end if
         104             :
         105        1536 :   if (ttrice_in < 0._r8) then
         106           0 :      write(errstring,*) 'wv_sat_methods_init: ERROR: ', &
         107           0 :           ttrice_in,' was input for ttrice, but negative range is invalid.'
         108           0 :      return
         109             :   end if
         110             :
         111        1536 :   tmelt = tmelt_in
         112        1536 :   h2otrip = h2otrip_in
         113        1536 :   tboil = tboil_in
         114        1536 :   ttrice = ttrice_in
         115        1536 :   epsilo = epsilo_in
         116             :
         117        1536 :   omeps = 1._r8 - epsilo
         118             :
         119             :   !$acc update device (tmelt,h2otrip,tboil,ttrice,epsilo,omeps)
         120             :
         121        1536 : end subroutine wv_sat_methods_init
         122             :
         123             : ! Look up index by name.
         124        1536 : pure function wv_sat_get_scheme_idx(name) result(idx)
         125             :   character(len=*), intent(in) :: name
         126             :   integer :: idx
         127             :
         128             :   select case (name)
         129             :   case("GoffGratch")
         130           0 :      idx = GoffGratch_idx
         131             :   case("MurphyKoop")
         132           0 :      idx = MurphyKoop_idx
         133             :   case("Bolton")
         134           0 :      idx = Bolton_idx
         135             :   case default
         136        1536 :      idx = Invalid_idx
         137             :   end select
         138             :
         139        1536 : end function wv_sat_get_scheme_idx
         140             :
         141             : ! Check validity of an index from the above routine.
         142        1536 : pure function wv_sat_valid_idx(idx) result(status)
         143             :   integer, intent(in) :: idx
         144             :   logical :: status
         145             :
         146        1536 :   status = (idx /= Invalid_idx)
         147             :
         148        1536 : end function wv_sat_valid_idx
         149             :
         150             : ! Set default scheme (otherwise, Goff & Gratch is default)
         151             : ! Returns a logical representing success (.true.) or
         152             : ! failure (.false.).
         153        1536 : function wv_sat_set_default(name) result(status)
         154             :   character(len=*), intent(in) :: name
         155             :   logical :: status
         156             :
         157             :   ! Don't want to overwrite valid default with invalid,
         158             :   ! so assign to temporary and check it first.
         159             :   integer :: tmp_idx
         160             :
         161        1536 :   tmp_idx = wv_sat_get_scheme_idx(name)
         162             :
         163        1536 :   status = wv_sat_valid_idx(tmp_idx)
         164             :
         165        1536 :   if (status) default_idx = tmp_idx
         166             :
         167        1536 : end function wv_sat_set_default
         168             :
         169             : ! Reset default scheme to initial value.
         170             : ! The same thing can be accomplished with wv_sat_set_default;
         171             : ! the real reason to provide this routine is to reset the
         172             : ! module for testing purposes.
         173           0 : subroutine wv_sat_reset_default()
         174             :
         175           0 :   default_idx = initial_default_idx
         176             :
         177           0 : end subroutine wv_sat_reset_default
         178             :
         179             : !---------------------------------------------------------------------
         180             : ! UTILITIES
         181             : !---------------------------------------------------------------------
         182             :
         183             : ! Get saturation specific humidity given pressure and SVP.
         184             : ! Specific humidity is limited to range 0-1.
         185 17042139860 : function wv_sat_svp_to_qsat(es, p) result(qs)
         186             :   real(r8), intent(in) :: es  ! SVP
         187             :   real(r8), intent(in) :: p   ! Current pressure.
         188             :   real(r8)             :: qs
         189             :
         190             :   ! If pressure is less than SVP, set qs to maximum of 1.
         191 17042139860 :   if ( (p - es) <= 0._r8 ) then
         192             :      qs = 1.0_r8
         193             :   else
         194 17042139532 :      qs = epsilo*es / (p - omeps*es)
         195             :   end if
         196             :
         197 17042139860 : end function wv_sat_svp_to_qsat
         198             :
         199             : ! Get saturation specific humidity given pressure and SVP.
         200             : ! Specific humidity is limited to range 0-1.
         201   486229471 : subroutine  wv_sat_svp_to_qsat_vect(es, p, qs, vlen)
         202             :
         203             :   integer,  intent(in) :: vlen
         204             :   real(r8), intent(in)  :: es(vlen)  ! SVP
         205             :   real(r8), intent(in)  :: p(vlen)   ! Current pressure.
         206             :   real(r8), intent(out) :: qs(vlen)
         207             :   integer :: i
         208             :
         209             :   ! If pressure is less than SVP, set qs to maximum of 1.
         210             :
         211             :   !$acc data present (es,p,qs)
         212             :
         213             :   !$acc parallel vector_length(VLENS) default(present)
         214             :   !$acc loop gang vector
         215  8104683799 :   do i=1,vlen
         216  8104683799 :      if ( (p(i) - es(i)) <= 0._r8 ) then
         217           0 :         qs(i) = 1.0_r8
         218             :      else
         219  7618454328 :         qs(i) = epsilo*es(i) / (p(i) - omeps*es(i))
         220             :      end if
         221             :   end do
         222             :   !$acc end parallel
         223             :
         224             :   !$acc end data
         225   486229471 : end subroutine wv_sat_svp_to_qsat_vect
         226             :
         227 12128668192 : subroutine wv_sat_qsat_water(t, p, es, qs, idx)
         228             :   !------------------------------------------------------------------!
         229             :   ! Purpose:                                                         !
         230             :   !   Calculate SVP over water at a given temperature, and then      !
         231             :   !   calculate and return saturation specific humidity.             !
         232             :   !------------------------------------------------------------------!
         233             :
         234             :   ! Inputs
         235             :   real(r8), intent(in) :: t    ! Temperature
         236             :   real(r8), intent(in) :: p    ! Pressure
         237             :   ! Outputs
         238             :   real(r8), intent(out) :: es  ! Saturation vapor pressure
         239             :   real(r8), intent(out) :: qs  ! Saturation specific humidity
         240             :
         241             :   integer,  intent(in), optional :: idx ! Scheme index
         242             :
         243 12128668192 :   es = wv_sat_svp_water(t, idx)
         244             :
         245 12128668192 :   qs = wv_sat_svp_to_qsat(es, p)
         246             :
         247             :   ! Ensures returned es is consistent with limiters on qs.
         248 12128668192 :   es = min(es, p)
         249             :
         250 12128668192 : end subroutine wv_sat_qsat_water
         251             :
         252           0 : subroutine wv_sat_qsat_water_vect(t, p, es, qs, vlen, idx)
         253             :   !------------------------------------------------------------------!
         254             :   ! Purpose:                                                         !
         255             :   !   Calculate SVP over water at a given temperature, and then      !
         256             :   !   calculate and return saturation specific humidity.             !
         257             :   !------------------------------------------------------------------!
         258             :   ! Inputs
         259             :
         260             :   integer,  intent(in) :: vlen
         261             :   real(r8), intent(in) :: t(vlen)    ! Temperature
         262             :   real(r8), intent(in) :: p(vlen)    ! Pressure
         263             :   ! Outputs
         264             :   real(r8), intent(out) :: es(vlen)  ! Saturation vapor pressure
         265             :   real(r8), intent(out) :: qs(vlen)  ! Saturation specific humidity
         266             :
         267             :   integer,  intent(in), optional :: idx ! Scheme index
         268             :   integer :: i
         269             :
         270             :   !$acc data present (t,p,es,qs)
         271             :
         272           0 :   call wv_sat_svp_water_vect(t, es, vlen, idx)
         273           0 :   call wv_sat_svp_to_qsat_vect(es, p, qs, vlen)
         274             :
         275             :   !$acc parallel vector_length(VLENS) default(present)
         276             :   !$acc loop gang vector
         277           0 :   do i=1,vlen
         278             :      ! Ensures returned es is consistent with limiters on qs.
         279           0 :      es(i) = min(es(i), p(i))
         280             :   enddo
         281             :   !$acc end parallel
         282             :
         283             :   !$acc end data
         284           0 : end subroutine wv_sat_qsat_water_vect
         285             :
         286           0 : subroutine wv_sat_qsat_ice(t, p, es, qs, idx)
         287             :   !------------------------------------------------------------------!
         288             :   ! Purpose:                                                         !
         289             :   !   Calculate SVP over ice at a given temperature, and then        !
         290             :   !   calculate and return saturation specific humidity.             !
         291             :   !------------------------------------------------------------------!
         292             :
         293             :   ! Inputs
         294             :   real(r8), intent(in) :: t    ! Temperature
         295             :   real(r8), intent(in) :: p    ! Pressure
         296             :   ! Outputs
         297             :   real(r8), intent(out) :: es  ! Saturation vapor pressure
         298             :   real(r8), intent(out) :: qs  ! Saturation specific humidity
         299             :
         300             :   integer,  intent(in), optional :: idx ! Scheme index
         301             :
         302           0 :   es = wv_sat_svp_ice(t, idx)
         303             :
         304           0 :   qs = wv_sat_svp_to_qsat(es, p)
         305             :
         306             :   ! Ensures returned es is consistent with limiters on qs.
         307           0 :   es = min(es, p)
         308             :
         309           0 : end subroutine wv_sat_qsat_ice
         310             :
         311           0 : subroutine wv_sat_qsat_ice_vect(t, p, es, qs, vlen, idx)
         312             :   !------------------------------------------------------------------!
         313             :   ! Purpose:                                                         !
         314             :   !   Calculate SVP over ice at a given temperature, and then        !
         315             :   !   calculate and return saturation specific humidity.             !
         316             :   !------------------------------------------------------------------!
         317             :   ! Inputs
         318             :
         319             :   integer,  intent(in) :: vlen
         320             :   real(r8), intent(in) :: t(vlen)    ! Temperature
         321             :   real(r8), intent(in) :: p(vlen)    ! Pressure
         322             :   ! Outputs
         323             :   real(r8), intent(out) :: es(vlen)  ! Saturation vapor pressure
         324             :   real(r8), intent(out) :: qs(vlen)  ! Saturation specific humidity
         325             :
         326             :   integer,  intent(in), optional :: idx ! Scheme index
         327             :   integer :: i
         328             :
         329             :   !$acc data present (t,p,es,qs)
         330             :
         331           0 :   call wv_sat_svp_ice_vect(t, es, vlen, idx)
         332           0 :   call wv_sat_svp_to_qsat_vect(es, p, qs, vlen)
         333             :
         334             :   !$acc parallel vector_length(VLENS) default(present)
         335             :   !$acc loop gang vector
         336           0 :   do i=1,vlen
         337             :      ! Ensures returned es is consistent with limiters on qs.
         338           0 :      es(i) = min(es(i), p(i))
         339             :   enddo
         340             :   !$acc end parallel
         341             :
         342             :   !$acc end data
         343           0 : end subroutine wv_sat_qsat_ice_vect
         344             :
         345           0 : subroutine wv_sat_qsat_trans(t, p, es, qs, idx)
         346             :   !------------------------------------------------------------------!
         347             :   ! Purpose:                                                         !
         348             :   !   Calculate SVP over ice at a given temperature, and then        !
         349             :   !   calculate and return saturation specific humidity.             !
         350             :   !------------------------------------------------------------------!
         351             :
         352             :   ! Inputs
         353             :   real(r8), intent(in) :: t    ! Temperature
         354             :   real(r8), intent(in) :: p    ! Pressure
         355             :   ! Outputs
         356             :   real(r8), intent(out) :: es  ! Saturation vapor pressure
         357             :   real(r8), intent(out) :: qs  ! Saturation specific humidity
         358             :
         359             :   integer,  intent(in), optional :: idx ! Scheme index
         360             :
         361           0 :   es = wv_sat_svp_trans(t, idx)
         362             :
         363           0 :   qs = wv_sat_svp_to_qsat(es, p)
         364             :
         365             :   ! Ensures returned es is consistent with limiters on qs.
         366           0 :   es = min(es, p)
         367             :
         368           0 : end subroutine wv_sat_qsat_trans
         369             :
         370             : !---------------------------------------------------------------------
         371             : ! SVP INTERFACE FUNCTIONS
         372             : !---------------------------------------------------------------------
         373             :
         374 12128860192 : function wv_sat_svp_water(t, idx) result(es)
         375             :   real(r8), intent(in) :: t
         376             :   integer,  intent(in), optional :: idx
         377             :   real(r8)             :: es
         378             :
         379             :   integer :: use_idx
         380             :
         381 12128860192 :   if (present(idx)) then
         382           0 :      use_idx = idx
         383             :   else
         384 12128860192 :      use_idx = default_idx
         385             :   end if
         386             :
         387 12128860192 :   select case (use_idx)
         388             :   case(GoffGratch_idx)
         389 12128860192 :      es = GoffGratch_svp_water(t)
         390             :   case(MurphyKoop_idx)
         391           0 :      es = MurphyKoop_svp_water(t)
         392             :   case(Bolton_idx)
         393 12128860192 :      es = Bolton_svp_water(t)
         394             :   end select
         395             :
         396 12128860192 : end function wv_sat_svp_water
         397             :
         398           0 : subroutine  wv_sat_svp_water_vect(t, es, vlen, idx)
         399             :   integer,  intent(in) :: vlen
         400             :   real(r8), intent(in) :: t(vlen)
         401             :   integer,  intent(in), optional :: idx
         402             :   real(r8), intent(out) :: es(vlen)
         403             :   integer :: i
         404             :   integer :: use_idx
         405             :
         406             :   !$acc data present (t,es)
         407             :
         408           0 :   if (present(idx)) then
         409           0 :      use_idx = idx
         410             :   else
         411           0 :      use_idx = default_idx
         412             :   end if
         413             :
         414           0 :   select case (use_idx)
         415             :   case(GoffGratch_idx)
         416           0 :      call GoffGratch_svp_water_vect(t,es,vlen)
         417             :   case(MurphyKoop_idx)
         418           0 :      call MurphyKoop_svp_water_vect(t,es,vlen)
         419             :   case(Bolton_idx)
         420           0 :      call Bolton_svp_water_vect(t,es,vlen)
         421             :   end select
         422             :
         423             :   !$acc end data
         424           0 : end subroutine wv_sat_svp_water_vect
         425             :
         426      224256 : function wv_sat_svp_ice(t, idx) result(es)
         427             :   real(r8), intent(in)  :: t
         428             :   integer,  intent(in), optional :: idx
         429             :   real(r8)              :: es
         430             :
         431             :   integer :: use_idx
         432             :
         433      224256 :   if (present(idx)) then
         434           0 :      use_idx = idx
         435             :   else
         436      224256 :      use_idx = default_idx
         437             :   end if
         438             :
         439      224256 :   select case (use_idx)
         440             :   case(GoffGratch_idx)
         441      224256 :      es = GoffGratch_svp_ice(t)
         442             :   case(MurphyKoop_idx)
         443           0 :      es = MurphyKoop_svp_ice(t)
         444             :   case(Bolton_idx)
         445      224256 :      es = Bolton_svp_water(t)
         446             :   end select
         447             :
         448      224256 : end function wv_sat_svp_ice
         449             :
         450           0 : subroutine wv_sat_svp_ice_vect(t, es, vlen, idx)
         451             :   integer,  intent(in) :: vlen
         452             :   real(r8), intent(in) :: t(vlen)
         453             :   integer,  intent(in), optional :: idx
         454             :   real(r8), intent(out) :: es(vlen)
         455             :   integer :: i
         456             :
         457             :   integer :: use_idx
         458             :
         459             :   !$acc data present (t,es)
         460             :
         461           0 :   if (present(idx)) then
         462           0 :      use_idx = idx
         463             :   else
         464           0 :      use_idx = default_idx
         465             :   end if
         466             :
         467           0 :   select case (use_idx)
         468             :   case(GoffGratch_idx)
         469           0 :      call GoffGratch_svp_ice_vect(t,es,vlen)
         470             :   case(MurphyKoop_idx)
         471           0 :      call MurphyKoop_svp_ice_vect(t,es,vlen)
         472             :   case(Bolton_idx)
         473           0 :      call Bolton_svp_water_vect(t,es,vlen)
         474             :   end select
         475             :
         476             :   !$acc end data
         477           0 : end subroutine wv_sat_svp_ice_vect
         478             :
         479      385536 : function wv_sat_svp_trans(t, idx) result(es)
         480             :
         481             :   real(r8), intent(in) :: t
         482             :   integer,  intent(in), optional :: idx
         483             :   real(r8) :: es
         484             :
         485             :   real(r8) :: esice      ! Saturation vapor pressure over ice
         486             :   real(r8) :: weight     ! Intermediate scratch variable for es transition
         487             :
         488             : !
         489             : ! Water
         490             : !
         491      385536 :   if (t >= (tmelt - ttrice)) then
         492      192000 :      es = wv_sat_svp_water(t,idx)
         493             :   else
         494             :      es = 0.0_r8
         495             :   end if
         496             :
         497             : !
         498             : ! Ice
         499             : !
         500      385536 :   if (t < tmelt) then
         501             :
         502      224256 :      esice = wv_sat_svp_ice(t,idx)
         503             :
         504      224256 :      if ( (tmelt - t) > ttrice ) then
         505             :         weight = 1.0_r8
         506             :      else
         507       30720 :         weight = (tmelt - t)/ttrice
         508             :      end if
         509             :
         510      224256 :      es = weight*esice + (1.0_r8 - weight)*es
         511             :   end if
         512             :
         513      385536 : end function wv_sat_svp_trans
         514             :
         515           0 : subroutine wv_sat_svp_trans_vect(t, es, vlen, idx)
         516             :
         517             :   integer,  intent(in)  :: vlen
         518             :   real(r8), intent(in)  :: t(vlen)
         519             :   integer,  intent(in), optional :: idx
         520             :   real(r8), intent(out) :: es(vlen)
         521             :
         522           0 :   real(r8) :: esice(vlen)      ! Saturation vapor pressure over ice
         523             :   real(r8) :: weight           ! Intermediate scratch variable for es transition
         524             :   integer  :: i
         525             :
         526             :   !$acc data present (t,es) &
         527             :   !$acc      create  (esice)
         528             :
         529             : !
         530             : ! Water
         531             : !
         532           0 :   call wv_sat_svp_water_vect(t,es,vlen,idx)
         533             :   !$acc parallel vector_length(VLENS) default(present)
         534             :   !$acc loop gang vector
         535           0 :   do i = 1, vlen
         536           0 :      if (t(i) < (tmelt - ttrice)) then
         537           0 :         es(i) = 0.0_r8
         538             :      end if
         539             :   end do
         540             :   !$acc end parallel
         541             : !
         542             : ! Ice
         543             : !
         544           0 :   call wv_sat_svp_ice_vect(t,esice,vlen,idx)
         545             :   !$acc parallel vector_length(VLENS) default(present)
         546             :   !$acc loop gang vector
         547           0 :   do i = 1, vlen
         548           0 :      if (t(i) < tmelt) then
         549           0 :         if ( (tmelt - t(i)) > ttrice ) then
         550             :            weight = 1.0_r8
         551             :         else
         552           0 :            weight = (tmelt - t(i))/ttrice
         553             :         end if
         554             :
         555           0 :         es(i) = weight*esice(i) + (1.0_r8 - weight)*es(i)
         556             :      end if
         557             :   end do
         558             :   !$acc end parallel
         559             :
         560             :   !$acc end data
         561           0 : end subroutine wv_sat_svp_trans_vect
         562             :
         563             : !---------------------------------------------------------------------
         564             : ! SVP METHODS
         565             : !---------------------------------------------------------------------
         566             :
         567             : ! Goff & Gratch (1946)
         568             :
         569 12128860192 : function GoffGratch_svp_water(t) result(es)
         570             :   real(r8), intent(in) :: t  ! Temperature in Kelvin
         571             :   real(r8) :: es             ! SVP in Pa
         572             :
         573             :   ! uncertain below -70 C
         574             :   es = 10._r8**(-7.90298_r8*(tboil/t-1._r8)+ &
         575             :        5.02808_r8*log10(tboil/t)- &
         576             :        1.3816e-7_r8*(10._r8**(11.344_r8*(1._r8-t/tboil))-1._r8)+ &
         577             :        8.1328e-3_r8*(10._r8**(-3.49149_r8*(tboil/t-1._r8))-1._r8)+ &
         578 12128860192 :        log10(1013.246_r8))*100._r8
         579             :
         580 12128860192 : end function GoffGratch_svp_water
         581             :
         582           0 : subroutine GoffGratch_svp_water_vect(t, es, vlen)
         583             :   integer, intent(in) :: vlen
         584             :   real(r8), intent(in)  :: t(vlen)  ! Temperature in Kelvin
         585             :   real(r8), intent(out) :: es(vlen) ! SVP in Pa
         586             :   real(r8) :: log_tboil
         587             :   integer :: i
         588             :
         589             :   !$acc data present (t,es)
         590             :
         591             :   ! Goff, J. A., and S. Gratch. “Low-Pressure Properties of Water from -160F
         592             :   ! to 212F.” Trans. Am. Soc. Heat. Vent. Eng. 52 (1946): 95–121.
         593             :   ! uncertain below -70 C
         594             :
         595           0 :   log_tboil = log10(tboil)
         596             :
         597             :   !$acc parallel vector_length(VLENS) default(present)
         598             :   !$acc loop gang vector
         599           0 :   do i=1,vlen
         600           0 :      es(i) = 10._r8**(-7.90298_r8*(tboil/t(i)-1._r8)+ &
         601             :        5.02808_r8*(log_tboil-log10(t(i)))- &
         602             :        1.3816e-7_r8*(10._r8**(11.344_r8*(1._r8-t(i)/tboil))-1._r8)+ &
         603             :        8.1328e-3_r8*(10._r8**(-3.49149_r8*(tboil/t(i)-1._r8))-1._r8)+ &
         604           0 :        log10(1013.246_r8))*100._r8
         605             :   enddo
         606             :   !$acc end parallel
         607             :
         608             :   !$acc end data
         609           0 : end subroutine GoffGratch_svp_water_vect
         610             :
         611      224256 : function GoffGratch_svp_ice(t) result(es)
         612             :   real(r8), intent(in) :: t  ! Temperature in Kelvin
         613             :   real(r8) :: es             ! SVP in Pa
         614             :
         615             :   ! good down to -100 C
         616             :   es = 10._r8**(-9.09718_r8*(h2otrip/t-1._r8)-3.56654_r8* &
         617             :        log10(h2otrip/t)+0.876793_r8*(1._r8-t/h2otrip)+ &
         618      224256 :        log10(6.1071_r8))*100._r8
         619             :
         620      224256 : end function GoffGratch_svp_ice
         621             :
         622           0 : subroutine GoffGratch_svp_ice_vect(t, es, vlen)
         623             :   integer, intent(in)   :: vlen
         624             :   real(r8), intent(in)  :: t(vlen)  ! Temperature in Kelvin
         625             :   real(r8), intent(out) :: es(vlen) ! SVP in Pa
         626             :   real(r8), parameter :: log_param = log10(6.1071_r8)
         627             :   integer :: i
         628             :   ! good down to -100 C
         629             :
         630             :   !$acc data present (t,es)
         631             :
         632             :   !$acc parallel vector_length(VLENS) default(present)
         633             :   !$acc loop gang vector
         634           0 :   do i=1,vlen
         635           0 :      es(i) = 10._r8**(-9.09718_r8*(h2otrip/t(i)-1._r8)-3.56654_r8* &
         636             :           log10(h2otrip/t(i))+0.876793_r8*(1._r8-t(i)/h2otrip)+ &
         637           0 :           log_param)*100._r8
         638             :   enddo
         639             :   !$acc end parallel
         640             :
         641             :   !$acc end data
         642           0 : end subroutine GoffGratch_svp_ice_vect
         643             :
         644             : ! Murphy & Koop (2005)
         645             :
         646           0 : function MurphyKoop_svp_water(t) result(es)
         647             :   real(r8), intent(in) :: t  ! Temperature in Kelvin
         648             :   real(r8) :: es             ! SVP in Pa
         649             :
         650             :   ! (good for 123 < T < 332 K)
         651             :   es = exp(54.842763_r8 - (6763.22_r8 / t) - (4.210_r8 * log(t)) + &
         652             :        (0.000367_r8 * t) + (tanh(0.0415_r8 * (t - 218.8_r8)) * &
         653             :        (53.878_r8 - (1331.22_r8 / t) - (9.44523_r8 * log(t)) + &
         654           0 :        0.014025_r8 * t)))
         655             :
         656           0 : end function MurphyKoop_svp_water
         657             :
         658           0 : subroutine MurphyKoop_svp_water_vect(t, es, vlen)
         659             :   integer, intent(in)   :: vlen
         660             :   real(r8), intent(in)  :: t(vlen)  ! Temperature in Kelvin
         661             :   real(r8), intent(out) :: es(vlen)             ! SVP in Pa
         662             :
         663             :   integer :: i
         664             :   ! Murphy, D. M., and T. Koop. “Review of the Vapour Pressure of Ice and
         665             :   ! Supercooled Water for Atmospheric Applications.” Q. J. R. Meteorol.
         666             :   ! Soc. 131, no. 608 (2005): 1539–65. 10.1256/qj.04.94
         667             :   ! (good for 123 < T < 332 K)
         668             :
         669             :   !$acc data present (t,es)
         670             :
         671             :   !$acc parallel vector_length(VLENS) default(present)
         672             :   !$acc loop gang vector
         673           0 :   do i = 1, vlen
         674           0 :      es(i) = exp(54.842763_r8 - (6763.22_r8 / t(i)) - (4.210_r8 * log(t(i))) + &
         675             :           (0.000367_r8 * t(i)) + (tanh(0.0415_r8 * (t(i) - 218.8_r8)) * &
         676             :           (53.878_r8 - (1331.22_r8 / t(i)) - (9.44523_r8 * log(t(i))) + &
         677           0 :           0.014025_r8 * t(i))))
         678             :   end do
         679             :   !$acc end parallel
         680             :
         681             :   !$acc end data
         682           0 : end subroutine MurphyKoop_svp_water_vect
         683             :
         684           0 : function MurphyKoop_svp_ice(t) result(es)
         685             :   real(r8), intent(in) :: t  ! Temperature in Kelvin
         686             :   real(r8) :: es             ! SVP in Pa
         687             :
         688             :   ! (good down to 110 K)
         689             :   es = exp(9.550426_r8 - (5723.265_r8 / t) + (3.53068_r8 * log(t)) &
         690           0 :        - (0.00728332_r8 * t))
         691             :
         692           0 : end function MurphyKoop_svp_ice
         693             :
         694           0 : subroutine MurphyKoop_svp_ice_vect(t, es, vlen)
         695             :   integer, intent(in)   :: vlen
         696             :   real(r8), intent(in) :: t(vlen)  ! Temperature in Kelvin
         697             :   real(r8), intent(out) :: es(vlen)             ! SVP in Pa
         698             :
         699             :   integer :: i
         700             :   ! (good down to 110 K)
         701             :
         702             :   !$acc data present (t,es)
         703             :
         704             :   !$acc parallel vector_length(VLENS) default(present)
         705             :   !$acc loop gang vector
         706           0 :   do i = 1, vlen
         707           0 :      es(i) = exp(9.550426_r8 - (5723.265_r8 / t(i)) + (3.53068_r8 * log(t(i))) &
         708           0 :              - (0.00728332_r8 * t(i)))
         709             :   end do
         710             :   !$acc end parallel
         711             :
         712             :   !$acc end data
         713           0 : end subroutine MurphyKoop_svp_ice_vect
         714             :
         715             : ! Bolton (1980)
         716             : ! zm_conv deep convection scheme contained this SVP calculation.
         717             : ! It appears to be from D. Bolton, 1980, Monthly Weather Review.
         718             : ! Unlike the other schemes, no distinct ice formula is associated
         719             : ! with it. (However, a Bolton ice formula exists in CLUBB.)
         720             :
         721             : ! The original formula used degrees C, but this function
         722             : ! takes Kelvin and internally converts.
         723             :
         724           0 : function Bolton_svp_water(t) result(es)
         725             :   real(r8),parameter :: c1 = 611.2_r8
         726             :   real(r8),parameter :: c2 = 17.67_r8
         727             :   real(r8),parameter :: c3 = 243.5_r8
         728             :
         729             :   real(r8), intent(in) :: t  ! Temperature in Kelvin
         730             :   real(r8) :: es             ! SVP in Pa
         731             :
         732           0 :   es = c1*exp( (c2*(t - tmelt))/((t - tmelt)+c3) )
         733             :
         734           0 : end function Bolton_svp_water
         735             :
         736           0 : subroutine Bolton_svp_water_vect(t, es,vlen)
         737             :   real(r8),parameter :: c1 = 611.2_r8
         738             :   real(r8),parameter :: c2 = 17.67_r8
         739             :   real(r8),parameter :: c3 = 243.5_r8
         740             :
         741             :   integer, intent(in)   :: vlen
         742             :   real(r8), intent(in)  :: t(vlen)  ! Temperature in Kelvin
         743             :   real(r8), intent(out) :: es(vlen)             ! SVP in Pa
         744             :
         745             :   integer :: i
         746             :
         747             :   !$acc data present (t,es)
         748             :
         749             :   !$acc parallel vector_length(VLENS) default(present)
         750             :   !$acc loop gang vector
         751           0 :   do i = 1, vlen
         752           0 :      es(i) = c1*exp( (c2*(t(i) - tmelt))/((t(i) - tmelt)+c3) )
         753             :   end do
         754             :   !$acc end parallel
         755             :
         756             :   !$acc end data
         757           0 : end subroutine Bolton_svp_water_vect
         758             :
         759             : end module wv_sat_methods

Generated by: LCOV version 1.14