! opday.f90 ! f90 program written by Tim Mitchell on 29.01.01 ! last modified on 29.04.03 ! tool to operate on standard .day files ! pgf90 -o ./../obs/opday filenames.f90 annfiles.f90 synfiles.f90 dayfiles.f90 ! stangeneral.f90 sortmod.f90 gales.f90 basicfun.f90 ./../obs/opday.f90 program OpDay use FileNames use ANNFiles use SYNFiles use DAYFiles use StanGeneral use SortMod use Gales use BasicFun implicit none real, pointer, dimension (:,:,:,:) :: Data, FileFlow real, pointer, dimension (:,:,:) :: FileDaily real, pointer, dimension (:,:) :: AnnOutput real, pointer, dimension (:) :: ClassBounds integer, pointer, dimension (:,:,:) :: SeasonKey, FileLamb, FileAuto, FileJenk integer, pointer, dimension (:,:) :: MonthLengths, GaleThresh integer, pointer, dimension (:) :: YearAD, FileYearAD, BaseYearAD character (len=9), pointer, dimension (:) :: AnnColTitles real, parameter :: MissVal = -999.0 character (len=80), parameter :: Blank = "" real :: MissAccept real :: RealConstant, Speed, Force, ScreenVal real :: DataMiss, DataFrac, DataMin, DataMax real :: OpMiss, OpEn, OpFrac, OpThresh, OpDiff, OpTot, OpLen, OpBase, MaxLen, MissThresh integer :: ReadStatus, AllocStat, MenuChoice, NextFree integer :: ChosenCol, ChosenColA, ChosenColB, ChosenColF, ChosenColZ, ChosenOp integer :: StartYear, EndYear, FirstYear, YearN integer :: BlockYearN, BlockStartAD, BlockEndAD, BlockStartX, BlockEndX integer :: XYear, XMonth, XDay, XHeader, XFooter, XFileYear, XVari, XCol, XSevere, XClass, XBound integer :: XGrowSeas,XJulian integer :: HeaderN, FooterN, MonthN, DayN, VariN, StringLen, ColN, LoadColN, ClassN integer :: FileYear0,FileYear1,Year0,Year1,Day0,Day1,Month0,Month1,Julian0,Julian1 integer :: QComp, QIntFloat, QFileComp, QUpDown integer :: NonBlank, IntConstant, Overlap, VariCode, CurrentSeason integer :: BegYear,BegMon,BegDay,BaseADYear0,BaseADYear1,BaseYearN,BaseYear0,BaseYear1 integer :: PrevEndYear,PrevEndMonth,PrevEndDay,PrevEndJulian,GrowSeasEnd character (len=80) :: GivenFile, OrigFile, LineFormat, Waste character (len=1) :: IntFloat !******************************************************************************* ! main call Intro do print*, " > Main menu. Make your choice. (0=list)" do read (*,*,iostat=ReadStatus), MenuChoice if (ReadStatus.LE.0) exit end do if (MenuChoice.EQ.1) then print*, " > Are you sure? (1=no,2=yes)" do read (*,*,iostat=ReadStatus), MenuChoice if (ReadStatus.LE.0.AND.MenuChoice.GE.1.AND.MenuChoice.LE.2) exit end do if (MenuChoice.EQ.1) print*, " > No changes made." if (MenuChoice.EQ.2) call Intro else if (MenuChoice.EQ. 2) then call OperateAk else if (MenuChoice.EQ. 3) then call OperateAB else if (MenuChoice.EQ. 4) then print*, " > Not yet written." print* else if (MenuChoice.EQ. 5) then call AnomaliseA else if (MenuChoice.EQ. 6) then call GetPerExceed else if (MenuChoice.EQ. 7) then call ScreenExceed else if (MenuChoice.EQ.10) then call LoadFromDAY else if (MenuChoice.EQ.11) then call LoadFromSYN else if (MenuChoice.EQ.20) then call SaveToDAY else if (MenuChoice.EQ.21) then call SaveToSYN else if (MenuChoice.EQ.30) then call CheckMaster else if (MenuChoice.EQ.40) then call CalcFreqA else if (MenuChoice.EQ.41) then call CalcPerKay else if (MenuChoice.EQ.42) then call CalcGaleFreq else if (MenuChoice.EQ.43) then call SeasonaliseA else if (MenuChoice.EQ.44) then call SeasonaliseA else if (MenuChoice.EQ.45) then call GrowSeasA else if (MenuChoice.NE.99) then print*, " > 1. Reinitialise" print*, " > 2. Operate A.k" print*, " > 3. Operate A.B" print*, " > 4. Smooth A with Gaussian filter" print*, " > 5. Anomalise A relative to period" print*, " > 6. Record periods <> k" print*, " > 7. Screen out values <> k" print*, " > 10. Load data from .day" print*, " > 11. Load data from .syn" print*, " > 20. Save data to .day" print*, " > 21. Save data to .syn" print*, " > 30. Check main arrays" print*, " > 40. Classify A --> .ann" print*, " > 41. Longest per <> k --> .ann" print*, " > 42. Gale freq --> .ann" print*, " > 43. Sum season of A --> .ann" print*, " > 44. Av. season of A --> .ann" print*, " > 45. Growing season A --> .ann" print*, " > 99. Exit" end if if (MenuChoice.EQ.99) exit end do call Conclude contains !******************************************************************************* ! intro subroutine Intro open (99,file="./../../../scratch/log-opday.dat",status="replace",action="write") print* print*, " > ##### OperateDay.f90 ##### Tool for operating on .day files #####" print* print*, " > Enter the number of columns in the master array:" do read (*,*,iostat=ReadStatus), ColN if (ReadStatus.LE.0 .AND. ColN.GE.1) exit end do print*, " > Enter the start and end years AD of the master array:" do read (*,*,iostat=ReadStatus), StartYear, EndYear if (ReadStatus.LE.0 .AND. StartYear.LE.EndYear) exit end do YearN = EndYear - StartYear + 1 MonthN = 12 ; DayN = 31 ; VariN = 8 NextFree = 1 ; VariCode = MissVal ; MissAccept = 10.0 allocate ( Data (ColN, YearN, MonthN, DayN), & YearAD (YearN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: Intro: Allocation failure #####" Data = MissVal do XYear = 1, YearN YearAD (XYear) = StartYear + XYear - 1 end do print* end subroutine Intro !******************************************************************************* ! load from .day file subroutine LoadFromDAY call LoadDAY (Blank, VariCode, FileYearAD, FileDaily) call CommonVecPer (FileYearAD,YearAD,FileYear0,FileYear1,Year0,Year1) if (FileYear0.EQ.MissVal) then print*, " > The loaded file has no period in common with the master array." else print*, " > The common period is: ", FileYearAD(FileYear0), FileYearAD(FileYear1) end if do XFileYear = FileYear0, FileYear1 XYear = Year0 + XFileYear - FileYear0 do XMonth = 1, MonthN do XDay = 1, DayN Data(NextFree,XYear,XMonth,XDay) = FileDaily(XFileYear,XMonth,XDay) end do end do end do deallocate (FileYearAD, FileDaily, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadFromDAY: Deallocation failure #####" call StoreMoveOn print* end subroutine LoadFromDAY !******************************************************************************* ! load from .syn file subroutine LoadFromSYN call LoadSYN (Blank,FileYearAD,FileLamb,FileJenk,FileAuto,FileFlow) call CommonVecPer (FileYearAD,YearAD,FileYear0,FileYear1,Year0,Year1) if (FileYear0.EQ.MissVal) then print*, " > The loaded file has no period in common with the master array." else print*, " > The common period is: ", FileYearAD(FileYear0), FileYearAD(FileYear1) end if print*, " > Variables: Lamb,Jenk,Auto,PM-1000,W,S,F,D,ZW,ZS,S" print*, " > Enter the number of columns to include in array: " do read (*,*,iostat=ReadStatus), LoadColN if (ReadStatus.LE.0 .AND. LoadColN.GE.1 .AND. LoadColN.LE.11) exit end do do XCol = 1, LoadColN if (LoadColN.LT.11) then print "(a53,i4)", " > Select column (1-11) from file --> array column: ", NextFree do read (*,*,iostat=ReadStatus), ChosenCol if (ReadStatus.LE.0 .AND. ChosenCol.GE.1 .AND. ChosenCol.LE.11) exit end do else ChosenCol = XCol end if do XFileYear = FileYear0, FileYear1 XYear = Year0 + XFileYear - FileYear0 do XMonth = 1, MonthN do XDay = 1, DayN if (ChosenCol.EQ.1) Data(NextFree,XYear,XMonth,XDay) = real(FileLamb(XFileYear,XMonth,XDay)) if (ChosenCol.EQ.2) Data(NextFree,XYear,XMonth,XDay) = real(FileJenk(XFileYear,XMonth,XDay)) if (ChosenCol.EQ.3) Data(NextFree,XYear,XMonth,XDay) = real(FileAuto(XFileYear,XMonth,XDay)) if (ChosenCol.GE.4) Data(NextFree,XYear,XMonth,XDay) = FileFlow(XFileYear,XMonth,XDay,(ChosenCol-3)) end do end do end do call StoreMoveOn end do deallocate (FileYearAD,FileLamb,FileJenk,FileAuto,FileFlow, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadFromSYN: Deallocation failure #####" print* end subroutine LoadFromSYN !******************************************************************************* ! save to .syn file subroutine SaveToSYN allocate ( FileFlow (YearN, MonthN, DayN, 8), & FileLamb (YearN, MonthN, DayN), & FileJenk (YearN, MonthN, DayN), & FileAuto (YearN, MonthN, DayN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SaveToSYN: Allocation failure #####" FileFlow = MissVal FileLamb = -9 ; FileJenk = -9 ; FileAuto = -9 print*, " > Variables: Lamb,Jenk,Auto,PM-1000,W,S,F,D,ZW,ZS,S" do XVari = 1, 11 print "(a58,i4)", " > Select column to use (-9=missing) for variable: ", XVari ChosenCol = -1 do read (*,*,iostat=ReadStatus), ChosenCol if (ChosenCol.NE.-9) then if (ChosenCol.LT.1.OR.ChosenCol.GT.ColN) ChosenCol = -1 end if if (ReadStatus.LE.0 .AND. ChosenCol.NE.-1) exit end do if (ChosenCol.NE.-9) then do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, DayN if (XVari.EQ.1) FileLamb(XYear,XMonth,XDay) = nint(Data(ChosenCol,XYear,XMonth,XDay)) if (XVari.EQ.2) FileJenk(XYear,XMonth,XDay) = nint(Data(ChosenCol,XYear,XMonth,XDay)) if (XVari.EQ.3) FileAuto(XYear,XMonth,XDay) = nint(Data(ChosenCol,XYear,XMonth,XDay)) if (XVari.GE.4) FileFlow(XYear,XMonth,XDay,(XVari-3)) = Data(ChosenCol,XYear,XMonth,XDay) end do end do end do end if end do call SaveSYN (Blank,YearAD,FileLamb,FileJenk,FileAuto,FileFlow) deallocate (FileLamb,FileJenk,FileAuto,FileFlow, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SaveToSYN: Deallocation failure #####" print* end subroutine SaveToSYN !******************************************************************************* ! save to .day file subroutine SaveToDAY call SelectColumn allocate ( FileDaily (YearN, MonthN, DayN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SaveToDAY: Allocation failure #####" do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, DayN FileDaily(XYear,XMonth,XDay) = Data(ChosenCol,XYear,XMonth,XDay) end do end do end do call SaveDAY (Blank,VariCode,YearAD,FileDaily) print* end subroutine SaveToDAY !******************************************************************************* ! operate A . constant subroutine OperateAk print*, " > Select the op (A/k=1, A*k=2, A-k=3, A+k=4, sqrt(A)=5, A**k=6, A(abs)=7):" do read (*,*,iostat=ReadStatus), ChosenOp if (ReadStatus.LE.0 .AND. ChosenOp.GE.1 .AND. ChosenOp.LE.7) exit end do call SelectColumn if (ChosenOp.NE.7.AND.ChosenOp.NE.5) then print*, " > Select the real constant: " do read (*,*,iostat=ReadStatus), RealConstant if (ReadStatus.LE.0) exit end do end if do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, DayN Data(NextFree,XYear,XMonth,XDay) = OpAwithB (Data(ChosenCol,XYear,XMonth,XDay), & RealConstant,ChosenOp) end do end do end do call StoreMoveOn print* end subroutine OperateAk !******************************************************************************* ! operate A . B subroutine OperateAB print*, " > Select the operation (A/B=1, A*B=2, A-B=3, A+B=4, A**B=6: " do read (*,*,iostat=ReadStatus), ChosenOp if (ReadStatus.LE.0 .AND. ChosenOp.GE.1 .AND. ChosenOp.LE.6 .AND. ChosenOp.NE.5) exit end do print*, " > Select columns A and B in turn: " call SelectColumn ChosenColA = ChosenCol call SelectColumn ChosenColB = ChosenCol do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, DayN Data(NextFree,XYear,XMonth,XDay) = OpAwithB & (Data(ChosenColA,XYear,XMonth,XDay),Data(ChosenColB,XYear,XMonth,XDay),ChosenOp) end do end do end do call StoreMoveOn print* end subroutine OperateAB !******************************************************************************* ! anomalise A against period from within itself subroutine AnomaliseA call SelectColumn print*, " > Select first, last years AD as base period: " do read (*,*,iostat=ReadStatus), BaseADYear0,BaseADYear1 if (ReadStatus.LE.0.AND.BaseADYear0.GE.YearAD(1).AND.BaseADYear1.LE.YearAD(YearN) & .AND.BaseADYear1.GE.BaseADYear0) exit end do BaseYearN = BaseADYear1 - BaseADYear0 + 1 OpThresh = real(BaseYearN) * (100.0 - MissAccept) / 100.0 allocate ( BaseYearAD (BaseYearN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: AnomaliseA: Allocation failure #####" do XYear = 1, BaseYearN BaseYearAD (XYear) = BaseADYear0 + XYear - 1 end do call CommonVecPer (BaseYearAD,YearAD,BaseYear0,BaseYear1,Year0,Year1) ! identify common period print*, " > Period identified: ", BaseYearAD(BaseYear0), BaseYearAD(BaseYear1) do XMonth = 1, MonthN do XDay = 1, DayN OpEn = 0.0 OpTot = 0.0 do XYear = Year0, Year1 ! calc base if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) then OpEn = OpEn + 1 OpTot = OpTot + Data(ChosenCol,XYear,XMonth,XDay) end if end do if (OpEn.GT.OpThresh) then ! calc anomalies OpBase = OpTot / OpEn do XYear = 1, YearN if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) Data(NextFree,XYear,XMonth,XDay) = & Data(ChosenCol,XYear,XMonth,XDay) - OpBase end do else if (XMonth.EQ.2.AND.XDay.EQ.29.AND.OpBase.NE.MissVal) then ! 29th Feb anom v 28th Feb do XYear = 1, YearN if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) Data(NextFree,XYear,XMonth,XDay) = & Data(ChosenCol,XYear,XMonth,XDay) - OpBase end do else OpBase = MissVal end if end do end do deallocate ( BaseYearAD, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: AnomaliseA: Deallocation failure #####" call StoreMoveOn print* end subroutine AnomaliseA !******************************************************************************* ! locate periods where value exceeds constant subroutine GetPerExceed call SelectColumn call GetMonthLengths (YearAD,MonthLengths) print*, " > Enter the threshold: " do read (*,*,iostat=ReadStatus), OpThresh if (ReadStatus.LE.0) exit end do print*, " > Find periods when threshold is (=1) or is not (=-1) exceeded: " do read (*,*,iostat=ReadStatus), QUpDown if (ReadStatus.LE.0.AND.QUpDown.LE.1.AND.QUpDown.GE.-1) exit end do OpEn = 0 ; BegDay = 0 ; BegMon = 0 ; BegYear = 0 do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, MonthLengths(XYear,XMonth) if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) then Data(NextFree,XYear,XMonth,XDay) = 0 OpDiff = Data(ChosenCol,XYear,XMonth,XDay) - OpThresh if ((OpDiff*QUpDown).GE.0) then OpEn = OpEn + 1 if (OpEn.EQ.1) then BegDay = XDay ; BegMon = XMonth ; BegYear = XYear end if Data (NextFree,BegYear,BegMon,BegDay) = OpEn else OpEn = 0 ; BegDay = 0 ; BegMon = 0 ; BegYear = 0 end if else OpEn = 0 ; BegDay = 0 ; BegMon = 0 ; BegYear = 0 end if end do end do end do print*, " > We record the length of a period of exceedance on the initial day." print*, " > All other non-missing days are set to zero." call StoreMoveOn print* end subroutine GetPerExceed !******************************************************************************* ! screen out all values <> specified constant subroutine ScreenExceed call SelectColumn call GetMonthLengths (YearAD,MonthLengths) print*, " > Screen out when threshold is (=1) or is not (=-1) exceeded: " do read (*,*,iostat=ReadStatus), QUpDown if (ReadStatus.LE.0.AND.QUpDown.LE.1.AND.QUpDown.GE.-1) exit end do print*, " > Enter the threshold: " do read (*,*,iostat=ReadStatus), OpThresh if (ReadStatus.LE.0) exit end do print*, " > Enter the value to place in screened cells: " do read (*,*,iostat=ReadStatus), ScreenVal if (ReadStatus.LE.0) exit end do do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, MonthLengths(XYear,XMonth) if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) then if (QUpDown.EQ.-1.AND.Data(ChosenCol,XYear,XMonth,XDay).LT.OpThresh) then Data(NextFree,XYear,XMonth,XDay) = ScreenVal else if (QUpDown.EQ. 1.AND.Data(ChosenCol,XYear,XMonth,XDay).GT.OpThresh) then Data(NextFree,XYear,XMonth,XDay) = ScreenVal else Data(NextFree,XYear,XMonth,XDay) = Data(ChosenCol,XYear,XMonth,XDay) end if end if end do end do end do call StoreMoveOn print* end subroutine ScreenExceed !******************************************************************************* ! calculate frequency of value in specified season subroutine CalcFreqA call SelectColumn call MakeSeasonKey (YearAD,SeasonKey) print*, " > Enter the number of classes: " do read (*,*,iostat=ReadStatus), ClassN if (ClassN.LT.2) print*, " > Number of classes must exceed one. Try again." if (ReadStatus.LE.0 .AND. ClassN.GE.2) exit end do allocate (ClassBounds (ClassN-1), & AnnOutput (YearN, (ClassN+1)), & AnnColTitles (ClassN+1), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcFreqA: Allocation failure #####" AnnOutput = 0 ; AnnColTitles = ' X' ; ClassBounds = MissVal AnnColTitles(ClassN+1)=' MISSING' ; AnnColTitles(1)=' LOWEST' ; AnnColTitles(ClassN)=' HIGHEST' print*, " > Enter the bounds between the classes, in ascending order: " do XBound = 1, (ClassN-1) do read (*,*,iostat=ReadStatus), ClassBounds(XBound) if (ReadStatus.GT.0) print*, " > Not a real. Re-enter." if (XBound.GT.1.AND.ClassBounds(XBound).LE.ClassBounds(XBound-1)) then print*, " > Too low. Re-enter." ClassBounds(XBound) = MissVal end if if (ReadStatus.LE.0 .AND. ClassBounds(XBound).NE.MissVal) exit end do end do do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, DayN if (SeasonKey(XYear,XMonth,XDay).NE.MissVal) then if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) then XBound = 0 do XBound = XBound + 1 if (Data(ChosenCol,XYear,XMonth,XDay).LT.ClassBounds(XBound)) & AnnOutput(SeasonKey(XYear,XMonth,XDay),XBound) = & AnnOutput(SeasonKey(XYear,XMonth,XDay),XBound) + 1 if (Data(ChosenCol,XYear,XMonth,XDay).LT.ClassBounds(XBound)) exit if (XBound.EQ.(ClassN-1)) exit end do if (Data(ChosenCol,XYear,XMonth,XDay).GE.ClassBounds(ClassN-1)) & AnnOutput(SeasonKey(XYear,XMonth,XDay),ClassN) = & AnnOutput(SeasonKey(XYear,XMonth,XDay),ClassN) + 1 else AnnOutput(SeasonKey(XYear,XMonth,XDay),(ClassN+1)) = & AnnOutput(SeasonKey(XYear,XMonth,XDay),(ClassN+1)) + 1 end if end if end do end do end do do XYear = 1, YearN OpEn = 0 do XClass = 1, ClassN OpEn = OpEn + AnnOutput (XYear,XClass) end do MissThresh = (MissAccept / 100.0) * OpEn if (AnnOutput(XYear,(ClassN+1)).GE.MissThresh) then do XClass = 1, ClassN AnnOutput (XYear,XClass) = MissVal end do end if end do call MakeANNColTitles (AnnColTitles) call SaveANN (Blank, YearAD, AnnColTitles, AnnOutput) print* deallocate (AnnOutput,AnnColTitles,ClassBounds,SeasonKey, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcFreqA: Deallocation failure #####" end subroutine CalcFreqA !******************************************************************************* ! calculate length of longest period that satisfies the following requirements: ! begin with first period where meanT>5degK for 5 consecutive days ! end with first subsequent period when meanT<5degK for 5 consecutive days subroutine GrowSeasA call SelectColumn call GetMonthLengths (YearAD,MonthLengths) allocate (AnnOutput (YearN,5), & AnnColTitles (5), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: GrowSeasA: Allocation failure #####" AnnOutput = 0 AnnColTitles(1) = ' LENGTH' ; AnnColTitles(2) = ' JULIAN' ; AnnColTitles(3) = ' BLANK' AnnColTitles(4) = ' JULI-BEG' ; AnnColTitles(5) = ' JULI-END' print*, " > Enter the temperature threshold (e.g. 5.0 degC): " do read (*,*,iostat=ReadStatus), OpThresh if (ReadStatus.LE.0) exit end do print*, " > Enter the length threshold (e.g. 5 days): " do read (*,*,iostat=ReadStatus), OpLen if (ReadStatus.LE.0) exit end do do XYear = 1, YearN if (MonthLengths(XYear,2).EQ.28) then AnnOutput (XYear,2) = 365 else AnnOutput (XYear,2) = 366 end if end do OpEn = 0.0 ; OpTot = 0.0 ! current mini-per length, current grow-seas length PrevEndYear = 1 ; PrevEndMonth = 1 ; PrevEndDay = 1 ! the lastday of last growing season PrevEndJulian = 1 ! the last Julian day of last growing season do XGrowSeas = 1, YearN GrowSeasEnd = 0 ! =1 when end of grow seas is found XYear=PrevEndYear ; XMonth=PrevEndMonth ; XDay=PrevEndDay ! start at end of last growseas XJulian=PrevEndJulian do ! year loop do ! month loop do ! day loop if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) then if (OpTot.EQ.0) then ! no grow-seas at present if (Data(ChosenCol,XYear,XMonth,XDay).GT.OpThresh) then ! potential mini-per OpEn = OpEn + 1 if (OpEn.EQ.OpLen) then ! this = potential grow-seas OpTot = OpLen ; OpEn = 0 end if else ! no mini-per at present OpEn = 0 end if else ! potential grow-seas in progress OpTot = OpTot + 1 ! len of potential grow-seas if (Data(ChosenCol,XYear,XMonth,XDay).LT.OpThresh) then ! potential mini-per OpEn = OpEn + 1 if (OpEn.EQ.OpLen) then ! this = end of potential g-s if (OpTot.GT.AnnOutput(XGrowSeas,1)) then ! this = growing season AnnOutput(XGrowSeas,1) = OpTot - OpLen AnnOutput(XGrowSeas,4) = XJulian + ((XYear-XGrowSeas)*AnnOutput(XGrowSeas,2)) - OpTot + 1 AnnOutput(XGrowSeas,5) = XJulian + ((XYear-XGrowSeas)*AnnOutput(XGrowSeas,2)) - OpLen PrevEndYear=XYear ; PrevEndMonth=XMonth ; PrevEndDay=XDay ; PrevEndJulian=XJulian end if if (XYear.GT.XGrowSeas) GrowSeasEnd = 1 ! if end + nextyr -> exit OpTot = 0 ; OpEn = 0 ! reset mini-per,potential g-s end if else ! no mini-per at present OpEn = 0 end if end if end if XDay = XDay + 1 ; XJulian = XJulian + 1 if (XDay.GT.MonthLengths(XYear,XMonth)) XDay = 1 ! end of month is reached if (XDay.EQ.1) exit if (GrowSeasEnd.EQ.1) exit end do XMonth = XMonth + 1 if (XMonth.GT.12) XMonth = 1 ! end of year is reached if (XMonth.EQ.1) exit if (GrowSeasEnd.EQ.1) exit end do if (XYear.EQ.XGrowSeas) then ! current year = year of growing seas if (OpTot.EQ.0) GrowSeasEnd = 1 ! not current grow seas -> exit end if XYear = XYear + 1 XJulian = 1 ! resets Julian day if (XYear.GT.YearN.AND.OpTot.GT.0) then ! if end-of-file prior to end of g-s if (OpTot.GT.AnnOutput(XGrowSeas,1)) then ! if this was gonna be g-s AnnOutput(XGrowSeas,1) = MissVal AnnOutput(XGrowSeas,4) = MissVal AnnOutput(XGrowSeas,5) = MissVal end if end if if (XYear.GT.YearN) exit ! end of data file is reached if (GrowSeasEnd.EQ.1) exit end do end do call SaveANN (Blank, YearAD, AnnColTitles, AnnOutput) print* deallocate (AnnOutput,AnnColTitles,MonthLengths, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: GrowSeasA: Deallocation failure #####" end subroutine GrowSeasA !******************************************************************************* ! calculate longest period in days in specified season when value exceeds/stays-below Kay subroutine CalcPerKay call SelectColumn call MakeSeasonKey (YearAD,SeasonKey) allocate (AnnOutput (YearN,5), & AnnColTitles (5), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcPerKay: Allocation failure #####" AnnOutput = 0 AnnColTitles(1) = ' MAX LEN' ; AnnColTitles(2) = ' PERIOD' ; AnnColTitles(3) = ' MISSING' AnnColTitles(4) = 'DAY0(SEA)' ; AnnColTitles(5) = 'DAY1(SEA)' print*, " > Enter the threshold: " do read (*,*,iostat=ReadStatus), OpThresh if (ReadStatus.LE.0) exit end do print*, " > Find longest period when threshold is (=1) or is not (=2) exceeded: " do read (*,*,iostat=ReadStatus), QUpDown if (ReadStatus.LE.0.AND.QUpDown.GE.1.AND.QUpDown.LE.2) exit end do CurrentSeason = 1 ; OpEn = 0 do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, DayN if (SeasonKey(XYear,XMonth,XDay).GT.CurrentSeason.AND.SeasonKey(XYear,XMonth,XDay).NE.MissVal) then OpEn = 0 CurrentSeason = SeasonKey(XYear,XMonth,XDay) end if if (SeasonKey(XYear,XMonth,XDay).EQ.CurrentSeason) then AnnOutput (CurrentSeason,2) = AnnOutput (CurrentSeason,2) + 1.0 if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) then if (QUpDown.EQ.1.AND.Data(ChosenCol,XYear,XMonth,XDay).GE.OpThresh) then OpEn = OpEn + 1 else if (QUpDown.EQ.2.AND.Data(ChosenCol,XYear,XMonth,XDay).LE.OpThresh) then OpEn = OpEn + 1 else OpEn = 0 end if else AnnOutput (CurrentSeason,3) = AnnOutput (CurrentSeason,3) + 1.0 end if end if if (OpEn.GT.AnnOutput(CurrentSeason,1)) then AnnOutput (CurrentSeason,1) = OpEn AnnOutput (CurrentSeason,4) = AnnOutput (CurrentSeason,2) - OpEn + 1 AnnOutput (CurrentSeason,5) = AnnOutput (CurrentSeason,2) end if end do end do end do do XYear = 1, YearN MissThresh = (MissAccept / 100.0) * AnnOutput(XYear,2) if (AnnOutput(XYear,3).GT.MissThresh) AnnOutput (CurrentSeason,1) = MissVal end do call SaveANN (Blank, YearAD, AnnColTitles, AnnOutput) print* deallocate (AnnOutput,AnnColTitles,SeasonKey, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcPerKay: Deallocation failure #####" end subroutine CalcPerKay !******************************************************************************* ! calculate gale frequencies for specified season subroutine CalcGaleFreq print*, " > To measure gales we require columns with variables F, Z." call SelectColumn ChosenColF = ChosenCol call SelectColumn ChosenColZ = ChosenCol call GetGaleThresh (YearAD,GaleThresh) call MakeSeasonKey (YearAD,SeasonKey) allocate (AnnOutput (YearN, 5), & AnnColTitles (5), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcGaleFreq: Allocation failure #####" AnnOutput = 0 AnnColTitles(1)=' GALE' ; AnnColTitles(2)=' SEVERE' ; AnnColTitles(3)=' V SEVERE' AnnColTitles(4)=' LENGTH' ; AnnColTitles(5)=' MISSING' do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, DayN if (SeasonKey(XYear,XMonth,XDay).NE.MissVal) then AnnOutput(SeasonKey(XYear,XMonth,XDay),4) = AnnOutput(SeasonKey(XYear,XMonth,XDay),4) + 1 Speed = GaleIndex (Data(ChosenColF,XYear,XMonth,XDay),Data(ChosenColZ,XYear,XMonth,XDay)) Force = GaleScore (Speed,GaleThresh(XYear,1),GaleThresh(XYear,2),GaleThresh(XYear,3)) if (Force.NE.MissVal) then do XSevere = 1, 3 if (Force.GE.XSevere) AnnOutput(SeasonKey(XYear,XMonth,XDay),XSevere) = & AnnOutput(SeasonKey(XYear,XMonth,XDay),XSevere) + 1 end do else AnnOutput(SeasonKey(XYear,XMonth,XDay),5) = AnnOutput(SeasonKey(XYear,XMonth,XDay),5) + 1 end if end if end do end do end do do XYear = 1, YearN MissThresh = (MissAccept / 100.0) * AnnOutput(XYear,4) if (AnnOutput(XYear,5).GE.MissThresh) then AnnOutput (XYear,1) = MissVal AnnOutput (XYear,2) = MissVal AnnOutput (XYear,3) = MissVal end if end do call SaveANN (Blank, YearAD, AnnColTitles, AnnOutput) print* deallocate (AnnOutput,AnnColTitles,GaleThresh,SeasonKey, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcGaleFreq: Deallocation failure #####" end subroutine CalcGaleFreq !******************************************************************************* ! calculate the sum (=43) or average (=44) of values in specified season subroutine SeasonaliseA if (MenuChoice.NE.43.AND.MenuChoice.NE.44) print*, " > ##### ERROR: SeasonaliseA: Menu-subroutine mismatch" call SelectColumn call MakeSeasonKey (YearAD,SeasonKey) allocate (AnnOutput (YearN, 3), & AnnColTitles (3), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SeasonaliseA: Allocation failure #####" AnnOutput = 0 if (MenuChoice.EQ.43) AnnColTitles (1) = ' seas-sum' if (MenuChoice.EQ.44) AnnColTitles (1) = ' seas-av' AnnColTitles (2) = ' length' ; AnnColTitles (3) = ' missing' do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, DayN if (SeasonKey(XYear,XMonth,XDay).NE.MissVal) then AnnOutput(SeasonKey(XYear,XMonth,XDay),2) = AnnOutput(SeasonKey(XYear,XMonth,XDay),2) + 1 if (Data(ChosenCol,XYear,XMonth,XDay).NE.MissVal) then AnnOutput(SeasonKey(XYear,XMonth,XDay),1) = AnnOutput(SeasonKey(XYear,XMonth,XDay),1) + & Data(ChosenCol,XYear,XMonth,XDay) else AnnOutput(SeasonKey(XYear,XMonth,XDay),3) = AnnOutput(SeasonKey(XYear,XMonth,XDay),3) + 1 end if end if end do end do end do do XYear = 1, YearN MissThresh = (MissAccept / 100.0) * AnnOutput(XYear,2) if (AnnOutput(XYear,3).GE.MissThresh) then AnnOutput (XYear,1) = MissVal else if (MenuChoice.EQ.44) then AnnOutput (XYear,1) = AnnOutput (XYear,1) / (AnnOutput (XYear,2) - AnnOutput (XYear,3)) end if end do call MakeANNColTitles (AnnColTitles) call SaveANN (Blank, YearAD, AnnColTitles, AnnOutput) print* deallocate (AnnOutput,AnnColTitles,SeasonKey, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SeasonaliseA: Deallocation failure #####" end subroutine SeasonaliseA !******************************************************************************* ! check master array subroutine CheckMaster call GetMonthLengths (YearAD,MonthLengths) OpEn = 0.0 do XYear = 1, YearN do XMonth = 1, MonthN OpEn = OpEn + MonthLengths(XYear,XMonth) end do end do print "(a38,f10.2)", " > Number of days in main array: ", OpEn print "(a17)", " > COL MISS% MIN MAX" do XCol = 1, ColN DataMiss = 0.0 DataMin = 100000.0 DataMax = -100000.0 do XYear = 1, YearN do XMonth = 1, MonthN do XDay = 1, MonthLengths(XYear,XMonth) if (Data (XCol,XYear,XMonth,XDay).EQ.MissVal) DataMiss = DataMiss + 1.0 if (Data (XCol,XYear,XMonth,XDay).LT.DataMin) DataMin = Data (XCol,XYear,XMonth,XDay) if (Data (XCol,XYear,XMonth,XDay).GT.DataMax) DataMax = Data (XCol,XYear,XMonth,XDay) end do end do end do DataFrac = 100.0 * DataMiss / OpEn print "(i9,3f8.2)", XCol, DataFrac, DataMin, DataMax end do print* deallocate (MonthLengths,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CheckMaster: Deallocation failure #####" end subroutine CheckMaster !******************************************************************************* ! select column subroutine SelectColumn print*, " > Select the column: " do read (*,*,iostat=ReadStatus), ChosenCol if (ReadStatus.LE.0 .AND. ChosenCol.GE.1 .AND. ChosenCol.LE.ColN) exit end do end subroutine SelectColumn !******************************************************************************* ! store data in column and move on subroutine StoreMoveOn call CheckBlank if (NonBlank.EQ.0) then print*, " > Operation has no valid results. No results stored." else print*, " > Results stored in column: ", NextFree NextFree = NextFree + 1 if (NextFree.GT.ColN) then NextFree = NextFree - 1 print*, " > All columns are being used. Next free set to: ", NextFree end if end if end subroutine StoreMoveOn !******************************************************************************* ! check whether column is (=0) or is not (=1) blank subroutine CheckBlank NonBlank = 0 XYear = 0 do XYear = XYear + 1 XMonth = 0 do XMonth = XMonth + 1 XDay = 0 do XDay = XDay + 1 if (Data(NextFree,XYear,XMonth,XDay).NE.MissVal) NonBlank = 1 if (NonBlank.EQ.1) exit if (XDay.EQ.DayN) exit end do if (NonBlank.EQ.1) exit if (XMonth.EQ.MonthN) exit end do if (NonBlank.EQ.1) exit if (XYear.EQ.YearN) exit end do end subroutine CheckBlank !******************************************************************************* ! conclude subroutine Conclude deallocate (YearAD,Data,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: Conclude: Deallocation failure #####" close (99) print* end subroutine Conclude !******************************************************************************* end program OpDay