include file: modgps03diff.cdk90
! -*- F90 -*-

!
! Structure containing a variable and its derivatives wrt the control
! variables of a model profile.
!
! Types:
!      gpsdiff:
!        Var     :: Value
!        DVar    :: List of derivatives of Var wrt the control vars
!
! Josep M. Aparicio, 2003-2012.
! ARMA/ASTD
! Environment Canada
!


module modgps03diff 20,70
  use modgps00base        , only: i4, dp, ngpscvmx
  implicit none
  
  type gpsdiff
     real(dp)           :: Var
     real(dp)           :: DVar(ngpscvmx)
  end type gpsdiff
  

  interface assignment(=)
     module procedure gpsdiffasfd, gpsdiffasff
  end interface
  

  interface operator(+)
     module procedure gpsdiffsmfd, gpsdiffsmdf, gpsdiffsmfi, gpsdiffsmif, gpsdiffsmff
  end interface
  

  interface operator(-)
     module procedure gpsdiffsbfd, gpsdiffsbdf, gpsdiffsbfi, gpsdiffsbif, gpsdiffsbff
  end interface
  

  interface operator(*)
     module procedure gpsdiffmlfd, gpsdiffmldf, gpsdiffmlfi, gpsdiffmlif, gpsdiffmlff
  end interface
  

  interface operator(/)
     module procedure gpsdiffdvfd, gpsdiffdvdf, gpsdiffdvfi, gpsdiffdvif, gpsdiffdvff
  end interface
  

  interface operator(**)
     module procedure gpsdiffpwfd, gpsdiffpwdf, gpsdiffpwfi, gpsdiffpwif, gpsdiffpwff
  end interface


  interface sqrt
     module procedure gpsdiffsqr
  end interface


  interface exp
     module procedure gpsdiffexp
  end interface
  

  interface log
     module procedure gpsdifflog
  end interface


  interface cos
     module procedure gpsdiffcos
  end interface


  interface tan
     module procedure gpsdifftan
  end interface


  interface acos
     module procedure gpsdiffacos
  end interface


  interface atan
     module procedure gpsdiffatan
  end interface
  
  private gpsdiffasfd, gpsdiffasff
  private gpsdiffsmfd, gpsdiffsmdf, gpsdiffsmfi, gpsdiffsmif, gpsdiffsmff
  private gpsdiffsbfd, gpsdiffsbdf, gpsdiffsbfi, gpsdiffsbif, gpsdiffsbff
  private gpsdiffmlfd, gpsdiffmldf, gpsdiffmlfi, gpsdiffmlif, gpsdiffmlff
  private gpsdiffdvfd, gpsdiffdvdf, gpsdiffdvfi, gpsdiffdvif, gpsdiffdvff
  private gpsdiffpwfd, gpsdiffpwdf, gpsdiffpwfi, gpsdiffpwif, gpsdiffpwff
  private gpsdiffexp
  private gpsdifflog
  private gpsdiffcos
  private gpsdifftan
  private gpsdiffacos
  private gpsdiffatan
  
