! anomproducts.f90
! f90 main program written on 20.12.99 by Tim Mitchell
! last modification on 02.10.00
! now fireproofed against PC crashes
! f90 -o anomproducts initialmod.f90 arraymod.f90 loadmod.f90 runselectmod.f90 extractmod.f90 
! transformmod.f90 savemod.f90 anomproducts.f90

program AnomProducts

use InitialMod
use LoadMod
use RunSelectMod
use ExtractMod	
use TransformMod
use SaveMod

implicit none

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

real, pointer, dimension (:)	:: WorkGloAnaSlice, TempIn, TempOut, TempOutA, TempOutB
real, pointer, dimension (:)	:: WorkBases, WorkMultiplier
real, pointer, dimension (:,:)	:: WorkLinAnaSeries, WorkGotDecade, WorkGotFull

integer, pointer, dimension (:) 	:: WorkADYear, WorkMapRawReg, WorkRegSizes, WorkAnaSizes
integer, pointer, dimension (:) 	:: WorkDecYearN, WorkDecGetYear0, WorkDecGetYear1
integer, pointer, dimension (:) 	:: WorkDecStyleThis, WorkDecStyleNext
integer, pointer, dimension (:,:) 	:: WorkMapIDLRaw, WorkMapIDLReg
integer, pointer, dimension (:,:) 	:: WorkDecBlockKey, WorkGotMem

integer, allocatable, dimension (:,:) 	:: DecValid

character (len=20), pointer, dimension (:) 	:: WorkRegNames
character (len=80), pointer, dimension (:) 	:: WorkDecPathThis, WorkDecPathNext

real, parameter :: MissVal = -999.0

integer :: WorkMonth0,WorkMonth1,WorkMonthN,WorkYearN,WorkDecN
integer :: WorkGrid,WorkLongN,WorkLatN,WorkDataN,WorkRegN
integer :: AllocStat, ReadStatus
integer :: XDec, XReg, XYear, XMem, XLong
integer :: Year0, Year1, ADYear0, ADYear1
integer :: DegChosen, SaveChosen, AnomChosen, QDeTrend
integer :: MemN, Unitary
integer :: DataMissN, RegValidN, YearValidN
integer :: QSaveUnsmoo, QSaveSmoo, QSaveRegMeans, QMaskPoles

character (len=10) :: WorkGridTitle
character (len=40) :: WorkRegTitle
character (len=80) :: WorkGridFilePath, WorkDecTitle, SaveTitle, GivenFile
character (len=80) :: WorkDecPathA, WorkDecPathB, Blank
character (len=80) :: SmooTitle, UnsmooTitle, SmooFile, UnsmooFile

!*******************************************************************************
! preliminaries

Blank = ""

open (99,file="/cru/u2/f709762/data/scratch/log-anom.dat",status="replace",action="write")

print*
print*, "  > ***** AnomProducts *****"
print*, "  > Calculates anomalies using .glo as a base"
print*

call GridSelect   (WorkGrid,WorkGridTitle,WorkLongN,WorkLatN,WorkDataN,WorkGridFilePath)
call RegSelect    (WorkGrid,WorkLongN,WorkLatN,WorkDataN,WorkMapIDLReg,WorkRegSizes,WorkRegNames,&
		   WorkRegTitle,WorkRegN)

Unitary = 0				! finds out whether (=0) or not (=1) all regions are a single box
XReg    = 0
do
  XReg = XReg + 1
  if (WorkRegSizes(XReg).GT.1) Unitary = 1
  if (Unitary.GT.0) exit
  if (XReg.EQ.WorkRegN) exit
end do

QMaskPoles = 1				! decides whether or not to mask poles
if (WorkGrid.EQ.3.AND.Unitary.EQ.0) then
  print*, "  > Mask poles ? (1=no,2=yes)"
  do
	read (*,*,iostat=ReadStatus), QMaskPoles
	if (ReadStatus.LE.0 .AND. QMaskPoles.GE.1 .AND. QMaskPoles.LE.2) exit
  end do
end if

call PeriodSelect (WorkYearN,WorkDecN,WorkADYear)
call SeasonSelect (WorkMonth0,WorkMonth1,WorkMonthN)
call RawSelect    (WorkGrid,WorkLongN,WorkLatN,WorkMapIDLReg,WorkMapIDLRaw,WorkMapRawReg)

print*, "  > Detrend time series ? (1=no,2=yes)"
do
	read (*,*,iostat=ReadStatus), QDeTrend
	if (ReadStatus.LE.0 .AND. QDeTrend.GE.1 .AND. QDeTrend.LE.2) exit
end do

if (QDeTrend.EQ.2) then
	print*, "  > Select the .glo file with the year-multiplier to detrend."
	call LoadGlo (WorkLongN,WorkLatN,WorkRegN,WorkMapIDLReg,WorkMultiplier)
