! stangeneral.f90 ! module in which various routines with general applicability are held ! contains: MakeSeasonKey, GetMonthLengths, CommonVecPer module StanGeneral implicit none contains !******************************************************************************* subroutine MakeSeasonKey (YearAD,SeasonKey) integer, pointer, dimension (:,:,:) :: SeasonKey integer, pointer, dimension (:,:) :: MonthLengths integer, pointer, dimension (:) :: YearAD real, parameter :: MissVal = -999.0 integer :: XYear, XMonth, XDay integer :: Day0, Day1, Month0, Month1, DayBeg, DayEnd integer :: YearN, MonthN, DayN integer :: AllocStat, ReadStatus integer :: Overlap !*************************************** call GetMonthLengths (YearAD,MonthLengths) DayN = 31 ; MonthN = 12 Day0 = 0 ; Month0 = 0 print*, " > Enter the first day, month of the season: " do read (*,*,iostat=ReadStatus), Day0, Month0 if (ReadStatus.GT.0) print*, " > Not integers. Try again." if (Month0.LT.1.OR.Month0.GT.MonthN) then print*, " > Month out of range. Try again." Month0 = 0 end if if (Day0.LT.1.OR.Day0.GT.DayN) then print*, " > Day out of range. Try again." Day0 = 0 end if if (ReadStatus.LE.0.AND.Day0.NE.0.AND.Month0.NE.0) exit end do Day1 = 0 ; Month1 = 0 print*, " > Enter the last day, month of the season (overlaps OK): " do read (*,*,iostat=ReadStatus), Day1, Month1 if (ReadStatus.GT.0) print*, " > Not integers. Try again." if (Month1.LT.1.OR.Month1.GT.MonthN) then print*, " > Month out of range. Try again." Month1 = 0 end if if (Day1.LT.1.OR.Day1.GT.DayN) then print*, " > Day out of range. Try again." Day1 = 0 end if if (ReadStatus.LE.0.AND.Day1.NE.0.AND.Month1.NE.0) exit end do Overlap = 0 if (Month1.LT.Month0) then Overlap = 1 else if (Month1.EQ.Month0) then if (Day1.LT.Day0) Overlap = 1 end if YearN = size (YearAD) allocate (SeasonKey(YearN,MonthN,DayN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SeasonKey: Allocation failure #####" SeasonKey = MissVal if (Overlap.EQ.0) then ! no overlap do XYear = 1, YearN do XMonth = Month0, Month1 DayBeg = 1 ; DayEnd = DayN if (XMonth.EQ.Month0) DayBeg = Day0 if (XMonth.EQ.Month1) DayEnd = Day1 do XDay = DayBeg, DayEnd if (MonthLengths(XYear,XMonth).GE.XDay) SeasonKey(XYear,XMonth,XDay) = XYear end do end do end do end if if (Overlap.EQ.1) then ! overlap do XYear = 1, (YearN-1) do XMonth = Month0, MonthN DayBeg = 1 ; DayEnd = DayN if (XMonth.EQ.Month0) DayBeg = Day0 do XDay = DayBeg, DayEnd if (MonthLengths(XYear,XMonth).GE.XDay) SeasonKey(XYear,XMonth,XDay) = XYear end do end do do XMonth = 1, Month1 DayBeg = 1 ; DayEnd = DayN if (XMonth.EQ.Month1) DayEnd = Day1 do XDay = DayBeg, DayEnd if (MonthLengths((XYear+1),XMonth).GE.XDay) SeasonKey((XYear+1),XMonth,XDay) = XYear end do end do end do end if deallocate (MonthLengths, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SeasonKey: Deallocation failure #####" end subroutine MakeSeasonKey !******************************************************************************* ! get month lengths appropriate to years AD subroutine GetMonthLengths (YearAD,MonthLengths) integer, pointer, dimension (:,:) :: MonthLengths integer, pointer, dimension (:) :: YearAD real :: Rem004,Rem100,Rem400 integer :: XYear, XMonth, YearN, AllocStat YearN = size (YearAD) allocate ( MonthLengths(YearN,12), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: GetMonthLengths: Allocation failure #####" MonthLengths = 31 do XYear = 1, YearN MonthLengths(XYear,4 ) = 30 MonthLengths(XYear,6 ) = 30 MonthLengths(XYear,9 ) = 30 MonthLengths(XYear,11) = 30 Rem004 = mod (YearAD(XYear), 4) Rem100 = mod (YearAD(XYear),100) Rem400 = mod (YearAD(XYear),400) if (Rem004.EQ.0) then if (Rem100.EQ.0) then if (Rem400.EQ.0) then MonthLengths(XYear,2) = 29 else MonthLengths(XYear,2) = 28 end if else MonthLengths(XYear,2) = 29 end if else MonthLengths(XYear,2) = 28 end if end do end subroutine GetMonthLengths !******************************************************************************* ! compare year vectors to find common period subroutine CommonVecPer (AYears,BYears,AStart,AEnd,BStart,BEnd) integer, pointer, dimension (:) :: AYears, BYears integer, intent (out) :: AStart,BStart,AEnd,BEnd integer :: AYearN,BYearN,ARest,BRest integer :: Offset,CommonLen real, parameter :: MissVal = -999.0 AYearN = size (AYears) BYearN = size (BYears) Offset = BYears(1) - AYears(1) + 1 if (Offset.GE.1) then AStart = Offset BStart = 1 else AStart = 1 BStart = 2 - Offset end if ARest = AYearN - AStart BRest = BYearN - BStart if (ARest.GE.0.AND.BRest.GE.0) then if (ARest.LT.BRest) then CommonLen = ARest + 1 else CommonLen = BRest + 1 end if AEnd = AStart + CommonLen - 1 BEnd = BStart + CommonLen - 1 else AStart=MissVal BStart=MissVal AEnd=MissVal BEnd=MissVal end if end subroutine CommonVecPer !******************************************************************************* end module StanGeneral