contains


  pure subroutine gpsdiffasfd(gd1, d2) 2
    type(gpsdiff), intent(out) :: gd1
    real(dp)     , intent(in)  :: d2
    
    gd1%Var  = d2
    gd1%DVar = 0._dp
  end subroutine gpsdiffasfd


  pure subroutine gpsdiffasff(gd1, gd2) 2
    type(gpsdiff), intent(out) :: gd1
    type(gpsdiff), intent(in)  :: gd2
    
    gd1%Var  = gd2%Var
    gd1%DVar = gd2%DVar
  end subroutine gpsdiffasff


  pure function gpsdiffsmfd(gd1, d2) 2
    type(gpsdiff), intent(in)  :: gd1
    real(dp)     , intent(in)  :: d2
    type(gpsdiff)              :: gpsdiffsmfd
    
    gpsdiffsmfd%Var  = gd1%Var  + d2
    gpsdiffsmfd%DVar = gd1%DVar
  end function gpsdiffsmfd


  pure function gpsdiffsmdf(d1, gd2) 2
    real(dp)     , intent(in)  :: d1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffsmdf
    
    gpsdiffsmdf%Var  = d1 + gd2%Var
    gpsdiffsmdf%DVar =      gd2%DVar
  end function gpsdiffsmdf


  pure function gpsdiffsmfi(gd1, i2) 2
    type(gpsdiff), intent(in)  :: gd1
    integer(i4)  , intent(in)  :: i2
    type(gpsdiff)              :: gpsdiffsmfi
    
    gpsdiffsmfi%Var  = gd1%Var  + i2
    gpsdiffsmfi%DVar = gd1%DVar
  end function gpsdiffsmfi


  pure function gpsdiffsmif(i1, gd2) 2
    integer(i4)  , intent(in)  :: i1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffsmif
    
    gpsdiffsmif%Var  = i1 + gd2%Var
    gpsdiffsmif%DVar =      gd2%DVar
  end function gpsdiffsmif


  pure function gpsdiffsmff(gd1, gd2) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffsmff
    
    gpsdiffsmff%Var  = gd1%Var  + gd2%Var
    gpsdiffsmff%DVar = gd1%DVar + gd2%DVar
  end function gpsdiffsmff
  

  pure function gpsdiffsbfd(gd1, d2) 2
    type(gpsdiff), intent(in)  :: gd1
    real(dp)     , intent(in)  :: d2
    type(gpsdiff)              :: gpsdiffsbfd
    
    gpsdiffsbfd%Var  = gd1%Var  - d2
    gpsdiffsbfd%DVar = gd1%DVar
  end function gpsdiffsbfd


  pure function gpsdiffsbdf(d1, gd2) 2
    real(dp)     , intent(in)  :: d1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffsbdf
    
    gpsdiffsbdf%Var  = d1 - gd2%Var
    gpsdiffsbdf%DVar =    - gd2%DVar
  end function gpsdiffsbdf


  pure function gpsdiffsbfi(gd1, i2) 2
    type(gpsdiff), intent(in)  :: gd1
    integer(i4)  , intent(in)  :: i2
    type(gpsdiff)              :: gpsdiffsbfi
    
    gpsdiffsbfi%Var  = gd1%Var  - i2
    gpsdiffsbfi%DVar = gd1%DVar
  end function gpsdiffsbfi


  pure function gpsdiffsbif(i1, gd2) 2
    integer(i4)  , intent(in)  :: i1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffsbif
    
    gpsdiffsbif%Var  = i1 - gd2%Var
    gpsdiffsbif%DVar =    - gd2%DVar
  end function gpsdiffsbif


  pure function gpsdiffsbff(gd1, gd2) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffsbff
    
    gpsdiffsbff%Var  = gd1%Var  - gd2%Var
    gpsdiffsbff%DVar = gd1%DVar - gd2%DVar
  end function gpsdiffsbff


  pure function gpsdiffmlfd(gd1, d2) 2
    type(gpsdiff), intent(in)  :: gd1
    real(dp)     , intent(in)  :: d2
    type(gpsdiff)              :: gpsdiffmlfd
    
    gpsdiffmlfd%Var  = d2 * gd1%Var
    gpsdiffmlfd%DVar = d2 * gd1%DVar
  end function gpsdiffmlfd


  pure function gpsdiffmldf(d1, gd2) 2
    real(dp)     , intent(in)  :: d1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffmldf
    
    gpsdiffmldf%Var  = d1 * gd2%Var
    gpsdiffmldf%DVar = d1 * gd2%DVar
  end function gpsdiffmldf


  pure function gpsdiffmlfi(gd1, i2) 2
    type(gpsdiff), intent(in)  :: gd1
    integer(i4)  , intent(in)  :: i2
    type(gpsdiff)              :: gpsdiffmlfi
    
    gpsdiffmlfi%Var  = i2 * gd1%Var
    gpsdiffmlfi%DVar = i2 * gd1%DVar
  end function gpsdiffmlfi


  pure function gpsdiffmlif(i1, gd2) 2
    integer(i4)  , intent(in)  :: i1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffmlif
    
    gpsdiffmlif%Var  = i1 * gd2%Var
    gpsdiffmlif%DVar = i1 * gd2%DVar
  end function gpsdiffmlif


  pure function gpsdiffmlff(gd1, gd2) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffmlff
    
    gpsdiffmlff%Var  = gd1%Var * gd2%Var
    gpsdiffmlff%DVar = (gd2%Var * gd1%DVar) + (gd1%Var * gd2%DVar)
  end function gpsdiffmlff


  pure function gpsdiffdvfd(gd1, d2) 2
    type(gpsdiff), intent(in)  :: gd1
    real(dp)     , intent(in)  :: d2
    type(gpsdiff)              :: gpsdiffdvfd
    
    gpsdiffdvfd%Var  = gd1%Var  / d2
    gpsdiffdvfd%DVar = gd1%DVar / d2
  end function gpsdiffdvfd


  pure function gpsdiffdvdf(d1, gd2) 2
    real(dp)     , intent(in)  :: d1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffdvdf
    
    gpsdiffdvdf%Var  =  d1 / gd2%Var
    gpsdiffdvdf%DVar = (-d1 / gd2%Var**2) * gd2%DVar
  end function gpsdiffdvdf


  pure function gpsdiffdvfi(gd1, i2) 2
    type(gpsdiff), intent(in)  :: gd1
    integer(i4)  , intent(in)  :: i2
    type(gpsdiff)              :: gpsdiffdvfi
    
    gpsdiffdvfi%Var  = gd1%Var  / i2
    gpsdiffdvfi%DVar = gd1%DVar / i2
  end function gpsdiffdvfi


  pure function gpsdiffdvif(i1, gd2) 2
    integer(i4)  , intent(in)  :: i1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffdvif
    
    gpsdiffdvif%Var  = i1 / gd2%Var
    gpsdiffdvif%DVar = (-i1 / gd2%Var**2) * gd2%DVar
  end function gpsdiffdvif


  pure function gpsdiffdvff(gd1, gd2) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffdvff
    real(dp)                   :: onegd2
    
    onegd2 = 1._dp / gd2%Var
    gpsdiffdvff%Var  = gd1%Var * onegd2
    gpsdiffdvff%DVar = onegd2 * gd1%DVar - (gd1%Var*onegd2*onegd2) * gd2%DVar
  end function gpsdiffdvff


  pure function gpsdiffpwfd(gd1, d2) 2
    type(gpsdiff), intent(in)  :: gd1
    real(dp)     , intent(in)  :: d2
    type(gpsdiff)              :: gpsdiffpwfd
    
    gpsdiffpwfd%Var  = gd1%Var  ** d2
    gpsdiffpwfd%DVar = (d2*(gd1%Var**(d2-1._dp))) * gd1%DVar
  end function gpsdiffpwfd


  pure function gpsdiffpwdf(d1, gd2) 2
    real(dp)     , intent(in)  :: d1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffpwdf
    
    gpsdiffpwdf%Var  =  d1 ** gd2%Var
    gpsdiffpwdf%DVar = (log(d1)*d1**gd2%Var) * gd2%DVar
  end function gpsdiffpwdf


  pure function gpsdiffpwfi(gd1, i2) 2
    type(gpsdiff), intent(in)  :: gd1
    integer(i4)  , intent(in)  :: i2
    type(gpsdiff)              :: gpsdiffpwfi
    
    gpsdiffpwfi%Var  = gd1%Var  ** i2
    gpsdiffpwfi%DVar = (i2*(gd1%Var**(i2-1))) * gd1%DVar
  end function gpsdiffpwfi


  pure function gpsdiffpwif(i1, gd2) 2
    integer(i4)  , intent(in)  :: i1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffpwif
    
    gpsdiffpwif%Var  = i1 ** gd2%Var
    gpsdiffpwif%DVar = (log(1._dp*i1)*i1**gd2%Var) * gd2%DVar
  end function gpsdiffpwif


  pure function gpsdiffpwff(gd1, gd2) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff), intent(in)  :: gd2
    type(gpsdiff)              :: gpsdiffpwff
    
    gpsdiffpwff%Var  = gd1%Var ** gd2%Var
    gpsdiffpwff%DVar = ( gd2%Var * ( gd1%Var**(gd2%Var-1) ) ) * gd1%DVar +    &
         (log(gd1%Var)*(gd1%Var**gd2%Var))*gd2%DVar
  end function gpsdiffpwff


  pure function gpsdiffsqr(gd1) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff)              :: gpsdiffsqr
    
    gpsdiffsqr%Var  = sqrt( gd1%Var )
    gpsdiffsqr%DVar = (0.5_dp / sqrt( gd1%Var )) * gd1%DVar
  end function gpsdiffsqr


  pure function gpsdiffexp(gd1) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff)              :: gpsdiffexp
    
    gpsdiffexp%Var  = exp(gd1%Var)
    gpsdiffexp%DVar = gd1%DVar * exp(gd1%Var)
  end function gpsdiffexp
  

  pure function gpsdifflog(gd1) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff)              :: gpsdifflog
    
    gpsdifflog%Var  = log(gd1%Var)
    gpsdifflog%DVar = gd1%DVar / gd1%Var
  end function gpsdifflog


  pure function gpsdiffcos(gd1) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff)              :: gpsdiffcos
    
    gpsdiffcos%Var  = cos(gd1%Var)
    gpsdiffcos%DVar = gd1%DVar * (-1._dp*sin(gd1%Var))
  end function gpsdiffcos


  pure function gpsdifftan(gd1) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff)              :: gpsdifftan
    
    gpsdifftan%Var  = tan(gd1%Var)
    gpsdifftan%DVar = (1._dp/cos(gd1%Var)**2) * gd1%DVar
  end function gpsdifftan


  pure function gpsdiffacos(gd1) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff)              :: gpsdiffacos
    
    gpsdiffacos%Var  = acos(gd1%Var)
    gpsdiffacos%DVar = gd1%DVar * (-1._dp/(1._dp-gd1%Var*gd1%Var))
  end function gpsdiffacos


  pure function gpsdiffatan(gd1) 2
    type(gpsdiff), intent(in)  :: gd1
    type(gpsdiff)              :: gpsdiffatan
    
    gpsdiffatan%Var  = atan(gd1%Var)
    gpsdiffatan%DVar = (1._dp/(1._dp+gd1%Var**2)) * gd1%DVar
  end function gpsdiffatan
  
end module modgps03diff