! anomdtb.f90
! f90 program written by Tim Mitchell 
! originally written as part of opcruts.f90 (originated 11.02.02) as options 25
! program to convert CRU ts .dtb files to anomaly .txt files for use in gridding
! pgf90 -Mstandard -Minfo -fast -Mscalarsse -Mvect=sse -Mflushz 
!	-o ./../cruts/anomdtb filenames.f90 time.f90 grimfiles.f90 
!	crutsfiles.f90 perfiles.f90 annfiles.f90 cetgeneral.f90 basicfun.f90 
!	wmokey.f90 gridops.f90 grid.f90 ctyfiles.f90 
!	./../cruts/anomdtb.f90 2> /tyn1/tim/scratch/stderr.txt

program AnomDTB

use FileNames
use Time
use GrimFiles
use CRUtsFiles
use PerFiles
use AnnFiles
use CETGeneral
use BasicFun
use WMOKey
use GridOps
use Grid
use CtyFiles

implicit none


real, pointer, dimension (:,:,:)		:: Stdev,Means,RealData
real, pointer, dimension (:,:)			:: StnMon,StnSea,SumsPer,NormMean,NormStdev
real, pointer, dimension (:,:)			:: RefGridLat,RefGridLon
real, pointer, dimension (:)			:: SrcEn,SrcTot,SrcTotSq
real, pointer, dimension (:)			:: StnAnn, Scatter, SumsAnn
real, pointer, dimension (:)			:: ALat,ALon,AElv,BLat,BLon,BElv,CLat,CLon,CElv

real, dimension (12)	:: ThreshLo,ThreshHi,MonthMeans,TheoryMax
real, dimension ( 4)	:: RefBounds

integer, pointer, dimension (:,:,:)		:: Data,DataA,DataB,DataC
integer, pointer, dimension (:,:,:)		:: DataSrc,DataASrc,DataBSrc,DataCSrc
integer, pointer, dimension (:,:,:)		:: LogMeans,LogStdev
integer, pointer, dimension (:,:)		:: DtbNormalsA,DtbNormalsC
integer, pointer, dimension (:,:)		:: HulmeA,Normals,RefGrid,MonthLengths
integer, pointer, dimension (:,:)		:: StnInfoA,StnInfoB,StnInfoC
integer, pointer, dimension (:,:)		:: LogPass,LogMiss,LogSkip,LogFail,LogAny,LogNorm
integer, pointer, dimension (:)			:: YearAD,StnYearAD,AYearAD,BYearAD,CYearAD,Order
integer, pointer, dimension (:)			:: CtyCode0,CtyCode1,CtyReg
integer, pointer, dimension (:)			:: AStn,BStn,CStn, AStnOld,BStnOld,CStnOld, MapCA,MapCB
integer, pointer, dimension (:)			:: StnSrcCodeA,StnSrcDateA
integer, pointer, dimension (:)			:: NmlYr0,NmlYr1,NmlSrc,NmlInc

character (len=80), pointer, dimension (:)	:: SaveBatch,DatabaseBatch
character (len=80), pointer, dimension (:)	:: Bat01,Bat02,Bat03,Bat04,Bat05,Bat06
character (len=80), pointer, dimension (:)	:: Bat07,Bat08,Bat09,Bat10,Bat11,Bat12
character (len=20), pointer, dimension (:)	:: StnNameA,StnNameB,StnNameC,AUni,Source
character (len=13), pointer, dimension (:)	:: StnCtyA,StnCtyB,StnCtyC,CtyName,CtyFinal
character (len=09), pointer, dimension (:)	:: StnLocalA,StnLocalB,StnLocalC,ColTitles
character (len=04), pointer, dimension (:)	:: StnSrcSuffixA

character (len=20), dimension (9) :: VersionKey=(/"WMO STATIONS MAY 98","WMO MAY 2002","NCDC MAY 2002", &
						"GHCN V2 TMP SERIES","HULME PRECIP","LISTER MAY 02", &
						"CRU NORMALS","CRU BIG.HDR.HYP","CRU TMP SERIES"/)
character (len=04), dimension (4) :: LogName=(/"PASS","MISS","SKIP","FAIL"/)
character (len=09), dimension(12) :: RegTitles=(/'    Globe','   Europe','  ex-USSR', &
						' Mid-East','     Asia','   Africa', &
	   					' NAmerica',' CAmerica',' SAmerica', &
	   					'   Antarc','  Oceania','   Marine'/)
character (len=02), dimension (12) :: MonthTxt=(/"01","02","03","04","05","06","07","08","09","10","11","12"/)
	   
real, dimension(12), parameter 	:: Ephemeris=(/-0.346,-0.216,-0.029, 0.173, 0.331, 0.403, &
					        0.369, 0.237, 0.044,-0.158,-0.316,-0.387/)
real, parameter 		:: MissVal = -999.0
integer, parameter 		:: DataMissVal = -9999
integer, parameter 		:: MultiSource=-888