end if

print*, "  > Construct abs (=1), percent (=2) anomalies, or do not anomalise (=3) ? "
do
	read (*,*,iostat=ReadStatus), AnomChosen
	if (ReadStatus.LE.0 .AND. AnomChosen.GE.1 .AND. AnomChosen.LE.3) exit
end do

if (AnomChosen.NE.3) then
  print*, "  > Select the .glo file with the region bases."
  call LoadGlo      (WorkLongN,WorkLatN,WorkRegN,WorkMapIDLReg,WorkBases)
end if

allocate ( WorkAnaSizes    (WorkRegN), &
	   WorkGloAnaSlice (WorkRegN), &
	   WorkLinAnaSeries(WorkRegN, WorkYearN), &
	   WorkGotDecade   (WorkRegN, 10), &
	   WorkGotFull     (WorkRegN, WorkYearN), &
	   WorkGotMem      (WorkRegN, WorkYearN), &
	   DecValid        (WorkRegN, 10), stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: Allocation failure #####"

print*, "  > Enter the number of ensemble members over which to average: "
do
	read (*,*,iostat=ReadStatus), MemN
	if (ReadStatus.LE.0 .AND. MemN.GE.1) exit
end do

WorkGotFull = 0.0
WorkGotMem  = 0

print "(a31,3i8)", "   > Members, regions, decades: ", MemN, WorkRegN, WorkDecN

!*******************************************************************************
! save options

print*, "  > Save unsmoothed region t-s to .tim ? (1=no,2=yes,fire-proof)"
do
	read (*,*,iostat=ReadStatus), QSaveUnsmoo
	if (ReadStatus.LE.0 .AND. QSaveUnsmoo.GE.1 .AND. QSaveUnsmoo.LE.2) exit
end do

if (QSaveUnsmoo.EQ.2) then
  print*, "  > Enter the .tim file title: "
  do
	read (*,*,iostat=ReadStatus), UnsmooTitle
	if (ReadStatus.LE.0.AND.UnsmooTitle.NE."") exit
  end do
  
  print*, "  > Enter the filepath of the .tim file to save: "
  do
	do
		read (*,*,iostat=ReadStatus), GivenFile
		if (ReadStatus.LE.0) exit
	end do
	
	inquire (file=GivenFile, name=UnsmooFile)
	open (1, file=UnsmooFile, status="new", iostat=ReadStatus)
	if (ReadStatus .EQ. 0) close (1)
	if (ReadStatus .EQ. 0) exit
  end do
end if  

print*, "  > Save smoothed (Gauss,30y) region t-s to .tim ? (1=no,2=yes,fire-proof)"
do
	read (*,*,iostat=ReadStatus), QSaveSmoo
	if (ReadStatus.LE.0 .AND. QSaveSmoo.GE.1 .AND. QSaveSmoo.LE.2) exit
end do

if (QSaveSmoo.EQ.2) then
  print*, "  > Enter the .tim file title: "
  do
	read (*,*,iostat=ReadStatus), SmooTitle
	if (ReadStatus.LE.0.AND.SmooTitle.NE."") exit
  end do
  
  print*, "  > Enter the filepath of the .tim file to save: "
  do
	do
		read (*,*,iostat=ReadStatus), GivenFile
		if (ReadStatus.LE.0) exit
	end do
	
	inquire (file=GivenFile, name=SmooFile)
	open (1, file=SmooFile, status="new", iostat=ReadStatus)
	if (ReadStatus .EQ. 0) close (1)
	if (ReadStatus .EQ. 0) exit
  end do
end if  

print*, "  > Save region means to .glo ? (1=no,2=yes,not fire-proof)"
do
	read (*,*,iostat=ReadStatus), QSaveRegMeans
	if (ReadStatus.LE.0 .AND. QSaveRegMeans.GE.1 .AND. QSaveRegMeans.LE.2) exit
end do

!*******************************************************************************
! extract data into WorkGotFull

do XMem = 1, MemN 

  if (MemN.GT.1) print*, "  > Select ensemble member: ", XMem
  
  call RunSelect    (WorkGrid,WorkMonth0,WorkMonth1,WorkYearN,WorkDecN,WorkADYear,&
		     WorkDecTitle,WorkDecStyleThis,WorkDecStyleNext,&
		     WorkDecPathThis,WorkDecPathNext,WorkDecYearN,WorkDecGetYear0,WorkDecGetYear1)

  print*, "  > Non-missing data loaded thus far, by decade: "
  print*, "  > Year AllData Regions   Years"

  do XDec = 1, WorkDecN

    DataMissN  = 0
    YearValidN = 0
    RegValidN  = 0
    DecValid   = 0
    
    Year0 = (XDec-1)*10 + 1
    Year1 = Year0 + 9
  
    WorkGotDecade = 0.0

    call BlockKey    (WorkDecYearN(XDec),WorkMonthN,WorkDecGetYear0(XDec),WorkDecGetYear1(XDec),&
  		      WorkMonth0,WorkMonth1,WorkDecPathThis(XDec),WorkDecPathNext(XDec),&
  		      WorkDecStyleThis(XDec),WorkDecStyleNext(XDec),WorkDecBlockKey)
    
    call ExtractFile (WorkLongN,WorkLatN,WorkDataN,WorkDecPathThis(XDec),WorkDecPathNext(XDec),&
    		      WorkDecStyleThis(XDec),WorkDecStyleNext(XDec),WorkRegN,WorkMonthN,&
  		      WorkDecYearN(XDec),WorkDecGetYear0(XDec),&
  		      WorkMapRawReg,WorkRegSizes,WorkDecBlockKey,WorkGotDecade)
  
    do XReg = 1, WorkRegN
     do XYear = 1, 10
      if (WorkGotDecade (XReg,XYear).NE.MissVal) then
       	WorkGotFull (XReg,(Year0+XYear-1)) = WorkGotFull (XReg,(Year0+XYear-1)) + &
       						WorkGotDecade (XReg,XYear)
       	WorkGotMem  (XReg,(Year0+XYear-1)) = WorkGotMem  (XReg,(Year0+XYear-1)) + 1
        DecValid    (XReg,XYear)           = 1
      else
        DataMissN = DataMissN + 1
      end if
     end do
    end do
    
    do XReg = 1, WorkRegN			! finds number of valid regions
      XYear = 0
      do
        XYear = XYear + 1
        if (DecValid(XReg,XYear).EQ.1) RegValidN = RegValidN + 1
        if (DecValid(XReg,XYear).EQ.1) exit
        if (XYear.EQ.10) exit
      end do      
    end do
    
    do XYear = 1, 10				! finds number of valid years
      XReg = 0
      do
        XReg = XReg + 1
        if (DecValid(XReg,XYear).EQ.1) YearValidN = YearValidN + 1
        if (DecValid(XReg,XYear).EQ.1) exit
        if (XReg.EQ.WorkRegN) exit
      end do      
    end do
    
    XYear = Year0 - 1				! finds first valid year in decade to report to screen
    do
      XYear = XYear + 1
      if (WorkADYear(XYear).NE.MissVal) exit
      if (XYear.EQ.Year1) exit
    end do    
    
    print "(a1,4i8)", " ", WorkADYear(XYear), ((10*WorkRegN)-DataMissN), RegValidN, YearValidN
  end do

end do

deallocate (DecValid, stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: AnomProducts: deallocation failure #####"

!*******************************************************************************
! average out members into mean

do XReg = 1, WorkRegN
  do XYear = 1, WorkYearN
    if (WorkGotMem(XReg,XYear).NE.0) then
       WorkGotFull(XReg,XYear) = WorkGotFull(XReg,XYear) / real(WorkGotMem(XReg,XYear))
    else
       WorkGotFull(XReg,XYear) = MissVal
    end if
  end do
end do

!*******************************************************************************
! detrend (by removing multiplier * yearAD / 100)

if (QDeTrend.EQ.2) then 

 do XYear = 1, WorkYearN
  if (WorkADYear(XYear).NE.MissVal) then
   do XReg = 1, WorkRegN
    if (WorkGotFull(XReg,XYear).NE.MissVal.AND.WorkMultiplier(XReg).NE.MissVal) then
       WorkGotFull(XReg,XYear) = WorkGotFull(XReg,XYear) - (WorkMultiplier(XReg)*real(WorkADYear(XYear))/100.0)
    else
       WorkGotFull(XReg,XYear) = MissVal
    end if
   end do
  else
   do XReg = 1, WorkRegN
       WorkGotFull(XReg,XYear) = MissVal
   end do  
  end if
 end do

end if

!*******************************************************************************
! anomalise

if (AnomChosen.EQ.1) then 

 do XReg = 1, WorkRegN
  do XYear = 1, WorkYearN
    if (WorkGotFull(XReg,XYear).NE.MissVal.AND.WorkBases(XReg).NE.MissVal) then
       WorkGotFull(XReg,XYear) = WorkGotFull(XReg,XYear) - WorkBases(XReg)
    else
       WorkGotFull(XReg,XYear) = MissVal
    end if
  end do
 end do

else if (AnomChosen.EQ.2) then 

 do XReg = 1, WorkRegN
  do XYear = 1, WorkYearN
    if (WorkGotFull(XReg,XYear).NE.MissVal.AND.WorkBases(XReg).NE.MissVal) then
       WorkGotFull(XReg,XYear) = (WorkGotFull(XReg,XYear) - WorkBases(XReg)) &
       				 * 100.0 / WorkBases(XReg)
    else
       WorkGotFull(XReg,XYear) = MissVal
    end if
  end do
 end do

end if

!*******************************************************************************
! mask poles

if (QMaskPoles.EQ.2) then
  do XLong = 1, WorkLongN
    do XYear = 1, WorkYearN
    	WorkGotFull (WorkMapIDLReg(XLong,1),       XYear) = MissVal
    	WorkGotFull (WorkMapIDLReg(XLong,WorkLatN),XYear) = MissVal
    end do
  end do
end if

!*******************************************************************************
! save unsmoothed time series to .tim

if (QSaveUnsmoo.EQ.2) then
  call SaveTim (WorkRegN,WorkYearN,UnsmooTitle,UnsmooFile,WorkRegNames,WorkADYear,WorkGotFull)
end if

!*******************************************************************************
! generate and save smoothed time series to .tim

if (QSaveSmoo.EQ.2) then

  WorkLinAnaSeries = 0.0

  allocate (TempIn   (WorkYearN), &
  	  TempOutA (WorkYearN), &
  	  TempOutB (WorkYearN), stat=AllocStat)

  do XReg = 1, WorkRegN
    if (AllocStat.NE.0) print*, "  > ##### ERROR: Allocation failure #####"
  
    TempIn (1:WorkYearN) = WorkGotFull (XReg,1:WorkYearN)
    TempOutA = MissVal
    TempOutB = MissVal
  
    call GaussSmooth (WorkYearN,30,1,TempIn,TempOutA,TempOutB)
  
    WorkLinAnaSeries (XReg,1:WorkYearN) = TempOutA (1:WorkYearN)
  end do

  deallocate (TempIn, TempOutA, TempOutB)

  call SaveTim (WorkRegN,WorkYearN,SmooTitle,SmooFile,WorkRegNames,WorkADYear,WorkLinAnaSeries)

end if

!*******************************************************************************
! generate and save means to .glo

if (QSaveRegMeans.EQ.2) then
 
 ADYear0 = -1
 ADYear1 = -1
 
 do
  
  if (ADYear1.GT.ADYear0) then
   
   Year0 = -1			! finds index year matching first AD year of slice
   XYear = 0
   do
     XYear = XYear + 1
     if (WorkADYear(XYear).EQ.ADYear0) Year0 = XYear
     if (Year0.NE.-1) exit
     if (XYear.EQ.WorkYearN) exit
   end do
   
   Year1 = -1			! finds index year matching last AD year of slice
   XYear = 0
   do
     XYear = XYear + 1
     if (WorkADYear(XYear).EQ.ADYear1) Year1 = XYear
     if (Year1.NE.-1) exit
     if (XYear.EQ.WorkYearN) exit
   end do
   
   if (Year0.NE.-1.AND.Year1.NE.-1) then	! if first and last index years are valid
   
    WorkGloAnaSlice  = 0.0
    WorkAnaSizes     = 0

    do XReg = 1, WorkRegN
     do XYear = Year0, Year1			! average over period selected
      if (WorkGotFull(XReg,XYear).NE.MissVal) then
        WorkGloAnaSlice (XReg) = WorkGloAnaSlice (XReg) + WorkGotFull(XReg,XYear)
        WorkAnaSizes (XReg)    = WorkAnaSizes (XReg) + 1
      end if
     end do
  
     if (WorkAnaSizes(XReg).GT.0) then
      WorkGloAnaSlice (XReg) = WorkGloAnaSlice (XReg) / real (WorkAnaSizes (XReg))
     else
      WorkGloAnaSlice (XReg) = MissVal
     end if
     
     if (WorkRegN.LE.5) print "(i4,a1,a20,f12.4)", XReg, " ", WorkRegNames(XReg), WorkGloAnaSlice (XReg)
    end do

    call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,Blank,Blank,&
  		WorkGloAnaSlice,WorkMapIDLReg)
  
   end if
  
  end if
  
  do
        print*, "  > Enter first, last years AD of slice to save (99,99=end): "
	read (*,*,iostat=ReadStatus), ADYear0, ADYear1
	if (ReadStatus.LE.0) exit
  end do
  
  if (ADYear0.EQ.99.AND.ADYear1.EQ.99) exit
 
 end do
 
end if

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

print*

deallocate (WorkAnaSizes,WorkGloAnaSlice,WorkLinAnaSeries,WorkGotDecade,WorkGotFull,WorkGotMem)
deallocate (WorkRegNames)

close (99)

end program AnomProducts
