!--------------------------------------- LICENCE BEGIN -----------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer,
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer
!version 3 or (at your option) any later version that should be found at:
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software;
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec),
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------


module physicsFunctions_mod 10,1
  use MathPhysConstants_mod
  implicit none
  private

  ! public procedures
  public :: FOEW8, FODLE8, FOQST8, FODQS8, FOEFQ8, FOQFE8, FOTVT8, FOTTV8
  public :: FOHR8, FOEWA8, FODLA8, FOQSA8, FODQA8, FOHRA8, FOTW8, FOTI8
  public :: FODTW8, FODTI8, FOTWI8, FODTWI8, FOEW8_CMAM, FOEI8_CMAM, FOERAT8_CMAM
  public :: FOEWI8_CMAM, FODLE8_CMAM, FOQST8_CMAM, FOTW8_CMAM, FOTI8_CMAM, FODTW8_CMAM
  public :: FODTI8_CMAM, FOTWI8_CMAM, FODTWI8_CMAM, FQBRANCH, FOEFQL, fotvvl, FOEFQA
  public :: FOEFQPSA, fottva, folnqva

!**s/r physicsFunctions  - REAL*8 thermodyanmic statement functions.
!
!     Author: JM Belanger CMDA/SMC  Aug. 2000
!
!     Revision 001: Yves J. Rochon *ARQX/SMC, Sept 2004
!                   - Added functions of sat. vapour pressure
!                     over water (FOEW8_CMAM) and over ice (FOEI8_CMAM),
!                     resultant sat. specific humidity (FOQST8_CMAM), and
!                     others.
!
!     REAL*8 version of thermodynamic functions based on
!     fintern.cdk in the physics library.
!

  contains
!
! ==============================================================================
!
!     FONCTION DE TENSION DE VAPEUR SATURANTE (TETENS) - EW OU EI SELON TT

      real*8 function FOEW8(TTT) 2
        implicit none
        real*8 TTT
        FOEW8 = 610.78D0*EXP( MIN(SIGN(17.269D0,TTT-MPC_TRIPLE_POINT_R8),SIGN &
          (21.875D0,TTT-MPC_TRIPLE_POINT_R8))*ABS(TTT-MPC_TRIPLE_POINT_R8)/ &
          (TTT-35.86D0+MAX(0.D0,SIGN(28.2D0,MPC_TRIPLE_POINT_R8-TTT))))
      end function foew8
!
!     FONCTION CALCULANT LA DERIVEE SELON T DE  LN EW (OU LN EI)

      real*8 function FODLE8(TTT) 1
        implicit none
        real*8 TTT
        FODLE8=(4097.93D0+MAX(0.D0,SIGN(1709.88D0,MPC_TRIPLE_POINT_R8-TTT))) &
         /((TTT-35.86D0+MAX(0.D0,SIGN(28.2D0,MPC_TRIPLE_POINT_R8-TTT)))*  &
         (TTT-35.86D0+MAX(0.D0,SIGN(28.2D0,MPC_TRIPLE_POINT_R8-TTT))))
      end function FODLE8
!
!     FONCTION CALCULANT L'HUMIDITE SPECIFIQUE SATURANTE (QSAT)

      real*8 function FOQST8(TTT,PRS) ,1
        implicit none
        real*8 TTT,PRS
        FOQST8=MPC_EPS1_R8/(MAX(1.D0,PRS/FOEW8(TTT))-MPC_EPS2_R8)
      end function FOQST8
!
!     FONCTION CALCULANT LA DERIVEE DE QSAT SELON T

      real*8 function FODQS8(QST,TTT) ,1
        implicit none
        real*8 TTT,QST
        FODQS8=QST*(1.D0+MPC_DELTA_R8*QST)*FODLE8(TTT)
      end function FODQS8
!     QST EST LA SORTIE DE FOQST
!
!     FONCTION CALCULANT TENSION VAP (EEE) FN DE HUM SP (QQQ) ET PRS

      real*8 function FOEFQ8(QQQ,PRS)   6
        implicit none
        real*8 QQQ,PRS
        FOEFQ8= MIN(PRS,(QQQ*PRS) / (MPC_EPS1_R8 + MPC_EPS2_R8*QQQ))
      end function FOEFQ8
!
!     FONCTION CALCULANT HUM SP (QQQ) DE TENS. VAP (EEE) ET PRES (PRS)

      real*8 function FOQFE8(EEE,PRS)  
        implicit none
        real*8 EEE,PRS
        FOQFE8= MIN(1.D0,MPC_EPS1_R8*EEE / (PRS-MPC_EPS2_R8*EEE))
      end function FOQFE8