character (len=80) :: LogMeansFile="/cru/mikeh1/f709762/scratch/log/log-opcruts-means.cts"
character (len=80) :: LogStdevFile="/cru/mikeh1/f709762/scratch/log/log-opcruts-stdev.cts"

logical :: ValidNorm

real :: Lat0,Lat1,Lon0,Lon1,Elv0,Elv1, PrecLat,PrecLon,PrecElv
real :: DataMulti,ThreshStdev,ThreshReject,ThreshPercent,ThreshOpCalc 
real :: EntryReal,Limit, PrevLat,PrevLon, Constant, SeqStatus, Sigma,Middl,Excess
real :: MissThresh,StdevThresh,DistanceThresh,Factor, ExeSpace,WyeSpace
real :: OpVal,OpTot,OpEn,OpTotSq,OpStdev,OpMean,OpDiff,OpMean0,OpMean1,OpStdev0,OpStdev1,OpStdevJ
real :: Distance,DecayDistance,Loaded,LatRad,Denom,Numer

integer :: ReadStatus,AllocStat
integer :: QMenu,QDataHeadLoad,QDataHeadSave,QTrueQuasi,QLongType,QCrossDL,QFile,QNoStdev,QNoPer
integer :: QDiff,QFake,QAlter,QManual,QReverse,QShift,QType,QSource,QOperation,QRestrict,QCombine
integer :: QManCheck,QReject,QNRMfile,QOutput,QSignCheck,QMisMatch,QStoreOld,QHomogSource,QMerge
integer :: QAnomPercent,QPosOnly
integer :: NAStn,NBStn,NCStn,NInfo,NStnYear,NAYear,NBYear,NCYear,NMonth,NVersion,NCty,NReg,NSrc
integer :: XAStn,XBStn,XCStn,XInfo,XStnYear,XAYear,XBYear,XCYear,XMonth,XVersion,XCty,XReg,XSrc
integer :: NBatch,NExe,NWye,NFile
integer :: XBatch,XExe,XWye,XFile
integer :: XAYear0,XLog,XSeason,XSeasonMonth,XSeasonYear,XMonth0,XYear0,XMonth1,XYear1,XBMonth
integer :: AddYearAD0,AddYearAD1,PrevStn,EquiStn,RegSub0,StatType,SourceCode,SuffixBeg, Digits
integer :: YearAD0,YearAD1,Month0,Month1, AStart,AEnd,BStart,BEnd,CAStart,CAEnd,CBStart,CBEnd
integer :: IntLat,IntLon,IntElv, LatMV,LonMV,ElvMV,DataMV, LatF,LonF,ElvF
integer :: FakeStn,OrigStn,NewStn, TotA,TotB,TotAB, Min,Max,MinImpose,MaxImpose
integer :: Log01,Log02,Log03,Log04,Log05,Log06,Log07,Log08,Log09,Log11,Log12,Log13
integer :: Log0,Log1,Log2,Log3,Log4,Log5,Log6,Log7
integer :: InRange, CheckYear0,CheckYear1,SaveYearAD0,SaveYearAD1, NormMin,StrLen,SubBeg
integer :: RefBoxes,SrcRemove

character (len=80) :: GivenFile,LoadFileA,LoadFileB,LoadFileC,SaveFileA,SaveFileB,SaveFileC,HeadFormat
character (len=80) :: LoadFileASrc,LoadFileBSrc,SaveFileASrc,SaveFileBSrc,SaveFileCSrc,Stem,Tip
character (len=80) :: CurrStr,PrevStr,Variable,Title,Trash
character (len=80) :: DatabaseFilter,DatabaseFilterSrc,DatabaseFileL,DatabaseSrcFileL
character (len=20) :: SourceStr,EntryString,YearTxt,LineFormat
character (len=08) :: Date
character (len=04) :: LoadSuffix,SaveSuffix,SaveFileType,FileSuffix,TimeVal

!*******************************************************************************

call Intro
call Specify
call Anomalise
call Dumping
call Finish

contains

!*******************************************************************************

subroutine Intro

open (99,file="./../../../scratch/log-anomdtb.dat",status="replace",action="write")

print*
print*, "  > ***** AnomDTB: converts .dtb to anom .txt for gridding *****"
print*

NMonth = 12 ; NVersion = 9 ; NSrc = 1000

end subroutine Intro

!*******************************************************************************

subroutine Specify

QHomogSource=0

print*, "  > Enter the suffix of the variable required:"
do
	read (*,*,iostat=ReadStatus), LoadSuffix
	if (ReadStatus.LE.0) then
		call CheckVariSuffix (LoadSuffix,Variable,Factor)
  		if (Variable.EQ."") then
  		  print*, "  > Variable unrecognised."
  		else
  		  if (LoadSuffix.EQ.".pre".OR.LoadSuffix.EQ.".wet") then
  			print*, "  > Will calculate percentage anomalies." ; QAnomPercent=1
  		  else
       			QAnomPercent=0
  		  end if
  		end if
	end if
	if (ReadStatus.LE.0.AND.Variable.NE."") exit
