! glofiles.f90
! module procedure written by Tim Mitchell on 29.03.01
! last modification on 14.11.01
! contains the relevant .glo file routines:
!    LoadGloVec and GetGloHeaders
!    LoadGloGrid is only if you want to load the grid of values as a raw thing (LongN,LatN)
!    SaveGlo
!    GetGloWeights,GetGloRef

module GloFiles

use FileNames

implicit none

contains

!*******************************************************************************
! if you don't have MapIDLReg before the call, get it
! CallGloFile may be blank

subroutine LoadGloGrid (CallGloFile, FileData, Silent)

integer, intent(in), optional			:: Silent															
character (len=80), intent (in)			:: CallGloFile			! may be blank in call

real, pointer, dimension (:,:) :: FileData

real, parameter :: MissVal = -999.0

real :: TimMin, TimMax, TimTot, GloAv
real :: TotalMiss, PerCentMiss

character (len=80) :: Title, ModelFilePath, GloFile
character (len=10) :: Format

integer :: LongN, LatN, RegN
integer :: XLong, XLat, XEight, XTen, XSix, XReg, XLetter
integer :: Long0, Long1
integer :: AllocStat, ReadStatus
integer :: RegMisMatch
integer :: GloFileLen, QZip

!***************************************
! load .glo data

GloFile = LoadPath (CallGloFile,".glo")					! get .glo file path

