! globulk.f90
! performs basic operations on .glo files in bulk
! pgf90 -Mstandard -Minfo -fast -Mscalarsse -Mvect=sse -Mflushz 
! 	-o ./../goglo/globulk filenames.f90 sortmod.f90 initialmod.f90 glofiles.f90 
!    	gloops.f90 basicfun.f90 ./../goglo/globulk.f90 2> /tyn1/tim/scratch/stderr.txt
! last modified 10.01.02

program GloBulk

use FileNames
use SortMod
use InitialMod
use GloFiles
use GloOps
use BasicFun

implicit none

!*******************************************************************************
! definitions

real, pointer, dimension (:)		:: RegVector,MidVector,OutVector,RegWeights
real, pointer, dimension (:,:)		:: GridWeights,FileRegData,Deg025,Deg050,DegNew

integer, pointer, dimension (:,:) 	:: MapIDLReg,MintMapIDLReg,OrigMapIDLReg  ! shape of IDL mapping arrays
integer, pointer, dimension (:,:) 	:: Biome
integer, pointer, dimension (:) 	:: RegSizes, MintRegSizes,OrigRegSizes,Order
integer, dimension (16) 		:: BiomeReg

character (len=20), pointer, dimension (:) :: RegNames,MintRegNames,OrigRegNames  ! names of individual regions
character (len=80), pointer, dimension (:) :: InFile, MidFile, OutFile

real, parameter :: MissVal = -999.0

real :: OpTot, OpMiss, OpEn, OpConstant, HugeVal, TinyVal, MagMin,MagMax, OpVal
real :: Lower,Upper,OpMin,OpMax

integer :: ReadStatus, AllocStat
integer :: FileN,RegN,MidFileN
integer :: XFile,XReg,XMidFile,XLong,XLat,XMiniLong,XMiniLongAny,XMiniLat,XPre,XTmp
integer :: XLat050,XLon050,XLat025,XLon025,XOut050,XLatRJ,XLonRJ,XLatAve,XLonAve,XExe,XWye
integer :: QOperation, QFinish, QOpPerform, QWeight, QStat, QOutMag, QReplicate
integer :: InSubLen,InSubBeg,InFileLen,LastSlash,LastMiss,MiniRad,NUnique,NMiss
integer :: GridChosen,GridLongN,GridLatN,GridDataN, BiomeOther,BiomeOut			

character (len=80), parameter :: Blank = ""

character (len=80) :: GivenFile, NameOnly, GridFile, GloSaveFile, BiomeFile
character (len=80) :: InSub, OutSub, SaveTitle
character (len=40) :: RegTitle			
character (len=10) :: GridTitle			

!*******************************************************************************
! main program

open  (99,file="./../../../scratch/log-globulk.dat",status="replace",action="write")

print*
print*, "  > ***** GloBulk: performs basic ops on .glo files in bulk *****"
print*

call SelectOp

print*

close (99)

contains

!*******************************************************************************
! select operation to perform on each .glo

subroutine SelectOp

print*, "  > Select the operation to perform (0=list): "
QOperation = -1
QFinish    = -1

do
  if      (QOperation.EQ.0) then
    print*, "  >  1. transform into different region set (weighting=option)"
    print*, "  >  2. place supra-region mean in dump file" 
    print*, "  >  3. fill gaps and save to new .glo" 
    print*, "  >  4. place supra-file median in .glo" 
    print*, "  >  5. place supra-file mean   in .glo" 
    print*, "  >  6. place supra-file count  in .glo" 
    print*, "  >  7. place supra-file classd in .glo" 
    print*, "  >  8. operate: .glo . constant"
    print*, "  >  9. operate: .glo . .glo"
    print*, "  > 11. convert RichJ to 0.5deg"
    print*, "  > 12. convert climate to biomes"
    print*, "  > 13. report grid-box value"
    QOperation = -1
  else if (QOperation.EQ.1) then
    call NewRegSet ; QFinish = 1
  else if (QOperation.EQ.2) then
    call SupraRegMean ; QFinish = 1
  else if (QOperation.EQ.3) then
    call FillGapsSave ; QFinish = 1
  else if (QOperation.EQ.4) then
    QStat = 1 ; call SupraFileMed ; QFinish = 1
  else if (QOperation.EQ.5) then
    QStat = 2 ; call SupraFileMed ; QFinish = 1
  else if (QOperation.EQ.6) then
    QStat = 3 ; call SupraFileMed ; QFinish = 1
  else if (QOperation.EQ.7) then
    QStat = 4 ; call SupraFileMed ; QFinish = 1
  else if (QOperation.EQ.8) then
    call OpGloConstant ; QFinish = 1
  else if (QOperation.EQ.9) then
    call OpMultiGlo ; QFinish = 1
  else if (QOperation.EQ.11) then
    call OpRichJHalfDeg ; QFinish = 1
  else if (QOperation.EQ.12) then
    call ConvertBiome ; QFinish = 1
  else if (QOperation.EQ.13) then
    call ReportGridBox ; QFinish = 1
  else
    do
      read (*,*,iostat=ReadStatus), QOperation
      if (ReadStatus.LE.0) exit
    end do
  end if
  
  if (QFinish.EQ.1) exit