end do

print*, "  > Select the .cts or .dtb file to load:"
do
	read (*,*,iostat=ReadStatus), GivenFile
        SuffixBeg = index(GivenFile,".cts") ; if (SuffixBeg.GT.0) FileSuffix = ".cts"
        SuffixBeg = index(GivenFile,".dtb") ; if (SuffixBeg.GT.0) FileSuffix = ".dtb"
	if (ReadStatus.LE.0.AND.(FileSuffix.EQ.".cts".OR.FileSuffix.EQ.".dtb")) exit
end do
LoadFileA  = LoadPath (GivenFile,FileSuffix)

if (FileSuffix.EQ.".cts") then
 print*, "  > Use supplementary .nrm file? (1=no,2=yes) ?"
 do
	read (*,*,iostat=ReadStatus), QNRMfile
	if (ReadStatus.LE.0.AND.QNRMfile.GE.1.AND.QNRMfile.LE.2) exit
 end do
 if (QNRMfile.EQ.2) then
  print*, "  > Select the .nrm file to load:"
  do
	read (*,*,iostat=ReadStatus), GivenFile
	if (ReadStatus.LE.0.AND.GivenFile.NE."") exit
  end do
  LoadFileB = LoadPath (GivenFile,".nrm")
 end if
else
 QNRMfile=1
end if

print*, "  > Specify the start,end of the normals period: "
do
	read (*,*,iostat=ReadStatus), YearAD0,YearAD1
	if (ReadStatus.LE.0.AND.YearAD1.GE.YearAD0) exit
end do

print*, "  > Specify the missing percentage permitted: "
do
	read (*,*,iostat=ReadStatus), MissThresh
	if (ReadStatus.LE.0.AND.MissThresh.GE.0.AND.MissThresh.LE.100) exit
end do
NormMin = ceiling((100.0-MissThresh)*(YearAD1-YearAD0+1)/100.0)
print*, "  > Data required for a normal: ", NormMin	! @@@@@@@@@@@@@@@@@@@@@@@

print*, "  > Specify the no. of stdevs at which to reject data: "
do
	read (*,*,iostat=ReadStatus), StdevThresh
	if (ReadStatus.LE.0.AND.StdevThresh.GT.0) exit
end do

print*, "  > Select outputs (1=.cts,2=.ann,3=.txt,4=.stn): "
do
	read (*,*,iostat=ReadStatus), QOutput
	if (QOutput.EQ.0) then
	  print*, "  >   1: save to .cts and .src, summarise to .ann"
	  print*, "  >   2: save summary of stns to .ann only"
	  print*, "  >   3: save to pre-interpol .txt, summarise to .ann"
	  print*, "  >   4: save stns-in-range .stn, summarise to .ann"
	end if
	if (ReadStatus.LE.0.AND.QOutput.GE.1.AND.QOutput.LE.4) exit
end do

DistanceThresh=0				! DON'T ALLOW FOR THIS IN SAVE TO .CTS
						! it is only valid when divorced from station info
if (QOutput.GE.2) then	
  print*, "  > Check for duplicate stns after anomalising? (0=no,>0=km range)"
  do
	read (*,*,iostat=ReadStatus), DistanceThresh
	if (ReadStatus.LE.0.AND.DistanceThresh.GE.0) exit
  end do
end if

if (QOutput.EQ.1) then
  print*, "  > Select the .cts file to save:"
  do
	read (*,*,iostat=ReadStatus), GivenFile
	if (ReadStatus.LE.0.AND.GivenFile.NE."") exit
  end do
  SaveFileB = SavePath (GivenFile,".cts")
else if (QOutput.EQ.2) then
  print*, "  > Select the .ann file to save:"
  do
	read (*,*,iostat=ReadStatus), GivenFile
	if (ReadStatus.LE.0.AND.GivenFile.NE."") exit
  end do
  SaveFileC = SavePath (GivenFile,".ann")
else if (QOutput.EQ.3) then
  print*, "  > Select the generic .txt file to save (yy.mm=auto):"
  do
	read (*,*,iostat=ReadStatus), GivenFile
	if (ReadStatus.LE.0.AND.GivenFile.NE."") exit
  end do
  SaveFileB = SavePath (GivenFile,".txt")
else if (QOutput.EQ.4) then
  print*, "  > Select the .stn file to save:"
  do
	read (*,*,iostat=ReadStatus), GivenFile
	if (ReadStatus.LE.0.AND.GivenFile.NE."") exit
  end do
  SaveFileB = SavePath (GivenFile,".stn")

  print*, "  > Enter the correlation decay distance:"
  do
	read (*,*,iostat=ReadStatus), DecayDistance
	if (ReadStatus.LE.0) exit
  end do

  print*, "  > Submit a grim that contains the appropriate grid."
  call GrabGrid (1,RefGrid,RefBounds,RefBoxes,Quiet=1)
  NExe=size(RefGrid,1) ; NWye=size(RefGrid,2)
end if

