! updatedtb.f90 ! f90 program written by Tim Mitchell on 14.05.02 as accession.f90 ! rewritten as updatedtb.f90 ! last modified on 25.03.03 ! program to process new files of station monthly obs ! pgf90 -Mstandard -Minfo -fast -Mscalarsse -Mvect=sse -Mflushz ! -o ./../cruts/updatedtb time.f90 filenames.f90 grimfiles.f90 crutsfiles.f90 ! gridops.f90 sortmod.f90 plainperm.f90 regress.f90 ctyfiles.f90 countries.f90 ! ghcnrefiter.f90 ./../cruts/updatedtb.f90 2> /tyn1/tim/scratch/stderr.txt program UpdateDTB use Time use FileNames use GrimFiles use CRUtsFiles use GridOps use SortMod use PlainPerm use Regress use CtyFiles use Countries use GHCNrefIter implicit none logical, pointer, dimension (:,:) :: Trust logical, pointer, dimension (:) :: Normalise,GotRef,GetSingle,CandValid,PerTrust,Calc real, pointer, dimension (:,:,:) :: Par real, pointer, dimension (:,:) :: RelA,RelB,RelR, PoolWei real, pointer, dimension (:) :: LatO,LonO,ElvO, LatM,LonM,ElvM real, pointer, dimension (:) :: LatA,LonA,ElvA, LatD,LonD,ElvD real, pointer, dimension (:) :: MasterLat,MasterLon,MasterEn real, pointer, dimension (:) :: OriginalLat,OriginalLon,OriginalEn real, pointer, dimension (:) :: CtyLon,CtyLat,CtyTot real, pointer, dimension (:) :: MatchCodeA,MatchDistanceA,MatchNameA,MatchScoreA real, pointer, dimension (:) :: CandidScoreA,CandidScoreM real, pointer, dimension (:) :: Decay, VecO,VecD,VecR, Exe,Wye integer, pointer, dimension (:,:,:) :: DataO,DataSrcO,DataD,DataSrcD, RefTS integer, pointer, dimension (:,:,:) :: FD,AbsD,ParPer integer, pointer, dimension (:,:) :: DataNmlO,DataNmlD,DataNmlSrcD integer, pointer, dimension (:,:) :: Info,TrashInfo, StnPer,Neigh,CandFD,CandAbs,Pool integer, pointer, dimension (:,:) :: Combo integer, pointer, dimension (:) :: StnOldO,StnNewM,StnOldA,StnNewA,StnOldD,StnNewD integer, pointer, dimension (:) :: StnSrcCodeO,StnSrcCodeA,YearADO,YearADD,TrashYearAD integer, pointer, dimension (:) :: StnCodeBegO,StnCodeEndO,StnContinentO integer, pointer, dimension (:) :: StnSrcDateA,MissInts, Per2Stn,Stn2Per,PerBeg,PerEnd integer, pointer, dimension (:) :: MasterCode0,MasterCode1,MasterContinent integer, pointer, dimension (:) :: CandidIndexM,CandidIndexA integer, pointer, dimension (:) :: OrderA,OrderD,OrderM character (len=80), pointer, dimension (:) :: Batch character (len=80), pointer, dimension (:) :: MasterBatch character (len=20), pointer, dimension (:) :: StnNameO,StnNameM,StnNameA,StnNameD,TrashName character (len=13), pointer, dimension (:) :: StnCtyO,StnCtyM,StnCtyA,StnCtyD,TrashCty character (len=13), pointer, dimension (:) :: MasterCty,MasterRawName,MasterFinalName character (len=09), pointer, dimension (:) :: StnLocalO,StnLocalM,StnLocalA,StnLocalD,TrashLocal character (len=04), pointer, dimension (:) :: StnSrcSuffixA logical, dimension (12) :: CheckMon real, dimension (12) :: MonthA,MonthB,MonthR,SumR integer, dimension (12) :: Min,Max,MonthPrior,MonthFresh,Adjust real, parameter :: MissVal = -999.0 real, parameter :: SumRThresh = 0.25 integer, parameter :: DataMissVal = -9999 integer, parameter :: MultiSource = -888 character (len=80), parameter :: LatLonFile = './../../../scratch/test-latlon.txt' logical :: ZOneDP,Differ,Success,Okay,Dense,Extrer,Overlapper,Butter,Adder,Pseudo real :: OpVal,OpTotSq,OpTot,OpEn,OpZero,OpStDev,Aye,Bee,Are,Enn,ErrSum,ErrEnn,RMSE real :: Factor,Distance,StnODigit6,RealVal,CorrelMean,WeightMean,DecayMemory,Estimate real :: TotNull,TotNeg,TotSmall,TotLarge,TotPos,TotMon,MeanR,Lat1DP,Lon1DP,Dist1DP,Dist2DP real :: PriorTot,PriorEn,FreshTot,FreshEn,NuffFresh,NuffPrior,SmallThresh,LargeThresh integer :: ReadStatus, AllocStat integer :: QOrigCode,QOrigSrc,QDigits,QIncludeOrig,QConvertedCty,QDecay integer :: QDodgy,QAlter,QProceed,QRelyMeta integer :: NOYear,NDYear,NOStn,NMStn,NAStn,NDStn,NODYear integer :: XOYear,XDYear,XOStn,XMStn,XAStn,XDStn,XODYear integer :: NChar,NBatch,NMonth,NMasterCty,NPrior,NCandid,NDecay,NRel,NAttempt integer :: XChar,XBatch,XMonth,XMasterCty,XPrior,XCandid,XDecay,XRel,XAttempt integer :: SubBeg,SubLen,Ascii,Code,OrigSrcCode,AnswerNoYes,Reverse,Find,Seek integer :: Butt,ButtYX,DecayDistance,StampInt,Window,Increment,NeedThresh integer :: CandidAStn,CandidDStn,CandidMStn integer :: AssignAStn,AssignDStn,AssignMStn, Log1,Log2,Log3,Log4, Elastic integer :: MergeBeg,MergeEnd,Beg,End,ClimBeg,ClimEnd,OStart,OEnd,DStart,DEnd character (len=80) :: GivenFile,Variable character (len=80) :: OrigFileL,OrigSrcFileL,DatabaseFileL,MasterFileL,AccessFileL character (len=80) :: OrigFileS,OrigSrcFileS,DatabaseFileS,MasterFileS,AccessFileS character (len=80) :: DatabaseSrcFileL character (len=80) :: DatabaseSrcFileS character (len=20) :: Dirty,Name,Stamp20 character (len=10) :: CurrentTime,FileTime,Stamp10,LogText character (len=08) :: CurrentDate,FileDate character (len=04) :: VariableSuffix !******************************************************************************* call Intro call SelectOriginal call SelectVariable call FindDatabase call LoadingOriginal call LoadingMaster call LoadingAccessions call ProcessOriginal call IdentifyStnSrc call SetupAssign call Assignment ! main loop call ShutdownAssign call PrepareSave call SavingDatabase call SavingAccession call SavingMaster call Conclude !******************************************************************************* ! Assignment ! AssignStnMeta ! CheckDataDensity checks data>2 for each month, else Dense=FALSE ! CheckOverlap ! Conclude conclude program ! ConcludeAssign ! FindDatabase identify database file ! GetAdditions identify additions to existing database from this stn ! GetButtJoin uses ref ts to ensure butt-join fits well ! IdentifyStnSrc identifies a single src code for each stn ! Intro initialises program ! LoadingAccessions loading accessions file ! LoadingDatabase loading database files (.dtb and .dts) ! LoadingMaster load master .hdr file ! LoadingOriginal load original .cts file ! LocateStn ! LogMarker put progress marker in log file ! MakeNewDatabase make new database filled with missing values ! MatchCandid identify master candidates from priors ! MatchCodeAccess match code with accessions file ! MatchCodeMaster match code with master file ! MatchDistanceAccess match location with accessions file ! MatchNameAccess match stn name with accessions file ! MatchScoreAccess calc match score for each access file stn ! MatchScoreMaster obtains final master score for candidate ! MergeOverlap ! MergeExisting ! NeededStretch ! PrepareAssign ! PrepareSave prepares for saving ! ProcessOriginal ! SavingAccession ! SavingDatabase ! SavingMaster ! SelectOriginal provides user with load options and specifications ! SelectProc processing options ! SelectVariable select climate variable, by suffix ! SetupAssign prepares arrays for assignment operations ! ShutDownAssign contains !******************************************************************************* ! carries out the assignment (iterating by stn, main loop) subroutine Assignment do XOStn = 1, NOStn ! assign signed 6-digit stn code call CheckDataDensity ! checks data>2 for each month, else Dense=FALSE if (Dense) then call PrepareAssign call MatchCodeAccess ! match accession entries call MatchDistanceAccess call MatchNameAccess call MatchScoreAccess call MatchCandid ! identify master candidates if (NCandid.GT.0) then NAttempt=NCandid ; OrderM=MissVal do XCandid=1,NCandid ! generates the metadata score for each cand CandidAStn = CandidIndexA(XCandid) ! stored in CandidScoreM(XCandid) CandidMStn = CandidIndexM(XCandid) call MatchCodeMaster call MatchScoreMaster ! for qualifying matches, seek dtb stn if (CandidScoreM(XCandid).LT.0.OR.CandidScoreA(XCandid).LT.0) then if (LocateStn(StnNewM(CandidMStn),StnNewD).NE.MissVal) & CandidScoreM(XCandid)=CandidScoreM(XCandid)-100 else NAttempt=NAttempt-1 ; CandidScoreM(XCandid)=MissVal end if end do if (NAttempt.GT.0) then XAttempt=0 do ! attempt a match, by candidate XAttempt=XAttempt+1 ; OpTot=100000 ; OpEn=MissVal do XCandid=1,NCandid if (CandidScoreM(XCandid).LT.OpTot .AND. & CandidScoreM(XCandid).NE.MissVal) OpEn=XCandid end do if (OpEn.NE.MissVal) then XCandid=OpEn CandidAStn = CandidIndexA(XCandid) CandidMStn = CandidIndexM(XCandid) CandidDStn = LocateStn (StnNewM(CandidMStn),StnNewD) CandidScoreM(XCandid) = MissVal end if if (CandidDStn.NE.MissVal) then ! dtb stn exists call GetAdditions ! look for extra data call CheckNinety ! carry out 90% check if (.NOT.Overlapper) call CheckOverlap ! look for overlap if ((.NOT.Extrer).AND.Butter) then ! if no-extra but good-match Butter=.FALSE. ; Overlapper=.TRUE. ! make overlapping end if if (Overlapper) then ! accept overlap call AssignStnMeta ! assign metadata call MergeOverlap ! merge data else if (Butter) then ! attempt butt join AssignDStn=CandidDStn ! assume a good match call MergeExisting ! merge data (not sources) call GetButtJoin ! seek butt-join (correct if nec) end if else ! dtb stn does not exist Adder=.TRUE. call AssignStnMeta ! assign metadata call MergeExisting ! add data end if if (XAttempt.EQ.NAttempt.OR.Overlapper.OR.Butter.OR.Adder) exit end do end if end if if ((.NOT.Overlapper).AND.(.NOT.Butter).AND.(.NOT.Adder)) then Pseudo=.TRUE. call AssignStnMeta call MergeExisting end if call ConcludeAssign end if end do end subroutine Assignment !******************************************************************************* subroutine AssignStnMeta ! ensure M stn index if (Pseudo) then ! new pseudo AssignMStn = LocateStn (nint(MissVal),StnNewM) ! find next free master stn call FindNextPseudo ! place pseudo in StnNewM else ! any other assignment AssignMStn = CandidMStn end if ! ensure D stn index if (Pseudo.OR.Adder) then ! new pseudo or dtb entry AssignDStn = LocateStn (nint(MissVal),StnNewD) ! find next free dtb stn else ! any other assignment AssignDStn = CandidDStn end if ! ensure A stn index if (Pseudo.OR.Adder) then ! new pseudo or dtb entry AssignAStn = LocateStn (nint(MissVal),StnNewA) ! find next free dtb stn else ! any other assignment if (StnOldA(CandidAStn).EQ.StnOldO(XOStn) .AND. & LatA(CandidAStn).EQ.LatO(XOStn) .AND. & LonA(CandidAStn).EQ.LonO(XOStn) .AND. & ElvA(CandidAStn).EQ.ElvO(XOStn) .AND. & StnNameA(CandidAStn).EQ.StnNameO(XOStn) .AND. & StnCtyA(CandidAStn).EQ.StnCtyO(XOStn) .AND. & StnSrcCodeA(CandidAStn).EQ.StnSrcCodeO(XOStn)) then AssignAStn = CandidAStn else AssignAStn = LocateStn (nint(MissVal),StnNewA) end if end if if (LatM(AssignMStn).EQ.MissVal) LatM(AssignMStn) = LatO(XOStn) if (LonM(AssignMStn).EQ.MissVal) LonM(AssignMStn) = LonO(XOStn) if (ElvM(AssignMStn).EQ.MissVal) ElvM(AssignMStn) = ElvO(XOStn) if (trim(StnNameM(AssignMStn)).EQ."UNKNOWN") StnNameM(AssignMStn) = StnNameO(XOStn) if (trim(StnCtyM(AssignMStn)).EQ."UNKNOWN") StnCtyM(AssignMStn) = StnCtyO(XOStn) if (StnLocalM(AssignMStn).EQ." nocode") StnLocalM(AssignMStn) = StnLocalO(XOStn) if (StnNewD(AssignDStn).EQ.MissVal) StnNewD(AssignDStn) = StnNewM(AssignMStn) if (LatD(AssignDStn).EQ.MissVal) LatD(AssignDStn) = LatM(AssignMStn) if (LonD(AssignDStn).EQ.MissVal) LonD(AssignDStn) = LonM(AssignMStn) if (ElvD(AssignDStn).EQ.MissVal) ElvD(AssignDStn) = ElvM(AssignMStn) if (trim(StnNameD(AssignDStn)).EQ."UNKNOWN") StnNameD(AssignDStn) = StnNameM(AssignMStn) if (trim(StnCtyD(AssignDStn)).EQ."UNKNOWN") StnCtyD(AssignDStn) = StnCtyM(AssignMStn) if (StnLocalD(AssignDStn).EQ." nocode") StnLocalD(AssignDStn) = StnLocalM(AssignMStn) if (.NOT.Normalise(AssignDStn)) Normalise(AssignDStn)=.TRUE. ! calc normal if (StnOldA(AssignAStn).EQ.MissVal) then ! new accession entry required StnOldA(AssignAStn) = StnOldO(XOStn) StnNewA(AssignAStn) = StnNewM(AssignMStn) LatA(AssignAStn) = LatO(XOStn) LonA(AssignAStn) = LonO(XOStn) ElvA(AssignAStn) = ElvO(XOStn) StnNameA(AssignAStn) = StnNameO(XOStn) StnCtyA(AssignAStn) = StnCtyO(XOStn) StnLocalA(AssignAStn) = StnLocalO(XOStn) StnSrcCodeA(AssignAStn) = StnSrcCodeO(XOStn) StnSrcSuffixA(AssignAStn) = VariableSuffix StnSrcDateA(AssignAStn) = StampInt end if end subroutine AssignStnMeta !******************************************************************************* ! checks data>2 for each month, else Dense=FALSE subroutine CheckDataDensity Dense=.TRUE. ; XMonth=0 do XMonth=XMonth+1 ; XOYear=0 ; OpEn=0 do XOYear=XOYear+1 if (DataO(XOYear,XMonth,XOStn).NE.DataMissVal) OpEn=OpEn+1 if (XOYear.EQ.NOYear.OR.OpEn.EQ.2) exit end do if (OpEn.LT.2) Dense=.FALSE. if (XMonth.EQ.12.OR.(.NOT.Dense)) exit end do end subroutine CheckDataDensity !******************************************************************************* ! carry out 90% test = if 90% data in overlap are identical, ! with at least 3 months checked, assume overlap is identical subroutine CheckNinety TotNeg=0 ; TotPos=0 ; TotMon=0 ; CheckMon=.FALSE. do XMonth=1,NMonth do XODYear = 1, NODYear XDYear = DStart + XODYear - 1 ; XOYear = OStart + XODYear - 1 if (DataD(XDYear,XMonth,CandidDStn).NE.DataMissVal.AND.& DataO(XOYear,XMonth,XOStn).NE.DataMissVal) then if (.NOT.CheckMon(XMonth)) then CheckMon(XMonth)=.TRUE. ; TotMon=TotMon+1 end if if (DataD(XDYear,XMonth,CandidDStn).EQ.DataO(XOYear,XMonth,XOStn)) then TotPos=TotPos+1 else TotNeg=TotNeg+1 end if end if end do end do if (TotMon.GE.3) then if ((TotPos/(TotPos+TotNeg)).GE.0.9) then Overlapper=.TRUE. ; Butter=.FALSE. end if end if end subroutine CheckNinety !******************************************************************************* ! checks overlap between original and candidate database entry subroutine CheckOverlap TotNull=0 ; TotNeg=0 ; TotSmall=0 ; TotLarge=0 ; MeanR=0 do XMonth=1,NMonth Exe=MissVal ; Wye=MissVal do XODYear = 1, NODYear XDYear = DStart + XODYear - 1 ; XOYear = OStart + XODYear - 1 if (DataD(XDYear,XMonth,CandidDStn).NE.DataMissVal) & Exe(XODYear) = DataD(XDYear,XMonth,CandidDStn) if (DataO(XOYear,XMonth,XOStn).NE.DataMissVal) & Wye(XODYear) = DataO(XOYear,XMonth,XOStn) end do if (Differ) then call MergeForDiff (Exe,Wye,1,NODYear) else call MergeForRatio (Exe,Wye,1,NODYear) end if call RegressVectors (Exe,Wye,Aye,Bee,Are,Enn,4) ! 4 is deliberate ! write (99,"(a,i3,4f10.2)"), "overlap month",XMonth,Aye,Bee,Are,Enn ! #################### SmallThresh=0.7-(Enn*0.05) ; if (SmallThresh.LT.0.1) SmallThresh=0.1 LargeThresh=SmallThresh+0.2 if (Are.EQ.MissVal.OR.(Are.EQ.0.0.AND.Aye.EQ.0.0)) then TotNull=TotNull+1 else if (Are.LT.SmallThresh) then TotNeg=TotNeg+1 ; MeanR=MeanR+Are else if (Are.LT.LargeThresh) then TotSmall=TotSmall+1 ; MeanR=MeanR+Are else TotLarge=TotLarge+1 ; MeanR=MeanR+Are end if end do if (TotNull.LT.12) MeanR=MeanR/(12-TotNull) ! write (99,"(a,4f5.1,f10.2)"), "overlap total",TotNull,TotNeg,TotSmall,TotLarge,MeanR ! #################### if (TotNull.GE.6) then Overlapper=.FALSE. ; Butter=.TRUE. ! nulls - butt join else if ((TotSmall+(2*TotNeg)).GE.TotLarge) then Overlapper=.FALSE. ; Butter=.FALSE. ! bad overlap - no match! write (99,"(a10,2i8,f7.2,f8.2,i5,x,a20,x,a13)"), " uncorrel", StnOldO(XOStn), & StnNewD(CandidDStn),LatD(CandidDStn),LonD(CandidDStn),nint(ElvD(CandidDStn)), & StnNameD(CandidDStn),StnCtyD(CandidDStn) else if (MeanR.LT.0.2) then Overlapper=.FALSE. ; Butter=.FALSE. ! bad overlap - no match! write (99,"(a10,2i8,f7.2,f8.2,i5,x,a20,x,a13)"), " uncorrel", StnOldO(XOStn), & StnNewD(CandidDStn),LatD(CandidDStn),LonD(CandidDStn),nint(ElvD(CandidDStn)), & StnNameD(CandidDStn),StnCtyD(CandidDStn) else if (MeanR.LT.0.4) then Overlapper=.FALSE. ; Butter=.TRUE. ! doubtful overlap - butt join else Overlapper=.TRUE. ; Butter=.FALSE. ! excellent overlap - accept! end if end subroutine CheckOverlap !******************************************************************************* ! conclude program subroutine Conclude print* close (99) end subroutine Conclude !******************************************************************************* ! conclude stn assignment subroutine ConcludeAssign if (Pseudo) then LogText = "pseudo" ; Log1=Log1+1 else if (Adder) then LogText = "new-entry" ; Log2=Log2+1 else if (Overlapper) then LogText = "overlap" ; Log3=Log3+1 else if (Butter) then LogText = "butt-join" ; Log4=Log4+1 end if write (99,"(a10,2i8,f7.2,f8.2,i5,x,a20,x,a13)"), LogText, StnOldO(XOStn), & StnNewD(AssignDStn),LatO(XOStn),LonO(XOStn),nint(ElvO(XOStn)), & StnNameO(XOStn),StnCtyO(XOStn) end subroutine ConcludeAssign !******************************************************************************* ! identify database file subroutine FindDatabase DatabaseFileL = "./../../../data/cruts/database/" // VariableSuffix(2:4) // & ".??????????.dtb" call GetBatch (DatabaseFileL,Batch,Silent=1,ReturnUnalloc=1) if (.not.associated(Batch)) then print*, " > There are no prior accessions for this variable. New database." DatabaseFileL = "" else NBatch = size(Batch,1) DatabaseFileL = Batch(NBatch) deallocate (Batch,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: FindDatabase: Dealloc #####" end if end subroutine FindDatabase !******************************************************************************* ! finds next available pseudo code, and place in StnNewM(AssignMStn) subroutine FindNextPseudo Seek = 0-StnCodeBegO(XOStn) do Find = LocateStn(Seek,StnNewM) if (Find.NE.MissVal) Seek = Seek - 1 if (Find.EQ.MissVal) exit end do StnNewM(AssignMStn) = Seek end subroutine FindNextPseudo !******************************************************************************* ! examine new entry; if there is nothing to be learned, make this overlap subroutine GetAdditions Extrer=.FALSE. ; XODYear=0 do XODYear=XODYear+1 ; XDYear=DStart+XODYear-1 ; XOYear=OStart+XODYear-1 do XMonth = 1, NMonth if ( DataD(XDYear,XMonth,CandidDStn).EQ.DataMissVal .AND. & DataO(XOYear,XMonth,XOStn).NE.DataMissVal) Extrer=.TRUE. end do if (XODYear.EQ.NODYear.OR.Extrer) exit end do end subroutine GetAdditions !******************************************************************************* subroutine GetButtJoin allocate (RefTS(NDYear,NMonth,NDStn),Trust(NDYear,NDStn),Calc(NDStn),GotRef(NDStn), & stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### GetButtJoin: alloc #####" RefTS=DataMissVal ; Trust=.TRUE. ; Calc=.FALSE. ; GotRef=.FALSE. Calc(CandidDStn)=.TRUE. ; NeedThresh=2 Increment= 1 ; call NeededStretch if (ClimBeg.NE.MissVal.AND.ClimEnd.NE.MissVal) call MakeRefTS & (RefTS,DataD,LatD,LonD,Calc,Trust,real(DecayDistance),Differ, & .TRUE.,nint(MissVal),GotRef,NeedBeg=ClimBeg,NeedEnd=ClimEnd) if (.NOT.GotRef(CandidDStn)) then Increment=-1 ; call NeededStretch if (ClimBeg.NE.MissVal.AND.ClimEnd.NE.MissVal) call MakeRefTS & (RefTS,DataD,LatD,LonD,Calc,Trust,real(DecayDistance),Differ, & .TRUE.,nint(MissVal),GotRef,NeedBeg=ClimBeg,NeedEnd=ClimEnd) end if if (GotRef(CandidDStn)) then do XMonth=1,NMonth VecO=MissVal ; VecD=MissVal ; VecR=MissVal do XODYear=1,NODYear ! set up vectors XDYear=DStart+XODYear-1 ; XOYear=OStart+XODYear-1 if (RefTS(XDYear,XMonth,CandidDStn).NE.DataMissVal) & VecR(XODYear)=real(RefTS(XDYear,XMonth,CandidDStn)) if (DataD(XDYear,XMonth,CandidDStn).NE.DataMissVal) & VecD(XODYear)=real(DataD(XDYear,XMonth,CandidDStn)) if (DataO(XOYear,XMonth,XOStn).NE.DataMissVal) & VecO(XODYear)=real(DataO(XOYear,XMonth,XOStn)) end do if (Differ) then ! adjust RefTS to match Database, then Orig to match RefTS call MergeForDiff (VecD,VecR,1,NODYear) ! in ghcnrefiter.f90 call MergeForDiff (VecR,VecO,1,NODYear) else call MergeForRatio (VecD,VecR,1,NODYear) call MergeForRatio (VecR,VecO,1,NODYear) end if do XODYear=1,NODYear ! in-fill data XDYear=DStart+XODYear-1 ; XOYear=OStart+XODYear-1 if ( DataD (XDYear,XMonth,CandidDStn).NE.DataMissVal .AND. & DataSrcD(XDYear,XMonth,CandidDStn).EQ.DataMissVal) then if (VecO(XODYear).NE.MissVal) then if (VecO(XODYear).LT.Min(XMonth)) then VecO(XODYear)=Min(XMonth) else if (VecO(XODYear).GT.Max(XMonth)) then VecO(XODYear)=Max(XMonth) end if end if DataD (XDYear,XMonth,CandidDStn) = nint(VecO(XODYear)) DataSrcD (XDYear,XMonth,CandidDStn) = DataSrcO(XOYear,XMonth,XOStn) end if end do end do call AssignStnMeta else if (QRelyMeta.EQ.1) then do XMonth=1,NMonth do XODYear=1,NODYear ! in-fill data XDYear=DStart+XODYear-1 ; XOYear=OStart+XODYear-1 if ( DataD (XDYear,XMonth,CandidDStn).NE.DataMissVal .AND. & DataSrcD(XDYear,XMonth,CandidDStn).EQ.DataMissVal) then DataSrcD (XDYear,XMonth,CandidDStn) = DataSrcO(XOYear,XMonth,XOStn) end if end do end do call AssignStnMeta else write (99,"(a10,2i8,f7.2,f8.2,i5,x,a20,x,a13)"), " no-refts", StnOldO(XOStn), & StnNewD(CandidDStn),LatD(CandidDStn),LonD(CandidDStn),nint(ElvD(CandidDStn)), & StnNameD(CandidDStn),StnCtyD(CandidDStn) do XMonth=1,NMonth do XDYear=1,NDYear if ( DataD (XDYear,XMonth,CandidDStn).NE.DataMissVal .AND. & DataSrcD(XDYear,XMonth,CandidDStn).EQ.DataMissVal) then DataD(XDYear,XMonth,CandidDStn) = DataMissVal end if end do end do Butter=.FALSE. end if deallocate (RefTS,Trust,Calc,GotRef,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### GetButtJoin: dealloc #####" end subroutine GetButtJoin !******************************************************************************* ! identifies a single src code for each stn subroutine IdentifyStnSrc allocate (StnSrcCodeO(NOStn),stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: IdentifyStnSrc: Alloc #####" if (QOrigSrc.EQ.0) then StnSrcCodeO = OrigSrcCode else StnSrcCodeO = DataMissVal do XOStn = 1, NOStn ! if one source in a stn, make StnSrcCodeO = src do XOYear = 1, NOYear ! else make StnSrcCodeO = MultiSource do XMonth = 1, NMonth if (DataSrcO(XOYear,XMonth,XOStn).NE.DataMissVal) then if (StnSrcCodeO(XOStn).EQ.DataMissVal) then StnSrcCodeO(XOStn) = DataSrcO(XOYear,XMonth,XOStn) else if (StnSrcCodeO(XOStn).NE.DataSrcO(XOYear,XMonth,XOStn)) then StnSrcCodeO(XOStn) = MultiSource end if end if end do end do end do end if end subroutine IdentifyStnSrc !******************************************************************************* ! initialises program subroutine Intro open (99,file="./../../../scratch/log-updatedtb.dat", & status="replace",action="write") print* print*, " > ***** UpdateDTB: processes new stn files *****" print* NMonth = 12 ; Log1=0 ; Log2=0 ; Log3=0 ; Log4=0 call date_and_time (CurrentDate, CurrentTime) Stamp10 = CurrentDate(3:8) // CurrentTime(1:4) Stamp20 = adjustr(Stamp10) StampInt = GetIntFromText(Stamp20) end subroutine Intro !******************************************************************************* ! loading accessions file subroutine LoadingAccessions AccessFileL="./../../../data/cruts/accession/??????????.hdr" call GetBatch (AccessFileL,Batch,Silent=1) NBatch = size(Batch,1) AccessFileL = Batch(NBatch) SubBeg=index(AccessFileL,"/",.TRUE.) FileDate=AccessFileL((SubBeg+1):(SubBeg+6)) FileTime=AccessFileL((SubBeg+7):(SubBeg+10)) call LoadCTS (TrashInfo,StnLocalA,StnNameA,StnCtyA,Code=StnOldA,OldCode=StnNewA, & Silent=1,Lat=LatA,Lon=LonA,Elv=ElvA,HeadOnly=1, & CallFile=AccessFileL,Extra=NOStn,SrcCode=StnSrcCodeA, & SrcSuffix=StnSrcSuffixA,SrcDate=StnSrcDateA) NAStn = size(StnOldA,1) where (StnSrcCodeA.EQ.MissVal) StnSrcCodeA=DataMissVal print "(a,2(a2,a1),a2,a4,a2,a1,a2,a,i7,a)", " > Accessions file on ", & FileDate(5:6),".",FileDate(3:4),".",FileDate(1:2)," at ", & FileTime(1:2),":",FileTime(3:4)," has ",(NAStn-NOStn)," stns" deallocate (TrashInfo,Batch,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadingAccessions: Dealloc #####" end subroutine LoadingAccessions !******************************************************************************* ! loading database files (.dtb and .dts) subroutine LoadingDatabase SubBeg=index(DatabaseFileL,"/",.TRUE.) FileDate=DatabaseFileL((SubBeg+5):(SubBeg+10)) FileTime=DatabaseFileL((SubBeg+11):(SubBeg+14)) call LoadCTS (TrashInfo,TrashLocal,TrashName,TrashCty,Data=DataD,YearAD=YearADD, & DtbNormals=DataNmlD,YearADMin=YearADO(1),YearADMax=YearADO(NOYear), & Silent=1,CallFile=DatabaseFileL,Extra=NOStn) NDStn = size(DataD,3) ; NDYear = size(YearADD,1) deallocate (TrashInfo,TrashLocal,TrashName,TrashCty,YearADD,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadingDatabase: Dealloc 1 #####" print "(a,2(a2,a1),a2,a4,a2,a1,a2,a,i7,a,i10,a)", " > Database file on ", & FileDate(5:6),".",FileDate(3:4),".",FileDate(1:2)," at ", & FileTime(1:2),":",FileTime(3:4)," has ",(NDStn-NOStn)," stns;", & count(DataD.NE.DataMissVal), " data" SubBeg = index(DatabaseFileL,".dtb") DatabaseSrcFileL = DatabaseFileL(1:SubBeg) // "dts" call LoadCTS (TrashInfo,StnLocalD,StnNameD,StnCtyD,Code=StnNewD, & Lat=LatD,Lon=LonD,Elv=ElvD,DtbNormals=DataNmlSrcD,Data=DataSrcD, & YearAD=YearADD,CallFile=DatabaseSrcFileL,Extra=NOStn,Silent=1, & YearADMin=YearADO(1),YearADMax=YearADO(NOYear)) deallocate (TrashInfo,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadingDatabase: Dealloc 2 #####" end subroutine LoadingDatabase !******************************************************************************* ! load master file subroutine LoadingMaster MasterFileL="./../../../data/cruts/master/??????????.hdr" call GetBatch (MasterFileL,Batch,Silent=1) NBatch = size(Batch,1) MasterFileL = Batch(NBatch) SubBeg=index(MasterFileL,"/",.TRUE.) FileDate=MasterFileL((SubBeg+1):(SubBeg+6)) FileTime=MasterFileL((SubBeg+7):(SubBeg+10)) call LoadCTS (TrashInfo,StnLocalM,StnNameM,StnCtyM,Code=StnNewM,Lat=LatM,Lon=LonM,Elv=ElvM, & HeadOnly=1,CallFile=MasterFileL,Extra=NOStn,Silent=1) NMStn = size(StnNewM,1) print "(a,2(a2,a1),a2,a4,a2,a1,a2,a,i7,a)", " > Master file at ", & FileDate(5:6),".",FileDate(3:4),".",FileDate(1:2)," at ", & FileTime(1:2),":",FileTime(3:4)," has ",(NMStn-NOStn)," stns" deallocate (TrashInfo,Batch,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadingMaster: Dealloc #####" end subroutine LoadingMaster !******************************************************************************* ! load original data file subroutine LoadingOriginal call LoadCTS (TrashInfo,StnLocalO,StnNameO,StnCtyO,OldCode=StnOldO, & Lat=LatO,Lon=LonO,Elv=ElvO,Data=DataO, & YearAD=YearADO,CallFile=OrigFileL,Silent=1) deallocate (TrashInfo,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadingOriginal: Dealloc 1 #####" NOStn = size(StnOldO,1) ; NOYear = size(DataO,1) print "(a,22x,a,i7,a,i10,a)", " > Original file","has ", NOStn, " stns;", & count(DataO.NE.DataMissVal), " data" call LoadCTS (TrashInfo,TrashLocal,TrashName,TrashCty,Data=DataSrcO, & YearAD=TrashYearAD,CallFile=OrigSrcFileL,Silent=1) deallocate (TrashInfo,TrashLocal,TrashName,TrashCty,TrashYearAD,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: LoadingOriginal: Dealloc 2 #####" end subroutine LoadingOriginal !******************************************************************************* function LocateStn (WantedCode,Stn) integer :: LocateStn,WantedCode,XStn,NStn integer, pointer, dimension (:) :: Stn real, parameter :: MissVal=-999.0 NStn=size(Stn,1) ; XStn=0 ; LocateStn=0 do XStn = XStn + 1 if (Stn(XStn).EQ.MissVal) LocateStn=MissVal if (Stn(XStn).EQ.WantedCode) LocateStn=XStn if (XStn.EQ.NStn.OR.LocateStn.NE.0) exit end do end function LocateStn !******************************************************************************* ! make new database filled with missing values subroutine MakeNewDatabase NDStn = NOStn ; NDYear = NOYear allocate (StnLocalD(NDStn), StnNameD(NDStn), StnCtyD(NDStn), StnNewD(NDStn), & LatD(NDStn), LonD(NDStn), ElvD(NDStn), YearADD(NDYear), & DataD(NDYear,NMonth,NDStn),DataSrcD(NDYear,NMonth,NDStn), & DataNmlD(NMonth,NDStn),DataNmlSrcD(NMonth,NDStn), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: MakeNewDatabase: Alloc #####" StnLocalD=" nocode" ; StnNameD="UNKNOWN" ; StnCtyD="UNKNOWN" ; StnNewD=MissVal LatD=MissVal ; LonD=MissVal ; ElvD=MissVal DataD=DataMissVal ; DataSrcD=DataMissVal ; DataNmlD=DataMissVal ; DataNmlSrcD=DataMissVal do XDYear = 1, NDYear YearADD(XDYear) = YearADO(XDYear) end do end subroutine MakeNewDatabase !******************************************************************************* ! identify master candidates from priors subroutine MatchCandid CandidIndexA=MissVal ; CandidIndexM=MissVal ; CandidScoreA=MissVal ; NCandid=0 if (NPrior.GE.1) then ! relevant prior accessions call QuickSort (Reals=MatchScoreA,OrderValid=OrderA) ! sort the access scores do XPrior = 1, NPrior ! iterate by access score XMStn=0 do ! iterate by master stn XMStn=XMStn+1 if (StnNewM(XMStn).EQ.StnNewA(OrderA(XPrior))) then ! access and master stns match XCandid=0 do XCandid=XCandid+1 if (CandidIndexM(XCandid).EQ.XMStn) exit ! candidate already selected if (CandidIndexM(XCandid).EQ.MissVal) exit ! new candidate end do if (CandidIndexM(XCandid).EQ.MissVal) then ! new candidate CandidScoreA(XCandid)=MatchScoreA(OrderA(XPrior)) ! candidate score CandidIndexA(XCandid)=OrderA(XPrior) ! stn-index in accession CandidIndexM(XCandid)=XMStn ! stn-index in master NCandid=NCandid+1 end if end if if (XMStn.EQ.NMStn.OR.StnNewM(XMStn).EQ.StnNewA(OrderA(XPrior))) exit end do end do end if end subroutine MatchCandid !******************************************************************************* ! match code with accessions file subroutine MatchCodeAccess MatchCodeA = MissVal ! unmatched if (StnOldO(XOStn).NE.MissVal) then do XAStn = 1, NAStn if (StnOldA(XAStn).EQ.StnOldO(XOStn)) then if (abs(StnSrcCodeA(XAStn)).EQ.StnSrcCodeO(XOStn) & .AND.StnSrcCodeO(XOStn).NE.MultiSource) then MatchCodeA(XAStn) = -25 ! acc-code + src-code match else MatchCodeA(XAStn) = -10 ! accession code match end if else if (StnOldA(XAStn).NE.MissVal) then MatchCodeA(XAStn) = 30 ! bad match end if end do end if end subroutine MatchCodeAccess !******************************************************************************* ! match code with master file subroutine MatchCodeMaster if (StnOldO(XOStn).NE.MissVal) then ! orig stn code OK if (StnOldA(CandidAStn).EQ.StnOldO(XOStn)) then ! matches acc code if (StnSrcCodeO(XOStn).NE.MultiSource.AND. & ! matches acc source abs(StnSrcCodeA(CandidAStn)).EQ.StnSrcCodeO(XOStn)) then CandidScoreM(XCandid) = -25 else CandidScoreM(XCandid) = -10 end if else if ((StnNewM(CandidMStn)*10).EQ.StnOldO(XOStn)) then CandidScoreM(XCandid) = -10 ! matches master else if (StnOldO(XOStn).LT.0.OR.mod(StnOldO(XOStn),10).NE.0) then CandidScoreM(XCandid) = 0 ! match impossible else if (StnNewM(CandidMStn).LT.0) then CandidScoreM(XCandid) = 0 ! match impossible else CandidScoreM(XCandid) = 30 ! match poss, but none end if else CandidScoreM(XCandid) = 0 ! match impossible end if end subroutine MatchCodeMaster !******************************************************************************* ! match location with accessions file subroutine MatchDistanceAccess MatchDistanceA = MissVal if (LatO(XOStn).NE.MissVal.AND.LonO(XOStn).NE.MissVal) then ! distance OK if (ZOneDP .AND.mod((100*LatO(XOStn)),10.0).EQ.0 & .AND.mod((100*LonO(XOStn)),10.0).EQ.0) then do XAStn = 1, NAStn if (LatA(XAStn).NE.MissVal.AND.LonA(XAStn).NE.MissVal) then Dist2DP = GetDistance (LatA(XAStn),LonA(XAStn),LatO(XOStn),LonO(XOStn)) Lat1DP = real(nint(LatA(XAStn)*10))/10.0 Lon1DP = real(nint(LonA(XAStn)*10))/10.0 Dist1DP = GetDistance (Lat1DP,Lon1DP,LatO(XOStn),LonO(XOStn)) if (Dist1DP.LT.Dist2DP) then MatchDistanceA(XAStn) = Dist1DP else MatchDistanceA(XAStn) = Dist2DP end if end if end do else do XAStn = 1, NAStn if (LatA(XAStn).NE.MissVal.AND.LonA(XAStn).NE.MissVal) then if (mod((100*LatA(XAStn)),10.0).EQ.0 & .AND.mod((100*LonA(XAStn)),10.0).EQ.0) then Dist2DP = GetDistance (LatA(XAStn),LonA(XAStn),LatO(XOStn),LonO(XOStn)) Lat1DP = real(nint(LatO(XOStn)*10))/10.0 Lon1DP = real(nint(LonO(XOStn)*10))/10.0 Dist1DP = GetDistance (Lat1DP,Lon1DP,LatA(XAStn),LonA(XAStn)) if (Dist1DP.LT.Dist2DP) then MatchDistanceA(XAStn) = Dist1DP else MatchDistanceA(XAStn) = Dist2DP end if else MatchDistanceA(XAStn) = GetDistance (LatA(XAStn),LonA(XAStn), & LatO(XOStn),LonO(XOStn)) end if end if end do end if end if end subroutine MatchDistanceAccess !******************************************************************************* ! match stn name with accessions file subroutine MatchNameAccess MatchNameA = MissVal if (trim(StnNameO(XOStn)).NE.'UNKNOWN') then ! name match OK do XAStn = 1, NAStn if (trim(StnNameA(XAStn)).NE.'UNKNOWN') then if (trim(StnNameA(XAStn)).EQ.trim(StnNameO(XOStn))) then MatchNameA(XAStn) = 0.0 else Name = StnNameO(XOStn) NChar = len_trim(adjustl(Name)) ; XChar = 0 ; SubLen = 0 do XChar = XChar + 1 SubBeg = index (StnNameA(XAStn),Name(1:XChar)) if (SubBeg.NE.0) SubLen = SubLen + 1 if (XChar.EQ.NChar.OR.SubBeg.EQ.0) exit end do MatchNameA(XAStn) = 10 - SubLen end if end if end do end if end subroutine MatchNameAccess !******************************************************************************* ! calc match score for each access file stn subroutine MatchScoreAccess MatchScoreA = MissVal ; NPrior = 0 do XAStn = 1, NAStn if (MatchCodeA(XAStn).NE.MissVal) then MatchScoreA(XAStn) = MatchCodeA(XAStn) if (MatchDistanceA(XAStn).NE.MissVal) then MatchScoreA(XAStn) = MatchScoreA(XAStn) + (MatchDistanceA(XAStn)-5) else MatchScoreA(XAStn) = MatchScoreA(XAStn) + 5 end if if (MatchNameA(XAStn).NE.MissVal) then MatchScoreA(XAStn) = MatchScoreA(XAStn) + (MatchNameA(XAStn)-5) else MatchScoreA(XAStn) = MatchScoreA(XAStn) + 5 end if if (ElvA(XAStn).NE.MissVal.AND.ElvO(XOStn).NE.MissVal) then OpVal = sqrt(abs(ElvA(XAStn)-ElvO(XOStn))+1)-3 if (OpVal.GT.5) OpVal=5 MatchScoreA(XAStn) = MatchScoreA(XAStn) + OpVal end if if (StnCtyA(XAStn).EQ.StnCtyO(XOStn)) & MatchScoreA(XAStn) = MatchScoreA(XAStn) - 1 if (StnLocalA(XAStn).EQ.StnLocalO(XOStn)) & MatchScoreA(XAStn) = MatchScoreA(XAStn) - 1 if (MatchScoreA(XAStn).GE.30) then MatchScoreA(XAStn) = MissVal else NPrior = NPrior + 1 end if end if end do end subroutine MatchScoreAccess !******************************************************************************* ! obtains final master score for candidate subroutine MatchScoreMaster if (LatO(XOStn).NE.MissVal.AND.LonO(XOStn).NE.MissVal.AND. & LatM(CandidMStn).NE.MissVal.AND.LonM(CandidMStn).NE.MissVal) then if (ZOneDP .AND.mod((100*LatO(XOStn)),10.0).EQ.0 & .AND.mod((100*LonO(XOStn)),10.0).EQ.0) then Dist2DP = GetDistance (LatM(CandidMStn),LonM(CandidMStn), & LatO(XOStn),LonO(XOStn)) Lat1DP = real(nint(LatM(CandidMStn)*10))/10.0 Lon1DP = real(nint(LonM(CandidMStn)*10))/10.0 Dist1DP = GetDistance (Lat1DP,Lon1DP,LatO(XOStn),LonO(XOStn)) if (Dist1DP.LT.Dist2DP) then Distance = Dist1DP else Distance = Dist2DP end if else if (mod((100*LatM(CandidMStn)),10.0).EQ.0 & .AND.mod((100*LonM(CandidMStn)),10.0).EQ.0) then Dist2DP = GetDistance (LatM(CandidMStn),LonM(CandidMStn), & LatO(XOStn),LonO(XOStn)) Lat1DP = real(nint(LatO(XOStn)*10))/10.0 Lon1DP = real(nint(LonO(XOStn)*10))/10.0 Dist1DP = GetDistance (Lat1DP,Lon1DP,LatM(CandidMStn),LonM(CandidMStn)) if (Dist1DP.LT.Dist2DP) then Distance = Dist1DP else Distance = Dist2DP end if else Distance = GetDistance (LatM(CandidMStn),LonM(CandidMStn), & LatO(XOStn),LonO(XOStn)) end if end if CandidScoreM(XCandid) = CandidScoreM(XCandid) + Distance - 5 else if (CandidScoreM(XCandid).GT.-10) CandidScoreM(XCandid) = 3 end if if (trim(StnNameO(XOStn)).NE.'UNKNOWN'.AND.trim(StnNameM(CandidMStn)).NE.'UNKNOWN') then if (trim(StnNameO(XOStn)).EQ.trim(StnNameM(CandidMStn))) then SubLen = 0.0 else Name = StnNameO(XOStn) NChar = len_trim(adjustl(Name)) ; XChar = 0 ; SubLen = 0 do XChar = XChar + 1 SubBeg = index (StnNameM(CandidMStn),Name(1:XChar)) if (SubBeg.NE.0) SubLen = SubLen + 1 if (XChar.EQ.NChar.OR.SubBeg.EQ.0) exit end do SubLen = 10 - SubLen if (SubLen.LT.0) SubLen = 1.0 end if CandidScoreM(XCandid) = CandidScoreM(XCandid) + SubLen - 5 end if if (ElvM(CandidMStn).NE.MissVal.AND.ElvO(XOStn).NE.MissVal) then OpVal = sqrt (abs(ElvM(CandidMStn)-ElvO(XOStn)) + 1) - 3 if (OpVal.GT.5) OpVal=5 CandidScoreM(XCandid) = CandidScoreM(XCandid) + OpVal end if if (StnCtyM(CandidMStn).EQ.StnCtyO(XOStn)) & CandidScoreM(XCandid) = CandidScoreM(XCandid) - 1 if (StnLocalM(CandidMStn).EQ.StnLocalO(XOStn)) & CandidScoreM(XCandid) = CandidScoreM(XCandid) - 1 end subroutine MatchScoreMaster !******************************************************************************* subroutine MergeOverlap do XMonth = 1, NMonth ! iterate by month VecO=MissVal ; VecD=MissVal do XODYear=1,NODYear ! set up vectors for this month XDYear=DStart+XODYear-1 ; XOYear=OStart+XODYear-1 if (DataO(XOYear,XMonth,XOStn).NE.DataMissVal) & VecO(XODYear)=real(DataO(XOYear,XMonth,XOStn)) if (DataD(XDYear,XMonth,AssignDStn).NE.DataMissVal) & VecD(XODYear)=real(DataD(XDYear,XMonth,AssignDStn)) end do if (Differ) then call MergeForDiff (VecD,VecO,1,NODYear) ! in ghcnrefiter.f90 else call MergeForRatio (VecD,VecO,1,NODYear) end if do XODYear=1,NODYear XDYear=DStart+XODYear-1 ; XOYear=OStart+XODYear-1 if (DataD(XDYear,XMonth,AssignDStn).EQ.DataMissVal.AND. & DataO(XOYear,XMonth,XOStn) .NE.DataMissVal) then if (VecO(XODYear).NE.MissVal) then if (VecO(XODYear).LT.Min(XMonth)) then VecO(XODYear)=Min(XMonth) else if (VecO(XODYear).GT.Max(XMonth)) then VecO(XODYear)=Max(XMonth) end if end if DataD (XDYear,XMonth,AssignDStn) = nint(VecO(XODYear)) DataSrcD (XDYear,XMonth,AssignDStn) = DataSrcO(XOYear,XMonth,XOStn) end if end do end do end subroutine MergeOverlap !******************************************************************************* subroutine MergeExisting do XODYear = 1, NODYear XDYear = DStart + XODYear - 1 ; XOYear = OStart + XODYear - 1 do XMonth = 1, NMonth if (DataD(XDYear,XMonth,AssignDStn).EQ.DataMissVal) then if (DataO(XOYear,XMonth,XOStn).NE.DataMissVal) then if (Butter) then ! butt-join DataD(XDYear,XMonth,AssignDStn) = DataO(XOYear,XMonth,XOStn) else if (Adder) then ! new stn for database DataD(XDYear,XMonth,AssignDStn) = DataO(XOYear,XMonth,XOStn) else if (Pseudo) then ! new pseudo code DataD(XDYear,XMonth,AssignDStn) = DataO(XOYear,XMonth,XOStn) end if if (DataD(XDYear,XMonth,AssignDStn).LT.Min(XMonth)) & DataD(XDYear,XMonth,AssignDStn) = Min(XMonth) if (DataD(XDYear,XMonth,AssignDStn).GT.Max(XMonth)) & DataD(XDYear,XMonth,AssignDStn) = Max(XMonth) if (.NOT.Butter) DataSrcD(XDYear,XMonth,AssignDStn) = DataSrcO(XOYear,XMonth,XOStn) end if end if end do end do end subroutine MergeExisting !******************************************************************************* subroutine NeededStretch MonthPrior=0 ; MonthFresh=0 ; NuffFresh=0 ; NuffPrior=0 if (Increment.GT.0) XDYear=0 if (Increment.LT.0) XDYear=NDYear+1 do XDYear=XDYear+Increment ; XMonth=0 do XMonth=XMonth+1 if ( DataD(XDYear,XMonth,CandidDStn).NE.DataMissVal.AND. & DataSrcD(XDYear,XMonth,CandidDStn).EQ.DataMissVal) then MonthFresh(XMonth)=MonthFresh(XMonth)+1 if (MonthFresh(XMonth).EQ.NeedThresh) NuffFresh=NuffFresh+1 end if if (XMonth.EQ.NMonth) exit end do if (Increment.GT.0.AND.XDYear.EQ.NDYear) exit if (Increment.LT.0.AND.XDYear.EQ.1) exit if (NuffFresh.EQ.12) exit end do if (NuffFresh.EQ.12) then if (Increment.GT.0) ClimEnd=XDYear if (Increment.LT.0) ClimBeg=XDYear do XDYear=XDYear-Increment ; XMonth=0 do XMonth=XMonth+1 if ( DataD(XDYear,XMonth,CandidDStn).NE.DataMissVal.AND. & DataSrcD(XDYear,XMonth,CandidDStn).NE.DataMissVal) then MonthPrior(XMonth)=MonthPrior(XMonth)+1 if (MonthPrior(XMonth).EQ.NeedThresh) NuffPrior=NuffPrior+1 end if if (XMonth.EQ.NMonth) exit end do if (Increment.LT.0.AND.XDYear.EQ.NDYear) exit if (Increment.GT.0.AND.XDYear.EQ.1) exit if (NuffPrior.EQ.12) exit end do end if if (NuffPrior.EQ.12) then if (Increment.GT.0) ClimBeg=XDYear if (Increment.LT.0) ClimEnd=XDYear else ClimBeg=MissVal ; ClimEnd=MissVal end if end subroutine NeededStretch !******************************************************************************* ! prepares stn for assignment subroutine PrepareAssign if (mod(XOStn,10).EQ.0.0) then ! progress marker write (99,*), "" write (99,"(2(a,i5),a,i3,a)"), "----- STATION ", XOStn, " OF ", NOStn, " (", & nint(100.0*(real(XOStn)/real(NOStn))), "%) -----" end if QDecay=0 ! no decay dist calc yet Overlapper=.FALSE. ; Butter=.FALSE. ; Adder=.FALSE. ; Pseudo=.FALSE. end subroutine PrepareAssign !******************************************************************************* ! prepares for saving subroutine PrepareSave print*, " > Saving consolidated files ..." MasterFileS = "./../../../data/cruts/master/" // Stamp10 // ".hdr" AccessFileS = "./../../../data/cruts/accession/" // Stamp10 // ".hdr" DatabaseFileS = "./../../../data/cruts/database/" // VariableSuffix(2:4) // & "." // Stamp10 // ".dtb" DatabaseSrcFileS = "./../../../data/cruts/database/" // VariableSuffix(2:4) // & "." // Stamp10 // ".dts" end subroutine PrepareSave !******************************************************************************* subroutine ProcessOriginal call ClarifyCty (StnCtyO,StnNameO,LatO,LonO,StnOldO,StnCtyM,StnNameM, & LatM,LonM,StnCodeBegO,StnCodeEndO,StnContinentO) OpZero=0 ; OpTot=0 do XOStn=1,NOStn if (LatO(XOStn).NE.MissVal.AND.LonO(XOStn).NE.MissVal) then OpTot=OpTot+1 if (mod((100*LatO(XOStn)),10.0).EQ.0.AND.mod((100*LonO(XOStn)),10.0).EQ.0) & OpZero=OpZero+1 end if end do if (OpZero.GT.(OpTot*0.10)) then ZOneDP=.TRUE. print "(2(a,i4),a)", " > Many stns have lat/lon to only 1 d.p. (", & nint(OpZero), "/", nint(OpTot), ")" else ZOneDP=.FALSE. print "(2(a,i4),a)", " > Few stns have lat/lon to only 1 d.p. (", & nint(OpZero), "/", nint(OpTot), ")" end if end subroutine ProcessOriginal !******************************************************************************* subroutine SavingAccession allocate (MissInts(NAStn),stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SavingAccession: Alloc #####" MissInts = MissVal where (StnSrcCodeA.EQ.DataMissVal) StnSrcCodeA=MissVal call MakeStnInfo (Info,StnOldA,StnNewA,LatA,LonA,ElvA,0,YearAD0=MissInts,YearAD1=MissInts,Silent=1) call SaveCTS (Info,StnLocalA,StnNameA,StnCtyA,CallFile=AccessFileS, & HeadOnly=1,Silent=1,SrcCode=StnSrcCodeA, & SrcSuffix=StnSrcSuffixA,SrcDate=StnSrcDateA) call system ('compress ' // trim(AccessFileL) // ' &') ! compress old accessions file call system ('chmod ug=rw ' // trim(AccessFileS)) ! set permissions for new acc file ! call system ('sort -1n -o ' // trim(AccessFileS) // & ! compaq f90 version ! ' ' // trim(AccessFileS) // ' &') ! sort call system ('sort -g -o ' // trim(AccessFileS) // & ! portland group f90 version ' ' // trim(AccessFileS) // ' &') ! sort deallocate (MissInts,Info,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SavingAccession: Dealloc #####" end subroutine SavingAccession !******************************************************************************* subroutine SavingDatabase allocate (MissInts(NDStn),OrderD(NDStn),stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SavingDatabase: Alloc #####" MissInts = MissVal call QuickSort (Ints=StnNewD,OrderValid=OrderD) SubBeg=index(DatabaseFileS,"/",.TRUE.) FileDate=DatabaseFileS((SubBeg+5):(SubBeg+10)) FileTime=DatabaseFileS((SubBeg+11):(SubBeg+14)) print "(a,2(a2,a1),a2,a4,a2,a1,a2,a,i7,a,i10,a)", " > Database file on ", & FileDate(5:6),".",FileDate(3:4),".",FileDate(1:2)," at ", & FileTime(1:2),":",FileTime(3:4)," has ",count(StnNewD.NE.MissVal), & " stns;", count(DataD.NE.DataMissVal), " data" call MakeStnInfo (Info,StnNewD,MissInts,LatD,LonD,ElvD,1, & Data=DataD,DtbNormals=DataNmlD,YearAD=YearADD,Silent=1) call SaveCTS (Info,StnLocalD,StnNameD,StnCtyD,CallFile=DatabaseFileS, & Data=DataD,DtbNormals=DataNmlD,YearAD=YearADD,Silent=1,Order=OrderD) call SaveCTS (Info,StnLocalD,StnNameD,StnCtyD,CallFile=DatabaseSrcFileS, & Data=DataSrcD,DtbNormals=DataNmlSrcD,YearAD=YearADD,Silent=1,Order=OrderD) if (DatabaseFileL.NE."") then call system ('compress ' // trim(DatabaseFileL) // ' &') call system ('compress ' // trim(DatabaseSrcFileL) // ' &') end if call system ('chmod ug=rw ' // trim(DatabaseFileS)) call system ('chmod ug=rw ' // trim(DatabaseSrcFileS)) deallocate (MissInts,Info,OrderD,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SavingDatabase: Dealloc #####" end subroutine SavingDatabase !******************************************************************************* subroutine SavingMaster allocate (MissInts(NMStn),stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SavingMaster: Alloc #####" MissInts = MissVal call MakeStnInfo (Info,StnNewM,MissInts,LatM,LonM,ElvM,0,YearAD0=MissInts,YearAD1=MissInts,Silent=1) call SaveCTS (Info,StnLocalM,StnNameM,StnCtyM,CallFile=MasterFileS,HeadOnly=1,Silent=1) call system ('compress ' // trim(MasterFileL) // ' &') ! compress old master file call system ('chmod ug=rw ' // trim(MasterFileS)) ! set perm for new master file ! call system ('sort -1n -o ' // trim(MasterFileS) // & ! compaq f90 version ! ' ' // trim(MasterFileS) // ' &') call system ('sort -g -o ' // trim(MasterFileS) // & ! portland group f90 version ' ' // trim(MasterFileS) // ' &') deallocate (MissInts,Info,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SavingMaster: Delloc #####" end subroutine SavingMaster !******************************************************************************* ! provides user with load options and specifications subroutine SelectOriginal do do print*, " > Select the .cts file to load: " read (*,*,iostat=ReadStatus), GivenFile if (ReadStatus.LE.0.AND.GivenFile.NE."") exit end do OrigFileL = LoadPath (GivenFile,".cts") SubBeg = index(OrigFileL,"homog") if (SubBeg.LT.1) then print*, " > File appears unhomogenised. Proceed ? (0=no,1=yes)" do read (*,*,iostat=ReadStatus), QProceed if (QProceed.EQ.1) SubBeg=1000 if (ReadStatus.LE.0) exit end do end if if (SubBeg.GT.0) exit end do QOrigSrc = 1 ! i.e. parallel src file exists SubBeg = index(OrigFileL,".cts") OrigSrcFileL = OrigFileL(1:(SubBeg-1)) // ".src" QOrigCode = 1 ! i.e. original 7-digit code in the 'grid box' col ! this is necessary for late sources like CLIMAT and MCDW ! for variables where there are not likely to be overlaps ! with stns in the dtb, because most stns end prior to 1990 ! so in this case, set to 1, where the presumption is that if ! a metadata match can be made, the data will match ! this is valid in the context of correcting stns to match latest ! values because earlier-ending series will have been corrected ! to match the latest values in those series do print*, " > Allow non-overlap matches with dtb stns using metadata ? (0=no,1=yes)" read (*,*,iostat=ReadStatus), QRelyMeta if (ReadStatus.LE.0.AND.QRelyMeta.GE.0.AND.QRelyMeta.LE.1) exit end do end subroutine SelectOriginal !******************************************************************************* ! select the climate variable, by suffix subroutine SelectVariable SubBeg = index(OrigFileL,".cts") VariableSuffix = OrigFileL((SubBeg-4):(SubBeg-1)) do if (VariableSuffix.EQ." ") then do print*, " > Identify the variable suffix (form:'.???'): " read (*,*,iostat=ReadStatus), VariableSuffix if (ReadStatus.LE.0) exit end do end if call CheckVariSuffix (VariableSuffix,Variable,Factor) if (Variable.EQ."") VariableSuffix = " " if (Variable.NE."") print "(2a)", " > The variable is: ", trim(Variable) if (Variable.NE."") exit end do if (VariableSuffix.EQ.".pre") then DecayDistance = 450 ; Min=0 ; Max=99900 ; Differ=.FALSE. else if (VariableSuffix.EQ.".tmp") then DecayDistance = 1200 ; Min=-2730 ; Max=9000 ; Differ=.TRUE. else if (VariableSuffix.EQ.".dtr") then DecayDistance = 750 ; Min=0 ; Max=10000 ; Differ=.TRUE. else if (VariableSuffix.EQ.".cld") then DecayDistance = 750 ; Min=0 ; Max=1000 ; Differ=.TRUE. else if (VariableSuffix.EQ.".spc") then ! assumed, after cld DecayDistance = 750 ; Min=0 ; Max=1000 ; Differ=.TRUE. else if (VariableSuffix.EQ.".vap") then DecayDistance = 1200 ; Min=0 ; Max=10000 ; Differ=.TRUE. else if (VariableSuffix.EQ.".rhm") then ! assumed, after vap, tmp DecayDistance = 1200 ; Min=0 ; Max=1000 ; Differ=.TRUE. else if (VariableSuffix.EQ.".wet") then DecayDistance = 450 ; Min=0 ; Differ=.FALSE. Max=(/3100,2900,3100,3000,3100,3000,3100,3100,3000,3100,3000,3100/) else print*, " > @@@@@ ERROR: SelectVariable: no var @@@@@" end if Elastic=10 ; if (Differ) Elastic=5 end subroutine SelectVariable !******************************************************************************* ! prepares arrays for assignment operations subroutine SetupAssign if (DatabaseFileL.EQ."") call MakeNewDatabase if (DatabaseFileL.NE."") call LoadingDatabase call CommonVecPer (YearADO,YearADD,OStart,OEnd,DStart,DEnd) print*, " > Assigning each stn in .cts file ..." NODYear = OEnd-OStart+1 allocate (MatchCodeA(NAStn),MatchDistanceA(NAStn),MatchNameA(NAStn), & MatchScoreA(NAStn),OrderA(NAStn),OrderM(NMStn), & CandidIndexA(NAStn),CandidIndexM(NMStn), & CandidScoreA(NAStn),CandidScoreM(NMStn),Exe(NODYear),Wye(NODYear), & Combo(NODYear,NMonth),Decay(NDStn),VecO(NODYear),VecD(NODYear), & VecR(NODYear),Normalise(NDStn), stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: SetupAssign: Alloc #####" Normalise=.FALSE. end subroutine SetupAssign !******************************************************************************* subroutine ShutDownAssign deallocate (MatchCodeA,MatchDistanceA,MatchNameA,MatchScoreA,CandidIndexA, & CandidIndexM,CandidScoreA,CandidScoreM, & Combo,Decay,VecO,VecD,VecR,Normalise,OrderA,OrderM,stat=AllocStat) if (AllocStat.NE.0) print*, " > ##### ERROR: ShutDownAssign: Dealloc #####" print "(a,4i5)", " > Stns: pseudo,new-entry,overlap,butt-join:", Log1,Log2,Log3,Log4 end subroutine ShutDownAssign !******************************************************************************* end program UpdateDTB