! samplingerror2.f90 ! f90 main program written on 16.02.99 by Tim Mitchell ! last modification on 17.07.00 ! f90 -o samplingerror2 initialmod.f90 runselectmod.f90 extractmod.f90 scalemod.f90 savemod.f90 loadmod.f90 ! transformmod.f90 sortmod.f90 basicfun.f90 samplingerror2.f90 program SamplingError2 use InitialMod use RunSelectMod use ExtractMod use ScaleMod use SaveMod use LoadMod use TransformMod use SortMod use BasicFun implicit none !******************************************************************************* real, pointer, dimension (:) :: WorkGloAnaSlice, AllRMSE, PerGlo, ValidGlo real, pointer, dimension (:) :: AllAye, AllBee, OpOut, LowerBound, UpperBound, Weights real, pointer, dimension (:,:) :: WorkGotDecade, WorkGotFull, OpProc real, pointer, dimension (:,:) :: MyYear, MyAnom integer, pointer, dimension (:) :: WorkADYear, WorkMapRawReg, WorkRegSizes integer, pointer, dimension (:) :: WorkDecYearN, WorkDecGetYear0, WorkDecGetYear1 integer, pointer, dimension (:) :: WorkDecStyleThis, WorkDecStyleNext integer, pointer, dimension (:,:) :: WorkMapIDLRaw, WorkMapIDLReg integer, pointer, dimension (:,:) :: WorkDecBlockKey character (len=20), pointer, dimension (:) :: WorkRegNames character (len=80), pointer, dimension (:) :: WorkDecPathThis, WorkDecPathNext real, allocatable, dimension (:,:) :: WorkBasePerMeans, WorkAnomPerMeans integer, allocatable, dimension (:) :: BaseSelect, PertSelect, UsePer integer, dimension (1) :: Seed real, parameter :: MissVal = -999.0 real :: MissAccept, TotalValid, PerCentValid real :: PerTot, PerEn, PerSqTot, RegTot, RegEn, RegSqTot real :: PertThreshold, BaseThreshold, RMSEThreshold, RegThresh, PerThresh, YearThresh, RegPerThresh real :: MemThresh, TrialThresh real :: EnRMSE, TotRMSE real :: MyAye, MyBee, MyPea real :: ValidSqSum, RegSignal real :: NoiseJFB, NoiseJFBPop real :: RandomReal, CalcReal, SigLevel integer :: WorkMonth0,WorkMonth1,WorkMonthN,WorkYearN,WorkDecN integer :: WorkGrid,WorkLongN,WorkLatN,WorkDataN,WorkRegN integer :: AllocStat, ReadStatus integer :: XDec, XReg, XYear, XMonth, XPer, XLong, XTrial, XMem integer :: Year0, Year1, WorkPerN integer :: QAnother, QOrigBase, QAnomType, QGetTrend, QSaveLSR, QSampPop, QGetWeights integer :: PerLen, GapLen, PerYear0, PerYear1, OrigLen, OrigBaseLen, PerYear, ThisPer integer :: ValidReg, ValidYear, ValidCheck integer :: ThreshExceeded integer :: PerValid, RegValid, RegPerValid integer :: WorkTrialN, RandomMem, CalcInt, TailN, RegMiss, TotMiss integer :: EnsPerN, EnsPerYearN, EnsMemN character (len=10) :: WorkGridTitle character (len=40) :: WorkRegTitle character (len=80) :: WorkGridFilePath, WorkDecTitle, SaveTitle !******************************************************************************* ! main loop MissAccept = 10.0 call Preliminaries call GrabRun open (99,file="/cru/u2/f709762/data/scratch/log-samerr.txt",status="replace",action="write") do print*, " > 0. Change % acceptable missing (currently: ", MissAccept print*, " > 1. Detrend the raw" print*, " > 2. Calc sd of anomaly means" print*, " > 3. Calc pattern noise following JFB" print*, " > 4. Calc sd of sd (interdec?)" print*, " > 5. Calc interann var for ens of 30y slices: save mean+sd of set" print*, " > 10. Check validity of file data and output into .glo" print*, " > 99. Exit" do read (*,*,iostat=ReadStatus), QAnother if (ReadStatus.LE.0 .AND. QAnother.GE.0 .AND. QAnother.LE.99) exit end do if (QAnother.EQ.0) then call SetMissAccept (MissAccept) else if (QAnother.EQ.1) then call DeTrendWork else if (QAnother.EQ.2) then call ControlOne else if (QAnother.EQ.3) then call ControlOne else if (QAnother.EQ.4) then call ControlOne else if (QAnother.EQ.5) then call InterAnnVar else if (QAnother.EQ.10) then call CheckValid end if if (QAnother.EQ.99) exit end do print* deallocate (WorkGotFull) deallocate (WorkMapIDLRaw,WorkMapRawReg,WorkMapIDLReg,WorkRegSizes,WorkRegNames) deallocate (PertSelect,BaseSelect) close (99) contains !******************************************************************************* ! check validity of basic data array subroutine CheckValid allocate ( ValidGlo (WorkRegN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CheckValid: Allocation failure #####" ValidGlo = MissVal YearThresh = WorkYearN * (100.0 - MissAccept) / 100.0 ValidReg = 0 ValidCheck = 0 do XReg = 1, WorkRegN ! check contents of main data array ValidYear = 0 ValidSqSum = 0.0 do XYear = 1, WorkYearN if (WorkGotFull(XReg,XYear).NE.MissVal) then ValidYear = ValidYear + 1 ValidSqSum = ValidSqSum + WorkGotFull(XReg,XYear) ** 2 end if end do ValidGlo (XReg) = ValidYear if (ValidYear .GE.YearThresh) then ValidReg = ValidReg + 1 if (ValidSqSum.EQ.0.0) then ValidCheck = ValidCheck + 1 write (99,"(a23,i6)"), "##### all zeros in reg: ", XReg end if end if write (99,"(2i6,e12.5)"), XReg, ValidYear, ValidSqSum end do if (ValidCheck.GE.1) then print*, " > ##### Suspect data: all zeros in regions, total: ", ValidCheck print*, " > ##### See logsamerr.txt for details #####" end if print*, " > We have valid regions totalling: ", ValidReg call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,ValidGlo,WorkMapIDLReg) end subroutine CheckValid !******************************************************************************* ! controls calculation of options 2 and 3 and 4 subroutine ControlOne print*, " > Calc for absolute (=1) or percentage (=2) anomalies ?" do read (*,*,iostat=ReadStatus), QAnomType if (ReadStatus.LE.0 .AND. QAnomType.GE.1 .AND. QAnomType.LE.2) exit end do if (WorkYearN.GT.240) then print*, " > Is the original base the 240y control (=1) or a perturbed period (=2) ?" do read (*,*,iostat=ReadStatus), QOrigBase if (ReadStatus.LE.0 .AND. QOrigBase.GE.1 .AND. QOrigBase.LE.2) exit end do else print*, " > We assume that the original base is a perturbed period." QOrigBase = 2 end if if (QOrigBase.EQ.1) then call Specification1 call IdentifyPer1 call CalcBaseMeans1 else if (QOrigBase.EQ.2) then call Specification2 call IdentifyPer2 call CalcBaseMeans2 end if call CalcAnomMeans if (QAnother.EQ.2) then call CalcStDev else if (QAnother.EQ.3) then call GetWeights call CalcPerGlo call CalcJFBGlo else if (QAnother.EQ.4) then call CalcStDevStDev end if deallocate (WorkAnomPerMeans) end subroutine ControlOne !******************************************************************************* ! loading prec preliminaries subroutine Preliminaries print* print*, " > ***** SamplingError *****" print*, " > Calculates sampling error from control data." print* call GridSelect (WorkGrid,WorkGridTitle,WorkLongN,WorkLatN,WorkDataN,WorkGridFilePath) call PeriodSelect (WorkYearN,WorkDecN,WorkADYear) call SeasonSelect (WorkMonth0,WorkMonth1,WorkMonthN) call RegSelect (WorkGrid,WorkLongN,WorkLatN,WorkDataN,WorkMapIDLReg,WorkRegSizes,WorkRegNames,& WorkRegTitle,WorkRegN) allocate ( WorkGotDecade (WorkRegN, 10), & WorkGotFull (WorkRegN, WorkYearN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: Allocation failure #####" allocate ( BaseSelect (WorkYearN), & PertSelect (WorkYearN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: Allocation failure #####" print*, " > Select the control run." call RunSelect (WorkGrid,WorkMonth0,WorkMonth1,WorkYearN,WorkDecN,WorkADYear,& WorkDecTitle,WorkDecStyleThis,WorkDecStyleNext,& WorkDecPathThis,WorkDecPathNext,WorkDecYearN,WorkDecGetYear0,WorkDecGetYear1) end subroutine Preliminaries !******************************************************************************* ! extract data into WorkGotFull subroutine GrabRun WorkGotFull = 0.0 print*, " > Operating on decade starting in: " do XDec = 1, WorkDecN Year0 = (XDec-1)*10 + 1 Year1 = Year0 + 9 WorkGotDecade = 0.0 print*, WorkADYear(Year0) call BlockKey (WorkDecYearN(XDec),WorkMonthN,WorkDecGetYear0(XDec),WorkDecGetYear1(XDec),& WorkMonth0,WorkMonth1,WorkDecPathThis(XDec),WorkDecPathNext(XDec),& WorkDecStyleThis(XDec),WorkDecStyleNext(XDec),WorkDecBlockKey) call ExtractFile (WorkLongN,WorkLatN,WorkDataN,WorkDecPathThis(XDec),WorkDecPathNext(XDec),& WorkDecStyleThis(XDec),WorkDecStyleNext(XDec),WorkRegN,WorkMonthN,& WorkDecYearN(XDec),WorkDecGetYear0(XDec),& WorkMapRawReg,WorkRegSizes,WorkDecBlockKey,WorkGotDecade) do XReg = 1, WorkRegN WorkGotFull (XReg,Year0:Year1) = WorkGotDecade (XReg,1:10) end do end do deallocate (WorkGotDecade,WorkDecYearN,WorkDecGetYear0,WorkDecGetYear1) deallocate (WorkDecPathThis,WorkDecPathNext,WorkDecStyleThis,WorkDecStyleNext,WorkDecBlockKey) if (WorkLongN.EQ.96.AND.WorkLatN.EQ.73.AND.WorkRegN.EQ.7008) then print*, " > Converting regperbox into rpb..." do XLong = 1, WorkLongN XReg = WorkMapIDLReg (XLong,1) WorkGotFull (XReg,1:WorkYearN) = MissVal XReg = WorkMapIDLReg (XLong,WorkLatN) WorkGotFull (XReg,1:WorkYearN) = MissVal end do end if end subroutine GrabRun !******************************************************************************* ! detrend raw data subroutine DeTrendWork call DeTrendTim (WorkRegN,WorkYearN,MissAccept,1,WorkADYear,WorkGotFull,AllAye,AllBee) print*, " > Save the values of 'a' and 'b' to .glo ? (1=no,2=yes)" do read (*,*,iostat=ReadStatus), QSaveLSR if (ReadStatus.LE.0 .AND. QSaveLSR.GE.1 .AND. QSaveLSR.LE.2) exit end do if (QSaveLSR.EQ.2) then do XReg = 1, WorkRegN if (AllAye(XReg).NE.MissVal) AllAye(XReg) = AllAye(XReg) * 100.0 end do print*, " > Save 'a' as 100*trend-per-yearAD: " call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,AllAye,WorkMapIDLReg) print*, " > Save 'b' (intercept): " call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,AllBee,WorkMapIDLReg) end if deallocate (AllAye,AllBee) end subroutine DeTrendWork !******************************************************************************* ! specify criteria for calc of sampling error subroutine Specification1 print*, " > Enter the period length for which to calc sampling error: " do read (*,*,iostat=ReadStatus), PerLen if (ReadStatus.LE.0 .AND. PerLen.GE.1) exit end do print*, " > Enter the gap length to leave between periods: " do read (*,*,iostat=ReadStatus), GapLen if (ReadStatus.LE.0 .AND. GapLen.GE.0) exit end do write (99,*), "specified criteria 1" end subroutine Specification1 !******************************************************************************* ! specify criteria for calc of sampling error subroutine Specification2 print*, " > Enter the length used (base+anom) of the original: " do read (*,*,iostat=ReadStatus), OrigLen if (ReadStatus.LE.0 .AND. OrigLen.GE.1) exit end do print*, " > Enter the length of the original base: " do read (*,*,iostat=ReadStatus), OrigBaseLen if (ReadStatus.LE.0 .AND. OrigBaseLen.GE.1 .AND. OrigBaseLen.LT.OrigLen) exit end do print*, " > Enter the first, last index yrs of the original to calc: (min,max poss: " print "(2i6)", (OrigBaseLen+1), OrigLen do read (*,*,iostat=ReadStatus), PerYear0, PerYear1 if (ReadStatus.LE.0 .AND. PerYear1.GE.PerYear0 .AND. & PerYear0.GE.(OrigBaseLen+1) .AND. PerYear1.LE.OrigLen) exit end do write (99,*), "specified criteria 2" end subroutine Specification2 !******************************************************************************* ! identify periods subroutine IdentifyPer1 BaseSelect = 0 PertSelect = 0 do XYear = 1, 240 BaseSelect(XYear) = 1 end do WorkPerN = floor ( (real(WorkYearN)-240.0) / (real(PerLen)+real(GapLen)) ) print*, " > Maximum periods available: ", WorkPerN do XPer = 1, WorkPerN Year0 = 241 + (XPer-1)*(PerLen+GapLen) do XYear = Year0, (Year0+PerLen-1) PertSelect (XYear) = XPer end do end do write (99,*), "identified periods 1" end subroutine IdentifyPer1 !******************************************************************************* ! identify periods subroutine IdentifyPer2 BaseSelect = 0 PertSelect = 0 WorkPerN = floor ( real(WorkYearN) / real(OrigLen) ) print*, " > Maximum periods available: ", WorkPerN do XPer = 1, WorkPerN Year0 = 1 + (XPer-1)*OrigLen do XYear = Year0, (Year0+OrigBaseLen-1) BaseSelect(XYear) = XPer end do Year0 = Year0 + PerYear0 - 1 Year1 = Year0 + PerYear1 - PerYear0 do XYear = Year0, Year1 PertSelect(XYear) = XPer end do end do write (99,*), "identified periods 2" end subroutine IdentifyPer2 !******************************************************************************* ! identify periods subroutine IdentifyPer3 PertSelect = 0 WorkPerN = floor ( real(WorkYearN) / (real(PerLen)+real(GapLen)) ) print*, " > Maximum periods available: ", WorkPerN do XPer = 1, WorkPerN Year0 = (XPer-1)*(PerLen+GapLen) do XYear = Year0, (Year0+PerLen-1) PertSelect (XYear) = XPer end do end do end subroutine IdentifyPer3 !******************************************************************************* ! calc base period means subroutine CalcBaseMeans1 allocate ( WorkBasePerMeans (WorkRegN,WorkPerN), & WorkAnomPerMeans (WorkRegN,WorkPerN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: Allocation failure #####" WorkBasePerMeans = MissVal WorkAnomPerMeans = MissVal TotalValid = 0.0 BaseThreshold = 240.0 *(100.0-MissAccept)/100.0 PertThreshold = PerLen*(100.0-MissAccept)/100.0 write (99,"(A16,F10.4)"), "base threshold: ", BaseThreshold write (99,"(A16,F10.4)"), "pert threshold: ", PertThreshold do XReg = 1, WorkRegN PerTot = 0.0 PerEn = 0.0 do XYear = 1, WorkYearN if (BaseSelect(XYear).EQ.1) then if (WorkGotFull(XReg,XYear).NE.MissVal) then PerTot = PerTot + WorkGotFull(XReg,XYear) PerEn = PerEn + 1.0 end if end if end do ! write (99,*), "Region, Total-in-base, Years-in-base" ! write (99,"(i6,2f10.4)"), XReg, PerTot, PerEn if (PerEn.GE.BaseThreshold.AND.PerTot.NE.0) then do XPer = 1, WorkPerN WorkBasePerMeans(XReg,XPer) = PerTot / PerEn TotalValid = TotalValid + 1.0 end do end if end do PerCentValid = 100.0 * TotalValid / real(WorkRegN*WorkPerN) print*, " > Percentage period-region bases valid: ", PerCentValid end subroutine CalcBaseMeans1 !******************************************************************************* ! calc base period means subroutine CalcBaseMeans2 allocate ( WorkBasePerMeans (WorkRegN,WorkPerN), & WorkAnomPerMeans (WorkRegN,WorkPerN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: Allocation failure #####" TotalValid = 0.0 WorkBasePerMeans = MissVal WorkAnomPerMeans = MissVal BaseThreshold = OrigBaseLen*(100.0-MissAccept)/100.0 PertThreshold = (PerYear1-PerYear0+1.0)*(100.0-MissAccept)/100.0 write (99,"(A16,F10.4)"), "base threshold: ", BaseThreshold write (99,"(A16,F10.4)"), "pert threshold: ", PertThreshold do XReg = 1, WorkRegN do XPer = 1, WorkPerN PerTot = 0.0 PerEn = 0.0 do XYear = 1, WorkYearN if (BaseSelect(XYear).EQ.XPer) then if (WorkGotFull(XReg,XYear).NE.MissVal) then PerTot = PerTot + WorkGotFull(XReg,XYear) PerEn = PerEn + 1.0 end if end if end do ! write (99,"(2i6,2f10.4)"), XReg, XPer, PerTot, PerEn if (PerEn.GE.BaseThreshold.AND.PerTot.NE.0) then WorkBasePerMeans(XReg,XPer) = PerTot / PerEn TotalValid = TotalValid + 1.0 end if end do end do PerCentValid = 100.0 * TotalValid / real(WorkRegN*WorkPerN) print*, " > Percentage period-region bases valid: ", PerCentValid end subroutine CalcBaseMeans2 !******************************************************************************* ! calc anom period means subroutine CalcAnomMeans TotalValid = 0.0 !write (99,*), "in groups of three lines to one region and period" do XReg = 1, WorkRegN do XPer = 1, WorkPerN if (WorkBasePerMeans(XReg,XPer).NE.MissVal) then ! calc anom v base PerTot = 0.0 PerEn = 0.0 ! write (99,"(2i6)"), XReg, XPer do XYear = 1, WorkYearN if (PertSelect(XYear).EQ.XPer) then if (WorkGotFull(XReg,XYear).NE.MissVal) then PerTot = PerTot + WorkGotFull(XReg,XYear) PerEn = PerEn + 1.0 end if end if end do ! write (99,"(2f10.4)"), PerTot, PerEn if (PerEn.GE.PertThreshold) then TotalValid = TotalValid + 1.0 if (QAnomType.EQ.1) then WorkAnomPerMeans(XReg,XPer) = (PerTot / PerEn) - WorkBasePerMeans(XReg,XPer) else if (QAnomType.EQ.2) then WorkAnomPerMeans(XReg,XPer) = 100.0 * ((PerTot / PerEn) - WorkBasePerMeans(XReg,XPer)) / & WorkBasePerMeans(XReg,XPer) end if end if ! write (99,"(2f10.4)"), WorkBasePerMeans(XReg,XPer), WorkAnomPerMeans(XReg,XPer) end if end do end do PerCentValid = 100.0 * TotalValid / real(WorkRegN*WorkPerN) print*, " > Percentage period-region anoms valid: ", PerCentValid deallocate (WorkBasePerMeans) end subroutine CalcAnomMeans !******************************************************************************* ! calc mean anom for globe for each period subroutine GetWeights print*, " > Load region weights from .glo file ? (1=no,2=yes)" do read (*,*,iostat=ReadStatus), QGetWeights if (ReadStatus.LE.0.AND.QGetWeights.GE.1.AND.QGetWeights.LE.2) exit end do if (QGetWeights.EQ.1) then allocate ( Weights (WorkRegN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcPerGlo: Allocation failure #####" Weights = 1.0 else call LoadGlo (WorkLongN, WorkLatN, WorkRegN, WorkMapIDLReg, Weights) end if end subroutine GetWeights !******************************************************************************* ! calc mean anom for globe for each period ! the mean anom is weighted by Weights() subroutine CalcPerGlo allocate ( PerGlo (WorkPerN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcPerGlo: Allocation failure #####" PerGlo = MissVal RegThresh = WorkRegN*(100.0-MissAccept)/100.0 PerValid = 0.0 do XPer = 1, WorkPerN PerTot = 0.0 PerEn = 0.0 do XReg = 1, WorkRegN if (WorkAnomPerMeans(XReg,XPer).NE.MissVal) then PerTot = PerTot + (WorkAnomPerMeans(XReg,XPer) * Weights(XReg)) PerEn = PerEn + Weights(XReg) end if end do if (PerEn.GE.RegThresh) then PerGlo(XPer) = PerTot / PerEn PerValid = PerValid + 1.0 end if end do print*, " > Periods with valid weighted global means: ", PerValid end subroutine CalcPerGlo !******************************************************************************* ! calc JFB pattern noise (global) ! the weighting follows Mitchell et al 99 as far as possible ! the difference between local and global is squared BEFORE being weighted subroutine CalcJFBGlo NoiseJFB = MissVal NoiseJFBPop = MissVal PerSqTot = 0.0 PerTot = 0.0 PerEn = 0.0 PerThresh = WorkPerN*(100.0-MissAccept)/100.0 RegThresh = WorkRegN*(100.0-MissAccept)/100.0 do XPer = 1, WorkPerN if (PerGlo(XPer).NE.MissVal) then RegSqTot = 0.0 RegEn = 0.0 do XReg = 1, WorkRegN if (WorkAnomPerMeans(XReg,XPer).NE.MissVal) then RegSqTot = RegSqTot + ( ((WorkAnomPerMeans(XReg,XPer) - PerGlo(XPer)) ** 2) * Weights(XReg) ) RegEn = RegEn + Weights(XReg) end if end do if (RegEn.GE.RegThresh) then RegSignal = RegSqTot / RegEn RegSignal = sqrt (RegSignal) write (99,"(i4,e16.5)"), XPer, RegSignal ! ########### PerSqTot = PerSqTot + (RegSignal ** 2) PerTot = PerTot + RegSignal PerEn = PerEn + 1.0 end if end if end do if (PerEn.GE.PerThresh.AND.PerEn.GE.2) then NoiseJFB = PerTot / PerEn print*, " > Mean of signals from control periods: ", NoiseJFB NoiseJFB = (PerSqTot / PerEn) - ( (PerTot / PerEn) ** 2) NoiseJFB = (NoiseJFB * PerEn) / ( PerEn - 1 ) NoiseJFB = sqrt (NoiseJFB) print*, " > Stdev of signals from control periods: ", NoiseJFB else print*, " > Too many missing signals to calc noise." print*, " > Valid total and threshold values: ", PerEn, PerThresh end if end subroutine CalcJFBGlo !******************************************************************************* ! calc stdev subroutine CalcStDev print*, " > Calculate sample (=1) or population (=2) noise ?" do read (*,*,iostat=ReadStatus), QSampPop if (ReadStatus.LE.0.AND.QSampPop.GE.1.AND.QSampPop.LE.2) exit end do allocate ( AllRMSE (WorkRegN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcStDev: Allocation failure #####" AllRMSE = MissVal TotalValid = 0.0 RMSEThreshold = WorkPerN*(100.0-MissAccept)/100.0 RegThresh = WorkRegN*(100.0-MissAccept)/100.0 TotRMSE = 0.0 EnRMSE = 0.0 write (99,"(A17,F10.4)"), "stdev threshold: ", RMSEThreshold do XReg = 1, WorkRegN PerSqTot = 0.0 PerTot = 0.0 PerEn = 0.0 do XPer = 1, WorkPerN if (WorkAnomPerMeans(XReg,XPer).NE.MissVal) then PerSqTot = PerSqTot + (WorkAnomPerMeans(XReg,XPer) ** 2) PerTot = PerTot + WorkAnomPerMeans(XReg,XPer) PerEn = PerEn + 1 end if end do if (PerEn.GE.RMSEThreshold) then if (QSampPop.EQ.2) then if (PerEn.GT.1) then AllRMSE (XReg) = (PerSqTot / PerEn) + ((PerTot / PerEn) * (PerTot / PerEn)) AllRMSE (XReg) = AllRMSE (XReg) * PerEn / (PerEn - 1) AllRMSE (XReg) = sqrt (AllRMSE (XReg)) TotalValid = TotalValid + 1.0 end if else AllRMSE (XReg) = (PerSqTot / PerEn) + ((PerTot / PerEn) * (PerTot / PerEn)) AllRMSE (XReg) = sqrt (AllRMSE (XReg)) TotalValid = TotalValid + 1.0 end if if (AllRMSE(XReg).GT.99999.99) AllRMSE(XReg) = 99999.99 ! the .glo file cannot store larger values TotRMSE = TotRMSE + AllRMSE (XReg) EnRMSE = EnRMSE + 1.0 end if ! write (99,"(i6,3f10.4)"), XReg, PerSqTot, PerTot, PerEn end do PerCentValid = 100.0 * TotalValid / real(WorkRegN) print*, " > Percentage region stdev valid: ", PerCentValid if (EnRMSE.GE.1.AND.EnRMSE.GT.RegThresh) & print*, " > Global mean RMSE: ", TotRMSE/EnRMSE print*, " > Save the stdev to .glo file." call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,AllRMSE,WorkMapIDLReg) deallocate (AllRMSE, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcStDev: Deallocation failure #####" end subroutine CalcStDev !******************************************************************************* ! calc stdev of stdev subroutine CalcStDevStDev print*, " > How many members in ensemble to mimic ?" do read (*,*,iostat=ReadStatus), EnsMemN if (ReadStatus.LE.0.AND.EnsMemN.GE.1.AND.EnsMemN.LT.WorkPerN) exit end do print*, " > Calculate sample (=1) or population (=2) noise ?" do read (*,*,iostat=ReadStatus), QSampPop if (ReadStatus.LE.0.AND.QSampPop.GE.1.AND.QSampPop.LE.2) exit end do print*, " > Enter random number seed integer." do read (*,*,iostat=ReadStatus), Seed (1) ! seed = rank-one size-one integer array if (ReadStatus.LE.0) exit end do WorkTrialN = 200 MemThresh = (100.0 - MissAccept) * real(EnsMemN) / 100.0 TrialThresh = (100.0 - MissAccept) * WorkTrialN / 100.0 allocate ( OpProc (WorkTrialN,WorkRegN), & OpOut (WorkTrialN), & UsePer (EnsMemN), & LowerBound (WorkRegN), & UpperBound (WorkRegN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcStDevStDev: Allocation failure #####" OpProc = MissVal OpOut = MissVal LowerBound = MissVal UpperBound = MissVal call random_seed (put=Seed) do XTrial = 1, WorkTrialN UsePer = 0 do XMem = 1, EnsMemN do call random_number (RandomReal) RandomReal = (RandomReal * WorkPerN) + 0.5 RandomMem = nint (RandomReal) if (RandomMem.GE.1.AND.RandomMem.LE.WorkPerN) exit end do UsePer (XMem) = RandomMem end do write (99,*), XTrial, (UsePer(XMem),XMem=1,EnsMemN) ! ############# do XReg = 1, WorkRegN PerSqTot = 0.0 PerTot = 0.0 PerEn = 0.0 do XMem = 1, EnsMemN if (WorkAnomPerMeans(XReg,UsePer(XMem)).NE.MissVal) then PerSqTot = PerSqTot + (WorkAnomPerMeans(XReg,UsePer(XMem)) ** 2) PerTot = PerTot + WorkAnomPerMeans(XReg,UsePer(XMem)) PerEn = PerEn + 1.0 end if end do if (PerEn.GE.MemThresh.AND.PerEn.GE.2) then OpProc (XTrial,XReg) = (PerSqTot / PerEn) - ( (PerTot / PerEn) ** 2 ) if (QSampPop.EQ.2.AND.OpProc(XTrial,XReg).GT.0) & OpProc (XTrial,XReg) = OpProc (XTrial,XReg) * PerEn / (PerEn - 1) if (OpProc(XTrial,XReg).GT.0) & OpProc (XTrial,XReg) = sqrt (OpProc (XTrial,XReg)) end if end do end do print*, " > Is this a ref distribution for a one (=1) or two (=2) tailed test ?" do read (*,*,iostat=ReadStatus), TailN if (ReadStatus.LE.0 .AND. TailN.GE.1 .AND. TailN.LE.2) exit end do print*, " > What is the significance level (e.g. 0.95) ?" do read (*,*,iostat=ReadStatus), SigLevel if (ReadStatus.LE.0 .AND. SigLevel.GE.0.5 .AND. SigLevel.LT.1) exit end do do XReg = 1, WorkRegN RegMiss = 0 do XTrial = 1, WorkTrialN OpOut (XTrial) = OpProc (XReg,XTrial) if (OpProc (XReg,XTrial).EQ.MissVal) RegMiss = RegMiss + 1 end do if ((WorkTrialN-RegMiss).GE.TrialThresh) then call BubbleSort (WorkTrialN,TotMiss,OpOut) CalcReal = (WorkTrialN - TotMiss) * (1.0 - SigLevel) / TailN CalcInt = floor (CalcReal) LowerBound (XReg) = OpOut (CalcInt) CalcReal = (WorkTrialN - TotMiss) * SigLevel / TailN CalcInt = ceiling (CalcReal) UpperBound (XReg) = OpOut (CalcInt) end if write (99,"(i6,2f10.4)"), XReg, LowerBound (XReg), UpperBound (XReg) end do if (TailN.EQ.1) print*, " > Save sig value for 1-tail (lower): " if (TailN.EQ.2) print*, " > Save sig value for 2-tail (lower): " call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,LowerBound,WorkMapIDLReg) if (TailN.EQ.1) print*, " > Save sig value for 1-tail (upper): " if (TailN.EQ.2) print*, " > Save sig value for 2-tail (upper): " call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,UpperBound,WorkMapIDLReg) deallocate (LowerBound,UpperBound,OpOut,UsePer,OpProc, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: CalcStDevStDev: Deallocation failure #####" end subroutine CalcStDevStDev !******************************************************************************* ! calc interann var for ens of 30y slices: save mean+sd of set ! no anomalising, so full set of PerLen+GapLen within control ! that full set is divided by EnsMemN, to give the sample size ! if PerLen=30, GapLen=10, EnsMemN=4, and WorkYearN=1400, then ! sample of 8: ! i = periods 1, 9,17,25 ! ii = periods 2,10,18,26 etc ! from the set of seasonal means (120 per sample member in e.g.), we calc interann var ! for the sample, we calc mean and stdev-pop subroutine InterAnnVar print*, " > The variance is the same whether or not we anom(abs), so we don't." call Specification1 ! gives PerLen and GapLen call IdentifyPer3 ! gives WorkPerN and PertSelect(XYear) print*, " > How many members in ensemble to mimic ?" do read (*,*,iostat=ReadStatus), EnsMemN if (ReadStatus.LE.0.AND.EnsMemN.GE.1.AND.EnsMemN.LT.WorkPerN) exit end do EnsPerYearN = EnsMemN * PerLen EnsPerN = floor (real(WorkPerN)/real(EnsMemN)) allocate ( OpOut (EnsPerYearN), & OpProc (WorkRegN,EnsPerN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: InterAnnVar: Allocation failure #####" OpProc = MissVal do XReg = 1, WorkRegN do XPer = 1, EnsPerN PerYear = 0 OpOut = MissVal do XMem = 1, EnsMemN do XYear = 1, WorkYearN ThisPer = XPer + ( (XMem-1) * EnsMemN ) ! select per to include if (PertSelect(XYear).EQ.ThisPer) then PerYear = PerYear + 1 OpOut(PerYear) = WorkGotFull (XReg,XYear) ! fill vector with PerLen seasonals end if end do end do OpProc (XReg,XPer) = OpCalcStDev (OpOut, EnsPerYearN, MissAccept, 3) ! calc samp-var (=3) for Reg and Per end do end do deallocate (OpOut,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: InterAnnVar: Deallocation failure #####" allocate ( OpOut (WorkPerN), & AllAye (WorkRegN), & AllBee (WorkRegN), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: InterAnnVar: Allocation failure #####" do XReg = 1, WorkRegN do XPer = 1, EnsPerN OpOut (XPer) = OpProc (XReg,XPer) ! fill vector with variances end do AllAye (XReg) = OpCalcMean (OpOut, EnsPerN, MissAccept) ! calc samp-mean for Reg AllBee (XReg) = OpCalcStDev (OpOut, EnsPerN, MissAccept, 1) ! calc pop-sd (=2) for Reg end do print*, " > Save means of period variances to .glo:" call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,AllAye,WorkMapIDLReg) print*, " > Save sd-pop of period variances to .glo:" call SaveGlo (WorkLongN,WorkLatN,WorkRegN,WorkGridFilePath,AllBee,WorkMapIDLReg) deallocate (OpOut,OpProc,AllAye,AllBee, stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: InterAnnVar: Deallocation failure #####" end subroutine InterAnnVar !******************************************************************************* ! end end program SamplingError2