if (QOutput.EQ.3.OR.QOutput.EQ.4) then
  print*, "  > Select the first,last years AD to save: "
  do
	read (*,*,iostat=ReadStatus), SaveYearAD0,SaveYearAD1
	if (ReadStatus.LE.0.AND.SaveYearAD1.GE.SaveYearAD0) exit
  end do
end if

end subroutine Specify

!*******************************************************************************

subroutine Anomalise

print*, "  > Operating..."

if (FileSuffix.EQ.'.cts') then
  call LoadCTS (StnInfoA,StnLocalA,StnNameA,StnCtyA,Code=AStn,OldCode=AStnOld, &
  			Lat=ALat,Lon=ALon,Elv=AElv, &
			Data=DataA,YearAD=AYearAD,CallFile=LoadFileA,silent=1) 	! get .cts file
  SuffixBeg=index(LoadFileA,".cts")
  LoadFileC=LoadFileA(1:SuffixBeg-1) // ".src"
  SuffixBeg=index(LoadFileC,"/",.TRUE.)
  call LoadCTS (StnInfoC,StnLocalC,StnNameC,StnCtyC,Data=DataC,YearAD=CYearAD, &
  			CallFile=LoadFileC,Silent=1)          			! get .src file
else
  call LoadCTS (StnInfoA,StnLocalA,StnNameA,StnCtyA,Code=AStn,OldCode=AStnOld, &
  			Lat=ALat,Lon=ALon,Elv=AElv,DtbNormals=DtbNormalsA, &
			Data=DataA,YearAD=AYearAD,CallFile=LoadFileA,silent=1) 	! get .dtb file
  SuffixBeg=index(LoadFileA,".dtb")
  LoadFileC=LoadFileA(1:SuffixBeg-1) // ".dts"
  SuffixBeg=index(LoadFileC,"/",.TRUE.)
  call LoadCTS (StnInfoC,StnLocalC,StnNameC,StnCtyC,Data=DataC,YearAD=CYearAD, &
  			CallFile=LoadFileC,Silent=1,DtbNormals=DtbNormalsC)     ! get .dts file
  deallocate (DtbNormalsC,stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### ERROR: Anomalise: Deallocation failure: DtbNormalsC #####"
end if

Loaded = count(DataA.NE.DataMissVal)
NAYear = size(DataA,1) ; NAStn = size(DataA,3) 
AStart = YearAD0 - AYearAD(1) + 1 ; AEnd = AStart + YearAD1 - YearAD0		! normals period
if (AStart.LT.1.AND.AEnd.GE.1) AStart = 1
if (AEnd.GT.NAYear.AND.AStart.LE.NAYear) AEnd = NAYear
if (AStart.LT.1.OR.AStart.GT.NAYear.OR.AEnd.LT.1.OR.AEnd.GT.NAYear) then
	AStart=-999 ; AEnd=-999
  	print*, "  > ##### ERROR: Anomalise: No valid normals period #####"
end if

if (QOutput.EQ.3) then								! output period
  BStart = SaveYearAD0 - AYearAD(1) + 1 ; BEnd = BStart + SaveYearAD1 - SaveYearAD0
  if (BStart.LT.1.AND.BEnd.GE.1) BStart = 1
  if (BEnd.GT.NAYear.AND.BStart.LE.NAYear) BEnd = NAYear
  if (BStart.LT.1.OR.BStart.GT.NAYear.OR.BEnd.LT.1.OR.BEnd.GT.NAYear) then
  	BStart=-999 ; BEnd=-999
  	print*, "  > ##### ERROR: Anomalise: No valid output period #####"
!  else
!  	print "(a,2i5)", "   > The output period is:", AYearAD(BStart),AYearAD(BEnd)	! @@@@@@@@@@@@@@
  end if
end if

allocate (NormMean  (NMonth,NAStn), &
          NormStdev (NMonth,NAStn), stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: Anomalise: Allocation failure: Norm #####"
NormMean=DataMissVal ; NormStdev=DataMissVal

print "(a,6x,a)", "   > NORMALS", "      MEAN percent      STDEV percent"
									! look for normals from .dtb
! if (FileSuffix.EQ.".dtb".AND.YearAD0.EQ.1961.AND.YearAD1.EQ.1990) call NormalsDtbLine
call NormalsDtbLine		! ########################

Log1=0 ; Log2=0
do XAStn = 1, NAStn           						! look for normals from .cts
  do XMonth = 1, NMonth
   if (NormMean(XMonth,XAStn).NE.DataMissVal) then
    OpEn=0 ; OpTot=0 ; OpTotSq=0
    do XAYear = 1, NAYear
          if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) then
            OpEn=OpEn+1
            OpTot=OpTot+DataA(XAYear,XMonth,XAStn)
            OpTotSq=OpTotSq+(DataA(XAYear,XMonth,XAStn)**2)
          end if
    end do
				
    if (OpEn.GE.5) then
          NormStDev(XMonth,XAStn) = &
        		sqrt((OpEn/(OpEn-1))*((OpTotSq/OpEn)-((OpTot/OpEn)**2)))
          do XAYear = 1, NAYear
            if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) Log2=Log2+1
          end do				
    end if
   else
    OpEn = 0.0 ; OpTot = 0.0 ; OpTotSq = 0.0
    if (AStart.NE.-999.AND.AEnd.NE.-999) then				! get totals for stn/mon
        do XAYear = AStart, AEnd
          if (DataA(XAYear,XMonth,XAStn).NE.-9999) then
          	OpEn = OpEn + 1.0
          	OpTot = OpTot + (real(DataA(XAYear,XMonth,XAStn))/Factor)
          	OpTotSq = OpTotSq + ((real(DataA(XAYear,XMonth,XAStn))/Factor) ** 2)
          end if
        end do
    end if
    
    if (OpEn.GE.NormMin) then						! calc av & stdev if possible
      NormMean  (XMonth,XAStn) = Factor*OpTot/OpEn
      if (OpTotSq.GT.0) NormStdev (XMonth,XAStn) = Factor*sqrt((OpTotSq/OpEn)-((OpTot/OpEn)**2))
      
      OpEn = 0.0 ; OpTot = 0.0 ; OpTotSq = 0.0
      if (AStart.NE.-999.AND.AEnd.NE.-999) then				! recalc normals, no outliers
        do XAYear = AStart, AEnd
          if (DataA(XAYear,XMonth,XAStn).NE.-9999.AND. &
          		abs(real(DataA(XAYear,XMonth,XAStn))-NormMean(XMonth,XAStn)).LE. &
          		(NormStdev(XMonth,XAStn)*StdevThresh)) then
          	OpEn = OpEn + 1.0
          	OpTot = OpTot + (real(DataA(XAYear,XMonth,XAStn))/Factor)
          	OpTotSq = OpTotSq + ((real(DataA(XAYear,XMonth,XAStn))/Factor) ** 2)
          end if
        end do
      end if
      
      if (OpEn.GE.NormMin) then
        NormMean  (XMonth,XAStn) = Factor*OpTot/OpEn
        if (OpTotSq.GT.0) then
          NormStdev (XMonth,XAStn) = Factor*sqrt((OpEn/(OpEn-1))*((OpTotSq/OpEn)-((OpTot/OpEn)**2)))
        else
          NormStdev (XMonth,XAStn) = DataMissVal
        end if
	
	do XAYear=1,NAYear
	  if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) then
	    Log1=Log1+1
	    if (NormStdev(XMonth,XAStn).NE.DataMissVal) Log2=Log2+1
	  end if
	end do
      else
        NormMean  (XMonth,XAStn) = DataMissVal
        NormStdev (XMonth,XAStn) = DataMissVal
      end if
    end if    
   end if
  end do