!
!     FONCTION CALCULANT TEMP VIRT. (TVI) DE TEMP (TTT) ET HUM SP (QQQ)

      real*8 function FOTVT8(TTT,QQQ)   5
        implicit none
        real*8 TTT,QQQ
        FOTVT8= TTT * (1.0D0 + MPC_DELTA_R8*QQQ)
      end function FOTVT8
!
!     FONCTION CALCULANT TTT DE TEMP VIRT. (TVI) ET HUM SP (QQQ)

      real*8 function FOTTV8(TVI,QQQ)  
        implicit none
        real*8 TVI,QQQ
        FOTTV8= TVI / (1.0D0 + MPC_DELTA_R8*QQQ)
      end function FOTTV8
!
!     FONCTION CALCULANT HUM REL DE HUM SP (QQQ), TEMP (TTT) ET PRES (PRS)
!     HR = E/ESAT

      real*8 function FOHR8(QQQ,TTT,PRS) ,2
        implicit none
        real*8 QQQ,TTT,PRS
        FOHR8 = MIN(PRS,FOEFQ8(QQQ,PRS)) / FOEW8(TTT)
      end function FOHR8
!
!     LES 5 FONCTIONS SUIVANTES SONT VALIDES DANS LE CONTEXTE OU ON
!     NE DESIRE PAS TENIR COMPTE DE LA PHASE GLACE DANS LES CALCULS
!     DE SATURATION.
!
!     FONCTION DE VAPEUR SATURANTE (TETENS)

      real*8 function FOEWA8(TTT)  2
        implicit none
        real*8 TTT
        FOEWA8=610.78D0*EXP(17.269D0*(TTT-MPC_TRIPLE_POINT_R8)/(TTT-35.86D0))
      end function FOEWA8
!
!     FONCTION CALCULANT LA DERIVEE SELON T DE LN EW

      real*8 function FODLA8(TTT)  1
        implicit none
        real*8 TTT
        FODLA8=17.269D0*(MPC_TRIPLE_POINT_R8-35.86D0)/(TTT-35.86D0)**2
      end function FODLA8
!
!     FONCTION CALCULANT L'HUMIDITE SPECIFIQUE SATURANTE

      real*8 function FOQSA8(TTT,PRS) ,1
        implicit none
        real*8 TTT,PRS
        FOQSA8=MPC_EPS1_R8/(MAX(1.D0,PRS/FOEWA8(TTT))-MPC_EPS2_R8)
      end function FOQSA8
!
!     FONCTION CALCULANT LA DERIVEE DE QSAT SELON T

      real*8 function FODQA8(QST,TTT) ,1
        implicit none
        real*8 QST,TTT
        FODQA8=QST*(1.D0+MPC_DELTA_R8*QST)*FODLA8(TTT)
      end function FODQA8
!
!     FONCTION CALCULANT L'HUMIDITE RELATIVE

      real*8 function FOHRA8(QQQ,TTT,PRS) ,2
        implicit none
        real*8 QQQ,TTT,PRS
        FOHRA8=MIN(PRS,FOEFQ8(QQQ,PRS))/FOEWA8(TTT)
      end function FOHRA8
!
!     LES 6 FONCTIONS SUIVANTES SONT REQUISES POUR LA TEMPERATURE
!     EN FONCTION DE LA TENSION DE VAPEUR SATURANTE.
!     (AJOUTE PAR YVES J. ROCHON, ARQX/SMC, JUIN 2004)
!
!     FONCTION DE LA TEMPERATURE EN FONCTION DE LA TENSION DE VAPEUR
!     SATURANTE PAR RAPPORT A EW.

      real*8 function FOTW8(EEE)  5
        implicit none
        real*8 EEE
        FOTW8=(35.86D0*LOG(EEE/610.78D0)-17.269D0*MPC_TRIPLE_POINT_R8)/ &
             (LOG(EEE/610.78D0)-17.269D0)
      end function FOTW8
!
!     FONCTION DE LA TEMPERATURE EN FONCTION DE LA TENSION DE VAPEUR
!     SATURANTE PAR RAPPORT A EI.

      real*8 function FOTI8(EEE)  1
        implicit none
        real*8 EEE
        FOTI8=(7.66D0*LOG(EEE/610.78D0)-21.875D0*MPC_TRIPLE_POINT_R8)/ &
             (LOG(EEE/610.78D0)-21.875D0)
      end function FOTI8
