source: trunk/WRF.COMMON/WRFV2/phys/module_fddaobs_rtfdda.F @ 3567

Last change on this file since 3567 was 11, checked in by aslmd, 14 years ago

spiga@svn-planeto:ajoute le modele meso-echelle martien

File size: 87.0 KB
Line 
1!WRF:MODEL_LAYER:PHYSICS
2!
3MODULE module_fddaobs_rtfdda
4
5! This obs-nudging FDDA module (RTFDDA) is developed by the
6! NCAR/RAL/NSAP (National Security Application Programs), under the
7! sponsorship of ATEC (Army Test and Evaluation Commands). ATEC is
8! acknowledged for releasing this capability for WRF community
9! research applications.
10!
11! The NCAR/RAL RTFDDA module was adapted, and significantly modified
12! from the obs-nudging module in the standard MM5V3.1 which was originally
13! developed by PSU (Stauffer and Seaman, 1994).
14!
15! Yubao Liu (NCAR/RAL): lead developer of the RTFDDA module
16! Al Bourgeois (NCAR/RAL): lead engineer implementing RTFDDA into WRF-ARW
17! Nov. 2006
18!
19! References:
20!   
21!   Liu, Y., A. Bourgeois, T. Warner, S. Swerdlin and J. Hacker, 2005: An
22!     implementation of obs-nudging-based FDDA into WRF for supporting
23!     ATEC test operations. 2005 WRF user workshop. Paper 10.7.
24!
25!   Liu, Y., A. Bourgeois, T. Warner, S. Swerdlin and W. Yu, 2006: An update
26!     on "obs-nudging"-based FDDA for WRF-ARW: Verification using OSSE
27!     and performance of real-time forecasts. 2006 WRF user workshop. Paper 4.7.
28
29!   
30!   Stauffer, D.R., and N.L. Seaman, 1994: Multi-scale four-dimensional data
31!     assimilation. J. Appl. Meteor., 33, 416-434.
32!
33!   http://www.rap.ucar.edu/projects/armyrange/references.html
34!
35
36CONTAINS
37
38!------------------------------------------------------------------------------
39  SUBROUTINE fddaobs_init(obs_nudge_opt, maxdom, inest, parid,         &
40                          dx_coarse, restart, obs_twindo, itimestep,   &
41                          e_sn, s_sn_cg, e_sn_cg, s_we_cg, e_we_cg,    &
42#if ( EM_CORE == 1 )
43                          fdob,                                        &
44#endif
45                          ids,ide, jds,jde, kds,kde,                   &
46                          ims,ime, jms,jme, kms,kme,                   &
47                          its,ite, jts,jte, kts,kte)     
48!-----------------------------------------------------------------------
49!  This routine does initialization for real time fdda obs-nudging.
50!
51!-----------------------------------------------------------------------
52  USE module_domain
53!-----------------------------------------------------------------------
54  IMPLICIT NONE
55!-----------------------------------------------------------------------
56
57!=======================================================================
58! Definitions
59!-----------
60  INTEGER, intent(in)  :: maxdom
61  INTEGER, intent(in)  :: obs_nudge_opt(maxdom)
62  INTEGER, intent(in)  :: ids,ide, jds,jde, kds,kde,                 &
63                          ims,ime, jms,jme, kms,kme,                 &
64                          its,ite, jts,jte, kts,kte
65  INTEGER, intent(in)  :: inest
66  INTEGER, intent(in)  :: parid(maxdom)
67  REAL    ,intent(in)  :: dx_coarse    ! coarse-domain grid cell-size (km)
68  LOGICAL, intent(in)  :: restart
69  REAL, intent(inout)  :: obs_twindo
70  INTEGER, intent(in)  :: itimestep
71  INTEGER, intent(in)  :: e_sn         ! ending   south-north grid index
72  INTEGER, intent(in)  :: s_sn_cg      ! starting south-north coarse-grid index
73  INTEGER, intent(in)  :: e_sn_cg      ! ending   south-north coarse-grid index
74  INTEGER, intent(in)  :: s_we_cg      ! starting west-east   coarse-grid index
75  INTEGER, intent(in)  :: e_we_cg      ! ending   west-east   coarse-grid index
76#if ( EM_CORE == 1 )
77  TYPE(fdob_type), intent(inout)  :: fdob
78#endif
79
80! Local variables
81  logical            :: nudge_flag      ! nudging flag for this nest
82  integer            :: ktau            ! current timestep
83  integer            :: nest            ! loop counter
84  integer            :: idom            ! domain id
85  integer            :: parent          ! parent domain
86
87#if ( EM_CORE == 1 )
88! This routine should only be called once. This is a check to make
89! certain that initialization only happens once.
90  if (fdob%domain_init .ne. 1) then
91!   Obs-nudging will be initialized on this call
92    fdob%domain_init = 1
93  else
94!   Obs-nudging has already been initialized, so return
95    return
96  endif
97
98! Set flag for nudging on pressure (not sigma) surfaces
99  fdob%iwtsig = 0
100
101! Set ending nudging date (used with dynamic ramp-down) to zero.
102  fdob%datend = 0.
103
104! Convert twindo from minutes to hours.
105  obs_twindo = obs_twindo / 60.
106
107! Initialize flags.
108
109  fdob%domain_tot=0
110  do nest=1,maxdom
111    fdob%domain_tot = fdob%domain_tot + obs_nudge_opt(nest)
112  end do
113
114! Set parameters.
115
116  fdob%pfree = 50.0
117  fdob%rinfmn = 1.0
118  fdob%rinfmx = 2.0
119  fdob%dpsmx = 7.5
120  fdob%dcon = 1.0/fdob%dpsmx
121  fdob%xn = 0.7155668                     ! cone factor
122
123  fdob%ds_cg = dx_coarse / 1000.          ! coarse gridsize (km)
124  fdob%sn_maxcg = e_sn_cg - s_sn_cg + 1   ! coarse domain grid dimension in N-S
125  fdob%we_maxcg = e_we_cg - s_we_cg + 1   ! coarse domain grid dimension in W-E
126  fdob%sn_end = e_sn - 1                  ! ending S-N grid coordinate
127
128! Calculate the nest levels, levidn. Note that each nest
129! must know the nest levels levidn(maxdom) of each domain.
130  do nest=1,maxdom
131
132! Initialize nest level for each domain.
133    if (nest .eq. 1) then
134      fdob%levidn(nest) = 0  ! Mother domain has nest level 0
135    else
136      fdob%levidn(nest) = 1  ! All other domains start with 1
137    endif
138    idom = nest
139100 parent = parid(idom)      ! Go up the parent tree
140      if (parent .gt. 1) then   ! If not up to mother domain
141        fdob%levidn(nest) = fdob%levidn(nest) + 1
142        idom = parid(parent)
143        goto 100
144      endif
145  enddo
146
147! Check to see if the nudging flag has been set. If not,
148! simply RETURN.
149  nudge_flag = (obs_nudge_opt(inest) .eq. 1)
150  if (.not. nudge_flag) return
151
152  ktau  = itimestep
153  if(restart) then
154    fdob%ktaur = ktau
155  else
156    fdob%ktaur = 0
157  endif
158
159  RETURN
160#endif
161  END SUBROUTINE fddaobs_init
162
163#if ( EM_CORE == 1 )
164!-----------------------------------------------------------------------
165SUBROUTINE errob(inest, ub, vb, tb, t0, qvb, pbase, pp, rovcp,  &
166                 uratx, vratx, tratx, nndgv,                    &
167                 nerrf, niobf, maxdom, levidn, parid, nstat,    &
168                 iswind,                                        &
169                 istemp, ismois, ispstr, rio, rjo, rko, varobs, &
170                 errf, i_parent_start, j_parent_start,          &
171                 ktau, iratio, npfi, iprt,                      &
172                 ids,ide, jds,jde, kds,kde,                     &
173                 ims,ime, jms,jme, kms,kme,                     &
174                 its,ite, jts,jte, kts,kte  )
175
176!-----------------------------------------------------------------------
177#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
178  USE module_dm, ONLY : get_full_obs_vector
179#endif
180
181!-----------------------------------------------------------------------
182  IMPLICIT NONE
183!-----------------------------------------------------------------------
184!
185! PURPOSE: THIS SUBROUTINE CALCULATES THE DIFFERENCE BETWEEN THE
186!     OBSERVED VALUES AND THE FORECAST VALUES AT THE OBSERVATION
187!     POINTS.  THE OBSERVED VALUES CLOSEST TO THE CURRENT
188!     FORECAST TIME (XTIME) WERE DETERMINED IN SUBROUTINE
189!     IN4DOB AND STORED IN ARRAY VAROBS.  THE DIFFERENCES
190!     CALCULATED BY SUBROUTINE ERROB WILL BE STORED IN ARRAY
191!     ERRF FOR THE NSTA OBSERVATION LOCATIONS.  MISSING
192!     OBSERVATIONS ARE DENOTED BY THE DUMMY VALUE 99999.
193!
194!     HISTORY: Original author: MM5 version???
195!              02/04/2004 - Creation of WRF version.           Al Bourgeois
196!              08/28/2006 - Conversion from F77 to F90         Al Bourgeois
197!------------------------------------------------------------------------------
198
199! THE STORAGE ORDER IN VAROBS AND ERRF IS AS FOLLOWS:
200!        IVAR                VARIABLE TYPE(TAU-1)
201!        ----                --------------------
202!         1                    U error
203!         2                    V error
204!         3                    T error
205!         4                    Q error
206!         5                    Surface press error at T points (not used)
207!         6                    Model surface press at T-points
208!         7                    Model surface press at U-points
209!         8                    Model surface press at V-points
210!         9                    RKO at U-points
211
212!-----------------------------------------------------------------------
213!
214!     Description of input arguments.
215!
216!-----------------------------------------------------------------------
217
218  INTEGER, INTENT(IN)  :: inest                        ! Domain index.
219  INTEGER, INTENT(IN)  :: nndgv                        ! Number of nudge variables.
220  INTEGER, INTENT(IN)  :: nerrf                        ! Number of error fields.
221  INTEGER, INTENT(IN)  :: niobf                        ! Number of observations.
222  INTEGER, INTENT(IN)  :: maxdom                       ! Maximum number of domains.
223  INTEGER, INTENT(IN)  :: levidn(maxdom)               ! Level of nest.
224  INTEGER, INTENT(IN)  :: parid(maxdom)                ! Id of parent grid.
225  INTEGER, INTENT(IN)  :: i_parent_start(maxdom)       ! Start i index in parent domain.
226  INTEGER, INTENT(IN)  :: j_parent_start(maxdom)       ! Start j index in parent domain.
227  INTEGER, INTENT(IN)  :: ktau
228  INTEGER, INTENT(IN)  :: iratio                       ! Nest to parent gridsize ratio.
229  INTEGER, INTENT(IN)  :: npfi                         ! Coarse-grid diagnostics freq.
230  LOGICAL, INTENT(IN)  :: iprt                         ! Print flag
231  INTEGER, INTENT(IN)  :: nstat
232  INTEGER, intent(in)  :: iswind
233  INTEGER, intent(in)  :: istemp
234  INTEGER, intent(in)  :: ismois
235  INTEGER, intent(in)  :: ispstr
236  INTEGER, INTENT(IN)  :: ids,ide, jds,jde, kds,kde  ! domain dims.
237  INTEGER, INTENT(IN)  :: ims,ime, jms,jme, kms,kme  ! memory dims.
238  INTEGER, INTENT(IN)  :: its,ite, jts,jte, kts,kte  ! tile   dims.
239
240  REAL,   INTENT(IN) :: ub( ims:ime, kms:kme, jms:jme )
241  REAL,   INTENT(IN) :: vb( ims:ime, kms:kme, jms:jme )
242  REAL,   INTENT(IN) :: tb( ims:ime, kms:kme, jms:jme )
243  REAL,   INTENT(IN) :: t0
244  REAL,   INTENT(IN) :: qvb( ims:ime, kms:kme, jms:jme )
245  REAL,   INTENT(IN) :: pbase( ims:ime, kms:kme, jms:jme )
246  REAL,   INTENT(IN) :: pp( ims:ime, kms:kme, jms:jme ) ! Press. perturbation (Pa)
247  REAL,   INTENT(IN)  :: rovcp
248  REAL,   INTENT(IN) :: uratx( ims:ime, jms:jme ) ! U to U10 ratio on mass points.
249  REAL,   INTENT(IN) :: vratx( ims:ime, jms:jme ) ! V to V10 ratio on mass points.
250  REAL,   INTENT(IN) :: tratx( ims:ime, jms:jme ) ! T to TH2 ratio on mass points.
251  REAL,   INTENT(IN) :: rio(niobf)                ! West-east coordinate.
252  REAL,   INTENT(IN) :: rjo(niobf)                ! South-north coordinate.
253  REAL,   INTENT(INOUT) :: rko(niobf)
254  REAL,   INTENT(INOUT) :: varobs(nndgv, niobf)
255  REAL,   INTENT(INOUT) :: errf(nerrf, niobf)
256
257! Local variables
258  INTEGER :: iobmg(niobf)   ! Obs i-coord on mass grid
259  INTEGER :: jobmg(niobf)   ! Obs j-coord on mass grid
260  INTEGER :: ia(niobf)
261  INTEGER :: ib(niobf)
262  INTEGER :: ic(niobf)
263  REAL :: pbbo(kds:kde)    ! column base pressure (cb) at obs loc.
264  REAL :: ppbo(kds:kde)    ! column pressure perturbation (cb) at obs loc.
265
266  REAL :: ra(niobf)
267  REAL :: rb(niobf)
268  REAL :: rc(niobf)
269  REAL :: dxobmg(niobf)     ! Interp. fraction (x dir) referenced to mass-grid
270  REAL :: dyobmg(niobf)     ! Interp. fraction (y dir) referenced to mass-grid
271  INTEGER MM(MAXDOM)
272  INTEGER NNL
273  real :: uratio( ims:ime, jms:jme )   ! U to U10 ratio on momentum points.
274  real :: vratio( ims:ime, jms:jme )   ! V to V10 ratio on momentum points.
275  real :: pug1,pug2,pvg1,pvg2
276
277! Define staggers for U, V, and T grids, referenced from non-staggered grid.
278  real, parameter :: gridx_t = 0.5     ! Mass-point x stagger
279  real, parameter :: gridy_t = 0.5     ! Mass-point y stagger
280  real, parameter :: gridx_u = 0.0     ! U-point x stagger
281  real, parameter :: gridy_u = 0.5     ! U-point y stagger
282  real, parameter :: gridx_v = 0.5     ! V-point x stagger
283  real, parameter :: gridy_v = 0.0     ! V-point y stagger
284
285  real :: dummy = 99999.
286
287  real :: pbhi, pphi
288  real :: press,ttemp                  !ajb scratch variables
289! real model_temp,pot_temp             !ajb scratch variables
290
291!***  DECLARATIONS FOR IMPLICIT NONE
292  integer nsta,ivar,n,ityp
293  integer iob,job,kob,iob_ms,job_ms
294  integer k,kbot,nml,nlb,nle
295  integer iobm,jobm,iobp,jobp,kobp,inpf,i,j
296  integer i_start,i_end,j_start,j_end    ! loop ranges for uratio,vratio calc.
297  integer k_start,k_end
298
299  real gridx,gridy,dxob,dyob,dzob,dxob_ms,dyob_ms
300  real pob
301  real grfacx,grfacy,uratiob,vratiob,tratiob,tratxob,fnpf
302  real stagx                       ! For x correction to mass-point stagger
303  real stagy                       ! For y correction to mass-point stagger
304
305#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
306  LOGICAL MP_LOCAL_DUMMASK(NIOBF)  ! Mask for work to be done on this processor
307  LOGICAL MP_LOCAL_UOBMASK(NIOBF)  ! Dot-point mask
308  LOGICAL MP_LOCAL_VOBMASK(NIOBF)  ! Dot-point mask
309  LOGICAL MP_LOCAL_COBMASK(NIOBF)  ! Cross-point mask
310#endif
311! LOGICAL, EXTERNAL :: TILE_MASK
312
313  NSTA=NSTAT
314
315! FIRST, DETERMINE THE GRID TYPE CORRECTION FOR U-momentum, V-momentum,
316! AND MASS POINTS, AND WHEN INEST=2, CONVERT THE STORED COARSE MESH INDICES
317! TO THE FINE MESH INDEX EQUIVALENTS
318
319! ITYP=1 FOR U-POINTS, ITYP=2 for V-POINTS, and ITYP=3 FOR MASS POINTS
320
321  if (iprt) then
322    write(6,'(a,i5,a,i2,a,i5,a)') '++++++CALL ERROB AT KTAU = ', &
323            KTAU,' AND INEST = ',INEST,':  NSTA = ',NSTA,' ++++++'
324  endif
325
326  ERRF = 0.0    ! Zero out errf array
327
328! Set up loop bounds for this grid's boundary conditions
329  i_start = max( its-1,ids )
330  i_end   = min( ite+1,ide-1 )
331  j_start = max( jts-1,jds )
332  j_end   = min( jte+1,jde-1 )
333  k_start = kts
334  k_end = min( kte, kde-1 )
335
336  DO ITYP=1,3   ! Big loop: ityp=1 for U, ityp=2 for V, ityp=3 for T,Q,SP
337
338!   Set grid stagger
339    IF(ITYP.EQ.1) THEN        ! U-POINT CASE
340       GRIDX = gridx_u
341       GRIDY = gridy_u
342    ELSE IF(ITYP.EQ.2) THEN   ! V-POINT CASE
343       GRIDX = gridx_v
344       GRIDY = gridy_v
345    ELSE                      ! MASS-POINT CASE
346       GRIDX = gridx_t
347       GRIDY = gridy_t
348    ENDIF
349
350!   Compute URATIO and VRATIO fields on momentum (u,v) points.
351    IF(ityp.eq.1)THEN
352      call upoint(i_start,i_end, j_start,j_end, ids,ide, ims,ime, jms,jme, uratx, uratio)
353    ELSE IF (ityp.eq.2) THEN
354      call vpoint(i_start,i_end, j_start,j_end, jds,jde, ims,ime, jms,jme, vratx, vratio)
355    ENDIF
356
357    IF(INEST.EQ.1) THEN       ! COARSE MESH CASE...
358      DO N=1,NSTA
359        RA(N)=RIO(N)-GRIDX
360        RB(N)=RJO(N)-GRIDY
361        IA(N)=RA(N)
362        IB(N)=RB(N)
363        IOB=MAX0(1,IA(N))
364        IOB=MIN0(IOB,ide-1)
365        JOB=MAX0(1,IB(N))
366        JOB=MIN0(JOB,jde-1)
367        DXOB=RA(N)-FLOAT(IA(N))
368        DYOB=RB(N)-FLOAT(IB(N))
369
370!       Save mass-point arrays for computing rko for all var types
371        if(ityp.eq.1) then
372          iobmg(n) = MIN0(MAX0(1,int(RIO(n)-gridx_t)),ide-1)
373          jobmg(n) = MIN0(MAX0(1,int(RJO(n)-gridy_t)),jde-1)
374          dxobmg(n) = RIO(N)-gridx_t-FLOAT(int(RIO(N)-gridx_t))
375          dyobmg(n) = RJO(N)-gridy_t-FLOAT(int(RJO(N)-gridy_t))
376        endif
377        iob_ms = iobmg(n)
378        job_ms = jobmg(n)
379        dxob_ms = dxobmg(n)
380        dyob_ms = dyobmg(n)
381
382
383!if(n.eq.1 .and. iprt) then
384!        write(6,*) 'ERROB - COARSE MESH:'
385!        write(6,'(a,i1,a,i1,4(a,f5.2),2(a,i3),2(a,f6.3))') 'OBS= ',n,  &
386!                   '  ityp= ',ityp,                                    &
387!                   '  ra= ',ra(n),'  rb= ',rb(n),                      &
388!                   '  rio= ',rio(n),'  rjo= ',rjo(n),                  &
389!                   '  iob= ',iob,'  job= ',job,                        &
390!                   '  dxob= ',dxob,'  dyob= ',dyob
391!        write(6,'(a,i3,a,i3,a,f5.2,a,f5.2)')                           &
392!                   '  iob_ms= ',iob_ms,'  job_ms= ',job_ms,            &
393!                   '  dxob_ms= ',dxob_ms,'  dyob_ms= ',dyob_ms
394!endif
395
396#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
397!       Set mask for obs to be handled by this processor
398        MP_LOCAL_DUMMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
399 
400        IF ( MP_LOCAL_DUMMASK(N) ) THEN
401#endif
402
403!         Interpolate pressure to obs location column and convert from Pa to cb.
404
405          do k = kds, kde
406            pbbo(k) = .001*(                                            &
407               (1.-DYOB_MS)*( (1.-DXOB_MS)*pbase(IOB_MS,K,JOB_MS) +     &
408                                  DXOB_MS *pbase(IOB_MS+1,K,JOB_MS) ) + &
409                   DYOB_MS* ( (1.-DXOB_MS)*pbase(IOB_MS,K,JOB_MS+1) +   &
410                                  DXOB_MS *pbase(IOB_MS+1,K,JOB_MS+1) ) ) 
411            ppbo(k) = .001*(                                            &
412               (1.-DYOB_MS)*( (1.-DXOB_MS)*pp(IOB_MS,K,JOB_MS) +        &
413                                  DXOB_MS *pp(IOB_MS+1,K,JOB_MS) ) +    &
414                   DYOB_MS* ( (1.-DXOB_MS)*pp(IOB_MS,K,JOB_MS+1) +      &
415                                  DXOB_MS *pp(IOB_MS+1,K,JOB_MS+1) ) ) 
416
417!     write(6,'(a,i2,2(a,f9.3)') ' k= ',k,' pbbo= ',pbbo(k),' ppbo= ',ppbo(k)
418          enddo
419
420!ajb      20040119: Note based on bugfix for dot/cross points split across processors,
421!ajb                which was actually a serial code fix: The ityp=2 (v-points) and
422!ajb                itype=3 (mass-points) cases should not use the ityp=1 (u-points)
423!ajb                case rko! This is necessary for bit-for-bit reproducability
424!ajb                with the parallel run.   (coarse mesh)
425
426
427          if(abs(rko(n)+99).lt.1.)then
428            pob = varobs(5,n)
429
430            if(pob .gt.-800000.)then
431              do k=k_end-1,1,-1
432                kbot = k
433                if(pob .le. pbbo(k)+ppbo(k)) then
434                  goto 199
435                endif
436              enddo
437 199          continue
438
439              pphi = ppbo(kbot+1)
440              pbhi = pbbo(kbot+1)
441
442              rko(n) = real(kbot+1)-                                    &
443                 ( (pob-pbhi-pphi) / (pbbo(kbot)+ppbo(kbot)-pbhi-pphi) )
444
445              rko(n)=max(rko(n),1.0)
446            endif
447          endif
448
449#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
450        ENDIF       !end IF( MP_LOCAL_DUMMASK(N) )                                 !ajb
451#endif
452
453        RC(N)=RKO(N)
454
455      ENDDO      ! END COARSE MESH LOOP OVER NSTA
456
457    ELSE       ! FINE MESH CASE
458           
459!     CONVERT (I,J,K) OF OBSERVATIONS TO THE EQUIVALENT FINE MESH VALUES.
460      DO N=1,NSTA
461
462!       COMPUTE THE OBS LOCATION WITH RESPECT TO THIS MESH (INEST)...
463        NML=INEST
464        MM(LEVIDN(INEST)+1)=INEST
465!       WORKING TOWARD COARSER MESHES, DETERMINE THE HIERARCHY OF MOTHER
466!       MESHES WITH RESPECT TO EACH MOTHER MESH STARTING AT MESH "IN"...
467!       THAT IS, DETERMINE ITS MOTHER, GRANDMOTHER, GREAT-GRANDMOTHER, ETC.
468!       OUT TO THE COARSE GRID MESH (INEST=1).
469!       LEVIDN HOLDS THE NEST LEVEL AND PARID HOLDS THE MOTHER MESH FOR EACH
470!       GRID (E.G., FOR 3 MESHES AND 2 NEST LEVELS, IN=1 IS THE COARSE GRID
471!       MESH, IN=2 HAS LEVIDN(2)=1 AND PARID(2)=1, AND IN=3 HAS LEVIDN(3)=2
472!       AND PARID(3)=2...)
473        DO NNL=LEVIDN(INEST),1,-1
474          MM(NNL)=PARID(NML)
475          NML=MM(NNL)
476        ENDDO
477
478!       NOTE: MM(1) MUST BE THE COARSE GRID MESH (INEST=0)
479        IF(MM(1).NE.1) then
480            if(iprt) write(6,*) 'stopping in errob: inest = ',inest
481            STOP 21
482        ENDIF
483
484        RA(N)=RIO(N)
485        RB(N)=RJO(N)
486        DO NNL=1,LEVIDN(INEST)
487          GRFACX=0.
488          GRFACY=0.
489!         COMPUTE THE OBS LOCATION WITH RESPECT TO THE INNER GRID IN NON-
490!         STAGGERED SPACE (GRID=0.).  WHEN WE REACH MESH INEST, THEN
491!         APPLY THE APPRPRIATE STAGGER, DEPENDING ON THE VARIABLE...
492          IF(NNL.EQ.LEVIDN(INEST)) THEN
493            GRFACX=GRIDX
494            GRFACY=GRIDY
495          ENDIF
496 
497          RA(N)=(RA(N)-FLOAT(i_parent_start(MM(NNL+1))))*  &
498                       FLOAT(IRATIO)+1.-GRFACX
499          RB(N)=(RB(N)-FLOAT(j_parent_start(MM(NNL+1))))*  &
500                       FLOAT(IRATIO)+1.-GRFACY
501
502          IA(N)=RA(N)
503          IB(N)=RB(N)
504          IOB=MAX0(1,IA(N))
505          IOB=MIN0(IOB,ide-1)
506          JOB=MAX0(1,IB(N))
507          JOB=MIN0(JOB,jde-1)
508          DXOB=RA(N)-FLOAT(IA(N))
509          DYOB=RB(N)-FLOAT(IB(N))
510
511!         Save mass-point arrays for computing rko for all var types
512          if(ityp.eq.1) then
513            stagx = grfacx - gridx_t     !Correct x stagger to mass-point
514            stagy = grfacy - gridy_t     !Correct y stagger to mass-point
515            iobmg(n) = MIN0(MAX0(1,int(RA(n)+stagx)),ide-1)
516            jobmg(n) = MIN0(MAX0(1,int(RB(n)+stagy)),jde-1)
517            dxobmg(n) = RA(N)+stagx-FLOAT(int(RA(N)+stagx))
518            dyobmg(n) = RB(N)+stagy-FLOAT(int(RB(N)+stagy))
519          endif
520          iob_ms = iobmg(n)
521          job_ms = jobmg(n)
522          dxob_ms = dxobmg(n)
523          dyob_ms = dyobmg(n)
524
525!if(n.eq.1) then
526!        write(6,*) 'ERROB - FINE MESH:'
527!        write(6,*) 'RA = ',ra(n),' RB = ',rb(n)
528!        write(6,'(a,i1,a,i1,4(a,f5.2),2(a,i3),2(a,f6.3))') 'OBS= ',n,  &
529!                   '  ityp= ',ityp,                                    &
530!                   '  ra= ',ra(n),'  rb= ',rb(n),                      &
531!                   '  rio= ',rio(n),'  rjo= ',rjo(n),                  &
532!                   '  iob= ',iob,'  job= ',job,                        &
533!                   '  dxob= ',dxob,'  dyob= ',dyob
534!        write(6,'(a,i3,a,i3,a,f5.2,a,f5.2)')                           &
535!                   '  iob_ms= ',iob_ms,'  job_ms= ',job_ms,            &
536!                   '  dxob_ms= ',dxob_ms,'  dyob_ms= ',dyob_ms
537!endif
538
539        ENDDO    ! end do nnl=1,levidn(inest)
540
541#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
542!       Set mask for obs to be handled by this processor
543        MP_LOCAL_DUMMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
544
545        IF ( MP_LOCAL_DUMMASK(N) ) THEN
546#endif
547
548!         Interpolate pressure to obs location column and convert from Pa to cb.
549
550          do k = kds, kde
551            pbbo(k) = .001*(                                            &
552               (1.-DYOB_MS)*( (1.-DXOB_MS)*pbase(IOB_MS,K,JOB_MS) +     &
553                                  DXOB_MS *pbase(IOB_MS+1,K,JOB_MS) ) + &
554                   DYOB_MS* ( (1.-DXOB_MS)*pbase(IOB_MS,K,JOB_MS+1) +   &
555                                  DXOB_MS *pbase(IOB_MS+1,K,JOB_MS+1) ) )
556            ppbo(k) = .001*(                                            &
557               (1.-DYOB_MS)*( (1.-DXOB_MS)*pp(IOB_MS,K,JOB_MS) +        &
558                                  DXOB_MS *pp(IOB_MS+1,K,JOB_MS) ) +    &
559                   DYOB_MS* ( (1.-DXOB_MS)*pp(IOB_MS,K,JOB_MS+1) +      &
560                                  DXOB_MS *pp(IOB_MS+1,K,JOB_MS+1) ) )
561
562!     write(6,'(a,i2,2(a,f9.3)') ' k= ',k,' pbbo= ',pbbo(k),' ppbo= ',ppbo(k)
563          enddo
564
565!ajb      20040119: Note based on bugfix for dot/cross points split across processors,
566!ajb                which was actually a serial code fix: The ityp=2 (v-points) and
567!ajb                itype=3 (mass-points) cases should not use the ityp=1 (u-points)
568!ajb                case) rko! This is necessary for bit-for-bit reproducability
569!ajb                with parallel run.   (fine mesh)
570
571          if(abs(rko(n)+99).lt.1.)then
572            pob = varobs(5,n)
573
574            if(pob .gt.-800000.)then
575              do k=k_end-1,1,-1
576                kbot = k
577                if(pob .le. pbbo(k)+ppbo(k)) then
578                  goto 198
579                endif
580              enddo
581 198          continue
582
583              pphi = ppbo(kbot+1)
584              pbhi = pbbo(kbot+1)
585
586              rko(n) = real(kbot+1)-                                    &
587                 ( (pob-pbhi-pphi) / (pbbo(kbot)+ppbo(kbot)-pbhi-pphi) )
588              rko(n)=max(rko(n),1.0)
589            endif
590          endif
591
592#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
593        ENDIF       !end IF( MP_LOCAL_DUMMASK(N) )                                 !ajb
594#endif
595
596        RC(N)=RKO(N)
597
598      ENDDO      ! END FINE MESH LOOP OVER NSTA
599   
600    ENDIF      ! end if(inest.eq.1)
601
602!   INITIALIZE THE ARRAY OF DIFFERENCES BETWEEN THE OBSERVATIONS
603!   AND THE LOCAL FORECAST VALUES TO ZERO.  FOR THE FINE MESH
604!   ONLY, SET THE DIFFERENCE TO A LARGE DUMMY VALUE IF THE
605!   OBSERVATION IS OUTSIDE THE FINE MESH DOMAIN.
606
607!   SET DIFFERENCE VALUE TO A DUMMY VALUE FOR OBS POINTS OUTSIDE
608!   CURRENT DOMAIN
609    IF(ITYP.EQ.1) THEN
610      NLB=1
611      NLE=1
612    ELSE IF(ITYP.EQ.2) THEN
613      NLB=2
614      NLE=2
615    ELSE
616      NLB=3
617      NLE=5
618    ENDIF
619    DO IVAR=NLB,NLE
620      DO N=1,NSTA
621        IF((RA(N)-1.).LT.0)THEN
622           ERRF(IVAR,N)=ERRF(IVAR,N)+DUMMY
623        ENDIF
624        IF((RB(N)-1.).LT.0)THEN
625           ERRF(IVAR,N)=ERRF(IVAR,N)+DUMMY
626        ENDIF
627        IF((FLOAT(ide)-2.0*GRIDX-RA(N)-1.E-10).LT.0)THEN
628           ERRF(IVAR,N)=ERRF(IVAR,N)+DUMMY
629        ENDIF
630        IF((FLOAT(jde)-2.0*GRIDY-RB(N)-1.E-10).LT.0)THEN
631           ERRF(IVAR,N)=ERRF(IVAR,N)+DUMMY
632        ENDIF
633        if(rc(n).lt.1.)errf(ivar,n)=errf(ivar,n)+dummy
634      ENDDO
635    ENDDO
636
637!   NOW FIND THE EXACT OFFSET OF EACH OBSERVATION FROM THE
638!   GRID POINT TOWARD THE LOWER LEFT
639    DO N=1,NSTA
640        IA(N)=RA(N)
641        IB(N)=RB(N)
642        IC(N)=RC(N)
643    ENDDO
644    DO N=1,NSTA
645        RA(N)=RA(N)-FLOAT(IA(N))
646        RB(N)=RB(N)-FLOAT(IB(N))
647        RC(N)=RC(N)-FLOAT(IC(N))
648    ENDDO
649!   PERFORM A TRILINEAR EIGHT-POINT (3-D) INTERPOLATION
650!   TO FIND THE FORECAST VALUE AT THE EXACT OBSERVATION
651!   POINTS FOR U, V, T, AND Q.
652
653!   Compute local masks for dot and cross points.
654    if(ityp.eq.1) then
655      DO N=1,NSTA
656        IOB=MAX0(1,IA(N))
657        IOB=MIN0(IOB,ide-1)
658        JOB=MAX0(1,IB(N))
659        JOB=MIN0(JOB,jde-1)
660#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
661!       Set mask for U-momemtum points to be handled by this processor
662        MP_LOCAL_UOBMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
663#endif
664      ENDDO
665    endif
666    if(ityp.eq.2) then
667      DO N=1,NSTA
668        IOB=MAX0(1,IA(N))
669        IOB=MIN0(IOB,ide-1)
670        JOB=MAX0(1,IB(N))
671        JOB=MIN0(JOB,jde-1)
672#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
673!       Set mask for V-momentum points to be handled by this processor
674        MP_LOCAL_VOBMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
675#endif
676      ENDDO
677    endif
678    if(ityp.eq.3) then
679      DO N=1,NSTA
680        IOB=MAX0(1,IA(N))
681        IOB=MIN0(IOB,ide-1)
682        JOB=MAX0(1,IB(N))
683        JOB=MIN0(JOB,jde-1)
684#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
685!       Set mask for cross (mass) points to be handled by this processor
686        MP_LOCAL_COBMASK(N) = TILE_MASK(IOB, JOB, its, ite, jts, jte)
687#endif
688      ENDDO
689    endif
690
691!**********************************************************
692!   PROCESS U VARIABLE (IVAR=1)
693!**********************************************************
694    IF(ITYP.EQ.1) THEN
695#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
696      DO N=1,NSTA
697        IF(MP_LOCAL_UOBMASK(N)) THEN
698          ERRF(9,N)=rko(n)       !RKO is needed by neighboring processors     !ajb
699        ENDIF
700      ENDDO
701#endif
702      IF(ISWIND.EQ.1) THEN
703        DO N=1,NSTA
704          IOB=MAX0(2,IA(N))
705          IOB=MIN0(IOB,ide-1)
706          IOBM=MAX0(1,IOB-1)
707          IOBP=MIN0(ide-1,IOB+1)
708          JOB=MAX0(2,IB(N))
709          JOB=MIN0(JOB,jde-1)
710          JOBM=MAX0(1,JOB-1)
711          JOBP=MIN0(jde-1,JOB+1)
712          KOB=MIN0(K_END,IC(N))
713
714#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
715          IF(MP_LOCAL_UOBMASK(N))THEN     ! Do if obs on this processor
716#endif
717            KOBP=MIN0(KOB+1,k_end)
718            DXOB=RA(N)
719            DYOB=RB(N)
720            DZOB=RC(N)
721
722!           Compute surface pressure values at surrounding U and V points
723            PUG1 = .5*( pbase(IOBM,1,JOB) + pbase(IOB,1,JOB) )
724            PUG2 = .5*( pbase(IOB,1,JOB) + pbase(IOBP,1,JOB) )
725
726!           This is to correct obs to model sigma level using reverse similarity theory
727            if(rko(n).eq.1.0)then
728              uratiob=((1.-DXOB)*((1.-DYOB)*uratio(IOB,JOB)+     &
729                    DYOB*uratio(IOBP,JOB)                        &
730                  )+DXOB*((1.-DYOB)*uratio(IOB,JOBP)+            &
731                  DYOB*uratio(IOBP,JOBP)))
732            else
733              uratiob=1.
734            endif
735!YLIU       Some PBL scheme do not define the vratio/uratio
736            if(abs(uratiob).lt.1.0e-3) then
737              uratiob=1.
738            endif
739
740!           INITIAL ERRF(IVAR,N) IS ZERO FOR OBSERVATIONS POINTS
741!           WITHIN THE DOMAIN, AND A LARGE DUMMY VALUE FOR POINTS
742!           OUTSIDE THE CURRENT DOMAIN
743 
744!           U COMPONENT WIND ERROR
745            ERRF(1,N)=ERRF(1,N)+uratiob*VAROBS(1,N)-((1.-DZOB)*        &
746                      ((1.-DyOB)*((1.-                                 &
747                      DxOB)*UB(IOB,KOB,JOB)+DxOB*UB(IOB+1,KOB,JOB)     &
748                      )+DyOB*((1.-DxOB)*UB(IOB,KOB,JOB+1)+DxOB*        &
749                      UB(IOB+1,KOB,JOB+1)))+DZOB*((1.-DyOB)*((1.-DxOB) &
750                      *UB(IOB,KOBP,JOB)+DxOB*UB(IOB+1,KOBP,JOB))+      &
751                      DyOB*((1.-DxOB)*UB(IOB,KOBP,JOB+1)+DxOB*         &
752                      UB(IOB+1,KOBP,JOB+1))))
753
754!      if(n.le.10) then
755!        write(6,*)
756!        write(6,'(a,i3,i3,i3,a,i3,a,i2)') 'ERRF1 at ',iob,job,kob,   &
757!                                     ' N = ',n,' inest = ',inest
758!        write(6,*) 'VAROBS(1,N) = ',varobs(1,n)
759!        write(6,*) 'VAROBS(5,N) = ',varobs(5,n)
760!        write(6,*) 'UB(IOB,KOB,JOB) = ',UB(IOB,KOB,JOB)
761!        write(6,*) 'UB(IOB+1,KOB,JOB) = ',UB(IOB+1,KOB,JOB)
762!        write(6,*) 'UB(IOB,KOB,JOB+1) = ',UB(IOB,KOB,JOB+1)
763!        write(6,*) 'UB(IOB+1,KOB,JOB+1) = ',UB(IOB+1,KOB,JOB+1)
764!        write(6,*) 'UB(IOB,KOBP,JOB) = ',UB(IOB,KOBP,JOB)
765!        write(6,*) 'UB(IOB+1,KOBP,JOB) = ',UB(IOB+1,KOBP,JOB)
766!        write(6,*) 'UB(IOB,KOBP,JOB+1) = ',UB(IOB,KOBP,JOB+1)
767!        write(6,*) 'UB(IOB+1,KOBP,JOB+1) = ',UB(IOB+1,KOBP,JOB+1)
768!        write(6,*) 'uratiob = ',uratiob
769!        write(6,*) 'DXOB,DYOB,DZOB = ',DXOB,DYOB,DZOB
770!        write(6,*) 'ERRF(1,N) = ',errf(1,n)
771!        write(6,*)
772!      endif
773
774
775!           Store model surface pressure (not the error!) at U point.
776            ERRF(7,N)=.001*( (1.-DXOB)*PUG1 + DXOB*PUG2 )
777 
778#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
779          ENDIF       ! end IF( MP_LOCAL_UOBMASK(N) )
780#endif
781        ENDDO    ! END U-POINT LOOP OVER OBS
782
783      ENDIF    ! end if(iswind.eq.1)
784
785    ENDIF   ! ITYP=1: PROCESS U
786
787!**********************************************************
788!   PROCESS V VARIABLE (IVAR=2)
789!**********************************************************
790    IF(ITYP.EQ.2) THEN
791
792      IF(ISWIND.EQ.1) THEN
793        DO N=1,NSTA
794          IOB=MAX0(2,IA(N))
795          IOB=MIN0(IOB,ide-1)
796          IOBM=MAX0(1,IOB-1)
797          IOBP=MIN0(ide-1,IOB+1)
798          JOB=MAX0(2,IB(N))
799          JOB=MIN0(JOB,jde-1)
800          JOBM=MAX0(1,JOB-1)
801          JOBP=MIN0(jde-1,JOB+1)
802          KOB=MIN0(K_END,IC(N))
803
804#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
805          IF(MP_LOCAL_VOBMASK(N))THEN     ! Do if obs on this processor
806#endif
807            KOBP=MIN0(KOB+1,k_end)
808            DXOB=RA(N)
809            DYOB=RB(N)
810            DZOB=RC(N)
811
812!           Compute surface pressure values at surrounding U and V points
813            PVG1 = .5*( pbase(IOB,1,JOBM) + pbase(IOB,1,JOB) )
814            PVG2 = .5*( pbase(IOB,1,JOB) + pbase(IOB,1,JOBP) )
815
816!           This is to correct obs to model sigma level using reverse similarity theory
817            if(rko(n).eq.1.0)then
818              vratiob=((1.-DXOB)*((1.-DYOB)*vratio(IOB,JOB)+     &
819                    DYOB*vratio(IOBP,JOB)                        &
820                  )+DXOB*((1.-DYOB)*vratio(IOB,JOBP)+            &
821                  DYOB*vratio(IOBP,JOBP)))
822            else
823              vratiob=1.
824            endif
825!YLIU       Some PBL scheme do not define the vratio/uratio
826            if(abs(vratiob).lt.1.0e-3) then
827              vratiob=1.
828            endif
829
830!           INITIAL ERRF(IVAR,N) IS ZERO FOR OBSERVATIONS POINTS
831!           WITHIN THE DOMAIN, AND A LARGE DUMMY VALUE FOR POINTS
832!           OUTSIDE THE CURRENT DOMAIN
833 
834!           V COMPONENT WIND ERROR
835            ERRF(2,N)=ERRF(2,N)+vratiob*VAROBS(2,N)-((1.-DZOB)*        &
836                     ((1.-DyOB)*((1.-                                  &
837                      DxOB)*VB(IOB,KOB,JOB)+DxOB*VB(IOB+1,KOB,JOB)     &
838                      )+DyOB*((1.-DxOB)*VB(IOB,KOB,JOB+1)+DxOB*        &
839                      VB(IOB+1,KOB,JOB+1)))+DZOB*((1.-DyOB)*((1.-DxOB) &
840                      *VB(IOB,KOBP,JOB)+DxOB*VB(IOB+1,KOBP,JOB))+      &
841                      DyOB*((1.-DxOB)*VB(IOB,KOBP,JOB+1)+DxOB*         &
842                      VB(IOB+1,KOBP,JOB+1))))
843 
844!           Store model surface pressure (not the error!) at V point.
845            ERRF(8,N)=.001*( (1.-DYOB)*PVG1 + DYOB*PVG2 )
846 
847#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
848          ENDIF       ! end IF( MP_LOCAL_VOBMASK(N) )
849#endif
850        ENDDO    ! END V-POINT LOOP OVER OBS
851
852      ENDIF    ! end if(iswind.eq.1)
853
854    ENDIF   ! ITYP=1: PROCESS V
855
856!**********************************************************
857!   PROCESS MASS-POINT VARIABLES IVAR=3 (T) AND IVAR=4 (QV)
858!**********************************************************
859    IF(ITYP.EQ.3) THEN
860
861      IF(ISTEMP.EQ.1 .OR. ISMOIS.EQ.1) THEN
862        DO N=1,NSTA
863          IOB=MAX0(1,IA(N))
864          IOB=MIN0(IOB,ide-1)
865          JOB=MAX0(1,IB(N))
866          JOB=MIN0(JOB,jde-1)
867#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
868          IF(MP_LOCAL_COBMASK(N)) THEN     ! Do if obs on this processor
869#endif
870            KOB=MIN0(k_end,IC(N))
871            KOBP=MIN0(KOB+1,K_END)
872            DXOB=RA(N)
873            DYOB=RB(N)
874            DZOB=RC(N)
875
876!           This is to correct obs to model sigma level using reverse similarity theory
877            if(rko(n).eq.1.0)then
878              tratxob=((1.-DXOB)*((1.-DYOB)*tratx(IOB,JOB)+        &
879                    DYOB*tratx(IOB+1,JOB)                          &
880                  )+DXOB*((1.-DYOB)*tratx(IOB,JOB+1)+              &
881                  DYOB*tratx(IOB+1,JOB+1)))
882            else
883              tratxob=1.
884            endif
885
886!yliu
887            if(abs(tratxob) .lt. 1.0E-3) tratxob=1.
888
889!ajb        testing only
890            if(iprt .and. n.eq.81)  then
891              write(6,*) 'POTENTIAL TEMP FOR N=81:'
892              write(6,*)
893              write(6,*) '            K      THETA       TEMPERATURE', &
894                         '       PBASE'
895              write(6,*)
896              do k=k_end,1,-1
897                press = pbase(iob,k,job)+pp(iob,k,job)
898                ttemp = exp ( alog(300.+TB(IOB,k,JOB)) - &
899                                           .2857143*alog(100000./press) )
900                write(6,*) k,300.+TB(IOB,k,JOB),ttemp,pbase(iob,k,job)
901              enddo
902            endif
903!ajb        end testing only
904
905!           TEMPERATURE ERROR
906!          if(n.le.10) then
907!             write(6,*) 'before: errf(3,n) = ',errf(3,n)
908!          endif
909            ERRF(3,N)=ERRF(3,N)+tratxob*VAROBS(3,N)-((1.-DZOB)*     &
910                      ((1.-DyOB)*((1.-                              &
911                      DxOB)*(TB(IOB,KOB,JOB))+DxOB*                 &
912                      (TB(IOB+1,KOB,JOB)))+DyOB*((1.-DxOB)*         &
913                      (TB(IOB,KOB,JOB+1))+DxOB*                     &
914                      (TB(IOB+1,KOB,JOB+1))))+DZOB*((1.-            &
915                      DyOB)*((1.-DxOB)*(TB(IOB,KOBP,JOB))+DxOB*     &
916                      (TB(IOB+1,KOBP,JOB)))+DyOB*((1.-DxOB)*        &
917                      (TB(IOB,KOBP,JOB+1))+DxOB*                    &
918                      (TB(IOB+1,KOBP,JOB+1)))))
919
920!       if(n.le.10) then
921!         write(6,*)
922!         write(6,'(a,i3,i3,i3,a,i3,a,i2)') 'ERRF3 at ',iob,job,kob,   &
923!                                      ' N = ',n,' inest = ',inest
924!         write(6,*) 'VAROBS(3,N) = ',varobs(3,n)
925!         write(6,*) 'VAROBS(5,N) = ',varobs(5,n)
926!         write(6,*) 'TB(IOB,KOB,JOB) = ',TB(IOB,KOB,JOB)
927!         write(6,*) 'TB(IOB+1,KOB,JOB) = ',TB(IOB+1,KOB,JOB)
928!         write(6,*) 'TB(IOB,KOB,JOB+1) = ',TB(IOB,KOB,JOB+1)
929!         write(6,*) 'TB(IOB+1,KOB,JOB+1) = ',TB(IOB+1,KOB,JOB+1)
930!         write(6,*) 'TB(IOB,KOBP,JOB) = ',TB(IOB,KOBP,JOB)
931!         write(6,*) 'TB(IOB+1,KOBP,JOB) = ',TB(IOB+1,KOBP,JOB)
932!         write(6,*) 'TB(IOB,KOBP,JOB+1) = ',TB(IOB,KOBP,JOB+1)
933!         write(6,*) 'TB(IOB+1,KOBP,JOB+1) = ',TB(IOB+1,KOBP,JOB+1)
934!         write(6,*) 'tratxob = ',tratxob
935!         write(6,*) 'DXOB,DYOB,DZOB = ',DXOB,DYOB,DZOB
936!         write(6,*) 'ERRF(3,N) = ',errf(3,n)
937!         write(6,*)
938!       endif
939
940
941!           MOISTURE ERROR
942            ERRF(4,N)=ERRF(4,N)+VAROBS(4,N)-((1.-DZOB)*((1.-DyOB)*((1.- &
943                      DxOB)*QVB(IOB,KOB,JOB)+DxOB*                      &
944                      QVB(IOB+1,KOB,JOB))+DyOB*((1.-DxOB)*              &
945                      QVB(IOB,KOB,JOB+1)+DxOB*                          &
946                      QVB(IOB+1,KOB,JOB+1)))+DZOB*((1.-                 &
947                      DyOB)*((1.-DxOB)*QVB(IOB,KOBP,JOB)+DxOB           &
948                      *QVB(IOB+1,KOBP,JOB))+DyOB*((1.-DxOB              &
949                      )*QVB(IOB,KOBP,JOB+1)+DxOB*                       &
950                      QVB(IOB+1,KOBP,JOB+1))))
951
952!           Store model surface pressure (not the error!) at T-point
953            ERRF(6,N)= .001*                                            &
954                      ((1.-DyOB)*((1.-DxOB)*pbase(IOB,1,JOB)+DxOB*      &
955                      pbase(IOB+1,1,JOB))+DyOB*((1.-DxOB)*              &
956                      pbase(IOB,1,JOB+1)+DxOB*pbase(IOB+1,1,JOB+1) ))
957 
958      if(iprt .and. n.eq.81) then
959       write(6,*) 'ERRF(6,81) calculation:'
960       write(6,*) 'iob,job = ',iob,job
961       write(6,*) 'pbase(iob,1,job) = ',pbase(iob,1,job)
962       write(6,*) 'pbase(iob+1,1,job) = ',pbase(iob+1,1,job)
963       write(6,*) 'pbase(iob,1,job+1) = ',pbase(iob,1,job+1)
964       write(6,*) 'pbase(iob+1,1,job+1) = ',pbase(iob+1,1,job+1)
965       write(6,*) 'ERRF(6,81) = ',errf(6,n)
966!      call flush(6)
967      endif
968
969#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
970          ENDIF       ! end IF( MP_LOCAL_COBMASK(N) )
971#endif
972        ENDDO     ! END T and QV LOOP OVER OBS
973
974      ENDIF   !end if(istemp.eq.1 .or. ismois.eq.1)
975
976!**********************************************************
977!     PROCESS SURFACE PRESSURE CROSS-POINT FIELD, IVAR=5,
978!     USING BILINEAR FOUR-POINT 2-D INTERPOLATION
979!**********************************************************
980      IF(ISPSTR.EQ.1) THEN
981        DO N=1,NSTA
982          IOB=MAX0(1,IA(N))
983          IOB=MIN0(IOB,ide-1)
984          JOB=MAX0(1,IB(N))
985          JOB=MIN0(JOB,jde-1)
986#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
987          IF(MP_LOCAL_COBMASK(N)) THEN    ! Do if obs on this processor
988#endif
989            DXOB=RA(N)
990            DYOB=RB(N)
991!ajb        fix this (put in correct pressure calc for IOB,JOB here)
992            ERRF(5,N)=ERRF(5,N)+VAROBS(5,N)-((1.-DyOB)*((1.-DxOB)*      &
993               pbase(IOB,1,JOB)+DxOB*pbase(IOB+1,1,JOB))+DyOB*          &
994               ((1.-DxOB)*pbase(IOB,1,JOB+1)+DxOB*                      &
995               pbase(IOB+1,1,JOB+1)))
996
997      if(n.eq.81) then
998       write(6,*) 'ERRF(5,81) calculation:'
999       write(6,*) 'iob,job = ',iob,job
1000       write(6,*) 'pbase(iob,1,job) = ',pbase(iob,1,job)
1001       write(6,*) 'pbase(iob+1,1,job) = ',pbase(iob+1,1,job)
1002       write(6,*) 'pbase(iob,1,job+1) = ',pbase(iob,1,job+1)
1003       write(6,*) 'pbase(iob+1,1,job+1) = ',pbase(iob+1,1,job+1)
1004       write(6,*) 'errf(5,81) = ',errf(5,n)
1005!      call flush(6)
1006      endif
1007
1008#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
1009          ENDIF       ! end IF( MP_LOCAL_COBMASK(N) )
1010#endif
1011
1012        ENDDO
1013
1014      ENDIF   ! end if(ispstr.eq.1)
1015
1016    ENDIF   ! end if(ityp.eq.3)
1017
1018  ENDDO   ! END BIG LOOP
1019
1020#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
1021! Gather the errf values calculated by the processors with the obs.
1022  CALL get_full_obs_vector(nsta, nerrf, niobf, mp_local_uobmask,     &
1023                           mp_local_vobmask, mp_local_cobmask, errf)
1024#endif
1025
1026! DIFFERENCE BETWEEN OBS AND FCST IS COMPLETED
1027  IF(INEST.EQ.1)THEN
1028    INPF=NPFI
1029  ELSE
1030    FNPF=IRATIO**LEVIDN(INEST)
1031    INPF=FNPF*NPFI
1032  ENDIF
1033! Gross error check for temperature. Set all vars bad.
1034  do n=1,nsta
1035    if((abs(errf(3,n)).gt.20.).and.           &
1036           (errf(3,n).gt.-800000.))then
1037
1038       errf(1,n)=-888888.
1039       errf(2,n)=-888888.
1040       errf(3,n)=-888888.
1041       errf(4,n)=-888888.
1042       varobs(1,n)=-888888.
1043       varobs(2,n)=-888888.
1044       varobs(3,n)=-888888.
1045       varobs(4,n)=-888888.
1046    endif
1047  enddo
1048
1049! For printout
1050!  IF(MOD(KTAU,INPF).NE.0) THEN
1051!      RETURN
1052!  ENDIF
1053
1054  RETURN
1055  END SUBROUTINE errob
1056
1057  SUBROUTINE upoint(i_start,i_end, j_start,j_end, ids,ide, ims,ime, jms,jme,  &
1058                    arrin, arrout)
1059!------------------------------------------------------------------------------
1060!     PURPOSE: This subroutine interpolates a real 2D array defined over mass
1061!              coordinate points, to U (momentum) points.
1062!
1063!------------------------------------------------------------------------------
1064  IMPLICIT NONE
1065
1066  INTEGER, INTENT(IN) :: i_start     ! Starting i index for this model tile
1067  INTEGER, INTENT(IN) :: i_end       ! Ending   i index for this model tile
1068  INTEGER, INTENT(IN) :: j_start     ! Starting j index for this model tile
1069  INTEGER, INTENT(IN) :: j_end       ! Ending   j index for this model tile
1070  INTEGER, INTENT(IN) :: ids         ! Starting i index for entire model domain
1071  INTEGER, INTENT(IN) :: ide         ! Ending   i index for entire model domain
1072  INTEGER, INTENT(IN) :: ims         ! Starting i index for model patch
1073  INTEGER, INTENT(IN) :: ime         ! Ending   i index for model patch
1074  INTEGER, INTENT(IN) :: jms         ! Starting j index for model patch
1075  INTEGER, INTENT(IN) :: jme         ! Ending   j index for model patch
1076  REAL,   INTENT(IN)  :: arrin ( ims:ime, jms:jme )  ! input array on mass points
1077  REAL,   INTENT(OUT) :: arrout( ims:ime, jms:jme )  ! output array on U points
1078
1079! Local variables
1080  integer :: i, j
1081
1082! Do domain interior first
1083  do j = j_start, j_end
1084    do i = max(2,i_start), i_end
1085       arrout(i,j) = 0.5*(arrin(i,j)+arrin(i-1,j))
1086    enddo
1087  enddo
1088
1089! Do west-east boundaries
1090  if(i_start .eq. ids) then
1091    do j = j_start, j_end
1092      arrout(i_start,j) = arrin(i_start,j)
1093    enddo
1094  endif
1095  if(i_end .eq. ide-1) then
1096    do j = j_start, j_end
1097      arrout(i_end+1,j) = arrin(i_end,j)
1098    enddo
1099  endif
1100
1101  RETURN
1102  END SUBROUTINE upoint
1103
1104  SUBROUTINE vpoint(i_start,i_end, j_start,j_end, jds,jde, ims,ime, jms,jme,  &
1105                    arrin, arrout)
1106!------------------------------------------------------------------------------
1107!     PURPOSE: This subroutine interpolates a real 2D array defined over mass
1108!              coordinate points, to V (momentum) points.
1109!
1110!------------------------------------------------------------------------------
1111  IMPLICIT NONE
1112
1113  INTEGER, INTENT(IN) :: i_start     ! Starting i index for this model tile
1114  INTEGER, INTENT(IN) :: i_end       ! Ending   i index for this model tile
1115  INTEGER, INTENT(IN) :: j_start     ! Starting j index for this model tile
1116  INTEGER, INTENT(IN) :: j_end       ! Ending   j index for this model tile
1117  INTEGER, INTENT(IN) :: jds         ! Starting j index for entire model domain
1118  INTEGER, INTENT(IN) :: jde         ! Ending   j index for entire model domain
1119  INTEGER, INTENT(IN) :: ims         ! Starting i index for model patch
1120  INTEGER, INTENT(IN) :: ime         ! Ending   i index for model patch
1121  INTEGER, INTENT(IN) :: jms         ! Starting j index for model patch
1122  INTEGER, INTENT(IN) :: jme         ! Ending   j index for model patch
1123  REAL,   INTENT(IN)  :: arrin ( ims:ime, jms:jme )  ! input array on mass points
1124  REAL,   INTENT(OUT) :: arrout( ims:ime, jms:jme )  ! output array on V points
1125
1126! Local variables
1127  integer :: i, j
1128
1129! Do domain interior first
1130  do j = max(2,j_start), j_end
1131    do i = i_start, i_end
1132      arrout(i,j) = 0.5*(arrin(i,j)+arrin(i,j-1))
1133    enddo
1134  enddo
1135
1136! Do south-north boundaries
1137  if(j_start .eq. jds) then
1138    do i = i_start, i_end
1139      arrout(i,j_start) = arrin(i,j_start)
1140    enddo
1141  endif
1142  if(j_end .eq. jde-1) then
1143    do i = i_start, i_end
1144      arrout(i,j_end+1) = arrin(i,j_end)
1145    enddo
1146  endif
1147
1148  RETURN
1149  END SUBROUTINE vpoint
1150
1151  LOGICAL FUNCTION TILE_MASK(iloc, jloc, its, ite, jts, jte)
1152!------------------------------------------------------------------------------
1153! PURPOSE: Check to see if an i, j grid coordinate is in the tile index range.
1154!     
1155! Returns: TRUE if the grid coordinate (ILOC,JLOC) is in the tile defined by
1156!                  tile-range indices (its,jts) and (ite,jte)
1157!          FALSE otherwise.
1158!
1159!------------------------------------------------------------------------------
1160  IMPLICIT NONE
1161
1162  INTEGER, INTENT(IN) :: iloc
1163  INTEGER, INTENT(IN) :: jloc
1164  INTEGER, INTENT(IN) :: its
1165  INTEGER, INTENT(IN) :: ite
1166  INTEGER, INTENT(IN) :: jts
1167  INTEGER, INTENT(IN) :: jte
1168
1169! Local variables
1170  LOGICAL :: retval
1171
1172  TILE_MASK = (iloc .LE. ite .AND. iloc .GE. its .AND.    &
1173               jloc .LE. jte .AND. jloc .GE. jts )
1174
1175  RETURN
1176  END FUNCTION TILE_MASK
1177
1178!-----------------------------------------------------------------------
1179  SUBROUTINE nudob(j, ivar, aten, inest, ifrest, ktau, ktaur,         &
1180                       xtime, mu, msf, nndgv, nerrf, niobf, maxdom,   &
1181                       npfi, ionf, rinxy, twindo, levidn,             &
1182                       parid, nstat, i_parent_start, j_parent_start,  &
1183                       fdob, lev_in_ob, plfo, nlevs_ob,               &
1184                       iratio, dx, dtmin, rio, rjo, rko,              &
1185                       timeob, varobs, errf, pbase, ptop, pp,         &
1186                       iswind, istemp, ismois, giv, git, giq,         &
1187                       savwt, kpblt, nscan,                           &
1188                       iprt,                                          &
1189                       ids,ide, jds,jde, kds,kde,                     &  ! domain dims
1190                       ims,ime, jms,jme, kms,kme,                     &  ! memory dims
1191                       its,ite, jts,jte, kts,kte )                       ! tile   dims
1192
1193!-----------------------------------------------------------------------
1194  USE module_model_constants
1195  USE module_domain
1196!-----------------------------------------------------------------------
1197  IMPLICIT NONE
1198!-----------------------------------------------------------------------
1199!
1200! PURPOSE: THIS SUBROUTINE GENERATES NUDGING TENDENCIES FOR THE J-TH
1201!     VERTICAL SLICE (I-K PLANE) FOR FOUR-DIMENSIONAL DATA
1202!     ASSIMILATION FROM INDIVIDUAL OBSERVATIONS.  THE NUDGING
1203!     TENDENCIES ARE FOUND FROM A ONE-PASS CALCULATION OF
1204!     WEIGHTING FACTORS SIMILAR TO THE BENJAMIN-SEAMAN OBJECTIVE
1205!     ANALYSIS.  THIS SUBROUTINE IS DESIGNED FOR RAPID EXECUTION
1206!     AND MINIMAL STORAGE REQUIREMENTS.  ALGORITHMS SHOULD BE
1207!     VECTORIZED WHEREVER POSSIBLE.
1208!
1209!     HISTORY: Original author: MM5 version???
1210!              02/04/2004 - Creation of WRF version.           Al Bourgeois
1211!              08/28/2006 - Conversion from F77 to F90         Al Bourgeois
1212!------------------------------------------------------------------------------
1213!
1214! NOTE: This routine was originally designed for MM5, which uses
1215!       a nonstandard (I,J) coordinate system. For WRF, I is the
1216!       east-west running coordinate, and J is the south-north
1217!       running coordinate. So a "J-slab" here is west-east in
1218!       extent, not south-north as for MM5.      -ajb 06/10/2004
1219!
1220!     NET WEIGHTING (WT) OF THE DIFFERENCE BETWEEN THE OBSERVATIONS
1221!     AND LOCAL FORECAST VALUES IS BASED ON THE MULTIPLE OF THREE
1222!
1223!     NET WEIGHTING (WT) OF THE DIFFERENCE BETWEEN THE OBSERVATIONS
1224!     AND LOCAL FORECAST VALUES IS BASED ON THE MULTIPLE OF THREE
1225!     TYPES OF FACTORS:
1226!       1) TIME WEIGHTING - ONLY OBSERVATIONS WITHIN A SELECTED
1227!          TIME WINDOW (TWINDO) CENTERED AT THE CURRENT FORECAST
1228!          TIME (XTIME) ARE USED.  OBSERVATIONS CLOSEST TO
1229!          XTIME ARE TIME-WEIGHTED MOST HEAVILY (TIMEWT)
1230!       2) VERTICAL WEIGHTING - NON-ZERO WEIGHTS (WTSIG) ARE
1231!          CALCULATED WITHIN A VERTICAL REGION OF INFLUENCE
1232!          (RINSIG).
1233!       3) HORIZONTAL WEIGHTING - NON-ZERO WEIGHTS (WTIJ) ARE
1234!          CALCULATED WITHIN A RADIUS OF INFLUENCE (RINXY).  THE
1235!          VALUE OF RIN IS DEFINED IN KILOMETERS, AND CONVERTED
1236!          TO GRID LENGTHS FOR THE APPROPRIATE MESH SIZE.
1237!
1238!     THE FIVE FORECAST VARIABLES ARE PROCESSED BY CHANGING THE
1239!     VALUE OF IVAR AS FOLLOWS:
1240!             IVAR                     VARIABLE(TAU-1)
1241!             ----                     ---------------
1242!               1                             U
1243!               2                             V
1244!               3                             T
1245!               4                             QV
1246!               5                          PSB(CROSS)   REMOVED IN V3
1247!              (6)                           PSB(DOT)
1248!
1249!-----------------------------------------------------------------------
1250!
1251!     Description of input arguments.
1252!
1253!-----------------------------------------------------------------------
1254
1255  INTEGER, INTENT(IN)  :: ids,ide, jds,jde, kds,kde  ! domain dims.
1256  INTEGER, INTENT(IN)  :: ims,ime, jms,jme, kms,kme  ! memory dims.
1257  INTEGER, INTENT(IN)  :: its,ite, jts,jte, kts,kte  ! tile   dims.
1258  INTEGER, INTENT(IN)  :: j                          ! south-north running coordinate.
1259  INTEGER, INTENT(IN)  :: ivar
1260  INTEGER, INTENT(IN)  :: inest                      ! domain index
1261  LOGICAL, INTENT(IN)  :: ifrest
1262  INTEGER, INTENT(IN)  :: ktau
1263  INTEGER, INTENT(IN)  :: ktaur
1264  REAL, INTENT(IN)     :: xtime                      ! forecast time in minutes
1265  INTEGER, INTENT(IN)  :: nndgv                      ! number of nudge variables
1266  INTEGER, INTENT(IN)  :: nerrf                      ! number of error fields
1267  INTEGER, INTENT(IN)  :: niobf                      ! number of observations
1268  INTEGER, INTENT(IN)  :: maxdom                     ! maximum number of domains
1269  INTEGER, INTENT(IN)  :: npfi
1270  INTEGER, INTENT(IN)  :: ionf
1271  REAL, INTENT(IN)     :: rinxy
1272  REAL, INTENT(IN)     :: twindo
1273  INTEGER, INTENT(IN)  :: levidn(maxdom)             ! level of nest
1274  INTEGER, INTENT(IN)  :: parid(maxdom)              ! parent domain id
1275  INTEGER, INTENT(IN)  :: nstat                      ! number of obs stations
1276  INTEGER, INTENT(IN)  :: i_parent_start(maxdom)     ! Start i index in parent domain.
1277  INTEGER, INTENT(IN)  :: j_parent_start(maxdom)     ! Start j index in parent domain.
1278  TYPE(fdob_type), intent(inout)  :: fdob
1279  REAL, INTENT(IN)     :: lev_in_ob(niobf)           ! Level in sounding-type obs.
1280  REAL, intent(IN)     :: plfo(niobf)
1281  REAL, INTENT(IN)     :: nlevs_ob(niobf)            ! Number of levels in sounding.
1282  INTEGER, INTENT(IN)  :: iratio                     ! Nest to parent gridsize ratio.
1283  REAL, INTENT(IN)     :: dx                         ! This domain grid cell-size (m)
1284  REAL, INTENT(IN)     :: dtmin
1285  REAL, INTENT(IN)     :: rio(niobf)
1286  REAL, INTENT(IN)     :: rjo(niobf)
1287  REAL, INTENT(INOUT)  :: rko(niobf)
1288  REAL, INTENT(IN)     :: timeob(niobf)
1289  REAL, INTENT(IN)     :: varobs(nndgv,niobf)
1290  REAL, INTENT(IN)     :: errf(nerrf, niobf)
1291  REAL, INTENT(IN)     :: pbase( ims:ime, kms:kme )  ! Base pressure.
1292  REAL, INTENT(IN)     :: ptop
1293  REAL, INTENT(IN)     :: pp( ims:ime, kms:kme ) ! Pressure perturbation (Pa)
1294  REAL, INTENT(IN)     :: mu(ims:ime)   ! Air mass on u, v, or mass-grid
1295  REAL, INTENT(IN)     :: msf(ims:ime)  ! Map scale (only used for vars u & v)
1296  INTEGER, intent(in)  :: iswind        ! Nudge flag for wind
1297  INTEGER, intent(in)  :: istemp        ! Nudge flag for temperature
1298  INTEGER, intent(in)  :: ismois        ! Nudge flag for moisture
1299  REAL, intent(in)     :: giv           ! Coefficient for wind
1300  REAL, intent(in)     :: git           ! Coefficient for temperature
1301  REAL, intent(in)     :: giq           ! Coefficient for moisture
1302  REAL, INTENT(INOUT)  :: aten( ims:ime, kms:kme)
1303  REAL, INTENT(INOUT)  :: savwt( nndgv, ims:ime, kms:kme )
1304  INTEGER, INTENT(IN)  :: kpblt(its:ite)
1305  INTEGER, INTENT(IN)  :: nscan                      ! number of scans
1306  LOGICAL, INTENT(IN)  :: iprt                       ! print flag
1307
1308! Local variables
1309  integer :: mm(maxdom)
1310  real :: ra(niobf)
1311  real :: rb(niobf)
1312  real :: psurf(niobf)
1313  real :: wtsig(kms:kme),wt(ims:ime,kms:kme),wt2err(ims:ime,kms:kme)
1314  real :: rscale(ims:ime)           ! For converting to rho-coupled units.
1315!      real :: tscale(ims:ime,kms:kme)   ! For converting to potential temp. units.
1316  real :: reserf(100)
1317  character*40 name
1318  character*3 chr_hr
1319
1320!***  DECLARATIONS FOR IMPLICIT NONE
1321  integer :: i,k,iplo,icut,ipl,inpf,infr,jjjn
1322  integer :: igrid,n,nml,nnl,nsthis,nsmetar,nsspeci,nsship
1323  integer :: nssynop,nstemp,nspilot,nssatwnds,nssams,nsprofs
1324  integer :: maxi,mini,maxj,minj,nnn,nsndlev,njcsnd,kob
1325  integer :: komin,komax,nn,nhi,nlo,nnjc
1326  integer :: i_s,i_e
1327  integer :: istq
1328  real :: gfactor,rfactor,gridx,gridy,rindx,schnes,ris
1329  real :: grfacx,grfacy
1330  real :: fdtim,tw1,tw2,tconst,timewt,timewt2,ttim,dift,pob
1331  real :: ri,rj,rx,ry,rsq,wtij,pdfac,erfivr,dk,slope,rinfac
1332  real :: rinprs,pijk,pobhi,poblo,pdiffj,w2eowt,gitq
1333
1334  real :: scratch
1335
1336!      print *,'start nudob, nstat,j,ivar=',nstat,j,ivar
1337!      if(ivar.ne.4)return
1338!yliu start -- for multi-scans: NSCAN=0: original
1339!                               NSCAN=1: added a scan with a larger Ri and smaller G
1340!       if(NSCAN.ne.0 .and. NSCAN.ne.1)  stop
1341! ajb note: Will need to increase memory for SAVWT if NSCAN=1:
1342  if(NSCAN.ne.0) then
1343    IF (iprt) write(6,*) 'SAVWT must be resized for NSCAN=1'
1344    stop
1345  endif
1346  IPLO=0  + NSCAN*4
1347  GFACTOR=1. +  NSCAN*(-1. + 0.33333)
1348  RFACTOR=1. +  NSCAN*(-1. + 3.0)
1349!yliu end
1350! jc
1351
1352! return if too close to j boundary
1353  if(inest.eq.1.and.ivar.lt.3.and.(j.le.2.or.j.ge.jde-1)) then
1354!       write(6,*) '1 RETURN: IVAR = ',ivar,' J = ',j,
1355!    $             ' too close to boundary.'
1356    return
1357  endif
1358  if(inest.eq.1.and.ivar.ge.3.and.(j.le.2.or.j.ge.jde-2)) then
1359!       write(6,*) '2 RETURN: IVAR = ',ivar,' J = ',j,
1360!    $             ' too close to boundary.'
1361    return
1362  endif
1363
1364! COMPUTE IPL WHICH REPRESENTS IVAR FOR EACH MESH IN SAVWT MODS
1365  ICUT=0
1366  IF(INEST.GT.1)ICUT=1
1367  i_s = max0(2+icut,its)
1368  i_e = min0(ide-1-icut,ite)
1369
1370  IPL=IVAR    + IPLO     !yliu +IPLO
1371
1372! DEFINE GRID-TYPE OFFSET FACTORS, IGRID AND GRID
1373
1374  IF(INEST.EQ.1)THEN
1375    INPF=NPFI
1376    INFR=IONF
1377  ELSE
1378    IF(IRATIO.NE.3) THEN
1379      IF (iprt) THEN
1380        write(6,*) 'iratio = ',iratio
1381        write(6,*) 'stop 1 in nudob: iratio = ',iratio
1382      ENDIF
1383      STOP 1
1384    ENDIF
1385    INPF=(3**LEVIDN(INEST))*NPFI
1386    INFR=(3**LEVIDN(INEST))*IONF
1387  ENDIF
1388  GRIDX=0.0
1389  GRIDY=0.0
1390  IGRID=0
1391  IF(IVAR.GE.3)THEN
1392    GRIDX=0.5
1393    GRIDY=0.5
1394    IGRID=1
1395  ELSEIF(IVAR.eq.1) THEN
1396    GRIDY=0.5
1397    IGRID=1
1398  ELSEIF(IVAR.eq.2) THEN
1399    GRIDX=0.5
1400    IGRID=1
1401  ENDIF
1402
1403! TRANSFORM THE HORIZONTAL RADIUS OF INFLUENCE, RINXY, FROM
1404! KILOMETERS TO GRID LENGTHS, RINDX
1405
1406  RINDX=RINXY*1000./DX          * RFACTOR   !yliu *RFACTOR
1407
1408! jc
1409! make horizontal radius vary per nest
1410!     rindx=rindx/float(inest)
1411! yliu test1 -- En 3, 4
1412!     rindx=rindx/float(3**(in-1))                                               !YLIU
1413! jc
1414! make horizontal radius vary per nest
1415!     schnes=1/float(inest)                                                      !JC
1416! yliu test1 -- En 3, 4                                                          !YLIU
1417  schnes=1/float(3**(inest-1))                                                   !JC
1418! reduce the Rinf in the nested grid proportionally
1419  rindx=rindx*schnes
1420! rinfmn =1., rinfmx=2., pfree=50 in param.F
1421! yliu test: for upper-air data, use larger influence radii
1422!            Essentially increase the slope -- the same radii
1423!            at 500mb and above as the coarse mesh and the
1424!            same small radii at sfc as that for sfc obs
1425  fdob%rinfmx=2. *1.0 /schnes                                                    !YLIU
1426!         rinfmx=1.2*1.0 /schnes                                                 !YLIU
1427! jc
1428  RIS=RINDX*RINDX
1429  IF(IFREST.AND.KTAU.EQ.KTAUR)GOTO 5
1430  IF(MOD(KTAU,INFR).NE.0)GOTO 126
14315 CONTINUE
1432  IF (iprt) THEN
1433   IF(J.EQ.10) write(6,6) INEST,J,KTAU,XTIME,IVAR,IPL,rindx
1434  ENDIF
14356 FORMAT(1X,'OBS NUDGING FOR IN,J,KTAU,XTIME,',                    &
1436            'IVAR,IPL: ',I2,1X,I2,1X,I5,1X,F8.2,1X,I2,1X,I2,       &
1437            ' rindx=',f4.1)
1438
1439! SET RA AND RB
1440  IF(INEST.EQ.1) THEN
1441
1442! SET RA AND RB FOR THE COARSE MESH...
1443    DO N=1,NSTAT
1444      RA(N)=RIO(N)-GRIDX
1445      RB(N)=RJO(N)-GRIDY
1446    ENDDO
1447
1448  ELSE
1449
1450! SET RA AND RB FOR THE FINE MESH CASE...
1451    DO N=1,NSTAT
1452
1453! COMPUTE THE OBS LOCATION WITH RESPECT TO THIS MESH (INEST)...
1454      NML=INEST
1455      MM(LEVIDN(INEST)+1)=INEST
1456! WORKING TOWARD COARSER MESHES, DETERMINE THE HIERARCHY OF MOTHER
1457! MESHES WITH RESPECT TO EACH MOTHER MESH STARTING AT MESH "INEST"...
1458! THAT IS, DETERMINE ITS MOTHER, GRANDMOTHER, GREAT-GRANDMOTHER, ETC.
1459! OUT TO THE COARSE GRID MESH (INEST=1).
1460! LEVIDN HOLDS THE NEST LEVEL AND PARID HOLDS THE MOTHER MESH FOR EACH
1461! GRID (E.G., FOR 3 MESHES AND 2 NEST LEVELS, INEST=1 IS THE COARSE GRID
1462! MESH, INEST=2 HAS LEVIDN(2)=1 AND PARID(2)=1, AND INEST=3 HAS LEVIDN(3)=2
1463! AND PARID(3)=2...)
1464      DO NNL=LEVIDN(INEST),1,-1
1465        MM(NNL)=PARID(NML)
1466        NML=MM(NNL)
1467      ENDDO
1468
1469! MM(1) MUST BE THE COARSE GRID MESH (INEST=0)
1470
1471      IF(MM(1).NE.1) then
1472        IF (iprt) write(6,*) 'stop 21 in nudob: inest = ',inest
1473        STOP 21
1474      ENDIF
1475      RA(N)=RIO(N)
1476      RB(N)=RJO(N)
1477      DO NNL=1,LEVIDN(INEST)
1478        GRFACX=0.
1479        GRFACY=0.
1480! COMPUTE THE OBS LOCATION WITH RESPECT TO THE INNER GRID IN DOT-POINT
1481! SPACE (GRID=0.).  WHEN WE REACH MESH IN, THEN USE "GRID" TO GO TO
1482! CROSS OR DOT DEPENDING ON THE VARIABLE...
1483        IF(NNL.EQ.LEVIDN(INEST)) THEN
1484          GRFACX=GRIDX
1485          GRFACY=GRIDY
1486        ENDIF
1487
1488        RA(N)=(RA(N)-FLOAT(i_parent_start(MM(NNL+1))))*       &
1489                     FLOAT(IRATIO)+1.-GRFACX
1490        RB(N)=(RB(N)-FLOAT(j_parent_start(MM(NNL+1))))*       &
1491                     FLOAT(IRATIO)+1.-GRFACY
1492
1493      ENDDO
1494
1495    ENDDO    ! END LOOP OVER OBS STATIONS FOR FINE MESH CASE
1496
1497  ENDIF    ! END SECTION FOR SETTING RA AND RB
1498
1499
1500! OUTPUT OBS PER GRID EVERY HOUR
1501  if ( mod(xtime,60.).gt.56. .and. ivar.eq.3 .and. j.eq.10) then
1502    IF (iprt) print *,'outputting obs number on grid ',    &
1503                 inest,' at time=',xtime
1504    write(chr_hr(1:3),'(i3)')nint(xtime/60.)
1505    if(chr_hr(1:1).eq.' ')chr_hr(1:1)='0'
1506    if(chr_hr(2:2).eq.' ')chr_hr(2:2)='0'
1507    IF (iprt) print *,'chr_hr=',chr_hr(1:3),nint(xtime/60.)
1508    open(91,file=                                             &
1509        'obs_g'//char(inest+ichar('0'))//'_'//chr_hr(1:3),    &
1510        form='FORMATted',status='unknown')
1511    write(91,911)nstat
1512    write(6,911)nstat
1513911 FORMAT('total obs=',i8)
1514    nsthis=0
1515    nsmetar=0
1516    nsspeci=0
1517    nsship=0
1518    nssynop=0
1519    nstemp=0
1520    nspilot=0
1521    nssatwnds=0
1522    nssams=0
1523    nsprofs=0
1524!   print *,'ide,jde=',ide,jde
1525    do jjjn=1,nstat
1526! DETERMINE THE TIME-WEIGHT FACTOR FOR N
1527      FDTIM=XTIME-DTMIN
1528! CONVERT TWINDO AND TIMEOB FROM HOURS TO MINUTES:
1529      TW1=TWINDO/2.*60.
1530      TW2=TWINDO*60.
1531      TCONST=1./TW1
1532      TIMEWT2=0.0
1533      TTIM=TIMEOB(jjjn)*60.
1534!***********TTIM=TARGET TIME IN MINUTES
1535      DIFT=ABS(FDTIM-TTIM)
1536      IF(DIFT.LE.TW1)TIMEWT2=1.0
1537
1538      IF(DIFT.GT.TW1.AND.DIFT.LE.TW2) THEN
1539        IF(FDTIM.LT.TTIM)TIMEWT2=(FDTIM-(TTIM-TW2))*TCONST
1540        IF(FDTIM.GT.TTIM)TIMEWT2=((TTIM+TW2)-FDTIM)*TCONST
1541      ENDIF
1542
1543!     print *,'timewt2=',timewt2,ttim,fdtim
1544      if (ra(jjjn).ge.1. .and. rb(jjjn).ge.1.                    &
1545      .and.ra(jjjn).le.real(ide) .and. rb(jjjn).le.real(jde)     &
1546      .and.timewt2.gt.0.) then
1547        if(lev_in_ob(jjjn).eq.1.)nsthis=nsthis+1
1548        if(plfo(jjjn).eq.1.)nsmetar=nsmetar+1
1549        if(plfo(jjjn).eq.2.)nsspeci=nsspeci+1
1550        if(plfo(jjjn).eq.3.)nsship=nsship+1
1551        if(plfo(jjjn).eq.4.)nssynop=nssynop+1
1552        if(plfo(jjjn).eq.5..and.lev_in_ob(jjjn).eq.1.) nstemp=nstemp+1
1553        if(plfo(jjjn).eq.6..and.lev_in_ob(jjjn).eq.1.) nspilot=nspilot+1
1554        if(plfo(jjjn).eq.7.)nssatwnds=nssatwnds+1
1555        if(plfo(jjjn).eq.8.)nssams=nssams+1
1556        if(plfo(jjjn).eq.9..and.lev_in_ob(jjjn).eq.1.) nsprofs=nsprofs+1
1557      endif
1558    enddo
1559    write(91,912)nsthis
1560    write(6,912)nsthis
1561912 FORMAT('total obs on this grid=',i8)
1562    write(91,921)nsmetar
1563    write(6,921)nsmetar
1564921 FORMAT('total metar obs on this grid=',i8)
1565    write(91,922)nsspeci
1566    write(6,922)nsspeci
1567922 FORMAT('total special obs on this grid=',i8)
1568    write(91,923)nsship
1569    write(6,923)nsship
1570923 FORMAT('total ship obs on this grid=',i8)
1571    write(91,924)nssynop
1572    write(6,924)nssynop
1573924 FORMAT('total synop obs on this grid=',i8)
1574    write(91,925)nstemp
1575    write(6,925)nstemp
1576925 FORMAT('total temp obs on this grid=',i8)
1577    write(91,926)nspilot
1578    write(6,926)nspilot
1579926 FORMAT('total pilot obs on this grid=',i8)
1580    write(91,927)nssatwnds
1581    write(6,927)nssatwnds
1582927 FORMAT('total sat-wind obs on this grid=',i8)
1583    write(91,928)nssams
1584    write(6,928)nssams
1585928 FORMAT('total sams obs on this grid=',i8)
1586    write(91,929)nsprofs
1587    write(6,929)nsprofs
1588929 FORMAT('total profiler obs on this grid=',i8)
1589    close(91)
1590  endif  ! END OUTPUT OBS PER GRID EVERY HOUR
1591
1592
1593! INITIALIZE WEIGHTING ARRAYS TO ZERO
1594  DO I=its,ite
1595    DO K=1,kte
1596      WT(I,K)=0.0
1597      WT2ERR(I,K)=0.0
1598    ENDDO
1599  ENDDO
1600
1601! DO P* COMPUTATIONS ON DOT POINTS FOR IVAR.LT.3 (U AND V)
1602! AND CROSS POINTS FOR IVAR.GE.3 (T,Q,P*).
1603!
1604! COMPUTE P* AT OBS LOCATION (RA,RB).  DO THIS AS SEPARATE VECTOR LOOP H
1605! SO IT IS ALREADY AVAILABLE IN NSTAT LOOP 120 BELOW
1606
1607! PSURF IS NOT AVAILABLE GLOBALLY, THEREFORE, THE BILINEAR INTERPOLATION
1608! AROUND THE OBS POINT IS DONE IN ERROB() AND STORED IN ERRF([678],N) FOR
1609! THE POINT (6=PRESS, 7=U-MOM, 8=V-MOM).
1610  DO N=1,NSTAT
1611    IF(IVAR.GE.3)THEN
1612      PSURF(N)=ERRF(6,N)
1613    ELSE
1614      IF(IVAR.EQ.1)THEN
1615        PSURF(N)=ERRF(7,N)        ! U-points
1616      ELSE
1617        PSURF(N)=ERRF(8,N)        ! V-points
1618      ENDIF
1619    ENDIF
1620  ENDDO
1621
1622! DETERMINE THE LIMITS OF THE SEARCH REGION FOR THE CURRENT
1623! J-STRIP
1624
1625  MAXJ=J+IFIX(RINDX*fdob%RINFMX+0.99)                                        !ajb
1626  MINJ=J-IFIX(RINDX*fdob%RINFMX+0.99)                                        !ajb
1627
1628! jc comment out this? want to use obs beyond the domain?
1629!      MAXJ=MIN0(JL-IGRID,MAXJ)           !yliu
1630!      MINJ=MAX0(1,MINJ)                  !yliu
1631
1632  n=1
1633
1634!***********************************************************************
1635  DO nnn=1,NSTAT   ! BEGIN OUTER LOOP FOR THE NSTAT OBSERVATIONS
1636!***********************************************************************
1637! Soundings are consecutive obs, but they need to be treated as a single
1638! entity. Thus change the looping to nnn, with n defined separately.
1639
1640
1641!yliu
1642!  note for sfc data: nsndlev=1 and njcsnd=1
1643    nsndlev=int(nlevs_ob(n)-lev_in_ob(n))+1   
1644
1645! yliu start -- set together with the other parts
1646! test: do the sounding levels as individual obs
1647!   nsndlev=1
1648! yliu end
1649    njcsnd=nsndlev
1650! set pob here, to be used later
1651    pob=varobs(5,n)
1652!     print *, "s-- n=,nsndlev",n,njcsnd,J, ipl
1653!     print *, "s--",ivar,(errf(ivar,i),i=n,n+njcsnd)
1654! CHECK TO SEE OF STATION N HAS DATA FOR VARIABLE IVAR
1655! AND IF IT IS SUFFICIENTLY CLOSE TO THE J STRIP.  THIS
1656! SHOULD ELIMINATE MOST STATIONS FROM FURTHER CONSIDER-
1657! ATION.
1658
1659!yliu: Skip bad obs if it is sfc or single level sounding.
1660!yliu: Before this (020918), a snd will be skipped if its first
1661!yliu        level has bad data- often true due to elevation
1662
1663    IF( ABS(ERRF(IVAR,N)).GT.9.E4 .and. njcsnd.eq.1 ) THEN
1664!     print *, " bad obs skipped"
1665
1666    ELSEIF( RB(N).LT.FLOAT(MINJ) .OR. RB(N).GT.FLOAT(MAXJ) ) THEN
1667!     print *, " skipped obs far away from this J-slice"
1668
1669!----------------------------------------------------------------------
1670    ELSE    ! BEGIN SECTION FOR PROCESSING THE OBSERVATION
1671!----------------------------------------------------------------------
1672
1673! DETERMINE THE TIME-WEIGHT FACTOR FOR N
1674      FDTIM=XTIME-DTMIN
1675! TWINDO IS IN MINUTES:
1676      TW1=TWINDO/2.*60.
1677      TW2=TWINDO*60.
1678      TCONST=1./TW1
1679      TIMEWT=0.0
1680      TTIM=TIMEOB(N)*60.
1681!***********TTIM=TARGET TIME IN MINUTES
1682      DIFT=ABS(FDTIM-TTIM)
1683      IF(DIFT.LE.TW1)TIMEWT=1.0
1684      IF(DIFT.GT.TW1.AND.DIFT.LE.TW2) THEN
1685        IF(FDTIM.LT.TTIM)TIMEWT=(FDTIM-(TTIM-TW2))*TCONST
1686        IF(FDTIM.GT.TTIM)TIMEWT=((TTIM+TW2)-FDTIM)*TCONST
1687      ENDIF
1688
1689! DETERMINE THE LIMITS OF APPLICATION OF THE OBS IN THE VERTICAL
1690! FOR THE VERTICAL WEIGHTING, WTSIG
1691
1692! ASSIMILATE OBSERVATIONS ON PRESSURE LEVELS, EXCEPT FOR SURFACE
1693!ajb 20021210: (Bugfix) RKO is not available globally. It is computed in
1694!ajb ERROB() by the processor handling the obs point, and stored in ERRF(9,N).
1695
1696#if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
1697      rko(n) = errf(9,n)        !ajb 20021210
1698#endif
1699      KOB=nint(RKO(N))
1700      KOB=MIN0(kte,KOB)
1701      KOB=MAX0(1,KOB)
1702
1703! ASSIMILATE SURFACE LAYER DATA ON SIGMA
1704      IF(KOB.EQ.1.AND.IVAR.LE.4.and.nlevs_ob(n).lt.1.5) THEN
1705        DO K=1,kte
1706          WTSIG(K)=0.0
1707        ENDDO
1708! DEFINE WTSIG: (FOR SRP: SPREAD SURFACE DATA THROUGH LOWEST 200 M)
1709!       WTSIG(1)=1.0
1710!       WTSIG(2)=0.67
1711!       WTSIG(3)=0.33
1712!       KOMIN=3
1713!       KOMAX=1
1714! DEFINE THE MAX AND MIN I VALUES FOR POSSIBLE NONZERO
1715! WEIGHTS, BASED ON THE RADIUS OF INFLUENCE, RINDX (IN GRID LENGTHS).
1716! fix this because kpblt at 1 and il is 0
1717        MAXI=IFIX(RA(N)+0.99+RINDX)
1718        MAXI=MIN0(ide-1,MAXI)
1719        MINI=IFIX(RA(N)-RINDX-0.99)
1720        MINI=MAX0(2,MINI)
1721!yliu start
1722! use also obs outside of this domain  -- surface obs
1723!     if(RA(N).LT.0.-RINDX .or. RA(N).GT.float(IL+RINDX) .or.
1724!    &   RB(N).LT.0.-RINDX .or. RB(N).GT.float(JL+RINDX)) then
1725!        print *, " skipped obs far away from this domain"
1726! currently can use obs within this domain or ones very close to (1/3
1727!   influence of radius in the coarse domain) this
1728!   domain. In later case, use BC column value to approximate the model value
1729!   at obs point -- ERRF need model field in errob.F !!
1730        if (  RA(N).GE.(0.-RINDX/3)                        &
1731        .and. RA(N).LE.float(ide)+RINDX/3                  &
1732        .and. RB(N).GE.(0.-RINDX/3)                        &
1733        .and. RB(N).LE.float(jde)+RINDX/3) then
1734
1735! or use obs within this domain only
1736!     if(RA(N).LT.1 .or. RA(N).GT.float(IL) .or.
1737!    &   RB(N).LT.1 .or. RB(N).GT.float(JL)) then
1738!        print *, " skipped obs far outside of this domain"
1739!        if(j.eq.3 .and. ivar.eq.3) then
1740!           write(6,*) 'N = ',n,' exit 120 3'
1741!        endif
1742!yliu end
1743!
1744! LOOP THROUGH THE NECESSARY GRID POINTS SURROUNDING
1745! OBSERVATION N.  COMPUTE THE HORIZONTAL DISTANCE TO
1746! THE OBS AND FIND THE WEIGHTING SUM OVER ALL OBS
1747          RJ=FLOAT(J)
1748          RX=RJ-RB(N)
1749! WEIGHTS FOR THE 3-D VARIABLES
1750          ERFIVR=ERRF(IVAR,N)
1751!
1752!JM I will be local, because it indexes into PDOC, WT, and others
1753
1754!      if((ivar.eq.1 .or. ivar.eq.3) .and. n.le.200) then
1755!        write(6,'(a,i3,a,i3)')'SURF OBS NEAR: N = ',n,' nest = ',inest
1756!        write(6,'(a,f10.3,a,f10.3,a,i3,a,i3,a,i3,a,i2)')
1757!     $        ' RA =',RA(N),' RB =',RB(N),' J =',j,
1758!     $        ' MINI =',MINI,' MAXI =',MAXI,' NEST =',inest
1759!      endif
1760
1761          DO I=max0(its,MINI),min0(ite,MAXI)
1762
1763            RI=FLOAT(I)
1764            RY=RI-RA(N)
1765            RIS=RINDX*RINDX
1766            RSQ=RX*RX+RY*RY
1767!           DPRIM=SQRT(RSQ)
1768! THIS FUNCTION DECREASES WTIJ AS PSFC CHANGES WITHIN SEARCH RADIUS
1769!           D=DPRIM+RINDX*DCON*ABS(PSBO(N)-PDOC(I,J))
1770!           DSQ=D*D
1771!           WTIJ=(RIS-DSQ)/(RIS+DSQ)
1772            wtij=(ris-rsq)/(ris+rsq)
1773            scratch = (abs(psurf(n)-.001*pbase(i,1))*fdob%DCON)
1774            pdfac=1.-AMIN1(1.0,scratch)
1775            wtij=wtij*pdfac
1776            WTIJ=AMAX1(0.0,WTIJ)
1777
1778! try making sfc obs weighting go thru pbl
1779! jc kpbl is at dot or cross only - need to interpolate?
1780!          wtsig(1)=1.
1781            komax=max0(3,kpblt(i))
1782
1783! jc arbitrary check here
1784            IF (iprt) THEN
1785              if (kpblt(i).gt.25 .and. ktau.ne.0)                         &
1786                                     write(6,552)inest,i,j,kpblt(i)
1787552           FORMAT('kpblt is gt 25, inest,i,j,kpblt=',4i4)
1788            ENDIF
1789
1790            if(kpblt(i).gt.25) komax=3
1791            komin=1
1792            dk=float(komax)
1793
1794            do k=komin,komax
1795 
1796              wtsig(k)=float(komax-k+1)/dk
1797              WT(I,K)=WT(I,K)+TIMEWT*WTSIG(K)*WTIJ
1798
1799              WT2ERR(I,K)=WT2ERR(I,K)+TIMEWT*TIMEWT*WTIJ*WTIJ*WTSIG(K)    &
1800                          *WTSIG(K)*ERFIVR
1801
1802!            if(ivar.eq.1 .and. i.eq.38 .and. j.eq.78) then
1803!
1804!             write(6,'(a,i2,a,f8.3,a,f8.3,a,f8.3,a,f8.3,a,f8.3)')
1805!                         'Surface obs, after: k = ',k,            &
1806!                         ' WT2ERR = ',wt2err(i,k),                &
1807!                         ' TIMEWT = ',timewt,                     &
1808!                         ' WTIJ = ',wtij,                         &
1809!                         ' WSIG = ',wtsig(k),                     &
1810!                         ' ERFIVR = ',erfivr
1811!            endif
1812
1813            enddo
1814
1815          ENDDO
1816
1817!         print *, "  Surface "
1818
1819        endif   ! end check for obs in domain
1820! END SURFACE-LAYER U OR V OBS NUDGING
1821
1822      ELSE   
1823! BEGIN CALCULATIONS TO SPREAD OBS INFLUENCE ALONG PRESSURE LEVELS
1824!
1825!       print *,'in upper air section'
1826! DEFINE THE MAX AND MIN I VALUES FOR POSSIBLE NONZERO
1827! WEIGHTS, BASED ON THE RADIUS OF INFLUENCE, RINDX, AND RINFAC.
1828! RINFAC VARIES AS A LINEAR FUNCTION FROM FROM RINFMN AT P*+PTOP
1829! TO RINFMX AT PFREE AND "ABOVE" (LOWER PRESSURE).
1830!ajb          SLOPE=(RINFMN-RINFMX)/(PSBO(N)+PTOP-PFREE)
1831
1832        slope = (fdob%RINFMN-fdob%RINFMX)/(psurf(n)-fdob%PFREE)
1833
1834        RINFAC=SLOPE*POB+fdob%RINFMX-SLOPE*fdob%pfree
1835        RINFAC=AMAX1(RINFAC,fdob%RINFMN)
1836        RINFAC=AMIN1(RINFAC,fdob%RINFMX)
1837!yliu: for multilevel upper-air data, take the maximum
1838!      for the I loop.
1839        if(nsndlev.gt.1) RINFAC = fdob%RINFMX
1840!yliu end
1841
1842        MAXI=IFIX(RA(N)+0.99+RINDX*RINFAC)
1843        MAXI=MIN0(ide-IGRID,MAXI)
1844        MINI=IFIX(RA(N)-RINDX*RINFAC-0.99)
1845        MINI=MAX0(1,MINI)
1846
1847! yliu start
1848! use also obs outside of but close to this domain  -- upr data   
1849!     if(   RA(N).LT.(0.-RINFAC*RINDX)
1850!    & .or. RA(N).GT.float(IL)+RINFAC*RINDX
1851!    & .or. RB(N).LT.(0.-RINFAC*RINDX)
1852!    & .or. RB(N).GT.float(JL)+RINFAC*RINDX)then         
1853!        print *, " skipped obs far away from this I-range"
1854! currently can use obs within this domain or ones very close to (1/3
1855!   influence of radius in the coarse domain) this
1856!   domain. In later case, use BC column value to approximate the model value
1857!   at obs point -- ERRF need model field in errob.F !!
1858
1859!cc         if (i.eq.39 .and. j.eq.34) then
1860!cc            write(6,*) 'RA(N) = ',ra(n)
1861!cc            write(6,*) 'rinfac = ',rinfac,' rindx = ',rindx
1862!cc         endif
1863        if(   RA(N).GE.(0.-RINFAC*RINDX/3)                      &
1864        .and. RA(N).LE.float(ide)+RINFAC*RINDX/3                &
1865        .and. RB(N).GE.(0.-RINFAC*RINDX/3)                      &
1866        .and. RB(N).LE.float(jde)+RINFAC*RINDX/3) then
1867! or use obs within this domain only
1868!     if(RA(N).LT.1 .or. RA(N).GT.float(IL) .or.
1869!    &   RB(N).LT.1 .or. RB(N).GT.float(JL)) then
1870!        print *, " skipped obs far outside of this domain"
1871
1872! yliu end
1873! is this 2 needed here - kpbl not used?
1874!          MINI=MAX0(2,MINI)
1875
1876! LOOP THROUGH THE NECESSARY GRID POINTS SURROUNDING
1877! OBSERVATION N.  COMPUTE THE HORIZONTAL DISTANCE TO
1878! THE OBS AND FIND THE WEIGHTING SUM OVER ALL OBS
1879          RJ=FLOAT(J)
1880          RX=RJ-RB(N)
1881! WEIGHTS FOR THE 3-D VARIABLES
1882!
1883          ERFIVR=ERRF(IVAR,N)
1884! jc
1885          nsndlev=int(nlevs_ob(n)-lev_in_ob(n))+1
1886! yliu start
1887! test: do the sounding levels as individual obs
1888!        nsndlev=1
1889! yliu end
1890          njcsnd=nsndlev
1891!
1892          DO I=max0(its,MINI),min0(ite,MAXI)
1893! jc
1894            RI=FLOAT(I)
1895            RY=RI-RA(N)
1896            RIS=RINDX*RINFAC*RINDX*RINFAC
1897            RSQ=RX*RX+RY*RY
1898! yliu test: for upper-air data, keep D1 influence radii
1899!           RIS=RIS  /schnes /schnes
1900            WTIJ=(RIS-RSQ)/(RIS+RSQ)
1901            WTIJ=AMAX1(0.0,WTIJ)
1902! weight ob in vertical with +- 50 mb
1903! yliu: 75 hba for single upper-air, 30hba for multi-level soundings
1904            if(nsndlev.eq.1) then
1905              rinprs=7.5
1906            else
1907             rinprs=3.0
1908            endif
1909! yliu end
1910!
1911!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
1912!   ---  HANDLE 1-LEVEL and MULTI-LEVEL OBSERVATIONS SEPARATELY  ---
1913!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
1914
1915            if(nsndlev.eq.1)then
1916!----------------------------------------------------------------------
1917!         ---   HANDLE 1-LEVEL OBSERVATIONS  ---
1918!----------------------------------------------------------------------
1919
1920!         if(I.eq.MINI) print *, "  Single snd "
1921! ERFIVR is the residual (difference) between the ob and the model
1922! at that point. We can analyze that residual up and down.
1923! First find komin for ob.
1924!yliu start -- in the old code, komax and komin were reversed!
1925              do k=kte,1,-1
1926                pijk = .001*(pbase(i,k)+pp(i,k))
1927!               print *,'k,pijk,pob,rinprs=',k,pijk,pob,rinprs
1928                if(pijk.ge.(pob+rinprs)) then
1929                  komin=k
1930                  go to 325
1931                endif
1932              enddo
1933              komin=1
1934 325          continue
1935! now find komax for ob
1936              do k=3,kte
1937                pijk = .001*(pbase(i,k)+pp(i,k))
1938                if(pijk.le.(pob-rinprs)) then
1939                  komax=k
1940                  go to 326
1941                endif
1942              enddo
1943              komax=kte   ! yliu 20050706
1944 326          continue
1945
1946! yliu: single-level upper-air data will act either above or below the PBL top
1947!          komax=min0(kpblt(i), komax)
1948              if(komax.gt.kpblt(i)) komin=max0(kpblt(i), komin)
1949              if(komin.lt.kpblt(i)) komax=min0(kpblt(i), komax)
1950! yliu end
1951!
1952!           print *,'1 level, komin,komax=',komin,komax
1953!           if(i.eq.MINI) then
1954!             print *, "yyyyyyyyyyS IPL erfivr=", IPL, ERFIVR,J,pob
1955!             ERFIVR=0
1956!           endif
1957              do k=1,kte
1958                reserf(k)=0.0
1959                wtsig(k)=0.0
1960              enddo
1961!yliu end
1962
1963!cc         if (i.eq.39 .and. j.eq.34) then
1964!cc              write(6,*) ' komin = ', komin,' komax = ',komax
1965!cc         endif
1966
1967              do k=komin,komax
1968                pijk = .001*(pbase(i,k)+pp(i,k))
1969                reserf(k)=erfivr
1970                wtsig(k)=1.-abs(pijk-pob)/rinprs
1971                wtsig(k)=amax1(wtsig(k),0.0)
1972!             print *,'k,pijk,pob,rinprs,wtsig=',k,pijk,pob,rinprs,wtsig(k)
1973! Now calculate WT and WT2ERR for each i,j,k point                      cajb
1974                WT(I,K)=WT(I,K)+TIMEWT*WTIJ*wtsig(k)
1975
1976                WT2ERR(I,K)=WT2ERR(I,K)+TIMEWT*TIMEWT*WTIJ*WTIJ*        &
1977                            reserf(k)*wtsig(k)*wtsig(k)
1978              enddo
1979
1980            else
1981!----------------------------------------------------------------------
1982!         ---   HANDLE MULTI-LEVEL OBSERVATIONS  ---
1983!----------------------------------------------------------------------
1984!yliu start
1985!           if(I.eq.MINI) print *, "  Multi-level  snd "
1986!             print *, "   n=,nsndlev",n,nsndlev,nlevs_ob(n),lev_in_ob(n)  &
1987!                  ,nlevs_ob(n+nsndlev-1),lev_in_ob(n+nsndlev-1)
1988              if(nlevs_ob(n+nsndlev-1).ne.lev_in_ob(n+nsndlev-1)) then
1989                IF (iprt) THEN
1990                  print *, "n = ",n,"nsndlev = ",nsndlev
1991                  print *, "nlevs_ob,lev_in_ob",                          &
1992                           nlevs_ob(n+nsndlev-1),lev_in_ob(n+nsndlev-1)
1993                  print *, "in nudobs.F: sounding level messed up, stopping"
1994                ENDIF
1995                stop
1996              endif       
1997!yliu end
1998! This is for a multi-level observation
1999! The trick here is that the sounding is "one ob". You don't
2000!    want multiple levels to each be treated like separate
2001!    and independent observations.
2002! At each i,j want to interpolate sounding to the model levels at that
2003!    particular point.
2004              komin=1
2005              komax=kte-2
2006! this loop goes to 1501
2007! do from kte-2 to 1 so don't adjust top of model. Arbitrary.
2008!yliu start
2009              do k=1,kte
2010                reserf(k)=0.0
2011                wtsig(k)=0.0
2012              enddo
2013!yliu end
2014
2015              do k=komax,komin,-1
2016 
2017                pijk = .001*(pbase(i,k)+pp(i,k))
2018
2019! if sigma level pressure is .gt. than the lowest ob level, don't interpolate
2020                if(pijk.gt.varobs(5,n)) then
2021                  go to 1501
2022                endif
2023
2024! if sigma level pressure is .lt. than the highest ob level, don't interpolate
2025                if(pijk.le.varobs(5,n+nsndlev-1)) then
2026                  go to 1501
2027                endif
2028
2029! now interpolate sounding to this k
2030! yliu start-- recalculate WTij for each k-level
2031!ajb      SLOPE = (fdob%RINFMN-fdob%RINFMX)/(pdoc(i,j)+PTOP-fdob%PFREE)       
2032                slope = (fdob%RINFMN-fdob%RINFMX)/ (.001*pbase(i,1)-fdob%PFREE)
2033                RINFAC=SLOPE*pijk+fdob%RINFMX-SLOPE*fdob%PFREE             
2034                RINFAC=AMAX1(RINFAC,fdob%RINFMN)     
2035                RINFAC=AMIN1(RINFAC,fdob%RINFMX)
2036                RIS=RINDX*RINFAC*RINDX*RINFAC 
2037                RSQ=RX*RX+RY*RY               
2038
2039! for upper-air data, keep D1 influence radii
2040!         RIS=RIS  /schnes /schnes
2041                WTIJ=(RIS-RSQ)/(RIS+RSQ)     
2042                WTIJ=AMAX1(0.0,WTIJ)
2043! yliu end
2044
2045! this loop goes to 1503
2046                do nn=2,nsndlev
2047! only set pobhi if varobs(ivar) is ok
2048                  pobhi=-888888.
2049
2050                  if(varobs(ivar,n+nn-1).gt.-800000.                           &
2051                  .and. varobs(5,n+nn-1).gt.-800000.) then
2052                    pobhi=varobs(5,n+nn-1)
2053                    nhi=n+nn-1
2054                    if(pobhi.lt.pijk .and. abs(pobhi-pijk).lt.20.) then
2055                      go to 1502        ! within 200mb of obs height
2056                    endif
2057                  endif
2058
2059                enddo
2060
2061! did not find any ob above within 100 mb, so jump out
2062                go to 1501
2063 1502           continue
2064
2065                nlo=nhi-1
2066                do nnjc=nhi-1,n,-1
2067                  if(varobs(ivar,nnjc).gt.-800000.                             &
2068                  .and. varobs(5,nnjc).gt.-800000.) then
2069                    poblo=varobs(5,nnjc)
2070                    nlo=nnjc
2071                    if(poblo.gt.pijk .and. abs(poblo-pijk).lt.20.) then
2072                      go to 1505        ! within 200mb of obs height
2073                    endif
2074                  endif
2075                enddo
2076!yliu end --
2077
2078! did not find any ob below within 200 mb, so jump out
2079                go to 1501
2080 1505           continue
2081
2082! interpolate to model level
2083                pdiffj=alog(pijk/poblo)/alog(pobhi/poblo)
2084                reserf(k)=errf(ivar,nlo)+                               &
2085                            (errf(ivar,nhi)-errf(ivar,nlo))*pdiffj
2086                wtsig(k)=1.
2087 
2088 1501           continue
2089
2090! now calculate WT and WT2ERR for each i,j,k point                               cajb
2091                WT(I,K)=WT(I,K)+TIMEWT*WTIJ*wtsig(k)
2092 
2093                WT2ERR(I,K)=WT2ERR(I,K)+TIMEWT*TIMEWT*WTIJ*WTIJ*        &
2094                            reserf(k)*wtsig(k)*wtsig(k)
2095
2096!        if(ivar.eq.1 .and. i.eq.38 .and. j.eq.78) then
2097!
2098!            if(wt(i,k) .ne. 0.0) then
2099!               scratch = WT2ERR(I,K)/WT(I,K)
2100!            else
2101!               scratch = 999.
2102!            endif
2103!
2104!         write(6,'(a,i2,a,f8.3,a,f4.2,a,f7.4,a,f4.2,a,f5.3,a,f7.4)')
2105!    $                    'Multi-level obs: k = ',k,
2106!    $                    ' WT2ERR = ',wt2err(i,k),
2107!    $                    ' WTIJ = ',wtij,
2108!    $                    ' RSF = ',reserf(k),
2109!    $                    ' WSIG = ',wtsig(k),
2110!    $                    ' WT = ',wt(i,k),
2111!    $                    ' W2EOWT = ',scratch
2112!        endif
2113
2114
2115! end do k
2116              enddo   ! enddo k levels
2117! end multi-levels
2118            endif  ! end if(nsndlev.eq.1)
2119!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
2120!   END 1-LEVEL AND MULTI-LEVEL OBSERVATIONS
2121!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
2122!
2123          ENDDO ! END DO MINI,MAXI LOOP
2124
2125        endif ! check for obs in domain
2126
2127! END OF NUDGING TO OBS ON PRESSURE LEVELS
2128
2129      ENDIF !end IF(KOB.EQ.1.AND.IVAR.LE.4.and.nlevs_ob(n).lt.1.5)
2130
2131!----------------------------------------------------------------------
2132    ENDIF  ! END SECTION FOR PROCESSING OF OBSERVATION
2133!----------------------------------------------------------------------
2134
2135!   n=n+1
2136    n=n+njcsnd
2137
2138!yliu  1202 continue
2139    if(n.gt.nstat)then
2140!     print *,'n,nstat=',n,nstat,ivar,j
2141      go to 1203
2142    endif
2143!   print *, "e-- n=,nsndlev",n,njcsnd,nlevs_ob(n),lev_in_ob(n)
2144
2145!***********************************************************************
2146  ENDDO  ! END OUTER LOOP FOR THE NSTAT OBSERVATIONS
2147!***********************************************************************
2148
2149 1203 continue
2150
2151! WEIGHTS AND WEIGHTED DIFFERENCES HAVE BEEN SUMMED.  NOW
2152! APPLY THE NUDGING FACTOR AND THE RESULTANT TENDENCY TO
2153! THE ATEN ARRAY
2154! ASSURE THAT WT(I,K) AND WTP(I,K) ARE NONZERO SINCE
2155! THEY ARE USED BELOW IN THE DENOMINATOR.
2156  DO K=kts,kte
2157    DO I=its,ite
2158      IF(WT(I,K).EQ.0)THEN
2159        WT2ERR(I,K)=0.0
2160      ENDIF
2161      IF(WT(I,K).EQ.0)THEN
2162        WT(I,K)=1.0
2163      ENDIF
2164    ENDDO
2165  ENDDO
2166
2167126 CONTINUE
2168
2169  IF(IVAR.GE.3)GOTO 170
2170! this is for u,v
2171! 3-D DOT POINT TENDENCIES
2172 
2173! Calculate scales for converting nudge factor from u (v)
2174! to rho_u (or rho_v) units.
2175 
2176  call calc_rcouple_scales(mu,msf,rscale,ims,ime,its,ite)
2177 
2178  DO K=1,kte
2179
2180    DO I=i_s,i_e
2181
2182      IF(MOD(KTAU,INFR).EQ.0.OR.(IFREST.AND.KTAU.EQ.KTAUR))THEN
2183        W2EOWT=WT2ERR(I,K)/WT(I,K)
2184      ELSE
2185        W2EOWT=SAVWT(IPL,I,K)
2186      ENDIF
2187
2188!      if(ivar .eq. 1 .and. i.eq.38 .and. j.eq.78 .and. k.eq.1) then
2189!           scratch = GIV*RSCALE(I)*W2EOWT*fdob%TFACI*ISWIND*GFACTOR
2190!           write(6,*) 'ATEN calc: k = ',k
2191!           write(6,*) 'U before: aten = ',aten(i,k),' scr = ',scratch
2192!           write(6,*) 'GIV = ',giv,' rscale = ',rscale(i),
2193!     $               ' W2EOWT = ',w2eowt
2194!           write(6,*) 'TFACI = ',fdob%tfaci,' ISWIND = ',iswind,
2195!     $               ' GFACTOR = ',gfactor
2196!       endif
2197!
2198!      if(ivar .eq. 2 .and. i.eq.39 .and. j.eq.29) then
2199!           scratch = GIV*RSCALE(I)*W2EOWT*fdob%TFACI*ISWIND*GFACTOR
2200!           write(6,*) 'ATEN calc: k = ',k
2201!           write(6,*) 'V before: aten = ',aten(i,k),' scr = ',scratch
2202!           write(6,*) 'GIV = ',giv,' rscale = ',rscale(i),
2203!     $                ' W2EOWT = ',w2eowt
2204!           write(6,*) 'TFACI = ',fdob%tfaci,' ISWIND = ',iswind,
2205!     $                ' GFACTOR = ',gfactor
2206!       endif
2207
2208        ATEN(i,k)=ATEN(i,k)+GIV*RSCALE(I)                        &
2209                    *W2EOWT*fdob%TFACI                           &
2210                    *ISWIND       *GFACTOR   !yliu *GFACTOR
2211
2212!      if(ivar .eq. 1 .and. i.eq.38 .and. j.eq.78 .and. k.eq.1) then
2213!           write(6,*) 'U after: aten = ',aten(i,k),' scr = ',scratch
2214!      endif
2215!      if(ivar .eq. 2 .and. i.eq.39 .and. j.eq.29) then
2216!           write(6,*) 'V after: aten = ',aten(i,k),' scr = ',scratch
2217!      endif
2218
2219    ENDDO
2220  ENDDO
2221
2222  IF(MOD(KTAU,INFR).EQ.0.OR.(IFREST.AND.KTAU.EQ.KTAUR))THEN
2223    DO K=1,kte
2224      DO I=its,ite
2225        SAVWT(IPL,I,K)=WT2ERR(I,K)/WT(I,K)
2226      ENDDO
2227    ENDDO
2228  ENDIF
2229
2230  RETURN
2231
2232170 CONTINUE
2233
2234! 3-D CROSS-POINT TENDENCIES
2235! this is for t (ivar=3) and q (ivsr=4)
2236  IF(3-IVAR.LT.0)THEN
2237    GITQ=GIQ
2238  ELSE
2239    GITQ=GIT
2240  ENDIF
2241  IF(3-IVAR.LT.0)THEN
2242    ISTQ=ISMOIS
2243  ELSE
2244    ISTQ=ISTEMP
2245  ENDIF
2246
2247  DO K=1,kte
2248    DO I=i_s,i_e
2249      IF(MOD(KTAU,INFR).EQ.0.OR.(IFREST.AND.KTAU.EQ.KTAUR))THEN
2250        W2EOWT=WT2ERR(I,K)/WT(I,K)
2251      ELSE
2252        W2EOWT=SAVWT(IPL,I,K)
2253      ENDIF
2254
2255!        if(ivar .eq. 3 .and. i.eq.39 .and. j.eq.29) then
2256!            scratch = GITQ*MU(I)*W2EOWT*fdob%TFACI*ISTQ*GFACTOR
2257!            write(6,*) 'ATEN calc: k = ',k
2258!            write(6,*) 'T before: aten = ',aten(i,k),' scr = ',scratch
2259!            write(6,*) 'GITQ = ',gitq,' MU = ',mu(i),
2260!     $                 ' W2EOWT = ',w2eowt
2261!            write(6,*) ' TFACI = ',fdob%tfaci,' ISTQ = ',istq,
2262!     $                 ' GFACTOR = ',gfactor
2263!        endif
2264!
2265!        if(ivar .eq. 4 .and. i.eq.39 .and. j.eq.29) then
2266!            scratch = GITQ*MU(I)*W2EOWT*fdob%TFACI*ISTQ*GFACTOR
2267!            write(6,*) 'ATEN calc: k = ',k
2268!            write(6,*) 'Q before: aten = ',aten(i,k),' scr = ',scratch
2269!            write(6,*) 'GITQ = ',gitq,' MU = ',mu(i),
2270!     $                 ' W2EOWT = ',w2eowt
2271!            write(6,*) ' TFACI = ',fdob%tfaci,' ISTQ = ',istq,
2272!     $                 ' GFACTOR = ',gfactor
2273!        endif
2274
2275      ATEN(i,k)=ATEN(i,k)+GITQ*MU(I)                       &
2276                  *W2EOWT*fdob%TFACI*ISTQ       *GFACTOR   !yliu *GFACTOR
2277
2278!        if(ivar .eq. 3 .and. i.eq.39 .and. j.eq.29) then
2279!            write(6,*) 'T after: aten = ',aten(i,k),' scr = ',scratch
2280!        endif
2281!        if(ivar .eq. 4 .and. i.eq.39 .and. j.eq.29) then
2282!            write(6,*) 'Q after: aten = ',aten(i,k),' scr = ',scratch
2283!        endif
2284
2285    ENDDO
2286  ENDDO
2287
2288  IF(MOD(KTAU,INFR).EQ.0.OR.(IFREST.AND.KTAU.EQ.KTAUR)) THEN
2289    DO K=1,kte
2290      DO I=its,ite
2291        SAVWT(IPL,I,K)=WT2ERR(I,K)/WT(I,K)
2292      ENDDO
2293    ENDDO
2294  ENDIF
2295
2296  RETURN
2297  END SUBROUTINE nudob
2298
2299  SUBROUTINE calc_rcouple_scales(a, msf, rscale, ims,ime, its,ite)
2300!-----------------------------------------------------------------------
2301  IMPLICIT NONE
2302!-----------------------------------------------------------------------
2303
2304  INTEGER, INTENT(IN)  :: ims,ime           ! Memory dimensions
2305  INTEGER, INTENT(IN)  :: its,ite           ! Tile   dimensions
2306  REAL, INTENT(IN)     :: a( ims:ime )      ! Air mass array
2307  REAL, INTENT(IN)     :: msf( ims:ime )    ! Map scale factor array
2308  REAL, INTENT(OUT)    :: rscale( ims:ime ) ! Scales for rho-coupling
2309
2310! Local variables
2311  integer :: i
2312
2313! Calculate scales to be used for producing rho-coupled nudging factors.
2314  do i = its,ite
2315    rscale(i) = a(i)/msf(i)
2316  enddo
2317
2318  RETURN
2319  END SUBROUTINE calc_rcouple_scales
2320
2321!ajb: Not used
2322  SUBROUTINE set_real_array(rscale, value, ims,ime, its,ite)
2323!-----------------------------------------------------------------------
2324  IMPLICIT NONE
2325!-----------------------------------------------------------------------
2326
2327  INTEGER, INTENT(IN)  :: ims,ime           ! Memory dimensions
2328  INTEGER, INTENT(IN)  :: its,ite           ! Tile   dimensions
2329  REAL, INTENT(IN)     :: value             ! Constant array value
2330  REAL, INTENT(OUT)    :: rscale( ims:ime ) ! Output array
2331
2332! Local variables
2333  integer :: i
2334
2335! Set array to constant value
2336  do i = its,ite
2337    rscale(i) = value
2338  enddo
2339
2340  RETURN
2341  END SUBROUTINE set_real_array
2342
2343!ajb: Not used
2344  SUBROUTINE calc_pottemp_scales(ivar, rcp, pb, p, tscale,             &
2345                                       ims,ime, its,ite,               &
2346                                     kms,kme, kts,kte)
2347!-----------------------------------------------------------------------
2348  IMPLICIT NONE
2349!-----------------------------------------------------------------------
2350
2351  INTEGER, INTENT(IN)  :: ims,ime, kms,kme      ! Memory dimensions
2352  INTEGER, INTENT(IN)  :: its,ite, kts,kte      ! Tile   dimensions
2353  INTEGER, INTENT(IN)  :: ivar                  ! Variable identifier
2354  REAL, INTENT(IN)     :: rcp                   ! Constant (2./7.)
2355  REAL, INTENT(IN)     :: pb(ims:ime, kms:kme)  ! Base pressure (Pa) array
2356  REAL, INTENT(IN)     :: p(ims:ime, kms:kme)   ! Pressure pert. (Pa) array
2357  REAL, INTENT(OUT)    :: tscale(ims:ime, kms:kme) ! Scales for pot. temp.
2358! Local variables
2359  integer :: i,k
2360
2361  if(ivar.eq.3) then
2362
2363! Calculate scales to be used for producing potential temperature nudging factors.
2364    do k = kts,kte
2365    do i = its,ite
2366      tscale(i,k) = ( 1000000. / ( pb(i,k)+p(i,k)) )**rcp
2367    enddo
2368    enddo
2369  else
2370! Set to 1. for moisture scaling.
2371    do k = kts,kte
2372      do i = its,ite
2373        tscale(i,k) = 1.0
2374      enddo
2375    enddo
2376  endif
2377     
2378  RETURN
2379  END SUBROUTINE calc_pottemp_scales
2380#endif
2381
2382END MODULE module_fddaobs_rtfdda
2383
Note: See TracBrowser for help on using the repository browser.