end do
print "(a,8x,a,2(x,i10,x,f7.1))", "   > ", ".cts", &
		Log1,(100*(real(Log1)/Loaded)), Log2,(100*(real(Log2)/Loaded))

if (QNRMfile.EQ.2) then
  call LoadCTS (StnInfoB,StnLocalB,StnNameB,StnCtyB,Code=BStn,OldCode=BStnOld, &     ! get .nrm file
                NmlData=Normals,NmlInc=NmlInc,CallFile=LoadFileB,Silent=1)
  
  Log1=0
  NBStn=size(Normals,2) ; XBStn=1 ; XAStn=1                           	! look for .nrm normals
  do
    do    
      if (AStn(XAStn).GT.BStn(XBStn)) XBStn=XBStn+1
      if (XBStn.LE.NBStn) then
       if (AStn(XAstn).EQ.BStn(XBStn)) then
        if (StnInfoB(XBStn,5).GE.YearAD0.AND.StnInfoB(XBStn,6).LE.YearAD1.AND. &
             real((StnInfoB(XBStn,6)-StnInfoB(XBStn,5)+1))*(real(NmlInc(XBStn))/100.0) &
             .GE.real(NormMin)) then
                    QMisMatch = 0 ; XMonth = 0
                    do XMonth = 1, NMonth
                       if (Normals(XMonth,XBStn).NE.DataMissVal) then
                        OpEn=0 ; OpTot=0 ; OpTotSq=0
                        do XAYear = 1, NAYear
                         if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) then
                             OpEn = OpEn + 1
                             OpTot = OpTot + (DataA(XAYear,XMonth,XAStn)/Factor)
                             OpTotSq = OpTotSq + (DataA(XAYear,XMonth,XAStn)/Factor) ** 2
                         end if
                        end do
                        if (OpEn.GE.5) then					! difference of means test
                             OpStDev = Factor*sqrt((OpEn/(OpEn-1))*((OpTotSq/OpEn)-((OpTot/OpEn)**2)))
                             OpMean  = Factor*(OpTot/OpEn)
                             OpDiff  = OpMean - Normals(XMonth,XBStn)		! stdev: assume .nrm = .cts
                             if ((abs(OpDiff)/(OpStdev/2.0)).GT.3.0) QMisMatch=QMisMatch+1
                        end if
                       end if                                              
                    end do
                    
                    if (QMisMatch.LT.3) then
                      do XMonth = 1, NMonth
                        if (NormMean(XMonth,XAStn).EQ.DataMissVal.AND. &
				Normals(XMonth,XBStn).NE.DataMissVal) then
                    	    NormMean(XMonth,XAStn)=Normals(XMonth,XBStn)
			    
			    do XAYear=1,NAYear
			      if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) Log1=Log1+1
			    end do
                    	end if
                      end do
                    end if
        end if
        XBStn=XBStn+1
       end if
      end if
      if (XBStn.GT.NBStn) exit
      if (AStn(XAStn).LT.BStn(XBStn)) exit
    end do
    
    XAStn=XAStn+1
    if (XAStn.GT.NAStn) exit
    if (XBStn.GT.NBStn) exit
  end do
  print "(a,8x,a,(x,i10,x,f7.1))", "   > ", ".nrm", Log1,(100*(real(Log1)/Loaded))