!
!     FONCTION DE LA DERIVE DE LA TEMPERATURE EN FONCTION DE LA TENSION DE
!     VAPEUR SATURANTE (EW).

      real*8 function FODTW8(TTT,EEE)  4
        implicit none
        real*8 TTT,EEE
        FODTW8=(35.86D0-TTT)/EEE/(LOG(EEE/610.78D0)-17.269D0)
      end function FODTW8
!
!     FONCTION DE LA DERIVE DE LA TEMPERATURE EN FONCTION DE LA TENSION DE
!     VAPEUR SATURANTE (EI).

      real*8 function FODTI8(TTT,EEE)  1
        implicit none
        real*8 TTT,EEE
        FODTI8=(7.66D0-TTT)/EEE  &
                      /(LOG(EEE/610.78D0)-21.875D0)
      end function FODTI8
!
!     FONCTION DE L'AJUSTEMENT DE LA TEMPERATURE.

      real*8 function FOTWI8(TTT,EEE) ,2
        implicit none
        real*8 TTT,EEE
        FOTWI8=MAX(0.0D0,SIGN(1.0D0,TTT-MPC_TRIPLE_POINT_R8))*FOTW8(EEE)  &
                     -MIN(0.0D0,SIGN(1.0D0,TTT-MPC_TRIPLE_POINT_R8))*FOTI8(EEE)
      end function FOTWI8
!
!     FONCTION DE L'AJUSTEMENT DE LA DERIVEE DE LA TEMPERATURE.

      real*8 function FODTWI8(TTT,EEE) ,2
        implicit none
        real*8 TTT,EEE
        FODTWI8=MAX(0.0D0,SIGN(1.0D0,TTT-MPC_TRIPLE_POINT_R8))*FODTW8(TTT,EEE)  &
                      -MIN(0.0D0,SIGN(1.0D0,TTT-MPC_TRIPLE_POINT_R8))*FODTI8(TTT,EEE)
      end function FODTWI8
!
!     LES 7 FONCTIONS SUIVANTES POUR EW-EI SONT REQUISES POUR LES MODELES
!     CMAM ET CGCM. (AJOUTE PAR YVES J. ROCHON, ARQX/SMC, JUIN 2004)
!
!     FONCTION DE TENSION DE VAPEUR SATURANTE - EW

      real*8 function FOEW8_CMAM(TTT)   1
        implicit none
        real*8 TTT
        FOEW8_CMAM= 100.D0*EXP(21.656D0-5418.D0/TTT)
      end function FOEW8_CMAM

!     FONCTION DE TENSION DE VAPEUR SATURANTE - EI

      real*8 function FOEI8_CMAM(TTT)   1
        implicit none
        real*8 TTT
        FOEI8_CMAM= 100.D0*EXP(24.292D0-6141.D0/TTT)
      end function FOEI8_CMAM
!
!     FONCTION DE LA PROPORTION DE LA CONTRIBUTION DE EW VS EI

      real*8 function FOERAT8_CMAM(TTT)  8
        implicit none
        real*8 TTT
        FOERAT8_CMAM=MIN(1.0D0,0.0059D0+0.9941D0*EXP(-0.003102D0*  &
            MIN(0.0D0,TTT-MPC_TRIPLE_POINT_R8)**2))
      end function FOERAT8_CMAM
!
!     FONCTION DE TENSION DE VAPEUR SATURANTE RESULTANTE - EW et EI

      real*8 function FOEWI8_CMAM(TTT)   1,4
        implicit none
        real*8 TTT
        FOEWI8_CMAM= FOEW8_CMAM(TTT)*FOERAT8_CMAM(TTT)  &
         +(1.0D0-FOERAT8_CMAM(TTT))*FOEI8_CMAM(TTT)
      end function FOEWI8_CMAM
!
!     FONCTION DE LA DERIVE DE LN(E) PAR RAPPORT A LA TEMPERATURE

      real*8 function FODLE8_CMAM(TTT)  ,2
        implicit none
        real*8 TTT
        FODLE8_CMAM= FOERAT8_CMAM(TTT)*5418.D0/TTT/TTT  &
         +(1.0D0-FOERAT8_CMAM(TTT))*6141.D0/TTT/TTT
      end function FODLE8_CMAM
!
!     FONCTION CALCULANT L'HUMIDITE SPECIFIQUE SATURANTE (QSAT).
!     PREND EN COMPTE LES PHASES GLACE ET EAU.

      real*8 function FOQST8_CMAM(TTT,PRS) ,1
        implicit none
        real*8 TTT,PRS
        FOQST8_CMAM=MPC_EPS1_R8/(MAX(1.0D0,PRS/  &
                           FOEWI8_CMAM(TTT))-MPC_EPS2_R8)
      end function FOQST8_CMAM