end do

end subroutine SelectOp

!*******************************************************************************
!  1. transform into different region set

subroutine NewRegSet

print*, "  > Identify the OLD region set (constants/goglo/ref/)."
call LoadRefReg (Blank,OrigMapIDLReg,OrigRegSizes,OrigRegNames)

print*, "  > Identify the NEW region set (constants/goglo/ref/)."
call LoadRefReg (Blank,MintMapIDLReg,MintRegSizes,MintRegNames)

print*, "  > Weight the aggregations by box (=1) or area (=2) ?"
do
      read (*,*,iostat=ReadStatus), QWeight
      if (ReadStatus.LE.0.AND.QWeight.GE.1.AND.QWeight.LE.2) exit
end do

GridLongN = size(OrigMapIDLReg,1) ; GridLatN = size(OrigMapIDLReg,2)

if (QWeight.EQ.1) then
  allocate (GridWeights(GridLongN,GridLatN),stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: NewRegSet: Allocation failure: Weights #####"
  GridWeights = 1.0
else
  GivenFile  = GetGloRef (GridLongN,GridLatN)
  InSubBeg   = index(GivenFile,".ref")
  GivenFile  = GivenFile(1:(InSubBeg-1)) // ".weights.glo"
  			! what we want is a weights .glo of rpb form, incl polar boxes 
  print "(2a)", "   > We look for: ", trim(adjustl(GivenFile))
  call LoadGloGrid (GivenFile, GridWeights, Silent=1)
  if (size(GridWeights,1).NE.GridLongN.OR.size(GridWeights,2).NE.GridLatN) then
    GridWeights = MissVal
    print*, "  > ##### ERROR: NewRegSet: Loaded .glo has wrong dims #####"
  end if
end if

call CheckOutMag

print*, "  > Select the OLD files. There must be a common substring."
call GetBatch (Blank,InFile)
FileN  = size (InFile, 1)

call GetOutFile

do XFile = 1, FileN
  GivenFile = InFile(XFile)
  LastSlash = index(GivenFile,"/",.TRUE.)
  NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
  print "(a,i4,2a)", "   > Batch item: ", XFile, ": ", trim(NameOnly)
  if (QOutMag.EQ.0) then
    call GloToGlo (InFile(XFile),OutFile(XFile),OrigMapIDLReg,MintMapIDLReg,CallWeights=GridWeights)
  else
    call GloToGlo (InFile(XFile),OutFile(XFile),OrigMapIDLReg,MintMapIDLReg,CallWeights=GridWeights, &
    			MagMin=MagMin,MagMax=MagMax)
  end if
end do

deallocate (OrigMapIDLReg,OrigRegSizes,OrigRegNames, &
	    MintMapIDLReg,MintRegSizes,MintRegNames, stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: NewRegSet: Deallocation failure: most #####"

deallocate (InFile,OutFile,GridWeights,stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: NewRegSet: Deallocation failure: file #####"

end subroutine NewRegSet

!*******************************************************************************
!  2. put supra-regional mean in dump file

subroutine SupraRegMean

print*, "  > Specify the common grid. "
call GridSelect (GridChosen,GridTitle,GridLongN,GridLatN,GridDataN,GridFile)
call RegSelect (GridChosen,GridLongN,GridLatN,GridDataN,MapIDLReg, RegSizes, RegNames, RegTitle, RegN)

print*, "  > Select the OLD files. There must be a common substring."
call GetBatch (Blank,InFile)
FileN  = size (InFile, 1)

open (98,file="./../../../scratch/dump-globulk.dat",status="replace",action="write")

do XFile = 1, FileN
  GivenFile = InFile(XFile)
  LastSlash = index(GivenFile,"/",.TRUE.)
  NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
  print "(a,i4,2a)", "   > Batch item: ", XFile, ": ", trim(NameOnly)
  
  call LoadGloVec (InFile(XFile), MapIDLReg, RegVector, Silent=1)
  
  OpTot=0.0 ; OpMiss=0.0 ; OpEn=0.0
  do XLong = 1, GridLongN
    do XLat = 1, GridLatN
      if (MapIDLReg(XLong,XLat).NE.MissVal) then
        OpEn=OpEn+1
        if (RegVector(MapIDLReg(XLong,XLat)).NE.MissVal) then
          OpTot=OpTot+RegVector(MapIDLReg(XLong,XLat)) 
        else
          OpMiss=OpMiss+1
        end if
      end if
    end do
  end do
  
  if (OpEn.GT.0.AND.(OpEn-OpMiss).GT.0) then
    write (98,"(2e12.5,a80)"), (OpTot/(OpEn-OpMiss)), (OpMiss/OpEn), trim(NameOnly)
  else
    write (98,"(2e12.5,a80)"), MissVal, MissVal, trim(NameOnly)
  end if  
  
  deallocate (RegVector, stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: SupraRegMean: Deallocation failure: RV #####"
end do

close (98)

deallocate (MapIDLReg, RegSizes, RegNames, stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: SupraRegMean: Deallocation failure: all #####"

deallocate (InFile,stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: SupraRegMean: Deallocation failure: file #####"

end subroutine SupraRegMean

!*******************************************************************************
!  3. fill gaps in file and resave

subroutine FillGapsSave

print*, "  > Specify the common grid. "
call GridSelect (GridChosen,GridTitle,GridLongN,GridLatN,GridDataN,GridFile)
call RegSelect (GridChosen,GridLongN,GridLatN,GridDataN,MapIDLReg, RegSizes, RegNames, RegTitle, RegN)

print*, "  > Select the OLD files. There must be a common substring."
call GetBatch (Blank,InFile)
FileN  = size (InFile, 1)

call GetOutFile

do XFile = 1, FileN
  GivenFile = InFile(XFile)
  LastSlash = index(GivenFile,"/",.TRUE.)
  NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
  print "(a,i4,2a)", "   > Batch item: ", XFile, ": ", trim(NameOnly)
  
  call LoadGloVec (InFile(XFile), MapIDLReg, RegVector, Silent=1)
  
  LastMiss = GridLongN * GridLatN ; MiniRad = 1
  do 
   OpMiss = 0
   
   do XLong = 1, GridLongN
    do XLat = 1, GridLatN
      if (MapIDLReg(XLong,XLat).NE.MissVal) then
        if (RegVector(MapIDLReg(XLong,XLat)).EQ.MissVal) then
          OpTot=0.0 ; OpEn=0.0
          
          do XMiniLongAny = (XLong-MiniRad), (XLong+MiniRad)
            XMiniLong = XMiniLongAny
            if (XMiniLong.LT.1) XMiniLong = GridLongN + XMiniLong
            if (XMiniLong.GT.GridLongN) XMiniLong = XMiniLong - GridLongN 
            
            do XMiniLat = (XLat-MiniRad), (XLat+MiniRad)
             if (XMiniLat.GE.1.AND.XMiniLat.LE.GridLatN) then
              if (MapIDLReg(XMiniLong,XMiniLat).NE.MissVal) then
                if (RegVector(MapIDLReg(XMiniLong,XMiniLat)).NE.MissVal) then
                  OpTot = OpTot + RegVector(MapIDLReg(XMiniLong,XMiniLat))
                  OpEn  = OpEn  + 1
                end if
              end if
             end if
            end do
          end do
          if (OpEn.GE.1) then
          	RegVector(MapIDLReg(XLong,XLat)) = OpTot / OpEn
          else
          	OpMiss = OpMiss + 1
          end if
        end if
      end if
    end do
   end do
   
   if (OpMiss.EQ.LastMiss) MiniRad = MiniRad + 1
   LastMiss = OpMiss
   
   if (OpMiss.EQ.0) exit
  end do
  
  SaveTitle = trim(NameOnly) // " : " // "with gaps filled"
  call SaveGlo (GridLongN,GridLatN,RegN,GridFile,OutFile(XFile),SaveTitle,RegVector,MapIDLReg)
  
  deallocate (RegVector, stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: FillGapsSave: Deallocation failure: RV #####"
end do

deallocate (MapIDLReg, RegSizes, RegNames, stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: FillGapsSave: Deallocation failure: all #####"

deallocate (InFile,OutFile,stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: FillGapsSave: Deallocation failure: file #####"

end subroutine FillGapsSave

!*******************************************************************************
!  4,5,6,7 place supra-file median,mean,count,classd in .glo
! count gives the number of unique values for a region, from the set of files
! classd gives a .glo containing the number of .glo with values in a certain range
!   e.g. 4,4,8,1 would give 3

subroutine SupraFileMed

print*, "  > Specify the common grid. "
call GridSelect (GridChosen,GridTitle,GridLongN,GridLatN,GridDataN,GridFile)
call RegSelect (GridChosen,GridLongN,GridLatN,GridDataN,MapIDLReg, RegSizes, RegNames, RegTitle, RegN)

print*, "  > Select the OLD files. There must be a common substring."
call GetBatch (Blank,InFile)
FileN  = size (InFile, 1)

if (QStat.EQ.4) then
  print*, "  > Enter the lower,upper bounds (-999=none):"
  do
      read (*,*,iostat=ReadStatus), Lower,Upper
      if (ReadStatus.LE.0.AND.(Lower.EQ.MissVal.OR.Upper.EQ.MissVal.OR.Lower.LE.Upper)) exit
  end do
end if

allocate (FileRegData(FileN,RegN),stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: SupraFileMed: Allocation failure: FRD #####"

do XFile = 1, FileN
  GivenFile = InFile(XFile)
  LastSlash = index(GivenFile,"/",.TRUE.)
  NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
  print "(a,i4,2a)", "   > Batch item: ", XFile, ": ", trim(NameOnly)
  
  call LoadGloVec (InFile(XFile), MapIDLReg, RegVector, Silent=1)
    
  do XReg = 1, RegN
    FileRegData(XFile,XReg) = RegVector(XReg)
  end do
  
  deallocate (RegVector,stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: SupraFileMed: Deallocation failure: RV #####"
end do

allocate (MidVector(FileN),&
	  OutVector(RegN),Order(FileN), stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: SupraFileMed: Allocation failure: MV #####"

if (QStat.EQ.1.OR.QStat.EQ.2) then
 do XReg = 1, RegN
  do XFile = 1, FileN
    MidVector(XFile) = FileRegData(XFile,XReg)
  end do
  
  if (QStat.EQ.1) then
    call QuickSort (Reals=MidVector,OrderValid=Order,NMiss=NMiss)
    OutVector(XReg) = MidVector (Order (nint((FileN-NMiss)/2.0)) )
  else if (QStat.EQ.2) then
    OutVector(XReg) = OpCalcMean  (MidVector,FileN,10.0)
  end if
 end do
else if (QStat.EQ.3) then
  do XReg = 1, RegN
    MidVector=MissVal ; NUnique=0
    do XFile = 1, FileN
      XMidFile=0 
      do
        XMidFile=XMidFile+1
	if (FileRegData(XFile,XReg).NE.MissVal.AND.MidVector(XMidFile).EQ.MissVal) then
	  MidVector(XMidFile)=FileRegData(XFile,XReg)
	  NUnique=NUnique+1
	end if
	if (MidVector(XMidFile).NE.MissVal.AND. &
		MidVector(XMidFile).EQ.FileRegData(XFile,XReg)) exit
	if (XMidFile.EQ.FileN) exit
      end do
    end do
    OutVector(XReg) = NUnique
  end do 
else if (QStat.EQ.4) then
 OutVector=0
 do XReg = 1, RegN
  do XFile = 1, FileN
    if (FileRegData(XFile,XReg).NE.MissVal) then
      if (Lower.EQ.MissVal.OR.FileRegData(XFile,XReg).GE.Lower) then
        if (Upper.EQ.MissVal.OR.FileRegData(XFile,XReg).LE.Upper) then
	  OutVector(XReg)=OutVector(XReg)+1
	end if
      end if
    end if
  end do
 end do
end if

OpMax=maxval(outvector) ; OpMin=minval(outvector)

print*, "  > Enter the .glo file to save (range:",OpMin,OpMax
do
      read (*,*,iostat=ReadStatus), GivenFile
      if (ReadStatus.LE.0.AND.GivenFile.NE."") exit
end do
GloSaveFile = SavePath (GivenFile,".glo")

print*, "  > Enter the information line:"
do
      read (*,*,iostat=ReadStatus), SaveTitle
      if (ReadStatus.LE.0.AND.SaveTitle.NE."") exit
end do

call SaveGlo (GridLongN,GridLatN,RegN,GridFile,GloSaveFile,SaveTitle,OutVector,MapIDLReg)  

deallocate (FileRegData,MidVector,OutVector,MapIDLReg,RegSizes,RegNames,Order,stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: SupraFileMed: Deallocation failure: RV #####"

end subroutine SupraFileMed

!*******************************************************************************
!  8. .glo . constant

subroutine OpGloConstant

print*, "  > Select the op: A/k=1,A*k=2,A-k=3,A+k=4,sqroot(A)=5,A**k=6,abs(A)=7"
do
      read (*,*,iostat=ReadStatus), QOpPerform
      if (ReadStatus.LE.0.AND.QOpPerform.GE.1.AND.QOpPerform.LE.7) exit
end do

print*, "  > Select the constant:"
do
      read (*,*,iostat=ReadStatus), OpConstant
      if (ReadStatus.LE.0) exit
end do

call CheckOutMag

print*, "  > Specify the common grid. "
call GridSelect (GridChosen,GridTitle,GridLongN,GridLatN,GridDataN,GridFile)
call RegSelect (GridChosen,GridLongN,GridLatN,GridDataN,MapIDLReg, RegSizes, RegNames, RegTitle, RegN)

print*, "  > Select the OLD files. There must be a common substring."
call GetBatch (Blank,InFile)
FileN  = size (InFile, 1)

call GetOutFile

do XFile = 1, FileN
  GivenFile = InFile(XFile)
  LastSlash = index(GivenFile,"/",.TRUE.)
  NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
  print "(a,i4,2a)", "   > Batch item: ", XFile, ": ", trim(NameOnly)
  
  call LoadGloVec (InFile (XFile), MapIDLReg, RegVector, Silent=1)
  allocate (OutVector(RegN),stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: OpGloConstant: Allocation failure: OV #####"
  
  do XReg = 1, RegN
    OutVector(XReg) = OpAwithB (RegVector(XReg),OpConstant,QOpPerform)
  end do
  
  if (QOutMag.EQ.1) then
   do XReg = 1, RegN
    if (OutVector(XReg).NE.MissVal) then
      if (abs(OutVector(XReg)).LT.MagMin) OutVector(XReg) = sign(MagMin,OutVector(XReg))
      if (abs(OutVector(XReg)).GT.MagMax) OutVector(XReg) = sign(MagMax,OutVector(XReg))
    end if
   end do
  end if
  
  SaveTitle = trim(NameOnly) // " operated on"
  call SaveGlo (GridLongN,GridLatN,RegN,GridFile,OutFile(XFile),SaveTitle,OutVector,MapIDLReg)
  
  deallocate (RegVector,OutVector, stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: OpGloConstant: Deallocation failure: RV #####"
end do  

deallocate (MapIDLReg, RegSizes, RegNames, stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: OpGloConstant: Deallocation failure: all #####"

deallocate (InFile,OutFile,stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: OpGloConstant: Deallocation failure: file #####"

end subroutine OpGloConstant

!*******************************************************************************
!  9. operate one .glo on another

subroutine OpMultiGlo

QReplicate = 0

print*, "  > Select the op: A/B=1,A*B=2,A-B=3,A+B=4,sqroot(A)=5,A**B=6,abs(A)=7"
do
      read (*,*,iostat=ReadStatus), QOpPerform
      if (ReadStatus.LE.0.AND.QOpPerform.GE.1.AND.QOpPerform.LE.7) exit
end do

call CheckOutMag

print*, "  > Specify the common grid. "
call GridSelect (GridChosen,GridTitle,GridLongN,GridLatN,GridDataN,GridFile)
call RegSelect (GridChosen,GridLongN,GridLatN,GridDataN,MapIDLReg, RegSizes, RegNames, RegTitle, RegN)
call GetParallelFiles
call GetOutFile

do XFile = 1, FileN
  call GetMidFileIndex
  
  call LoadGloVec (InFile (XFile), MapIDLReg, RegVector, Silent=1)	! load 'in' file
  call LoadGloVec (MidFile(XMidFile), MapIDLReg, MidVector, Silent=1)  	! load 'mid' file
  
  allocate (OutVector(RegN),stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: OpMultiGlo: Allocation failure: OV #####"
  
  do XReg = 1, RegN
    OutVector(XReg) = OpAwithB (RegVector(XReg),MidVector(XReg),QOpPerform)
  end do
  
  if (QOutMag.EQ.1) then
   do XReg = 1, RegN
    if (OutVector(XReg).NE.MissVal) then
      if (abs(OutVector(XReg)).LT.MagMin) OutVector(XReg) = sign(MagMin,OutVector(XReg))
      if (abs(OutVector(XReg)).GT.MagMax) OutVector(XReg) = sign(MagMax,OutVector(XReg))
    end if
   end do
  end if
  
  SaveTitle = 'result of bulk operation'
  call SaveGlo (GridLongN,GridLatN,RegN,GridFile,OutFile(XFile),SaveTitle,OutVector,MapIDLReg)
  
  deallocate (RegVector,MidVector,OutVector, stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: OpMultiGlo: Deallocation failure: RV #####"
end do  

deallocate (MapIDLReg, RegSizes, RegNames,InFile,OutFile,MidFile,stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: OpMultiGlo: Deallocation failure: file #####"

end subroutine OpMultiGlo

!*******************************************************************************
! 11. convert RichJ .glo to 0.5deg .glo

subroutine OpRichJHalfDeg

print*, "  > Select OLD files on RichJ grid. There must be a common substring."
call GetBatch (Blank,InFile)
FileN  = size (InFile, 1)

call GetOutFile

GridFile = "./../../../constants/goglo/ref/half-degree.ref"

allocate (Deg025(720,1440), &
	  DegNew(720,1440), &
	  Deg050(360, 720), &
	  OutVector(259200),stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: OpRichJHalfDeg: Allocation failure #####"

do XFile = 1, FileN
  GivenFile = OutFile(XFile)
  LastSlash = index(GivenFile,"/",.TRUE.)
  NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
  print "(a,i4,2a)", "   > Batch item: ", XFile, ": ", trim(NameOnly)
  
  call LoadGloGrid (InFile (XFile), FileRegData, Silent=1)
  
  allocate (MapIDLReg(720,360), stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: OpRichJHalfDeg: Reallocation failure: MapIDLReg #####"

  Deg025=MissVal ; Deg050=MissVal ; DegNew=MissVal
  
  XLatRJ=1
  do XLat025=1,720
    XLonRJ=1
    if (mod((real(XLat025)-6.0),10.0).EQ.0.0) XLatRJ=XLatRJ+1
    do XLon025=1,1440
      if (mod((real(XLon025)-0.0),10.0).EQ.0.0) XLonRJ=XLonRJ+1      
      Deg025(XLat025,XLon025) = FileRegData(XLonRJ,XLatRJ)
    end do
  end do
  
  do XLat025=1,720
    do XLon025=1,1440
      OpTot=0.0 ; OpEn=0.0
      do XLatAve=max(1,XLat025-4),min(720,XLat025+4)
        do XLonAve=XLon025-4,XLon025+4
          if (XLonAve.LT.1) then
            if (Deg025(XLatAve,XLonAve+1440).NE.MissVal) then
              OpTot=OpTot+Deg025(XLatAve,XLonAve+1440) ; OpEn=OpEn+1
            end if
          else if (XLonAve.GT.1440) then
            if (Deg025(XLatAve,XLonAve-1440).NE.MissVal) then
              OpTot=OpTot+Deg025(XLatAve,XLonAve-1440) ; OpEn=OpEn+1
            end if
          else
            if (Deg025(XLatAve,XLonAve).NE.MissVal) then
              OpTot=OpTot+Deg025(XLatAve,XLonAve) ; OpEn=OpEn+1
            end if
          end if
        end do        
      end do
      if (OpEn.GE.09) DegNew(XLat025,XLon025) = OpTot/OpEn
    end do
  end do
  
  do XLat050=1,360
    do XLon050=1,720
      OpTot=0.0 ; OpEn=0.0
      do XLat025=((XLat050-1)*2)+1,((XLat050-1)*2)+2
        do XLon025=((XLon050-1)*2)+1,((XLon050-1)*2)+2
          if (DegNew(XLat025,XLon025).NE.MissVal) then
            OpTot=OpTot+DegNew(XLat025,XLon025) ; OpEn=OpEn+1
          end if
        end do
      end do
      if (OpEn.GT.0) Deg050(XLat050,XLon050) = OpTot/OpEn
    end do
  end do
  
  XOut050=0
  do XLon050=1,720
    do XLat050=1,360
      XOut050=XOut050+1
      MapIDLReg(XLon050,XLat050)=XOut050
      OutVector(XOut050)=Deg050(XLat050,XLon050)
    end do
  end do

  SaveTitle = '144*73->720*360'
  call SaveGlo (720,360,259200,GridFile,OutFile(XFile),SaveTitle,OutVector,MapIDLReg)
  
  deallocate (FileRegData,MapIDLReg, stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: OpRichJHalfDeg: Deallocation failure: loop #####"
end do

deallocate (Deg025,Deg050,DegNew,OutVector,stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: OpRichJHalfDeg: Deallocation failure #####"

end subroutine OpRichJHalfDeg

!*******************************************************************************
! 12. convert climate to biomes

subroutine ConvertBiome

QReplicate = 0 

allocate (Biome(45,45),stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: ConvertBiome: Allocation failure: OV #####"
Biome=MissVal
BiomeFile="./../../../constants/biome/biomedefine.txt"

open  (2,file=BiomeFile,status="old",access="sequential",form="formatted",action="read")
do XPre=1,17
  read (2, fmt="(a)"), GivenFile	! just a convenient trash form
end do
do XTmp=45,1,-1
  read (2, fmt="(45i3)"), (Biome(XTmp,XPre),XPre=1,45) 
end do
close (2)

print*, "  > Specify the common grid. "
call GridSelect (GridChosen,GridTitle,GridLongN,GridLatN,GridDataN,GridFile)
call RegSelect (GridChosen,GridLongN,GridLatN,GridDataN,MapIDLReg, RegSizes, RegNames, RegTitle, RegN)
print*, "  > Files: A=temp(ann mean,C), B=prec(ann total,mm)"
call GetParallelFiles
call GetOutFile

do XFile = 1, FileN
  call GetMidFileIndex
  
  call LoadGloVec (InFile (XFile),    MapIDLReg, RegVector, Silent=1)	! load 'in' file
  call LoadGloVec (MidFile(XMidFile), MapIDLReg, MidVector, Silent=1)  	! load 'mid' file
  
  allocate (OutVector(RegN),stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: ConvertBiome: Allocation failure: OV #####"
  OutVector=0	! initialised to 'undefined'
  BiomeReg=0	! number of allocations to each biome
  BiomeOther=0 ; BiomeOut=0
  
  do XReg = 1, RegN
    if (RegVector(XReg).NE.MissVal.AND.MidVector(XReg).NE.MissVal) then
      if (RegVector(XReg).GE.  30) RegVector(XReg)=  29.5
      if (RegVector(XReg).LT. -15) RegVector(XReg)= -14.5
      if (MidVector(XReg).GE.4500) MidVector(XReg)=4450
	
      XTmp=floor(RegVector(XReg))+16
      XPre=floor(MidVector(XReg)/100.0)+1
      OutVector(XReg)=Biome(XTmp,XPre)
      BiomeReg(Biome(XTmp,XPre))=BiomeReg(Biome(XTmp,XPre))+1
    else
      OutVector(XReg)=MissVal
    end if
  end do
  
  print "(a,16i6)", "   > ", (BiomeReg(XTmp),XTmp=1,16)
  write (99,"(i4,8i10)"), XFile, (BiomeReg(XTmp),XTmp=1,8)
  write (99,"(i4,8i10)"), XFile, (BiomeReg(XTmp),XTmp=9,16)
  
  SaveTitle = 'biomes'
  call SaveGlo (GridLongN,GridLatN,RegN,GridFile,OutFile(XFile),SaveTitle,OutVector,MapIDLReg)
  
  deallocate (RegVector,MidVector,OutVector, stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: ConvertBiome: Deallocation failure: RV #####"
end do  

deallocate (MapIDLReg,RegSizes,RegNames,InFile,OutFile,MidFile,Biome,stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: ConvertBiome: Deallocation failure: file #####"

end subroutine ConvertBiome

!*******************************************************************************
! 13. report grid-box

subroutine ReportGridBox

print*, "  > Specify the common grid. "
call GridSelect (GridChosen,GridTitle,GridLongN,GridLatN,GridDataN,GridFile)
call RegSelect (GridChosen,GridLongN,GridLatN,GridDataN,MapIDLReg, RegSizes, RegNames, RegTitle, RegN)

print*, "  > Select the box reference (exe,wye): "
do
      read (*,*,iostat=ReadStatus), XExe,XWye
      if (XExe.LT.1.OR.XWye.LT.1.OR.XExe.GT.GridLongN.OR.XWye.GT.GridLatN) then
        ReadStatus=1 ; print*, "  > Out-of-range. Retry. "
      else if (MapIDLReg(XExe,XWye).EQ.MissVal) then
        ReadStatus=1 ; print*, "  > Not part of a region. Retry. "
      end if
      if (ReadStatus.LE.0) exit
end do

print*, "  > Select the files."
call GetBatch (Blank,InFile)
FileN  = size (InFile, 1)

do XFile=1,FileN
  GivenFile="" ; GivenFile = InFile(XFile)
  LastSlash = index(GivenFile,"/",.TRUE.)
  NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
  
  call LoadGloVec (InFile(XFile), MapIDLReg, RegVector, Silent=1)
  
  print "(a,i4,2a,f10.2)", "   > Batch item: ", XFile, ": ", trim(NameOnly), &
  		RegVector(MapIDLReg(XExe,XWye))
  write (99,"(a,i4,2a,f10.2)"), "   > Batch item: ", XFile, ": ", trim(NameOnly), &
  		RegVector(MapIDLReg(XExe,XWye))
end do

end subroutine ReportGridBox

!*******************************************************************************
! get 'mid' file index, depending on replication

subroutine GetMidFileIndex

if      (QReplicate.EQ.0) then		! work out 'mid' file index
    XMidFile = XFile
else if (QReplicate.EQ.1) then
    XMidFile = nint(mod(real(XFile),real(MidFileN)))
    if (XMidFile.EQ.0) XMidFile = MidFileN
else if (QReplicate.EQ.2) then
    if (XFile.EQ.1) XMidFile=0
    if (mod(real(XFile),(real(FileN)/real(MidFileN))).EQ.1) XMidFile=XMidFile+1
end if

if (QReplicate.GT.0) then
    print*
    GivenFile = InFile(XFile)
    LastSlash = index(GivenFile,"/",.TRUE.)
    NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
    print "(a,i4,2a)", "   > File A: ", XFile, ": ", trim(NameOnly)
    GivenFile = MidFile(XMidFile)
    LastSlash = index(GivenFile,"/",.TRUE.)
    NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
    print "(a,i4,2a)", "   > File B: ", XFile, ": ", trim(NameOnly)
else
    GivenFile = OutFile(XFile)
    LastSlash = index(GivenFile,"/",.TRUE.)
    NameOnly  = adjustl(trim(GivenFile((LastSlash+1):80)))
    print "(a,i4,2a)", "   > Batch item: ", XFile, ": ", trim(NameOnly)
end if
  
end subroutine GetMidFileIndex

!*******************************************************************************
! get parallel files

subroutine GetParallelFiles

print*, "  > Select OLD files 'A'. There must be a common substring."
call GetBatch (Blank,InFile)
FileN  = size (InFile, 1)

print*, "  > Select OLD files 'B'. There must be a common substring."
do
  call GetBatch (Blank,MidFile)
  MidFileN = size(MidFile, 1)
  if (FileN.NE.MidFileN) then
    if (mod(real(FileN),real(MidFileN)).EQ.0) then
      print*, "  > Replicate the files to match A ? (0=no,1,2=yes)"
      print*, "  >   1=(a:a,n+a,...) 2=(a:n*a+1,n*a+2,...)"
      do
        read (*,*,iostat=ReadStatus), QReplicate
        if (ReadStatus.LE.0.AND.QReplicate.GE.0.AND.QReplicate.LE.2) exit
      end do
    end if

    if (QReplicate.EQ.0) then
      print*, "  > Incorrect number of files. Try again."
      deallocate (MidFile, stat=AllocStat)
      if (AllocStat.NE.0) print*, "  > ##### ERROR: OpMultiGlo: Deallocation failure: MF #####"
    end if
  end if
  if (FileN.EQ.MidFileN.OR.QReplicate.GT.0) exit
end do

end subroutine GetParallelFiles

!*******************************************************************************
! get output file vector

subroutine GetOutFile

print*, "  > Enter the substring in the OLD A files to alter in the NEW files: "
do
	read (*,*,iostat=ReadStatus), InSub
	if (ReadStatus.GT.0) then	
			print*, "  > Bad format. Try again."
	else if (InSub.EQ."") then
			print*, "  > Blank not permitted. Try again."
	end if
	if (ReadStatus.LE.0.AND.InSub.NE."") exit
end do
InSub=trim(adjustl(InSub))

print "(3a)", "   > Enter the substring in the NEW files to replace '", trim(InSub), "':"
do
	read (*,*,iostat=ReadStatus), OutSub
	if (ReadStatus.GT.0) then	
			print*, "  > Bad format. Try again."
	else if (OutSub.EQ."") then
			print*, "  > Blank not permitted. Try again."
	end if
	if (ReadStatus.LE.0.AND.OutSub.NE."") exit
end do

InSubLen = len(trim(InSub))
  
allocate (OutFile (FileN), stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: GloBulk: OutFile: Allocation failure #####"
OutFile = ""

do XFile = 1, FileN
      GivenFile = InFile(XFile)
      InSubBeg  = index(GivenFile,InSub(1:InSubLen))
      InFileLen = len(adjustl(trim(GivenFile)))
      
      OutFile(XFile) = GivenFile(1:(InSubBeg-1)) // trim(adjustl(OutSub)) // &
      		GivenFile((InSubBeg+InSubLen):InFileLen)
end do

end subroutine GetOutFile

!*******************************************************************************
! check output magnitudes

subroutine CheckOutMag

print*, "  > Restrict output magnitudes (0=no,1=yes) ?"
do
      read (*,*,iostat=ReadStatus), QOutMag
      if (ReadStatus.LE.0.AND.QOutMag.GE.0.AND.QOutMag.LE.1) exit
end do
if (QOutMag.EQ.1) then
  print*, "  > Magnitudes smaller than X are set to X. Enter X."
  do
      read (*,*,iostat=ReadStatus), MagMin
      if (ReadStatus.LE.0.AND.MagMin.GE.0) exit
  end do
  
  print*, "  > Magnitudes larger  than X are set to X. Enter X."
  do
      read (*,*,iostat=ReadStatus), MagMax
      if (ReadStatus.LE.0.AND.MagMax.GE.0) exit
  end do  
end if

end subroutine CheckOutMag

!*******************************************************************************
! end

end program GloBulk