end if

Log0=0 ; Log1=0 ; Log2=0 ; Log3=0 ; Log4=0 ; Log5=0
do XAStn = 1, NAStn           						! anomalise
  if (ALat(XAStn).NE.MissVal.OR.ALon(XAStn).NE.MissVal) then
   do XMonth = 1, NMonth
    do XAYear = 1, NAYear
      if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) then
        if (NormMean(XMonth,XAStn).NE.DataMissVal.AND.(QAnomPercent.EQ.0.OR. &
        			NormMean(XMonth,XAStn).NE.0)) then
          if (NormStdev(XMonth,XAStn).NE.DataMissVal) then
            Log5=Log5+1				! stdev check performed
	    if (abs(DataA(XAYear,XMonth,XAStn)-NormMean(XMonth,XAStn)).LE. &
            			(NormStdev(XMonth,XAStn)*StdevThresh)) then
              if (QAnomPercent.EQ.0) then
                DataA(XAYear,XMonth,XAStn) = DataA(XAYear,XMonth,XAStn) - NormMean(XMonth,XAStn)
              else
                DataA(XAYear,XMonth,XAStn) = nint(1000.0*((real(DataA(XAYear,XMonth,XAStn)) / &
                				real(NormMean(XMonth,XAStn)))-1.0))
              end if
              Log1=Log1+1			! accepted for moment
            else
              DataA(XAYear,XMonth,XAStn) = DataMissVal ; DataC(XAYear,XMonth,XAStn) = DataMissVal
              Log3=Log3+1			! outside stdev range
            end if
          else
            if (QAnomPercent.EQ.0) then
                DataA(XAYear,XMonth,XAStn) = DataA(XAYear,XMonth,XAStn) - NormMean(XMonth,XAStn)
            else
                DataA(XAYear,XMonth,XAStn) = nint(1000.0*((real(DataA(XAYear,XMonth,XAStn)) / &
                				real(NormMean(XMonth,XAStn)))-1.0))
            end if
            Log1=Log1+1				! accepted for moment
          end if
        else
          DataA(XAYear,XMonth,XAStn) = DataMissVal ; DataC(XAYear,XMonth,XAStn) = DataMissVal
          Log2=Log2+1				! no normal
        end if
      end if
      
      if (DataA(XAYear,XMonth,XAStn).GT.99999) DataA(XAYear,XMonth,XAStn) = 99998
      if (DataA(XAYear,XMonth,XAStn).LT.-9999) DataA(XAYear,XMonth,XAStn) = -9998
    end do
   end do
  else
   AStn(XAStn) = -999   
   
   do XMonth = 1, NMonth
    do XAYear = 1, NAYear
     if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) then
       Log0=Log0+1				! no lat/lon
       DataA(XAYear,XMonth,XAStn) = DataMissVal ; DataC(XAYear,XMonth,XAStn) = DataMissVal
     end if
    end do
   end do
  end if
end do

print "(a,6x,a,x,a)", "   > PROCESS", "  DECISION percent %of-chk"
print "(a,x,i10,2(x,f7.1))", "   > no lat/lon  ", &
	Log0,(100*(real(Log0)/Loaded)),(100*(real(Log0)/Loaded))
print "(a,x,i10,2(x,f7.1))", "   > no normal   ", &
	Log2,(100*(real(Log2)/Loaded)),(100*(real(Log2)/(Loaded-real(Log0))))
print "(a,x,i10,2(x,f7.1))", "   > out-of-range", &
	Log3,(100*(real(Log3)/Loaded)),(100*(real(Log3)/real(Log5)))