!
!     LES 6 FONCTIONS SUIVANTES SONT REQUISES POUR LA TEMPERATURE
!     EN FONCTION DE LA TENSION DE VAPEUR SATURANTE POUR CMAM/CGCM
!     (AJOUTE PAR YVES J. ROCHON, ARQX/SMC, JUIN 2004)
!
!     FONCTION DE LA TEMPERATURE EN FONCTION DE LA TENSION DE VAPEUR
!     SATURANTE PAR RAPPORT A EW.

      real*8 function FOTW8_CMAM(EEE)  1
        implicit none
        real*8 EEE
        FOTW8_CMAM=5418.D0/(21.656D0-LOG(EEE/100.0D0))
      end function FOTW8_CMAM
!
!     FONCTION DE LA TEMPERATURE EN FONCTION DE LA TENSION DE VAPEUR
!     SATURANTE PAR RAPPORT A EI.

      real*8 function FOTI8_CMAM(EEE)  1
        implicit none
        real*8 EEE
        FOTI8_CMAM=6141.D0/(24.292D0-LOG(EEE/100.0D0))
      end function FOTI8_CMAM
!
!     FONCTION DE LA DERIVE DE LA TEMPERATURE EN FONCTION DE LA TENSION DE
!     VAPEUR SATURANTE (EW).

      real*8 function FODTW8_CMAM(TTT,EEE)  1
        implicit none
        real*8 TTT,EEE
        FODTW8_CMAM=TTT/EEE/(21.656D0-LOG(EEE/100.0D0))
      end function FODTW8_CMAM
!
!     FONCTION DE LA DERIVE DE LA TEMPERATURE EN FONCTION DE LA TENSION DE
!     VAPEUR SATURANTE (EI).

      real*8 function FODTI8_CMAM(TTT,EEE)  1
        implicit none
        real*8 TTT,EEE
        FODTI8_CMAM=TTT/EEE/(24.292D0-LOG(EEE/100.0D0))
      end function FODTI8_CMAM
!
!     FONCTION DE L'AJUSTEMENT DE LA TEMPERATURE.

      real*8 function FOTWI8_CMAM(TTT,EEE) ,4
        implicit none
        real*8 TTT,EEE
        FOTWI8_CMAM= FOERAT8_CMAM(TTT)*FOTW8_CMAM(EEE)+ &
                   (1.0D0-FOERAT8_CMAM(TTT))*FOTI8_CMAM(EEE)
      end function FOTWI8_CMAM
!
!     FONCTION DE L'AJUSTEMENT DE LA DERIVEE DE LA TEMPERATURE.

      real*8 function FODTWI8_CMAM(TTT,EEE) ,4
        implicit none
        real*8 TTT,EEE
        FODTWI8_CMAM= FOERAT8_CMAM(TTT)*FODTW8_CMAM(TTT,EEE)+  &
                    (1.0D0-FOERAT8_CMAM(TTT))*FODTI8_CMAM(TTT,EEE)
      end function FODTWI8_CMAM
!

!
!     function returning 0/1 depending on the minimum q branch condition
!     as discussed by Brunet (1996) to prevent getting a vapour pressure that exceeds
!     the total pressure p when q exceeds 1.
!

      real*8 function FQBRANCH(QQQ)   4
        implicit none
        real*8 QQQ
        FQBRANCH= 0.5D0+SIGN(0.5D0,1.D0-(QQQ))
      end function FQBRANCH

!=============================================================================
!
!     TLM  of  THERMODYNAMIC FUNCTIONS USED IN 3DVAR
!     CONSTANTS FROM COMMON /CTESDYN/
!     NOTE: ALL FUNCTIONS WORK IN  S.I. UNITS
!           I.E PRS IN PA, QQQ IN KG/KG
!
!          ***C. Chouinard August 1998 ***
! Revision:
!          S. Pellerin *ARMA/AES - Sept. 1998
!                      -Tangent-linear operator of Tv
!
!
!      TLM  OF FUNCTION CALCULATING VAPOUR PRESSURE
!             - INPUT:  QQL ,  PERTURBATION OF LN SPECIFIC HUM
!                       PRSL ,   PERTURBATION OF SURFACE PRESSURE
!                       QQQ   ,  SPECIFIC HUMIDITY
!                       PRS   , PRESSURE
!                       PNETA   , VALUE OF ETA LEVEL
!             - OUTPUT: FOEFQL,  PERTURBATION  OF VAPOUR PRESSURE
!

      real*8 function FOEFQL(QQL,PRSL,QQQ,PRS,PNETA)   1,2
        implicit none
        real*8 QQL,PRSL,QQQ,PRS,PNETA
        FOEFQL= FQBRANCH(QQQ)  &
           * ((QQL*MPC_EPS1_R8*PRS*QQQ/(MPC_EPS1_R8+MPC_EPS2_R8*QQQ)  &
           +  PRSL*PNETA*QQQ)/(MPC_EPS1_R8+MPC_EPS2_R8*QQQ))  &
           + (1.0D0 - FQBRANCH(QQQ))*PRSL*PNETA
      end function FOEFQL
