! ttest.f90
! module contains routines for T-testing

module TTest

implicit none

contains

!*******************************************************************************

subroutine DiffMeans (SampleA,SampleB,BegA,EndA,BegB,EndB,Upper)

real, pointer, dimension (:) :: SampleA,SampleB
integer, intent (in) :: BegA,EndA,BegB,EndB
real, intent(out) :: Upper

real, parameter :: MissVal=-999.0

real :: OpEn,OpTot,OpTotSq,MeanA,MeanB,VarA,VarB,EnA,EnB
real :: TestStat,Denom
integer :: NAye,NBee
integer :: XAye,XBee

MeanA=MissVal ; MeanB=MissVal ; VarA=MissVal ; VarB=MissVal 
EnA=MissVal ; EnB=MissVal ; Upper=MissVal

OpEn=0 ; OpTot=0 ; OpTotSq=0
do XAye = BegA,EndA
  if (SampleA(XAye).NE.MissVal) then
    OpEn=OpEn+1 ; OpTot=OpTot+SampleA(XAye)
    OpTotSq=OpTotSq+(SampleA(XAye)**2)
  end if
end do
if (OpEn.GT.1) then
  EnA=OpEn
  MeanA=OpTot/OpEn
  VarA=(OpEn/(OpEn-1))*((OpTotSq/OpEn)-(MeanA**2))
end if

if (EnA.NE.MissVal) then
 OpEn=0 ; OpTot=0 ; OpTotSq=0
 do XBee = BegB,EndB
  if (SampleB(XBee).NE.MissVal) then
    OpEn=OpEn+1 ; OpTot=OpTot+SampleB(XBee)
    OpTotSq=OpTotSq+(SampleB(XBee)**2)
  end if
 end do
 if (OpEn.GT.1) then
  EnB=OpEn
  MeanB=OpTot/OpEn
  VarB=(OpEn/(OpEn-1))*((OpTotSq/OpEn)-(MeanB**2))
 
  if ((EnA+EnB).GT.7) then
    Denom = (VarA/EnA)+(VarB/EnB)
    if (Denom.GT.0) then
      TestStat = (MeanA-MeanB) / sqrt(Denom)
      Upper = studnt (TestStat,(EnA+EnB-2.0))
    end if
  end if
 end if
end if

end subroutine DiffMeans

!*******************************************************************************

FUNCTION studnt (t, doff) RESULT(fn_val)

! N.B. Argument IFAULT has been removed.
 
! Code converted using TO_F90 by Alan Miller
! Date: 2002-01-02  Time: 21:19:45
! TDM 28.04.03 : it seems that this gives the p-value for a 2-tail test

!     ALGORITHM AS 27  APPL. STATIST. VOL.19, NO.1

!     Calculate the upper tail area under Student's t-distribution

!     Translated from Algol by Alan Miller

IMPLICIT NONE
REAL, INTENT(IN)      :: t
REAL, INTENT(IN)      :: doff
REAL                  :: fn_val

!     Local variables

REAL     :: v, x, tt
LOGICAL  :: pos
REAL, PARAMETER  :: four = 4.0, one = 1.0, zero = 0.0, half = 0.5
REAL, PARAMETER  :: a1 = 0.09979441, a2 = -0.581821, a3 = 1.390993,  &
                    a4 = -1.222452, a5 = 2.151185
REAL, PARAMETER  :: b1 = 5.537409, b2 = 11.42343
REAL, PARAMETER  :: c1 = 0.04431742, c2 = -0.2206018, c3 = -0.03317253,  &
                    c4 = 5.679969, c5 = -12.96519
REAL, PARAMETER  :: d1 = 5.166733, d2 = 13.49862
REAL, PARAMETER  :: e1 = 0.009694901, e2 = -0.1408854, e3 = 1.88993,  &
                    e4 = -12.75532, e5 = 25.77532
REAL, PARAMETER  :: f1 = 4.233736, f2 = 14.3963
REAL, PARAMETER  :: g1 = -9.187228E-5, g2 = 0.03789901, g3 = -1.280346,  &
                    g4 = 9.249528, g5 = -19.08115
REAL, PARAMETER  :: h1 = 2.777816, h2 = 16.46132
REAL, PARAMETER  :: i1 = 5.79602E-4, i2 = -0.02763334, i3 = 0.4517029,  &
                    i4 = -2.657697, i5 = 5.127212
REAL, PARAMETER  :: j1 = 0.5657187, j2 = 21.83269

!     Check that number of degrees of freedom > 4.

IF (doff <= four) THEN
  WRITE(*, *) '** Error in AS27 - degrees of freedom <= 4  **'
  RETURN
END IF

!     Evaluate series.

v = one / doff
pos = (t >= zero)
tt = ABS(t)
x = half*(one +   &
    tt*(((a1 + v*(a2 + v*(a3 + v*(a4 + v*a5)))) / (one - v*(b1 - v*b2))) +  &
    tt*(((c1 + v*(c2 + v*(c3 + v*(c4 + v*c5)))) / (one - v*(d1 - v*d2))) +  &
    tt*(((e1 + v*(e2 + v*(e3 + v*(e4 + v*e5)))) / (one - v*(f1 - v*f2))) +  &
    tt*(((g1 + v*(g2 + v*(g3 + v*(g4 + v*g5)))) / (one - v*(h1 - v*h2))) +  &
    tt*((i1 + v*(i2 + v*(i3 + v*(i4 + v*i5)))) / (one - v*(j1 - v*j2))) ))))) ** (-8)
IF (pos) THEN
  fn_val = x
ELSE
  fn_val = one - x
END IF

RETURN
END FUNCTION studnt

end module TTest