if (DistanceThresh.GT.0) then			! merge duplicate stations, judging by distance
  do XAStn=1,NAStn				! this is toggled distance/omit for save option 3
   if (AStn(XAStn).NE.MissVal) then
     do XBStn=XAStn+1,NAStn
      if (AStn(XBStn).NE.MissVal) then
        if (GetDistance (ALat(XAStn),ALon(XAStn),ALat(XBStn),ALon(XBStn)).LT.DistanceThresh) then
	  write (99,"(i7,a,i7)"), AStn(XAStn), " duplicates ", AStn(XBStn)
          AStn(XAStn) = -999

          do XAYear=1,NAYear
            do XMonth=1,NMonth
              if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) then
                if (DataA(XAYear,XMonth,XBStn).EQ.DataMissVal) then
                  DataA(XAYear,XMonth,XBStn) = DataA(XAYear,XMonth,XAStn)
              	else
              	  Log4=Log4+1
              	end if
              end if
            end do
          end do
        end if
      end if
     end do
   end if
  end do

  print "(a,x,i10,2(x,f7.1))", "   > duplicated  ", &
	Log4,(100*(real(Log4)/Loaded)),(100*(real(Log4)/real(Log1)))
  Log1=Log1-Log4
end if
print "(a,x,i10,(x,f7.1))", "   > accepted    ", &
	Log1,(100*(real(Log1)/Loaded))

end subroutine Anomalise

!*******************************************************************************

subroutine Dumping

if (QOutput.EQ.1) then				! dump to .cts and .src
  call MakeStnInfo (StnInfoB,AStn,AStnOld,ALat,ALon,AElv,1,YearAD=AYearAD,Data=DataA)
  call SaveCTS (StnInfoB,StnLocalA,StnNameA,StnCtyA,YearAD=AYearAD,Data=DataA, &
  		CallFile=SaveFileB,Silent=1)

  do XAYear=1,NAYear
    do XMonth=1,NMonth
      do XAStn=1,NAStn
        if (DataA(XAYear,XMonth,XAStn).EQ.-9999) DataC(XAYear,XMonth,XAStn)=-9999
      end do
    end do
  end do
  
  SuffixBeg=index(SaveFileB,".cts")
  SaveFileC=SaveFileB(1:SuffixBeg-1) // ".src"
  SuffixBeg=index(SaveFileC,"/",.TRUE.)
  print "(2a)", "   > Saving source file:   ", trim(SaveFileC(SuffixBeg+1:80))
  call SaveCTS (StnInfoB,StnLocalA,StnNameA,StnCtyA,YearAD=AYearAD,Data=DataC, &
  		CallFile=SaveFileC,Silent=1)  
else if (QOutput.EQ.3) then			! dump to .txt
  print "(a,2(i4,a))", "   > Dumping years ", AYearAD(BStart), "-", AYearAD(BEnd), " to .txt files..."
  SuffixBeg=index(SaveFileB,".txt")
  do XAYear=BStart,BEnd
    YearTxt = GetTextFromInt (AYearAD(XAYear))
    do XMonth=1,NMonth
       GivenFile = SaveFileB(1:SuffixBeg-1) // "." // trim(YearTxt) // "." // MonthTxt(XMonth) // ".txt"
       open  (9,file=GivenFile,status="replace",access="sequential",form="formatted",action="write")
       do XAStn = 1, NAStn
         if (DataA(XAYear,XMonth,XAStn).NE.-9999) write (9,"(2f8.2,f8.1,f13.5,i7)"), &
           ALat(XAStn),ALon(XAStn),AElv(XAStn),real(DataA(XAYear,XMonth,XAStn))*Factor,AStn(XAStn)
       end do
       close (9)
    end do
  end do  
else if (QOutput.EQ.4) then			! dump to .stn
  print*, "  > Calculating station coverages..."
  NBYear=SaveYearAD1-SaveYearAD0+1
  
  allocate (RefGridLat(NExe,NWye),RefGridLon(NExe,NWye), &
	    BYearAD(NBYear),RealData(NBYear,NMonth,RefBoxes), stat=AllocStat)
  if (AllocStat.NE.0) print*, "  > ##### WithinRange: Alloc: DataB #####"
  RefGridLat=MissVal ; RefGridLon=MissVal ; RealData=0
  ExeSpace=(RefBounds(2)-RefBounds(1))/real(NExe)
  WyeSpace=(RefBounds(4)-RefBounds(3))/real(NWye)

  do XBYear = 1, NBYear
    BYearAD(XBYear) = SaveYearAD0+XBYear-1
  end do
  call CommonVecPer (AYearAD,BYearAD,AStart,AEnd,BStart,BEnd)

  do XExe=1,NExe
   do XWye=1,NWye
    if (RefGrid(XExe,XWye).GT.0) then
      RefGridLon(XExe,XWye) = RefBounds(1)+((real(XExe)-0.5)*ExeSpace)
      RefGridLat(XExe,XWye) = RefBounds(3)+((real(XWye)-0.5)*WyeSpace)
    end if
   end do
  end do
  
  do XAStn=1,NAStn
    XMonth=0 ; ValidNorm=.FALSE.
    do
      XMonth=XMonth+1
      if (NormMean(XMonth,XAStn).NE.DataMissVal) ValidNorm=.TRUE.
      if (ValidNorm.OR.XMonth.EQ.12) exit
    end do
    
    if (ValidNorm) then
     do XExe = 1, NExe
      do XWye = 1, NWye
       if (RefGrid(XExe,XWye).GT.0) then
        Distance = GetDistance(ALat(XAStn),ALon(XAStn), &
        		RefGridLat(XExe,XWye),RefGridLon(XExe,XWye))	! gridops.f90
        if (Distance.LT.DecayDistance) then
          do XAYear = AStart,AEnd
            XBYear=(XAYear-AStart)+BStart
            do XMonth = 1, NMonth
              if (DataA(XAYear,XMonth,XAStn).NE.-9999) &
              	  RealData(XBYear,XMonth,RefGrid(XExe,XWye)) = &
              	  RealData(XBYear,XMonth,RefGrid(XExe,XWye)) + 1
            end do
          end do
        end if
       end if
      end do
     end do
    end if
  end do
  
  print*, "  > Saving..."
  Title="station count"
  call SaveGrim (RealData,RefGrid,BYearAD,RefBounds,Title,SaveFileB,".stn", &
  		 SaveSuffix,NoZip=1,Silent=1)