!
!
!---- Tangent-linear operator of virtual temperature -----
!
!     qqq: backgroud specific humidity
!     ttt: backgroud temperature
!     ttl: temperature increment
!     plnql: increment of logarithm specific humidity  (del(ln q))
!

      real*8 function fotvvl(qqq,ttt,ttl,plnql) 
        implicit none
        real*8 qqq,ttt,ttl,plnql
        fotvvl=(1 + MPC_DELTA_R8*qqq)*ttl + MPC_DELTA_R8*qqq*ttt*plnql
      end function fotvvl

!=============================================================================
!
!   DEFINITION OF ADJOINTS OF THERMODYNAMIC  FUNCTIONS
!   CONSTANTS AS IN COMMON /CTESDYN/
!     NOTE: ALL  UNITS S.I.
!           I.E. PADES IN DEG K, PRS EN PA, QQQ EN KG/KG
!
!      ADJOINT OF LN SPECIFIC  HUM (QQQ) DUE TO DEWPOINT DEPRESSION CORRECTIONS
!             - INPUT : PADES ,  ADJOINT OF DEWPOINT DEPRESSION
!                       PGAMMA,  ADOINT OF VAPOUR PRESSURE RELATIONSHIP
!                       QQQ   , SPECIFIC HUMIDITY
!                       PRS   , PRESSURE
!             - OUTPUT: FOEFQA, ADJOINT OF LN SPECIFIC HUMIDITY
!

      real*8 function FOEFQA(PADES,PGAMMA,QQQ,PRS)   2
        implicit none
        real*8 PADES,PGAMMA,QQQ,PRS
        FOEFQA= PADES*PGAMMA*MPC_EPS1_R8*PRS*QQQ/  &
                ((MPC_EPS1_R8+MPC_EPS2_R8*QQQ)*(MPC_EPS1_R8+MPC_EPS2_R8*QQQ))
      end function FOEFQA

!
!      ADJOINT OF SURFACE PRESSURE  DUE TO DEWPOINT DEPRESSION CORRECTIONS
!             - INPUT:  PADES ,  ADJOINT OF DEWPOINT DEPRESSION
!                       PGAMMA,  ADOINT OF VAPOUR PRESSURE RELATIONSHIP
!                       QQQ   , SPECIFIC HUMIDITY
!                       PNETA   , VALUE OF NETA
!             - OUTPUT: FOEFQPSA, ADJOINT OF SURFACE PRESSURE
!

      real*8 function FOEFQPSA(PADES,PGAMMA,QQQ,PNETA)  2
        implicit none
        real*8 PADES,PGAMMA,QQQ,PNETA
        FOEFQPSA = PADES*PGAMMA*QQQ*PNETA/  &
                   (MPC_EPS1_R8+MPC_EPS2_R8*QQQ)
      end function FOEFQPSA

!
!--------------------- Adjoint of virtual temperature operator -------------------------
!
!     fottva: Adjoint of temperature due to virtual temperature correction
!     qqq:   background specific humidity
!     tva:   adjoint variable of virtual temperature
!

      real*8 function fottva(qqq,tva)   5
        implicit none
        real*8 qqq,tva
        fottva= (1D0 + MPC_DELTA_R8*qqq)*tva
      end function fottva

!
!     folnqva: Adjoint of logarithm of specific humidity due to virtual temperature correction
!     qqq:   background specific humidity
!     ttt:   background temperature
!     tva:   adjoint variable of virtual temperature
!

      real*8 function folnqva(qqq,ttt,tva)  4
        implicit none
        real*8 qqq,ttt,tva
        folnqva = MPC_DELTA_R8*qqq*ttt*tva
      end function folnqva

end module physicsFunctions_mod