! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE PREPSFCOBS ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE prepsfcobs & (ntime,mxstn, & nvar_ob,nvar_anx,nsrc_sng,nobs, & sfcfile,tmchkfile,blackfile, & var_ob,var_anx,name_src,qsrc, & rmiss,iqspr,sprdist,nobsrd,obstime, & stn,chsrc,isrc,latsta,lonsta,elevsta,xsta,ysta, & wx,kloud,idp3,store_emv,store_hgt,store_amt, & obsrd,obs,rely,qobs,qual,ival,climin,climax, & range,klim,wlim,qcthr, & knt,wgtsum,zsum,sqsum,iqclist,iqcsave,jstatus) ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Accumulate surface data and prepare them for analysis. ! Includes reading of data, temporal and horizontal ! consistemcy checks, and conversion of units. ! !----------------------------------------------------------------------- ! ! AUTHOR: Keith Brewster, CAPS ! March, 1994 ! ! MODIFICATION HISTORY: ! July, 1995 (Keith Brewster, CAPS) ! ARPSanx version ! ! Jan, 1996 (KB) ! Updated documentation. ! ! Aug, 1997 (KB) ! Modified for new handling of observation error, qsrc. ! QC is now done on analysis variables. ! ! Nov, 1997 (KB) ! Added argument rhmax, tmchkfile, for reorganized ADAS. ! ! Mar, 1998 (KB) ! Added argument blackfile ! !----------------------------------------------------------------------- ! ! INPUT: ! ! ntime Number of data times to process (normally 2) ! mxstn Size of data storage arrays ! nvar_ob Number of observed variables ! nvar_anx Number of analysis variables ! nsrc_sng Number of single-level data sources ! sfcfile Name of surface data file ! tmchkfile Name of surface data file used for time consistency check ! blackfile Name file containing blacklisted surface stations ! var_ob Names of observation variables ! var_anx Names of analysis variables ! name_src Names of data sources ! qsrc Standard error of observation for each source ! rmiss Missing value flag ! iqspr Super-observation flag ! sprdist Super-observation distance ! nobsrd Number of observations read-in ! nobs Number of observations output ! obstime Observation time ! stn Station name ! chsrc Source for each station ! isrc Source number for each station ! latsta Latitude of each station ! lonsta Longitude of each station ! elevsta Elevation of each station ! xsta X-coordinate of each station ! ysta Y-coordinate of each station ! wx Weather string ! kloud Number of cloud levels ! idp3 ! store_emv For each cloud level ! store_hgt Height of each cloud level ! store_amt Cloud amt for each cloud level ! obsrd Observations as read ! obs Analysis observations ! rely Reliability as assigned by time-consistency check ! qobs Observation standard error ! qual Observation quality indicator ! ival ! climin Climatic mininum (used to QC observations) ! climax Climatic maxinum (used to QC observations) ! range Analysis range -- used for Barnes QC check ! klim Minimum number of stations in Barnes QC check ! wlim Minimum weight in Barnes QC ! qcthr Quality control threshold for each variable and source ! knt Temporary array used in Barnes QC routine ! wgtsum Temporary array used in Barnes QC routine ! zsumc Temporary array used in Barnes QC routine ! sqsum Temporary array used in Barnes QC routine ! iqclist Unit number/Flag for printing list of rejected obs ! iqcsave Unit number/Flag for printing info on QC processing ! jstatus Return status indicator ! !----------------------------------------------------------------------- ! ! Variable Declarations: ! !----------------------------------------------------------------------- ! IMPLICIT NONE ! !----------------------------------------------------------------------- ! ! Arguments ! !----------------------------------------------------------------------- ! INTEGER :: ntime,mxstn INTEGER :: nvar_ob,nvar_anx,nsrc_sng INTEGER :: nobs ! CHARACTER (LEN=132) :: sfcfile CHARACTER (LEN=132) :: tmchkfile CHARACTER (LEN=132) :: blackfile ! CHARACTER (LEN=6) :: var_ob(nvar_ob),var_anx(nvar_anx) CHARACTER (LEN=8) :: name_src(nsrc_sng) REAL :: qsrc(nvar_anx,nsrc_sng) REAL :: rmiss INTEGER :: iqspr REAL :: sprdist ! INTEGER :: nobsrd(ntime) CHARACTER (LEN=8) :: chsrc(mxstn,ntime) INTEGER :: isrc(mxstn) REAL :: latsta(mxstn,ntime),lonsta(mxstn,ntime) REAL :: elevsta(mxstn,ntime) REAL :: xsta(mxstn),ysta(mxstn) INTEGER :: obstime(mxstn,ntime) CHARACTER (LEN=5) :: stn(mxstn,ntime) CHARACTER (LEN=8) :: wx(mxstn,ntime) CHARACTER (LEN=1) :: store_emv(mxstn,5,ntime) CHARACTER (LEN=4) :: store_amt(mxstn,5,ntime) INTEGER :: kloud(mxstn,ntime),idp3(mxstn,ntime) REAL :: store_hgt(mxstn,5,ntime) REAL :: obsrd(mxstn,nvar_ob,ntime) INTEGER :: rely(mxstn,nvar_ob,ntime) REAL :: qobs(nvar_anx,mxstn) REAL :: obs(nvar_anx,mxstn) INTEGER :: qual(nvar_anx,mxstn) INTEGER :: ival(mxstn) REAL :: climin(nvar_ob),climax(nvar_ob) ! REAL :: range,wlim INTEGER :: klim REAL :: qcthr(nvar_anx,nsrc_sng) ! INTEGER :: knt(nvar_anx) REAL :: wgtsum(nvar_anx) REAL :: zsum(nvar_anx) REAL :: sqsum(nvar_anx) ! INTEGER :: iqclist,iqcsave INTEGER :: jstatus ! !----------------------------------------------------------------------- ! ! Misc quality parameters ! !----------------------------------------------------------------------- ! INTEGER :: qcflag,qcsuper PARAMETER (qcflag=-199, qcsuper=200) ! !----------------------------------------------------------------------- ! ! Misc local variables ! !----------------------------------------------------------------------- ! CHARACTER (LEN=24) :: atime REAL :: ddrot INTEGER :: n_meso_g, & n_meso_pos,n_sao_g,n_sao_pos_g,n_sao_b,n_sao_pos_b,n_obs_g, & n_obs_pos_g,n_obs_b,n_obs_pos_b INTEGER :: nxt,iob,ivar,j,istatus ! !----------------------------------------------------------------------- ! ! Note that the variable names are in var_ob and are ! reproduced here: ! 1. t 2. td 3. dd 4. ff 5. u_ear 6. v_ear 7. pstn ! 8. pmsl 9. alt 10. ceil 11. hlow 12. cover 13. solar ! 14. vis ! ! 5 and 6 are actually read in us wind gust data, but ! are converted to u,v in the grid orientation by the loop ! after the read call. ! ! !----------------------------------------------------------------------- ! nxt=nobs+1 WRITE(6,810) sfcfile 810 FORMAT(' Getting surface data from: ',a132) CALL read_surface_obs(sfcfile,blackfile,mxstn,nxt,atime,n_meso_g, & n_meso_pos,n_sao_g,n_sao_pos_g,n_sao_b,n_sao_pos_b,n_obs_g, & n_obs_pos_g,n_obs_b,n_obs_pos_b,stn(1,1),chsrc(1,1), & latsta(1,1),lonsta(1,1),elevsta(1,1),wx(1,1), & obsrd(1,1,1),obsrd(1,2,1),obsrd(1,3,1),obsrd(1,4,1), & obsrd(1,5,1),obsrd(1,6,1),obsrd(1,7,1),obsrd(1,8,1), & obsrd(1,9,1), kloud(1,1),obsrd(1,10,1),obsrd(1,11,1), & obsrd(1,12,1),obsrd(1,13,1),idp3(1,1),store_emv(1,1,1), & store_amt(1,1,1),store_hgt(1,1,1),obsrd(1,14,1), & obstime(1,1),istatus) nobsrd(1)=n_obs_b ! IF(istatus /= 1) THEN ! surface obs not available jstatus = 0 WRITE(6,815) sfcfile 815 FORMAT(' ++Bad status return trying to get surface data from:', & /,a132) RETURN END IF ! WRITE(6,820) atime 820 FORMAT(' LSO data vaild time: ',a24) ! !----------------------------------------------------------------------- ! ! The winds are read in as dd,ff so we need to convert them to ! u,v and we'll place the u,v in the slot originally held by ! the wind gust info ddg,ffg. ! ! Important detail: At his point winds are "rotated" so that ! u,v is with respect to the map projection coordinates rather ! than earth coordinates. This is different than LAPS and OLAPS ! where earth coordinate u,v are analysed. ! !----------------------------------------------------------------------- ! DO iob=nxt,(nobs+nobsrd(1)) obsrd(iob,5,1)=rmiss obsrd(iob,6,1)=rmiss IF(obsrd(iob,3,1) >= 0. .AND. obsrd(iob,4,1) >= 0.) & CALL ddrotuv(1,lonsta(iob,1), & obsrd(iob,3,1),obsrd(iob,4,1), & ddrot,obsrd(iob,5,1),obsrd(iob,6,1)) END DO ! ! !----------------------------------------------------------------------- ! ! Find the x,y location of each station. ! Note the use of lltoxy requires that map projection ! be initialized with map parameters. It is assumed here ! that this has been done already. ! !----------------------------------------------------------------------- ! CALL lltoxy(nobsrd(1),1,latsta(nxt,1),lonsta(nxt,1), & xsta(nxt),ysta(nxt)) ! write(6,821) ! 821 format(' stn lat lon elev dd ff ugr vgr ') ! DO 111 i=1,nobsrd(1) ! k=i+nobs ! write(6,822) stn(k,1),latsta(k,1),lonsta(k,1),elevsta(k,1), ! : obsrd(k,3,1),obsrd(k,4,1),obsrd(k,5,1),obsrd(k,6,1) ! 822 format(a5,f6.1,f6.1,f6.0,f6.1,f6.1,f6.1,f6.1) ! 111 CONTINUE ! ! !----------------------------------------------------------------------- ! ! Temporal QC ! Read in past data. ! !----------------------------------------------------------------------- ! WRITE(6,830) tmchkfile 830 FORMAT(' Getting past surface data from: ',a132) CALL read_surface_obs(tmchkfile,blackfile,mxstn,1,atime,n_meso_g, & n_meso_pos,n_sao_g,n_sao_pos_g,n_sao_b,n_sao_pos_b,n_obs_g, & n_obs_pos_g,n_obs_b,n_obs_pos_b,stn(1,2),chsrc(1,2), & latsta(1,2),lonsta(1,2),elevsta(1,2),wx(1,2), & obsrd(1,1,2),obsrd(1,2,2),obsrd(1,3,2),obsrd(1,4,2), & obsrd(1,5,2),obsrd(1,6,2),obsrd(1,7,2),obsrd(1,8,2), & obsrd(1,9,2), kloud(1,2),obsrd(1,10,2),obsrd(1,11,2), & obsrd(1,12,2),obsrd(1,13,2),idp3(1,2),store_emv(1,1,2), & store_amt(1,1,2),store_hgt(1,1,2),obsrd(1,14,2), & obstime(1,2),istatus) nobsrd(2)=n_obs_b ! IF(istatus == 1 .AND. nobsrd(2) > 0 ) THEN ! old surface OK, do QC ! ! !----------------------------------------------------------------------- ! ! The winds are read in as dd,ff so we need to convert them to ! u,v and we'll place the u,v in the slot originally held by ! the wind gust info ddg,ffg. ! !----------------------------------------------------------------------- ! DO iob=1,nobsrd(2) obsrd(iob,5,2)=rmiss obsrd(iob,6,2)=rmiss IF(obsrd(iob,3,2) >= 0. .AND. obsrd(iob,4,2) >= 0.) & CALL ddrotuv(1,lonsta(iob,2), & obsrd(iob,3,2),obsrd(iob,4,2), & ddrot,obsrd(iob,5,2),obsrd(iob,6,2)) END DO ! ! DO 211 i=1,nobsrd(2) ! write(6,822) stn(i,2),latsta(i,2),lonsta(i,2),elevsta(i,2), ! : obsrd(i,3,2),obsrd(i,4,2),obsrd(i,5,2),obsrd(i,6,2) ! 211 CONTINUE ! ELSE WRITE(6,835) tmchkfile 835 FORMAT(' ++Bad status return trying to get surface data from:', & /,a132,/,' Temporal QC skipped') END IF ! !----------------------------------------------------------------------- ! ! Call subroutine to match-up obs and compare hourly changes. ! !----------------------------------------------------------------------- ! CALL qcdata(mxstn,nsrc_sng,nvar_ob,ntime,nobs,nobsrd,stn,chsrc, & latsta,lonsta,xsta,ysta,elevsta, & wx,obsrd,kloud,idp3,store_emv, & store_amt,store_hgt,obstime, & climin,climax,rely,ival,istatus) ! !----------------------------------------------------------------------- ! ! Set isrc based on read-in source. ! !----------------------------------------------------------------------- ! CALL setisrc(mxstn,nsrc_sng,nobsrd(1),name_src, & chsrc(nxt,1),isrc(nxt)) ! !----------------------------------------------------------------------- ! ! Create observation array containing observations or ! derived observations that are to be analysed. ! !----------------------------------------------------------------------- ! DO j=1,nsrc_sng PRINT *, ' qsrc = ',(qsrc(ivar,j),ivar=1,nvar_anx) END DO ! CALL cvtobsanx(mxstn,nvar_ob,nvar_anx,nsrc_sng,nobs,nobsrd(1), & stn,isrc,latsta,lonsta,elevsta, & obsrd,kloud,idp3,store_emv,store_amt, & store_hgt,rely,qsrc,rmiss, & obs,qobs,qual,istatus) ! !----------------------------------------------------------------------- ! ! Call subroutine to do horizontal quality control ! !----------------------------------------------------------------------- ! CALL barqc(mxstn,nvar_anx,nsrc_sng,nobs,nobsrd(1), & obs,obstime,xsta,ysta,isrc,qual, & knt,wgtsum,zsum,sqsum, & range,wlim,klim,qcthr,var_anx,stn, & iqclist,iqcsave,qcflag) ! !----------------------------------------------------------------------- ! ! Now create superobs by combining observations within a small ! distance from each other. This helps eliminate some Barnes ! artifacts due to the fact that Barnes does not account for the ! relative distribution of stations that go into the analysis ! at each grid point. ! !----------------------------------------------------------------------- ! nobs=nobs+nobsrd(1) CALL suprob(mxstn,nvar_anx,nobs,stn,xsta,ysta,elevsta, & obs,isrc,qobs,qual, & iqspr,sprdist,qcsuper) ! RETURN END SUBROUTINE prepsfcobs ! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE SUPEROB ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE suprob(mxstn,nvar,nobs,stn,xsta,ysta,elevsta, & 1,1 obs,isrc,qobs,qual, & iqspr,sprdist,qcsuper) ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Combine observations that are within a specified ! distance (sprdist) from each other. The combined obs are ! put into a new "station" and the original obs are set to ! missing. ! ! !----------------------------------------------------------------------- ! ! AUTHOR: Keith Brewster, CAPS ! March, 1994 ! ! MODIFICATION HISTORY: ! ! 1/21/96 (K. Brewster) ! Added full documentation. ! !----------------------------------------------------------------------- ! ! Variable Declarations: ! !----------------------------------------------------------------------- ! IMPLICIT NONE INTEGER :: mxstn,nvar,nobs CHARACTER (LEN=5) :: stn(mxstn) REAL :: xsta(mxstn) REAL :: ysta(mxstn) REAL :: elevsta(mxstn) REAL :: obs(nvar,mxstn) INTEGER :: isrc(mxstn) REAL :: qobs(nvar,mxstn) INTEGER :: qual(nvar,mxstn) INTEGER :: iqspr REAL :: sprdist INTEGER :: qcsuper ! !----------------------------------------------------------------------- ! ! Misc. local variables ! !----------------------------------------------------------------------- ! INTEGER :: ivar,ista,jsta,jmin,ksta,kntsta REAL :: super2,dist1,dist2,dist,distm,qinvi,qinvj,qobloc ! CALL zerosrc(nvar,mxstn,obs,qual,isrc,nobs) ! super2=sprdist*sprdist kntsta=nobs ista=0 ! !----------------------------------------------------------------------- ! ! Loop over all stations ! Since may be adding stations within the loop we can't ! use a standard FORTRAN do loop with fixed limits. ! !----------------------------------------------------------------------- ! 10 CONTINUE ista=ista+1 IF(ista > kntsta) GO TO 200 IF(isrc(ista) /= 0) THEN distm=99999999. jmin=0 ! !----------------------------------------------------------------------- ! ! Find the nearest neighbor to this station. ! !----------------------------------------------------------------------- ! DO jsta=1,kntsta IF(isrc(jsta) /= 0 .AND. ista /= jsta) THEN dist1=xsta(ista)-xsta(jsta) dist2=ysta(ista)-ysta(jsta) dist=dist1*dist1 + dist2*dist2 IF(dist < distm) THEN distm=dist jmin=jsta END IF END IF END DO ! !----------------------------------------------------------------------- ! ! If the distance is less than the super-ob threshold ! distance, combine the neighboring stations into one superob. ! !----------------------------------------------------------------------- ! IF(jmin > 0 .AND. distm < super2) THEN WRITE(6,'(a,a,a,a)') ' Combining stations: ',stn(ista), & ' and ',stn(jmin) IF(isrc(jmin) > 0) THEN isrc(jmin)=0 kntsta=kntsta+1 IF(kntsta > mxstn) THEN nobs=mxstn GO TO 900 END IF ksta=kntsta ELSE ksta=jmin END IF isrc(ksta)=isrc(ista) isrc(ista)=0 stn(ksta)=stn(ista)(1:3)//stn(jmin)(3:4) ! !----------------------------------------------------------------------- ! ! Note here that iqspr designates which variable's q ! is used to weight the locations and elevation. General ! this should be a pressure variable, since the pressure ! reduction will be affected by the resultant elevation. ! !----------------------------------------------------------------------- ! qinvi=1./qobs(iqspr,ista) qinvj=1./qobs(iqspr,jmin) qobloc=1./(qinvi + qinvj) xsta(ksta)=qobloc* & ( qinvi*xsta(ista) + qinvj*xsta(jmin) ) ysta(ksta)=qobloc* & ( qinvi*ysta(ista) + qinvj*ysta(jmin) ) elevsta(ksta)=qobloc* & ( qinvi*elevsta(ista) + qinvj*elevsta(jmin) ) ! !----------------------------------------------------------------------- ! ! Combine each variable, weighting by the inverse of qobs ! !----------------------------------------------------------------------- ! DO ivar=1,nvar IF(qual(ivar,ista) > 0) THEN IF(qual(ivar,jmin) > 0) THEN PRINT *, ' SUPR qobs(ivar,ista): ',qobs(ivar,ista) PRINT *, ' SUPR qobs(ivar,jmin): ',qobs(ivar,ista) qinvi=1./qobs(ivar,ista) qinvj=1./qobs(ivar,jmin) qobs(ivar,ksta)=1./(qinvi + qinvj) obs(ivar,ksta)=qobs(ivar,ksta)* & (qinvi*obs(ivar,ista) + & qinvj*obs(ivar,jmin) ) ! print *, ' ivar= ',ivar ! print *, ' old= ',obs(ivar,ista),obs(ivar,jmin) ! print *, ' comb= ',obs(ivar,ksta) qual(ivar,ista)=qcsuper qual(ivar,jmin)=qcsuper ELSE obs(ivar,ksta)=obs(ivar,ista) qobs(ivar,ksta)=qobs(ivar,ista) qual(ivar,ista)=qcsuper END IF ELSE IF(qual(ivar,jmin) > 0) THEN obs(ivar,ksta)=obs(ivar,jmin) qobs(ivar,ksta)=qobs(ivar,jmin) qual(ivar,jmin)=qcsuper ELSE qobs(ivar,ksta)=qobs(ivar,ista) qual(ivar,ista)=qcsuper END IF END DO END IF END IF GO TO 10 200 CONTINUE nobs=kntsta 900 CONTINUE RETURN END SUBROUTINE suprob ! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE ZEROSRC ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE zerosrc(nvar,mxstn,obs,qual,isrc,nsta) 1 ! ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Set isrc to zero if there are no valid data at this ! obs site. ! !----------------------------------------------------------------------- ! ! AUTHOR: Keith Brewster ! !----------------------------------------------------------------------- ! ! Variable Declarations: ! !----------------------------------------------------------------------- ! IMPLICIT NONE INTEGER :: nvar,mxstn REAL :: obs(nvar,mxstn) INTEGER :: qual(nvar,mxstn) INTEGER :: isrc(mxstn) INTEGER :: nsta ! !----------------------------------------------------------------------- ! ! Misc. local variables ! !----------------------------------------------------------------------- ! INTEGER :: ista,ivar INTEGER num_vars ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! Beginning of executable code... ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! DO ista=1,nsta num_vars = 0 DO ivar=1,nvar IF(qual(ivar,ista) > 0) num_vars = num_vars + 1 END DO IF (num_vars == 0) isrc(ista) = 0 END DO RETURN END SUBROUTINE zerosrc ! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE CVTOBSANX ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE cvtobsanx(mxstn,nvar_ob,nvar_anx,nsrc,nobs,nobsrd, & 1,2 stn,isrc,latsta,lonsta,elevsta, & obsrd,kloud,idp3,store_emv,store_amt, & store_hgt,rely,qsrc,rmiss, & obs,qobs,qual,istatus) ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Convert observed surface data to variables to be ! used in the analysis. ! ! !----------------------------------------------------------------------- ! ! AUTHOR: Keith Brewster, CAPS ! July, 1995 ! ! MODIFICATION HISTORY: ! ! 12/01/98 (K. Brewster) ! Removed rotation of winds to avoid duplication later. ! !----------------------------------------------------------------------- ! IMPLICIT NONE ! INTEGER :: mxstn,nvar_ob,nvar_anx,nsrc INTEGER :: nobs,nobsrd CHARACTER (LEN=5) :: stn(mxstn) INTEGER :: isrc(mxstn) REAL :: latsta(mxstn) REAL :: lonsta(mxstn) REAL :: elevsta(mxstn) REAL :: obsrd(mxstn,nvar_ob) INTEGER :: kloud(mxstn),idp3(mxstn) CHARACTER (LEN=1) :: store_emv(mxstn) CHARACTER (LEN=4) :: store_amt(mxstn) REAL :: store_hgt(mxstn,5) INTEGER :: rely(mxstn,nvar_ob) REAL :: qsrc(nvar_anx,nsrc) REAL :: rmiss ! REAL :: obs(nvar_anx,mxstn) REAL :: qobs(nvar_anx,mxstn) INTEGER :: qual(nvar_anx,mxstn) INTEGER :: istatus ! !----------------------------------------------------------------------- ! ! Parameters ! !----------------------------------------------------------------------- ! REAL :: ktstoms,mbtopa PARAMETER (ktstoms=0.5144,mbtopa=100.) ! !----------------------------------------------------------------------- ! ! Conversion functions ! !----------------------------------------------------------------------- ! REAL :: ftoc,alttostpr,msltostpr ! !----------------------------------------------------------------------- ! ! Misc. local variables ! !----------------------------------------------------------------------- ! INTEGER :: iob,kob,ivar,jsrc,nprev REAL :: tf,psta,tk,tdk,qv,qvsat ! !----------------------------------------------------------------------- ! ! Include files ! !----------------------------------------------------------------------- ! INCLUDE 'phycst.inc' ! !----------------------------------------------------------------------- ! ! Function f_qvsat and inline directive for Cray PVP ! !----------------------------------------------------------------------- ! REAL :: f_qvsat !fpp$ expand (f_qvsat) !dir$ inline always f_qvsat !*$* inline routine (f_qvsat) ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! Beginning of executable code... ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ftoc(tf)=5.*(tf-32.)/9. nprev=nobs ! DO ivar=1,nvar_anx DO iob=nprev+1,(nprev+nobsrd) obs(ivar,iob)=rmiss qobs(ivar,iob)=999. qual(ivar,iob)=-999 END DO END DO ! DO iob=1,nobsrd kob=nprev+iob IF(isrc(kob) /= 0) THEN jsrc=isrc(kob) ! !----------------------------------------------------------------------- ! ! Winds, u,v kts to m/s ! !----------------------------------------------------------------------- ! IF(obsrd(kob,5) > rmiss .AND. obsrd(kob,6) > rmiss .AND. & rely(kob,5) > 0 .AND. rely(kob,6) > 0 ) THEN obs(1,kob)=obsrd(kob,5)*ktstoms obs(2,kob)=obsrd(kob,6)*ktstoms qobs(1,kob)=qsrc(1,jsrc) qobs(2,kob)=qsrc(2,jsrc) qual(1,kob)=100 qual(2,kob)=100 END IF ! !----------------------------------------------------------------------- ! ! Station pressure (mb) ! For now we'll convert msl pressure to station pressure ! using the current temperature. ! !----------------------------------------------------------------------- ! IF(obsrd(kob,7) > rmiss .AND. rely(kob,7) > 0) THEN psta=mbtopa*obsrd(kob,7) obs(3,kob)=psta qobs(3,kob)=qsrc(3,jsrc) qual(3,kob)=100 ELSE IF(obsrd(kob,9) > rmiss .AND. rely(kob,9) > 0) THEN psta=mbtopa*alttostpr(obsrd(kob,9),elevsta(kob)) obs(3,kob)=psta qobs(3,kob)=qsrc(3,jsrc) qual(3,kob)=100 ELSE IF(obsrd(kob,8) > rmiss .AND. & obsrd(kob,1) > rmiss .AND. & rely(kob,8) > 0 .AND. rely(kob,1) > 0 .AND. & elevsta(kob) < 500. ) THEN tk=ftoc(obsrd(kob,1)) + 273.15 psta=mbtopa*msltostpr(obsrd(kob,8),tk,elevsta(kob)) ! print *, ' msl,elev,stpr: ', ! : obsrd(kob,8),elevsta(kob),(0.01*psta) obs(3,kob)=psta qobs(3,kob)=qsrc(3,jsrc) qual(3,kob)=100 ELSE IF(obsrd(kob,8) > rmiss .AND. rely(kob,8) > 0 .AND. & elevsta(kob) == 0. ) THEN psta=mbtopa*obsrd(kob,8) obs(3,kob)=psta qobs(3,kob)=qsrc(3,jsrc) qual(3,kob)=100 ELSE psta=mbtopa*alttostpr(1013.,elevsta(kob)) END IF ! print *, ' stn,pr,qobs,qual: ',stn(kob),obs(3,kob), ! : qobs(3,kob),qual(3,kob) ! !----------------------------------------------------------------------- ! ! Potential temperature (K) ! !----------------------------------------------------------------------- ! IF(obsrd(kob,1) > rmiss .AND. rely(kob,1) > 0) THEN tk=ftoc(obsrd(kob,1)) + 273.15 obs(4,kob)=tk*((p0/psta)**rddcp) qobs(4,kob)=qsrc(4,jsrc) qual(4,kob)=100 END IF ! !----------------------------------------------------------------------- ! ! Specific humidity (kg/kg) ! !----------------------------------------------------------------------- ! IF(obsrd(kob,1) > rmiss .AND. obsrd(kob,2) > rmiss .AND. & rely(kob,1) > 0 .AND. rely(kob,2) > 0 ) THEN tk=ftoc(obsrd(kob,1)) + 273.15 tdk=ftoc(obsrd(kob,2)) + 273.15 qv = f_qvsat( psta,tdk ) qvsat = f_qvsat( psta, tk ) obs(5,kob)=MAX(1.0E-08,qv) qobs(5,kob)=qsrc(5,jsrc) qual(5,kob)=100 END IF END IF END DO RETURN END SUBROUTINE cvtobsanx ! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE SETISRC ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE setisrc(mxstn,nsrc,nobs,name_src, & 1 chsrc,isrc) ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Assign source number to observations based on read-in ! source name. ! !----------------------------------------------------------------------- ! ! AUTHOR: Keith Brewster, CAPS ! Aug, 1997 ! !----------------------------------------------------------------------- ! ! Variable Declarations: ! !----------------------------------------------------------------------- ! IMPLICIT NONE INTEGER :: mxstn,nsrc INTEGER :: nobs CHARACTER (LEN=8) :: name_src(nsrc) CHARACTER (LEN=8) :: chsrc(mxstn) INTEGER :: isrc(mxstn) ! !----------------------------------------------------------------------- ! ! Misc. local variables ! !----------------------------------------------------------------------- ! INTEGER :: iob,jsrc ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! Beginning of executable code... ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! DO iob=1,nobs DO jsrc=1,nsrc IF(chsrc(iob) == name_src(jsrc)) GO TO 120 END DO WRITE(6,'(a,a)') chsrc(iob),' source not matched ' isrc(iob)=0 CYCLE 120 CONTINUE isrc(iob)=jsrc ! write(6,'(a,a,i4)') chsrc(iob), & ! ' source matched isrc=',isrc(iob) END DO ! RETURN END SUBROUTINE setisrc ! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE QCDATA ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE qcdata(mxstn,nsrc,nvar_ob,ntime,nobs,nobsrd,stn,chsrc, & 1,2 latsta,lonsta,xsta,ysta,elevsta, & wx,obsrd,kloud,idp3,store_emv, & store_amt,store_hgt,obstime, & climin,climax,rely,ival,istatus) ! ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! !----------------------------------------------------------------------- ! ! AUTHOR: Ming Xue IMPLICIT NONE INTEGER :: mxstn,nsrc,nvar_ob,ntime ! !----------------------------------------------------------------------- ! ! Arrays for the input obs at two different times ! !----------------------------------------------------------------------- ! INTEGER :: nobs,nobsrd(ntime) REAL :: latsta(mxstn,ntime),lonsta(mxstn,ntime) REAL :: elevsta(mxstn,ntime) REAL :: xsta(mxstn),ysta(mxstn) INTEGER :: obstime(mxstn,ntime) CHARACTER (LEN=5) :: stn(mxstn,ntime) CHARACTER (LEN=8) :: chsrc(mxstn,ntime) CHARACTER (LEN=8) :: wx(mxstn,ntime) CHARACTER (LEN=1) :: store_emv(mxstn,5,ntime) CHARACTER (LEN=4) :: store_amt(mxstn,5,ntime) INTEGER :: kloud(mxstn,ntime),idp3(mxstn,ntime) REAL :: store_hgt(mxstn,5,ntime) REAL :: obsrd(mxstn,nvar_ob,ntime) REAL :: climin(nvar_ob),climax(nvar_ob) INTEGER :: rely(mxstn,nvar_ob,ntime) INTEGER :: ival(mxstn) ! !----------------------------------------------------------------------- ! ! Misc. local variables ! !----------------------------------------------------------------------- ! REAL :: missing INTEGER :: ktime,jvar,iob,kob INTEGER :: imissing,istatus,jstatus ! PARAMETER ( missing = -99.9, & imissing = -99) ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! Beginning of executable code... ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! istatus = 0 ! WRITE(6,'(a)') ' ** begin temporal qc on surface data ' ! DO ktime=1,ntime DO jvar=1,nvar_ob DO iob=1,mxstn rely(iob,jvar,ktime) = imissing END DO END DO END DO ! !----------------------------------------------------------------------- ! ! Climatological extreme test ! !----------------------------------------------------------------------- ! WRITE(6,'(a,i5,i6)') ' # of data stns available: ', & nobsrd(1),nobsrd(2) IF(nobsrd(1) <= 0 .OR. nobsrd(2) <= 0) THEN PRINT *, ' No data for current and/or previous hr..stop QC.' RETURN END IF ! DO jvar = 1,nvar_ob DO iob = 1,nobsrd(1) kob=nobs+iob IF(obsrd(kob,jvar,1) >= climin(jvar) .AND. & obsrd(kob,jvar,1) <= climax(jvar) ) & rely(kob,jvar,1)=10 END DO END DO DO jvar = 1,nvar_ob DO iob = 1,nobsrd(2) IF(obsrd(iob,jvar,2) >= climin(jvar) .AND. & obsrd(iob,jvar,2) <= climax(jvar) ) & rely(iob,jvar,2)=10 END DO END DO ! ! DO 150 iob =1,nobs(ktime) ! IF(kloud(m,ktime) .gt. 0) THEN ! DO 110 k=1,kloud(m,ktime) ! IF(store_emv(m,k,ktime) .eq. ' ' .OR. ! : store_emv(m,k,ktime) .eq. 'E' .OR. ! : store_emv(m,k,ktime) .eq. 'M' .OR. ! : store_emv(m,k,ktime) .eq. 'V' ) ! : rely(22,m)=10 ! IF(store_hgt(m,k) .ge. 0. .and. store_hgt(m,k) .le. 22500.) ! : rely(24,m)=10 !110 CONTINUE ! END IF !150 CONTINUE ! ! 200 CONTINUE ! CALL sta_match(mxstn,ntime,nobs,nobsrd,stn,chsrc,ival) ! !----------------------------------------------------------------------- ! ! Standard deviation check ! !----------------------------------------------------------------------- ! DO jvar=1,nvar_ob CALL dev_ck(mxstn,nvar_ob,ntime,jvar,nobs,nobsrd, & obsrd,rely,ival) END DO ! !----------------------------------------------------------------------- ! ! Temporal QC finished ! !----------------------------------------------------------------------- ! jstatus = 1 WRITE(6,'(a)')' ** temporal QC of surface data complete. ** ' RETURN END SUBROUTINE qcdata ! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE STA_MATCH ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE sta_match(mxstn,ntime,nobs,nobsrd,stn,chsrc,ival) 1 ! ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Match-up stations by their name and source name. ! This provides a mapping of the data from one time to another. ! ! !----------------------------------------------------------------------- ! ! AUTHOR: ! !----------------------------------------------------------------------- ! ! Variable Declarations: ! !----------------------------------------------------------------------- ! IMPLICIT NONE ! INTEGER :: mxstn,ntime INTEGER :: nobs INTEGER :: nobsrd(ntime) CHARACTER (LEN=5) :: stn(mxstn,ntime) CHARACTER (LEN=8) :: chsrc(mxstn,ntime) INTEGER :: ival(mxstn) ! !----------------------------------------------------------------------- ! ! Misc. local variables ! !----------------------------------------------------------------------- ! INTEGER :: m,n,kntno,kob ! kntno=0 DO n=1,nobsrd(1) kob=n+nobs ival(kob) = -99 DO m=1,nobsrd(2) IF ( stn(m,2) == stn(kob,1) ) THEN IF( chsrc(m,2) == chsrc(kob,1) ) THEN ival(kob) = m GO TO 20 END IF END IF END DO kntno=kntno+1 ! print *, ' Cannot find match for ',stn(kob,1) 20 CONTINUE END DO WRITE(6,'(a,i4,a,/a,i4,a)') & ' FYI from sta_match: ',kntno,' stations ', & ' of ',nobsrd(1),' were not matched.' RETURN END SUBROUTINE sta_match ! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE DEV_CHK ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE dev_ck(mxstn,nvar_ob,ntime,ivar,nobs,nobsrd, & 1 obsrd,rely,ival) ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Check hourly changes for an individual observed ! variable. A mean hourly change is computed for the whole ! field and the change at an individual station is compared ! to the rms change for the group. ! ! ! !----------------------------------------------------------------------- ! ! AUTHOR: ! Original version: FSL LAPS team ! Restructured to remove local storage arrays ! Keith Brewster, CAPS, March, 1994. ! ! ! !----------------------------------------------------------------------- ! ! Variable Declarations: ! !----------------------------------------------------------------------- ! IMPLICIT NONE ! INTEGER :: mxstn,nvar_ob,ntime INTEGER :: ivar INTEGER :: nobs,nobsrd(ntime) REAL :: obsrd(mxstn,nvar_ob,ntime) INTEGER :: rely(mxstn,nvar_ob,ntime) INTEGER :: ival(mxstn) ! INTEGER :: m,n,numdiff,kob REAL :: missing,diff,sumdiff,sumsq,std,avgdiff REAL :: diffnor ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! Beginning of executable code... ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! missing = -99. ! !----------------------------------------------------------------------- ! ! Compute avg change from prev hr (omit mesonet pressures) ! !----------------------------------------------------------------------- ! std=0. avgdiff=0. sumdiff=0. sumsq=0. numdiff = 0 DO n=1,nobsrd(1) kob=n+nobs m = ival(kob) IF(m > 0) THEN IF(obsrd(kob,ivar,1) > missing .AND. obsrd(m,ivar,2) > missing .AND. & rely(m,ivar,2) > 0) THEN diff = obsrd(kob,ivar,1) - obsrd(m,ivar,2) numdiff = numdiff + 1 sumdiff = sumdiff + diff sumsq=sumsq+diff*diff END IF END IF END DO ! !----------------------------------------------------------------------- ! ! Compute average and standard deviation of hourly change. ! !----------------------------------------------------------------------- ! IF (numdiff < 2) THEN WRITE(6,'(a)') ' numdiff<2...no dev_ck done.' RETURN ELSE avgdiff = sumdiff/FLOAT(numdiff) sumsq = sumsq - sumdiff*avgdiff IF(sumsq > 0. .AND. numdiff > 1) std=SQRT(sumsq/FLOAT((numdiff-1))) END IF ! IF (std == 0.) THEN WRITE(6,'(a)') ' std dev = 0., dev_ck not completed...' RETURN ELSE ! !----------------------------------------------------------------------- ! ! Add or subtract reliability points based on the ! hourly difference normalized by the std. ! !----------------------------------------------------------------------- ! WRITE(6,'(a,i4,a,f10.2,a,f10.2)') ' Hourly change: ivar=',ivar, & ' mean= ',avgdiff,' stddev= ',std DO n=1,nobsrd(1) kob=n+nobs m = ival(kob) IF(m > 0) THEN IF(obsrd(kob,ivar,1) > missing .AND. obsrd(m,ivar,2) > missing .AND. & rely(m,ivar,2) > 0) THEN diff=ABS(obsrd(kob,ivar,1)-obsrd(m,ivar,2)-avgdiff) diffnor=diff/std IF(diffnor > 4.) THEN rely(kob,ivar,1)=rely(kob,ivar,1)-25 ELSE rely(kob,ivar,1)=rely(kob,ivar,1)+25 END IF END IF END IF END DO WRITE(6,'(a,i4)') ' subr dev_ck complete ', ivar END IF RETURN END SUBROUTINE dev_ck