end if

if (QOutput.EQ.1) then
    SuffixBeg=index(SaveFileB,".cts")
    SaveFileC=SaveFileB(1:SuffixBeg-1) // ".ann"
else if (QOutput.EQ.3) then
    SuffixBeg=index(SaveFileB,".txt")
    SaveFileC=SaveFileB(1:SuffixBeg-1) // ".ann"
else if (QOutput.EQ.4) then
    SuffixBeg=index(SaveFileB,".stn")
    SaveFileC=SaveFileB(1:SuffixBeg-1) // ".ann"
end if
  
SuffixBeg=index(SaveFileC,"/",.TRUE.)
! print "(2a)", "   > Saving summary file:  ", trim(SaveFileC(SuffixBeg+1:80))

call ClassifyContinent
call SaveANN (SaveFileC,AYearAD,ColTitles,SumsPer,DecPlaceN=1)

end subroutine Dumping

!*******************************************************************************

subroutine Finish

print*

close (99)

end subroutine Finish

!*******************************************************************************

subroutine NormalsDtbLine

Log1=0
do XAStn = 1, NAStn
  do XMonth = 1, NMonth
    if (NormMean(XMonth,XAStn).EQ.DataMissVal) then
      if (DtbNormalsA(XMonth,XAStn).NE.DataMissVal) then
        NormMean(XMonth,XAStn) = DtbNormalsA(XMonth,XAStn)
        
        do XAYear = 1, NAYear
          if (DataA(XAYear,XMonth,XAStn).NE.DataMissVal) Log1=Log1+1
        end do				
      end if
    end if
  end do
end do

print "(a,8x,a,(x,i10,x,f7.1))", "   > ", ".dtb", &
		Log1,(100*(real(Log1)/Loaded))

end subroutine NormalsDtbLine

!*******************************************************************************
! CAREFUL! this is called both from DescribeAAnn and Anomalise

subroutine ClassifyContinent

NCty=MasterSize()						! ctyfiles.f90
allocate (CtyName  (NCty), &
	  CtyFinal (NCty), &
	  CtyCode0 (NCty), &
	  CtyCode1 (NCty), &
	  CtyReg   (NCty), stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: ClassifyContinent: Allocation failure #####"

call LoadMasterCty (CtyName,CtyFinal,CtyCode0,CtyCode1,CtyReg)	! ctyfiles.f90

allocate (SumsPer(NAYear,12), &
	  ColTitles(12),      stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: ClassifyContinent: Allocation failure #####"
SumsPer = 0 ; ColTitles = RegTitles

do XAStn = 1, NAStn
 if (AStn(XAStn).NE.MissVal) then
  XCty=0 ; XReg=0
  do
    XCty=XCty+1
    if (trim(StnCtyA(XAStn)).EQ.trim(CtyName(XCty))) XReg=CtyReg(XCty)
    if (XReg.NE.0) exit
    if (XCty.EQ.NCty) exit
  end do
  
  do XAYear = 1, NAYear
    do XMonth = 1, NMonth
      if (DataA(XAYear,XMonth,XAStn).NE.-9999) then
      	SumsPer(XAYear,1)=SumsPer(XAYear,1)+1
      	if (XReg.GE.1.AND.XReg.LE.11) SumsPer(XAYear,(XReg+1))=SumsPer(XAYear,(XReg+1))+1
      end if
    end do
  end do
 end if
end do

TotA = 0
do XAYear = 1, NAYear
  TotA = TotA + SumsPer(XAYear,1)
  do XReg = 1, 12
    SumsPer(XAYear,XReg)=SumsPer(XAYear,XReg)/12.0
  end do
end do

deallocate (CtyName,CtyFinal,CtyCode0,CtyCode1,CtyReg, stat=AllocStat)
if (AllocStat.NE.0) print*, "  > ##### ERROR: ClassifyContinent: Deallocation failure #####"

end subroutine ClassifyContinent 

!*******************************************************************************

end program AnomDTB
