! grimfiles.f90 ! module holding standard save and load GRIM (GRIdded Monthly) routines ! SaveGrim,LoadGrim,SaveGrimMonthPost,LoadGrimMonthPrep,SaveGrimMonth,LoadGrimMonth ! SaveGrip,LoadGrip,CheckGridAB ! written by Tim Mitchell on 22.03.01 ! last modified on 20.11.01 module GrimFiles use FileNames use Time implicit none contains !******************************************************************************* ! this ensures that the data is saved in the order implicit in the grid dimensions: ! i.e. long (X) varies slowest (-180...180), and lat (Y) quickest (-90...90) ! call SaveGrim (OperA,Grid,FileYearAD,Bounds,CommInfo(XComm,XExec),CommFile(XComm,XExec)," ",& ! FileSuffix,NoZip=1,SaveYearAD0=CommOp(XComm,4),SaveYearAD1=CommOp(XComm,5)) subroutine SaveGrim (Data,Grid,YearAD,Bounds,Info,CallFile,CallSuffix,SaveSuffix, & SaveYearAD0,SaveYearAD1,NoZip,Silent) real,pointer,dimension(:,:,:) :: Data integer, pointer, dimension (:,:) :: Grid integer, pointer, dimension (:) :: YearAD real, dimension (4) :: Bounds integer, dimension (12) :: YearData character (len=80), dimension (5) :: Headers integer, optional, intent (in) :: NoZip,Silent integer, optional, intent (in) :: SaveYearAD0,SaveYearAD1 character (len=80), intent (in) :: Info, CallFile character (len= 4), intent (in) :: CallSuffix character (len= 4), intent (out) :: SaveSuffix real, parameter :: MissVal = -999.0 integer, parameter :: DataMissVal = -9999 real :: Divisor integer :: YearN,MonthN,BoxN,ExeN,WyeN,SaveYearN integer :: XYear,XMonth,XBox,XHeader,XExe,XWye integer :: AllocStat, TotExceed,XSaveYear0,XSaveYear1 character (len=80) :: SaveFile, Variable !*************************************** YearN = size (Data,1) ; MonthN = size (Data,2) ; BoxN = size (Data,3) ExeN = size (Grid,1) ; WyeN = size (Grid,2) ; TotExceed = 0 if (size(YearAD).NE.YearN) print*, " > ##### ERROR: SaveGrim: incompatible arrays #####" if (MonthN .NE. 12) print*, " > ##### ERROR: SaveGrim: weird calendar #####" if (Bounds(2).EQ.Bounds(1)) print*, " > ##### ERROR: SaveGrim: zero longitude range #####" if (Bounds(4).EQ.Bounds(3)) print*, " > ##### ERROR: SaveGrim: zero latitude range #####" if (present(SaveYearAD0).AND.present(SaveYearAD1)) then XSaveYear0 = SaveYearAD0 - YearAD(1) + 1 XSaveYear1 = SaveYearAD1 - YearAD(1) + 1 SaveYearN = XSaveYear1 - XSaveYear0 + 1 if (.not.present(Silent)) print "(a,2(x,i4))", " > Period:",XSaveYear0,XSaveYear1 if (XSaveYear0.LT.1.OR.XSaveYear0.GT.YearN.OR.XSaveYear1.LT.1.OR.XSaveYear1.GT.YearN) & print*, " > ##### ERROR: SaveGrim: save years out of range #####" else XSaveYear0 = 1 ; XSaveYear1 = YearN ; SaveYearN = YearN end if call ReviewCall (CallFile,CallSuffix,SaveFile,SaveSuffix,2) ! checks for file/suffix consistency !*************************************** call CheckVariSuffix (SaveSuffix,Variable,Divisor) ! get Divisor if (.not.present(Silent)) print "(2a)", " > ", trim(Info) open (2,file=SaveFile,status="replace",access="sequential",form="formatted",action="write") call WriteHeaders (SaveSuffix,Info,Bounds,ExeN,WyeN,BoxN, & YearAD(XSaveYear0),YearAD(XSaveYear1),"grim") do XExe = 1, ExeN do XWye = 1, WyeN if (Grid(XExe,XWye).NE.MissVal) then write ( 2,"(a9,i4,a1,i4)"), "Grid-ref=", XExe, ",", XWye do XYear = XSaveYear0, XSaveYear1 do XMonth = 1, MonthN if (Data(XYear,XMonth,Grid(XExe,XWye)).NE.MissVal) then YearData(XMonth) = nint(Data(XYear,XMonth,Grid(XExe,XWye)) / Divisor) if (YearData(XMonth).GT.99999.OR.YearData(XMonth).LT.-9999) then YearData(XMonth) = nint(MissVal) TotExceed = TotExceed + 1 end if else YearData(XMonth) = nint(MissVal) end if end do write (2,"(12i5)"), (YearData(XMonth), XMonth=1,MonthN) end do end if end do end do close (2) if (TotExceed.GT.0) print "(a,i9)", " > Box-months outside range: ", TotExceed !*************************************** if (present(NoZip)) then if (.not.present(Silent)) print*, " > The file is not being compressed." else if (.not.present(Silent)) print*, " > Compressing in background..." call system ('compress ' // SaveFile // ' &') end if end subroutine SaveGrim !******************************************************************************* ! when using this routine, do not assume that this Grid and your Grid are identical ! however, if the same cells are non-missing in the original saves to grim, ! the SaveGrim procedure ensures that the Grids obtained will be the same from the two loads from grim ! Data (A) may be defined (=Y) or not (=N) in the call; MasterYearAD (B) may (=Y) or may not (=N) be specified ! if A=Y,B=Y: loading requires sizes A=B, and common period between B and file ! if A=Y,B=N: loading requires sizes A=file ! if A=N,B=Y: loading requires common period between B and file, Data=(MasterYearN,12,BoxN) ! if A=N,B=N: loaded automatically, Data=(FileYearN,12,BoxN) ! if Data is defined in the call, it must also have already been initialised if that is necessary ! FileYearAD IS the genuine FileYearAD, and may differ from Data and MasterYearAD ! use Override with caution! it fills in FileYear0 (and hence FileYear1) subroutine LoadGrim (Data,Grid,FileYearAD,Bounds,Info,CallFile,CallSuffix,LoadSuffix,& MasterYearAD,Quiet,OverRide) real, pointer, dimension (:,:,:) :: Data integer, pointer, dimension (:,:) :: Grid integer, pointer, dimension (:) :: FileYearAD integer, pointer, optional, dimension (:) :: MasterYearAD ! may or may not be included: see top integer, dimension (12) :: YearData character (len=80), dimension (5) :: Headers real, dimension (4) :: Bounds integer, intent(in), optional :: Quiet,OverRide character (len=80), intent (out) :: Info character (len=80), intent (in) :: CallFile character (len= 4), intent (in) :: CallSuffix character (len= 4), intent (out) :: LoadSuffix real, parameter :: MissVal = -999.0 real :: Multiplier integer :: FileYearN,MasterYearN,MonthN,BoxN,ExeN,WyeN integer :: XFileYear,XMasterYear,XMonth,XBox,XHeader,XExe,XWye integer :: AllocStat integer :: LoadFileLen,FileYearAD0,FileYearAD1,FileYear0,FileYear1,MasterYear0,MasterYear1 integer :: QZip integer :: DataEn,DataMiss character (len=80) :: LoadFile, Variable, Trash !*************************************** call ReviewCall (CallFile,CallSuffix,LoadFile,LoadSuffix,1) ! checks for file/suffix consistency LoadFileLen = len_trim(LoadFile) if (LoadFileLen.GT.1.AND.LoadFile((LoadFileLen-1):LoadFileLen).EQ.".Z") then QZip = 2 ! file is zipped if (.not.present(Quiet)) print*, " > Uncompressing on the fly..." call system ('uncompress ' // LoadFile) LoadFile ((LoadFileLen-1):LoadFileLen) = " " ! change filename to the unzipped file else QZip = 1 ! file already unzipped end if call CheckVariSuffix (LoadSuffix,Variable,Multiplier) ! get multiplier !*************************************** open (2,file=LoadFile,status="old",access="sequential",form="formatted",action="read") call ReadHeaders (LoadSuffix,Info,Bounds,ExeN,WyeN,BoxN,FileYearAD0,FileYearAD1,"grim") if (Bounds(2).EQ.Bounds(1)) print*, " > ##### ERROR: LoadGrim: zero longitude range #####" if (Bounds(4).EQ.Bounds(3)) print*, " > ##### ERROR: LoadGrim: zero latitude range #####" FileYearN = FileYearAD1 - FileYearAD0 + 1 MonthN = 12 if (present(MasterYearAD).AND.associated(Data)) then if (size(Data,1).NE.size(MasterYearAD,1)) then print*, " > ##### ERROR: LoadGrim: call mismatch #####",size(Data,1),size(MasterYearAD,1) MasterYearN = MissVal else MasterYearN = size(Data,1) end if else if (present(MasterYearAD)) then MasterYearN = size(MasterYearAD,1) else if (associated(Data)) then MasterYearN = size(Data,1) else MasterYearN = FileYearN end if if (associated(Data)) then if (size(Data,2).NE.MonthN) print*, " > ##### ERROR: LoadGrim: Months mismatch #####", & size(Data,2),MonthN if (size(Data,3).NE.BoxN) print*, " > ##### ERROR: LoadGrim: Domain mismatch #####", & size(Data,3),BoxN else allocate (Data (MasterYearN,MonthN,BoxN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadGRIM: Allocation failure: Data #####" Data = MissVal end if allocate (Grid (ExeN,WyeN), & FileYearAD (FileYearN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadGRIM: Allocation failure: All #####" Grid = MissVal if (present(OverRide)) then FileYearAD0=OverRide ; FileYearAD1=OverRide+FileYearN-1 end if do XFileYear = 1, FileYearN FileYearAD(XFileYear) = FileYearAD0 + XFileYear - 1 end do if (present(MasterYearAD)) then call CommonVecPer (FileYearAD,MasterYearAD,FileYear0,FileYear1,MasterYear0,MasterYear1) if (FileYear0.EQ.MissVal) then print "(a)", " > ##### ERROR: LoadGrim: The file and spec are mismatched in period #####", & FileYear0,FileYear1,MasterYear0,MasterYear1 FileYear0 = MissVal ; FileYear1 = MissVal ; MasterYear0 = MissVal ; MasterYear1 = MissVal else if (.not.present(Quiet)) print "(a,i4,a1,i4))", " > Period loading: ", FileYearAD(FileYear0), & "-", FileYearAD(FileYear1) end if else if (size(Data,1).EQ.FileYearN) then FileYear0 = 1 ; FileYear1 = FileYearN ; MasterYear0 = 1 ; MasterYear1 = FileYearN else print*, " > ##### ERROR: LoadGrim: Period mismatch #####",size(Data,1),FileYearN FileYear0 = MissVal ; FileYear1 = MissVal ; MasterYear0 = MissVal ; MasterYear1 = MissVal end if end if if (FileYear0.NE.MissVal) then if (.not.present(Quiet)) print "(2a)", " > ", trim(Info) DataEn = 0 ; DataMiss = 0 do XBox = 1, BoxN read (2,"(a9,i4,a1,i4)"), Trash, XExe, Trash, XWye Grid(XExe,XWye) = XBox do XFileYear = 1, FileYearN read (2,"(12i5)"), (YearData(XMonth), XMonth=1,MonthN) if (XFileYear.GE.FileYear0.AND.XFileYear.LE.FileYear1) then XMasterYear = MasterYear0 + XFileYear - FileYear0 do XMonth = 1, MonthN DataEn = DataEn + 1 if (YearData(XMonth).EQ.MissVal) then Data(XMasterYear,XMonth,XBox) = MissVal DataMiss = DataMiss + 1 else Data(XMasterYear,XMonth,XBox) = real(YearData(XMonth)) * Multiplier end if end do end if end do end do if (.not.present(Quiet)) print "(a,2i12)", " > Total and missing values: ", DataEn, DataMiss else print*, " > ##### Nothing was loaded from the file. #####" end if close (2) !*************************************** if (QZip.EQ.2) then call system ('compress ' // LoadFile // ' &') if (.not.present(Quiet)) print*, " > Recompressing in the background..." end if end subroutine LoadGrim !******************************************************************************* ! saves GRIdded Seasonic files (12*month,4*season,1*annual) ! this ensures that the data is saved in the order implicit in the grid dimensions: ! i.e. long (X) varies slowest (-180...180), and lat (Y) quickest (-90...90) subroutine SaveGrip (Data,Grid,Bounds,Info,CallFile,CallSuffix,SaveSuffix) real, pointer, dimension (:,:) :: Data integer, pointer, dimension (:,:) :: Grid real, dimension (4) :: Bounds character (len=80), dimension (5) :: Headers character (len=80), intent (in) :: Info, CallFile character (len= 4), intent (in) :: CallSuffix character (len= 4), intent (out) :: SaveSuffix real, parameter :: MissVal = -999.0 real :: Divisor integer :: SeasonN,BoxN,ExeN,WyeN integer :: XSeason,XBox,XHeader,XExe,XWye integer :: AllocStat character (len=80) :: SaveFile, Variable, SaveBinFile !*************************************** SeasonN = size (Data,1) ; BoxN = size (Data,2) ExeN = size (Grid,1) ; WyeN = size (Grid,2) if (SeasonN .NE. 17) print*, " > ##### ERROR: SaveGrip: weird calendar #####" !if (Bounds(1).LT.-180.OR.Bounds(2).GT.180.OR.Bounds(1).GT.Bounds(2)) & ! print*, " > ##### ERROR: SaveGrip: longitudes not within spherical geometry #####" ! !if (Bounds(3).LT.-90.OR.Bounds(4).GT.90.OR.Bounds(3).GT.Bounds(4)) & ! print*, " > ##### ERROR: SaveGrip: latitudes not within spherical geometry #####" if (Bounds(2).EQ.Bounds(1)) print*, " > ##### ERROR: SaveGrip: zero longitude range #####" if (Bounds(4).EQ.Bounds(3)) print*, " > ##### ERROR: SaveGrip: zero latitude range #####" call ReviewCall (CallFile,CallSuffix,SaveFile,SaveSuffix,2) ! checks for file/suffix consistency SaveFile = trim(SaveFile) // ".X" !*************************************** print "(2a)", " > ", trim(Info) open (2,file=SaveFile,status="replace",access="sequential",form="unformatted",action="write") call WriteHeaders (SaveSuffix,Info,Bounds,ExeN,WyeN,BoxN,0,0,"grip") do XExe = 1, ExeN do XWye = 1, WyeN if (Grid(XExe,XWye).NE.MissVal) then write (2), XExe, XWye, (Data(XSeason,Grid(XExe,XWye)), XSeason=1,SeasonN) end if end do end do close (2) end subroutine SaveGrip !******************************************************************************* ! when using this routine, do not assume that this Grid and your Grid are identical ! however, if the same cells are non-missing in the original saves to grim, ! the SaveGrip procedure ensures that the Grids obtained will be the same from the two loads from grim ! Data (A) may be defined (=Y) or not (=N) in the call ! if Data is defined in the call, it must also have already been initialised if that is necessary subroutine LoadGrip (Data,Grid,Bounds,Info,CallFile,CallSuffix,LoadSuffix) real, pointer, dimension (:,:) :: Data real, dimension (17) :: Line integer, pointer, dimension (:,:) :: Grid character (len=80), dimension (5) :: Headers real, dimension (4) :: Bounds character (len=80), intent (out) :: Info character (len=80), intent (in) :: CallFile character (len= 4), intent (in) :: CallSuffix character (len= 4), intent (out) :: LoadSuffix real, parameter :: MissVal = -999.0 integer, parameter :: SeasonN = 17 integer :: BoxN,ExeN,WyeN integer :: XSeason,XBox,XHeader,XExe,XWye integer :: AllocStat integer :: LoadFileLen,QBin integer :: Year0,Year1 integer :: DataEn,DataMiss character (len=80) :: LoadFile, Variable, Trash !*************************************** call ReviewCall (CallFile,CallSuffix,LoadFile,LoadSuffix,1) ! checks for file/suffix consistency open (2,file=LoadFile,status="old",access="sequential",form="unformatted",action="read") call ReadHeaders (LoadSuffix,Info,Bounds,ExeN,WyeN,BoxN,Year0,Year1,"grip") if (Bounds(2).EQ.Bounds(1)) print*, " > ##### ERROR: LoadGrip: zero longitude range #####" if (Bounds(4).EQ.Bounds(3)) print*, " > ##### ERROR: LoadGrip: zero latitude range #####" if (associated(Data)) then if (size(Data,1).NE.SeasonN) print*, " > ##### ERROR: LoadGrip: SeasonN mismatch #####" if (size(Data,2).NE.BoxN) print*, " > ##### ERROR: LoadGrip: Domain mismatch #####" else allocate (Data (SeasonN,BoxN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadGrip: Allocation failure: Data #####" Data = MissVal end if allocate (Grid (ExeN,WyeN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadGrip: Allocation failure: All #####" Grid = MissVal if (Year1.GE.Year0) then print "(2a)", " > ", trim(Info) do XBox = 1, BoxN read (2), XExe, XWye, (Line(XSeason), XSeason=1,SeasonN) Grid (XExe,XWye) = XBox do XSeason = 1, SeasonN Data(XSeason,XBox) = Line(XSeason) end do end do else print*, " > Nothing was loaded from the file." end if close (2) end subroutine LoadGrip !******************************************************************************* ! this saves the data from individual month/year files into one big array ! so do work, save to year/month files, and call this ! hence Save Monthly Grim files Post-analysis subroutine SaveGrimMonthPost (DataFile,BoxN,Grid,YearAD,Bounds,Info,CallFile,CallSuffix,SaveSuffix) real, pointer, dimension (:,:,:) :: Data real, pointer, dimension (:) :: DataMonth integer, pointer, dimension (:,:) :: Grid integer, pointer, dimension (:) :: YearAD character (len=80), pointer, dimension (:,:) :: DataFile character (len= 4), pointer, dimension (:) :: YearText character (len= 2), pointer, dimension (:) :: MonthText real, dimension (4) :: Bounds integer, intent (in) :: BoxN character (len=80), intent (in) :: Info, CallFile character (len= 4), intent (in) :: CallSuffix character (len= 4), intent (out) :: SaveSuffix real, parameter :: MissVal = -999.0 integer :: AllocStat integer :: YearN,MonthN,XYear,XMonth,XBox integer :: CurrentPos,CurrentCod character (len= 4) :: GivenText !*************************************** YearN = size (DataFile,1) MonthN = size (DataFile,2) allocate (Data(YearN,MonthN,BoxN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SaveGrimMonthPost: Allocation failure #####" do XYear = 1, YearN ! get Data from individual time steps do XMonth = 1, MonthN call LoadGrimMonth (DataFile(XYear,XMonth),DataMonth) ! ... and dump to file do XBox = 1, BoxN Data(XYear,XMonth,XBox) = DataMonth(XBox) end do deallocate (DataMonth,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SaveGrimMonthPost: Deallocation failure #####" end do end do call SaveGrim (Data,Grid,YearAD,Bounds,Info,CallFile,CallSuffix,SaveSuffix) deallocate (Data,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SaveGrimMonthPrep: Deallocation failure #####" end subroutine SaveGrimMonthPost !******************************************************************************* ! this loads the data into one big array ! saves it as individual month/year files subroutine LoadGrimMonthPrep (DataFile,BoxN,Grid,YearAD,Bounds,Info,CallFile,CallSuffix,LoadSuffix) real, pointer, dimension (:,:,:) :: Data real, pointer, dimension (:) :: DataMonth integer, pointer, dimension (:,:) :: Grid integer, pointer, dimension (:) :: YearAD character (len=80), pointer, dimension (:,:) :: DataFile character (len= 4), pointer, dimension (:) :: YearText character (len= 2), pointer, dimension (:) :: MonthText real, dimension (4) :: Bounds integer, intent (out) :: BoxN character (len=80), intent (in) :: CallFile character (len=80), intent (out) :: Info character (len= 4), intent (in) :: CallSuffix character (len= 4), intent (out) :: LoadSuffix real, parameter :: MissVal = -999.0 integer :: AllocStat integer :: YearN,MonthN,XYear,XMonth,XBox integer :: CurrentPos,CurrentCod character (len= 4) :: GivenText !*************************************** call LoadGrim (Data,Grid,YearAD,Bounds,Info,CallFile,CallSuffix,LoadSuffix) YearN = size (Data,1) MonthN = size (Data,2) BoxN = size (Data,3) allocate (DataFile (YearN,MonthN), & YearText (YearN), & MonthText (MonthN), & DataMonth (BoxN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadGrimMonthPrep: Allocation failure #####" open (1,file="/cru/scratch2/f709762/year-scratch.txt",status="scratch") write (1,"(i4)"), YearAD(1) rewind (1) read (1,"(a4)"), GivenText close (1) YearText(1) = GivenText ! get year AD in text form do XYear = 2, YearN GivenText = YearText (XYear-1) CurrentPos = 4 do CurrentCod = iachar(GivenText(CurrentPos:CurrentPos)) if (CurrentCod.LE.56) then GivenText(CurrentPos:CurrentPos) = achar(CurrentCod+1) CurrentPos = 0 else GivenText(CurrentPos:CurrentPos) = achar(48) CurrentPos = CurrentPos - 1 end if if (CurrentPos.EQ.0) exit end do YearText (XYear) = GivenText end do MonthText(1) = "01" ; MonthText(2) = "02" ; MonthText(3) = "03" ; MonthText(4) = "04" MonthText(5) = "05" ; MonthText(6) = "06" ; MonthText(7) = "07" ; MonthText(8) = "08" MonthText(9) = "09" ; MonthText(10) = "10" ; MonthText(11) = "11" ; MonthText(12) = "12" do XYear = 1, YearN ! split up Data into individual time steps do XMonth = 1, MonthN do XBox = 1, BoxN DataMonth(XBox) = Data(XYear,XMonth,XBox) end do DataFile(XYear,XMonth) = '/cru/scratch2/f709762/' // YearText(XYear) // '.' & // MonthText(XMonth) // LoadSuffix call SaveGrimMonth (DataFile(XYear,XMonth),DataMonth) ! ... and dump to file end do end do deallocate (Data,DataMonth,YearText,MonthText,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadGrimMonthPrep: Deallocation failure #####" end subroutine LoadGrimMonthPrep !******************************************************************************* ! checks the filename and suffix given in call ! returns the correct suffix, and correct filename with the correct suffix subroutine ReviewCall (CallFile,CallSuffix,CheckFile,CheckSuffix,LoadSave) character (len=80), intent (in) :: CallFile character (len= 4), intent (in) :: CallSuffix character (len=80), intent (out) :: CheckFile character (len= 4), intent (out) :: CheckSuffix integer, intent (in) :: LoadSave ! 1=load,2=save character (len=80), parameter :: Blank = "" character (len=80) :: Variable, WorkFile character (len= 4) :: FileSuffix real :: Factor integer :: SuffixStart,ReadStatus,ZipStart,CallFileLen !*************************************** CheckFile = "" ; CheckSuffix = "" ; Variable = "" CallFileLen = len_trim(CallFile) ! remove any zip or binary expression if (CallFileLen.GT.1) then if (CallFile((CallFileLen-1):CallFileLen).EQ.".Z".OR.CallFile((CallFileLen-1):CallFileLen).EQ.".X") then WorkFile = CallFile(1:(CallFileLen-2)) // " " else WorkFile = CallFile end if else WorkFile = CallFile end if if (CallSuffix.EQ."".OR.CallSuffix.EQ." ") then ! suffix is not present in call if (WorkFile.EQ."") then ! and there is no file in call do print*, " > Enter the grim filepath: " ! get filepath do read (*,*,iostat=ReadStatus), WorkFile if (ReadStatus.EQ.0) exit end do CheckSuffix = GetFileSuffix (WorkFile) ! get suffix from filepath if (CheckSuffix.NE."") exit end do ! check filepath if (LoadSave.EQ.1) CheckFile = LoadPath (WorkFile,CheckSuffix) if (LoadSave.EQ.2) CheckFile = SavePath (WorkFile,CheckSuffix) else ! and there is a file in call do CheckSuffix = GetFileSuffix (WorkFile) ! get suffix from filepath if (CheckSuffix.EQ."") then print*, " > Enter the grim filepath: " ! get filepath do read (*,*,iostat=ReadStatus), WorkFile if (ReadStatus.EQ.0) exit end do end if if (CheckSuffix.NE."") exit end do ! check filepath if (LoadSave.EQ.1) CheckFile = LoadPath (WorkFile,CheckSuffix) if (LoadSave.EQ.2) CheckFile = SavePath (WorkFile,CheckSuffix) end if else ! suffix present in call call CheckVariSuffix (CallSuffix,Variable,Factor) if (Variable.EQ."") then ! but unrecognised... print*, " > Supplied suffix is invalid. Supply another. " ! therefore obtain another do CheckSuffix = GetFreshSuffix () if (Variable.NE."") exit end do else ! and is recognised CheckSuffix = CallSuffix end if if (WorkFile.NE."") then ! gotta suffix, investigate file in call FileSuffix = GetFileSuffix (WorkFile) ! get suffix from file if (FileSuffix.EQ.CheckSuffix) then ! suffix good, so check filepath if (LoadSave.EQ.1) CheckFile = LoadPath (WorkFile,CheckSuffix) if (LoadSave.EQ.2) CheckFile = SavePath (WorkFile,CheckSuffix) else if (FileSuffix.EQ."") then ! suffix bad, so get filepath print*, " > File suffix is not recognised." else print*, " > File suffix is not the same as the supplied suffix." end if if (LoadSave.EQ.1) CheckFile = LoadPath (Blank,CheckSuffix) if (LoadSave.EQ.2) CheckFile = SavePath (Blank,CheckSuffix) end if else ! gotta suffix but no file in call if (LoadSave.EQ.1) CheckFile = LoadPath (Blank,CheckSuffix) if (LoadSave.EQ.2) CheckFile = SavePath (Blank,CheckSuffix) end if end if end subroutine ReviewCall !******************************************************************************* ! get any legitimate suffix function GetFreshSuffix (Verbose, NoPrompt) integer, intent (in), optional :: Verbose integer, optional :: NoPrompt real :: Factor integer :: ReadStatus character (len=80) :: Variable character (len= 4) :: GetFreshSuffix, Suffix if (.not.present(NoPrompt)) print*, " > Enter the grim file suffix: " Variable = "" do read (*,*,iostat=ReadStatus), Suffix if (Suffix.EQ."") then print*, " > Blank is unacceptable. Try again." else call CheckVariSuffix (Suffix,Variable,Factor) if (Variable.EQ."") print*, " > Suffix unrecognised. Try again." end if if (ReadStatus.EQ.0.AND.Variable.NE."") exit end do if (present(Verbose)) print "(2a)", " > Variable: ", trim(Variable) GetFreshSuffix = Suffix end function GetFreshSuffix !******************************************************************************* ! extract suffix from file function GetFileSuffix (CallFile,Verbose) real :: Factor integer, intent (in), optional :: Verbose integer :: ReadStatus, CallFileLen, SuffixStart character (len=80) :: Variable, CallFile, WorkFile character (len= 4) :: GetFileSuffix, Suffix CallFileLen = len_trim(CallFile) ! remove any zip or binary expression if (CallFileLen.GT.1) then if (CallFile((CallFileLen-1):CallFileLen).EQ.".Z".OR.CallFile((CallFileLen-1):CallFileLen).EQ.".X") then WorkFile = CallFile(1:(CallFileLen-2)) // " " else WorkFile = CallFile end if else WorkFile = CallFile end if Suffix = "" ; Variable = "" ; GetFileSuffix = " " SuffixStart = index (WorkFile,".",.TRUE.) ! identify suffix if (SuffixStart.GT.0) then ! check suffix Suffix = WorkFile(SuffixStart:(SuffixStart+3)) call CheckVariSuffix (Suffix,Variable,Factor) if (Variable.EQ."") print*, " > Suffix unrecognised." if (Variable.NE."") then if (present(Verbose)) print "(2a)", " > Variable: ", trim(Variable) GetFileSuffix = Suffix ! return suffix end if else print*, " > No identifiable suffix in filepath." end if end function GetFileSuffix !******************************************************************************* ! relies on Suffix being correct !! subroutine WriteHeaders (Suffix,Info,Bounds,ExeN,WyeN,BoxN,YearAD0,YearAD1,FileType) real, dimension (4) :: Bounds character (len=80), intent (in) :: Info character (len= 4), intent (in) :: Suffix, FileType integer, intent(in) :: BoxN,ExeN,WyeN,YearAD0,YearAD1 real :: Multi integer :: XBound character (len=80) :: Variable character (len=12) :: Date,Time character (len= 4) :: Year character (len= 2) :: Month,Day,Hour,Minute !*************************************** call CheckVariSuffix (Suffix,Variable,Multi) call date_and_time (Date, Time) Year = Date (1:4) Month = Date (5:6) Day = Date (7:8) Hour = Time (1:2) Minute= Time (3:4) if (FileType.EQ."grim") then write (2,"(a15,a4,a17,a2,a1,a2,a1,a4,a4,a2,a1,a2,a20)"), "Tyndall Centre ", FileType, " file created on ", & Day, ".", Month, ".", Year, " at ", Hour, ":", Minute, " by Dr. Tim Mitchell" write (2,"(a4,a3,a)"), Suffix, " = ", trim(Variable) write (2,"(a)"), trim(Info) write (2,"(a6,f7.2,a1,f7.2,a8,f7.2,a1,f7.2,a12,i4,a1,i4,a1)"), & "[Long=", Bounds(1), ",", Bounds(2), "] [Lati=", Bounds(3), ",", Bounds(4), & "] [Grid X,Y=", ExeN, ",", WyeN, "]" write (2,"(a7,i8,a9,i4,a1,i4,a9,f10.4,a16)"), & "[Boxes=", BoxN, "] [Years=", YearAD0, "-", YearAD1, "] [Multi=", Multi, "] [Missing=-999]" else if (FileType.EQ."grip") then write (2), FileType, Day, Month, Year, Hour, Minute write (2), Suffix, Variable write (2), Info write (2), (Bounds(XBound),XBound=1,4), ExeN, WyeN write (2), BoxN, 0, 0, 1.0, -999.0 end if end subroutine WriteHeaders !******************************************************************************* ! checks filename suffix against header suffix subroutine ReadHeaders (FileNameSuffix,Info,Bounds,ExeN,WyeN,BoxN,YearAD0,YearAD1,FileType) real, dimension (4) :: Bounds character (len= 4), intent (in) :: FileNameSuffix,FileType character (len=80), intent (out) :: Info integer, intent(out) :: BoxN,ExeN,WyeN,YearAD0,YearAD1 real :: LoadMulti, LoadMissVal integer :: XBound character (len=80) :: Trash, LoadVariable character (len= 4) :: HeaderSuffix, LoadFileType character (len= 4) :: Year character (len= 2) :: Month,Day,Hour,Minute !*************************************** if (FileType.EQ."grim") then read (2,"(a15,a4)"), Trash, LoadFileType read (2,"(a4)"), HeaderSuffix read (2,"(a80)"), Info read (2,"(a6,f7.2,a1,f7.2,a8,f7.2,a1,f7.2,a12,i4,a1,i4)"), & Trash, Bounds(1), Trash, Bounds(2), Trash, Bounds(3), Trash, Bounds(4), & Trash, ExeN, Trash, WyeN read (2,"(a7,i8,a9,i4,a1,i4)"), Trash, BoxN, Trash, YearAD0, Trash, YearAD1 else if (FileType.EQ."grip") then read (2), LoadFileType, Day, Month, Year, Hour, Minute ! read (2), HeaderSuffix, LoadVariable read (2), HeaderSuffix read (2), Info read (2), (Bounds(XBound),XBound=1,4), ExeN, WyeN read (2), BoxN, YearAD0,YearAD1, LoadMulti, LoadMissVal end if if (LoadFileType.EQ."file") LoadFileType = "grim" if (LoadFileType.NE.FileType) then print*, " > ##### ERROR: ReadHeaders: Mismatch between called and actual file type." YearAD1 = YearAD0 - 1 end if if (HeaderSuffix.NE.FileNameSuffix) then print*, " > ##### ERROR: ReadHeaders: Mismatch between filename and header suffixes." YearAD1 = YearAD0 - 1 end if end subroutine ReadHeaders !******************************************************************************* ! saves a single month's data in a temporary file subroutine SaveGrimMonth (CallFile,DataMonth) real, pointer, dimension (:) :: DataMonth character (len=80), intent (in) :: CallFile integer :: BoxN, XBox BoxN = size (DataMonth) open (3,file=CallFile,status="new",access="sequential",form="unformatted",action="write") write (3), BoxN do XBox = 1, BoxN write (3), DataMonth(XBox) end do close (3) end subroutine SaveGrimMonth !******************************************************************************* ! loads a single month's data from a temporary file subroutine LoadGrimMonth (CallFile,DataMonth) real, pointer, dimension (:) :: DataMonth character (len=80), intent (in) :: CallFile integer :: BoxN, XBox, AllocStat open (3,file=CallFile,status="old",access="sequential",form="unformatted",action="read") read (3), BoxN allocate (DataMonth(BoxN),stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadGrimMonth: Allocation failure #####" do XBox = 1, BoxN read (3), DataMonth(XBox) end do close (3) end subroutine LoadGrimMonth !******************************************************************************* ! BoxN : >0:grids are the same with this number of boxes, MissVal=grids are not the same subroutine CheckGridAB (GridA,GridB,BoxN) integer, pointer, dimension (:,:) :: GridA, GridB integer, intent(out) :: BoxN real, parameter :: MissVal = -999.0 integer :: ExeN,WyeN,XExe,XWye BoxN = 0 if (size(GridA,1).NE.size(GridB,1)) then BoxN = MissVal else ExeN = size(GridA,1) end if if (size(GridA,2).NE.size(GridB,2)) then BoxN = MissVal else WyeN = size(GridA,2) end if if (BoxN.NE.MissVal) then XExe = 0 do XExe = XExe + 1 ; XWye = 0 do XWye = XWye + 1 if (GridA(XExe,XWye).EQ.GridB(XExe,XWye)) then if (GridA(XExe,XWye).NE.MissVal) BoxN = BoxN + 1 else BoxN = MissVal end if if (XWye.EQ.WyeN) exit if (BoxN.EQ.MissVal) exit end do if (XExe.EQ.ExeN) exit if (BoxN.EQ.MissVal) exit end do end if end subroutine CheckGridAB !******************************************************************************* ! check given file suffix ! Variable is either blank (suffix unrecognised) or contains description of variable ! Factor is zero unless Variable is set subroutine CheckVariSuffix (Suffix,Variable,Factor) real, intent (out) :: Factor character (len=80), intent (out) :: Variable character (len= 4), intent (in) :: Suffix Variable = "undefined" if (Suffix.EQ.".alp") then Variable="precip (mm) gamma distribution alpha" Factor = 0.01 else if (Suffix.EQ.".bet") then Variable="precip (mm) gamma distribution beta" Factor = 0.0001 else if (Suffix.EQ.".cld") then Variable="cloud cover (percentage)" Factor = 0.1 ! some naughty files think it is 0.01 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ else if (Suffix.EQ.".dew") then Variable="dew point temperature (degrees Celsius)" Factor = 0.1 else if (Suffix.EQ.".dir") then Variable="wind direction (degrees)" Factor = 0.1 else if (Suffix.EQ.".dpd") then Variable="dew point depression (degrees Celsius)" Factor = 0.1 else if (Suffix.EQ.".dsf") then Variable="downward shortwave flux (W/m2)" Factor = 0.1 else if (Suffix.EQ.".dtr") then Variable="diurnal temperature range (degrees Celsius)" Factor = 0.1 else if (Suffix.EQ.".elv") then Variable="elevation (km)" Factor = 0.001 else if (Suffix.EQ.".frs") then Variable="ground frost frequency (days)" Factor = 0.01 else if (Suffix.EQ.".oct") then Variable="cloud cover (octas)" Factor = 0.01 else if (Suffix.EQ.".osb") then Variable="Osborn cum-prob (0.00002) or obs/lofreq (0.001)" Factor = 1.0 else if (Suffix.EQ.".pre") then Variable="precipitation (mm)" Factor = 0.1 else if (Suffix.EQ.".prc") then Variable="precip change (%)" Factor = 0.001 else if (Suffix.EQ.".prd") then Variable="precip change (%)" Factor = 0.1 else if (Suffix.EQ.".prp") then Variable="precipitation rate (mm/day)" Factor = 0.1 else if (Suffix.EQ.".prq") then Variable="precipitation quintile" Factor = 0.01 else if (Suffix.EQ.".prr") then Variable="precipitation rate (mm/day)" Factor = 0.001 else if (Suffix.EQ.".rad") then Variable="radiation (W/(m*m))" Factor = 0.1 else if (Suffix.EQ.".rd0") then Variable="rain day frequency (days)" Factor = 0.01 else if (Suffix.EQ.".rhm") then Variable="relative humidity (%)" Factor = 0.1 else if (Suffix.EQ.".shp") then Variable="gamma shape parameter" Factor = 0.001 else if (Suffix.EQ.".shu") then Variable="specific humidity (kg/kg)" Factor = 0.0001 else if (Suffix.EQ.".slp") then Variable="sea level pressure" Factor = 0.1 else if (Suffix.EQ.".snh") then Variable="sunshine hours" Factor = 0.1 else if (Suffix.EQ.".spc") then Variable="sunshine percentage" Factor = 0.1 else if (Suffix.EQ.".spn") then Variable="sunshine (percentage of normal)" Factor = 0.1 else if (Suffix.EQ.".ssh") then Variable="sunshine hours" Factor = 0.01 else if (Suffix.EQ.".stn") then Variable="stations" Factor = 1.0 else if (Suffix.EQ.".stp") then Variable="station pressure" Factor = 0.1 else if (Suffix.EQ.".tmp") then Variable="near-surface temperature (degrees Celsius)" Factor = 0.1 else if (Suffix.EQ.".tmk") then Variable="near-surface temperature (degrees Kelvin)" Factor = 0.1 else if (Suffix.EQ.".tmn") then Variable="near-surface temperature minimum (degrees Celsius)" Factor = 0.1 else if (Suffix.EQ.".tik") then Variable="near-surface temperature minimum (degrees Kelvin)" Factor = 0.1 else if (Suffix.EQ.".tmx") then Variable="near-surface temperature maximum (degrees Celsius)" Factor = 0.1 else if (Suffix.EQ.".twb") then Variable="wet-bulb temperature (degrees Celsius)" Factor = 0.1 else if (Suffix.EQ.".txk") then Variable="near-surface temperature maximum (degrees Kelvin)" Factor = 0.1 else if (Suffix.EQ.".tcl") then Variable="total cloud (fraction) from long-wave radiation" Factor = 0.0001 else if (Suffix.EQ.".tcs") then Variable="total cloud (fraction) from short-wave radiation" Factor = 0.0001 else if (Suffix.EQ.".vap") then Variable="vapour pressure (hPa)" Factor = 0.1 else if (Suffix.EQ.".wet") then Variable="wet day frequency (days)" Factor = 0.01 else if (Suffix.EQ.".wnd") then Variable="wind (m/s)" Factor = 0.1 else Variable = "" Factor = 0.0 end if end subroutine CheckVariSuffix !******************************************************************************* end module GRIMFiles