! module ArrayMod
! deals with basic array operations
! contains: RandomiseSeed, UnBlankReal, UnBlankInteger, GetChunkMeans

module ArrayMod

implicit none

contains

!*******************************************************************************
! get random value and make it act as seed, using time
! once this has been called, simply use random_number

subroutine RandomiseSeed

integer, dimension(1) :: Seed
real, parameter :: MissVal = -999.0
integer :: Minute,Second
character (len=80) :: ListDump, Trash, CommandLine

ListDump = '/cru/u2/f709762/data/scratch/listdump.txt'
ListDump = trim (ListDump)

CommandLine = 'ps -o etime > ' // ListDump
CommandLine = trim (CommandLine)
call system (CommandLine)

open  (2,file=ListDump,status="old",action="read")
read  (2,*), Trash
read  (2,"(a6,i2,a1,i2,a1,i2)"), Trash, Minute, Trash, Second
close (2)

CommandLine = 'rm ' // ListDump
CommandLine = trim (CommandLine)
call system (CommandLine)

Seed(1) = MissVal

if (Minute.NE.0) then
  if (Second.NE.0) then
	Seed(1) = (1000*Minute) / Second
  else
	Seed(1) = Minute
  end if
else
  if (Second.NE.0) &
	Seed(1) = Second
end if

! call random_seed (put=Seed)	! compaq fortran version
call random_seed

end subroutine RandomiseSeed

!*******************************************************************************
! weed out missing values and reform array so that it has the right size
!   to contain all, and only, valid values

subroutine UnBlankReal (InVector,OutVector)

real, pointer, dimension (:) 	:: InVector,OutVector

real, parameter :: MissVal = -999.0

integer :: AllocStat
integer :: InN, ValidN
integer :: XIn, XValid

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

InN = size (InVector,1)

ValidN = 0
do XIn = 1, InN
  if (InVector(XIn).NE.MissVal) ValidN = ValidN + 1
end do

allocate (OutVector(ValidN), stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: UnBlankReal: Allocation failure #####"
OutVector = MissVal

XValid = 0
do XIn = 1, InN
  if (InVector(XIn).NE.MissVal) then
  	XValid = XValid + 1
  	OutVector (XValid) = InVector (XIn)
  end if
end do

end subroutine UnBlankReal

!*******************************************************************************
! weed out missing values and reform array so that it has the right size
!   to contain all, and only, valid values

subroutine UnBlankInteger (InVector,OutVector)

integer, pointer, dimension (:) :: InVector,OutVector

real, parameter :: MissVal = -999.0

integer :: AllocStat
integer :: InN, ValidN
integer :: XIn, XValid

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

InN = size (InVector,1)

ValidN = 0
do XIn = 1, InN
  if (InVector(XIn).NE.MissVal) ValidN = ValidN + 1
end do

allocate (OutVector(ValidN), stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: UnBlankInteger: Allocation failure #####"
OutVector = MissVal

XValid = 0
do XIn = 1, InN
  if (InVector(XIn).NE.MissVal) then
  	XValid = XValid + 1
  	OutVector (XValid) = InVector (XIn)
  end if
end do

end subroutine UnBlankInteger

!*******************************************************************************
! cut up Data into chunks, calc means, and return means in Chunks
! offset >= 0 and is the number of values to omit at the beginning

subroutine GetChunkMeans (Data,Chunks,Offset,PerLen,GapLen,MissAccept)

real, pointer, dimension (:) :: Data, Chunks

integer, intent(in) :: Offset, PerLen, GapLen

real, intent(in) :: MissAccept

real, parameter :: MissVal = -999.0

real :: SectN, Thresh, OpTot, OpEn

integer :: InN, ChunkN, LastBit
integer :: XChunk, XYear, XIn
integer :: Abandon, AllocStat, ValidTot

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

Abandon = 0					! checks arguments are acceptable
if (Offset.LT.0.OR.PerLen.LT.1.OR.GapLen.LT.0.OR.MissAccept.GT.100.OR.MissAccept.LT.0) Abandon = 1

if (Abandon.EQ.0) then				! calcs number of chunks
  InN     = size (Data,1)
  SectN   = (real(InN)-real(Offset)) / (real(PerLen)+real(GapLen))
  LastBit = InN - Offset - (floor(SectN) * (PerLen+GapLen))
  ChunkN  = floor(SectN)
  if (LastBit.GE.PerLen) ChunkN = ChunkN + 1
  if (ChunkN.LT.1) Abandon = 1
  Thresh = (100.0 - MissAccept) * real(PerLen) / 100.0  
end if

if (Abandon.EQ.0) then				! chunkify into means
  allocate (Chunks(ChunkN), stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: GetChunkMeans: Allocation failure #####"
  Chunks = MissVal
  
  ValidTot = 0
  XIn      = Offset
  
  do XChunk = 1, ChunkN
    OpTot = 0.0
    OpEn  = 0.0
    
    do XYear = 1, PerLen			! go through period to obtain total
      XIn = XIn + 1
      if (Data(XIn).NE.MissVal) then
        OpTot = OpTot + Data(XIn)
        OpEn  = OpEn  + 1.0
      end if
    end do
    						! obtain chunk mean
    if (OpEn.GE.Thresh.AND.OpEn.GT.0) then
    	Chunks(XChunk) = OpTot / OpEn
    	ValidTot = ValidTot + 1
    end if
    
    if (XChunk.LT.ChunkN) XIn = XIn + GapLen	! miss out gap
  end do
else						! return without chunkifying
  allocate (Chunks(1), stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: GetChunkMeans: Allocation failure #####"
  Chunks = MissVal
end if

end subroutine GetChunkMeans

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

end module ArrayMod
