2 ! Author(s)/Contact(s):
7 ! Parameters: <Specify typical arguments passed>
9 ! <list file names and briefly describe the data they include>
11 ! <list file names and briefly describe the information they include>
14 ! <list exit condition or error codes returned >
15 ! If appropriate, descriptive troubleshooting instructions or
16 ! likely causes for failures could be mentioned here with the
17 ! appropriate error code
19 ! User controllable options: <if applicable>
21 module module_stream_nudging
23 use config_base, only: nlst
24 use module_nudging_io, only: lastObsStructure, lastObsStructure_SoA
27 use module_mpp_reachls, only: ReachLS_write_io
29 use module_hydro_stop, only:HYDRO_stop
32 !===================================================================================================
35 !========================
36 ! obs and obsTime data structures. Each entry in obsTime holds a timeslice file, with the
37 ! individual obs in the obsStr.
39 character(len=15) :: usgsId ! the 15 char USGS identifier.
40 character(len=19) :: obsTime ! observation at gage dims: nGages
41 real :: obsDischarge ! observation at gage dims: nGages
42 real :: obsQC ! quality control factpr [0,1]
43 integer :: obsStaticInd ! the index to the obsStaticStr where static info is kept
44 real :: innov ! obs-modeled
48 character(len=19) :: time
49 character(len=19) :: updateTime
50 integer, allocatable, dimension(:) :: allCellInds ! cell indices affected at this time
51 integer, allocatable, dimension(:) :: nGageCell ! number of gages for each affected cell ind
52 type(obsStructure), allocatable, dimension(:) :: obsStr ! the obs at this file time / timeslice
53 end type obsTimeStructure
55 ! The top level structure used to solve the nudges
56 type(obsTimeStructure), allocatable, dimension(:) :: obsTimeStr ! size=nObsTimes
58 !========================
59 ! lastObs structure, corresponding to nudgingLastObs.YYYY-mm-dd_HH:MM:ss.nc
60 ! How observations from the past are carried forward.
61 ! Type defined in module_nudging_io.F
62 type(lastObsStructure), allocatable, dimension(:) :: lastObsStr
63 type(lastObsStructure_SoA) :: lastObsStr_SoA
65 !========================
66 ! This holds static information for a given gage for a given cycle (when R, G, and tau) do not
68 ! The "lastObs" variables are not exactly static... they were an afterthought and this was
69 ! by far the best place for them to live.
70 type, extends(lastObsStructure) :: obsStaticStructure
71 !! Inherited components
72 !!character(len=15) :: usgsId ! the 15 char USGS identifier.
73 !!real :: lastObsDischarge(:) ! last observed discharge
74 !!character(len=19) :: lastObsTime(:) ! time of last obs discharge (.le.hydroTime)
75 !!real :: lastObsQuality(:) ! quality of the last obs discharge
76 !!real :: lastObsModelDischarge(:) ! the modeled discharge value at the time of the last obs
78 integer, allocatable, dimension(:) :: cellsAffected ! indices of cells affected
79 real, allocatable, dimension(:) :: dist ! optional: dist to affected cells, optional
80 real, allocatable, dimension(:) :: ws ! spatial cressman weights at affected cells discharge.
81 end type obsStaticStructure
83 type, extends(lastObsStructure_SoA) :: obsStaticStructure_SoA
84 !! Inherited components
85 !!character(len=15) :: usgsId ! the 15 char USGS identifier.
86 !!real :: lastObsDischarge(:) ! last observed discharge
87 !!character(len=19) :: lastObsTime(:) ! time of last obs discharge (.le.hydroTime)
88 !!real :: lastObsQuality(:) ! quality of the last obs discharge
89 !!real :: lastObsModelDischarge(:) ! the modeled discharge value at the time of the last obs
91 integer, allocatable :: obsCellInd(:) ! index of obs on model channel network, for distance calc
92 real,allocatable :: R(:), G(:), tau(:) ! the nudging parameters at this gage.
93 end type obsStaticStructure_SoA
95 ! The static obs/gage information - store here to perform calculations
96 ! only once per cycle.
97 ! Currently the dimensions of this are fixed to 10000 which should
98 ! work for the forseeable future. May want to consider some routine for
99 ! augmenting this size if necessary.
100 type(obsStaticStructure), allocatable, dimension(:) :: obsStaticStr
101 type(obsStaticStructure_SoA) :: obsStaticStr_Soa
103 !! The number of up/down stream links which can be collected
104 !! using R to solve which links are "neighboring".
105 !! This value applies to both directions, it's the number
107 integer, parameter :: maxNeighLinksDim=5000
109 !========================
110 ! Node and gage collocation - For reach based routing, corresponds to the "gage" column
112 type nodeGageStructure
113 integer, allocatable, dimension(:) :: nodeId
114 character(len=15), allocatable, dimension(:) :: usgsId
115 end type nodeGageStructure
116 type(nodeGageStructure) :: nodeGageTmp, nodeGageStr
117 integer :: nGagesDomain ! the number of gages specified
119 !========================
120 ! Nudging parameters structure, corresponding to NudgeParams.nc file.
121 !! for dealloction purposes, might be better to put the dimension onthe derived type.
122 type nudgingParamStructure
123 character(len=15), allocatable, dimension(:) :: usgsId
124 real, allocatable, dimension(:) :: R
125 real, allocatable, dimension(:) :: G
126 real, allocatable, dimension(:) :: tau
127 real, allocatable, dimension(:,:,:) :: qThresh !! gage, month, nThresh
128 real, allocatable, dimension(:,:,:) :: expCoeff !! gage, month, nThresh
129 end type nudgingParamStructure
130 type(nudgingParamStructure) :: nudgingParamsTmp, nudgingParamsStr
132 !========================
133 ! Network reExpression structure, corresponding to netwkReExFile.nc
134 type netwkReExpStructure
135 integer*4, allocatable, dimension(:) :: go
136 integer*4, allocatable, dimension(:) :: start
137 integer*4, allocatable, dimension(:) :: end
138 end type netwkReExpStructure
139 type(netwkReExpStructure) :: downNetwkStr, upNetwkStr
141 !========================
142 ! Track gages from NWIS not in our param file and not in the intersection or
143 ! the Route_Link gages and the gages in the parameter file.
144 integer, parameter :: maxNwisNotRLAndParamsCount=20000
145 character(len=15), dimension(maxNwisNotRLAndParamsCount) :: nwisNotRLAndParams
146 integer :: nwisNotRLAndParamsCount
148 !========================
150 real, allocatable, dimension(:) :: t0Discharge
152 !========================
153 ! Control book keeping
154 logical :: nudgeThisLsmTimeStep
156 !! JLM: these options are hardcoded/hardwired for now, evnt go in namelist
157 integer, parameter :: obsResolutionInt = 15 ! minutes
158 real, parameter :: obsCheckFreq = 90 ! minutes
159 logical, parameter :: filterObsToDom = .TRUE.
160 character(len=15), parameter :: missingGage = ' '
161 logical, parameter :: nudgeWAdvance = .FALSE.
162 character(len=4), parameter :: nudgingClockType = 'wall'
163 logical, parameter :: sanityQcDischarge = .true.
164 logical, parameter :: readTimesliceErrFatal = .false.
165 logical, parameter :: futureLastObsFatal = .true.
166 logical, parameter :: futureLastObsZero = .false.
167 real, parameter :: invDistTimeWeightExp = 5.000
168 real, parameter :: noConstInterfCoeff = 1.0 !0.500
170 ! hydro.namelist: &NUDGING_nlist variables.
171 character(len=256) :: nudgingParamFile
172 character(len=256) :: netwkReExFile
173 character(len=256) :: nudgingLastObsFile !! passed by namelist
174 character(len=256) :: nudgingLastObsFileTry !! either the passed or, if not passed, a default
175 logical :: readTimesliceParallel
176 logical :: temporalPersistence
177 logical :: persistBias
178 logical :: biasWindowBeforeT0
179 integer :: nTimesLastObs !! aka nlst_rt(did)%nLastObs
180 integer :: minNumPairsBiasPersist
181 integer :: maxAgePairsBiasPersist
182 logical :: invDistTimeWeightBias
183 logical :: noConstInterfBias
185 !========================
187 logical :: nudgeSpatial = .true. !! is spatial interpolation of nudging active?
188 integer, parameter :: did=1 !! 1 for WRF-uncoupled runs...
190 !========================
194 character(len=19) :: lsmTime, initTime
195 integer :: lsmDt !1234567890123456789
196 character(len=19), parameter :: missingLastObsTime='9999999999999999999'
197 character(len=2) :: obsResolution
198 logical :: gotT0Discharge
201 integer, parameter :: flushUnit=6
202 logical, parameter :: flushAll=.true.
206 !========================
207 ! Parallel book keeping
208 real, allocatable, dimension(:) :: chanlen_image0 !A global version kept on image 0
214 !===================================================================================================
216 ! init_stream_nudging_clock
217 ! Author(s)/Contact(s):
218 ! James L McCreight <jamesmcc><ucar><edu>
220 ! One-time initialization of diagnostic stream nuding clock.
222 ! 10/08/15 -Created, JLM.
226 ! Output Files: None.
227 ! Condition codes: this only gets called if #ifdef HYDRO_D?
228 ! User controllable options: None.
231 subroutine init_stream_nudging_clock
232 use module_nudging_utils, only: totalNudgeTime, &
238 totalNudgeTime = 0. ! Nudging time accumulation init.
239 call system_clock(count_rate=sysClockCountRate, count_max=sysClockCountMax)
240 clockType = trim(nudgingClockType)
241 !!$#ifdef HYDRO_D /* un-ifdef to get timing results */
242 !!$print*,'Ndg: totalNudgeTime: ', totalNudgeTime
243 !!$print*,'Ndg: sysClockCountRate: ', sysClockCountRate
244 !!$print*,'Ndg: sysClockCountMax: ', sysClockCountMax
245 !!$print*,'Ndg: clockType: ', trim(nudgingClockType)
246 !!$if(flushAll) flush(flushUnit)
247 !!$#endif /* HYDRO_D un-ifdef to get timing results */
248 end subroutine init_stream_nudging_clock
251 !===================================================================================================
253 ! init_stream_nudging
254 ! Author(s)/Contact(s):
255 ! James L McCreight <jamesmcc><ucar><edu>
257 ! One-time initialization of certain stream nuding information. Some of this infomation
258 ! may be updated later in the run, but probably not frequently.
260 ! 7/23/15 -Created, JLM.
263 ! Input Files: currently hardwired module variables
267 ! Output Files: None.
269 ! User controllable options: None.
272 subroutine init_stream_nudging
274 use module_RT_data, only: rt_domain
275 use module_nudging_utils, only: whichInLoop2, &
278 use module_nudging_io, only: get_netcdf_dim, &
279 read_gridded_nudging_frxst_gage_csv, &
280 read_reach_gage_collocation, &
281 read_nudging_param_file, &
282 read_network_reexpression, &
283 find_nudging_last_obs_file, &
284 read_nudging_last_obs, &
285 read_nudging_last_obs_soa
286 use module_mpp_reachls, only: ReachLS_decomp
290 integer :: nLinks, nLinksL
291 !integer, dimension(nlinks) :: strmFrxstPts
293 integer :: ii, kk, ll, tt, count, toSize, fromSize
294 integer :: nParamGages, nParamMonth, nParamThresh, nParamThreshCat, nGgDists, nGgDistsKeep
295 integer :: nWhGageDists1, nWhGageDists2, nGagesWParamsDom
296 integer, allocatable, dimension(:) :: whParamsDom
297 real, allocatable, dimension(:) :: g_nudge
298 integer :: downSize, upSize, baseSize, nStnLastObs
299 character(len=256) :: lastObsFile !! confirms existence of a file
300 logical :: lastObsFileFound
301 !!$#ifdef HYDRO_D /* un-ifdef to get timing results */
302 !!$real :: startCodeTimeAcc, endCodeTimeAcc
305 !!$if(my_id .eq. io_id) &
307 !!$ call nudging_timer(startCodeTimeAcc)
308 !!$#endif /* HYDRO_D */ /* un-ifdef to get timing results */
311 !!$print*, "Ndg: Start init_stream_nudging"
313 !!$print*, 'Ndg: PARALLEL NUDGING!'
315 !!$if(flushAll) flush(flushUnit)
316 !!$#endif /* HYDRO_D */
318 !! this ifdef is bizarre problem with pgf compiler
319 !#ifdef WRF_HYDRO_NUDGING !JLM
320 nudgingParamFile = nlst(did)%nudgingParamFile
321 netwkReExFile = nlst(did)%netwkReExFile
322 readTimesliceParallel = nlst(did)%readTimesliceParallel
323 temporalPersistence = nlst(did)%temporalPersistence
324 persistBias = nlst(did)%persistBias
325 biasWindowBeforeT0 = nlst(did)%biasWindowBeforeT0
326 nudgingLastObsFile = nlst(did)%nudgingLastObsFile
327 nTimesLastObs = nlst(did)%nLastObs
328 minNumPairsBiasPersist = nlst(did)%minNumPairsBiasPersist
329 maxAgePairsBiasPersist = nlst(did)%maxAgePairsBiasPersist
330 invDistTimeWeightBias = nlst(did)%invDistTimeWeightBias
331 noConstInterfBias = nlst(did)%noConstInterfBias
334 nLinks = RT_DOMAIN(did)%NLINKS ! For gridded channel routing
336 nLinksL = RT_DOMAIN(did)%gNLINKSL ! For reach-based routing in parallel, no decomp for nudging
338 nLinksL = RT_DOMAIN(did)%NLINKSL ! For reach-based routing
342 nwisNotRLAndParams = missingGage
343 nwisNotRLAndParamsCount=0
344 gotT0Discharge = .false.
346 !=================================================
347 ! 0. This routine is called with condition that chanrtswcrt.ne.0 in module_HYDRO_drv
349 !=================================================
350 ! 1. Gage link/node collocation.
351 ! which gages are actually in the domain?
352 ! Musk routines: use routelink csv! New column for associated gage Id for each link.
353 ! Grid channel : frxst_pts layer in Fulldom, and a new Nudge_frxst_gage.csv file, which
354 ! simply contains frxst_pts index and the associated gage ID, *** may be blank?***
355 !========================
356 !!$! Gridded channel routing is option 3
357 !!$if (nlst_rt(did)%channel_option .eq. 3) then
358 !!$ strmfrxstpts = RT_DOMAIN(did)%STRMFRXSTPTS
359 !!$ ! For gridded channel routing, setup the relationship between frxst_pts and gage IDs via
360 !!$ ! the Nudging_frxst_gage.csv.
361 !!$ ! For now this is a csv, but it should be netcdf in the long run.
363 !!$ print*, 'Ndg: Start initializing Nudging_frxst_gage.csv'
365 !!$ !! allocate the maximum number of gages, say 8000.
366 !!$ allocate(nodeGageTmp%nodeId(maxGages), nodeGageTmp%usgsId(maxGages))
367 !!$ ! This actually returns frxst point from the file...
368 !!$ call read_gridded_nudging_frxst_gage_csv(nodeGageTmp%nodeId, nodeGageTmp%usgsId, nGagesDomain)
369 !!$ ! ... we'll convert this to index on the stream network.
370 !!$ allocate(nodeGageStr%nodeId(nGagesDomain), nodeGageStr%usgsId(nGagesDomain))
372 !!$ !! JLM: need to handle desired frxst points which are not gages.
373 !!$ !! Need to make sure these are a complete set 1:nGages.
375 !!$ if(strmFrxstPts(ll) .ne. -9999) then
376 !!$ nodeGageStr%nodeId(strmFrxstPts(ll)) = ll
377 !!$ nodeGageStr%usgsId(strmFrxstPts(ll)) = adjustr(nodeGageTmp%usgsId(strmFrxstPts(ll)))
381 !!$ deallocate(nodeGageTmp%nodeId, nodeGageTmp%usgsId)
384 !!$ print*,nGagesDomain
385 !!$ print*,nodeGageStr%nodeId
386 !!$ print*,nodeGageStr%usgsId
387 !!$ print*, 'Ndg: Finish initializing Nudging_frxst_gage.csv'
389 !!$end if ! gridded channel models
391 !========================
392 ! Muskingum routines are channel_options 1 and 2
393 if (nlst(did)%channel_option .eq. 1 .or. &
394 nlst(did)%channel_option .eq. 2) then
396 ! For reach-based/muskingum routing methods, we are currently requiring
397 ! the netcdf file for input of gages.
400 if(my_id .eq. io_id) then
404 print*, 'Ndg: Start initializing reach gages (netcdf)'
405 if(flushAll) flush(flushUnit)
408 allocate(nodeGageTmp%usgsId(nLinksL))
409 call read_reach_gage_collocation(nodeGageTmp%usgsId)
412 !check: nLinksL .eq. size(nodeGageTmp%usgsId)
414 do ll=1,size(nodeGageTmp%usgsId)
415 if(nodeGageTmp%usgsId(ll) .ne. missingGage) nGagesDomain=nGagesDomain+1
418 if(nGagesDomain .gt. 0) then
419 allocate(nodeGageStr%nodeId(nGagesDomain), nodeGageStr%usgsId(nGagesDomain))
420 nodeGageStr%usgsId = pack(nodeGageTmp%usgsId, mask=nodeGageTmp%usgsId .ne. missingGage)
421 ! This just index, we are NOT using comIds in nudging.
422 ! nodeGageStr%nodeId = pack(rt_domain(did)%linkId, mask=nodeGageTmp%usgsId .ne. '')
423 nodeGageStr%nodeId = pack((/(ii, ii=1,nLinksL)/), mask=nodeGageTmp%usgsId .ne. missingGage)
425 deallocate(nodeGageTmp%usgsId)
428 print*,'Ndg: nGagesDomain:',nGagesDomain
429 print*,'Ndg: nLinksL', nLinksL
430 print*,"Ndg: size(nodeGageStr%nodeId):", size(nodeGageStr%nodeId)
432 'Ndg: nodeGageStr%usgsId((size(nodeGageStr%nodeId)-nGagesDomain+1):(size(nodeGageStr%nodeId))):',&
433 nodeGageStr%usgsId((size(nodeGageStr%nodeId)-nGagesDomain+1):(size(nodeGageStr%nodeId)))
434 print*,'Ndg: Finish initializing reach gages (netcdf)'
435 if(flushAll) flush(flushUnit)
439 end if ! my_id .eq. io_id
441 call mpp_land_bcast_int1(nGagesDomain)
442 if(my_id .ne. io_id) then
443 allocate(nodeGageStr%nodeId(nGagesDomain))
444 allocate(nodeGageStr%usgsId(nGagesDomain))
446 call mpp_land_bcast_char1d(nodeGageStr%usgsId)
447 call mpp_land_bcast_int1d(nodeGageStr%nodeId)
450 end if ! muskingum channel models
452 !=================================================
453 ! 3. Read nudging parameter files and reduce to the gages in the domain (nGagesDomain, etc above).
455 if(my_id .eq. IO_id) then
457 nParamGages = get_netcdf_dim(nudgingParamFile, 'stationIdInd', 'init_stream_nudging')
462 if(temporalPersistence) then
463 nParamMonth = get_netcdf_dim(nudgingParamFile, 'monthInd', 'init_stream_nudging')
464 nParamThresh = get_netcdf_dim(nudgingParamFile, 'threshInd', 'init_stream_nudging')
465 nParamThreshCat = get_netcdf_dim(nudgingParamFile, 'threshCatInd', 'init_stream_nudging')
468 print*,'Ndg: nParamGages: ', nParamGages
469 print*,'Ndg: nParamGages', nParamGages
470 print*,'Ndg: nParamMonth', nParamMonth
471 print*,'Ndg: nParamThresh', nParamThresh
472 print*,'Ndg: nParamThreshCat', nParamThreshCat
473 if(flushAll) flush(flushUnit)
476 if(nParamMonth.eq.0 .or. nParamThresh.eq.0 .or. nParamThreshCat.eq.0) then
477 temporalPersistence = .false.
480 else if((nParamThresh+1) .ne. nParamThreshCat) then
481 temporalPersistence = .false.
485 endif !temporal persistence
488 print*,'Ndg: nParamGages: ', nParamGages
489 print*,'Ndg: nParamMonth', nParamMonth
490 print*,'Ndg: nParamThresh', nParamThresh
491 print*,'Ndg: nParamThreshCat', nParamThreshCat
492 print*,'Ndg: temporalPersistence: ', temporalPersistence
493 if(flushAll) flush(flushUnit)
496 allocate(nudgingParamsTmp%usgsId( nParamGages))
497 allocate(nudgingParamsTmp%R( nParamGages))
498 allocate(nudgingParamsTmp%G( nParamGages))
499 allocate(nudgingParamsTmp%tau( nParamGages))
500 allocate(nudgingParamsTmp%qThresh( nParamThresh, nParamMonth, nParamGages))
501 allocate(nudgingParamsTmp%expCoeff(nParamThresh+1, nParamMonth, nParamGages))
503 call read_nudging_param_file(nudgingParamFile, &
504 nudgingParamsTmp%usgsId, &
505 nudgingParamsTmp%R, &
506 nudgingParamsTmp%G, &
507 nudgingParamsTmp%tau, &
508 nudgingParamsTmp%qThresh, &
509 nudgingParamsTmp%expCoeff )
513 print*,'Ndg: minval( nudgingParamsTmp%qThresh(ii,:,:)), ii=', ii,': ', &
514 minval( nudgingParamsTmp%qThresh(ii,:,:))
516 do ii=1,nParamThreshCat
517 print*,'Ndg: minval( nudgingParamsTmp%expCoeff(ii,:,:)), ii=', ii,': ', &
518 minval( nudgingParamsTmp%expCoeff(ii,:,:))
520 if(flushAll) flush(flushUnit)
523 ! Reduce the parameters to just the gages in the domain
524 allocate(whParamsDom(nParamGages))
526 call whichInLoop2(nudgingParamsTmp%usgsId, nodeGageStr%usgsId, whParamsDom, nGagesWParamsDom)
529 if(nGagesWParamsDom .ne. nGagesDomain) then
530 print*,'Ndg: WARNING Gages are apparently missing from the nudgingParams.nc file'
531 print*,'Ndg: WARNING nGagesWParamsDom: ', nGagesWParamsDom
532 print*,'Ndg: WARNING nGagesDomain: ', nGagesDomain
533 if(flushAll) flush(flushUnit)
537 allocate(nudgingParamsStr%usgsId(nGagesWParamsDom))
538 allocate(nudgingParamsStr%R( nGagesWParamsDom))
539 allocate(nudgingParamsStr%G( nGagesWParamsDom))
540 allocate(nudgingParamsStr%tau( nGagesWParamsDom))
541 if(temporalPersistence) then
542 allocate(nudgingParamsStr%qThresh( nParamThresh, nParamMonth, nGagesWParamsDom))
543 allocate(nudgingParamsStr%expCoeff(nParamThresh+1, nParamMonth, nGagesWParamsDom))
548 if(whParamsDom(kk) .gt. 0) then
549 nudgingParamsStr%usgsId(count) = nudgingParamsTmp%usgsId(kk)
550 nudgingParamsStr%R(count) = nudgingParamsTmp%R(kk)
551 nudgingParamsStr%G(count) = nudgingParamsTmp%G(kk)
552 nudgingParamsStr%tau(count) = nudgingParamsTmp%tau(kk)
553 if(temporalPersistence) then
554 nudgingParamsStr%qThresh( :,:,count) = nudgingParamsTmp%qThresh( :,:,kk)
555 nudgingParamsStr%expCoeff(:,:,count) = nudgingParamsTmp%expCoeff(:,:,kk)
561 deallocate(whParamsDom)
562 deallocate(nudgingParamsTmp%usgsId, nudgingParamsTmp%R )
563 deallocate(nudgingParamsTmp%G, nudgingParamsTmp%tau)
564 if(temporalPersistence) then
565 deallocate(nudgingParamsTmp%qThresh)
566 deallocate(nudgingParamsTmp%expCoeff)
570 print*,'Ndg: nudgingParamsStr%usgsId', nudgingParamsStr%usgsId(size(nudgingParamsStr%usgsId))
571 print*,'Ndg: nudgingParamsStr%R', nudgingParamsStr%R(size(nudgingParamsStr%R))
572 print*,'Ndg: nudgingParamsStr%G', nudgingParamsStr%G(size(nudgingParamsStr%G))
573 print*,'Ndg: nudgingParamsStr%tau', nudgingParamsStr%tau(size(nudgingParamsStr%tau))
574 if(temporalPersistence) then
575 print*,'Ndg: nudgingParamsStr%qThresh', nudgingParamsStr%qThresh(1,1,size(nudgingParamsStr%tau))
576 print*,'Ndg: nudgingParamsStr%expCoeff',nudgingParamsStr%expCoeff(1,1,size(nudgingParamsStr%tau))
578 if(flushAll) flush(flushUnit)
581 endif ! my_id .eq. io_id
584 call mpp_land_bcast_int1(nGagesWParamsDom)
585 if(my_id .ne. io_id) then
586 allocate(nudgingParamsStr%usgsId(nGagesWParamsDom))
587 allocate(nudgingParamsStr%R(nGagesWParamsDom))
588 allocate(nudgingParamsStr%G(nGagesWParamsDom))
589 allocate(nudgingParamsStr%tau(nGagesWParamsDom))
591 call mpp_land_bcast_char1d(nudgingParamsStr%usgsId)
592 call mpp_land_bcast_real_1d(nudgingParamsStr%R)
593 call mpp_land_bcast_real_1d(nudgingParamsStr%G)
594 call mpp_land_bcast_real_1d(nudgingParamsStr%tau)
595 call mpp_land_bcast_logical(temporalPersistence)
596 if(temporalPersistence) then
597 call mpp_land_bcast_int1(nParamThresh)
598 call mpp_land_bcast_int1(nParamMonth)
599 if(my_id .ne. io_id) then
600 allocate(nudgingParamsStr%qThresh( nParamThresh, nParamMonth, nGagesWParamsDom))
601 allocate(nudgingParamsStr%expCoeff(nParamThresh+1, nParamMonth, nGagesWParamsDom))
604 call mpp_land_bcast_real3d(nudgingParamsStr%qThresh)
605 call mpp_land_bcast_real3d(nudgingParamsStr%expCoeff)
606 end if ! temporalPersistence
607 #endif /* MPP_LAND */
609 allocate(obsStaticStr(size(nudgingParamsStr%usgsId)))
611 allocate(obsStaticStr_SoA%usgsId(size(nudgingParamsStr%usgsId)))
612 allocate(obsStaticStr_SoA%R(size(nudgingParamsStr%usgsId)))
613 allocate(obsStaticStr_SoA%tau(size(nudgingParamsStr%usgsId)))
614 allocate(obsStaticStr_SoA%G(size(nudgingParamsStr%usgsId)))
615 allocate(obsStaticStr_SoA%obsCellInd(size(nudgingParamsStr%usgsId)))
616 ! This seems silly now that I'm solving the whole thing at init.
617 obsStaticStr_SoA%R(:) = nudgingParamsStr%R(:)
618 obsStaticStr_SoA%G(:) = nudgingParamsStr%G(:)
619 obsStaticStr_SoA%tau(:) = nudgingParamsStr%tau(:)
620 obsStaticStr_SoA%usgsId(:) = nudgingParamsStr%usgsId(:)
621 obsStaticStr(:)%usgsId = nudgingParamsStr%usgsId
623 allocate(obsStaticStr_SoA%lastObsDischarge(nlst(did)%nLastObs, size(nudgingParamsStr%usgsId)))
624 allocate(obsStaticStr_SoA%lastObsModelDischarge(nlst(did)%nLastObs, size(nudgingParamsStr%usgsId)))
625 allocate(obsStaticStr_SoA%lastObsTime(nlst(did)%nLastObs, size(nudgingParamsStr%usgsId)))
626 allocate(obsStaticStr_SoA%lastObsQuality(nlst(did)%nLastObs, size(nudgingParamsStr%usgsId)))
628 !=================================================
629 ! 4. Read in 'nudgingLastObs.nc' file (initialization and broadcasting come later)
631 if(my_id .eq. io_id) then
632 if(temporalPersistence) then
634 !! Initalizing the structure is not contingent upon there
635 !! being a file on disk
636 obsStaticStr_SoA%lastObsDischarge = real(-9999)
637 obsStaticStr_SoA%lastObsModelDischarge = real(-9999)
638 obsStaticStr_SoA%lastObsTime = missingLastObsTime
639 obsStaticStr_SoA%lastObsQuality = real(0) !! keep this zero
641 !! if blank, look for file at the current/init time
642 if(trim(nudgingLastObsFile) .eq. '') then
643 nudgingLastObsFileTry = 'nudgingLastObs.' // nlst(did)%olddate // '.nc'
645 nudgingLastObsFileTry = nudgingLastObsFile
647 lastObsFile = find_nudging_last_obs_file(nudgingLastObsFileTry)
648 if(trim(lastObsFile) .ne. '') then
649 nStnLastObs = get_netcdf_dim(nudgingLastObsFileTry, 'stationIdInd', 'init_stream_nudging')
650 if(nStnLastObs .gt. 0) then
651 print*,'Reading in nudgingLastObsFileTry: ', trim(nudgingLastObsFileTry)
652 allocate(lastObsStr_SoA%usgsId(nStnLastObs))
653 allocate(lastObsStr_SoA%lastObsDischarge(nlst(did)%nLastObs,nStnLastObs))
654 allocate(lastObsStr_SoA%lastObsModelDischarge(nlst(did)%nLastObs,nStnLastObs))
655 allocate(lastObsStr_SoA%lastObsTime(nlst(did)%nLastObs,nStnLastObs))
656 allocate(lastObsStr_SoA%lastObsQuality(nlst(did)%nLastObs,nStnLastObs))
658 allocate(lastObsStr(nStnLastObs))
660 allocate(g_nudge(rt_domain(1)%gnlinksl))
661 call read_nudging_last_obs_soa(nudgingLastObsFileTry, lastObsStr_SoA, g_nudge)
662 end if ! nStnLastObs .gt. 0 -> read the file
663 endif! trim(lastObsFile).ne.''
664 end if ! temporalPersistence
669 if(my_id .eq. io_id) lastObsFileFound=allocated(g_nudge)
670 call mpp_land_bcast_logical(lastObsFileFound)
671 if(lastObsFileFound) then
672 call ReachLS_decomp(g_nudge, RT_DOMAIN(1)%nudge)
673 if(my_id .eq. io_id) deallocate(g_nudge)
675 if(my_id .NE. io_id) deallocate(g_nudge)
678 !=================================================
679 ! 5. Sort out which gages are actually in the domain.
680 ! JLM: there can be an inconsistency between the gages with parameters
681 ! JLM: and the gages with distances.
682 ! JLM: How to handle locations without parameters?
683 ! JLM: How to determine the functional list of gages in the domain?
686 !=================================================
687 ! 6. Set up the global time parameters
689 ! MPP need to broadcast the initial time and setup the dt
690 if(my_id .eq. io_id) then
693 call mpp_land_bcast_int1(lsmDt)
700 ! |- - - -L* * * *|- - - -|- - - -|
702 ! - time chunks of obsResolution
703 ! | separators denoting lsmDt chunks
704 ! * obsRresolution points in the current lsmDt/hydro time advance
705 ! + is the center of the assim window size = tau*2, at that the hydro time
706 ! ! are the bounds of all assim windows
708 ! S-E The start and end times for hydro advance
709 ! t denotes times needed by size of tau
710 ! w denotes times needed by size of lsmDt
711 ! Regardless of tau, need window of size (2*tau+lsmDt)
712 ! which will have (2*tau+lsmDt)/obsResolution+1 observation times in it
713 ! the +1 is for the zeroth time.
715 maxTau = maxval(nudgingParamsStr%tau) ! This is fixed as tau does not change for a cycle.
716 write(obsResolution, '(i0.2)') obsResolutionInt
717 nObsTimes = 2*ceiling(maxTau/obsResolutionInt) + ceiling(real(lsmDt)/(60.*obsResolutionInt)) + 1
721 if(my_id .eq. io_id) then
723 print*,'Ndg: obsResolution:',obsResolution
724 print*,'Ndg: maxTau: ', maxTau
725 print*,'Ndg: nObsTimes: ', nObsTimes
726 if(flushAll) flush(flushUnit)
732 allocate(obsTimeStr(nObsTimes))
733 !! initialize these as blanks and 'none'
734 obsTimeStr(:)%time = ''
735 obsTimeStr(:)%updateTime = 'none'
738 !=================================================
739 ! 8. MPP: Keep a copy of the full chanlen on image 0
740 !! only necessary if doing spatial nudging interpolation
741 if(my_id .eq. io_id) allocate(chanlen_image0(nLinksL))
742 if(my_id .ne. io_id) allocate(chanlen_image0(1)) !! memory fix, the next call modifies it's second arg
743 call ReachLS_write_io(rt_domain(did)%chanlen, chanlen_image0)
747 !=================================================
748 ! 9. Solve obsStaticStr once and for all on image 0 (could parallelize)
749 ! This also solves nudgeSpatial: is spatial nudging active? Needed in 10.
750 ! Remove lastObsStr (only needed for ingest of nudingLastObs/restart file).
751 call obs_static_to_struct()
753 if(my_id .eq. io_id) then
755 if(allocated(lastObsStr)) deallocate(lastObsStr)
760 !=================================================
761 !10. Solve the bias terms for when biasWindowBeforeT0 = .TRUE. (in the forecast)
763 !if(persistBias .and. biasWindowBeforeT0) then
764 ! do gg=1,nGages.........
766 ! end do ! gg=1,nGages
767 !end if ! if(persistBias) then
769 !=================================================
772 if(my_id .eq. io_id) &
774 print*, "Ndg: Finish init_stream_nudging"
775 if(flushAll) flush(flushUnit)
778 !!$#ifdef HYDRO_D /* un-ifdef to get timing results */
780 !!$if(my_id .eq. io_id) then
782 !!$ call nudging_timer(endCodeTimeAcc)
783 !!$ call accum_nudging_time(startCodeTimeAcc, endCodeTimeAcc, 'init_stream_nudging', .true.)
787 !!$if(flushAll) flush(flushUnit)
788 !!$#endif /* HYDRO_D */ /* un-ifdef to get timing results */
790 end subroutine init_stream_nudging
792 !===================================================================================================
794 ! subroutine setup_stream_nudging
795 ! Author(s)/Contact(s):
796 ! James L McCreight <jamesmcc><ucar><edu>
798 ! Setup the nudging for the current hydroTime, only establishes the
799 ! shared obsTimeStr above.
801 ! 6/04/15 -Created, JLM.
807 ! User controllable options:
810 subroutine setup_stream_nudging(hydroDT)
812 use module_RT_data, only: rt_domain
813 use module_nudging_utils, only: whichLoop, &
815 accum_nudging_time, &
818 use module_date_utils_nudging, only: geth_newdate, &
819 round_resolution_minute, &
823 integer, intent(in) :: hydroDT ! the number of seconds of hydro advance from lsmTime
825 integer :: ii, tt, oo
826 character(len=19) :: hydroTime, obsHydroTime ! hydro model time and corresponding observation
827 character(len=19), dimension(nObsTimes) :: obsTimes ! obs times in the current window
828 integer :: oldDiff, nShiftLeft
830 logical, allocatable, dimension(:) :: theMask
831 integer, allocatable, dimension(:) :: whObsMiss
832 logical, allocatable, dimension(:) :: obsTimeStrAllocated
835 integer :: did=1 !! jlm: assuming did=1
836 integer :: nWhObsMiss
839 integer :: nGages, nCellsInR, cc, nLinkAff, nStatic, iiImage
842 !!$#ifdef HYDRO_D /* un-ifdef to get timing results */
843 !!$real :: startCodeTime, endCodeTime
844 !!$real :: startCodeTimeOuter
847 !!$if(my_id .eq. io_id) &
849 !!$ call nudging_timer(startCodeTimeOuter)
850 !!$if(flushAll) flush(flushUnit)
851 !!$#endif /* HYDRO_D :: un-ifdef to get timing results */
855 if(my_id .eq. io_id) &
857 print*,'Ndg: start setup_stream_nudging'
858 if(flushAll) flush(flushUnit)
863 !!$if(my_id .eq. io_id) &
865 !!$ call nudging_timer(startCodeTime)
866 !!$if(flushAll) flush(flushUnit)
867 !!$#endif /* HYDRO_D */
869 !#ifdef MPP_LAND - just do this section on all images. There is no IO.
870 ! The hydro model time as a string.
872 !update and broadcast the lsm time
873 if(my_id .eq. io_id) lsmTime = nlst(did)%olddate
874 if(my_id .eq. io_id) initTime = nlst(did)%startdate
875 call mpp_land_bcast_char(19, lsmTime )
876 call mpp_land_bcast_char(19, initTime)
878 lsmTime = nlst(did)%olddate
879 initTime = nlst(did)%startdate
882 ! This is apparently fixed so that olddate is lsmTime and not
883 ! behind by 1 lsm timestep when the hydro model is run.
884 !call geth_newdate(hydroTime, nlst(1)%olddate, hydroDT+nint(nlst(1)%dt))
885 !call geth_newdate(hydroTime, lsmTimeMinusDt, hydroDT+lsmDt)
886 call geth_newdate(hydroTime, lsmTime, hydroDT)
888 ! Calculate the closest multiple of obsResolution to the hydroTime
889 obsHydroTime = round_resolution_minute(hydroTime, obsResolutionInt)
892 if(my_id .eq. io_id) &
894 print*,'Ndg: obsHydroTime: ', obsHydroTime
895 if(flushAll) flush(flushUnit)
898 ! Now solve all of the observation times in the current nudging window.
899 ! nObsTimes is set at init from maxTau and obsResolution.
900 ! These times correspond to the timestamps on the observation files, which
901 ! mark the center of the time period they represent with width obsResolution.
903 call geth_newdate(obsTimes(tt), obsHydroTime, &
904 !obsResolutionInt*(tt - (nObsTimes+1)/2 )*60)
905 (tt-1-ceiling(maxTau/obsResolutionInt))*60*obsResolutionInt )
908 ! If this is the first setup, these are all blank. This is their init value.
909 if(all(obsTimeStr(:)%time .eq. '')) obsTimeStr(:)%time = obsTimes
911 !print*,'Ndg: hydroTime: ', hydroTime
912 !print*,'Ndg: obsHydroTime: ', obsHydroTime
913 !print*,'Ndg: obsTimes: ', obsTimes
914 !print*,'Ndg: obsTimeStr: before obsTimeStr(:)%time: ', obsTimeStr(:)%time
916 ! If there are existing observations older than the first obsTime for this
917 ! nudging window, shift them left. This should just shift one position left
918 ! with each advance in time resolution.
919 call geth_idts(obsTimeStr(1)%time, obsTimes(1), oldDiff)
920 !print*,"Ndg: olddiff:", oldDiff
921 if(oldDiff .eq. 0) then
924 ! nShiftLeft should not exceed nObsTimes
925 nShiftLeft = min( abs(oldDiff/obsResolutionInt/60), nObsTimes )
927 !print*,"Ndg: nShiftLeft:", nShiftLeft
929 if(nShiftLeft .gt. 0 .and. nShiftLeft .lt. nObsTimes) then
930 do tt=1,nObsTimes-nShiftLeft
932 obsTimeStr(tt)%time = obsTimeStr(tt+nShiftLeft)%time
933 obsTimeStr(tt)%updateTime = obsTimeStr(tt+nShiftLeft)%updateTime
935 if(allocated(obsTimeStr(tt)%allCellInds)) deallocate(obsTimeStr(tt)%allCellInds)
936 if(allocated(obsTimeStr(tt)%nGageCell)) deallocate(obsTimeStr(tt)%nGageCell)
937 if(allocated(obsTimeStr(tt)%obsStr)) deallocate(obsTimeStr(tt)%obsStr)
939 if(allocated(obsTimeStr(tt+nShiftLeft)%allCellInds)) then
940 allocate(obsTimeStr(tt)%allCellInds(size(obsTimeStr(tt+nShiftLeft)%allCellInds)))
941 obsTimeStr(tt)%allCellInds = obsTimeStr(tt+nShiftLeft)%allCellInds
944 if(allocated(obsTimeStr(tt+nShiftLeft)%nGageCell)) then
945 allocate(obsTimeStr(tt)%nGageCell(size(obsTimeStr(tt+nShiftLeft)%nGageCell)))
946 obsTimeStr(tt)%nGageCell = obsTimeStr(tt+nShiftLeft)%nGageCell
949 if(allocated(obsTimeStr(tt+nShiftLeft)%obsStr)) then
950 allocate(obsTimeStr(tt)%obsStr(size(obsTimeStr(tt+nShiftLeft)%obsStr)))
951 obsTimeStr(tt)%obsStr = obsTimeStr(tt+nShiftLeft)%obsStr
956 if(nShiftLeft .gt. 0) then
958 do tt=nObsTimes-nShiftLeft+1,nObsTimes
959 obsTimeStr(tt)%time = obsTimes(tt) !'' !! JLM is this a fix? why?
960 obsTimeStr(tt)%updateTime = 'none'
961 if(allocated(obsTimeStr(tt)%allCellInds)) deallocate(obsTimeStr(tt)%allCellInds)
962 if(allocated(obsTimeStr(tt)%nGageCell)) deallocate(obsTimeStr(tt)%nGageCell)
963 if(allocated(obsTimeStr(tt)%obsStr)) deallocate(obsTimeStr(tt)%obsStr)
967 !if(.NOT. all(obsTimeStr(:)%time .EQ. obsTimes)) &
968 ! call hydro_stop("obsTimeStr(:)%times not what they should be. Please investigate.")
970 ! Updates obs already in memory if flag is set.
971 ! Not going to be used for IOC. This will happen later.
972 ! Should the frequency be in model time or in real time? Probably real time
973 ! and will require a clock time of 'obsLast' checked in obsTimeStr?
974 ! call check_for_new_obs()
976 ! Read in obs at times not already checked, eg. new obs this window
977 ! Obs not already checked have updateTime='none'
978 ! Obs already checked for with:
979 ! : a missing file have updateTime='no file'
980 ! : no observations in the domain have updateTime='no obs'.
982 if(my_id .eq. io_id) then
984 nWhObsMiss = size(obsTimeStr(:)%updateTime)
985 allocate(theMask(nWhObsMiss), whObsMiss(nWhObsMiss) )
986 do ii=1,size(obsTimeStr(:)%updateTime)
987 theMask(ii) = trim(obsTimeStr(ii)%updateTime) .eq. 'none'
989 call whichLoop(theMask, whObsMiss, nObsMiss)
994 ! Broadcast the basic info above.
995 call mpp_land_bcast_int1(nWhObsMiss)
996 if(my_id .ne. io_id) then
997 if(allocated(whObsMiss)) deallocate(whObsMiss)
998 allocate(whObsMiss(nWhObsMiss))
1000 call mpp_land_bcast_int1d(whObsMiss)
1001 call mpp_land_bcast_int1(nObsMiss)
1005 !!$if(my_id .eq. io_id) then
1006 !!$ call nudging_timer(endCodeTime)
1007 !!$ call accum_nudging_time(startCodeTime, endCodeTime, &
1008 !!$ 'setup1: prelim', .false.)
1009 !!$ call nudging_timer(startCodeTime)
1010 !!$if(flushAll) flush(flushUnit)
1014 !bring in timeslice files
1015 allocate(obsTimeStrAllocated(nObsMiss))
1017 do ii=1,nObsMiss ! if nObsMiss is zero, this loop is skipped?
1019 if(readTimesliceParallel) then
1020 iiImage = mod(ii-1,numprocs)
1024 if(my_id .eq. iiImage) then !! this would give parallel IO
1027 ! set/reset this obsTime
1028 obsTimeStr(tt)%time = obsTimes(tt)
1029 obsTimeStr(tt)%updateTime = 'none'
1030 !! This might be paranoid/overkill...
1031 if(allocated(obsTimeStr(tt)%allCellInds)) deallocate(obsTimeStr(tt)%allCellInds)
1032 if(allocated(obsTimeStr(tt)%nGageCell)) deallocate(obsTimeStr(tt)%nGageCell)
1033 if(allocated(obsTimeStr(tt)%obsStr)) deallocate(obsTimeStr(tt)%obsStr)
1034 call timeslice_file_to_struct(tt) ! uses obsTimeStr%time to get file
1035 obsTimeStrAllocated(ii) = allocated(obsTimeStr(tt)%obsStr)
1036 !obsTimeStrAllocated = allocated(obsTimeStr(tt)%obsStr)
1038 end if ! my_id .eq. iiImage
1043 !!$if(my_id .eq. io_id) then
1044 !!$ !print*,'Ndg: obsTimeStr(tt)%time: ',obsTimeStr(tt)%time
1045 !!$ !print*,'Ndg: obsTimeStrAllocated(ii), ii: ', obsTimeStrAllocated(ii), ii
1046 !!$ call nudging_timer(endCodeTime)
1047 !!$ call accum_nudging_time(startCodeTime, endCodeTime, &
1048 !!$ 'setup2.0: timeslice_file_to_struct before bcast', .false.)
1049 !!$ !call nudging_timer(startCodeTime) ! skip this b/c there's no mpi sync till after next section
1050 !!$ if(flushAll) flush(flushUnit)
1055 ! broadcast the IO from above
1056 do ii=1,nObsMiss ! if nObsMiss is zero, this loop is skipped?
1057 if(readTimesliceParallel) then
1058 iiImage = mod(ii-1,numprocs)
1064 ! Here have to expose some of the guts of timeslice_file_to_struct
1065 ! Note nGages depends on ii/tt
1066 call mpp_land_bcast_int1_root(tt, iiImage)
1067 call mpp_land_bcast_logical_root(obsTimeStrAllocated(ii), iiImage)
1068 if(obsTimeStrAllocated(ii)) then
1069 if(my_id .eq. iiImage) nGages=size(obsTimeStr(tt)%obsStr)
1070 call mpp_land_bcast_int1_root(nGages, iiImage)
1071 if(my_id .ne. iiImage) then
1072 if(allocated(obsTimeStr(tt)%obsStr)) deallocate(obsTimeStr(tt)%obsStr)
1073 allocate(obsTimeStr(tt)%obsStr(nGages))
1075 ! Variables in order assigned in the call in timeslice_file_to_struct
1076 call mpp_land_bcast_char_root(19,obsTimeStr(tt)%time, iiImage)
1077 call mpp_land_bcast_char_root(19,obsTimeStr(tt)%updateTime, iiImage)
1078 call mpp_land_bcast_char1d_root(obsTimeStr(tt)%obsStr(:)%usgsId, iiImage)
1079 call mpp_land_bcast_char1d_root(obsTimeStr(tt)%obsStr(:)%obsTime, iiImage)
1080 call mpp_land_bcast_real_1d_root(obsTimeStr(tt)%obsStr(:)%obsQC, iiImage)
1081 call mpp_land_bcast_real_1d_root(obsTimeStr(tt)%obsStr(:)%obsDischarge, iiImage)
1087 !!$if(my_id .eq. io_id) then
1088 !!$ call nudging_timer(endCodeTime)
1089 !!$ call accum_nudging_time(startCodeTime, endCodeTime, &
1090 !!$ 'setup2.1: timeslice_file_to_struct after bcast', .false.)
1091 !!$ call nudging_timer(startCodeTime) ! images are synched so reset timer
1092 !!$ if(flushAll) flush(flushUnit)
1096 !! get index of static info in obsStaticStr
1097 do ii=1,nObsMiss ! if nObsMiss is zero, this loop is skipped?
1099 if(readTimesliceParallel) then
1100 iiImage = mod(ii-1,numprocs)
1104 if(my_id .eq. iiImage) then
1107 if(obsTimeStrAllocated(ii)) then
1108 allocate(theMask(size(nudgingParamsStr%usgsId)))
1109 do oo=1,size(obsTimeStr(tt)%obsStr(:)%obsStaticInd)
1110 ! If the gage is not in the parameter file, skip it
1111 if(.not. any(nudgingParamsStr%usgsId .eq. obsTimeStr(tt)%obsStr(oo)%usgsId)) then
1112 !! If you ended up here, then filterObsToDom should not be on...
1113 if(filterObsToDom) call hydro_stop('obs_static_to_struct: logical clash with filterObsToDom')
1114 call accumulate_nwis_not_in_RLAndParams(nwisNotRLAndParams, &
1115 nwisNotRLAndParamsCount, &
1116 obsTimeStr(tt)%obsStr(oo)%usgsId)
1117 cycle !! skip this observation.
1119 theMask = obsStaticStr_SoA%usgsId .eq. obsTimeStr(tt)%obsStr(oo)%usgsId
1120 !! This is a double (tripple?!) for loop... thanks to whUniLoop
1121 obsTimeStr(tt)%obsStr(oo)%obsStaticInd = whUniLoop(theMask)
1131 !!$if(my_id .eq. io_id) then
1132 !!$ call nudging_timer(endCodeTime)
1133 !!$ call accum_nudging_time(startCodeTime, endCodeTime, &
1134 !!$ 'setup3: obs_static_to_struct', .false.)
1135 !!$ call nudging_timer(startCodeTime)
1136 !!$ if(flushAll) flush(flushUnit)
1141 do ii=1,nObsMiss ! broadcast IO from above. (if nObsMiss is zero, this loop is skipped)
1142 if(readTimesliceParallel) then
1143 iiImage = mod(ii-1,numprocs)
1148 if(obsTimeStrAllocated(ii)) then
1150 ! Treat obs_static_to_strutct
1151 call mpp_land_bcast_int1d_root(obsTimeStr(tt)%obsStr(:)%obsStaticInd, iiImage)
1152 call mpp_land_bcast_char1d_root(obsStaticStr_SoA%usgsId(:), iiImage)
1153 call mpp_land_bcast_int1d_root(obsStaticStr_SoA%obsCellInd(:), iiImage)
1154 call mpp_land_bcast_real_1d_root(obsStaticStr_SoA%R(:), iiImage)
1155 call mpp_land_bcast_real_1d_root(obsStaticStr_SoA%G(:), iiImage)
1156 call mpp_land_bcast_real_1d_root(obsStaticStr_SoA%tau(:), iiImage)
1158 nStatic = sum( (/ (1, cc=1,size(obsStaticStr_SoA%obsCellInd(:))) /), &
1159 mask=obsStaticStr_SoA%obsCellInd(:) .ne. 0 )
1161 if(my_id .eq. iiImage) nCellsInR = size(obsStaticStr(cc)%cellsAffected)
1162 call mpp_land_bcast_int1_root(nCellsInR, iiImage)
1163 if(my_id .ne. iiImage) then
1164 if(allocated(obsStaticStr(cc)%cellsAffected)) deallocate(obsStaticStr(cc)%cellsAffected)
1165 if(allocated(obsStaticStr(cc)%dist)) deallocate(obsStaticStr(cc)%dist)
1166 if(allocated(obsStaticStr(cc)%ws)) deallocate(obsStaticStr(cc)%ws)
1167 allocate(obsStaticStr(cc)%cellsAffected(nCellsInR))
1168 allocate(obsStaticStr(cc)%dist(nCellsInR))
1169 allocate(obsStaticStr(cc)%ws(nCellsInR))
1171 call mpp_land_bcast_int1d_root(obsStaticStr(cc)%cellsAffected, iiImage)
1172 call mpp_land_bcast_real_1d_root(obsStaticStr(cc)%dist, iiImage)
1173 call mpp_land_bcast_real_1d_root(obsStaticStr(cc)%ws, iiImage)
1180 !!$if(my_id .eq. io_id) then
1181 !!$ call nudging_timer(endCodeTime)
1182 !!$ call accum_nudging_time(startCodeTime, endCodeTime, &
1183 !!$ 'setup4: bcast obs_static_struct', .false.)
1184 !!$ call nudging_timer(startCodeTime)
1185 !!$ if(flushAll) flush(flushUnit)
1189 do ii=1,nObsMiss ! if nObsMiss is zero, this loop is skipped?
1191 iiImage = 0! causes issues also refactor tally_affected_links? mod(ii-1,numprocs)
1192 if(my_id .eq. iiImage) then
1195 if(obsTimeStrAllocated(ii)) call tally_affected_links(tt)
1202 !!$if(my_id .eq. io_id) then
1203 !!$ call nudging_timer(endCodeTime)
1204 !!$ call accum_nudging_time(startCodeTime, endCodeTime, &
1205 !!$ 'setup5: tally_affected_links', .false.)
1206 !!$ call nudging_timer(startCodeTime)
1207 !!$ if(flushAll) flush(flushUnit)
1212 do ii=1,nObsMiss ! if nObsMiss is zero, this loop is skipped?
1213 iiImage = 0 ! this must happen on the same images as the above two mod(ii-1,numprocs)
1215 if(obsTimeStrAllocated(ii)) then
1217 ! Treat tally_affected_links
1218 if(my_id .eq. iiImage) nLinkAff = size(obsTimeStr(tt)%allCellInds)
1219 call mpp_land_bcast_int1_root(nLinkAff, iiImage)
1221 if(my_id .ne. iiImage) then
1222 if(allocated(obsTimeStr(tt)%allCellInds)) deallocate(obsTimeStr(tt)%allCellInds)
1223 if(allocated(obsTimeStr(tt)%nGageCell)) deallocate(obsTimeStr(tt)%nGageCell)
1224 allocate(obsTimeStr(tt)%allCellInds(nLinkAff))
1225 allocate(obsTimeStr(tt)%nGageCell(nLinkAff))
1227 call mpp_land_bcast_int1d_root(obsTimeStr(tt)%allCellInds, iiImage)
1228 call mpp_land_bcast_int1d_root(obsTimeStr(tt)%nGageCell, iiImage)
1234 !!$if(my_id .eq. io_id) then
1235 !!$ call nudging_timer(endCodeTime)
1236 !!$ call accum_nudging_time(startCodeTime, endCodeTime, &
1237 !!$ 'setup6: after bcast tally_aff', .false.)
1238 !!$ call nudging_timer(startCodeTime)
1239 !!$ if(flushAll) flush(flushUnit)
1245 !if(my_id .eq. io_id) then
1246 if(my_id .eq. -5) then
1249 print*,'Ndg: !-------------------------------------------------'
1250 print*,'Ndg: obsTimeStr(tt=',tt,')'
1251 print*,'Ndg: obsTimeStr(tt)%time:', obsTimeStr(tt)%time
1252 print*,'Ndg: obsTimeStr(tt)%updateTime:', obsTimeStr(tt)%updateTime
1253 print*,'Ndg: obsTimeStr(tt)%allCellInds:', obsTimeStr(tt)%allCellInds
1254 print*,'Ndg: obsTimeStr(tt)%nGageCell:', obsTimeStr(tt)%nGageCell
1255 if(trim(obsTimeStr(tt)%updateTime(1:7)) .ne. 'no file') then
1256 print*,'Ndg: nobs:', size(obsTimeStr(tt)%obsStr)
1257 print*,'Ndg: obsTimeStr(tt)%obsStr(1)%usgsId:', obsTimeStr(tt)%obsStr(1)%usgsId
1258 print*,'Ndg: obsTimeStr(tt)%obsStr(1)%obsTime:', obsTimeStr(tt)%obsStr(1)%obsTime
1259 print*,'Ndg: obsTimeStr(tt)%obsStr(1)%obsDischarge:', obsTimeStr(tt)%obsStr(1)%obsDischarge
1260 print*,'Ndg: obsTimeStr(tt)%obsStr(1)%obsQC:', obsTimeStr(tt)%obsStr(1)%obsQC
1261 print*,'Ndg: obsTimeStr(tt)%obsStr(1)%obsStaticInd:', obsTimeStr(tt)%obsStr(1)%obsStaticInd
1263 print*,'Ndg: !-------------------------------------------------'
1266 if(flushAll) flush(flushUnit)
1269 #endif /* HYDRO_D */
1273 !!$if(my_id .eq. io_id) then
1275 !!$ call nudging_timer(endCodeTime)
1276 !!$ call accum_nudging_time(startCodeTime, endCodeTime, &
1277 !!$ 'setup6: diagnostics at end', .false.)
1278 !!$ if(flushAll) flush(flushUnit)
1282 !!$#endif /* HYDRO_D */
1284 deallocate(obsTimeStrAllocated, whObsMiss)
1288 if(my_id .eq. io_id) &
1290 print*,'Ndg: finish setup_stream_nudging'
1293 !!$if(my_id .eq. io_id) then
1295 !!$ call nudging_timer(endCodeTime)
1296 !!$ call accum_nudging_time(startCodeTimeOuter, endCodeTime, &
1297 !!$ 'setup7: finish/full setup_stream_nudging', .true. )
1302 if(flushAll) flush(flushUnit)
1303 #endif /* HYDRO_D */
1305 end subroutine setup_stream_nudging
1307 !===================================================================================================
1309 ! timeslice_file_to_struct
1310 ! Author(s)/Contact(s):
1311 ! James L McCreight <jamesmcc><ucar><edu>
1313 ! Read a timeslice file, subset to observations in the domain, put into the
1314 ! obsTimeStr(timeIndex)%obsStr where obsTimeStr(timeIndex)%time impiles the
1315 ! file being read in and timeIndex is the only argument to this subroutine.
1317 ! 7/23/15 -Created, JLM.
1320 ! timeIndex: the index corresponding to time in the obsTimeStr
1321 ! Input Files: Specified argument.
1322 ! Output Files: None.
1324 ! User controllable options:
1325 ! Namelist option, logical "filterObsToDom". This removes observations which are not in the
1326 ! domain. May be useful for running small domains using large data files.
1329 subroutine timeslice_file_to_struct(structIndex)
1330 use module_nudging_utils, only: whichInLoop2
1332 use module_nudging_io, only: find_timeslice_file, &
1333 read_timeslice_file, &
1337 integer, intent(in) :: structIndex
1339 character(len=19) :: thisTime !! the of this time/slice of the structure
1340 character(len=256) :: fileName !! the corresponding obs file.
1343 integer, allocatable, dimension(:) :: whSliceInDom
1344 integer :: nWhSliceInDom
1345 integer :: count, ww, errStatus
1347 character(len=19) :: timeIn, updateTimeIn !! the time of file/slice and when it was updated
1348 character(len=2) :: sliceResoIn !! the temporal resolution of the slice
1349 character(len=19), allocatable, dimension(:) :: gageTimeIn !!
1350 real, allocatable, dimension(:) :: gageQCIn !!
1351 character(len=15), allocatable, dimension(:) :: usgsIdIn !! USGS ID
1352 real, allocatable, dimension(:) :: gageDischargeIn !! m3/s
1354 ! Is there a timeslice file?
1355 thisTime = obsTimeStr(structIndex)%time
1356 fileName = find_timeslice_file(thisTime, obsResolution)
1358 ! If no file, note in updateTime and get out!
1359 if(fileName .eq. '') then
1360 obsTimeStr(structIndex)%updateTime='no file'
1362 print*,'Ndg: no timeSliceFile at this time: ', thisTime
1363 if(flushAll) flush(flushUnit)
1369 print*,'Ndg: Found file:', fileName
1370 print*,'Ndg: timeSlice: ',thisTime
1371 print*,'Ndg: timeSliceFile:',trim(fileName), my_id
1372 if(flushAll) flush(flushUnit)
1375 nGages=get_netcdf_dim(fileName, 'stationIdInd', &
1376 'timeslice_file_to_struct', &
1377 readTimesliceErrFatal )
1378 ! If the dimension comes back zero, there's an issue with the file.
1379 ! If the error is not fatal, then handle the file as missing & print an
1380 ! additional message
1381 if(nGages .eq. 0) then
1382 obsTimeStr(structIndex)%updateTime='no file'
1383 print*,'Ndg: WARNING: issues with skipped timeSliceFile : ', thisTime
1387 !! Reduce to just the observations in the domain or not?
1388 if(filterObsToDom) then
1390 ! Bring in the full file to intermediate local variables.
1391 !! JLM:: it would probably be more efficient to do this when readingin the netcdf files.
1392 !! This capability is probably not needed for IOC, so I'm not doing it now.
1393 allocate(usgsIdIn(nGages))
1394 allocate(gageTimeIn(nGages))
1395 allocate(gageQCIn(nGages))
1396 allocate(gageDischargeIn(nGages))
1398 call read_timeslice_file(fileName, &
1399 sanityQcDischarge, &
1407 readTimesliceErrFatal,&
1410 if(errStatus .ne. 0) then
1411 obsTimeStr(structIndex)%updateTime='no file'
1412 print*,'Ndg: WARNING: issues with skipped timeSliceFile : ', thisTime
1413 deallocate(usgsIdIn, gageTimeIn, gageQCIn, gageDischargeIn)
1417 if(timeIn .NE. obsTimeStr(structIndex)%time) &
1418 call hydro_stop('timeslice_file_to_struct: file time does not match structure')
1419 if(obsResolution .NE. sliceResoIn) &
1420 call hydro_stop('timeslice_file_to_struct: model and file timeslice resolution do not match.')
1421 !save when the file was updated
1422 obsTimeStr(structIndex)%updateTime = updateTimeIn
1424 allocate(whSliceInDom(size(usgsIdIn)))
1425 call whichInLoop2(usgsIdIn, nodeGageStr%usgsId, whSliceInDom, nWhSliceInDom)
1428 ! print*,'Ndg: usgsIdIn: ', usgsIdIn
1429 ! print*,'Ndg: nodeGageStr%usgsId', nodeGageStr%usgsId
1430 print*,'Ndg: nWhSliceInDom:', nWhSliceInDom
1431 if(flushAll) flush(flushUnit)
1433 allocate(obsTimeStr(structIndex)%obsStr(nWhSliceInDom))
1434 !! because these dont get set here, give them default values.
1435 obsTimeStr(structIndex)%obsStr%obsStaticInd = 0
1436 obsTimeStr(structIndex)%obsStr%innov = -9999
1438 if(nWhSliceInDom .gt. 0) then
1440 do ww=1,size(whSliceInDom)
1441 if(whSliceInDom(ww) .gt. 0) then
1442 obsTimeStr(structIndex)%obsStr(count)%usgsId = usgsIdIn(ww)
1443 obsTimeStr(structIndex)%obsStr(count)%obsTime = gageTimeIn(ww)
1444 obsTimeStr(structIndex)%obsStr(count)%obsQC = gageQCIn(ww)
1445 obsTimeStr(structIndex)%obsStr(count)%obsDischarge = gageDischargeIn(ww)
1448 !! the gage is not in the domain/parameter file, record that this
1449 !! gage is available but unable to be assimilated.
1450 call accumulate_nwis_not_in_RLAndParams(nwisNotRLAndParams, &
1451 nwisNotRLAndParamsCount, usgsIdIn(ww))
1456 deallocate(whSliceInDom)
1457 deallocate(usgsIdIn, gageTimeIn, gageQCIn, gageDischargeIn)
1459 else ! dont filterObsToDom
1461 ! not reducing the obs file to the domain, can
1462 ! bring in the full file directly to the structure.
1463 allocate(obsTimeStr(structIndex)%obsStr(nGages))
1464 obsTimeStr(structIndex)%obsStr%obsStaticInd = 0
1465 obsTimeStr(structIndex)%obsStr%innov = -9999
1467 call read_timeslice_file(fileName, &
1468 sanityQcDischarge, &
1470 obsTimeStr(structIndex)%updateTime, &
1472 obsTimeStr(structIndex)%obsStr(:)%usgsId, &
1473 obsTimeStr(structIndex)%obsStr(:)%obsTime, &
1474 obsTimeStr(structIndex)%obsStr(:)%obsQC, &
1475 obsTimeStr(structIndex)%obsStr(:)%obsDischarge, &
1476 readTimesliceErrFatal, &
1479 if(errStatus .ne. 0) then
1480 obsTimeStr(structIndex)%updateTime='no file'
1481 print*,'Ndg: WARNING: issues with skipped timeSliceFile : ', thisTime
1482 deallocate(obsTimeStr(structIndex)%obsStr)
1486 if(timeIn .NE. obsTimeStr(structIndex)%time) &
1487 call hydro_stop('timeslice_file_to_struct: file time does not match that in obsTimeStr')
1488 if(obsResolution .NE. sliceResoIn) &
1489 call hydro_stop('timeslice_file_to_struct: model and file timeslice resolution do not match.')
1491 endif !filterObsToDom
1495 if(my_id .eq. io_id) &
1497 print*,'Ndg: finish timeslice_file_to_struct'
1498 if(flushAll) flush(flushUnit)
1501 end subroutine timeslice_file_to_struct
1503 !===================================================================================================
1505 ! obs_static_to_struct
1506 ! Author(s)/Contact(s):
1507 ! James L McCreight <jamesmcc><ucar><edu>
1509 ! For new obs read in from file, determine the associate static data:
1510 ! link index, parameters, cellsAffected, distances, and weights.
1512 ! 8/5/15 -Created, JLM.
1515 ! Input Files: Specified argument.
1516 ! Output Files: None.
1518 ! User controllable options:
1521 subroutine obs_static_to_struct()
1522 use module_nudging_utils, only: whUniLoop
1525 logical, allocatable, dimension(:) :: theMask
1526 integer, dimension(maxNeighLinksDim) :: upAllInds, downAllInds ! the collected inds/links
1527 real, dimension(maxNeighLinksDim) :: upAllDists, downAllDists ! distance at each collected ind
1528 integer :: upLastInd, downLastInd ! # of inds/links collected so far
1529 integer :: ll, whLastObsStr, tt
1530 integer, allocatable, dimension(:) :: nCellsInR
1531 logical :: setLastObsInfo
1535 if(my_id .eq. io_id) &
1537 print*,'Ndg: start obs_static_to_struct'
1538 if(flushAll) flush(flushUnit)
1541 ! nudgingParamsStr was already reduced to the intersection of all the
1542 ! gages in the parameter file and all those defined in nodeGageStr (Route_Link)
1543 ! so this is minimal by construction.
1548 if(my_id .eq. io_id) then
1550 ! have to search for the corresponding nodeId/obsCellInd. seems like this
1551 ! could have been done with making nudgingParamsStr, but it's not (necessary).
1552 allocate(theMask(size(nodeGageStr%usgsId)))
1553 ! loop over the entire structure and solve %obsCellind
1554 nudgeSpatial=.false.
1555 do ll=1,size(obsStaticStr_SoA%usgsId(:))
1556 !! this will always have a match b/c all
1557 !! obsStaticStr%usgsId=nudgingParamsStr$usgsId
1558 !! are in nodeGageStr by construction
1559 !! (if we were looping on nodeGageStr%usgsId this would not be assured)
1560 theMask = nodeGageStr%usgsId .eq. obsStaticStr_SoA%usgsId(ll)
1561 !! This is a double for loop... thanks to whUniLoop
1562 obsStaticStr_SoA%obsCellInd(ll) = nodeGageStr%nodeId(whUniLoop(theMask))
1563 if(obsStaticStr_SoA%R(ll) .ge. chanlen_image0(obsStaticStr_SoA%obsCellInd(ll))/2) &
1570 call mpp_land_bcast_logical(nudgeSpatial)
1571 call mpp_land_bcast_int1d(obsStaticStr_SoA%obsCellInd(:))
1576 if(my_id .eq. io_id) &
1578 print*,'Ndg: nudgeSpatial = ', nudgeSpatial
1580 !! get the requsite files if necessary
1581 !! this solves/allocates upNetwkStr and downNetwkStr
1582 if(nudgeSpatial) call get_netwk_reexpression()
1584 ! loop over the entire structure and solve
1585 ! 1) the spatial info: %cellsAffected, %dist, %ws
1586 ! 2) the lastObs info: %lastObsDischarge, %lastObsModelDischarge, %lastObsTime, %lastObsQuality
1587 ! 3) print diagnostics with or witout spatial info
1589 allocate(nCellsInR(size(obsStaticStr_SoA%usgsId(:))))
1591 if(my_id .eq. io_id) then
1593 do ll=1,size(obsStaticStr_SoA%usgsId(:))
1595 !! spatial static info
1596 if(nudgeSpatial) then
1598 !! Now solve the spaital part of obsStaticStr
1599 !---------------------
1600 ! Calculate cells affected by this gage
1601 ! upstream to R keep distances
1603 call distance_along_channel( &
1604 upNetwkStr, & ! traversal structure in up/down direction
1605 obsStaticStr_SoA%obsCellInd(ll), & ! the starting link
1606 0.0000000000, & ! distance (m) at the starting node (this iter.)
1607 obsStaticStr_SoA%R(ll), & ! to traverse, in meters.
1608 upAllInds, & ! collected links/inds
1609 upAllDists, & ! distance to collected links
1610 upLastInd ) ! index of last collected link in above 2 arrays.
1612 ! downstream to R keep distances
1614 call distance_along_channel( &
1615 downNetwkStr, & ! traversal structure in up/down direction
1616 obsStaticStr_SoA%obsCellInd(ll), & ! the starting link
1617 0.0000000000, & ! distance (m) at the starting node (this iter.)
1618 obsStaticStr_SoA%R(ll), & ! to traverse, in meters.
1619 downAllInds, & ! collected links/inds
1620 downAllDists, & ! distance to collected links
1621 downLastInd ) ! index of last collected link in above 2 arrays.
1623 ! Collect the up and down stream cells
1624 nCellsInR(ll) = 1 + upLastInd + downLastInd
1625 allocate(obsStaticStr(ll)%cellsAffected(nCellsInR(ll)))
1626 allocate(obsStaticStr(ll)%dist(nCellsInR(ll)))
1627 allocate(obsStaticStr(ll)%ws(nCellsInR(ll)))
1629 obsStaticStr(ll)%cellsAffected(1) = obsStaticStr_SoA%obsCellInd(ll)
1630 obsStaticStr(ll)%cellsAffected(2:(upLastInd+1)) = upAllInds(1:upLastInd)
1631 obsStaticStr(ll)%cellsAffected((upLastInd+2):nCellsInR(ll)) = downAllInds(1:downLastInd)
1633 ! Distance is optional in obsStaticStr. Right now keeping it for diagnostic potential.
1634 ! May replace with a local variable later when we dont want to keep it.
1635 obsStaticStr(ll)%dist(1) = 0
1636 obsStaticStr(ll)%dist(2:(upLastInd+1)) = -1. * upAllDists(1:upLastInd)
1637 obsStaticStr(ll)%dist((upLastInd+2):nCellsInR(ll)) = downAllDists(1:downLastInd)
1639 ! Calculate the cressman spatial weights
1640 obsStaticStr(ll)%ws = &
1641 ( obsStaticStr_SoA%R(ll)**2 - obsStaticStr(ll)%dist**2 ) / &
1642 ( obsStaticStr_SoA%R(ll)**2 + obsStaticStr(ll)%dist**2 )
1646 ! Collect the up and down stream cells
1648 allocate(obsStaticStr(ll)%cellsAffected(nCellsInR(ll)))
1649 allocate(obsStaticStr(ll)%dist(nCellsInR(ll)))
1650 allocate(obsStaticStr(ll)%ws(nCellsInR(ll)))
1652 obsStaticStr(ll)%cellsAffected(1) = obsStaticStr_SoA%obsCellInd(ll)
1653 obsStaticStr(ll)%dist(1) = 0
1654 obsStaticStr(ll)%ws = 1
1656 end if ! nudgeSpatial
1658 if(temporalPersistence) then
1659 ! the last obs "static" info
1660 ! this puts in dummy values if none are found
1661 setLastObsInfo = .false.
1662 if(allocated(lastObsStr_SoA%usgsId)) then
1663 if(any(lastObsStr_SoA%usgsId(:) .eq. obsStaticStr_SoA%usgsId(ll))) then
1664 allocate(theMask(size(lastObsStr_SoA%usgsId(:))))
1665 theMask = lastObsStr_SoA%usgsId(:) .eq. obsStaticStr_SoA%usgsId(ll)
1666 whLastObsStr = whUniLoop(theMask)
1668 !! Drop in the entire derived type for each array index! Very nice.
1669 obsStaticStr_SoA%lastObsStructure_SoA%usgsId(ll) = lastObsStr_SoA%usgsId(whLastObsStr)
1670 obsStaticStr_SoA%lastObsStructure_SoA%lastObsDischarge(:,ll) = lastObsStr_SoA%lastObsDischarge(:,whLastObsStr)
1671 obsStaticStr_SoA%lastObsStructure_SoA%lastObsTime(:,ll) = lastObsStr_SoA%lastObsTime(:,whLastObsStr)
1672 obsStaticStr_SoA%lastObsStructure_SoA%lastObsQuality(:,ll) = lastObsStr_SoA%lastObsQuality(:,whLastObsStr)
1673 obsStaticStr_SoA%lastObsStructure_SoA%lastObsModelDischarge(:,ll) = lastObsStr_SoA%lastObsModelDischarge(:,whLastObsStr)
1675 setLastObsInfo = .true.
1679 if(.not. setLastObsInfo) then ! the gage did not have a last observation
1680 obsStaticStr_SoA%lastObsDischarge(:,ll) = real(-9999)
1681 obsStaticStr_SoA%lastObsModelDischarge(:,ll) = real(-9999)
1682 do tt=1,nTimesLastObs
1683 obsStaticStr_SoA%lastObsTime(tt,ll) = missingLastObsTime
1685 obsStaticStr_SoA%lastObsQuality(:,ll) = real(0) !! keep this zero
1687 end if !temporalPersistence
1691 if (my_id .eq. -5) then
1692 ! 1 2 3 4 5 6 7 8 9 10
1693 !if( any( (/ 136, 981, 2242, 2845, 2946, 3014, 3066, 3068, 3072, 3158, 3228, &
1694 ! 3325, 3328, 3330, 3353, 3374, 3398, 3416, 3445, 3487, 3536, &
1695 ! 3621, 3667, 13554, 13651, 15062, 15311, 17450, 17394 /) &
1696 ! .eq. obsStaticStr(ll)%obsCellInd ) )then
1698 print*,'Ndg: !----------------------------------'
1699 print*,'Ndg: ! obsStaticStr(',ll,'):'
1700 print*,'Ndg: obsStaticStr(ll)%usgsId: ', obsStaticStr_SoA%usgsId(ll)
1701 print*,'Ndg: obsStaticStr(ll)%obsCellInd: ', obsStaticStr_SoA%obsCellInd(ll)
1702 print*,'Ndg: obsStaticStr(ll)%R: ', obsStaticStr_SoA%R(ll)
1703 print*,'Ndg: obsStaticStr(ll)%G: ', obsStaticStr_SoA%G(ll)
1704 print*,'Ndg: obsStaticStr(ll)%tau: ', obsStaticStr_SoA%tau(ll)
1705 print*,'Ndg: obsStaticStr(ll)%cellsAffected: ', obsStaticStr(ll)%cellsAffected
1706 print*,'Ndg: obsStaticStr(ll)%dist: ', obsStaticStr(ll)%dist
1707 print*,'Ndg: obsStaticStr(ll)%ws: ', obsStaticStr(ll)%ws
1708 if(temporalPersistence) then
1709 print*,'Ndg: obsStaticStr(ll)%lastObsDischarge: ', obsStaticStr_SoA%lastObsDischarge(:,ll)
1710 print*,'Ndg: obsStaticStr(ll)%lastObsDischarge: ', obsStaticStr_SoA%lastObsModelDischarge(:,ll)
1711 print*,'Ndg: obsStaticStr(ll)%lastObsTime: ', obsStaticStr_SoA%lastObsTime(:,ll)
1712 print*,'Ndg: obsStaticStr(ll)%lastObsQuality: ', obsStaticStr_SoA%lastObsQuality(:,ll)
1714 print*,'Ndg: !----------------------------------'
1716 endif ! my_id .eq. -5 (off) or any of the diagnostic inds - toggle the comments.
1717 if(flushAll) flush(flushUnit)
1718 #endif /* HYDRO_D */
1722 end if !! my_id .eq. io_id
1724 !broadcast %cellsAffected, %dist, %ws
1725 do ll=1,size(obsStaticStr_SoA%usgsId)
1726 call mpp_land_bcast_int1(nCellsInR(ll))
1727 if(my_id .ne. io_id) then
1728 allocate(obsStaticStr(ll)%cellsAffected(nCellsInR(ll)))
1729 allocate(obsStaticStr(ll)%dist(nCellsInR(ll)))
1730 allocate(obsStaticStr(ll)%ws(nCellsInR(ll)))
1732 call mpp_land_bcast_int1d(obsStaticStr(ll)%cellsAffected)
1733 call mpp_land_bcast_real_1d(obsStaticStr(ll)%dist)
1734 call mpp_land_bcast_real_1d(obsStaticStr(ll)%ws)
1736 if(temporalPersistence) then
1737 call mpp_land_bcast_real_1d(obsStaticStr_SoA%lastObsDischarge(:,ll))
1738 call mpp_land_bcast_real_1d(obsStaticStr_SoA%lastObsModelDischarge(:,ll))
1739 call mpp_land_bcast_char1d( obsStaticStr_SoA%lastObsTime(:,ll))
1740 call mpp_land_bcast_real_1d(obsStaticStr_SoA%lastObsQuality(:,ll))
1743 #endif /* MPP_LAND */
1745 deallocate(nCellsInR)
1748 print*,'Finnish obs_static_to_struct'
1749 if(flushAll) flush(flushUnit)
1752 end subroutine obs_static_to_struct
1755 !===================================================================================================
1757 ! subroutine output_nudging_last_obs
1758 ! Author(s)/Contact(s):
1759 ! James L McCreight <jamesmcc><ucar><edu>
1761 ! Collect and Write out the last observations collected over time.
1763 ! 02/09/16 -Created, JLM.
1769 ! User controllable options: None.
1770 ! Notes: Needs better error handling...
1772 subroutine output_nudging_last_obs()
1773 use module_RT_data, only: rt_domain
1774 use module_nudging_utils, only: whUniLoop
1775 use module_nudging_io, only: write_nudging_last_obs, write_nudging_last_obs_soa
1777 use MODULE_mpp_ReachLS, only: linkls_s, linkls_e
1779 real, allocatable, dimension(:) :: g_nudge
1780 logical, allocatable, dimension(:) :: theMask
1781 integer :: whImage, oo
1784 if(.not. temporalPersistence) return
1787 !! if MPP: last obs are being written on different processors,
1788 !! get them back to image0 for output.
1789 !! 1. loop over obsStaticStr.
1790 !! 2. find the image holding obsCellInd
1791 !! 3. communicate it's last ob back to image0.
1792 allocate(theMask(size(linkls_s))) ! number of processors
1794 do oo=1, size(obsStaticStr_SoA%obsCellInd(:)) ! loop over the gages
1796 ! Is this gage in the range for this image?
1797 theMask = ( obsStaticStr_SoA%obsCellInd(oo) .ge. linkls_s .and. &
1798 obsStaticStr_SoA%obsCellInd(oo) .le. linkls_e )
1799 ! The image where the gage info is located
1800 whImage = whUniLoop(theMask) - 1
1802 ! if the data is on this image or this image is the receiver, then communicate.
1803 if(my_id .ne. whImage .and. my_id .ne. io_id) cycle
1804 ! no communication necessary on the io image
1805 if(whImage .eq. io_id) cycle
1807 call mpp_comm_1d_real(obsStaticStr_SoA%lastObsDischarge(:,oo), whImage, io_id)
1808 call mpp_comm_1d_real(obsStaticStr_SoA%lastObsModelDischarge(:,oo), whImage, io_id)
1809 call mpp_comm_1d_char(obsStaticStr_SoA%lastObsTime(:,oo), whImage, io_id)
1810 call mpp_comm_1d_real(obsStaticStr_SoA%lastObsQuality(:,oo), whImage, io_id)
1816 if(my_id .eq. io_id) then
1817 allocate(g_nudge(rt_domain(1)%gnlinksl))
1819 allocate(g_nudge(1))
1821 call ReachLS_write_io(RT_DOMAIN(1)%nudge,g_nudge)
1823 if(my_id .eq. io_id) &
1824 #endif /* MPP_LAND */
1825 !! write out the last obs to file
1826 call write_nudging_last_obs_soa(obsStaticStr_SoA%lastObsStructure_SoA, &
1827 nlst(did)%olddate, &
1832 end subroutine output_nudging_last_obs
1835 !===================================================================================================
1837 ! accumulate_nwis_not_in_RLAndParams
1838 ! Author(s)/Contact(s):
1839 ! James L McCreight <jamesmcc><ucar><edu>
1841 ! Keep a running, non-redundant log of gages seen in the forecast cycle
1842 ! (from nwis) which were not found in the intersection of the Route_Link
1843 ! gages and the parameter file gages.
1845 ! 11/4/15 - Created, JLM.
1851 ! User controllable options:
1854 subroutine accumulate_nwis_not_in_RLAndParams(nwisNotRLAndParams_local, &
1855 nwisNotRLAndParamsCount_local, &
1858 character(len=15), dimension(:), intent(inout) :: nwisNotRLAndParams_local
1859 integer, intent(inout) :: nwisNotRLAndParamsCount_local
1860 character(len=15), intent(in) :: gageId
1861 if(.not. any(nwisNotRLAndParams_local .eq. gageId)) then
1862 nwisNotRLAndParamsCount_local=nwisNotRLAndParamsCount_local+1
1863 if(nwisNotRLAndParamsCount .gt. size(nwisNotRLAndParams)) &
1864 call hydro_stop('accumulate_nwis_not_in_RLAndParams: coutn of gages from NWIS not found ' // &
1865 'in intersection of RL and Param gages are exceeding the hardcoded limit:,'// &
1866 ' maxNwisNotRLAndParamsCount')
1867 nwisNotRLAndParams_local(nwisNotRLAndParamsCount_local)=gageId
1869 end subroutine accumulate_nwis_not_in_RLAndParams
1872 !===================================================================================================
1874 ! distance_along_channel
1875 ! Author(s)/Contact(s):
1876 ! James L McCreight <jamesmcc><ucar><edu>
1878 ! Traverse the gridded channel network up or down stream, return the cumulative distance
1879 ! and indices of points visited. Going from one link to the next counts half the length
1880 ! of each as the distance. Conceptually that's midpoint to midpoint though there's really
1881 ! no midpoint. If half the length to the first midpoint exceeds R, no index is returned.
1882 ! That is, lastInd is zero.
1885 ! 6/4/15 - Created, JLM.
1886 ! 8/7/15 - Heavily refactored to remove searching, JLM.
1889 ! See formal arguments and their declarations
1890 ! Input Files: Specified argument.
1891 ! Output Files: None.
1893 ! User controllable options:
1895 ! The total number of links gathered is hardwired to 10,000 which is for both directions. In NHD+
1896 ! the shortest link is 1m. If you managed to traverse just the shortest 10,000 links then you only
1897 ! go [R language: > sum(head(sort(reInd$length),10000))/1000 = 60.0745] 60km. This is the minimum
1898 ! upper bound on R implied by the choice of 10,000. If lastInd ever becomes 10,001 a fatal error
1901 recursive subroutine distance_along_channel(direction, & ! traversal structure in up/down direction
1902 startInd, & ! the starting link
1903 startDist, & ! distance at the starting node (this iter.)
1904 radius, & ! to traverse, in meters.
1905 allInds, & ! collected links/inds
1906 allDists, & ! distance to collected links
1907 lastInd ) ! index of last collected link in above.
1908 use module_RT_data, only: rt_domain
1911 type(netwkReExpStructure), intent(in) :: direction ! up/down NtwkStr with tarversal inds, pass by ref!
1912 integer, intent(in) :: startInd ! the starting link
1913 real, intent(in) :: startDist ! distance at the starting node (for this iteration)
1914 real, intent(in) :: radius ! in meteres
1915 integer, intent(inout), dimension(maxNeighLinksDim) :: allInds ! the collected inds/links
1916 real, intent(inout), dimension(maxNeighLinksDim) :: allDists ! the distance at each collected ind
1917 integer, intent(inout) :: lastInd ! the number of inds/links collected so far.
1919 ! whGo is only > 1 upstream with a current max of 17 in NHD+
1923 integer, parameter :: did=1
1925 !! this routine is only called on io_id
1929 if(my_id .eq. io_id) &
1931 print*,'Ndg: start distance_along_channel'
1932 if(flushAll) flush(flushUnit)
1935 if(direction%end(startInd) .eq. 0) return ! a pour point (downstream) or a 1st order link (upstream)
1937 nGo = direction%end(startInd) - direction%start(startInd)
1938 nGo = nGo + 1 ! end-start+1 if end-start > 0
1940 go = direction%go( direction%start(startInd) + gg )
1941 allInds(lastInd+1) = go
1943 newDist = ( chanlen_image0(startInd) + chanlen_image0(go) ) / 2.
1945 newDist = ( rt_domain(did)%chanlen(startInd) + rt_domain(did)%chanlen(go) ) / 2.
1947 if(startDist + newDist .gt. radius) return ! strictly greater than.
1948 allDists(lastInd+1) = startDist + newDist
1950 if(lastInd .ge. 10001) &
1951 call hydro_stop('distance_along_channel: hardwired 10000 variable size exceeded. FIX.')
1952 call distance_along_channel( &
1953 direction, & ! the traversal structure, pass by reference.
1954 go, & ! the new startInd is where we go from the old startInd
1955 startDist+newDist, & ! a little bit further is where we start the next call.
1957 allInds, & ! collected inds
1958 allDists, & ! collected dists
1959 lastInd ) ! the number collected so far
1963 print*,'Ndg: end distance_along_channel'
1964 if(flushAll) flush(flushUnit)
1967 end subroutine distance_along_channel
1969 !===================================================================================================
1971 ! tally_affected_links
1972 ! Author(s)/Contact(s):
1973 ! James L McCreight <jamesmcc><ucar><edu>
1977 ! Usage: call tally_affected_links(tt)
1979 ! Input Files: None.
1980 ! Output Files: None.
1982 ! User controllable options:
1985 subroutine tally_affected_links(timeIndex)
1986 use module_RT_data, only: rt_domain
1989 integer, intent(in) :: timeIndex
1990 integer, allocatable, dimension(:) :: affectedInds, nGageAffect
1991 integer :: nlinks, ii, oo, cc, nLinkAff, indAff, staticInd
1992 integer, parameter :: did=1
1994 if (nlst(did)%channel_option .eq. 3) nLinks = RT_DOMAIN(did)%NLINKS ! For gridded channel routing
1995 if (nlst(did)%channel_option .eq. 1 .or. &
1996 nlst(did)%channel_option .eq. 2 ) &
1999 RT_DOMAIN(did)%gNLINKSL ! For reach-based routing in parallel
2001 RT_DOMAIN(did)%NLINKSL ! For reach-based routing
2004 allocate(affectedInds(nLinks), nGageAffect(nLinks))
2009 ! parallelize this ||||||||||||||||||||||||||||||||||||||||
2010 do oo=1,size(obsTimeStr(timeIndex)%obsStr)
2011 staticInd = obsTimeStr(timeIndex)%obsStr(oo)%obsStaticInd
2012 if(staticInd .eq. 0) cycle
2013 nLinkAff = size(obsStaticStr(staticInd)%cellsAffected)
2015 indAff = obsStaticStr(staticInd)%cellsAffected(cc)
2016 affectedInds(indAff) = indAff
2017 nGageAffect(indAff) = nGageAffect(indAff) + 1
2021 ! how many total cells affected?
2022 nLinkAff = sum((/(1, ii=1,nLinks)/), mask=affectedInds .ne. 0)
2024 allocate(obsTimeStr(timeIndex)%allCellInds(nLinkAff))
2025 allocate(obsTimeStr(timeIndex)%nGageCell(nLinkAff))
2027 obsTimeStr(timeIndex)%allCellInds = pack(affectedInds, mask=affectedInds .ne. 0)
2028 obsTimeStr(timeIndex)%nGageCell = pack(nGageAffect, mask=nGageAffect .ne. 0)
2030 deallocate(affectedInds, nGageAffect)
2033 print*,'Ndg: end tally_affected_links'
2034 if(flushAll) flush(flushUnit)
2037 end subroutine tally_affected_links
2040 !===================================================================================================
2043 ! author(s)/contact(s):
2046 ! compute the temporal weight factor for an observation
2049 ! 12/1/15 - moved to inverse distance
2056 ! user controllable options:
2059 real function time_wt(modelTime, tau, obsTime)
2060 use module_date_utils_nudging, only: geth_idts
2062 character(len=19), intent(in) :: modelTime ! model time string
2063 real, intent(in) :: tau ! tau half window (minutes)
2064 character(len=19), intent(in) :: obsTime ! observation time string
2067 real, parameter :: ten = 10.000000000
2068 real, parameter :: one = 1.000000000
2069 real, parameter :: zero = 0.000000000
2070 integer, parameter :: zeroInt = 0
2071 !! returned timeDiff is in seconds
2072 call geth_idts(obsTime, modelTime, timeDiff)
2073 timeDiff = timeDiff / 60. ! minutes to match tau
2075 !! this is the old, ramped, wrf-style time weighting.
2076 !time_wt = 0. ! = if(abs(timeDiff) .gt. tau)
2077 !if(abs(timeDiff) .lt. tau/2.) time_wt = 1.
2078 !if(abs(timeDiff) .ge. tau/2. .and. &
2079 ! abs(timeDiff) .le. tau ) time_wt = (tau - abs(timeDiff)) / (tau/2.)
2081 !this is the new, inverse distance weighting
2082 if(abs(timeDiff) .gt. tau) then
2086 !! this function has a range of [1, 10^10] so that
2087 !! the variable "weighting" in the function 'nudge_term_link' is
2088 !! assuredly greater than 1e-8 if weights are calculated.
2089 time_wt = (ten ** ten) * ((one/ten) ** (abs(timeDiff)/(tau/ten)))
2091 end function time_wt
2093 !!$!===================================================================================================
2096 !!$! Author(s)/Contact(s):
2101 !!$! 6/4/15 - Created,
2107 !!$! Condition codes:
2108 !!$! User controllable options:
2110 !!$real function cress(rr,rrmax)
2112 !!$real,intent(in):: rr,rrmax
2113 !!$if(rr .ge. rrmax)then
2116 !!$ cress = (rrmax - rr)/(rrmax + rr)
2118 !!$end function cress
2121 !===================================================================================================
2124 ! Author(s)/Contact(s):
2126 ! James McCreight >jamesmcc<>at<>ucar<>dot<>edu<
2128 ! Calculate the innovations of obs.
2130 ! 2015.07.15 - Created.
2138 ! User controllable options:
2141 subroutine nudge_innov(discharge)
2143 real, dimension(:,:), intent(in) :: discharge !! modeled discharge (m3/s)
2144 integer :: tt, oo, nObsTt, linkInd, staticInd
2145 if(.not. allocated(obsTimeStr)) return
2146 do tt=1,size(obsTimeStr)
2147 if(.not. allocated(obsTimeStr(tt)%obsStr)) cycle
2148 nObsTt = size(obsTimeStr(tt)%obsStr)
2150 staticInd = obsTimeStr(tt)%obsStr(oo)%obsStaticInd
2151 linkInd = obsStaticStr_SoA%obsCellInd(staticInd)
2152 obsTimeStr(tt)%obsStr(oo)%innov = &
2153 ( obsTimeStr(tt)%obsStr(oo)%obsDischarge - discharge(linkInd,2) ) &
2154 *obsTimeStr(tt)%obsStr(oo)%obsQC
2157 end subroutine nudge_innov
2160 !===================================================================================================
2163 ! Author(s)/Contact(s):
2164 ! Wu YH, James McCreight
2166 ! Calculate the nudging term for one
2168 ! 2015.07.21 - Created,
2175 ! User controllable options:
2178 subroutine nudge_term_all(discharge, nudgeAdj, hydroAdv)
2179 use module_RT_data, only: rt_domain
2180 use module_nudging_utils, only: nudging_timer, &
2183 use MODULE_mpp_ReachLS, only: linkls_s, linkls_e, gNLinksL, ReachLS_write_io
2187 real, dimension(:,:), intent(inout) :: discharge !! modeled discharge (m3/s)
2188 real, dimension(:), intent(out) :: nudgeAdj !! nudge to modeled discharge (m3/s)
2189 integer, intent(in) :: hydroAdv !! number of seconds the channel model has advanced
2191 real, allocatable, dimension(:) :: global_discharge !! modeled discharge (m3/s)
2193 integer :: ll, startInd, endInd, checkInd
2196 !!$#ifdef HYDRO_D /* un-ifdef to get timing results */
2197 !!$real :: startCodeTimeAcc, endCodeTimeAcc
2199 !!$if(my_id .eq. io_id) &
2200 !!$#endif /* MPP_LAND */
2201 !!$ call nudging_timer(startCodeTimeAcc)
2202 !!$if(flushAll) flush(flushUnit)
2203 !!$#endif /* HYDRO_D */ /* un-ifdef to get timing results */
2206 !! get global discharge. This is only needed if spatial interpolation.
2207 !! eventually logic: if spatialNudging determines use of global_discharge
2208 allocate(global_discharge(gNLinksL))
2209 call ReachLS_write_io(discharge(:,2), global_discharge)
2210 call mpp_land_bcast_real_1d(global_discharge)
2211 !! need to transform passed index to appropriate index for image
2212 startInd=linkls_s(my_id+1)
2213 endInd =linkls_e(my_id+1)
2216 endInd =RT_DOMAIN(did)%NLINKSL
2219 if(.not. gotT0Discharge) then
2220 allocate(t0Discharge(size(discharge(:,1))))
2221 t0Discharge = discharge(:,1)
2222 gotT0Discharge = .true.
2225 do ll=startInd, endInd ! ll is in the index of the global Route_Link
2228 checkInd = -9999 ! 136 !2569347 !2139306 !213095 ! 2211014 ! see below as well
2229 if(ll .eq. checkInd) then
2230 print*,'Ndg: checkInd: -------------------------'
2231 print*,"Ndg: checkInd: checkInd: ",checkInd
2232 print*,'Ndg: checkInd: discharge(ll,2) before:',discharge(ll-startInd+1,2)
2233 if(flushAll) flush(flushUnit)
2236 theNudge = nudge_term_link(ll-startInd+1, hydroAdv, global_discharge)
2237 discharge(ll-startInd+1,2) = discharge(ll-startInd+1,2) + theNudge
2239 if(ll .eq. checkInd) then
2240 print*,'Ndg: checkInd: theNudge:',theNudge
2241 print*,'Ndg: checkInd: discharge(ll,2) after:',discharge(ll-startInd+1,2)
2242 if(flushAll) flush(flushUnit)
2246 !! the following only valid since nudge_term_all is applied after the time step.
2247 nudgeAdj=discharge(:,2)-discharge(:,1)
2248 discharge(:,1)=discharge(:,2)
2249 deallocate(global_discharge)
2251 #ifdef HYDRO_D /* un-ifdef to get timing results */
2253 !!$if(my_id .eq. io_id) then
2255 !!$ call nudging_timer(endCodeTimeAcc)
2256 !!$ call accum_nudging_time(startCodeTimeAcc, endCodeTimeAcc, 'nudge_term_all', .true.)
2261 if(my_id .eq. io_id) &
2263 print*,'Ndg: finish nudge_term_all'
2264 if(flushAll) flush(flushUnit)
2265 #endif /* HYDRO_D */ /* un-ifdef to get timing results */
2267 end subroutine nudge_term_all
2270 !===================================================================================================
2273 ! Author(s)/Contact(s):
2275 ! James L McCreight jamesmcc><at><ucar><dot><edu
2277 ! Calculate the nudging term for one model cell
2279 ! 2015.07.21 - Created,
2286 ! User controllable options:
2288 ! note well that the weighting term has to sum to more than 1.E-8
2289 ! or the weighting is ignored.
2291 function nudge_term_link(linkIndIn, hydroAdv, discharge)
2292 use module_nudging_utils, only: whUniLoop
2293 use module_date_utils_nudging, only: geth_newdate, geth_idts
2295 use MODULE_mpp_ReachLS, only: linkls_s, linkls_e
2299 integer, intent(in) :: linkIndIn !! stream cell index (local)
2300 integer, intent(in) :: hydroAdv !! number of seconds the channel model has advanced
2301 real, dimension(:), intent(in) :: discharge !! modeled discharge (m3/s)
2302 real :: nudge_term_link
2304 logical :: persistBias_local
2306 character(len=19) :: hydroTime !! actual time of the routing model
2307 real :: theInnov, weighting, theBias
2308 integer :: tt, oo, ll, jj, nObsTt, staticInd, obsInd
2309 real, parameter :: smallestWeight=1.e-8
2310 !! persistence related variables in following block
2311 integer :: whGageId, flowMonth, whThresh, lastObsDt, prstDtErrInt, obsDtInt, pairCount
2312 logical, dimension(nTimesLastObs) :: biasMask, whObsTooOld
2313 real, dimension(nTimesLastObs) :: biasWeights
2314 real :: prstB, prstDtErr, prstErr, biasWeightSum, coefVarX, coefVarY
2315 character(len=15) :: prstGageId
2317 real :: corr, sumx, sumx2, sumxy, sumy, sumy2, xCorr, yCorr, deltaT0Discharge
2318 integer, parameter :: sixty=60
2319 real, parameter :: smallestNudge=1.e-10
2320 real, parameter :: zero=1.e-37
2321 real, parameter :: zeroInt=0
2322 real, parameter :: one= 1.00000000000000000000000
2324 integer :: whPrstParams
2325 logical, allocatable, dimension(:) :: theMask
2327 integer :: whImage, checkInd
2329 !! need to transform passed index to appropriate index for image
2330 linkInd = linkIndIn + linkls_s(my_id+1) - 1
2334 checkInd = -9999 ! 136 !2569347 !2139306 !2565959 !213095!2211014 ! see above
2336 call geth_newdate(hydroTime, lsmTime, hydroAdv)
2338 nudge_term_link = zero
2342 if(linkInd .eq. checkInd) then
2343 print*,'Ndg: checkInd: hydroTime: ',hydroTime
2344 print*,'Ndg: checkInd: linkInd', linkInd
2345 if(flushAll) flush(flushUnit)
2349 !! JLM: document what is this loop doing?
2350 !! 1) Moving the observation structure in to nudginLastObs struct.
2351 !! 2) Calculating the nudging terms & weights at different positions along the assim window.
2352 do tt=1,size(obsTimeStr)
2354 if(.not. allocated(obsTimeStr(tt)%allCellInds)) cycle
2355 if(.not. any(obsTimeStr(tt)%allCellInds .eq. linkInd)) cycle
2356 if(.not. allocated(obsTimeStr(tt)%obsStr)) cycle
2358 do oo=1,size(obsTimeStr(tt)%obsStr)
2360 !! if no spatial interp... this could be sped up, there's at most one match.
2361 !! this might just be an exit statement at the end of the loop for non-spatial nudges.
2362 staticInd = obsTimeStr(tt)%obsStr(oo)%obsStaticInd
2363 if(.not. any(obsStaticStr(staticInd)%cellsAffected .eq. linkInd)) cycle
2365 if(temporalPersistence) then
2366 ! If the model time is greater than or at the obs time AND
2367 ! the obs time is greater than the last written obs: then write to last obs.
2368 call geth_idts(hydroTime, obsTimeStr(tt)%obsStr(oo)%obsTime, prstDtErrInt)
2370 if(missingLastObsTime .eq. &
2371 obsStaticStr_SoA%lastObsTime(nTimesLastObs,staticInd)) then
2374 call geth_idts(obsTimeStr(tt)%obsStr(oo)%obsTime, &
2375 obsStaticStr_SoA%lastObsTime(nTimesLastObs,staticInd), obsDtInt)
2378 if(prstDtErrInt .ge. 0 .and. &
2379 obsDtInt .gt. 0 .and. &
2380 obsTimeStr(tt)%obsStr(oo)%obsQC .eq. 1) then
2381 !! shift (note cshift does not work for all these)
2382 obsStaticStr_SoA%lastObsTime(1:(nTimesLastObs-1),staticInd) = &
2383 obsStaticStr_SoA%lastObsTime(2:nTimesLastObs,staticInd)
2384 obsStaticStr_SoA%lastObsDischarge(1:(nTimesLastObs-1),staticInd) = &
2385 obsStaticStr_SoA%lastObsDischarge(2:nTimesLastObs,staticInd)
2386 obsStaticStr_SoA%lastObsModelDischarge(1:(nTimesLastObs-1),staticInd) = &
2387 obsStaticStr_SoA%lastObsModelDischarge(2:nTimesLastObs,staticInd)
2388 obsStaticStr_SoA%lastObsQuality(1:(nTimesLastObs-1),staticInd) = &
2389 obsStaticStr_SoA%lastObsQuality(2:nTimesLastObs,staticInd)
2391 obsStaticStr_SoA%lastObsTime(nTimesLastObs,staticInd) = &
2392 obsTimeStr(tt)%obsStr(oo)%obsTime
2393 obsStaticStr_SoA%lastObsDischarge(nTimesLastObs,staticInd) = &
2394 obsTimeStr(tt)%obsStr(oo)%obsDischarge
2395 obsStaticStr_SoA%lastObsModelDischarge(nTimesLastObs,staticInd) = &
2396 discharge(obsStaticStr_SoA%obsCellInd(staticInd))
2397 obsStaticStr_SoA%lastObsQuality(nTimesLastObs,staticInd) = &
2398 obsTimeStr(tt)%obsStr(oo)%obsQC
2400 endif !temporalPersistence
2402 allocate(theMask(size(obsStaticStr(staticInd)%cellsAffected)))
2403 theMask = obsStaticStr(staticInd)%cellsAffected .eq. linkInd
2404 ll = whUniLoop(theMask)
2407 obsInd = obsStaticStr_SoA%obsCellInd(staticInd)
2410 ( obsTimeStr(tt)%obsStr(oo)%obsDischarge - discharge(obsInd) ) &
2411 *obsTimeStr(tt)%obsStr(oo)%obsQC
2413 nudge_term_link = nudge_term_link &
2415 *obsStaticStr_SoA%G(staticInd) &
2416 *time_wt(hydroTime, &
2417 obsStaticStr_SoA%tau(staticInd), &
2418 obsTimeStr(tt)%obsStr(oo)%obsTime) &
2419 *time_wt(hydroTime, &
2420 obsStaticStr_SoA%tau(staticInd), &
2421 obsTimeStr(tt)%obsStr(oo)%obsTime) &
2422 *obsStaticStr(staticInd)%ws(ll) &
2423 *obsStaticStr(staticInd)%ws(ll)
2425 !! note well that the weighting has to sum to more than 1.E-8
2426 !! or the whole nudge is ignored.
2427 weighting = weighting &
2428 +time_wt(hydroTime, &
2429 obsStaticStr_SoA%tau(staticInd), &
2430 obsTimeStr(tt)%obsStr(oo)%obsTime) &
2431 *time_wt(hydroTime, &
2432 obsStaticStr_SoA%tau(staticInd), &
2433 obsTimeStr(tt)%obsStr(oo)%obsTime) &
2434 *obsStaticStr(staticInd)%ws(ll) &
2435 *obsStaticStr(staticInd)%ws(ll)
2438 if(linkInd .eq. checkInd) then
2439 !if( (obsTimeStr(tt)%time .eq. obsTimeStr(tt)%obsStr(oo)%obsTime) .and. &
2440 ! ( abs(discharge(obsInd)+theInnov - obsTimeStr(tt)%obsStr(oo)%obsDischarge) .gt. .01) ) then
2441 print*,'Ndg: checkInd: -*-*-*-*-*-*-*-*-*-*-*-*'
2442 print*,'Ndg: checkInd: linkInd: ', linkInd
2443 print*,'Ndg: checkInd: tt: ', tt
2444 print*,'Ndg: checkInd: oo: ', oo
2445 print*,'Ndg: checkInd: obsCellInd: ', obsInd
2447 print*,'Ndg: checkInd: discharge: ', discharge(obsInd)
2448 print*,'Ndg: checkInd: theInnov: ',theInnov
2450 print*,'Ndg: checkInd: obsDischarge: ', obsTimeStr(tt)%obsStr(oo)%obsDischarge
2452 print*,'Ndg: checkInd: obsQC: ', obsTimeStr(tt)%obsStr(oo)%obsQC
2453 print*,'Ndg: checkInd: usgsId: ', obsTimeStr(tt)%obsStr(oo)%usgsId
2455 print*,'Ndg: checkInd: time_wt: ', time_wt(hydroTime,obsStaticStr_SoA%tau(staticInd), &
2456 obsTimeStr(tt)%obsStr(oo)%obsTime )
2457 print*,'Ndg: checkInd: hydroTime : ', hydroTime
2458 print*,'Ndg: checkInd: obsTimeStr(tt)%time: ', obsTimeStr(tt)%time
2459 print*,'Ndg: checkInd: obsTime: ', obsTimeStr(tt)%obsStr(oo)%obsTime
2460 print*,'Ndg: checkInd: ws: ', obsStaticStr(staticInd)%ws(ll)
2461 print*,'Ndg: checkInd: nudge_term_link: ', nudge_term_link
2462 print*,'Ndg: checkInd: weighting: ', weighting
2463 if(flushAll) flush(flushUnit)
2465 #endif /* HYDRO_D */
2471 !!---------------------------------------------
2472 !! Was there a nudge in +-tau or do we apply persistence?
2473 if(abs(weighting) .gt. smallestWeight) then !! 1.e-10
2476 !!$ if(linkInd .eq. 4) then
2477 !!$ print*,'Ndg: nudge_term_link: ', nudge_term_link
2478 !!$ print*,'Ndg: weighting: ', weighting
2479 !!$ print*,'Ndg: nudge_term_link/weighting: ',nudge_term_link/weighting
2482 ! normalize the nudge
2483 nudge_term_link = nudge_term_link/weighting
2485 else if (temporalPersistence) then
2489 !! -1) Make a local copy of the global/namelist setting persistBias so that
2490 !! if there are not enough observations available to persistBias, the
2491 !! standard observation persistence is applied.
2492 persistBias_local = persistBias
2494 !! if no nudge was applied then fall back on to persistence of last observation
2495 !! 0) assume we dont find a solution so we can freely bail out.
2496 nudge_term_link = zero
2498 !! 1) what is the current link's gageId?
2499 if(.not. any(obsStaticStr_SoA%obsCellInd(:) .eq. linkInd)) return
2501 allocate(theMask(size(obsStaticStr_SoA%obsCellInd(:))))
2503 theMask = obsStaticStr_SoA%obsCellInd(:) .eq. linkInd
2504 whGageId = whUniLoop(theMask)
2507 prstGageId = obsStaticStr_SoA%usgsId(whGageId)
2508 obsInd = obsStaticStr_SoA%obsCellInd(whGageId)
2510 !! 2) minimum number of observations
2511 if(persistBias_local) then
2512 !! This section creates a mask of usable values to use in the bias calculation
2513 !! subject to two parameters of the method.
2515 !!-----------------------------------
2516 !! maxAgePairsBiasPersist
2517 !! if greater than 0: apply an age-based filter
2518 !! if zero : apply no additional use all available obs.
2519 !! if less than zero: apply an count-based filter
2522 if(maxAgePairsBiasPersist .gt. 0) then
2523 !! assume the obs are all too old, find the not so old ones
2524 whObsTooOld = .true.
2525 !! assume all weights are bad
2526 if(persistBias_local .and. invDistTimeWeightBias) biasWeights = -9999
2527 do tt=nTimesLastObs,1,-1
2528 !! missing obs are not mixed with good obs. The first missing obs means the rest are missing.
2529 if(obsStaticStr_SoA%lastObsTime(tt,whGageId) .eq. missingLastObsTime) exit
2530 if(biasWindowBeforeT0) then
2531 !! use the init time to define the end of the bias window
2532 call geth_idts(initTime, obsStaticStr_SoA%lastObsTime(tt,whGageId), obsDtInt)
2534 !! use the hydro model time to define the end of the bias window
2535 call geth_idts(hydroTime, obsStaticStr_SoA%lastObsTime(tt,whGageId), obsDtInt)
2537 if(persistBias_local .and. invDistTimeWeightBias) &
2539 biasWeights(tt) = real(obsDtInt + nlst(did)%dtrt_ch)
2541 !biasWeights(tt) = real(obsDtInt + obsResolutionInt)
2543 if(obsDtInt .gt. (maxAgePairsBiasPersist*60*60)) exit
2544 whObsTooOld(tt) = .false.
2546 biasMask= obsStaticStr_SoA%lastObsQuality(:,whGageId) .eq. one .and. &
2547 obsStaticStr_SoA%lastObsTime(:,whGageId) .ne. missingLastObsTime .and. &
2548 obsStaticStr_SoA%lastObsModelDischarge(:,whGageId) .gt. zero .and. &
2552 if(maxAgePairsBiasPersist .eq. 0) then
2553 biasMask= obsStaticStr_SoA%lastObsQuality(:,whGageId) .eq. one .and. &
2554 obsStaticStr_SoA%lastObsTime(:,whGageId) .ne. missingLastObsTime .and. &
2555 obsStaticStr_SoA%lastObsModelDischarge(:,whGageId) .gt. zero
2558 if(maxAgePairsBiasPersist .lt. 0) then
2559 biasMask= obsStaticStr_SoA%lastObsQuality(:,whGageId) .eq. one .and. &
2560 obsStaticStr_SoA%lastObsTime(:,whGageId) .ne. missingLastObsTime .and. &
2561 obsStaticStr_SoA%lastObsModelDischarge(:,whGageId) .gt. zero
2563 !if((-1*maxAgePairs) .ge. nTimesLastObs) then there's nothing to do.
2564 if((-1*maxAgePairsBiasPersist) .lt. nTimesLastObs) then
2566 do tt=nTimesLastObs,1,-1
2567 if(biasMask(tt)) pairCount = pairCount + 1
2568 if(pairCount .gt. (-1*maxAgePairsBiasPersist)) biasMask(tt) = .false.
2574 !!-----------------------------------
2575 !! minNumPairsBiasPersist
2576 !! If the pair count starts to dwindle during the forecast period, how does the transition
2577 !! happen from bias correction to open loop?
2578 !! Looks like it would get switched instantaneously. Avoid this problem with the
2579 !! negative maxAgePairsBiasPersist which always use the last maxAgePairsBiasPersist count
2580 !! of obs available. If there enough obs for bias correction at a site, this will ensure
2581 !! that there's no transition away from bias correction in the forecast. If there are not
2582 !! enough obs for bias correction, then observation persistence+decay will be applied as
2584 if(count(biasMask) .lt. minNumPairsBiasPersist) then
2585 persistBias_local = .false.
2586 !! JLM move this to hydro_d
2587 !print*,'JLM: Ndg: not enough observations for bias persistence, using obs persistence', &
2590 end if ! if(persistBias_local)
2592 !! Must check this for both cases obs and persistance nudging
2593 !! JLM: currently not also checking the quality. May be ok, but not ideal.
2594 if(obsStaticStr_SoA%lastObsTime(nTimesLastObs,whGageId) .eq. missingLastObsTime) return
2596 !! 3) are there parameters for this link? no -> return
2597 if(.not. any(nudgingParamsStr%usgsId .eq. prstGageId)) return
2600 print*,'Ndg: Persistence nudging execution'
2601 if(flushAll) flush(flushUnit)
2604 !! 4) what is the index of this link/gage in nudgingParamsStr?
2605 allocate(theMask(size(nudgingParamsStr%usgsId)))
2606 theMask = nudgingParamsStr%usgsId .eq. prstGageId
2607 whPrstParams = whUniLoop(theMask)
2610 !! --- Deal with the parameters ---
2611 !! 5) what month is the flow in [1,12]
2612 read(hydroTime(6:7),*) flowMonth
2614 !! 6) what thereshold is the flow?
2615 whThresh=1 !! init value
2616 do tt=1,size(nudgingParamsStr%qThresh,1)
2617 if(discharge(obsInd) .gt. nudgingParamsStr%qThresh(tt, flowMonth, whPrstParams)) &
2621 !!7) get the parameter of the exponential decay
2622 prstB=nudgingParamsStr%expCoeff(whThresh, flowMonth, whPrstParams)
2624 !! --- Deal with the last ob ---
2625 !! 9) what is the time difference with the last ob/obs?
2626 prstDtErrInt = -9999*60 ! JLM: magic value? set as a parameter above
2627 do tt=nTimesLastObs,1,-1
2628 ! Conditons for rejecting obs
2629 if(persistBias_local) then
2630 if(.not. biasMask(tt)) cycle
2632 if(obsStaticStr_SoA%lastObsQuality(tt,whGageId) .eq. 0) cycle
2634 call geth_idts(hydroTime, obsStaticStr_SoA%lastObsTime(tt,whGageId), prstDtErrInt)
2635 if(prstDtErrInt .lt. zeroInt) then
2636 print*,'initTime:', hydroTime
2637 print*,'obsStaticStr(whGageId)%lastObsTime(tt):', obsStaticStr_SoA%lastObsTime(tt,whGageId)
2638 print*,'prstDtErrInt:',prstDtErrInt
2639 print*,'Ndg: WARNING: lastObs times are in the future of the model time.'
2640 if(futureLastObsFatal) then
2641 call hydro_stop('nudge_term_link: negative prstDtErrInt: last obs in future')
2643 prstDtErrInt=abs(prstDtErrInt)
2648 ! By design, should not get here
2649 if(prstDtErrInt .eq. -9999*60) then
2650 persistBias_local=.false.
2651 call hydro_stop('nudge_term_link: negative prstDtErrInt: still default value=-9999*60')
2653 prstDtErr = real(prstDtErrInt)/real(sixty) !! second -> minutes
2655 !! 10) what is the error or bias ?
2657 !! Always calculate the observation nudge error.
2658 prstErr = obsStaticStr_SoA%lastObsDischarge(nTimesLastObs,whGageId) - discharge(obsInd)
2661 if(persistBias_local) then
2663 if(invDistTimeWeightBias) then
2665 if(count(biasMask .and. (biasWeights.gt.zero)) .lt. minNumPairsBiasPersist) then
2666 persistBias_local=.false.
2669 !! normalize to the latest (least) time difference and invert.
2670 biasWeights=1./(biasWeights/minval(biasWeights, &
2671 mask=biasMask .and. (biasWeights.gt.zero) ))
2672 biasWeights=biasWeights**invDistTimeWeightExp !! = 5.000, hard coded above
2674 !! The less than equal to one prevents division by huge/infinite
2675 !! numbers which may result from zero time differences.
2678 biasWeightSum=sum(biasWeights, mask=biasMask .and. (biasWeights.gt.zero) )
2680 !biasWeightSum=sum(biasWeights, mask=biasMask .and. &
2681 ! (biasWeights.gt.zero) .and. &
2682 ! (biasWeights.le.one) )
2684 theBias = sum( biasWeights * &
2685 (obsStaticStr_SoA%lastObsDischarge(:,whGageId) - &
2686 obsStaticStr_SoA%lastObsModelDischarge(:,whGageId)), &
2687 mask=biasMask .and. (biasWeights.gt.zero)) / &
2694 !! Simple, straight average / unweighted, way of calculating bias
2695 theBias = sum( obsStaticStr_SoA%lastObsDischarge(:,whGageId) - &
2696 obsStaticStr_SoA%lastObsModelDischarge(:,whGageId), mask=biasMask ) / &
2697 max( 1, count(biasMask) )
2701 if(noConstInterfBias) then
2702 !! Game to reduce bias issues.
2703 !! Maybe make this an option later if it works.
2704 !! do I need to stash the t0 flow? It is not the same as the last ob or the lastObsModelDischarge
2705 deltaT0Discharge = discharge(obsInd) - t0Discharge(linkIndIn)
2707 if(theBias .lt. zero .and. &
2708 deltaT0Discharge .lt. zero ) then
2710 if(t0Discharge(linkIndIn) .gt. .01) then
2712 !1!theBias=theBias - noConstInterfCoeff*(deltaT0Discharge) ! negative - negative
2713 !2!theBias=theBias*(1-(noConstInterfCoeff*abs(deltaT0Discharge)/t0Discharge(linkIndIn)))
2716 (1.0-(noConstInterfCoeff* &
2717 ( (abs(deltaT0Discharge)/t0Discharge(linkIndIn)+.25)**2.5 - .25**2.5) ) )
2719 !! if the toDischarge is really small, zero out the bias.
2722 theBias = min( theBias, zero ) ! do not let the bias go positive
2723 theBias = max( theBias, -1*discharge(obsInd)/2. ) ! do not let the bias to remove be more than half the total flow.
2728 if(theBias .gt. zero .and. &
2729 deltaT0Discharge .gt. zero ) then
2731 if(t0Discharge(linkIndIn) .gt. .01) then
2733 !1 !theBias = theBias - noConstInterfCoeff*(deltaT0Discharge) ! positive - positive
2734 !2!theBias=theBias*(1-(noConstInterfCoeff*abs(deltaT0Discharge)/t0Discharge(linkIndIn)))
2737 (1.0-(noConstInterfCoeff* &
2738 ( (abs(deltaT0Discharge)/t0Discharge(linkIndIn)+.25)**2.5 - .25**2.5) ) )
2740 !! if the toDischarge is really small, use a naminal t0Discharge of .01
2742 (1.0-(noConstInterfCoeff* &
2743 ( (abs(deltaT0Discharge)/.01+.25)**2.5 - .25**2.5) ) )
2745 theBias = max( theBias, zero ) ! do not let the bias go negative
2750 endif ! if (persistBias_local)
2754 if(.not. persistBias_local) then
2756 obsStaticStr_SoA%lastObsQuality(nTimesLastObs,whGageId) * &
2757 prstErr * exp(real(-1)*prstDtErr/prstB)
2760 obsStaticStr_SoA%lastObsQuality(nTimesLastObs,whGageId) * &
2761 prstErr * exp(real(-1)*prstDtErr/prstB) + &
2762 theBias * (1.0 - exp(real(-1)*prstDtErr/prstB) )
2764 endif !! if(.not. persistBias_local) then; else;
2766 !! Currently cant get here...
2767 if((prstDtErr .lt. zero) .and. futureLastObsZero) nudge_term_link = zero
2769 !! Ensure the nudge does not make the streamflow less than zero.
2770 !! This is particularly important if persistBias
2771 !! Is this OK as ZERO?? Musk-cunge allows it (in theory).
2772 if (discharge(obsInd)+nudge_term_link .lt. zero) then
2773 nudge_term_link = zero - discharge(obsInd) + smallestNudge
2774 !print*,'JLM setting nudge_term_link + observed discharge to zero (or very small)', prstGageId
2779 if(linkInd .eq. checkInd) then
2780 print*,'Ndg: checkInd pst: -------------------'
2781 print*,'Ndg: checkInd pst: usgsId: ', prstGageId
2782 print*,'Ndg: checkInd pst: -------------------'
2783 print*,'Ndg: checkInd pst: prstGageId: ', prstGageId
2784 print*,'Ndg: checkInd pst: obsInd: ', obsInd
2785 print*,'Ndg: checkInd pst: initTime:', initTime
2786 print*,'Ndg: checkInd pst: hydroTime: ', hydroTime
2787 print*,'Ndg: checkInd pst: flowmonth: ', flowMonth
2788 print*,'Ndg: checkInd pst: lastObsTime: ', obsStaticStr_SoA%lastObsTime(nTimesLastObs,whGageId)
2789 print*,'Ndg: checkInd pst: time difference mins: ', prstDtErr
2790 print*,'Ndg: checkInd pst: obsStaticStr(whGageId)%lastObsQuality: ', &
2791 obsStaticStr_SoA%lastObsQuality(nTimesLastObs,whGageId)
2792 print*,'Ndg: checkInd pst: obsStaticStr(whGageId)%lastObsDischarge: ', &
2793 obsStaticStr_SoA%lastObsDischarge(nTimesLastObs,whGageId)
2794 print*,'Ndg: checkInd pst: modeled discharge(obsInd): ', discharge(obsInd)
2795 print*,'Ndg: checkInd pst: qThresh: ', nudgingParamsStr%qThresh(:, flowMonth, whPrstParams)
2796 print*,'Ndg: checkInd pst: whThresh: ', whThresh
2797 print*,'Ndg: checkInd pst: discharge difference:', prstErr
2798 print*,'Ndg: checkInd pst: prstB:', prstB
2799 print*,'Ndg: checkInd pst: time difference mins prstDtErr: ', prstDtErr
2800 print*,'Ndg: checkInd pst: exponent term: ', exp(real(-1)*prstDtErr/prstB)
2802 if(persistBias_local) then
2803 print*,'Ndg: checkInd pst: BIAS PERSISTENCE INFO'
2804 do tt=1,nTimesLastObs
2805 if(biasMask(tt)) then
2806 print*,'checkInd: ---- tt:', tt
2807 print*,'checkInd: Diff: ', obsStaticStr_SoA%lastObsDischarge(tt,whGageId) - &
2808 obsStaticStr_SoA%lastObsModelDischarge(tt,whGageId)
2809 print*,'checkInd: o - : ', obsStaticStr_SoA%lastObsDischarge(tt,whGageId)
2810 print*,'checkInd: m: ', obsStaticStr_Soa%lastObsModelDischarge(tt,whGageId)
2811 print*,'checkInd: biasWeights: ', biasWeights(tt)
2814 print*,'Ndg: checkInd pst: max( 1, count(biasMask) ): ',max( 1, count(biasMask) )
2815 print*,'Ndg: checkInd pst: biasWeightSum: ', biasWeightSum
2816 print*,'Ndg: checkInd pst: corr: ', corr
2817 print*,'Ndg: checkInd pst: nCorr: ', nCorr
2818 print*,'Ndg: checkInd pst: theBias:', theBias
2819 print*,'Ndg: checkInd pst: theBias/corr:', theBias/corr
2820 print*,'Ndg: checkInd pst: obsStaticStr(whGageId)%lastObsQuality(nTimesLastObs) *'
2821 print*,'Ndg: checkInd pst: prstErr * exp(real(-1)*prstDtErr/prstB)', &
2822 obsStaticStr_SoA%lastObsQuality(nTimesLastObs,whGageId) * &
2823 prstErr * exp(real(-1)*prstDtErr/prstB)
2824 print*,'Ndg: checkInd pst: theBias * (1-exp(real(-1)*prstDtErr/prstB)):', &
2825 theBias * (1-exp(real(-1)*prstDtErr/prstB))
2828 print*,'Ndg: checkInd pst: nudge_term_link: ', nudge_term_link
2830 if(flushAll) flush(flushUnit)
2832 #endif /* HYDRO_D */
2833 endif !! if(abs(weighting) .gt. smallestWeight) then !! 1.e-10
2837 if(my_id .eq. io_id) &
2839 print*,'Ndg: finish nudge_term_link'
2840 if(flushAll) flush(flushUnit)
2844 end function nudge_term_link
2847 !===================================================================================================
2849 ! nudge_apply_upstream_muskingumCunge
2850 ! Author(s)/Contact(s):
2851 ! James L McCreight, <jamesmcc><ucar><edu>
2853 ! Gets the previous nudge into the collected upstream current and previous fluxes.
2855 ! 4/5/17 - Created, JLM
2861 ! User controllable options:
2864 subroutine nudge_apply_upstream_muskingumCunge( qup, quc, np, k )
2865 use module_RT_data, only: rt_domain
2867 real, intent(inout) :: qup ! previous upstream inflows
2868 real, intent(inout) :: quc ! current upstream inflows
2869 real, intent(in) :: np ! previous nudge
2870 integer, intent(in) :: k ! index of flow/routlink on local image
2872 !! If not on a gage... get out.
2873 if(rt_domain(1)%gages(k) .eq. rt_domain(1)%gageMiss) return
2878 end subroutine nudge_apply_upstream_muskingumCunge
2880 !===================================================================================================
2882 ! get_netwk_reexpression
2883 ! Author(s)/Contact(s):
2884 ! James L McCreight, <jamesmcc><ucar><edu>
2886 ! Bring in the network re-expression for indexed traversal
2887 ! of the stream network.
2889 ! 8/20/15 - Created, JLM
2895 ! User controllable options:
2896 ! Notes: Sets module derived type strs: upNetwkStr and downNetwkStr
2897 subroutine get_netwk_reexpression
2898 use module_RT_data, only: rt_domain
2899 use module_nudging_io,only: read_network_reexpression, get_netcdf_dim
2902 integer :: downSize, upSize, baseSize, nLinksL
2905 nLinksL = RT_DOMAIN(did)%gNLINKSL ! For reach-based routing in parallel, no decomp for nudging
2907 nLinksL = RT_DOMAIN(did)%NLINKSL ! For reach-based routing
2911 if(my_id .eq. IO_id) then
2913 downSize = get_netcdf_dim(netwkReExFile, 'downDim', 'init_stream_nudging')
2914 upSize = get_netcdf_dim(netwkReExFile, 'upDim', 'init_stream_nudging')
2915 baseSize = get_netcdf_dim(netwkReExFile, 'baseDim', 'init_stream_nudging')
2916 !if(baseSize .ne. nLinksL) call hydro_stop('init_stream_nudging: baseSize .ne. nLinksL')
2918 allocate(upNetwkStr%go(upSize))
2919 allocate(upNetwkStr%start(nLinksL))
2920 allocate(upNetwkStr%end(nLinksL))
2921 allocate(downNetwkStr%go(downSize))
2922 allocate(downNetwkStr%start(nLinksL))
2923 allocate(downNetwkStr%end(nLinksL))
2925 call read_network_reexpression( &
2926 netwkReExFile, & ! file with dims of the stream netwk
2927 upNetwkStr%go, & ! where each ind came from, upstream
2928 upNetwkStr%start, & ! where each ind's upstream links start in upGo
2929 upNetwkStr%end, & ! where each ind's upstream links end in upGo
2930 downNetwkStr%go, & ! where each ind goes, downstream
2931 downNetwkStr%start, & ! where each ind's downstream links start in downGo
2932 downNetwkStr%end ) ! where each ind's downstream links end in downGo
2935 endif ! my_id .eq. io_id
2938 call mpp_land_bcast_int1(upSize)
2939 call mpp_land_bcast_int1(downSize)
2940 if(my_id .ne. io_id) then
2941 allocate(upNetwkStr%go(upSize))
2942 allocate(upNetwkStr%start(nLinksL))
2943 allocate(upNetwkStr%end(nLinksL))
2944 allocate(downNetwkStr%go(downSize))
2945 allocate(downNetwkStr%start(nLinksL))
2946 allocate(downNetwkStr%end(nLinksL))
2948 call mpp_land_bcast_int1d(upNetwkStr%go)
2949 call mpp_land_bcast_int1d(upNetwkStr%start)
2950 call mpp_land_bcast_int1d(upNetwkStr%end)
2951 call mpp_land_bcast_int1d(downNetwkStr%go)
2952 call mpp_land_bcast_int1d(downNetwkStr%start)
2953 call mpp_land_bcast_int1d(downNetwkStr%end)
2955 end subroutine get_netwk_reexpression
2958 !===================================================================================================
2960 ! finish_stream_nudging
2961 ! Author(s)/Contact(s):
2962 ! James L McCreight, <jamesmcc><ucar><edu>
2964 ! Finish off the nudging routines, memory and timing.
2966 ! 8/20/15 - Created, JLM
2972 ! User controllable options:
2975 subroutine finish_stream_nudging
2976 use module_nudging_utils, only: totalNudgeTime, &
2978 accum_nudging_time, &
2980 use module_nudging_io, only: write_nwis_not_in_RLAndParams
2983 character(len=15), allocatable, dimension(:) :: nwisNotRLAndParamsGathered
2984 character(len=15), allocatable, dimension(:) :: nwisNotRLAndParamsConsolidated
2985 integer, dimension(numprocs) :: nwisNotRLAndParamsCountVector
2986 integer :: nwisNotRLAndParamsCountConsolidated, gg, ii
2988 #ifdef HYDRO_D /* un-ifdef to get timing results */
2989 !!$real :: startCodeTimeAcc, endCodeTimeAcc
2991 if(my_id .eq. io_id) &
2993 print*,'Ndg: start finish_stream_nudging'
2994 if(flushAll) flush(flushUnit)
2996 !!$if(my_id .eq. io_id) &
2998 !!$ call nudging_timer(startCodeTimeAcc)
2999 #endif /* HYDRO_D un-ifdef to get timing results */
3001 !! accumulate_nwis_not_in_RLAndParams
3002 !! because of parallel IO, accumulation is happening on
3003 !! multiple images and these need to be consolidated before outputting.
3004 ! get the total of nwisNotRLAndParam gages on all images
3005 nwisNotRLAndParamsCountVector(my_id+1) = nwisNotRLAndParamsCount
3007 call mpp_land_bcast_int1_root(nwisNotRLAndParamsCountVector(ii+1), ii)
3010 allocate(nwisNotRLAndParamsGathered(sum(nwisNotRLAndParamsCountVector)))
3013 if(my_id .eq. io_id) &
3015 allocate(nwisNotRLAndParamsConsolidated(sum(nwisNotRLAndParamsCountVector)))
3017 call write_IO_char_head(nwisNotRLAndParams, nwisNotRLAndParamsGathered, nwisNotRLAndParamsCountVector)
3019 if(my_id .eq. io_id) then
3020 ! now consolidate these again...
3021 nwisNotRLAndParamsCountConsolidated=0
3022 do gg=1,size(nwisNotRLAndParamsGathered)
3023 call accumulate_nwis_not_in_RLAndParams(nwisNotRLAndParamsConsolidated, &
3024 nwisNotRLAndParamsCountConsolidated, &
3025 nwisNotRLAndParamsGathered(gg) )
3027 if(nwisNotRLAndParamsCountConsolidated .gt. 0) &
3028 call write_nwis_not_in_RLAndParams(nwisNotRLAndParamsConsolidated, &
3029 nwisNotRLAndParamsCountConsolidated )
3032 !! deallocate local variables
3033 if(allocated(nwisNotRLAndParamsGathered)) deallocate(nwisNotRLAndParamsGathered)
3034 if(allocated(nwisNotRLAndParamsConsolidated)) deallocate(nwisNotRLAndParamsConsolidated)
3036 !! deallocate module variables here and time this
3037 if(allocated(obsTimeStr)) deallocate(obsTimeStr)
3038 if(allocated(obsStaticStr)) deallocate(obsStaticStr)
3039 !if(allocated(nodeGageTmp%nodeId)) deallocate(nodeGageTmp%nodeId)
3040 if(allocated(nodeGageTmp%usgsId)) deallocate(nodeGageTmp%usgsId) !redundant
3041 if(allocated(nodeGageStr%nodeId)) deallocate(nodeGageStr%nodeId)
3042 if(allocated(nodeGageStr%usgsId)) deallocate(nodeGageStr%usgsId)
3043 if(allocated(nudgingParamsTmp%usgsId)) deallocate(nudgingParamsTmp%usgsId) !redundant
3044 if(allocated(nudgingParamsTmp%R)) deallocate(nudgingParamsTmp%R) !redundant
3045 if(allocated(nudgingParamsTmp%G)) deallocate(nudgingParamsTmp%G) !redundant
3046 if(allocated(nudgingParamsTmp%tau)) deallocate(nudgingParamsTmp%tau) !redundant
3047 if(allocated(nudgingParamsStr%usgsId)) deallocate(nudgingParamsStr%usgsId)
3048 if(allocated(nudgingParamsStr%R)) deallocate(nudgingParamsStr%R)
3049 if(allocated(nudgingParamsStr%G)) deallocate(nudgingParamsStr%G)
3050 if(allocated(nudgingParamsStr%tau)) deallocate(nudgingParamsStr%tau)
3051 if(allocated(nudgingParamsStr%qThresh)) deallocate(nudgingParamsStr%qThresh)
3052 if(allocated(nudgingParamsStr%expCoeff)) deallocate(nudgingParamsStr%expCoeff)
3053 if(allocated(upNetwkStr%go)) deallocate(upNetwkStr%go)
3054 if(allocated(upNetwkStr%start)) deallocate(upNetwkStr%start)
3055 if(allocated(upNetwkStr%end)) deallocate(upNetwkStr%end)
3056 if(allocated(downNetwkStr%go)) deallocate(downNetwkStr%go)
3057 if(allocated(downNetwkStr%start)) deallocate(downNetwkStr%start)
3058 if(allocated(downNetwkStr%end)) deallocate(downNetwkStr%end)
3059 if(allocated(chanlen_image0)) deallocate(chanlen_image0)
3061 !! print ouf the full timing results here.
3062 !! dont i need to make another accumultion call here?
3065 if(my_id .eq. io_id) then
3067 !!$ call nudging_timer(endCodeTimeAcc)
3068 !!$ call accum_nudging_time(startCodeTimeAcc, endCodeTimeAcc, 'very end of nudging', .true.)
3069 !!$ print*,'Ndg: *nudge timing* TOTAL NUDGING TIME (seconds): ', totalNudgeTime
3070 print*,'Ndg: end of finish_stream_nudging'
3071 if(flushAll) flush(flushUnit)
3075 #endif /* HYDRO_D */
3077 end subroutine finish_stream_nudging
3081 end module module_stream_nudging