GloFileLen = len_trim(GloFile)
if (GloFileLen.GE.2.AND.GloFile((GloFileLen-1):GloFileLen).EQ.'.Z') then
  QZip = 2							! file is zipped
  call system ('uncompress ' // trim(GloFile))
  GloFile ((GloFileLen-1):GloFileLen) = "  "			! change filename to the unzipped file
else
  QZip = 1							! file already unzipped
end if

open (2, file=GloFile, status="old", access="sequential", form="formatted", action="read")

read (2, fmt="(A80)"), Title
read (2, fmt="(A10)"), Format
Format = trim(adjustl(Format))

if      (Format(2:2).EQ."8") then
  XLetter = 3
else if (Format(2:2).EQ."6") then
  XLetter = 3
else if (Format(2:3).EQ."10") then
  XLetter = 4
else
  XLetter = 3
end if
							! allows .glo without format specifier
if (Format(XLetter:XLetter).NE.'E'.AND.Format(XLetter:XLetter).NE.'F') then
    close (2)
    open (2, file=GloFile, status="old", access="sequential", form="formatted", action="read")
    read (2, fmt="(A80)"), Title
    Format = "(8F12.4)"
end if
if (.NOT.present(Silent)) print "(2a)", "   > ", trim(adjustl(Title))

read (2, fmt="(2I6)"), LongN, LatN
read (2, fmt="(A80)"), ModelFilePath

allocate (FileData  (LongN,LatN), stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: LoadGloGrid: Allocation failure #####"
FileData = MissVal

if      (Format(2:2).EQ."8") then
 do XLat = 1, LatN
  do XEight = 1, (LongN/8)
   Long0 = (XEight-1)*8 + 1
   Long1 = Long0 + 7
  
   read (2, fmt=Format), (FileData (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
else if (Format(2:3).EQ."10") then
 do XLat = 1, LatN
  do XTen = 1, (LongN/10)
   Long0 = (XTen-1)*10 + 1
   Long1 = Long0 + 9
  
   read (2, fmt=Format), (FileData (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
else if (Format(2:2).EQ."6") then
 do XLat = 1, LatN
  do XSix = 1, (LongN/6)
   Long0 = (XSix-1)*6 + 1
   Long1 = Long0 + 5
  
   read (2, fmt=Format), (FileData (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
end if

close (2)

where (FileData.LT.0.1E-05.AND.FileData.GT.-0.1E-05) FileData = 0.0

if (QZip.EQ.2) call system ('compress ' // GloFile // ' &')

end subroutine LoadGloGrid

!*******************************************************************************
! if you don't have MapIDLReg before the call, get it
! CallGloFile may be blank

subroutine LoadGloVec (CallGloFile, MapIDLReg, GloVec, Silent)

real, pointer, dimension (:)			:: GloVec			! one value per region
					
integer, pointer, dimension (:,:) 		:: MapIDLReg			! maps IDL grid to regions

integer, intent(in), optional			:: Silent															
character (len=80), intent (in)			:: CallGloFile			! may be blank in call

real, allocatable, dimension (:,:) :: FileData

real, parameter :: MissVal = -999.0

real :: TimMin, TimMax, TimTot, GloAv
real :: TotalMiss, PerCentMiss
real :: TinyVal, HugeVal

character (len=80) :: Title, ModelFilePath, GloFile
character (len=10) :: Format

integer :: LongN, LatN, RegN
integer :: XLong, XLat, XEight, XSix, XReg, XTen, XLetter
integer :: Long0, Long1
integer :: AllocStat, ReadStatus
integer :: RegMisMatch
integer :: GloFileLen, QZip

!***************************************
! load .glo data

RegN = maxval (MapIDLReg)

GloFile = LoadPath (CallGloFile,".glo")					! get .glo file path

GloFileLen = len_trim(GloFile)
if (GloFileLen.GE.2.AND.GloFile((GloFileLen-1):GloFileLen).EQ.'.Z') then
  QZip = 2							! file is zipped
  call system ('uncompress ' // trim(GloFile))
  GloFile ((GloFileLen-1):GloFileLen) = "  "			! change filename to the unzipped file
else
  QZip = 1							! file already unzipped
end if

open (2, file=GloFile, status="old", access="sequential", form="formatted", action="read")

read (2, fmt="(A80)"), Title
read (2, fmt="(A10)"), Format
Format = trim(adjustl(Format))

if      (Format(2:2).EQ."8") then
  XLetter = 3
else if (Format(2:2).EQ."6") then
  XLetter = 3
else if (Format(2:3).EQ."10") then
  XLetter = 4
else
  XLetter = 3
end if
							! allows .glo without format specifier
if (Format(XLetter:XLetter).NE.'E'.AND.Format(XLetter:XLetter).NE.'F') then
    close (2)
    open (2, file=GloFile, status="old", access="sequential", form="formatted", action="read")
    read (2, fmt="(A80)"), Title
    Format = "(8F12.4)"
end if
if (.NOT.present(Silent)) print "(2a)", "   > ", trim(adjustl(Title))

read (2, fmt="(2I6)"), LongN, LatN
read (2, fmt="(A80)"), ModelFilePath

write (99,"(2a)"), "got headers", Format	! @@@@@@@@@@@@@@@@@@@@@@@

allocate (FileData  (LongN,LatN), &
	  GloVec    (RegN),       stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: LoadGlo: Allocation failure #####"
FileData = MissVal ; GloVec = MissVal

if      (Format(2:2).EQ."8") then
 do XLat = 1, LatN
  do XEight = 1, (LongN/8)
   Long0 = (XEight-1)*8 + 1
   Long1 = Long0 + 7
  
   read (2, fmt=Format), (FileData (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
else if (Format(2:3).EQ."10") then
 do XLat = 1, LatN
  do XTen = 1, (LongN/10)
   Long0 = (XTen-1)*10 + 1
   Long1 = Long0 + 9
  
   read (2, fmt=Format), (FileData (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
else if (Format(2:2).EQ."6") then
 do XLat = 1, LatN
  do XSix = 1, (LongN/6)
   Long0 = (XSix-1)*6 + 1
   Long1 = Long0 + 5
  
   read (2, fmt=Format), (FileData (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
end if

close (2)

write (99,"(2a)"), "got data", Format	! @@@@@@@@@@@@@@@@@@@@@@@

if (QZip.EQ.2) call system ('compress ' // GloFile // ' &')

!***************************************
! process .glo data

RegMisMatch = 0

TinyVal = tiny(GloVec) ; HugeVal = huge(GloVec)

do XLong = 1, LongN
  do XLat = 1, LatN
   if (FileData(XLong,XLat).LT.TinyVal.AND.FileData(XLong,XLat).GT.(0.0-TinyVal)) &
   			FileData(XLong,XLat) = TinyVal
   
   if (FileData(XLong,XLat).GT.HugeVal) FileData(XLong,XLat) = HugeVal
   
   if (FileData(XLong,XLat).LT.(0.0-HugeVal)) FileData(XLong,XLat) = 0.0 - HugeVal
   
   				! grid box relates to a region
   if (MapIDLReg(XLong,XLat).NE.MissVal) then

     				! ...and region already has a value
     if (GloVec(MapIDLReg(XLong,XLat)).NE.MissVal) then
       				! ......but the region val does not equal the grid box val
       if (GloVec(MapIDLReg(XLong,XLat)).NE.FileData(XLong,XLat)) RegMisMatch = RegMisMatch + 1
       
     else			! ...but region does not (yet) have a value
       				! ...so we give it a value
       GloVec (MapIDLReg(XLong,XLat)) = FileData (XLong,XLat)
     end if

   else				! grid box does not relate to a region
       				! ...yet it contains a value
     if (FileData(XLong,XLat).NE.MissVal) RegMisMatch = RegMisMatch + 1

   end if
   
  end do
end do

if (RegMisMatch.GT.0) then
	print*, "  > ##### ERROR: LoadGlo: .glo Belongs to Wrong Region Set #####"
	print*, "  > Number of regions in call: ", RegN
	GloVec = MissVal
end if

deallocate (FileData)

if (.NOT.present(Silent)) then
  TimMin    =  100000.0
  TimMax    = -100000.0
  TimTot    =       0.0
  TotalMiss =       0.0
  do XReg = 1, RegN
    if      (GloVec (XReg).EQ.MissVal) then
       TotalMiss = TotalMiss + 1.0
    else
       TimTot = TimTot + GloVec (XReg)
       
       if (GloVec (XReg).GT.TimMax)  then
         TimMax    = GloVec (XReg)
       end if
       
       if (GloVec (XReg).LT.TimMin)  then
         TimMin    = GloVec (XReg)
       end if
    end if
  end do

  PerCentMiss = 100.0 * TotalMiss / (RegN)
  GloAv       = MissVal

  if (TotalMiss.LT.RegN) GloAv = TimTot / (RegN - TotalMiss)
  print "(a28,4f10.4)", "   > % miss, min, max, mean: ", PerCentMiss, TimMin, TimMax, GloAv
end if

end subroutine LoadGloVec

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

subroutine GetGloHeaders (CallGloFile,Title,Format,LongN,LatN,ModelFilePath)

character (len=80), intent (in)		:: CallGloFile			! may be blank in call
character (len=80), intent (out) 	:: Title, ModelFilePath
character (len=10), intent (out) 	:: Format

integer, intent (out) 			:: LongN, LatN

integer :: GloFileLen, QZip, XLetter

character (len=80) :: GloFile

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

GloFile = LoadPath (CallGloFile,".glo")					! get .glo file path

GloFileLen = len_trim(GloFile)
if (GloFileLen.GE.2.AND.GloFile((GloFileLen-1):GloFileLen).EQ.'.Z') then
  QZip = 2							! file is zipped
  call system ('uncompress ' // trim(GloFile))
  GloFile ((GloFileLen-1):GloFileLen) = "  "			! change filename to the unzipped file
else
  QZip = 1							! file already unzipped
end if

open (2, file=GloFile, status="old", access="sequential", form="formatted", action="read")

read (2, fmt="(A80)"), Title
read (2, fmt="(A10)"), Format
Format = trim(adjustl(Format))

if      (Format(2:2).EQ."8") then
  XLetter = 3
else if (Format(2:2).EQ."6") then
  XLetter = 3
else if (Format(2:3).EQ."10") then
  XLetter = 4
else
  XLetter = 3
end if
							! allows .glo without format specifier
if (Format(XLetter:XLetter).NE.'E'.AND.Format(XLetter:XLetter).NE.'F') then
    close (2)
    open (2, file=GloFile, status="old", access="sequential", form="formatted", action="read")
    read (2, fmt="(A80)"), Title
    Format = "(8F12.4)"
end if

read (2, fmt="(2I6)"), LongN, LatN
read (2, fmt="(A80)"), ModelFilePath

close (2)

if (QZip.EQ.2) call system ('compress ' // GloFile // ' &')

end subroutine GetGloHeaders

!*******************************************************************************
! altered on 12.07.00 to prompt for title; SpecTitle and SpecFilePath (len=80) can both be set to ""
! altered on 04.10.01 to allow for save as HadCM2 when calling with 97,73 grid

subroutine SaveGlo (CallLongN,CallLatN,CallRegN,CallFilePath,SpecFilePath,SpecTitle,GloAnaSlice,CallMapIDLReg)

integer, pointer, dimension (:,:) 		:: CallMapIDLReg, MapIDLReg
					! maps IDL grid to regions
real, pointer, dimension (:)			:: GloAnaSlice
					! one value per region

character (len=80), intent (in)			:: CallFilePath, SpecFilePath, SpecTitle
integer, intent (in)				:: CallLongN, CallLatN, CallRegN

real, allocatable, dimension (:,:) :: OutArray

real, parameter :: MissVal = -999.0

character (len=80) :: GivenFile, GloFilePath, GloTitle, FilePath
character (len=10) :: GloFormat

integer :: LongN, LatN
integer :: XLong, XLat, XEight, XTen, XSix
integer :: Long0, Long1, NoPolesBeg
integer :: AllocStat			! status of allocation statement
integer :: ReadStatus			! status of user input

if (SpecTitle.EQ."") then
  print*, "  > Enter the .glo file title: "
  do
	read (*,*,iostat=ReadStatus), GloTitle
	if (ReadStatus.LE.0.AND.GloTitle.NE."") exit
  end do
else
  GloTitle = SpecTitle
end if

if (SpecFilePath.EQ."") then
  print*, "  > Enter the filepath of the .glo file to save: "
  do
	do
		read (*,*,iostat=ReadStatus), GivenFile
		if (ReadStatus.LE.0) exit
	end do
	
	inquire (file=GivenFile, name=GloFilePath)
	open (1, file=GloFilePath, status="new", iostat=ReadStatus)
	if (ReadStatus .EQ. 0) close (1)
	if (ReadStatus .EQ. 0) exit
  end do
else
  GloFilePath = SpecFilePath
end if

if (CallLongN.EQ.97.AND.CallLatN.EQ.73) then		! this goes from h2grid to HadCM2
  LatN=73 ; LongN=96
  
  NoPolesBeg = index(CallFilePath,'h2grid.ref')
  FilePath = CallFilePath(1:(NoPolesBeg-1)) // 'hadcm2.ref'
  
  allocate (MapIDLReg(96,73)) ; MapIDLReg = MissVal
  do XLong = 1, LongN
    do XLat = 2, 72
      MapIDLReg(XLong,XLat) = CallMapIDLReg(XLong,XLat)
    end do
  end do
else
  LatN=CallLatN ; LongN=CallLongN ; FilePath=CallFilePath ; MapIDLReg=>CallMapIDLReg
end if

allocate (OutArray (LongN,LatN))

do XLong = 1, LongN
  do XLat = 1, LatN
    if (MapIDLReg(XLong,XLat).NE.MissVal) then
      OutArray (XLong,XLat) = GloAnaSlice (MapIDLReg (XLong,XLat))
    else
      OutArray (XLong,XLat) = MissVal
    end if
  end do
end do 

if ((real(LongN)/8.0).EQ.nint(real(LongN)/8.0)) then
  GloFormat = "(8E12.4)"			! examine LoadGlo before altering
else if ((real(LongN)/10.0).EQ.nint(real(LongN)/10.0)) then
  GloFormat = "(10E12.4)"			! examine LoadGlo before altering
else if ((real(LongN)/6.0).EQ.nint(real(LongN)/6.0)) then
  GloFormat = "(6E12.4)"			! examine LoadGlo before altering
else
  print*, "  > ##### ERROR: SaveGlo: LongN not divisible by 10 or 8 or 6 #####"
end if

open (2, file=GloFilePath, status="replace", access="sequential", form="formatted", &
		action="write")

write (2, fmt="(A80)"), GloTitle
write (2, fmt="(A10)"), GloFormat
write (2, fmt="(2I6)"), LongN, LatN
write (2, fmt="(A80)"), FilePath

if (GloFormat.EQ."(8E12.4)") then
 do XLat = 1, LatN
  do XEight = 1, (LongN/8)
   Long0 = (XEight-1)*8 + 1
   Long1 = Long0 + 7
  
   write (2, fmt=GloFormat), (OutArray (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
else if (GloFormat.EQ."(10E12.4)") then
 do XLat = 1, LatN
  do XTen = 1, (LongN/10)
   Long0 = (XTen-1)*10 + 1
   Long1 = Long0 + 9
  
   write (2, fmt=GloFormat), (OutArray (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
else if (GloFormat.EQ."(6E12.4)") then
 do XLat = 1, LatN
  do XSix = 1, (LongN/6)
   Long0 = (XSix-1)*6 + 1
   Long1 = Long0 + 5
  
   write (2, fmt=GloFormat), (OutArray (XLong, XLat), XLong=Long0,Long1 )
  end do
 end do
else
  print*, "  > ##### ERROR: SaveGlo: No save of data #####"
end if

close (2)

deallocate (OutArray)

if (FilePath.NE.CallFilePath) then
  deallocate (MapIDLReg)
else
  nullify (MapIDLReg)
end if

end subroutine SaveGlo

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

subroutine GetGloWeights (ExeN,WyeN,GloWeights)

real, pointer, dimension (:,:) 	:: GloWeights, WeightsXtra

integer, intent(in) 		:: ExeN, WyeN

real, parameter :: MissVal = -999.0

integer :: XWye, XExe
integer :: FileSubBeg, AllocStat

character (len=80) :: GenericFile

write (99,*), "running getgloweights..."					! ########################
GenericFile  = GetGloRef (ExeN,WyeN)
FileSubBeg   = index(GenericFile,".ref")
GenericFile  = GenericFile(1:(FileSubBeg-1)) // ".weights.glo"
  
write (99,*), "calling loadglogrid..."					! ########################
call LoadGloGrid (GenericFile, GloWeights, Silent=1)

write (99,*), "checking gloweights..."					! ########################
if (size(GloWeights,1).NE.ExeN.OR.size(GloWeights,2).NE.WyeN) then
    if (ExeN.EQ.97.AND.size(GloWeights,1).EQ.96) then
      allocate (WeightsXtra(ExeN,WyeN), stat=AllocStat)
      if (AllocStat.NE.0) print*, "  > ##### ERROR: GetGloWeights: Allocation failure: WeightsXtra #####"
      
      do XWye = 1, WyeN
        do XExe = 1, 96
          WeightsXtra(XExe,XWye) = GloWeights(XExe,XWye)
        end do
        WeightsXtra(97,XWye) = GloWeights(1,XWye)
      end do
      
      deallocate (GloWeights, stat=AllocStat)
      if (AllocStat.NE.0) print*, "  > ##### ERROR: GetGloWeights: Deallocation failure: GloWeights #####"
      
      allocate (GloWeights(ExeN,WyeN), stat=AllocStat)
      if (AllocStat.NE.0) print*, "  > ##### ERROR: GetGloWeights: Allocation failure: GloWeights #####"
      
      do XWye = 1, WyeN
        do XExe = 1, ExeN
          GloWeights(XExe,XWye) = WeightsXtra(XExe,XWye)
        end do
      end do
      
      deallocate (WeightsXtra, stat=AllocStat)
      if (AllocStat.NE.0) print*, "  > ##### ERROR: GetGloWeights: Deallocation failure: WeightsXtra #####"      
    else
      GloWeights = MissVal
      print*, "  > ##### ERROR: GetGloWeights: Loaded .glo has wrong dims #####"
    end if
end if
write (99,*), "finished getgloweights"					! ########################

end subroutine GetGloWeights

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

function GetGloRef (ExeN,WyeN)

integer, intent (in) :: ExeN, WyeN

integer :: ReadStatus

character (len=80) :: GivenFile, GetGloRef

if      (ExeN.EQ.720.AND.WyeN.EQ.360) then
  GetGloRef = "/tyn1/tim/constants/goglo/half-degree.ref"
else if (ExeN.EQ.160.AND.WyeN.EQ.106) then
  GetGloRef = "/tyn1/tim/constants/goglo/half-degree-euro.ref"
else if (ExeN.EQ.480.AND.WyeN.EQ.313) then
  GetGloRef = "/tyn1/tim/constants/goglo/tenmin-euro.ref"
else if (ExeN.EQ.258.AND.WyeN.EQ.228) then
  GetGloRef = "/tyn1/tim/constants/goglo/tenmin-ateam.ref"
else if (ExeN.EQ.192.AND.WyeN.EQ.144) then
  GetGloRef = "/tyn1/tim/constants/goglo/regridx2.ref"
else if (ExeN.EQ.180.AND.WyeN.EQ.290) then
  GetGloRef = "/tyn1/tim/constants/goglo/ng5.ref"
else if (ExeN.EQ.144.AND.WyeN.EQ. 73) then
  GetGloRef = "/tyn1/tim/constants/goglo/richjones.ref"
else if (ExeN.EQ.130.AND.WyeN.EQ.242) then
  GetGloRef = "/tyn1/tim/constants/goglo/ng5cut.ref"
else if (ExeN.EQ. 96.AND.WyeN.EQ. 73) then
  GetGloRef = "/tyn1/tim/constants/goglo/hadcm2.ref"  
else if (ExeN.EQ. 97.AND.WyeN.EQ. 73) then
  GetGloRef = "/tyn1/tim/constants/goglo/h2grid.ref"  
else if (ExeN.EQ. 80.AND.WyeN.EQ. 72) then
  GetGloRef = "/tyn1/tim/constants/goglo/tenmin-brit.ref"
else if (ExeN.EQ. 64.AND.WyeN.EQ. 56) then
  GetGloRef = "/tyn1/tim/constants/goglo/csiro.ref"
else if (ExeN.EQ. 96.AND.WyeN.EQ. 48) then
  GetGloRef = "/tyn1/tim/constants/goglo/cgcm1.ref"
else if (ExeN.EQ.128.AND.WyeN.EQ. 64) then
  GetGloRef = "/tyn1/tim/constants/goglo/ncar-pcm3.ref"
else
  print*, "  > Enter the grid .ref file (/tyn1/tim/constants/goglo/): "
  do
	read (*,*,iostat=ReadStatus), GivenFile
	if (ReadStatus.LE.0) exit
  end do
  GetGloRef = LoadPath (GivenFile,".ref")
end if 

end function GetGloRef

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

end module GloFiles
