MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
gwf-sfr.f90
Go to the documentation of this file.
1 !> @brief This module contains the SFR package methods
2 !!
3 !! This module contains the overridden methods for the streamflow routing (SFR)
4 !! package. Most of the methods in the base Boundary Package are overridden.
5 !!
6 !<
7 module sfrmodule
8  !
9  use kindmodule, only: dp, i4b, lgp
11  maxadpit, &
12  dzero, dprec, dem30, dem6, dem5, dem4, dem2, &
14  dp9, dp99, dp999, &
16  dhundred, dep20, &
19  lenbudtxt, &
20  dhnoflo, dhdry, dnodata, &
22  mnormal
28  use bndmodule, only: bndtype
29  use bndextmodule, only: bndexttype
31 
33  use tablemodule, only: tabletype, table_cr
34  use observemodule, only: observetype
36  use basedismodule, only: disbasetype
37  use simmodule, only: count_errors, store_error, &
45  use dag_module, only: dag
47  !
48  implicit none
49  !
50  character(len=LENFTYPE) :: ftype = 'SFR' !< package ftype string
51  character(len=LENPACKAGENAME) :: text = ' SFR' !< package budget string
52  !
53  private
54  public :: sfr_create
55  public :: sfrtype
56 
57  !> @brief Input context array pointers for SFR.
58  !!
59  !! PACKAGEDATA pointers are set in sfr_source_packagedata; PERIOD
60  !! pointers are set once in sfr_ar.
61  !<
62  type :: sfrinputtype
63  ! -- packagedata (TS-linked; set in sfr_source_packagedata)
64  real(dp), dimension(:), pointer, contiguous :: rhk => null()
65  real(dp), dimension(:), pointer, contiguous :: man => null()
66  real(dp), dimension(:), pointer, contiguous :: ustrf => null()
67  integer(I4B), dimension(:), pointer :: rhk_tslink => null() !< nonzero for RHK rows linked to a time series
68  integer(I4B), dimension(:), pointer :: man_tslink => null() !< nonzero for MAN rows linked to a time series
69  integer(I4B), dimension(:), pointer :: ustrf_tslink => null() !< nonzero for USTRF rows linked to a time series
70  ! -- period
71  integer(I4B), pointer :: nbound => null()
72  integer(I4B), dimension(:), pointer, contiguous :: ifno => null()
73  type(characterstringtype), dimension(:), pointer, &
74  contiguous :: status => null()
75  type(characterstringtype), dimension(:), pointer, &
76  contiguous :: setting => null()
77  integer(I4B), dimension(:), pointer, contiguous :: idv => null()
78  type(characterstringtype), dimension(:), pointer, &
79  contiguous :: tab6_filename => null()
80  type(characterstringtype), dimension(:), pointer, &
81  contiguous :: auxname => null()
82  real(dp), dimension(:), pointer, contiguous :: auxval => null()
83  contains
84  procedure :: init => sfr_input_init
85  procedure :: destroy => sfr_input_destroy
86  end type sfrinputtype
87 
88  type, extends(bndexttype) :: sfrtype
89  ! -- scalars
90  ! -- for budgets
91  ! -- characters
92  character(len=16), dimension(:), pointer, contiguous :: csfrbudget => null() !< advanced package budget names
93  character(len=16), dimension(:), pointer, contiguous :: cauxcbc => null() !< aux names
94  character(len=LENBOUNDNAME), dimension(:), pointer, &
95  contiguous :: sfrname => null() !< internal SFR reach name
96  ! -- integers
97  integer(I4B), pointer :: istorage => null() !< flag for using kinematic wave approximation
98  integer(I4B), pointer :: iprhed => null() !< flag for printing stages to listing file
99  integer(I4B), pointer :: istageout => null() !< flag and unit number for binary stage output
100  integer(I4B), pointer :: ibudgetout => null() !< flag and unit number for binary sfr budget output
101  integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file
102  integer(I4B), pointer :: ipakcsv => null() !< flag and unit number for package convergence information
103  integer(I4B), pointer :: idiversions => null() !< flag indicating if there are any diversions
104  integer(I4B), pointer :: nconn => null() !< number of reach connections
105  integer(I4B), pointer :: maxsfrpicard => null() !< maximum number of Picard iteration calls to SFR solve
106  integer(I4B), pointer :: maxsfrit => null() !< maximum number of iterations in SFR solve
107  integer(I4B), pointer :: bditems => null() !< number of SFR budget items
108  integer(I4B), pointer :: cbcauxitems => null() !< number of aux items in cell-by-cell budget file
109  integer(I4B), pointer :: icheck => null() !< flag indicating if input should be checked (default is yes)
110  integer(I4B), pointer :: iconvchk => null() !< flag indicating of final convergence run is executed
111  integer(I4B), pointer :: gwfiss => null() !< groundwater model steady-state flag
112  integer(I4B), pointer :: ianynone => null() !< number of reaches with 'none' connection
113  ! -- double precision
114  real(dp), pointer :: unitconv => null() !< unit conversion factor (SI to model units)
115  real(dp), pointer :: lengthconv => null() !< length conversion factor (SI to model units)
116  real(dp), pointer :: timeconv => null() !< time conversion factor (SI to model units)
117  real(dp), pointer :: dmaxchg => null() !< maximum depth change allowed
118  real(dp), pointer :: deps => null() !< perturbation value
119  real(dp), pointer :: storage_weight => null() !< time weighting factor for kinematic wave approximation
120  ! -- integer vectors
121  integer(I4B), dimension(:), pointer, contiguous :: isfrorder => null() !< sfr reach order determined from DAG of upstream reaches
122  integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< CRS row pointer for SFR reaches
123  integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< CRS column pointers for SFR reach connections
124  ! -- double precision output vectors
125  real(dp), dimension(:), pointer, contiguous :: qoutflow => null() !< reach downstream flow
126  real(dp), dimension(:), pointer, contiguous :: qextoutflow => null() !< reach discharge to external boundary
127  real(dp), dimension(:), pointer, contiguous :: qauxcbc => null() !< aux value
128  real(dp), dimension(:), pointer, contiguous :: dbuff => null() !< temporary vector
129  !
130  ! -- sfr budget object
131  type(budgetobjecttype), pointer :: budobj => null() !< SFR budget object
132  !
133  ! -- sfr table objects
134  type(tabletype), pointer :: stagetab => null() !< reach stage table written to the listing file
135  type(tabletype), pointer :: couranttab => null() !< Courant number table written to the listing file
136  type(tabletype), pointer :: pakcsvtab => null() !< SFR package convergence table
137  !
138  ! -- sfr reach data
139  integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !< ibound array for SFR reaches that defines active, inactive, and constant reaches
140  integer(I4B), dimension(:), pointer, contiguous :: igwfnode => null() !< groundwater node connected to SFR reaches
141  integer(I4B), dimension(:), pointer, contiguous :: igwftopnode => null() !< highest active groundwater node under SFR reaches
142  real(dp), dimension(:), pointer, contiguous :: length => null() !< reach length
143  real(dp), dimension(:), pointer, contiguous :: width => null() !< reach width
144  real(dp), dimension(:), pointer, contiguous :: strtop => null() !< reach bed top elevation
145  real(dp), dimension(:), pointer, contiguous :: bthick => null() !< reach bed thickness
146  real(dp), dimension(:), pointer, contiguous :: hk => null() !< vertical hydraulic conductivity of reach bed sediments
147  real(dp), dimension(:), pointer, contiguous :: slope => null() !< reach slope
148  integer(I4B), dimension(:), pointer, contiguous :: nconnreach => null() !< number of connections for each reach
149  real(dp), dimension(:), pointer, contiguous :: ustrf => null() !< upstream flow fraction for upstream connections
150  logical(LGP), dimension(:), pointer, contiguous :: bedk_set => null() !< reach has an active PERIOD BEDK override
151  logical(LGP), dimension(:), pointer, contiguous :: manning_set => null() !< reach has an active PERIOD MANNING override
152  logical(LGP), dimension(:), pointer, contiguous :: ustrf_set => null() !< reach has an active PERIOD UPSTREAM_FRACTION override
153  real(dp), dimension(:), pointer, contiguous :: ftotnd => null() !< total fraction of connected reaches that are not diversions
154  integer(I4B), dimension(:), pointer, contiguous :: ndiv => null() !< number of diversions for each reach
155  real(dp), dimension(:), pointer, contiguous :: usflow => null() !< upstream reach flow
156  real(dp), dimension(:), pointer, contiguous :: dsflow => null() !< downstream reach flow
157  real(dp), dimension(:), pointer, contiguous :: dsflowold => null() !< downstream reach flow for previous time step
158  real(dp), dimension(:), pointer, contiguous :: usinflow => null() !< upstream reach flow for previous time step
159  real(dp), dimension(:), pointer, contiguous :: usinflowold => null() !< upstream reach flow for previous time step
160  real(dp), pointer :: ats_courant => null() !< target Courant number for ATS time step submission
161  integer(I4B), dimension(:), pointer, contiguous :: itvd_upstream => null() !< upstream reach index for TVD limiter (0 = headwater or confluence)
162  real(dp), dimension(:), pointer, contiguous :: crmin => null() !< simulation-wide minimum Courant number per reach
163  real(dp), dimension(:), pointer, contiguous :: crmax => null() !< simulation-wide maximum Courant number per reach
164  real(dp), dimension(:), pointer, contiguous :: crsum => null() !< simulation-wide sum of Courant numbers per reach
165  integer(I4B), dimension(:), pointer, contiguous :: crcnt => null() !< simulation-wide count of non-zero Courant evaluations per reach
166  real(dp), dimension(:), pointer, contiguous :: depth => null() !< reach depth
167  real(dp), dimension(:), pointer, contiguous :: stage => null() !< reach stage
168  real(dp), dimension(:), pointer, contiguous :: stageold => null() !< reach stage for last timestep
169  real(dp), dimension(:), pointer, contiguous :: gwflow => null() !< flow from groundwater to reach
170  real(dp), dimension(:), pointer, contiguous :: simevap => null() !< simulated reach evaporation
171  real(dp), dimension(:), pointer, contiguous :: simrunoff => null() !< simulated reach runoff
172  real(dp), dimension(:), pointer, contiguous :: stage0 => null() !< previous reach stage iterate
173  real(dp), dimension(:), pointer, contiguous :: usflow0 => null() !< previous upstream reach flow iterate
174  real(dp), dimension(:), pointer, contiguous :: storage => null() !< previous upstream reach flow iterate
175  ! -- cross-section data
176  integer(I4B), pointer :: ncrossptstot => null() !< total number of cross-section points
177  integer(I4B), dimension(:), pointer, contiguous :: ncrosspts => null() !< number of cross-section points for each reach
178  integer(I4B), dimension(:), pointer, contiguous :: iacross => null() !< pointers to cross-section data for each reach
179  real(dp), dimension(:), pointer, contiguous :: station => null() !< cross-section station (x-position) data
180  real(dp), dimension(:), pointer, contiguous :: xsheight => null() !< cross-section height data
181  real(dp), dimension(:), pointer, contiguous :: xsrough => null() !< cross-section roughness data
182  ! -- connection data
183  integer(I4B), dimension(:), pointer, contiguous :: idir => null() !< reach connection direction
184  integer(I4B), dimension(:), pointer, contiguous :: idiv => null() !< reach connection diversion number
185  real(dp), dimension(:), pointer, contiguous :: qconn => null() !< reach connection flow
186  ! -- boundary data
187  real(dp), dimension(:), pointer, contiguous :: rough => null() !< reach Manning's roughness coefficient (SI units)
188  real(dp), dimension(:), pointer, contiguous :: rain => null() !< reach rainfall
189  real(dp), dimension(:), pointer, contiguous :: evap => null() !< reach potential evaporation
190  real(dp), dimension(:), pointer, contiguous :: inflow => null() !< reach upstream inflow
191  real(dp), dimension(:), pointer, contiguous :: runoff => null() !< reach maximum runoff
192  real(dp), dimension(:), pointer, contiguous :: sstage => null() !< reach specified stage
193  ! -- diversion data
194  integer(I4B), dimension(:), pointer, contiguous :: iadiv => null() !< row pointer for reach diversions
195  integer(I4B), dimension(:), pointer, contiguous :: divreach => null() !< diversion reach
196  character(len=10), dimension(:), pointer, contiguous :: divcprior => null() !< diversion rule
197  real(dp), dimension(:), pointer, contiguous :: divflow => null() !< specified diversion flow value
198  real(dp), dimension(:), pointer, contiguous :: divq => null() !< simulated diversion flow
199  !
200  ! -- density variables
201  integer(I4B), pointer :: idense !< flag indicating if density corrections are active
202  real(dp), dimension(:, :), pointer, contiguous :: denseterms => null() !< density terms
203  !
204  ! -- viscosity variables
205  real(dp), dimension(:, :), pointer, contiguous :: viscratios => null() !< viscosity ratios (1: sfr vsc ratio; 2: gwf vsc ratio)
206  !
207  ! -- input context data pointers (PACKAGEDATA + PERIOD arrays)
208  type(sfrinputtype) :: input
209  !
210  ! -- type bound procedures
211  contains
212  procedure :: sfr_allocate_scalars
213  procedure :: sfr_allocate_arrays
215  procedure :: source_options => sfr_source_options
216  procedure :: source_dimensions => sfr_source_dimensions
217 
218  ! procedure :: set_pointers => sfr_set_pointers
219  procedure :: bnd_ar => sfr_ar
220  procedure :: bnd_rp => sfr_rp
221  procedure :: bnd_ad => sfr_ad
222  procedure :: bnd_cf => sfr_cf
223  procedure :: bnd_fc => sfr_fc
224  procedure :: bnd_fn => sfr_fn
225  procedure :: bnd_cc => sfr_cc
226  procedure :: bnd_cq => sfr_cq
227  procedure :: bnd_ot_package_flows => sfr_ot_package_flows
228  procedure :: bnd_ot_dv => sfr_ot_dv
229  procedure :: bnd_ot_bdsummary => sfr_ot_bdsummary
230  procedure :: bnd_dt => sfr_dt
231  procedure :: bnd_fp => sfr_fp
232  procedure :: bnd_da => sfr_da
233  procedure :: define_listlabel
234  ! -- methods for observations
235  procedure, public :: bnd_obs_supported => sfr_obs_supported
236  procedure, public :: bnd_df_obs => sfr_df_obs
237  procedure, public :: bnd_rp_obs => sfr_rp_obs
238  procedure, public :: bnd_bd_obs => sfr_bd_obs
239  ! -- private procedures
240 
241  procedure, private :: sfr_solve
242  procedure, private :: sfr_calc_constant
243  procedure, private :: sfr_calc_transient
244  procedure, private :: sfr_calc_tvd
245  procedure, private :: sfr_calc_celerity
246  procedure, private :: sfr_calc_steady
247  procedure, private :: sfr_precompute_tvd
248  procedure, private :: sfr_update_flows
249  procedure, private :: sfr_adjust_ro_ev
250  procedure, private :: sfr_calc_qgwf
251  procedure, private :: sfr_gwf_conn
252  procedure, private :: sfr_calc_cond
253  procedure, private :: sfr_calc_qman
254  procedure, private :: sfr_calc_qd
255  procedure, private :: sfr_calc_qsource
256  procedure, private :: sfr_calc_div
257  ! -- geometry
258  procedure, private :: calc_area_wet
259  procedure, private :: calc_perimeter_wet
260  procedure, private :: calc_surface_area
261  procedure, private :: calc_surface_area_wet
262  procedure, private :: calc_top_width_wet
263  ! -- input context sourcing
264  procedure, private :: sfr_source_packagedata
265  procedure, private :: sfr_source_crosssections
266  procedure, private :: sfr_source_connectiondata
267  procedure, private :: sfr_source_diversions
268  procedure, private :: sfr_source_initialstages
269  ! -- calculations
270  procedure, private :: sfr_calc_reach_depth
271  procedure, private :: sfr_calc_xs_depth
272  ! -- error checking
273  procedure, private :: sfr_check_conversion
274  procedure, private :: sfr_check_storage_weight
275  procedure, private :: sfr_check_reaches
276  procedure, private :: sfr_check_connections
277  procedure, private :: sfr_check_diversions
278  procedure, private :: sfr_check_initialstages
279  procedure, private :: sfr_check_ustrf
280  procedure, private :: sfr_set_period_value
281  ! -- budget
282  procedure, private :: sfr_setup_budobj
283  procedure, private :: sfr_fill_budobj
284  ! -- table
285  procedure, private :: sfr_setup_tableobj
286  ! -- density
287  procedure :: sfr_activate_density
288  procedure, private :: sfr_calculate_density_exchange
289  ! -- viscosity
291  end type sfrtype
292 
293  interface
294  module subroutine sfr_calc_steady(this, n, d1, hgwf, &
295  qu, qi, qfrommvr, qr, qe, qro, &
296  qgwf, qd)
297  class(sfrtype) :: this !< SfrType object
298  integer(I4B), intent(in) :: n !< reach number
299  real(dp), intent(inout) :: d1 !< current reach depth estimate
300  real(dp), intent(in) :: hgwf !< head in gw cell
301  real(dp), intent(in) :: qu !< reach upstream flow
302  real(dp), intent(in) :: qi !< reach specified inflow
303  real(dp), intent(in) :: qfrommvr !< reach flow from mover
304  real(dp), intent(in) :: qr !< reach rainfall
305  real(dp), intent(in) :: qe !< reach evaporation
306  real(dp), intent(in) :: qro !< reach runoff flow
307  real(dp), intent(inout) :: qgwf !< reach-aquifer exchange
308  real(dp), intent(inout) :: qd !< reach outflow
309  end subroutine
310  end interface
311 
312  interface
313  module subroutine sfr_calc_transient(this, n, d1, hgwf, &
314  qu, qi, qfrommvr, qr, qe, qro, &
315  qgwf, qd)
316  class(sfrtype) :: this !< SfrType object
317  integer(I4B), intent(in) :: n !< reach number
318  real(dp), intent(inout) :: d1 !< current reach depth estimate
319  real(dp), intent(in) :: hgwf !< head in gw cell
320  real(dp), intent(in) :: qu !< reach upstream flow
321  real(dp), intent(in) :: qi !< reach specified inflow
322  real(dp), intent(in) :: qfrommvr !< reach flow from mover
323  real(dp), intent(in) :: qr !< reach rainfall
324  real(dp), intent(in) :: qe !< reach evaporation
325  real(dp), intent(in) :: qro !< reach runoff flow
326  real(dp), intent(inout) :: qgwf !< reach-aquifer exchange
327  real(dp), intent(inout) :: qd !< reach outflow
328  end subroutine
329  end interface
330 
331  interface
332  module subroutine sfr_calc_tvd(this, n, d1, hgwf, &
333  qu, qi, qfrommvr, qr, qe, qro, &
334  qgwf, qd)
335  class(sfrtype) :: this !< SfrType object
336  integer(I4B), intent(in) :: n !< reach number
337  real(dp), intent(inout) :: d1 !< current reach depth estimate
338  real(dp), intent(in) :: hgwf !< head in gw cell
339  real(dp), intent(in) :: qu !< reach upstream flow
340  real(dp), intent(in) :: qi !< reach specified inflow
341  real(dp), intent(in) :: qfrommvr !< reach flow from mover
342  real(dp), intent(in) :: qr !< reach rainfall
343  real(dp), intent(in) :: qe !< reach evaporation
344  real(dp), intent(in) :: qro !< reach runoff flow
345  real(dp), intent(inout) :: qgwf !< reach-aquifer exchange
346  real(dp), intent(inout) :: qd !< reach outflow
347  end subroutine
348  end interface
349 
350  interface
351  module subroutine sfr_calc_constant(this, n, d1, hgwf, qgwf, qd)
352  class(sfrtype) :: this !< SfrType object
353  integer(I4B), intent(in) :: n !< reach number
354  real(dp), intent(inout) :: d1 !< current reach depth estimate
355  real(dp), intent(in) :: hgwf !< head in gw cell
356  real(dp), intent(inout) :: qgwf !< reach-aquifer exchange
357  real(dp), intent(inout) :: qd !< reach outflow
358  end subroutine
359  end interface
360 
361 contains
362 
363  !> @ brief Create a new package object
364  !!
365  !! Create a new SFR Package object
366  !<
367  subroutine sfr_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, &
368  mempath)
369  ! -- modules
371  ! -- dummy
372  class(bndtype), pointer :: packobj !< pointer to default package type
373  integer(I4B), intent(in) :: id !< package id
374  integer(I4B), intent(in) :: ibcnum !< boundary condition number
375  integer(I4B), intent(in) :: inunit !< unit number of SFR package input file
376  integer(I4B), intent(in) :: iout !< unit number of model listing file
377  character(len=*), intent(in) :: namemodel !< model name
378  character(len=*), intent(in) :: pakname !< package name
379  character(len=*), intent(in) :: mempath !< input mempath
380  ! -- local
381  type(sfrtype), pointer :: sfrobj
382  !
383  ! -- allocate the object and assign values to object variables
384  allocate (sfrobj)
385  packobj => sfrobj
386  !
387  ! -- create name and memory path
388  call packobj%set_names(ibcnum, namemodel, pakname, ftype, mempath)
389  packobj%text = text
390  !
391  ! -- allocate scalars
392  call sfrobj%sfr_allocate_scalars()
393  !
394  ! -- initialize package
395  call packobj%pack_initialize()
396 
397  packobj%inunit = inunit
398  packobj%iout = iout
399  packobj%id = id
400  packobj%ibcnum = ibcnum
401  packobj%ncolbnd = 4
402  packobj%iscloc = 0 ! not supported
403  packobj%isadvpak = 1
404  packobj%ictMemPath = create_mem_path(namemodel, 'NPF')
405  end subroutine sfr_create
406 
407  !> @ brief Allocate scalars
408  !!
409  !! Allocate and initialize scalars for the SFR package. The base model
410  !! allocate scalars method is also called.
411  !<
412  subroutine sfr_allocate_scalars(this)
413  ! -- modules
416  ! -- dummy
417  class(sfrtype), intent(inout) :: this !< SfrType object
418  !
419  ! -- call standard BndExtType allocate scalars
420  call this%BndExtType%allocate_scalars()
421  !
422  ! -- allocate the object and assign values to object variables
423  call mem_allocate(this%istorage, 'ISTORAGE', this%memoryPath)
424  call mem_allocate(this%iprhed, 'IPRHED', this%memoryPath)
425  call mem_allocate(this%istageout, 'ISTAGEOUT', this%memoryPath)
426  call mem_allocate(this%ibudgetout, 'IBUDGETOUT', this%memoryPath)
427  call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath)
428  call mem_allocate(this%ipakcsv, 'IPAKCSV', this%memoryPath)
429  call mem_allocate(this%idiversions, 'IDIVERSIONS', this%memoryPath)
430  call mem_allocate(this%maxsfrpicard, 'MAXSFRPICARD', this%memoryPath)
431  call mem_allocate(this%maxsfrit, 'MAXSFRIT', this%memoryPath)
432  call mem_allocate(this%bditems, 'BDITEMS', this%memoryPath)
433  call mem_allocate(this%cbcauxitems, 'CBCAUXITEMS', this%memoryPath)
434  call mem_allocate(this%unitconv, 'UNITCONV', this%memoryPath)
435  call mem_allocate(this%lengthconv, 'LENGTHCONV', this%memoryPath)
436  call mem_allocate(this%timeconv, 'TIMECONV', this%memoryPath)
437  call mem_allocate(this%dmaxchg, 'DMAXCHG', this%memoryPath)
438  call mem_allocate(this%deps, 'DEPS', this%memoryPath)
439  call mem_allocate(this%storage_weight, 'STORAGE_WEIGHT', this%memoryPath)
440  call mem_allocate(this%ats_courant, 'ATS_COURANT', this%memoryPath)
441  call mem_allocate(this%nconn, 'NCONN', this%memoryPath)
442  call mem_allocate(this%icheck, 'ICHECK', this%memoryPath)
443  call mem_allocate(this%iconvchk, 'ICONVCHK', this%memoryPath)
444  call mem_allocate(this%idense, 'IDENSE', this%memoryPath)
445  call mem_allocate(this%ianynone, 'IANYNONE', this%memoryPath)
446  call mem_allocate(this%ncrossptstot, 'NCROSSPTSTOT', this%memoryPath)
447  !
448  ! -- set pointer to gwf iss
449  call mem_setptr(this%gwfiss, 'ISS', create_mem_path(this%name_model))
450  !
451  ! -- Set values
452  this%istorage = 0
453  this%iprhed = 0
454  this%istageout = 0
455  this%ibudgetout = 0
456  this%ibudcsv = 0
457  this%ipakcsv = 0
458  this%idiversions = 0
459  this%maxsfrpicard = 100
460  this%maxsfrit = maxadpit
461  this%bditems = 8
462  this%cbcauxitems = 1
463  this%unitconv = done
464  this%lengthconv = dnodata
465  this%timeconv = dnodata
466  this%dmaxchg = dem5
467  this%deps = dp999 * this%dmaxchg
468  this%storage_weight = dnodata
469  this%ats_courant = dnodata
470  this%nconn = 0
471  this%icheck = 1
472  this%iconvchk = 1
473  this%idense = 0
474  this%ivsc = 0
475  this%ianynone = 0
476  this%ncrossptstot = 0
477  end subroutine sfr_allocate_scalars
478 
479  !> @ brief Allocate arrays
480  !!
481  !! Allocate and initialize array for the SFR package.
482  !<
483  subroutine sfr_allocate_arrays(this)
484  ! -- modules
486  ! -- dummy
487  class(sfrtype), intent(inout) :: this !< SfrType object
488  ! -- local
489  integer(I4B) :: i
490  !
491  ! -- allocate character array for budget text
492  allocate (this%csfrbudget(this%bditems))
493  call mem_allocate(this%sfrname, lenboundname, this%maxbound, &
494  'SFRNAME', this%memoryPath)
495  !
496  ! -- variables originally in SfrDataType
497  call mem_allocate(this%iboundpak, this%maxbound, 'IBOUNDPAK', &
498  this%memoryPath)
499  call mem_allocate(this%igwfnode, this%maxbound, 'IGWFNODE', this%memoryPath)
500  call mem_allocate(this%igwftopnode, this%maxbound, 'IGWFTOPNODE', &
501  this%memoryPath)
502  call mem_allocate(this%length, this%maxbound, 'LENGTH', this%memoryPath)
503  call mem_allocate(this%width, this%maxbound, 'WIDTH', this%memoryPath)
504  call mem_allocate(this%strtop, this%maxbound, 'STRTOP', this%memoryPath)
505  call mem_allocate(this%bthick, this%maxbound, 'BTHICK', this%memoryPath)
506  call mem_allocate(this%slope, this%maxbound, 'SLOPE', this%memoryPath)
507  call mem_allocate(this%nconnreach, this%maxbound, 'NCONNREACH', &
508  this%memoryPath)
509  call mem_allocate(this%bedk_set, this%maxbound, 'BEDK_SET', this%memoryPath)
510  call mem_allocate(this%manning_set, this%maxbound, 'MANNING_SET', &
511  this%memoryPath)
512  call mem_allocate(this%ustrf_set, this%maxbound, 'USTRF_SET', &
513  this%memoryPath)
514  this%bedk_set = .false.
515  this%manning_set = .false.
516  this%ustrf_set = .false.
517  call mem_allocate(this%ftotnd, this%maxbound, 'FTOTND', this%memoryPath)
518  call mem_allocate(this%ndiv, this%maxbound, 'NDIV', this%memoryPath)
519  call mem_allocate(this%usflow, this%maxbound, 'USFLOW', this%memoryPath)
520  call mem_allocate(this%dsflow, this%maxbound, 'DSFLOW', this%memoryPath)
521  call mem_allocate(this%depth, this%maxbound, 'DEPTH', this%memoryPath)
522  call mem_allocate(this%stage, this%maxbound, 'STAGE', this%memoryPath)
523  call mem_allocate(this%gwflow, this%maxbound, 'GWFLOW', this%memoryPath)
524  call mem_allocate(this%simevap, this%maxbound, 'SIMEVAP', this%memoryPath)
525  call mem_allocate(this%simrunoff, this%maxbound, 'SIMRUNOFF', &
526  this%memoryPath)
527  call mem_allocate(this%stage0, this%maxbound, 'STAGE0', this%memoryPath)
528  call mem_allocate(this%usflow0, this%maxbound, 'USFLOW0', this%memoryPath)
529  !
530  ! -- stage, usflow, inflow, and dsflow for previous timestep
531  if (this%istorage == 1) then
532  call mem_allocate(this%stageold, this%maxbound, 'STAGEOLD', &
533  this%memoryPath)
534  call mem_allocate(this%usinflow, this%maxbound, 'USINFLOW', &
535  this%memoryPath)
536  call mem_allocate(this%usinflowold, this%maxbound, 'USINFLOWOLD', &
537  this%memoryPath)
538  call mem_allocate(this%dsflowold, this%maxbound, 'DSFLOWOLD', &
539  this%memoryPath)
540  call mem_allocate(this%storage, this%maxbound, 'STORAGE', &
541  this%memoryPath)
542  call mem_allocate(this%crmin, this%maxbound, 'CRMIN', this%memoryPath)
543  call mem_allocate(this%crmax, this%maxbound, 'CRMAX', this%memoryPath)
544  call mem_allocate(this%crsum, this%maxbound, 'CRSUM', this%memoryPath)
545  call mem_allocate(this%crcnt, this%maxbound, 'CRCNT', this%memoryPath)
546  if (this%ats_courant /= dnodata) then
547  call mem_allocate(this%itvd_upstream, this%maxbound, &
548  'ITVD_UPSTREAM', this%memoryPath)
549  else
550  call mem_allocate(this%itvd_upstream, 0, 'ITVD_UPSTREAM', this%memoryPath)
551  end if
552  end if
553  !
554  ! -- reach order and connection data
555  call mem_allocate(this%isfrorder, this%maxbound, 'ISFRORDER', &
556  this%memoryPath)
557  call mem_allocate(this%ia, this%maxbound + 1, 'IA', this%memoryPath)
558  call mem_allocate(this%ja, 0, 'JA', this%memoryPath)
559  call mem_allocate(this%idir, 0, 'IDIR', this%memoryPath)
560  call mem_allocate(this%idiv, 0, 'IDIV', this%memoryPath)
561  call mem_allocate(this%qconn, 0, 'QCONN', this%memoryPath)
562  !
563  ! -- alias into the input context's permanent, feature-indexed arrays
564  ! (allocated and DZERO-initialized by the loader)
565  call mem_setptr(this%rain, 'RAINFALL', this%input_mempath)
566  call mem_setptr(this%evap, 'EVAPORATION', this%input_mempath)
567  call mem_setptr(this%inflow, 'INFLOW', this%input_mempath)
568  call mem_setptr(this%runoff, 'RUNOFF', this%input_mempath)
569  call mem_setptr(this%sstage, 'STAGE', this%input_mempath)
570  call mem_setptr(this%hk, 'BEDK', this%input_mempath)
571  call mem_setptr(this%rough, 'MANNING', this%input_mempath)
572  call mem_setptr(this%ustrf, 'UPSTREAM_FRAC', this%input_mempath)
573  !
574  !
575  ! -- diversion variables
576  call mem_allocate(this%iadiv, this%maxbound + 1, 'IADIV', this%memoryPath)
577  call mem_allocate(this%divreach, 0, 'DIVREACH', this%memoryPath)
578  call mem_allocate(this%divq, 0, 'DIVQ', this%memoryPath)
579  !
580  ! -- cross-section data
581  call mem_allocate(this%ncrosspts, this%maxbound, 'NCROSSPTS', &
582  this%memoryPath)
583  call mem_allocate(this%iacross, this%maxbound + 1, 'IACROSS', &
584  this%memoryPath)
585  call mem_allocate(this%station, this%ncrossptstot, 'STATION', &
586  this%memoryPath)
587  call mem_allocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', &
588  this%memoryPath)
589  call mem_allocate(this%xsrough, this%ncrossptstot, 'XSROUGH', &
590  this%memoryPath)
591  !
592  ! -- initialize variables
593  this%iacross(1) = 0
594  do i = 1, this%maxbound
595  this%iboundpak(i) = 1
596  this%igwfnode(i) = 0
597  this%igwftopnode(i) = 0
598  this%length(i) = dzero
599  this%width(i) = dzero
600  this%strtop(i) = dzero
601  this%bthick(i) = dzero
602  this%hk(i) = dzero
603  this%slope(i) = dzero
604  this%nconnreach(i) = 0
605  this%ustrf(i) = dzero
606  this%ftotnd(i) = dzero
607  this%ndiv(i) = 0
608  this%usflow(i) = dzero
609  this%dsflow(i) = dzero
610  this%depth(i) = dzero
611  this%stage(i) = dzero
612  this%gwflow(i) = dzero
613  this%simevap(i) = dzero
614  this%simrunoff(i) = dzero
615  this%stage0(i) = dzero
616  this%usflow0(i) = dzero
617  !
618  ! -- stage
619  if (this%istorage == 1) then
620  this%stageold(i) = dzero
621  this%usinflow(i) = dzero
622  this%usinflowold(i) = dzero
623  this%dsflowold(i) = dzero
624  this%storage(i) = dzero
625  this%crmin(i) = dep20
626  this%crmax(i) = -dep20
627  this%crsum(i) = dzero
628  this%crcnt(i) = 0
629  if (this%ats_courant /= dnodata) then
630  this%itvd_upstream(i) = 0
631  end if
632  end if
633  !
634  ! -- boundary data
635  this%rough(i) = dzero
636  !
637  !
638  ! -- cross-section data
639  this%ncrosspts(i) = 0
640  this%iacross(i + 1) = 0
641  end do
642  !
643  ! -- initialize additional cross-section data
644  do i = 1, this%ncrossptstot
645  this%station(i) = dzero
646  this%xsheight(i) = dzero
647  this%xsrough(i) = dzero
648  end do
649  !
650  !-- fill csfrbudget
651  this%csfrbudget(1) = ' RAINFALL'
652  this%csfrbudget(2) = ' EVAPORATION'
653  this%csfrbudget(3) = ' RUNOFF'
654  this%csfrbudget(4) = ' EXT-INFLOW'
655  this%csfrbudget(5) = ' GWF'
656  this%csfrbudget(6) = ' EXT-OUTFLOW'
657  this%csfrbudget(7) = ' FROM-MVR'
658  this%csfrbudget(8) = ' TO-MVR'
659  !
660  ! -- allocate and initialize budget output data
661  call mem_allocate(this%qoutflow, this%maxbound, 'QOUTFLOW', this%memoryPath)
662  call mem_allocate(this%qextoutflow, this%maxbound, 'QEXTOUTFLOW', &
663  this%memoryPath)
664  do i = 1, this%maxbound
665  this%qoutflow(i) = dzero
666  this%qextoutflow(i) = dzero
667  end do
668  !
669  ! -- allocate and initialize dbuff
670  if (this%istageout > 0) then
671  call mem_allocate(this%dbuff, this%maxbound, 'DBUFF', this%memoryPath)
672  do i = 1, this%maxbound
673  this%dbuff(i) = dzero
674  end do
675  else
676  call mem_allocate(this%dbuff, 0, 'DBUFF', this%memoryPath)
677  end if
678  !
679  ! -- allocate character array for budget text
680  allocate (this%cauxcbc(this%cbcauxitems))
681  !
682  ! -- allocate and initialize qauxcbc
683  call mem_allocate(this%qauxcbc, this%cbcauxitems, 'QAUXCBC', &
684  this%memoryPath)
685  do i = 1, this%cbcauxitems
686  this%qauxcbc(i) = dzero
687  end do
688  !
689  ! -- fill cauxcbc
690  this%cauxcbc(1) = 'FLOW-AREA '
691  !
692  ! -- allocate denseterms to size 0
693  call mem_allocate(this%denseterms, 3, 0, 'DENSETERMS', this%memoryPath)
694  !
695  ! -- allocate viscratios to size 0
696  call mem_allocate(this%viscratios, 2, 0, 'VISCRATIOS', this%memoryPath)
697  end subroutine sfr_allocate_arrays
698 
699  !> @brief Alias deprecated SFR variable names to their current storage
700  !!
701  !! IDM integration moved several reach variables into the input context,
702  !! renaming some. These aliases share memory with the relocated variables so
703  !! that programs addressing them through the API by their old package-path
704  !! names continue to resolve; each use is reported as deprecated. DIVFLOW is
705  !! only set from the input context when diversions are present; otherwise an
706  !! empty DIVFLOW is allocated at the package path, as before IDM integration.
707  !<
708  subroutine sfr_checkin_deprecated_names(this)
709  ! -- modules
712  ! -- dummy
713  class(sfrtype), intent(inout) :: this
714  ! -- local
715  real(DP), dimension(:, :), pointer, contiguous :: aux => null()
716  integer(I4B) :: isize
717  ! -- code
718  !
719  ! -- reach auxiliary values, present (possibly empty) in the input context
720  call get_isize('AUX', this%input_mempath, isize)
721  if (isize >= 0) then
722  call mem_setptr(aux, 'AUX', this%input_mempath)
723  call mem_alias_deprecated(aux, 'RAUXVAR', this%memoryPath, &
724  'AUX', this%input_mempath, '6.8.2')
725  end if
726  !
727  ! -- diversion flows
728  if (associated(this%divflow)) then
729  call mem_alias_deprecated(this%divflow, 'DIVFLOW', this%memoryPath, &
730  'DIVFLOW', this%input_mempath, '6.8.2')
731  else
732  call mem_allocate(this%divflow, 0, 'DIVFLOW', this%memoryPath)
733  end if
734  !
735  call mem_alias_deprecated(this%rain, 'RAIN', this%memoryPath, &
736  'RAINFALL', this%input_mempath, '6.8.2')
737  call mem_alias_deprecated(this%evap, 'EVAP', this%memoryPath, &
738  'EVAPORATION', this%input_mempath, '6.8.2')
739  call mem_alias_deprecated(this%inflow, 'INFLOW', this%memoryPath, &
740  'INFLOW', this%input_mempath, '6.8.2')
741  call mem_alias_deprecated(this%runoff, 'RUNOFF', this%memoryPath, &
742  'RUNOFF', this%input_mempath, '6.8.2')
743  call mem_alias_deprecated(this%sstage, 'SSTAGE', this%memoryPath, &
744  'STAGE', this%input_mempath, '6.8.2')
745  call mem_alias_deprecated(this%hk, 'HK', this%memoryPath, &
746  'BEDK', this%input_mempath, '6.8.2')
747  call mem_alias_deprecated(this%rough, 'ROUGH', this%memoryPath, &
748  'MANNING', this%input_mempath, '6.8.2')
749  call mem_alias_deprecated(this%ustrf, 'USTRF', this%memoryPath, &
750  'UPSTREAM_FRAC', this%input_mempath, '6.8.2')
751  end subroutine sfr_checkin_deprecated_names
752 
753  !> @brief Source OPTIONS from input context
754  !<
755  subroutine sfr_source_options(this)
756  ! -- modules
757  use memorymanagermodule, only: get_isize
760  use openspecmodule, only: access, form
761  ! -- dummy
762  class(sfrtype), intent(inout) :: this !< SfrType object
763  ! -- local
764  character(len=LINELENGTH) :: fname
765  logical(LGP) :: found
766  ! -- formats
767  character(len=*), parameter :: fmtpicard = &
768  &"(4x, 'MAXIMUM SFR PICARD ITERATION VALUE (',i0,') SPECIFIED.')"
769  character(len=*), parameter :: fmtiter = &
770  &"(4x, 'MAXIMUM SFR ITERATION VALUE (',i0,') SPECIFIED.')"
771  character(len=*), parameter :: fmtdmaxchg = &
772  &"(4x, 'MAXIMUM DEPTH CHANGE VALUE (',g0,') SPECIFIED.')"
773  character(len=*), parameter :: fmtlengthconv = &
774  &"(4x, 'LENGTH CONVERSION VALUE (',g0,') SPECIFIED.')"
775  character(len=*), parameter :: fmttimeconv = &
776  &"(4x, 'TIME CONVERSION VALUE (',g0,') SPECIFIED.')"
777  character(len=*), parameter :: fmtstoweight = &
778  &"(4x, 'KINEMATIC STORAGE WEIGHT (',g0,') SPECIFIED.')"
779  character(len=*), parameter :: fmtsfrbin = &
780  "(4x, 'SFR ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, &
781  &'OPENED ON UNIT: ', I0)"
782  integer(I4B) :: isize
783  !
784  ! -- source base BndExtType options (NAUX, BOUNDNAMES, PRINT_INPUT, etc.)
785  call this%BndExtType%source_options()
786  !
787  write (this%iout, '(/1x,a)') &
788  'PROCESSING '//trim(adjustl(this%text))//' OPTIONS'
789  !
790  ! -- STORAGE
791  call mem_set_value(this%istorage, 'STORAGE', this%input_mempath, found)
792  if (found) then
793  write (this%iout, '(4x,a)') trim(adjustl(this%text))// &
794  ' REACH STORAGE IS ACTIVE.'
795  end if
796  !
797  ! -- ATS_COURANT
798  call mem_set_value(this%ats_courant, 'ATS_COURANT', &
799  this%input_mempath, found)
800  if (found) then
801  if (this%ats_courant <= dzero) then
802  write (errmsg, '(a,g0,a)') &
803  "ATS_COURANT SPECIFIED TO BE '", this%ats_courant, &
804  "' BUT MUST BE GREATER THAN ZERO"
805  call store_error(errmsg)
806  call store_error_filename(this%input_fname)
807  else
808  write (this%iout, '(4x,a,1pg15.6)') &
809  'TARGET COURANT NUMBER FOR ADAPTIVE TIME STEPS: ', &
810  this%ats_courant
811  end if
812  end if
813  !
814  ! -- PRINT_STAGE
815  call mem_set_value(this%iprhed, 'PRINT_STAGE', this%input_mempath, found)
816  if (found) then
817  write (this%iout, '(4x,a)') trim(adjustl(this%text))// &
818  ' STAGES WILL BE PRINTED TO LISTING FILE.'
819  end if
820  !
821  ! -- STAGEFILE
822  call mem_set_value(fname, 'STAGEFILE', this%input_mempath, found)
823  if (found) then
824  this%istageout = getunit()
825  call openfile(this%istageout, this%iout, fname, 'DATA(BINARY)', &
826  form, access, 'REPLACE', mnormal)
827  write (this%iout, fmtsfrbin) 'STAGE', trim(fname), this%istageout
828  end if
829  !
830  ! -- BUDGETFILE
831  call mem_set_value(fname, 'BUDGETFILE', this%input_mempath, found)
832  if (found) then
833  call assign_iounit(this%ibudgetout, this%inunit, 'BUDGET fileout')
834  call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', &
835  form, access, 'REPLACE', mnormal)
836  write (this%iout, fmtsfrbin) 'BUDGET', trim(fname), this%ibudgetout
837  end if
838  !
839  ! -- BUDGETCSVFILE
840  call mem_set_value(fname, 'BUDGETCSVFILE', this%input_mempath, found)
841  if (found) then
842  call assign_iounit(this%ibudcsv, this%inunit, 'BUDGETCSV fileout')
843  call openfile(this%ibudcsv, this%iout, fname, 'CSV', &
844  filstat_opt='REPLACE')
845  write (this%iout, fmtsfrbin) 'BUDGET CSV', trim(fname), this%ibudcsv
846  end if
847  !
848  ! -- PACKAGE_CONVERGENCE_FILENAME (mf6internal: pkgconvfname)
849  call mem_set_value(fname, 'PKGCONVFNAME', this%input_mempath, found)
850  if (found) then
851  this%ipakcsv = getunit()
852  call openfile(this%ipakcsv, this%iout, fname, 'CSV', &
853  filstat_opt='REPLACE', mode_opt=mnormal)
854  write (this%iout, fmtsfrbin) 'PACKAGE_CONVERGENCE', trim(fname), &
855  this%ipakcsv
856  end if
857  !
858  ! -- MOVER
859  call mem_set_value(this%imover, 'MOVER', this%input_mempath, found)
860  if (found) then
861  write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED'
862  end if
863  !
864  ! -- MAXIMUM_PICARD_ITERATIONS (mf6internal: maxsfrpicard)
865  call mem_set_value(this%maxsfrpicard, 'MAXSFRPICARD', &
866  this%input_mempath, found)
867  if (found) write (this%iout, fmtpicard) this%maxsfrpicard
868  !
869  ! -- MAXIMUM_ITERATIONS (mf6internal: maxsfrit)
870  call mem_set_value(this%maxsfrit, 'MAXSFRIT', &
871  this%input_mempath, found)
872  if (found) write (this%iout, fmtiter) this%maxsfrit
873  !
874  ! -- MAXIMUM_DEPTH_CHANGE (mf6internal: dmaxchg)
875  call mem_set_value(this%dmaxchg, 'DMAXCHG', &
876  this%input_mempath, found)
877  if (found) then
878  this%deps = dp999 * this%dmaxchg
879  write (this%iout, fmtdmaxchg) this%dmaxchg
880  end if
881  !
882  ! -- LENGTH_CONVERSION (mf6internal: lengthconv)
883  call mem_set_value(this%lengthconv, 'LENGTHCONV', &
884  this%input_mempath, found)
885  if (found) write (this%iout, fmtlengthconv) this%lengthconv
886  !
887  ! -- TIME_CONVERSION
888  call mem_set_value(this%timeconv, 'TIME_CONVERSION', &
889  this%input_mempath, found)
890  if (found) write (this%iout, fmttimeconv) this%timeconv
891  !
892  ! -- UNIT_CONVERSION (deprecated)
893  call mem_set_value(this%unitconv, 'UNIT_CONVERSION', &
894  this%input_mempath, found)
895  if (found) then
896  write (warnmsg, '(a)') 'SETTING UNIT_CONVERSION DIRECTLY'
897  call deprecation_warning('OPTIONS', 'UNIT_CONVERSION', '6.4.2', &
898  warnmsg, this%inunit)
899  end if
900  !
901  ! -- DEV_STORAGE_WEIGHT (mf6internal: storage_weight)
902  call mem_set_value(this%storage_weight, 'STORAGE_WEIGHT', &
903  this%input_mempath, found)
904  if (found) then
905  if (this%storage_weight < dhalf .or. this%storage_weight > done) then
906  write (errmsg, '(a,g0,a)') &
907  "STORAGE_WEIGHT SPECIFIED TO BE '", this%storage_weight, &
908  "' BUT CANNOT BE LESS THAN 0.5 OR GREATER THAN 1.0"
909  call store_error(errmsg)
910  call store_error_filename(this%input_fname)
911  else
912  write (this%iout, fmtstoweight) this%storage_weight
913  end if
914  end if
915  !
916  ! -- DEV_NO_CHECK (mf6internal: icheck)
917  call get_isize('ICHECK', this%input_mempath, isize)
918  if (isize > 0) then
919  this%icheck = 0
920  write (this%iout, '(4x,a)') &
921  'REACH GEOMETRY AND PARAMETER CHECKS WILL NOT BE MADE'
922  end if
923  !
924  ! -- DEV_NO_FINAL_CHECK (mf6internal: iconvchk)
925  call get_isize('ICONVCHK', this%input_mempath, isize)
926  if (isize > 0) then
927  this%iconvchk = 0
928  write (this%iout, '(4x,a)') &
929  'A FINAL CONVERGENCE CHECK OF THE CHANGE IN STREAM FLOW ROUTING '// &
930  'STAGES AND FLOWS WILL NOT BE MADE'
931  end if
932  !
933  write (this%iout, '(1x,a)') &
934  'END OF '//trim(adjustl(this%text))//' OPTIONS'
935  end subroutine sfr_source_options
936 
937  !> @brief Source DIMENSIONS block from input context and load static data
938  !<
939  subroutine sfr_source_dimensions(this)
940  ! -- modules
942  ! -- dummy
943  class(sfrtype), intent(inout) :: this !< SfrType object
944  ! -- local
945  logical(LGP) :: found
946  !
947  ! -- initialize dimensions to 0
948  this%maxbound = 0
949  !
950  write (this%iout, '(/1x,a)') &
951  'PROCESSING '//trim(adjustl(this%text))//' DIMENSIONS'
952  !
953  ! -- source NREACHES
954  call mem_set_value(this%maxbound, 'MAXBOUND', this%input_mempath, found, &
955  release=.false.)
956  if (found) then
957  write (this%iout, '(4x,a,i0)') 'NREACHES = ', this%maxbound
958  end if
959  !
960  write (this%iout, '(1x,a)') &
961  'END OF '//trim(adjustl(this%text))//' DIMENSIONS'
962  !
963  if (this%maxbound < 1) then
964  write (errmsg, '(a)') &
965  'NREACHES was not specified or was specified incorrectly.'
966  call store_error(errmsg)
967  call store_error_filename(this%input_fname)
968  end if
969  !
970  ! -- set npakeq (SFR adds no extra equations)
971  this%npakeq = 0
972  !
973  ! -- define the default label
974  call this%define_listlabel()
975  !
976  ! -- define default cross-section data size
977  this%ncrossptstot = this%maxbound
978  !
979  ! -- allocate arrays
980  call this%sfr_allocate_arrays()
981  !
982  ! -- source packagedata
983  call this%sfr_source_packagedata()
984  !
985  ! -- source crosssections
986  call this%sfr_source_crosssections()
987  !
988  ! -- source connectiondata
989  call this%sfr_source_connectiondata()
990  !
991  ! -- source diversions
992  call this%sfr_source_diversions()
993  !
994  ! -- alias deprecated variable names
995  call this%sfr_checkin_deprecated_names()
996  !
997  ! -- source initialstages
998  call this%sfr_source_initialstages()
999  !
1000  ! -- setup the budget object
1001  call this%sfr_setup_budobj()
1002  !
1003  ! -- setup the stage table object
1004  call this%sfr_setup_tableobj()
1005  end subroutine sfr_source_dimensions
1006 
1007  !> @brief Source PACKAGEDATA block from input context
1008  !<
1009  subroutine sfr_source_packagedata(this)
1010  ! -- modules
1011  use memorymanagermodule, only: mem_setptr
1013  ! -- dummy
1014  class(sfrtype), intent(inout) :: this !< SfrType object
1015  ! -- local
1016  integer(I4B) :: i, n, nconzero
1017  integer(I4B) :: ipos
1018  character(len=10) :: cnum
1019  character(len=LENBOUNDNAME) :: bndName
1020  character(len=LINELENGTH) :: cellid_str
1021  integer(I4B), allocatable :: nboundchk(:)
1022  integer(I4B), dimension(:), pointer, contiguous :: ifno => null()
1023  integer(I4B), dimension(:, :), pointer, contiguous :: cellid => null()
1024  real(DP), dimension(:), pointer, contiguous :: rlen => null()
1025  real(DP), dimension(:), pointer, contiguous :: rwid => null()
1026  real(DP), dimension(:), pointer, contiguous :: rgrd => null()
1027  real(DP), dimension(:), pointer, contiguous :: rtp => null()
1028  real(DP), dimension(:), pointer, contiguous :: rbth => null()
1029  integer(I4B), dimension(:), pointer, contiguous :: ncon => null()
1030  integer(I4B), dimension(:), pointer, contiguous :: ndv => null()
1031  type(characterstringtype), dimension(:), pointer, contiguous :: &
1032  boundname => null()
1033  integer(I4B), dimension(:, :), pointer, contiguous :: tslink => null()
1034  type(characterstringtype), dimension(:), pointer, contiguous :: &
1035  tslinkvars => null()
1036  !
1037  write (this%iout, '(/1x,a)') &
1038  'PROCESSING '//trim(adjustl(this%text))//' PACKAGEDATA'
1039  !
1040  ! -- get input context PACKAGEDATA column arrays
1041  call mem_setptr(ifno, 'PACKAGEDATA_IFNO', this%input_mempath)
1042  call mem_setptr(cellid, 'CELLID', this%input_mempath)
1043  call mem_setptr(rlen, 'RLEN', this%input_mempath)
1044  call mem_setptr(rwid, 'RWID', this%input_mempath)
1045  call mem_setptr(rgrd, 'RGRD', this%input_mempath)
1046  call mem_setptr(rtp, 'RTP', this%input_mempath)
1047  call mem_setptr(rbth, 'RBTH', this%input_mempath)
1048  call mem_setptr(this%input%rhk, 'RHK', this%input_mempath)
1049  call mem_setptr(this%input%man, 'MAN', this%input_mempath)
1050  call mem_setptr(ncon, 'NCON', this%input_mempath)
1051  call mem_setptr(this%input%ustrf, 'USTRF', this%input_mempath)
1052  call mem_setptr(tslink, 'TSLINK_PD', this%input_mempath)
1053  call mem_setptr(tslinkvars, 'TSLINKVARS_PD', this%input_mempath)
1054  do n = 1, size(tslinkvars)
1055  if (tslinkvars(n) == 'RHK') this%input%rhk_tslink => tslink(n, :)
1056  if (tslinkvars(n) == 'MAN') this%input%man_tslink => tslink(n, :)
1057  if (tslinkvars(n) == 'USTRF') this%input%ustrf_tslink => tslink(n, :)
1058  end do
1059  if (.not. (associated(this%input%rhk_tslink) .and. &
1060  associated(this%input%man_tslink) .and. &
1061  associated(this%input%ustrf_tslink))) then
1062  call store_error('Time series links for RHK, MAN and USTRF not found &
1063  &in input.')
1064  call store_error_filename(this%input_fname)
1065  end if
1066  call mem_setptr(ndv, 'NDV', this%input_mempath)
1067  if (this%inamedbound /= 0) then
1068  call mem_setptr(boundname, 'BOUNDNAME', this%input_mempath)
1069  end if
1070  !
1071  ! -- allocate check array
1072  allocate (nboundchk(this%maxbound))
1073  nboundchk = 0
1074  nconzero = 0
1075  !
1076  ! -- populate reach data from input context arrays
1077  do i = 1, this%maxbound
1078  n = ifno(i)
1079  !
1080  n = this%validate_ifno(n, this%maxbound, nboundchk, &
1081  'rno', 'PACKAGEDATA')
1082  if (n == 0) cycle
1083  !
1084  ! -- cellid → igwfnode: convert integer cellid array to string
1085  ! -- all-zero or negative cellid means unconnected reach (NONE keyword or 0 0 0)
1086  if (all(cellid(1:this%dis%ndim, i) <= 0)) then
1087  this%igwfnode(n) = 0
1088  else
1089  write (cellid_str, '(10(i0,1x))') cellid(1:this%dis%ndim, i)
1090  this%igwfnode(n) = this%dis%noder_from_cellid(cellid_str, &
1091  this%inunit, this%iout, &
1092  flag_string=.false., &
1093  allow_zero=.true.)
1094  end if
1095  this%igwftopnode(n) = this%igwfnode(n)
1096  if (this%igwfnode(n) < 1) this%ianynone = this%ianynone + 1
1097  !
1098  ! -- scalar reach properties
1099  this%length(n) = rlen(i)
1100  this%width(n) = rwid(i)
1101  this%slope(n) = rgrd(i)
1102  this%strtop(n) = rtp(i)
1103  this%bthick(n) = rbth(i)
1104  !
1105  ! -- ncon and nconn
1106  this%nconnreach(n) = ncon(i)
1107  this%nconn = this%nconn + ncon(i)
1108  if (ncon(i) < 0) then
1109  write (errmsg, '(a,1x,i0,1x,a,i0,a)') &
1110  'NCON for reach', n, &
1111  'must be greater than or equal to 0 (', ncon(i), ').'
1112  call store_error(errmsg)
1113  else if (ncon(i) == 0) then
1114  nconzero = nconzero + 1
1115  end if
1116  !
1117  ! -- ndv (diversions)
1118  this%ndiv(n) = ndv(i)
1119  if (ndv(i) > 0) this%idiversions = 1
1120  !
1121  ! -- bound name
1122  write (cnum, '(i10.10)') n
1123  bndname = 'Reach'//cnum
1124  if (this%inamedbound /= 0) then
1125  bndname = boundname(i)
1126  end if
1127  this%sfrname(n) = bndname
1128  !
1129  ! -- hk, roughness (Manning), upstream fraction: copied from
1130  ! input context; sfr_ad re-syncs TS-linked values each timestep
1131  this%hk(n) = this%input%rhk(i)
1132  this%rough(n) = this%input%man(i)
1133  this%ustrf(n) = this%input%ustrf(i)
1134  !
1135  ! -- initialize sstage to reach top
1136  this%sstage(n) = this%strtop(n)
1137  end do
1138  !
1139  write (this%iout, '(1x,a)') &
1140  'END OF '//trim(adjustl(this%text))//' PACKAGEDATA'
1141  !
1142  ! -- check every reach is specified exactly once
1143  call this%report_ifno_coverage(nboundchk, this%maxbound, 'reach', &
1144  'PACKAGEDATA')
1145  deallocate (nboundchk)
1146  !
1147  if (nconzero > 0) then
1148  write (warnmsg, '(a,1x,a,1x,a,1x,i0,1x,a)') &
1149  'SFR Package', trim(this%packName), &
1150  'has', nconzero, 'reach(es) with zero connections.'
1151  call store_warning(warnmsg)
1152  end if
1153  !
1154  if (count_errors() > 0) then
1155  call store_error_filename(this%input_fname)
1156  end if
1157  !
1158  ! -- initialize default cross-section data
1159  ipos = 1
1160  this%iacross(1) = ipos
1161  do i = 1, this%maxbound
1162  this%ncrosspts(i) = 1
1163  this%station(ipos) = this%width(i)
1164  this%xsheight(ipos) = dzero
1165  this%xsrough(ipos) = done
1166  ipos = ipos + 1
1167  this%iacross(i + 1) = ipos
1168  end do
1169  !
1170  ! -- release input context packagedata memory; PACKAGEDATA_IFNO excluded
1171  ! (allocate_featureauxvar); RHK/MAN/USTRF excluded
1172  call memorystore_release('CELLID', this%input_mempath)
1173  call memorystore_release('RLEN', this%input_mempath)
1174  call memorystore_release('RWID', this%input_mempath)
1175  call memorystore_release('RGRD', this%input_mempath)
1176  call memorystore_release('RTP', this%input_mempath)
1177  call memorystore_release('RBTH', this%input_mempath)
1178  call memorystore_release('NCON', this%input_mempath)
1179  call memorystore_release('NDV', this%input_mempath)
1180  call memorystore_release('BOUNDNAME', this%input_mempath)
1181  end subroutine sfr_source_packagedata
1182 
1183  !> @brief Source CROSSSECTIONS block from input context
1184  !<
1185  subroutine sfr_source_crosssections(this)
1186  ! -- modules
1187  use constantsmodule, only: lenmempath
1191  ! -- dummy
1192  class(sfrtype), intent(inout) :: this !< SfrType object
1193  ! -- local
1194  integer(I4B), dimension(:), pointer, contiguous :: ifno => null()
1195  type(characterstringtype), dimension(:), pointer, contiguous :: &
1196  tab6_filename => null()
1197  type(characterstringtype), dimension(:), pointer, contiguous :: &
1198  sfrtab6_mempaths => null()
1199  type(sfrcrosssection), pointer :: cross_data => null()
1200  integer(I4B) :: i, n, ncrossptstot
1201  integer(I4B), allocatable :: nboundchk(:)
1202  integer(I4B) :: isize
1203  character(len=LINELENGTH) :: tabfname
1204  character(len=LENMEMPATH) :: mempath
1205  !
1206  ! -- check if CROSSSECTIONS block was loaded (optional block)
1207  call get_isize('CROSSSECT_IFNO', this%input_mempath, isize)
1208  if (isize < 1) return
1209  !
1210  write (this%iout, '(/1x,a)') &
1211  'PROCESSING '//trim(adjustl(this%text))//' CROSSSECTIONS'
1212  !
1213  ! -- get input context arrays
1214  call mem_setptr(ifno, 'CROSSSECT_IFNO', this%input_mempath)
1215  call mem_setptr(tab6_filename, 'SFRTAB6_FILENAME', this%input_mempath)
1216  call mem_setptr(sfrtab6_mempaths, 'SFRTAB6_MEMPATH', this%input_mempath)
1217  !
1218  ! -- create cross-section object
1219  call cross_section_cr(cross_data, this%iout, this%iprpak, this%maxbound)
1220  call cross_data%initialize(this%ncrossptstot, this%ncrosspts, &
1221  this%iacross, this%station, this%xsheight, &
1222  this%xsrough)
1223  !
1224  allocate (nboundchk(this%maxbound))
1225  nboundchk = 0
1226  !
1227  do i = 1, isize
1228  n = this%validate_ifno(ifno(i), this%maxbound, nboundchk, &
1229  'reach', 'CROSSSECTIONS')
1230  if (n == 0) cycle
1231  tabfname = tab6_filename(i)
1232  mempath = sfrtab6_mempaths(i)
1233  call cross_data%source_table(n, this%width(n), mempath, &
1234  trim(adjustl(tabfname)))
1235  end do
1236  !
1237  write (this%iout, '(1x,a)') &
1238  'END OF '//trim(adjustl(this%text))//' CROSSSECTIONS'
1239  !
1240  ! -- CROSSSECTIONS is optional; only duplicates are reported
1241  call this%report_ifno_coverage(nboundchk, this%maxbound, 'reach', &
1242  'CROSSSECTIONS', check_missing=.false.)
1243  deallocate (nboundchk)
1244  !
1245  if (count_errors() > 0) then
1246  call store_error_filename(this%input_fname)
1247  end if
1248  !
1249  ! -- reallocate cross-section arrays if needed
1250  ncrossptstot = cross_data%get_ncrossptstot()
1251  if (ncrossptstot /= this%ncrossptstot) then
1252  this%ncrossptstot = ncrossptstot
1253  call mem_reallocate(this%station, this%ncrossptstot, 'STATION', &
1254  this%memoryPath)
1255  call mem_reallocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', &
1256  this%memoryPath)
1257  call mem_reallocate(this%xsrough, this%ncrossptstot, 'XSROUGH', &
1258  this%memoryPath)
1259  end if
1260  !
1261  call cross_data%output(this%width, this%rough)
1262  call cross_data%pack(this%ncrossptstot, this%ncrosspts, this%iacross, &
1263  this%station, this%xsheight, this%xsrough)
1264  call cross_data%destroy()
1265  deallocate (cross_data)
1266  nullify (cross_data)
1267  !
1268  ! -- release input context crosssections memory
1269  call memorystore_release('CROSSSECT_IFNO', this%input_mempath)
1270  call memorystore_release('SFRTAB6_FILENAME', this%input_mempath)
1271  end subroutine sfr_source_crosssections
1272 
1273  !> @brief Source CONNECTIONDATA block from input context
1274  !<
1275  subroutine sfr_source_connectiondata(this)
1276  ! -- modules
1278  use sparsemodule, only: sparsematrix
1279  ! -- dummy
1280  class(sfrtype), intent(inout) :: this !< SfrType object
1281  ! -- local
1282  integer(I4B), dimension(:), pointer, contiguous :: cd_ifno => null()
1283  integer(I4B), dimension(:), pointer, contiguous :: ic_flat => null()
1284  integer(I4B), dimension(:), pointer, contiguous :: cd_ia => null()
1285  type(sparsematrix), pointer :: sparse => null()
1286  integer(I4B), dimension(:), pointer, contiguous :: rowmaxnnz => null()
1287  integer(I4B), allocatable :: nboundchk(:)
1288  integer(I4B), allocatable :: iconndata(:, :)
1289  integer(I4B), allocatable :: iup(:)
1290  integer(I4B), allocatable :: order(:)
1291  type(dag) :: sfr_dag
1292  integer(I4B) :: i, n, j, jj, jcol, jcol2, nja, nconnmax
1293  integer(I4B) :: ival, idir, nup, ipos, istat, ierr, jlocal, nread
1294  !
1295  write (this%iout, '(/1x,a)') &
1296  'PROCESSING '//trim(adjustl(this%text))//' CONNECTIONDATA'
1297  !
1298  ! -- get input context CONNECTIONDATA arrays
1299  call mem_setptr(cd_ifno, 'CONNDATA_IFNO', this%input_mempath)
1300  call mem_setptr(ic_flat, 'IC', this%input_mempath)
1301  call mem_setptr(cd_ia, 'IC_IA', this%input_mempath)
1302  !
1303  ! -- allocate and initialize check array
1304  allocate (nboundchk(this%maxbound))
1305  nboundchk = 0
1306  !
1307  ! -- build rowmaxnnz from nconnreach
1308  nja = 0
1309  nconnmax = 0
1310  allocate (rowmaxnnz(this%maxbound))
1311  do n = 1, this%maxbound
1312  ival = this%nconnreach(n)
1313  if (ival < 0) ival = 0
1314  rowmaxnnz(n) = ival + 1
1315  nja = nja + ival + 1
1316  if (ival > nconnmax) nconnmax = ival
1317  end do
1318  !
1319  ! -- reallocate connection arrays
1320  call mem_reallocate(this%ja, nja, 'JA', this%memoryPath)
1321  call mem_reallocate(this%idir, nja, 'IDIR', this%memoryPath)
1322  call mem_reallocate(this%idiv, nja, 'IDIV', this%memoryPath)
1323  call mem_reallocate(this%qconn, nja, 'QCONN', this%memoryPath)
1324  this%idir = 0
1325  this%idiv = 0
1326  this%qconn = dzero
1327  !
1328  ! -- allocate iconndata
1329  allocate (iconndata(nconnmax, this%maxbound))
1330  iconndata = 0
1331  !
1332  allocate (sparse)
1333  call sparse%init(this%maxbound, this%maxbound, rowmaxnnz)
1334  !
1335  ! -- process connection data rows
1336  do i = 1, this%maxbound
1337  n = this%validate_ifno(cd_ifno(i), this%maxbound, nboundchk, &
1338  'reach', 'CONNECTIONDATA')
1339  if (n == 0) cycle
1340  nread = cd_ia(i + 1) - cd_ia(i)
1341  if (nread /= this%nconnreach(n)) then
1342  write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,a)') &
1343  'Reach', n, 'connectiondata specifies', nread, &
1344  'connections but NCON for this reach in packagedata is', &
1345  this%nconnreach(n), '.'
1346  call store_error(errmsg)
1347  cycle
1348  end if
1349  call sparse%addconnection(n, n, 1)
1350  jlocal = 0
1351  do j = cd_ia(i), cd_ia(i + 1) - 1
1352  jlocal = jlocal + 1
1353  ival = ic_flat(j)
1354  iconndata(jlocal, n) = ival
1355  if (ival < 0) then
1356  idir = -1
1357  ival = abs(ival)
1358  else if (ival == 0) then
1359  call store_error('Missing or zero connection reach in connectiondata.')
1360  cycle
1361  else
1362  idir = 1
1363  end if
1364  if (ival > this%maxbound) then
1365  call store_error('Reach number exceeds NREACHES in connectiondata.')
1366  cycle
1367  end if
1368  call sparse%addconnection(n, ival, 1)
1369  end do
1370  end do
1371  !
1372  write (this%iout, '(1x,a)') &
1373  'END OF '//trim(adjustl(this%text))//' CONNECTIONDATA'
1374  !
1375  call this%report_ifno_coverage(nboundchk, this%maxbound, 'reach', &
1376  'CONNECTIONDATA')
1377  !
1378  if (count_errors() > 0) then
1379  call store_error_filename(this%input_fname)
1380  end if
1381  !
1382  ! -- fill ia and ja from sparse
1383  call sparse%filliaja(this%ia, this%ja, ierr, sort=.true.)
1384  if (ierr /= 0) then
1385  write (errmsg, '(a,3(1x,a))') &
1386  'Could not fill', trim(this%packName), &
1387  'package IA and JA connection data.', &
1388  'Check connectivity data in connectiondata block.'
1389  call store_error(errmsg)
1390  end if
1391  !
1392  ! -- fill flat connection storage with direction
1393  do n = 1, this%maxbound
1394  do j = this%ia(n) + 1, this%ia(n + 1) - 1
1395  jcol = this%ja(j)
1396  do jj = 1, this%nconnreach(n)
1397  jcol2 = iconndata(jj, n)
1398  if (abs(jcol2) == jcol) then
1399  idir = 1
1400  if (jcol2 < 0) idir = -1
1401  this%idir(j) = idir
1402  exit
1403  end if
1404  end do
1405  end do
1406  end do
1407  !
1408  ! -- deallocate temporaries
1409  deallocate (rowmaxnnz)
1410  deallocate (nboundchk)
1411  deallocate (iconndata)
1412  call sparse%destroy()
1413  deallocate (sparse)
1414  !
1415  ! -- compute reach order using DAG
1416  call sfr_dag%set_vertices(this%maxbound)
1417  fill_dag: do n = 1, this%maxbound
1418  nup = 0
1419  do j = this%ia(n) + 1, this%ia(n + 1) - 1
1420  if (this%idir(j) > 0) nup = nup + 1
1421  end do
1422  if (nup == 0) cycle fill_dag
1423  allocate (iup(nup))
1424  ipos = 1
1425  do j = this%ia(n) + 1, this%ia(n + 1) - 1
1426  if (this%idir(j) > 0) then
1427  iup(ipos) = this%ja(j)
1428  ipos = ipos + 1
1429  end if
1430  end do
1431  call sfr_dag%set_edges(n, iup)
1432  deallocate (iup)
1433  end do fill_dag
1434  call sfr_dag%toposort(order, istat)
1435  if (istat == -1) then
1436  write (warnmsg, '(a)') &
1437  trim(adjustl(this%text))//' PACKAGE ('// &
1438  trim(adjustl(this%packName))//') cannot calculate a '// &
1439  'Directed Asyclic Graph for reach connectivity because '// &
1440  'of circular dependency. Using the reach number for '// &
1441  'solution ordering.'
1442  call store_warning(warnmsg)
1443  end if
1444  do n = 1, this%maxbound
1445  if (istat == 0) then
1446  this%isfrorder(n) = order(n)
1447  else
1448  this%isfrorder(n) = n
1449  end if
1450  end do
1451  call sfr_dag%destroy()
1452  if (istat == 0) deallocate (order)
1453  !
1454  ! -- release input context connectiondata memory
1455  call memorystore_release('CONNDATA_IFNO', this%input_mempath)
1456  call memorystore_release('IC', this%input_mempath)
1457  call memorystore_release('IC_IA', this%input_mempath)
1458  end subroutine sfr_source_connectiondata
1459 
1460  !> @brief Source DIVERSIONS block from input context
1461  !<
1462  subroutine sfr_source_diversions(this)
1463  ! -- modules
1466  ! -- dummy
1467  class(sfrtype), intent(inout) :: this !< SfrType object
1468  ! -- local
1469  integer(I4B), dimension(:), pointer, contiguous :: d_ifno => null()
1470  integer(I4B), dimension(:), pointer, contiguous :: d_idv => null()
1471  integer(I4B), dimension(:), pointer, contiguous :: d_iconr => null()
1472  type(characterstringtype), dimension(:), pointer, contiguous :: &
1473  d_cprior => null()
1474  integer(I4B) :: i, n, idiv, ndiversions, i0, ipos, jpos
1475  integer(I4B) :: isize
1476  integer(I4B), allocatable :: iachk(:), nboundchk(:)
1477  character(len=16) :: cval
1478  !
1479  ! -- build iadiv and count total diversions
1480  ndiversions = 0
1481  i0 = 1
1482  this%iadiv(1) = i0
1483  do n = 1, this%maxbound
1484  ndiversions = ndiversions + this%ndiv(n)
1485  i0 = i0 + this%ndiv(n)
1486  this%iadiv(n + 1) = i0
1487  end do
1488  !
1489  ! -- reallocate diversion arrays
1490  if (ndiversions > 0) then
1491  call mem_reallocate(this%divreach, ndiversions, 'DIVREACH', &
1492  this%memoryPath)
1493  allocate (this%divcprior(ndiversions))
1494  call mem_setptr(this%divflow, 'DIVFLOW', this%input_mempath)
1495  call mem_reallocate(this%divq, ndiversions, 'DIVQ', this%memoryPath)
1496  this%divq = dzero
1497  end if
1498  !
1499  ! -- check if DIVERSIONS block was loaded (optional block)
1500  call get_isize('DIVERSIONS_IFNO', this%input_mempath, isize)
1501  if (isize < 1) then
1502  if (this%idiversions /= 0) then
1503  call store_error('REQUIRED DIVERSIONS BLOCK NOT FOUND.')
1504  call store_error_filename(this%input_fname)
1505  end if
1506  return
1507  end if
1508  !
1509  if (this%idiversions == 0) then
1510  write (errmsg, '(a,1x,a)') &
1511  'A diversions block should not be', &
1512  'specified if diversions are not specified.'
1513  call store_error(errmsg)
1514  call store_error_filename(this%input_fname)
1515  return
1516  end if
1517  !
1518  write (this%iout, '(/1x,a)') &
1519  'PROCESSING '//trim(adjustl(this%text))//' DIVERSIONS'
1520  !
1521  ! -- get input context arrays
1522  call mem_setptr(d_ifno, 'DIVERSIONS_IFNO', this%input_mempath)
1523  call mem_setptr(d_idv, 'DIVERSIONS_IDV', this%input_mempath)
1524  call mem_setptr(d_iconr, 'ICONR', this%input_mempath)
1525  call mem_setptr(d_cprior, 'CPRIOR', this%input_mempath)
1526  !
1527  ! -- build check arrays
1528  allocate (iachk(this%maxbound + 1))
1529  allocate (nboundchk(ndiversions))
1530  nboundchk = 0
1531  iachk(1) = 1
1532  do n = 1, this%maxbound
1533  iachk(n + 1) = iachk(n) + this%ndiv(n)
1534  end do
1535  !
1536  do i = 1, isize
1537  n = d_ifno(i)
1538  if (n < 1 .or. n > this%maxbound) then
1539  write (errmsg, '(a,i0,a)') 'Reach number should be between 1 and ', &
1540  this%maxbound, '.'
1541  call store_error(errmsg)
1542  cycle
1543  end if
1544  if (this%ndiv(n) < 1) then
1545  write (errmsg, '(a,i0)') &
1546  'Diversions cannot be specified for reach ', n
1547  call store_error(errmsg)
1548  cycle
1549  end if
1550  idiv = d_idv(i)
1551  if (idiv < 1 .or. idiv > this%ndiv(n)) then
1552  write (errmsg, '(a,i0,a,i0,a)') &
1553  'Reach ', n, ' diversion number should be between 1 and ', &
1554  this%ndiv(n), '.'
1555  call store_error(errmsg)
1556  cycle
1557  end if
1558  ipos = iachk(n) + idiv - 1
1559  nboundchk(ipos) = nboundchk(ipos) + 1
1560  jpos = this%iadiv(n) + idiv - 1
1561  if (d_iconr(i) < 1 .or. d_iconr(i) > this%maxbound) then
1562  write (errmsg, '(a,i0,a)') &
1563  'Diversion target reach number should be between 1 and ', &
1564  this%maxbound, '.'
1565  call store_error(errmsg)
1566  cycle
1567  end if
1568  this%divreach(jpos) = d_iconr(i)
1569  cval = d_cprior(i)
1570  select case (trim(cval))
1571  case ('UPTO', 'THRESHOLD', 'FRACTION', 'EXCESS')
1572  case default
1573  errmsg = 'Invalid cprior type '//trim(cval)//'.'
1574  call store_error(errmsg)
1575  end select
1576  this%divcprior(jpos) = trim(cval)
1577  end do
1578  !
1579  write (this%iout, '(1x,a)') &
1580  'END OF '//trim(adjustl(this%text))//' DIVERSIONS'
1581  !
1582  do n = 1, this%maxbound
1583  do idiv = 1, this%ndiv(n)
1584  ipos = iachk(n) + idiv - 1
1585  if (nboundchk(ipos) == 0) then
1586  write (errmsg, '(a,1x,i0,1x,a,1x,i0)') &
1587  'No data specified for reach', n, 'diversion', idiv
1588  call store_error(errmsg)
1589  else if (nboundchk(ipos) > 1) then
1590  write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') &
1591  'Data for reach', n, 'diversion', idiv, &
1592  'specified', nboundchk(ipos), 'times'
1593  call store_error(errmsg)
1594  end if
1595  end do
1596  end do
1597  deallocate (iachk)
1598  deallocate (nboundchk)
1599  !
1600  if (count_errors() > 0) then
1601  call store_error_filename(this%input_fname)
1602  end if
1603  !
1604  ! -- release input context diversions memory; DIVFLOW excluded
1605  call memorystore_release('DIVERSIONS_IFNO', this%input_mempath)
1606  call memorystore_release('DIVERSIONS_IDV', this%input_mempath)
1607  call memorystore_release('ICONR', this%input_mempath)
1608  call memorystore_release('CPRIOR', this%input_mempath)
1609  end subroutine sfr_source_diversions
1610 
1611  !> @brief Source INITIALSTAGES block from input context
1612  !<
1613  subroutine sfr_source_initialstages(this)
1614  ! -- modules
1616  ! -- dummy
1617  class(sfrtype), intent(inout) :: this !< SfrType object
1618  ! -- local
1619  integer(I4B), dimension(:), pointer, contiguous :: is_ifno => null()
1620  real(DP), dimension(:), pointer, contiguous :: is_stage => null()
1621  integer(I4B) :: i, n
1622  integer(I4B) :: isize
1623  integer(I4B), allocatable :: nboundchk(:)
1624  real(DP) :: rval
1625  !
1626  ! -- check if INITIALSTAGES block was loaded (optional block)
1627  call get_isize('INITSTAGE_IFNO', this%input_mempath, isize)
1628  if (isize < 1) then
1629  ! -- set default initial stage to reach top if STORAGE active
1630  if (this%istorage == 1) then
1631  do n = 1, this%maxbound
1632  this%stage(n) = this%strtop(n)
1633  end do
1634  end if
1635  return
1636  end if
1637  !
1638  write (this%iout, '(/1x,a)') &
1639  'PROCESSING '//trim(adjustl(this%text))//' INITIALSTAGES'
1640  !
1641  call mem_setptr(is_ifno, 'INITSTAGE_IFNO', this%input_mempath)
1642  call mem_setptr(is_stage, 'INITIALSTAGE', this%input_mempath)
1643  !
1644  allocate (nboundchk(this%maxbound))
1645  nboundchk = 0
1646  !
1647  do i = 1, isize
1648  n = this%validate_ifno(is_ifno(i), this%maxbound, nboundchk, &
1649  'reach', 'INITIALSTAGES')
1650  if (n == 0) cycle
1651  rval = is_stage(i)
1652  this%stage(n) = rval
1653  this%depth(n) = rval - this%strtop(n)
1654  if (rval < this%strtop(n)) then
1655  write (errmsg, '(a,g0,a,1x,i0,1x,a,g0,a)') &
1656  'Initial stage (', rval, ') for reach', n, &
1657  'is less than the reach top (', this%strtop(n), ').'
1658  call store_error(errmsg)
1659  end if
1660  end do
1661  !
1662  write (this%iout, '(1x,a)') &
1663  'END OF '//trim(adjustl(this%text))//' INITIALSTAGES'
1664  !
1665  call this%report_ifno_coverage(nboundchk, this%maxbound, 'reach', &
1666  'INITIALSTAGES')
1667  deallocate (nboundchk)
1668  !
1669  if (count_errors() > 0) then
1670  call store_error_filename(this%input_fname)
1671  end if
1672  !
1673  ! -- release input context initialstages memory
1674  call memorystore_release('INITSTAGE_IFNO', this%input_mempath)
1675  call memorystore_release('INITIALSTAGE', this%input_mempath)
1676  end subroutine sfr_source_initialstages
1677 
1678  !> @ brief Allocate and read method for package
1679  !!
1680  !! Method to read and prepare period data for the SFR package.
1681  !<
1682  subroutine sfr_ar(this)
1683  ! -- modules
1684  use tdismodule, only: inats
1685  ! -- dummy
1686  class(sfrtype), intent(inout) :: this !< SfrType object
1687  ! -- local
1688  integer(I4B) :: n
1689  integer(I4B) :: ierr
1690  !
1691  ! -- allocate and read observations
1692  call this%obs%obs_ar()
1693  !
1694  ! -- allocate BndType connection-level arrays (nodelist, bound, auxvar, etc.)
1695  call this%BndExtType%allocate_arrays()
1696  !
1697  ! -- allocate featureauxvar and set pkg_ifno/pkg_auxvar input context
1698  ! pointers
1699  call this%BndExtType%allocate_featureauxvar()
1700  !
1701  ! -- set persistent PERIOD pointers into input context (valid for
1702  ! simulation lifetime)
1703  call this%input%init(this%input_mempath, this%naux)
1704  !
1705  ! -- set boundname for each connection
1706  if (this%inamedbound /= 0) then
1707  do n = 1, this%maxbound
1708  this%boundname(n) = this%sfrname(n)
1709  end do
1710  end if
1711  !
1712  ! -- copy boundname into boundname_cst
1713  call this%copy_boundname()
1714  !
1715  ! -- copy igwfnode into nodelist
1716  do n = 1, this%maxbound
1717  this%nodelist(n) = this%igwfnode(n)
1718  end do
1719  !
1720  ! -- check the sfr unit conversion data
1721  call this%sfr_check_conversion()
1722  !
1723  ! -- check the storage_weight
1724  call this%sfr_check_storage_weight()
1725  !
1726  ! -- check that ATS_COURANT is only used with STORAGE
1727  if (this%ats_courant /= dnodata .and. this%istorage /= 1) then
1728  write (errmsg, '(a)') &
1729  'ATS_COURANT OPTION REQUIRES STORAGE OPTION TO BE ACTIVE'
1730  call store_error(errmsg)
1731  end if
1732  !
1733  ! -- warn when ATS_COURANT is specified but ATS is not active in TDIS
1734  if (this%ats_courant /= dnodata .and. inats == 0) then
1735  write (warnmsg, '(a)') &
1736  'ATS_COURANT IS SPECIFIED IN THE SFR OPTIONS BLOCK BUT THE '// &
1737  'ATS PACKAGE IS NOT ACTIVE IN TDIS, SO THE TIME STEP IS NOT '// &
1738  'ADAPTED TO THE COURANT NUMBER. IF THE COURANT NUMBER EXCEEDS 1 '// &
1739  'THE EXPLICIT KINEMATIC-WAVE ROUTING MAY OSCILLATE WHILE STILL '// &
1740  'CLOSING THE BUDGET. ACTIVATE THE ATS PACKAGE OR USE A SMALLER '// &
1741  'TIME STEP.'
1742  call store_warning(warnmsg)
1743  end if
1744  !
1745  ! -- pre-compute TVD upstream connectivity when ATS_COURANT is active
1746  if (this%ats_courant /= dnodata .and. this%istorage == 1) then
1747  call this%sfr_precompute_tvd()
1748  end if
1749  !
1750  ! -- check the sfr reach data
1751  call this%sfr_check_reaches()
1752 
1753  ! -- check the connection data
1754  call this%sfr_check_connections()
1755 
1756  ! -- check the diversion data
1757  if (this%idiversions /= 0) then
1758  call this%sfr_check_diversions()
1759  end if
1760 
1761  ! -- check the diversion data
1762  if (this%istorage == 1) then
1763  call this%sfr_check_initialstages()
1764  end if
1765  !
1766  ! -- terminate if errors were detected in any of the static sfr data
1767  ierr = count_errors()
1768  if (ierr > 0) then
1769  call store_error_filename(this%input_fname)
1770  end if
1771  !
1772  ! -- setup pakmvrobj
1773  if (this%imover /= 0) then
1774  allocate (this%pakmvrobj)
1775  call this%pakmvrobj%ar(this%maxbound, this%maxbound, this%memoryPath)
1776  end if
1777  end subroutine sfr_ar
1778 
1779  !> @ brief Read and prepare period data for package
1780  !!
1781  !! Method to read and prepare period data for the SFR package.
1782  !<
1783  subroutine sfr_rp(this)
1784  ! -- modules
1785  use constantsmodule, only: lenvarname
1786  use tdismodule, only: kper
1789  ! -- dummy
1790  class(sfrtype), intent(inout) :: this !< SfrType object
1791  ! -- local
1792  character(len=LINELENGTH) :: crossfile
1793  character(len=LINELENGTH) :: str
1794  real(DP) :: auxvaldbl
1795  character(len=LINELENGTH) :: title
1796  character(len=LINELENGTH) :: text
1797  character(len=LENVARNAME) :: setting
1798  character(len=10) :: cnum
1799  character(len=10) :: cp
1800  integer(I4B) :: n
1801  integer(I4B) :: i
1802  integer(I4B) :: ii
1803  integer(I4B) :: jj
1804  integer(I4B) :: idiv
1805  integer(I4B) :: ichkustrm
1806  integer(I4B) :: ncrossptstot
1807  type(sfrcrosssection), pointer :: cross_data => null()
1808  ! -- formats
1809  character(len=*), parameter :: fmtlsp = &
1810  &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')"
1811  !
1812  ! -- initialize flags
1813  ichkustrm = 0
1814  if (kper == 1) then
1815  ichkustrm = 1
1816  end if
1817  !
1818  ! -- set nbound to maxbound
1819  this%nbound = this%maxbound
1820  !
1821  ! -- check if input context has been updated for this stress period
1822  if (this%iper == kper) then
1823  !
1824  ! -- create and initialize cross-section data
1825  call cross_section_cr(cross_data, this%iout, this%iprpak, this%maxbound)
1826  call cross_data%initialize(this%ncrossptstot, this%ncrosspts, &
1827  this%iacross, &
1828  this%station, this%xsheight, &
1829  this%xsrough)
1830  !
1831  ! -- setup table to echo period data
1832  if (this%iprpak /= 0) then
1833  title = trim(adjustl(this%text))//' PACKAGE ('// &
1834  trim(adjustl(this%packName))//') DATA FOR PERIOD'
1835  write (title, '(a,1x,i6)') trim(adjustl(title)), kper
1836  call table_cr(this%inputtab, this%packName, title)
1837  call this%inputtab%table_df(1, 4, this%iout, finalize=.false.)
1838  text = 'NUMBER'
1839  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
1840  text = 'KEYWORD'
1841  call this%inputtab%initialize_column(text, 20, alignment=tableft)
1842  do jj = 1, 2
1843  write (text, '(a,1x,i6)') 'VALUE', jj
1844  call this%inputtab%initialize_column(text, 15, alignment=tabcenter)
1845  end do
1846  end if
1847  !
1848  ! -- process each period data entry
1849  do i = 1, this%input%nbound
1850  n = this%input%ifno(i)
1851  if (n < 1 .or. n > this%maxbound) then
1852  write (errmsg, '(a,1x,a,1x,i0,a)') &
1853  'Reach number (RNO) must be greater than 0 and', &
1854  'less than or equal to', this%maxbound, '.'
1855  call store_error(errmsg)
1856  cycle
1857  end if
1858  !
1859  ! -- dispatch key for this row
1860  setting = this%input%setting(i)
1861  !
1862  ! -- STATUS
1863  if (trim(setting) == 'STATUS') then
1864  str = this%input%status(i)
1865  ichkustrm = 1
1866  if (str == 'INACTIVE') then
1867  this%iboundpak(n) = 0
1868  else if (str == 'ACTIVE') then
1869  this%iboundpak(n) = 1
1870  else if (str == 'SIMPLE') then
1871  this%iboundpak(n) = -1
1872  else
1873  write (errmsg, '(2a)') &
1874  'Unknown '//trim(this%text)//' sfr status keyword: ', trim(str)
1875  call store_error(errmsg)
1876  end if
1877  end if
1878  !
1879  ! -- BEDK, MANNING, STAGE, INFLOW, RAINFALL, EVAPORATION, RUNOFF,
1880  ! UPSTREAM_FRAC; sfr_ad re-syncs these each timestep if TS-linked
1881  call this%sfr_set_period_value(i, n, setting)
1882  if (trim(setting) == 'UPSTREAM_FRAC') ichkustrm = 1
1883  !
1884  ! -- DIVERSION (compound group)
1885  if (trim(setting) == 'DIVERSION') then
1886  if (this%ndiv(n) < 1) then
1887  write (cnum, '(i0)') n
1888  errmsg = 'diversions cannot be specified for reach '//trim(cnum)
1889  call store_error(errmsg)
1890  else
1891  idiv = this%input%idv(i)
1892  if (idiv < 1 .or. idiv > this%ndiv(n)) then
1893  write (cnum, '(i0)') n
1894  errmsg = 'Reach '//trim(cnum)
1895  write (cnum, '(i0)') this%ndiv(n)
1896  errmsg = trim(errmsg)//' diversion number should be between 1 '// &
1897  'and '//trim(cnum)//'.'
1898  call store_error(errmsg)
1899  else
1900  ii = this%iadiv(n) + idiv - 1
1901  ! -- if cprior is 'FRACTION', check 0.0 <= divflow <= 1.0
1902  cp = this%divcprior(ii)
1903  if (cp == 'FRACTION' .and. &
1904  (this%divflow(ii) < dzero .or. this%divflow(ii) > done)) then
1905  write (errmsg, '(a,1x,i0,a)') &
1906  'cprior is type FRACTION for diversion no.', ii, &
1907  ', but divflow not within the range 0.0 to 1.0'
1908  call store_error(errmsg)
1909  end if
1910  end if
1911  end if
1912  end if
1913  !
1914  ! -- CROSS_SECTION (compound group)
1915  if (trim(setting) == 'CROSS_SECTION') then
1916  crossfile = this%input%tab6_filename(i)
1917  call cross_data%read_table(n, this%width(n), trim(adjustl(crossfile)))
1918  end if
1919  !
1920  ! -- AUXILIARY (compound group): featureauxvar already holds the
1921  ! -- current value; only extract auxname for echoing this row
1922  if (this%naux > 0) then
1923  if (trim(setting) == 'PERIOD_AUXILIARY') then
1924  str = this%input%auxname(i)
1925  auxvaldbl = this%input%auxval(i)
1926  end if
1927  end if
1928  !
1929  ! -- echo row to period data table
1930  if (this%iprpak /= 0) then
1931  call this%inputtab%add_term(n)
1932  if (trim(setting) == 'PERIOD_AUXILIARY') then
1933  call this%inputtab%add_term('AUXILIARY')
1934  else
1935  call this%inputtab%add_term(trim(setting))
1936  end if
1937  select case (trim(setting))
1938  case ('STATUS')
1939  call this%inputtab%add_term(trim(str))
1940  call this%inputtab%add_term(' ')
1941  case ('BEDK')
1942  call this%inputtab%add_term(this%hk(n))
1943  call this%inputtab%add_term(' ')
1944  case ('MANNING')
1945  call this%inputtab%add_term(this%rough(n))
1946  call this%inputtab%add_term(' ')
1947  case ('STAGE')
1948  call this%inputtab%add_term(this%sstage(n))
1949  call this%inputtab%add_term(' ')
1950  case ('INFLOW')
1951  call this%inputtab%add_term(this%inflow(n))
1952  call this%inputtab%add_term(' ')
1953  case ('RAINFALL')
1954  call this%inputtab%add_term(this%rain(n))
1955  call this%inputtab%add_term(' ')
1956  case ('EVAPORATION')
1957  call this%inputtab%add_term(this%evap(n))
1958  call this%inputtab%add_term(' ')
1959  case ('RUNOFF')
1960  call this%inputtab%add_term(this%runoff(n))
1961  call this%inputtab%add_term(' ')
1962  case ('UPSTREAM_FRAC')
1963  call this%inputtab%add_term(this%ustrf(n))
1964  call this%inputtab%add_term(' ')
1965  case ('DIVERSION')
1966  call this%inputtab%add_term(idiv)
1967  call this%inputtab%add_term(this%divflow(ii))
1968  case ('CROSS_SECTION')
1969  call this%inputtab%add_term(trim(crossfile))
1970  call this%inputtab%add_term(' ')
1971  case ('PERIOD_AUXILIARY')
1972  call this%inputtab%add_term(trim(str))
1973  call this%inputtab%add_term(auxvaldbl)
1974  case default
1975  call this%inputtab%add_term(' ')
1976  call this%inputtab%add_term(' ')
1977  end select
1978  end if
1979  end do
1980  if (this%iprpak /= 0) then
1981  call this%inputtab%finalize_table()
1982  end if
1983  !
1984  ! -- determine the current size of cross-section data
1985  ncrossptstot = cross_data%get_ncrossptstot()
1986  !
1987  ! -- reallocate sfr package cross-section data if size changed
1988  if (ncrossptstot /= this%ncrossptstot) then
1989  this%ncrossptstot = ncrossptstot
1990  call mem_reallocate(this%station, this%ncrossptstot, 'STATION', &
1991  this%memoryPath)
1992  call mem_reallocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', &
1993  this%memoryPath)
1994  call mem_reallocate(this%xsrough, this%ncrossptstot, 'XSROUGH', &
1995  this%memoryPath)
1996  end if
1997  !
1998  ! -- write cross-section data to the model listing file
1999  call cross_data%output(this%width, this%rough, kstp=1, kper=kper)
2000  !
2001  ! -- pack cross-section data
2002  call cross_data%pack(this%ncrossptstot, this%ncrosspts, &
2003  this%iacross, &
2004  this%station, &
2005  this%xsheight, &
2006  this%xsrough)
2007  !
2008  ! -- deallocate temporary local storage for reach cross-sections
2009  call cross_data%destroy()
2010  deallocate (cross_data)
2011  nullify (cross_data)
2012  else
2013  write (this%iout, fmtlsp) trim(this%filtyp)
2014  end if
2015  !
2016  ! -- check upstream fraction values every period; ftotnd must be
2017  ! initialized for sfr_update_flows even when there is no period data
2018  if (ichkustrm /= 0) then
2019  call this%sfr_check_ustrf()
2020  end if
2021  !
2022  ! -- write summary of package block error messages
2023  if (count_errors() > 0) then
2024  call store_error_filename(this%input_fname)
2025  end if
2026  end subroutine sfr_rp
2027 
2028  !> @ brief Advance the package
2029  !!
2030  !! Advance data in the SFR package. The method sets advances
2031  !! time series, time array series, and observation data.
2032  !<
2033  subroutine sfr_ad(this)
2034  ! -- modules
2035  use constantsmodule, only: lenvarname
2036  ! -- dummy
2037  class(sfrtype) :: this !< SfrType object
2038  ! -- local
2039  integer(I4B) :: n
2040  integer(I4B) :: i
2041  integer(I4B) :: ii
2042  integer(I4B) :: idiv
2043  integer(I4B) :: iaux
2044  character(len=LENVARNAME) :: setting
2045 
2046  ! -- sync PACKAGEDATA AUX TS and advance observations;
2047  ! -- step auxvar period block overrides
2048  call this%BndExtType%bnd_ad()
2049  !
2050  ! -- update previous values
2051  if (this%istorage == 1) then
2052  do n = 1, this%maxbound
2053  this%stageold(n) = this%stage(n)
2054  this%usinflowold(n) = this%usinflow(n)
2055  this%dsflowold(n) = this%dsflow(n)
2056  end do
2057  end if
2058  !
2059  ! -- sync PACKAGEDATA and PERIOD TS fields from input context each
2060  ! timestep; skipped when no TS6 files are configured. PACKAGEDATA
2061  ! values are synced only for rows linked to a time series
2062  if (this%ts_active) then
2063  do i = 1, this%maxbound
2064  n = this%pkg_ifno(i)
2065  if (.not. this%bedk_set(n) .and. &
2066  this%input%rhk_tslink(i) /= 0) &
2067  this%hk(n) = this%input%rhk(i)
2068  if (.not. this%manning_set(n) .and. &
2069  this%input%man_tslink(i) /= 0) &
2070  this%rough(n) = this%input%man(i)
2071  if (.not. this%ustrf_set(n) .and. &
2072  this%input%ustrf_tslink(i) /= 0) &
2073  this%ustrf(n) = this%input%ustrf(i)
2074  end do
2075  !
2076  if (this%input%nbound > 0) then
2077  do i = 1, this%input%nbound
2078  n = this%input%ifno(i)
2079  if (n < 1 .or. n > this%maxbound) cycle
2080  ! -- BEDK, MANNING, UPSTREAM_FRAC, STAGE, INFLOW, RAINFALL, EVAPORATION, RUNOFF
2081  setting = this%input%setting(i)
2082  call this%sfr_set_period_value(i, n, setting)
2083  ! -- DIVFLOW
2084  if (trim(setting) == 'DIVERSION') then
2085  if (this%ndiv(n) >= 1) then
2086  idiv = this%input%idv(i)
2087  if (idiv >= 1 .and. idiv <= this%ndiv(n)) then
2088  ii = this%iadiv(n) + idiv - 1
2089  end if
2090  end if
2091  end if
2092  end do
2093  end if
2094  end if
2095  !
2096  ! -- check upstream fractions (only needed when USTRF may be TS-updated;
2097  ! sfr_rp already validates ustrf once per period via ichkustrm)
2098  if (this%ts_active) call this%sfr_check_ustrf()
2099  !
2100  ! -- update auxiliary variables by copying from the derived-type time
2101  ! series variable into the bndpackage auxvar variable so that this
2102  ! information is properly written to the GWF budget file
2103  if (this%naux > 0) then
2104  do n = 1, this%maxbound
2105  do iaux = 1, this%naux
2106  if (this%noupdateauxvar(iaux) /= 0) cycle
2107  this%auxvar(iaux, n) = this%featureauxvar(iaux, n)
2108  end do
2109  end do
2110  end if
2111  !
2112  ! -- reset upstream flow to zero and set specified stage
2113  do n = 1, this%maxbound
2114  this%usflow(n) = dzero
2115  if (this%iboundpak(n) < 0) then
2116  this%stage(n) = this%sstage(n)
2117  end if
2118  end do
2119  !
2120  ! -- pakmvrobj ad
2121  if (this%imover == 1) then
2122  call this%pakmvrobj%ad()
2123  end if
2124  end subroutine sfr_ad
2125 
2126  !> @ brief Formulate the package hcof and rhs terms.
2127  !!
2128  !! Formulate the hcof and rhs terms for the WEL package that will be
2129  !! added to the coefficient matrix and right-hand side vector.
2130  !<
2131  subroutine sfr_cf(this)
2132  ! -- dummy
2133  class(sfrtype) :: this !< SfrType object
2134  ! -- local
2135  integer(I4B) :: n
2136  integer(I4B) :: igwfnode
2137  !
2138  ! -- return if no sfr reaches
2139  if (this%nbound == 0) return
2140  !
2141  ! -- find highest active cell
2142  do n = 1, this%nbound
2143  igwfnode = this%igwftopnode(n)
2144  if (igwfnode > 0) then
2145  if (this%ibound(igwfnode) == 0) then
2146  call this%dis%highest_active(igwfnode, this%ibound)
2147  end if
2148  end if
2149  this%igwfnode(n) = igwfnode
2150  this%nodelist(n) = igwfnode
2151  end do
2152  end subroutine sfr_cf
2153 
2154  !> @ brief Copy hcof and rhs terms into solution.
2155  !!
2156  !! Add the hcof and rhs terms for the SFR package to the
2157  !! coefficient matrix and right-hand side vector.
2158  !<
2159  subroutine sfr_fc(this, rhs, ia, idxglo, matrix_sln)
2160  ! -- dummy
2161  class(sfrtype) :: this !< SfrType object
2162  real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model
2163  integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers
2164  integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global)
2165  class(matrixbasetype), pointer :: matrix_sln !< solution coefficient matrix
2166  ! -- local
2167  integer(I4B) :: i
2168  integer(I4B) :: j
2169  integer(I4B) :: n
2170  integer(I4B) :: ipos
2171  integer(I4B) :: node
2172  real(DP) :: s0
2173  real(DP) :: ds
2174  real(DP) :: dsmax
2175  real(DP) :: hgwf
2176  real(DP) :: v
2177  real(DP) :: hhcof
2178  real(DP) :: rrhs
2179  !
2180  ! -- picard iterations for sfr to achieve good solution regardless
2181  ! of reach order
2182  sfrpicard: do i = 1, this%maxsfrpicard
2183  !
2184  ! -- initialize maximum stage change for iteration to zero
2185  dsmax = dzero
2186  !
2187  ! -- pakmvrobj fc - reset qformvr to zero
2188  if (this%imover == 1) then
2189  call this%pakmvrobj%fc()
2190  end if
2191  !
2192  ! -- solve for each sfr reach
2193  reachsolve: do j = 1, this%nbound
2194  n = this%isfrorder(j)
2195  node = this%igwfnode(n)
2196  if (node > 0) then
2197  hgwf = this%xnew(node)
2198  else
2199  hgwf = dep20
2200  end if
2201  !
2202  ! -- save previous stage and upstream flow
2203  if (i == 1) then
2204  this%stage0(n) = this%stage(n)
2205  this%usflow0(n) = this%usflow(n)
2206  end if
2207  !
2208  ! -- set initial stage to calculate stage change
2209  s0 = this%stage(n)
2210  !
2211  ! -- solve for flow in swr
2212  if (this%iboundpak(n) /= 0) then
2213  call this%sfr_solve(n, hgwf, hhcof, rrhs)
2214  else
2215  this%depth(n) = dzero
2216  this%stage(n) = this%strtop(n)
2217  v = dzero
2218  call this%sfr_update_flows(n, v, v)
2219  hhcof = dzero
2220  rrhs = dzero
2221  end if
2222  !
2223  ! -- set package hcof and rhs
2224  this%hcof(n) = hhcof
2225  this%rhs(n) = rrhs
2226  !
2227  ! -- calculate stage change
2228  ds = s0 - this%stage(n)
2229  !
2230  ! -- evaluate if stage change exceeds dsmax
2231  if (abs(ds) > abs(dsmax)) then
2232  dsmax = ds
2233  end if
2234 
2235  end do reachsolve
2236  !
2237  ! -- evaluate if the sfr picard iterations should be terminated
2238  if (abs(dsmax) <= this%dmaxchg) then
2239  exit sfrpicard
2240  end if
2241 
2242  end do sfrpicard
2243  !
2244  ! -- Copy package rhs and hcof into solution rhs and amat
2245  do n = 1, this%nbound
2246  node = this%nodelist(n)
2247  if (node < 1) cycle
2248  rhs(node) = rhs(node) + this%rhs(n)
2249  ipos = ia(node)
2250  call matrix_sln%add_value_pos(idxglo(ipos), this%hcof(n))
2251  end do
2252  end subroutine sfr_fc
2253 
2254  !> @ brief Add Newton-Raphson terms for package into solution.
2255  !!
2256  !! Calculate and add the Newton-Raphson terms for the SFR package to the
2257  !! coefficient matrix and right-hand side vector.
2258  !<
2259  subroutine sfr_fn(this, rhs, ia, idxglo, matrix_sln)
2260  ! -- dummy
2261  class(sfrtype) :: this !< SfrType object
2262  real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model
2263  integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers
2264  integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global)
2265  class(matrixbasetype), pointer :: matrix_sln !< solution coefficient matrix
2266  ! -- local
2267  integer(I4B) :: i
2268  integer(I4B) :: j
2269  integer(I4B) :: n
2270  integer(I4B) :: ipos
2271  real(DP) :: rterm
2272  real(DP) :: drterm
2273  real(DP) :: rhs1
2274  real(DP) :: hcof1
2275  real(DP) :: q1
2276  real(DP) :: q2
2277  real(DP) :: hgwf
2278  !
2279  ! -- Copy package rhs and hcof into solution rhs and amat
2280  do j = 1, this%nbound
2281  i = this%isfrorder(j)
2282  ! -- skip inactive reaches
2283  if (this%iboundpak(i) < 1) cycle
2284  ! -- skip if reach is not connected to gwf
2285  n = this%nodelist(i)
2286  if (n < 1) cycle
2287  ipos = ia(n)
2288  rterm = this%hcof(i) * this%xnew(n)
2289  ! -- calculate perturbed head
2290  hgwf = this%xnew(n) + dem4
2291  call this%sfr_solve(i, hgwf, hcof1, rhs1, update=.false.)
2292  q1 = rhs1 - hcof1 * hgwf
2293  ! -- calculate unperturbed head
2294  q2 = this%rhs(i) - this%hcof(i) * this%xnew(n)
2295  ! -- calculate derivative
2296  drterm = (q2 - q1) / dem4
2297  ! -- add terms to convert conductance formulation into
2298  ! newton-raphson formulation
2299  call matrix_sln%add_value_pos(idxglo(ipos), drterm - this%hcof(i))
2300  rhs(n) = rhs(n) - rterm + drterm * this%xnew(n)
2301  end do
2302  end subroutine sfr_fn
2303 
2304  !> @ brief Convergence check for package.
2305  !!
2306  !! Perform additional convergence checks on the flow between the SFR package
2307  !! and the model it is attached to.
2308  !<
2309  subroutine sfr_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak)
2310  ! -- modules
2311  use tdismodule, only: totim, kstp, kper, delt
2312  ! -- dummy
2313  class(sfrtype), intent(inout) :: this !< SfrType object
2314  integer(I4B), intent(in) :: innertot !< total number of inner iterations
2315  integer(I4B), intent(in) :: kiter !< Picard iteration number
2316  integer(I4B), intent(in) :: iend !< flag indicating if this is the last Picard iteration
2317  integer(I4B), intent(in) :: icnvgmod !< flag inficating if the model has met specific convergence criteria
2318  character(len=LENPAKLOC), intent(inout) :: cpak !< string for user node
2319  integer(I4B), intent(inout) :: ipak !< location of the maximum dependent variable change
2320  real(DP), intent(inout) :: dpak !< maximum dependent variable change
2321  ! -- local
2322  character(len=LENPAKLOC) :: cloc
2323  character(len=LINELENGTH) :: tag
2324  integer(I4B) :: icheck
2325  integer(I4B) :: ipakfail
2326  integer(I4B) :: locdhmax
2327  integer(I4B) :: locrmax
2328  integer(I4B) :: locdqfrommvrmax
2329  integer(I4B) :: ntabrows
2330  integer(I4B) :: ntabcols
2331  integer(I4B) :: n
2332  real(DP) :: q
2333  real(DP) :: q0
2334  real(DP) :: qtolfact
2335  real(DP) :: dh
2336  real(DP) :: r
2337  real(DP) :: dhmax
2338  real(DP) :: rmax
2339  real(DP) :: dqfrommvr
2340  real(DP) :: dqfrommvrmax
2341  !
2342  ! -- initialize local variables
2343  icheck = this%iconvchk
2344  ipakfail = 0
2345  locdhmax = 0
2346  locrmax = 0
2347  r = dzero
2348  dhmax = dzero
2349  rmax = dzero
2350  locdqfrommvrmax = 0
2351  dqfrommvrmax = dzero
2352  !
2353  ! -- if not saving package convergence data on check convergence if
2354  ! the model is considered converged
2355  if (this%ipakcsv == 0) then
2356  if (icnvgmod == 0) then
2357  icheck = 0
2358  end if
2359  !
2360  ! -- saving package convergence data
2361  else
2362  !
2363  ! -- header for package csv
2364  if (.not. associated(this%pakcsvtab)) then
2365  !
2366  ! -- determine the number of columns and rows
2367  ntabrows = 1
2368  ntabcols = 9
2369  if (this%imover == 1) then
2370  ntabcols = ntabcols + 2
2371  end if
2372  !
2373  ! -- setup table
2374  call table_cr(this%pakcsvtab, this%packName, '')
2375  call this%pakcsvtab%table_df(ntabrows, ntabcols, this%ipakcsv, &
2376  lineseparator=.false., separator=',', &
2377  finalize=.false.)
2378  !
2379  ! -- add columns to package csv
2380  tag = 'total_inner_iterations'
2381  call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
2382  tag = 'totim'
2383  call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
2384  tag = 'kper'
2385  call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
2386  tag = 'kstp'
2387  call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
2388  tag = 'nouter'
2389  call this%pakcsvtab%initialize_column(tag, 10, alignment=tableft)
2390  tag = 'dvmax'
2391  call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
2392  tag = 'dvmax_loc'
2393  call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
2394  tag = 'dinflowmax'
2395  call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
2396  tag = 'dinflowmax_loc'
2397  call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
2398  if (this%imover == 1) then
2399  tag = 'dqfrommvrmax'
2400  call this%pakcsvtab%initialize_column(tag, 15, alignment=tableft)
2401  tag = 'dqfrommvrmax_loc'
2402  call this%pakcsvtab%initialize_column(tag, 16, alignment=tableft)
2403  end if
2404  end if
2405  end if
2406  !
2407  ! -- perform package convergence check
2408  if (icheck /= 0) then
2409  final_check: do n = 1, this%maxbound
2410  if (this%iboundpak(n) == 0) cycle
2411  !
2412  ! -- set the Q to length factor
2413  qtolfact = delt / this%calc_surface_area(n)
2414  !
2415  ! -- calculate stage change
2416  dh = this%stage0(n) - this%stage(n)
2417  !
2418  ! -- evaluate flow difference if the time step is transient
2419  if (this%gwfiss == 0) then
2420  r = this%usflow0(n) - this%usflow(n)
2421  !
2422  ! -- normalize flow difference and convert to a depth
2423  r = r * qtolfact
2424  end if
2425  !
2426  ! -- q from mvr
2427  dqfrommvr = dzero
2428  if (this%imover == 1) then
2429  q = this%pakmvrobj%get_qfrommvr(n)
2430  q0 = this%pakmvrobj%get_qfrommvr0(n)
2431  dqfrommvr = qtolfact * (q0 - q)
2432  end if
2433  !
2434  ! -- evaluate magnitude of differences
2435  if (n == 1) then
2436  locdhmax = n
2437  dhmax = dh
2438  locrmax = n
2439  rmax = r
2440  dqfrommvrmax = dqfrommvr
2441  locdqfrommvrmax = n
2442  else
2443  if (abs(dh) > abs(dhmax)) then
2444  locdhmax = n
2445  dhmax = dh
2446  end if
2447  if (abs(r) > abs(rmax)) then
2448  locrmax = n
2449  rmax = r
2450  end if
2451  if (abs(dqfrommvr) > abs(dqfrommvrmax)) then
2452  dqfrommvrmax = dqfrommvr
2453  locdqfrommvrmax = n
2454  end if
2455  end if
2456  end do final_check
2457  !
2458  ! -- set dpak and cpak
2459  if (abs(dhmax) > abs(dpak)) then
2460  ipak = locdhmax
2461  dpak = dhmax
2462  write (cloc, "(a,'-',a)") trim(this%packName), 'stage'
2463  cpak = trim(cloc)
2464  end if
2465  if (abs(rmax) > abs(dpak)) then
2466  ipak = locrmax
2467  dpak = rmax
2468  write (cloc, "(a,'-',a)") trim(this%packName), 'inflow'
2469  cpak = trim(cloc)
2470  end if
2471  if (this%imover == 1) then
2472  if (abs(dqfrommvrmax) > abs(dpak)) then
2473  ipak = locdqfrommvrmax
2474  dpak = dqfrommvrmax
2475  write (cloc, "(a,'-',a)") trim(this%packName), 'qfrommvr'
2476  cpak = trim(cloc)
2477  end if
2478  end if
2479  !
2480  ! -- write convergence data to package csv
2481  if (this%ipakcsv /= 0) then
2482  !
2483  ! -- write the data
2484  call this%pakcsvtab%add_term(innertot)
2485  call this%pakcsvtab%add_term(totim)
2486  call this%pakcsvtab%add_term(kper)
2487  call this%pakcsvtab%add_term(kstp)
2488  call this%pakcsvtab%add_term(kiter)
2489  call this%pakcsvtab%add_term(dhmax)
2490  call this%pakcsvtab%add_term(locdhmax)
2491  call this%pakcsvtab%add_term(rmax)
2492  call this%pakcsvtab%add_term(locrmax)
2493  if (this%imover == 1) then
2494  call this%pakcsvtab%add_term(dqfrommvrmax)
2495  call this%pakcsvtab%add_term(locdqfrommvrmax)
2496  end if
2497  !
2498  ! -- finalize the package csv
2499  if (iend == 1) then
2500  call this%pakcsvtab%finalize_table()
2501  end if
2502  end if
2503  end if
2504  end subroutine sfr_cc
2505 
2506  !> @ brief Calculate package flows.
2507  !!
2508  !! Calculate the flow between connected SFR package control volumes.
2509  !<
2510  subroutine sfr_cq(this, x, flowja, iadv)
2511  ! -- modules
2512  use budgetmodule, only: budgettype
2513  ! -- dummy
2514  class(sfrtype), intent(inout) :: this !< SfrType object
2515  real(DP), dimension(:), intent(in) :: x !< current dependent-variable value
2516  real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes
2517  integer(I4B), optional, intent(in) :: iadv !< flag that indicates if this is an advance package
2518  ! -- local
2519  integer(I4B) :: i
2520  real(DP) :: qext
2521  ! -- for budget
2522  integer(I4B) :: n
2523  integer(I4B) :: n2
2524  real(DP) :: qoutflow
2525  real(DP) :: qfrommvr
2526  real(DP) :: qtomvr
2527  !
2528  ! -- call base functionality in bnd_cq. This will calculate sfr-gwf flows
2529  ! and put them into this%simvals
2530  call this%BndType%bnd_cq(x, flowja, iadv=1)
2531  !
2532  ! -- Calculate qextoutflow and qoutflow for subsequent budgets
2533  do n = 1, this%maxbound
2534  !
2535  ! -- mover
2536  qfrommvr = dzero
2537  qtomvr = dzero
2538  if (this%imover == 1) then
2539  qfrommvr = this%pakmvrobj%get_qfrommvr(n)
2540  qtomvr = this%pakmvrobj%get_qtomvr(n)
2541  if (qtomvr > dzero) then
2542  qtomvr = -qtomvr
2543  end if
2544  end if
2545  !
2546  ! -- external downstream stream flow
2547  qext = this%dsflow(n)
2548  qoutflow = dzero
2549  if (qext > dzero) then
2550  qext = -qext
2551  end if
2552  do i = this%ia(n) + 1, this%ia(n + 1) - 1
2553  if (this%idir(i) > 0) cycle
2554  n2 = this%ja(i)
2555  if (this%iboundpak(n2) == 0) cycle
2556  qext = dzero
2557  exit
2558  end do
2559  !
2560  ! -- adjust external downstream stream flow using qtomvr
2561  if (qext < dzero) then
2562  if (qtomvr < dzero) then
2563  qext = qext - qtomvr
2564  end if
2565  else
2566  qoutflow = this%dsflow(n)
2567  if (qoutflow > dzero) then
2568  qoutflow = -qoutflow
2569  end if
2570  end if
2571  !
2572  ! -- set qextoutflow and qoutflow for cell by cell budget
2573  ! output and observations
2574  this%qextoutflow(n) = qext
2575  this%qoutflow(n) = qoutflow
2576  !
2577  end do
2578  !
2579  ! -- fill the budget object
2580  call this%sfr_fill_budobj()
2581  end subroutine sfr_cq
2582 
2583  !> @ brief Output package flow terms.
2584  !!
2585  !! Output SFR package flow terms.
2586  !<
2587  subroutine sfr_ot_package_flows(this, icbcfl, ibudfl)
2588  ! -- modules
2589  use tdismodule, only: kstp, kper, delt, pertim, totim
2590  ! -- dummy
2591  class(sfrtype) :: this !< SfrType object
2592  integer(I4B), intent(in) :: icbcfl !< flag and unit number for cell-by-cell output
2593  integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved
2594  ! -- local
2595  integer(I4B) :: ibinun
2596  character(len=20), dimension(:), allocatable :: cellidstr
2597  integer(I4B) :: n
2598  integer(I4B) :: node
2599  !
2600  ! -- write the flows from the budobj
2601  ibinun = 0
2602  if (this%ibudgetout /= 0) then
2603  ibinun = this%ibudgetout
2604  end if
2605  if (icbcfl == 0) ibinun = 0
2606  if (ibinun > 0) then
2607  call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, &
2608  pertim, totim, this%iout)
2609  end if
2610  !
2611  ! -- Print sfr flows table
2612  if (ibudfl /= 0 .and. this%iprflow /= 0) then
2613  !
2614  ! -- If there are any 'none' gwf connections then need to calculate
2615  ! a vector of cellids and pass that in to the budget flow table because
2616  ! the table assumes that there are maxbound gwf entries, which is not
2617  ! the case if any 'none's are specified.
2618  if (this%ianynone > 0) then
2619  allocate (cellidstr(this%maxbound))
2620  do n = 1, this%maxbound
2621  node = this%igwfnode(n)
2622  if (node > 0) then
2623  call this%dis%noder_to_string(node, cellidstr(n))
2624  else
2625  cellidstr(n) = 'NONE'
2626  end if
2627  end do
2628  call this%budobj%write_flowtable(this%dis, kstp, kper, cellidstr)
2629  deallocate (cellidstr)
2630  else
2631  call this%budobj%write_flowtable(this%dis, kstp, kper)
2632  end if
2633  end if
2634  end subroutine sfr_ot_package_flows
2635 
2636  !> @ brief Output package dependent-variable terms.
2637  !!
2638  !! Output SFR boundary package dependent-variable terms.
2639  !<
2640  subroutine sfr_ot_dv(this, idvsave, idvprint)
2641  ! -- modules
2642  use tdismodule, only: kstp, kper, pertim, totim
2643  use inputoutputmodule, only: ulasav
2644  ! -- dummy
2645  class(sfrtype) :: this !< SfrType object
2646  integer(I4B), intent(in) :: idvsave !< flag and unit number for dependent-variable output
2647  integer(I4B), intent(in) :: idvprint !< flag indicating if dependent-variable should be written to the model listing file
2648  ! -- local
2649  character(len=20) :: cellid
2650  integer(I4B) :: ibinun
2651  integer(I4B) :: n
2652  integer(I4B) :: node
2653  real(DP) :: d
2654  real(DP) :: v
2655  real(DP) :: hgwf
2656  real(DP) :: sbot
2657  real(DP) :: depth
2658  real(DP) :: stage
2659  real(DP) :: w
2660  real(DP) :: cond
2661  real(DP) :: grad
2662  !
2663  ! -- set unit number for binary dependent variable output
2664  ibinun = 0
2665  if (this%istageout /= 0) then
2666  ibinun = this%istageout
2667  end if
2668  if (idvsave == 0) ibinun = 0
2669  !
2670  ! -- write sfr binary output
2671  if (ibinun > 0) then
2672  do n = 1, this%maxbound
2673  d = this%depth(n)
2674  v = this%stage(n)
2675  if (this%iboundpak(n) == 0) then
2676  v = dhnoflo
2677  else if (d == dzero) then
2678  v = dhdry
2679  end if
2680  this%dbuff(n) = v
2681  end do
2682  call ulasav(this%dbuff, ' STAGE', kstp, kper, pertim, totim, &
2683  this%maxbound, 1, 1, ibinun)
2684  end if
2685  !
2686  ! -- print sfr stage and depth table
2687  if (idvprint /= 0 .and. this%iprhed /= 0) then
2688  !
2689  ! -- set table kstp and kper
2690  call this%stagetab%set_kstpkper(kstp, kper)
2691  !
2692  ! -- fill stage data
2693  do n = 1, this%maxbound
2694  node = this%igwfnode(n)
2695  if (node > 0) then
2696  call this%dis%noder_to_string(node, cellid)
2697  hgwf = this%xnew(node)
2698  else
2699  cellid = 'NONE'
2700  end if
2701  if (this%inamedbound == 1) then
2702  call this%stagetab%add_term(this%boundname(n))
2703  end if
2704  call this%stagetab%add_term(n)
2705  call this%stagetab%add_term(cellid)
2706  if (this%iboundpak(n) /= 0) then
2707  depth = this%depth(n)
2708  stage = this%stage(n)
2709  w = this%calc_top_width_wet(n, depth)
2710  call this%sfr_calc_cond(n, depth, cond, stage, hgwf)
2711  else
2712  depth = dhnoflo
2713  stage = dhnoflo
2714  w = dhnoflo
2715  cond = dhnoflo
2716  end if
2717  if (depth == dzero) then
2718  call this%stagetab%add_term(dhdry)
2719  else
2720  call this%stagetab%add_term(stage)
2721  end if
2722  call this%stagetab%add_term(depth)
2723  call this%stagetab%add_term(w)
2724  if (node > 0) then
2725  if (this%iboundpak(n) /= 0) then
2726  sbot = this%strtop(n) - this%bthick(n)
2727  if (hgwf < sbot) then
2728  grad = stage - sbot
2729  else
2730  grad = stage - hgwf
2731  end if
2732  grad = grad / this%bthick(n)
2733  else
2734  grad = dhnoflo
2735  end if
2736  call this%stagetab%add_term(hgwf)
2737  call this%stagetab%add_term(cond)
2738  call this%stagetab%add_term(grad)
2739  else
2740  call this%stagetab%add_term('--')
2741  call this%stagetab%add_term('--')
2742  call this%stagetab%add_term('--')
2743  end if
2744  end do
2745  end if
2746  end subroutine sfr_ot_dv
2747 
2748  !> @ brief Output advanced package budget summary.
2749  !!
2750  !! Output SFR package budget summary.
2751  !<
2752  subroutine sfr_ot_bdsummary(this, kstp, kper, iout, ibudfl)
2753  ! -- module
2754  use tdismodule, only: totim, delt
2755  ! -- dummy
2756  class(sfrtype) :: this !< SfrType object
2757  integer(I4B), intent(in) :: kstp !< time step number
2758  integer(I4B), intent(in) :: kper !< period number
2759  integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file
2760  integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written
2761  !
2762  call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim, delt)
2763  end subroutine sfr_ot_bdsummary
2764 
2765  !> @brief Write the Courant-number summary table to the listing file
2766  !<
2767  subroutine sfr_fp(this)
2768  ! -- dummy
2769  class(sfrtype) :: this !< SfrType object
2770  ! -- local
2771  integer(I4B) :: n
2772  real(DP) :: crmean
2773  !
2774  if (this%istorage == 1) then
2775  do n = 1, this%maxbound
2776  if (this%inamedbound == 1) then
2777  call this%couranttab%add_term(this%boundname(n))
2778  end if
2779  call this%couranttab%add_term(n)
2780  if (this%crmin(n) == dep20) then
2781  call this%couranttab%add_term('--')
2782  else
2783  call this%couranttab%add_term(this%crmin(n))
2784  end if
2785  if (this%crmax(n) < dzero) then
2786  call this%couranttab%add_term('--')
2787  else
2788  call this%couranttab%add_term(this%crmax(n))
2789  end if
2790  if (this%crcnt(n) > 0) then
2791  crmean = this%crsum(n) / real(this%crcnt(n), dp)
2792  call this%couranttab%add_term(crmean)
2793  else
2794  call this%couranttab%add_term('--')
2795  end if
2796  end do
2797  end if
2798  end subroutine sfr_fp
2799 
2800  !> @brief Submit the ATS time step for the most Courant-constraining reach
2801  !<
2802  subroutine sfr_dt(this)
2803  ! -- modules
2804  use tdismodule, only: kstp, kper, ats
2805  ! -- dummy
2806  class(sfrtype) :: this !< SfrType object
2807  ! -- local
2808  integer(I4B) :: n
2809  integer(I4B) :: nrmin
2810  real(DP) :: celerity
2811  real(DP) :: dt_n
2812  real(DP) :: dtmin
2813  character(len=LINELENGTH) :: msg
2814  !
2815  if (this%ats_courant == dnodata) return
2816  if (this%istorage /= 1) return
2817  !
2818  dtmin = dnodata
2819  nrmin = 0
2820  !
2821  do n = 1, this%maxbound
2822  call this%sfr_calc_celerity(n, this%dsflow(n), celerity)
2823  if (celerity > dzero) then
2824  dt_n = this%ats_courant * this%length(n) / celerity
2825  if (dt_n < dtmin) then
2826  dtmin = dt_n
2827  nrmin = n
2828  end if
2829  end if
2830  end do
2831  !
2832  if (nrmin > 0) then
2833  write (msg, '(a,i0)') trim(this%packName)//'-REACH-', nrmin
2834  call ats%ats_submit_delt(kstp, kper, dtmin, trim(msg))
2835  end if
2836  end subroutine sfr_dt
2837 
2838  !> @brief Kinematic-wave celerity from a flow perturbation (0 if dry)
2839  !<
2840  subroutine sfr_calc_celerity(this, n, q, celerity)
2841  ! -- dummy
2842  class(sfrtype) :: this !< SfrType object
2843  integer(I4B), intent(in) :: n !< reach number
2844  real(DP), intent(in) :: q !< reach flow
2845  real(DP), intent(out) :: celerity !< kinematic-wave celerity
2846  ! -- local
2847  real(DP) :: d
2848  real(DP) :: a
2849  real(DP) :: a2
2850  !
2851  celerity = dzero
2852  call this%sfr_calc_reach_depth(n, q, d)
2853  if (d > dzero) then
2854  a = this%calc_area_wet(n, d)
2855  call this%sfr_calc_reach_depth(n, q + this%deps, d)
2856  a2 = this%calc_area_wet(n, d)
2857  if (a2 > a) then
2858  celerity = this%deps / (a2 - a)
2859  end if
2860  end if
2861  end subroutine sfr_calc_celerity
2862 
2863  !> @ brief Deallocate package memory
2864  !!
2865  !! Deallocate SFR package scalars and arrays.
2866  !<
2867  subroutine sfr_da(this)
2868  ! -- modules
2870  ! -- dummy
2871  class(sfrtype) :: this !< SfrType object
2872  !
2873  ! -- deallocate arrays
2874  call mem_deallocate(this%qoutflow)
2875  call mem_deallocate(this%qextoutflow)
2876  deallocate (this%csfrbudget)
2877  call mem_deallocate(this%sfrname, 'SFRNAME', this%memoryPath)
2878  call mem_deallocate(this%dbuff)
2879  deallocate (this%cauxcbc)
2880  call mem_deallocate(this%qauxcbc)
2881  call mem_deallocate(this%iboundpak)
2882  call mem_deallocate(this%igwfnode)
2883  call mem_deallocate(this%igwftopnode)
2884  call mem_deallocate(this%length)
2885  call mem_deallocate(this%width)
2886  call mem_deallocate(this%strtop)
2887  call mem_deallocate(this%bthick)
2888  call mem_deallocate(this%slope)
2889  call mem_deallocate(this%nconnreach)
2890  call mem_deallocate(this%bedk_set)
2891  call mem_deallocate(this%manning_set)
2892  call mem_deallocate(this%ustrf_set)
2893  call mem_deallocate(this%ftotnd)
2894  call mem_deallocate(this%usflow)
2895  call mem_deallocate(this%dsflow)
2896  call mem_deallocate(this%depth)
2897  call mem_deallocate(this%stage)
2898  call mem_deallocate(this%gwflow)
2899  call mem_deallocate(this%simevap)
2900  call mem_deallocate(this%simrunoff)
2901  call mem_deallocate(this%stage0)
2902  call mem_deallocate(this%usflow0)
2903  call mem_deallocate(this%denseterms)
2904  call mem_deallocate(this%viscratios)
2905  !
2906  ! -- stage, usflow, and dsflow for previous timestep
2907  if (this%istorage == 1) then
2908  call mem_deallocate(this%stageold)
2909  call mem_deallocate(this%dsflowold)
2910  call mem_deallocate(this%storage)
2911  call mem_deallocate(this%usinflow)
2912  call mem_deallocate(this%usinflowold)
2913  call mem_deallocate(this%crmin)
2914  call mem_deallocate(this%crmax)
2915  call mem_deallocate(this%crsum)
2916  call mem_deallocate(this%crcnt)
2917  call mem_deallocate(this%itvd_upstream)
2918  end if
2919  !
2920  ! -- deallocate reach order and connection data
2921  call mem_deallocate(this%isfrorder)
2922  call mem_deallocate(this%ia)
2923  call mem_deallocate(this%ja)
2924  call mem_deallocate(this%idir)
2925  call mem_deallocate(this%idiv)
2926  call mem_deallocate(this%qconn)
2927  !
2928  nullify (this%rain)
2929  nullify (this%evap)
2930  nullify (this%inflow)
2931  nullify (this%runoff)
2932  nullify (this%sstage)
2933  nullify (this%hk)
2934  nullify (this%rough)
2935  nullify (this%ustrf)
2936  !
2937  ! -- deallocate diversion variables
2938  call mem_deallocate(this%iadiv)
2939  call mem_deallocate(this%divreach)
2940  if (associated(this%divcprior)) then
2941  deallocate (this%divcprior)
2942  end if
2943  ! -- divflow is package-owned only when empty (no diversions); it is not
2944  ! associated if the simulation stopped before it was set
2945  if (associated(this%divflow)) then
2946  if (size(this%divflow) == 0) then
2947  call mem_deallocate(this%divflow)
2948  else
2949  nullify (this%divflow)
2950  end if
2951  end if
2952  call mem_deallocate(this%divq)
2953  call mem_deallocate(this%ndiv)
2954  !
2955  ! -- deallocate cross-section data
2956  call mem_deallocate(this%ncrosspts)
2957  call mem_deallocate(this%iacross)
2958  call mem_deallocate(this%station)
2959  call mem_deallocate(this%xsheight)
2960  call mem_deallocate(this%xsrough)
2961  !
2962  ! -- deallocate budobj
2963  call this%budobj%budgetobject_da()
2964  deallocate (this%budobj)
2965  nullify (this%budobj)
2966  !
2967  ! -- deallocate stage table
2968  if (this%iprhed > 0) then
2969  call this%stagetab%table_da()
2970  deallocate (this%stagetab)
2971  nullify (this%stagetab)
2972  end if
2973  !
2974  ! -- deallocate Courant number table
2975  if (associated(this%couranttab)) then
2976  call this%couranttab%table_da()
2977  deallocate (this%couranttab)
2978  nullify (this%couranttab)
2979  end if
2980  !
2981  ! -- deallocate package csv table
2982  if (this%ipakcsv > 0) then
2983  if (associated(this%pakcsvtab)) then
2984  call this%pakcsvtab%table_da()
2985  deallocate (this%pakcsvtab)
2986  nullify (this%pakcsvtab)
2987  end if
2988  end if
2989  !
2990  ! -- deallocate scalars
2991  call mem_deallocate(this%ats_courant)
2992  call mem_deallocate(this%istorage)
2993  call mem_deallocate(this%storage_weight)
2994  call mem_deallocate(this%iprhed)
2995  call mem_deallocate(this%istageout)
2996  call mem_deallocate(this%ibudgetout)
2997  call mem_deallocate(this%ibudcsv)
2998  call mem_deallocate(this%ipakcsv)
2999  call mem_deallocate(this%idiversions)
3000  call mem_deallocate(this%maxsfrpicard)
3001  call mem_deallocate(this%maxsfrit)
3002  call mem_deallocate(this%bditems)
3003  call mem_deallocate(this%cbcauxitems)
3004  call mem_deallocate(this%unitconv)
3005  call mem_deallocate(this%lengthconv)
3006  call mem_deallocate(this%timeconv)
3007  call mem_deallocate(this%dmaxchg)
3008  call mem_deallocate(this%deps)
3009  call mem_deallocate(this%nconn)
3010  call mem_deallocate(this%icheck)
3011  call mem_deallocate(this%iconvchk)
3012  call mem_deallocate(this%idense)
3013  call mem_deallocate(this%ianynone)
3014  call mem_deallocate(this%ncrossptstot)
3015  nullify (this%gwfiss)
3016  !
3017  ! -- nullify SFR input context pointers (input context owns the memory)
3018  call this%input%destroy()
3019  !
3020  ! -- call base BndExtType deallocate
3021  call this%BndExtType%bnd_da()
3022  end subroutine sfr_da
3023 
3024  !> @brief Pre-compute the single upstream reach index for the TVD limiter
3025  !!
3026  !! Index 0 for reaches with zero or multiple upstream connections.
3027  !<
3028  subroutine sfr_precompute_tvd(this)
3029  ! -- dummy
3030  class(sfrtype), intent(inout) :: this !< SfrType object
3031  ! -- local
3032  integer(I4B) :: n
3033  integer(I4B) :: j
3034  integer(I4B) :: iup_count
3035  integer(I4B) :: m
3036  !
3037  do n = 1, this%maxbound
3038  iup_count = 0
3039  m = 0
3040  do j = this%ia(n) + 1, this%ia(n + 1) - 1
3041  if (this%idir(j) > 0) then
3042  iup_count = iup_count + 1
3043  m = this%ja(j)
3044  end if
3045  end do
3046  if (iup_count == 1) then
3047  this%itvd_upstream(n) = m
3048  else
3049  this%itvd_upstream(n) = 0
3050  end if
3051  end do
3052  end subroutine sfr_precompute_tvd
3053 
3054  !> @ brief Define the list label for the package
3055  !!
3056  !! Method defined the list label for the SFR package. The list label is
3057  !! the heading that is written to iout when PRINT_INPUT option is used.
3058  !<
3059  subroutine define_listlabel(this)
3060  ! -- dummy
3061  class(sfrtype), intent(inout) :: this !< SfrType object
3062  !
3063  ! -- create the header list label
3064  this%listlabel = trim(this%filtyp)//' NO.'
3065  if (this%dis%ndim == 3) then
3066  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER'
3067  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW'
3068  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL'
3069  elseif (this%dis%ndim == 2) then
3070  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER'
3071  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D'
3072  else
3073  write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE'
3074  end if
3075  write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE'
3076  if (this%inamedbound == 1) then
3077  write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME'
3078  end if
3079  end subroutine define_listlabel
3080 
3081  !
3082  ! -- Procedures related to observations (type-bound)
3083 
3084  !> @brief Determine if observations are supported.
3085  !!
3086  !! Function to determine if observations are supported by the SFR package.
3087  !! Observations are supported by the SFR package.
3088  !!
3089  !! @return sfr_obs_supported boolean indicating if observations are supported
3090  !<
3091  logical function sfr_obs_supported(this)
3092  ! -- dummy
3093  class(sfrtype) :: this !< SfrType object
3094  !
3095  ! -- set boolean
3096  sfr_obs_supported = .true.
3097  end function sfr_obs_supported
3098 
3099  !> @brief Define the observation types available in the package
3100  !!
3101  !! Method to define the observation types available in the SFR package.
3102  !<
3103  subroutine sfr_df_obs(this)
3104  ! -- dummy
3105  class(sfrtype) :: this !< SfrType object
3106  ! -- local
3107  integer(I4B) :: indx
3108  !
3109  ! -- Store obs type and assign procedure pointer
3110  ! for stage observation type.
3111  call this%obs%StoreObsType('stage', .false., indx)
3112  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3113  !
3114  ! -- Store obs type and assign procedure pointer
3115  ! for inflow observation type.
3116  call this%obs%StoreObsType('inflow', .true., indx)
3117  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3118  !
3119  ! -- Store obs type and assign procedure pointer
3120  ! for inflow observation type.
3121  call this%obs%StoreObsType('ext-inflow', .true., indx)
3122  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3123  !
3124  ! -- Store obs type and assign procedure pointer
3125  ! for rainfall observation type.
3126  call this%obs%StoreObsType('rainfall', .true., indx)
3127  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3128  !
3129  ! -- Store obs type and assign procedure pointer
3130  ! for runoff observation type.
3131  call this%obs%StoreObsType('runoff', .true., indx)
3132  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3133  !
3134  ! -- Store obs type and assign procedure pointer
3135  ! for evaporation observation type.
3136  call this%obs%StoreObsType('evaporation', .true., indx)
3137  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3138  !
3139  ! -- Store obs type and assign procedure pointer
3140  ! for outflow observation type.
3141  call this%obs%StoreObsType('outflow', .true., indx)
3142  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3143  !
3144  ! -- Store obs type and assign procedure pointer
3145  ! for ext-outflow observation type.
3146  call this%obs%StoreObsType('ext-outflow', .true., indx)
3147  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3148  !
3149  ! -- Store obs type and assign procedure pointer
3150  ! for to-mvr observation type.
3151  call this%obs%StoreObsType('to-mvr', .true., indx)
3152  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3153  !
3154  ! -- Store obs type and assign procedure pointer
3155  ! for sfr-frommvr observation type.
3156  call this%obs%StoreObsType('from-mvr', .true., indx)
3157  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3158  !
3159  ! -- Store obs type and assign procedure pointer
3160  ! for sfr observation type.
3161  call this%obs%StoreObsType('sfr', .true., indx)
3162  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3163  !
3164  ! -- Store obs type and assign procedure pointer
3165  ! for upstream flow observation type.
3166  call this%obs%StoreObsType('upstream-flow', .true., indx)
3167  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3168  !
3169  ! -- Store obs type and assign procedure pointer
3170  ! for downstream flow observation type.
3171  call this%obs%StoreObsType('downstream-flow', .true., indx)
3172  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3173  !
3174  ! -- Store obs type and assign procedure pointer
3175  ! for depth observation type.
3176  call this%obs%StoreObsType('depth', .false., indx)
3177  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3178  !
3179  ! -- Store obs type and assign procedure pointer
3180  ! for wetted-perimeter observation type.
3181  call this%obs%StoreObsType('wet-perimeter', .false., indx)
3182  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3183  !
3184  ! -- Store obs type and assign procedure pointer
3185  ! for wetted-area observation type.
3186  call this%obs%StoreObsType('wet-area', .false., indx)
3187  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3188  !
3189  ! -- Store obs type and assign procedure pointer
3190  ! for wetted-width observation type.
3191  call this%obs%StoreObsType('wet-width', .false., indx)
3192  this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsid
3193  end subroutine sfr_df_obs
3194 
3195  !> @brief Save observations for the package
3196  !!
3197  !! Method to save simulated values for the SFR package.
3198  !<
3199  subroutine sfr_bd_obs(this)
3200  ! -- dummy
3201  class(sfrtype) :: this !< SfrType object
3202  ! -- local
3203  integer(I4B) :: i
3204  integer(I4B) :: j
3205  integer(I4B) :: n
3206  real(DP) :: v
3207  character(len=100) :: msg
3208  type(observetype), pointer :: obsrv => null()
3209  !
3210  ! Write simulated values for all sfr observations
3211  if (this%obs%npakobs > 0) then
3212  call this%obs%obs_bd_clear()
3213  do i = 1, this%obs%npakobs
3214  obsrv => this%obs%pakobs(i)%obsrv
3215  do j = 1, obsrv%indxbnds_count
3216  n = obsrv%indxbnds(j)
3217  v = dzero
3218  select case (obsrv%ObsTypeId)
3219  case ('STAGE')
3220  v = this%stage(n)
3221  case ('TO-MVR')
3222  v = dnodata
3223  if (this%imover == 1) then
3224  v = this%pakmvrobj%get_qtomvr(n)
3225  if (v > dzero) then
3226  v = -v
3227  end if
3228  end if
3229  case ('FROM-MVR')
3230  v = dnodata
3231  if (this%imover == 1) then
3232  v = this%pakmvrobj%get_qfrommvr(n)
3233  end if
3234  case ('EXT-INFLOW')
3235  v = this%inflow(n)
3236  case ('INFLOW')
3237  v = this%usflow(n)
3238  case ('OUTFLOW')
3239  v = this%qoutflow(n)
3240  case ('EXT-OUTFLOW')
3241  v = this%qextoutflow(n)
3242  case ('RAINFALL')
3243  if (this%iboundpak(n) /= 0) then
3244  v = this%rain(n)
3245  else
3246  v = dzero
3247  end if
3248  case ('RUNOFF')
3249  v = this%simrunoff(n)
3250  case ('EVAPORATION')
3251  v = this%simevap(n)
3252  case ('SFR')
3253  v = this%gwflow(n)
3254  case ('UPSTREAM-FLOW')
3255  v = this%usflow(n)
3256  if (this%imover == 1) then
3257  v = v + this%pakmvrobj%get_qfrommvr(n)
3258  end if
3259  case ('DOWNSTREAM-FLOW')
3260  v = this%dsflow(n)
3261  if (v > dzero) then
3262  v = -v
3263  end if
3264  case ('DEPTH')
3265  v = this%depth(n)
3266  case ('WET-PERIMETER')
3267  v = this%calc_perimeter_wet(n, this%depth(n))
3268  case ('WET-AREA')
3269  v = this%calc_area_wet(n, this%depth(n))
3270  case ('WET-WIDTH')
3271  v = this%calc_top_width_wet(n, this%depth(n))
3272  case default
3273  msg = 'Unrecognized observation type: '//trim(obsrv%ObsTypeId)
3274  call store_error(msg)
3275  end select
3276  call this%obs%SaveOneSimval(obsrv, v)
3277  end do
3278  end do
3279  !
3280  ! -- write summary of package error messages
3281  if (count_errors() > 0) then
3282  call store_error_filename(this%input_fname)
3283  end if
3284  end if
3285  end subroutine sfr_bd_obs
3286 
3287  !> @brief Read and prepare observations for a package
3288  !!
3289  !! Method to read and prepare observations for a SFR package.
3290  !<
3291  subroutine sfr_rp_obs(this)
3292  ! -- modules
3293  use tdismodule, only: kper
3294  ! -- dummy
3295  class(sfrtype), intent(inout) :: this !< SfrType object
3296  ! -- local
3297  integer(I4B) :: i
3298  integer(I4B) :: j
3299  integer(I4B) :: nn1
3300  character(len=LENBOUNDNAME) :: bname
3301  logical(LGP) :: jfound
3302  class(observetype), pointer :: obsrv => null()
3303  ! -- formats
3304 10 format('Boundary "', a, '" for observation "', a, &
3305  '" is invalid in package "', a, '"')
3306 30 format('Boundary name not provided for observation "', a, &
3307  '" in package "', a, '"')
3308  !
3309  ! -- process each package observation
3310  ! only done the first stress period since boundaries are fixed
3311  ! for the simulation
3312  if (kper == 1) then
3313  do i = 1, this%obs%npakobs
3314  obsrv => this%obs%pakobs(i)%obsrv
3315  !
3316  ! -- get node number 1
3317  nn1 = obsrv%NodeNumber
3318  if (nn1 == namedboundflag) then
3319  bname = obsrv%FeatureName
3320  if (bname /= '') then
3321  ! -- Observation location(s) is(are) based on a boundary name.
3322  ! Iterate through all boundaries to identify and store
3323  ! corresponding index(indices) in bound array.
3324  jfound = .false.
3325  if (this%inamedbound /= 0) then
3326  do j = 1, this%maxbound
3327  if (this%boundname(j) == bname) then
3328  jfound = .true.
3329  call obsrv%AddObsIndex(j)
3330  end if
3331  end do
3332  end if
3333  if (.not. jfound) then
3334  write (errmsg, 10) &
3335  trim(bname), trim(obsrv%name), trim(this%packName)
3336  call store_error(errmsg)
3337  end if
3338  else
3339  write (errmsg, 30) trim(obsrv%name), trim(this%packName)
3340  call store_error(errmsg)
3341  end if
3342  else if (nn1 < 1 .or. nn1 > this%maxbound) then
3343  write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') &
3344  trim(adjustl(obsrv%ObsTypeId)), &
3345  'reach must be greater than 0 and less than or equal to', &
3346  this%maxbound, '(specified value is ', nn1, ')'
3347  call store_error(errmsg)
3348  else
3349  if (obsrv%indxbnds_count == 0) then
3350  call obsrv%AddObsIndex(nn1)
3351  else
3352  errmsg = 'Programming error in sfr_rp_obs'
3353  call store_error(errmsg)
3354  end if
3355  end if
3356  !
3357  ! -- catch non-cumulative observation assigned to observation defined
3358  ! by a boundname that is assigned to more than one element
3359  if (obsrv%ObsTypeId == 'STAGE' .or. &
3360  obsrv%ObsTypeId == 'DEPTH' .or. &
3361  obsrv%ObsTypeId == 'WET-PERIMETER' .or. &
3362  obsrv%ObsTypeId == 'WET-AREA' .or. &
3363  obsrv%ObsTypeId == 'WET-WIDTH') then
3364  nn1 = obsrv%NodeNumber
3365  if (nn1 == namedboundflag) then
3366  if (obsrv%indxbnds_count > 1) then
3367  write (errmsg, '(a,3(1x,a))') &
3368  trim(adjustl(obsrv%ObsTypeId)), &
3369  'for observation', trim(adjustl(obsrv%Name)), &
3370  ' must be assigned to a reach with a unique boundname.'
3371  call store_error(errmsg)
3372  end if
3373  end if
3374  end if
3375  !
3376  ! -- check that node number 1 is valid; call store_error if not
3377  do j = 1, obsrv%indxbnds_count
3378  nn1 = obsrv%indxbnds(j)
3379  if (nn1 < 1 .or. nn1 > this%maxbound) then
3380  write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') &
3381  trim(adjustl(obsrv%ObsTypeId)), &
3382  'reach must be greater than 0 and less than or equal to', &
3383  this%maxbound, '(specified value is ', nn1, ')'
3384  call store_error(errmsg)
3385  end if
3386  end do
3387  end do
3388  !
3389  ! -- evaluate if there are any observation errors
3390  if (count_errors() > 0) then
3391  call store_error_filename(this%input_fname)
3392  end if
3393  end if
3394  end subroutine sfr_rp_obs
3395 
3396  !
3397  ! -- Procedures related to observations (NOT type-bound)
3398 
3399  !> @brief Process observation IDs for a package
3400  !!
3401  !! Method to process observation ID strings for a SFR package.
3402  !<
3403  subroutine sfr_process_obsid(obsrv, dis, inunitobs, iout)
3404  ! -- dummy
3405  type(observetype), intent(inout) :: obsrv !< Observation object
3406  class(disbasetype), intent(in) :: dis !< Discretization object
3407  integer(I4B), intent(in) :: inunitobs !< file unit number for the package observation file
3408  integer(I4B), intent(in) :: iout !< model listing file unit number
3409  ! -- local
3410  integer(I4B) :: nn1
3411  integer(I4B) :: icol
3412  integer(I4B) :: istart
3413  integer(I4B) :: istop
3414  character(len=LINELENGTH) :: string
3415  character(len=LENBOUNDNAME) :: bndname
3416  !
3417  ! -- initialize local variables
3418  string = obsrv%IDstring
3419  !
3420  ! -- Extract reach number from string and store it.
3421  ! If 1st item is not an integer(I4B), it should be a
3422  ! boundary name--deal with it.
3423  icol = 1
3424  !
3425  ! -- get reach number or boundary name
3426  call extract_idnum_or_bndname(string, icol, istart, istop, nn1, bndname)
3427  if (nn1 == namedboundflag) then
3428  obsrv%FeatureName = bndname
3429  end if
3430  !
3431  ! -- store reach number (NodeNumber)
3432  obsrv%NodeNumber = nn1
3433  end subroutine sfr_process_obsid
3434 
3435  !> @brief Solve reach continuity equation
3436  !!
3437  !! Method to solve the continuity equation for a SFR package reach.
3438  !<
3439  subroutine sfr_solve(this, n, h, hcof, rhs, update)
3440  ! -- dummy
3441  class(sfrtype) :: this !< SfrType object
3442  integer(I4B), intent(in) :: n !< reach number
3443  real(DP), intent(in) :: h !< groundwater head in cell connected to reach
3444  real(DP), intent(inout) :: hcof !< coefficient term added to the diagonal
3445  real(DP), intent(inout) :: rhs !< right-hand side term
3446  logical(LGP), intent(in), optional :: update !< boolean indicating if the reach depth and stage variables should be updated to current iterate
3447  ! -- local
3448  logical(LGP) :: lupdate
3449  integer(I4B) :: i
3450  integer(I4B) :: ii
3451  integer(I4B) :: n2
3452  real(DP) :: hgwf
3453  real(DP) :: sa
3454  real(DP) :: sa_wet
3455  real(DP) :: qu
3456  real(DP) :: qi
3457  real(DP) :: qr
3458  real(DP) :: qe
3459  real(DP) :: qro
3460  real(DP) :: qsrc
3461  real(DP) :: qfrommvr
3462  real(DP) :: qgwf
3463  real(DP) :: tp
3464  real(DP) :: bt
3465  real(DP) :: hsfr
3466  real(DP) :: qd
3467  real(DP) :: d1
3468  real(DP) :: sumleak
3469  real(DP) :: sumrch
3470  real(DP) :: gwfhcof
3471  real(DP) :: gwfrhs
3472  !
3473  ! -- Process optional dummy variables
3474  if (present(update)) then
3475  lupdate = update
3476  else
3477  lupdate = .true.
3478  end if
3479 
3480  ! -- initialize variables
3481  hcof = dzero
3482  rhs = dzero
3483  !
3484  if (this%iboundpak(n) == 0) then
3485  this%depth(n) = dzero
3486  this%stage(n) = dhnoflo
3487  this%usflow(n) = dzero
3488  this%simevap(n) = dzero
3489  this%simrunoff(n) = dzero
3490  this%dsflow(n) = dzero
3491  this%gwflow(n) = dzero
3492  else
3493  hgwf = h
3494  d1 = dzero
3495  qsrc = dzero
3496  qgwf = dzero
3497  qd = this%dsflow(n)
3498 
3499  ! -- calculate initial depth assuming a wide cross-section and
3500  ! ignore groundwater leakage
3501  ! -- calculate upstream flow
3502  qu = dzero
3503  do i = this%ia(n) + 1, this%ia(n + 1) - 1
3504  if (this%idir(i) < 0) cycle
3505  n2 = this%ja(i)
3506  do ii = this%ia(n2) + 1, this%ia(n2 + 1) - 1
3507  if (this%idir(ii) > 0) cycle
3508  if (this%ja(ii) /= n) cycle
3509  qu = qu + this%qconn(ii)
3510  end do
3511  end do
3512  this%usflow(n) = qu
3513 
3514  ! -- calculate remaining terms
3515  sa = this%calc_surface_area(n)
3516  sa_wet = this%calc_surface_area_wet(n, this%depth(n))
3517  qi = this%inflow(n)
3518  qr = this%rain(n) * sa
3519  qe = this%evap(n) * sa_wet
3520  qro = this%runoff(n)
3521 
3522  ! -- Water mover term; assume that it goes in at the upstream end of the reach
3523  qfrommvr = dzero
3524  if (this%imover == 1) then
3525  qfrommvr = this%pakmvrobj%get_qfrommvr(n)
3526  end if
3527 
3528  ! -- calculate downstream flow ignoring groundwater leakage
3529  qsrc = qu + qi + qr - qe + qro + qfrommvr
3530 
3531  ! -- adjust runoff or evaporation if sum of sources is negative
3532  call this%sfr_adjust_ro_ev(qsrc, qu, qi, qr, qro, qe, qfrommvr)
3533 
3534  ! -- set simulated evaporation and runoff
3535  this%simevap(n) = qe
3536  this%simrunoff(n) = qro
3537 
3538  ! -- calculate reach flow using appropriate method
3539  if (this%iboundpak(n) < 0) then
3540  call this%sfr_calc_constant(n, d1, hgwf, qgwf, qd)
3541  else
3542  if (this%gwfiss == 0 .and. this%istorage == 1) then
3543  if (this%ats_courant /= dnodata) then
3544  call this%sfr_calc_tvd(n, d1, hgwf, qu, qi, &
3545  qfrommvr, qr, qe, qro, &
3546  qgwf, qd)
3547  else
3548  call this%sfr_calc_transient(n, d1, hgwf, qu, qi, &
3549  qfrommvr, qr, qe, qro, &
3550  qgwf, qd)
3551  end if
3552  else
3553  call this%sfr_calc_steady(n, d1, hgwf, qu, qi, &
3554  qfrommvr, qr, qe, qro, &
3555  qgwf, qd)
3556  end if
3557  end if
3558 
3559  ! -- update sfr stage
3560  tp = this%strtop(n)
3561  bt = tp - this%bthick(n)
3562  hsfr = tp + d1
3563 
3564  ! -- update stored values
3565  if (lupdate) then
3566  ! -- save depth and calculate stage
3567  this%depth(n) = d1
3568  this%stage(n) = hsfr
3569  ! -- update flows
3570  call this%sfr_update_flows(n, qd, qgwf)
3571  end if
3572 
3573  ! -- calculate sumleak and sumrch
3574  sumleak = dzero
3575  sumrch = dzero
3576  if (this%gwfiss == 0) then
3577  sumleak = qgwf
3578  else
3579  sumleak = qgwf
3580  end if
3581  if (hgwf < bt) then
3582  sumrch = qgwf
3583  end if
3584 
3585  ! -- make final qgwf calculation and obtain
3586  ! gwfhcof and gwfrhs values
3587  call this%sfr_calc_qgwf(n, d1, hgwf, qgwf, gwfhcof, gwfrhs)
3588 
3589  ! -- update hcof and rhs terms
3590  if (abs(sumleak) > dzero) then
3591  ! -- stream leakage is not head dependent
3592  if (hgwf < bt) then
3593  rhs = rhs - sumrch
3594  ! -- stream leakage is head dependent
3595  else if ((sumleak - qsrc) < -dem30) then
3596  if (this%gwfiss == 0) then
3597  rhs = rhs + gwfrhs - sumrch
3598  else
3599  rhs = rhs + gwfrhs
3600  end if
3601  hcof = gwfhcof
3602  ! -- place holder for UZF
3603  else
3604  if (this%gwfiss == 0) then
3605  rhs = rhs - sumleak - sumrch
3606  else
3607  rhs = rhs - sumleak
3608  end if
3609  end if
3610 
3611  ! -- add groundwater leakage
3612  else if (hgwf < bt) then
3613  rhs = rhs - sumrch
3614  end if
3615  end if
3616  end subroutine sfr_solve
3617 
3618  !> @brief Update flow terms
3619  !!
3620  !! Method to update downstream flow and groundwater leakage terms for
3621  !! a SFR package reach.
3622  !<
3623  subroutine sfr_update_flows(this, n, qd, qgwf)
3624  ! -- dummy
3625  class(sfrtype), intent(inout) :: this !< SfrType object
3626  integer(I4B), intent(in) :: n !< reach number
3627  real(DP), intent(inout) :: qd !< downstream reach flow
3628  real(DP), intent(in) :: qgwf !< groundwater leakage for reach
3629  ! -- local
3630  integer(I4B) :: i
3631  integer(I4B) :: n2
3632  integer(I4B) :: idiv
3633  integer(I4B) :: jpos
3634  real(DP) :: qdiv
3635  real(DP) :: f
3636  !
3637  ! -- update reach terms
3638  !
3639  ! -- save final downstream stream flow
3640  this%dsflow(n) = qd
3641  !
3642  ! -- save groundwater leakage
3643  this%gwflow(n) = qgwf
3644  !
3645  ! -- route downstream flow
3646  if (qd > dzero) then
3647  !
3648  ! -- route water to diversions
3649  do i = this%ia(n) + 1, this%ia(n + 1) - 1
3650  if (this%idir(i) > 0) cycle
3651  idiv = this%idiv(i)
3652  if (idiv == 0) cycle
3653  jpos = this%iadiv(n) + idiv - 1
3654  call this%sfr_calc_div(n, idiv, qd, qdiv)
3655  this%qconn(i) = qdiv
3656  this%divq(jpos) = qdiv
3657  end do
3658  !
3659  ! -- Mover terms: store outflow after diversion loss
3660  ! as qformvr and reduce outflow (qd)
3661  ! by how much was actually sent to the mover
3662  if (this%imover == 1) then
3663  call this%pakmvrobj%accumulate_qformvr(n, qd)
3664  qd = max(qd - this%pakmvrobj%get_qtomvr(n), dzero)
3665  end if
3666  !
3667  ! -- route remaining water to downstream reaches
3668  do i = this%ia(n) + 1, this%ia(n + 1) - 1
3669  if (this%idir(i) > 0) cycle
3670  if (this%idiv(i) > 0) cycle
3671  n2 = this%ja(i)
3672  if (this%iboundpak(n2) == 0) cycle
3673  f = this%ustrf(n2) / this%ftotnd(n)
3674  this%qconn(i) = qd * f
3675  end do
3676  else
3677  do i = this%ia(n) + 1, this%ia(n + 1) - 1
3678  if (this%idir(i) > 0) cycle
3679  this%qconn(i) = dzero
3680  idiv = this%idiv(i)
3681  if (idiv == 0) cycle
3682  jpos = this%iadiv(n) + idiv - 1
3683  this%divq(jpos) = dzero
3684  end do
3685  end if
3686  end subroutine sfr_update_flows
3687 
3688  !> @brief Adjust runoff and evaporation
3689  !!
3690  !! Method to adjust runoff and evaporation for a SFR package reach
3691  !! based on the total reach flow.
3692  !<
3693  subroutine sfr_adjust_ro_ev(this, qc, qu, qi, qr, qro, qe, qfrommvr)
3694  ! -- dummy
3695  class(sfrtype) :: this !< SfrType object
3696  real(DP), intent(inout) :: qc !< total reach volumetric flow
3697  real(DP), intent(in) :: qu !< upstream reach volumetric flow
3698  real(DP), intent(in) :: qi !< reach volumetric inflow
3699  real(DP), intent(in) :: qr !< reach volumetric rainfall
3700  real(DP), intent(inout) :: qro !< reach volumetric runoff
3701  real(DP), intent(inout) :: qe !< reach volumetric evaporation
3702  real(DP), intent(in) :: qfrommvr !< reach volumetric flow from mover
3703  ! -- local
3704  real(DP) :: qt
3705  !
3706  ! -- adjust runoff or evaporation if sum of sources is negative
3707  if (qc < dzero) then
3708  !
3709  ! -- calculate sources without evaporation
3710  qt = qu + qi + qr + qro + qfrommvr
3711  !
3712  ! -- runoff exceeds sources of water for reach
3713  if (qt < dzero) then
3714  if (qro < dzero) then
3715  qro = -(qu + qi + qr + qfrommvr)
3716  qe = dzero
3717  end if
3718  !
3719  ! -- evaporation exceeds sources of water for reach
3720  else
3721  if (qe > dzero) then
3722  qe = qu + qi + qr + qro + qfrommvr
3723  end if
3724  end if
3725  qc = qu + qi + qr - qe + qro + qfrommvr
3726  end if
3727  end subroutine sfr_adjust_ro_ev
3728 
3729  !> @brief Calculate downstream flow term
3730  !!
3731  !! Method to calculate downstream flow for a SFR package reach.
3732  !<
3733  subroutine sfr_calc_qd(this, n, depth, hgwf, qgwf, qd)
3734  ! -- dummy
3735  class(sfrtype) :: this !< SfrType object
3736  integer(I4B), intent(in) :: n !< reach number
3737  real(DP), intent(in) :: depth !< reach depth
3738  real(DP), intent(in) :: hgwf !< groundwater head in connected GWF cell
3739  real(DP), intent(inout) :: qgwf !< groundwater leakage for reach
3740  real(DP), intent(inout) :: qd !< residual
3741  ! -- local
3742  real(DP) :: qsrc
3743  !
3744  ! -- initialize residual
3745  qd = dzero
3746  !
3747  ! -- calculate total water sources excluding groundwater leakage
3748  call this%sfr_calc_qsource(n, depth, qsrc)
3749  !
3750  ! -- estimate groundwater leakage
3751  call this%sfr_calc_qgwf(n, depth, hgwf, qgwf)
3752  if (-qgwf > qsrc) qgwf = -qsrc
3753  !
3754  ! -- calculate down stream flow
3755  qd = qsrc + qgwf
3756  !
3757  ! -- limit downstream flow to a positive value
3758  if (qd < dem30) qd = dzero
3759  end subroutine sfr_calc_qd
3760 
3761  !> @brief Calculate sum of sources
3762  !!
3763  !! Method to calculate the sum of sources for reach, excluding
3764  !! reach leakage, for a SFR package reach.
3765  !<
3766  subroutine sfr_calc_qsource(this, n, depth, qsrc)
3767  ! -- dummy
3768  class(sfrtype) :: this !< SfrType object
3769  integer(I4B), intent(in) :: n !< reach number
3770  real(DP), intent(in) :: depth !< reach depth
3771  real(DP), intent(inout) :: qsrc !< sum of sources for reach
3772  ! -- local
3773  real(DP) :: qu
3774  real(DP) :: qi
3775  real(DP) :: qr
3776  real(DP) :: qe
3777  real(DP) :: qro
3778  real(DP) :: qfrommvr
3779  real(DP) :: a
3780  real(DP) :: ae
3781  !
3782  ! -- initialize residual
3783  qsrc = dzero
3784  !
3785  ! -- calculate flow terms
3786  qu = this%usflow(n)
3787  qi = this%inflow(n)
3788  qro = this%runoff(n)
3789  !
3790  ! -- calculate rainfall and evap
3791  a = this%calc_surface_area(n)
3792  ae = this%calc_surface_area_wet(n, depth)
3793  qr = this%rain(n) * a
3794  qe = this%evap(n) * ae
3795  !
3796  ! -- calculate mover term
3797  qfrommvr = dzero
3798  if (this%imover == 1) then
3799  qfrommvr = this%pakmvrobj%get_qfrommvr(n)
3800  end if
3801  !
3802  ! -- calculate down stream flow
3803  qsrc = qu + qi + qr - qe + qro + qfrommvr
3804  !
3805  ! -- adjust runoff or evaporation if sum of sources is negative
3806  call this%sfr_adjust_ro_ev(qsrc, qu, qi, qr, qro, qe, qfrommvr)
3807  end subroutine sfr_calc_qsource
3808 
3809  !> @brief Calculate streamflow
3810  !!
3811  !! Method to calculate the streamflow using Manning's equation for a
3812  !! SFR package reach.
3813  !<
3814  subroutine sfr_calc_qman(this, n, depth, qman)
3815  ! -- dummy
3816  class(sfrtype) :: this !< SfrType object
3817  integer(I4B), intent(in) :: n !< reach number
3818  real(DP), intent(in) :: depth !< reach depth
3819  real(DP), intent(inout) :: qman !< streamflow
3820  ! -- local
3821  integer(I4B) :: npts
3822  integer(I4B) :: i0
3823  integer(I4B) :: i1
3824  real(DP) :: sat
3825  real(DP) :: derv
3826  real(DP) :: s
3827  real(DP) :: r
3828  real(DP) :: aw
3829  real(DP) :: wp
3830  real(DP) :: rh
3831  !
3832  ! -- initialize variables
3833  qman = dzero
3834  !
3835  ! -- calculate Manning's discharge for non-zero depths
3836  if (depth > dzero) then
3837  npts = this%ncrosspts(n)
3838  !
3839  ! -- set constant terms for Manning's equation
3840  call schsmooth(depth, sat, derv)
3841  s = this%slope(n)
3842  !
3843  ! -- calculate the mannings coefficient that is a
3844  ! function of depth
3845  if (npts > 1) then
3846  !
3847  ! -- get the location of the cross-section data for the reach
3848  i0 = this%iacross(n)
3849  i1 = this%iacross(n + 1) - 1
3850  !
3851  ! -- get the Manning's sum of the Manning's discharge
3852  ! for each section
3853  qman = get_mannings_section(npts, &
3854  this%station(i0:i1), &
3855  this%xsheight(i0:i1), &
3856  this%xsrough(i0:i1), &
3857  this%rough(n), &
3858  this%unitconv, &
3859  s, &
3860  depth)
3861  else
3862  r = this%rough(n)
3863  aw = this%calc_area_wet(n, depth)
3864  wp = this%calc_perimeter_wet(n, depth)
3865  if (wp > dzero) then
3866  rh = aw / wp
3867  else
3868  rh = dzero
3869  end if
3870  qman = this%unitconv * aw * (rh**dtwothirds) * sqrt(s) / r
3871  end if
3872  !
3873  ! -- calculate stream flow
3874  qman = sat * qman
3875  end if
3876  end subroutine sfr_calc_qman
3877 
3878  !> @brief Calculate reach-aquifer exchange
3879  !!
3880  !! Method to calculate the reach-aquifer exchange for a SFR package reach.
3881  !! The reach-aquifer exchange is relative to the reach. Calculated flow
3882  !! is positive if flow is from the aquifer to the reach.
3883  !<
3884  subroutine sfr_calc_qgwf(this, n, depth, hgwf, qgwf, gwfhcof, gwfrhs)
3885  ! -- dummy
3886  class(sfrtype) :: this !< SfrType object
3887  integer(I4B), intent(in) :: n !< reach number
3888  real(DP), intent(in) :: depth !< reach depth
3889  real(DP), intent(in) :: hgwf !< head in GWF cell connected to reach
3890  real(DP), intent(inout) :: qgwf !< reach-aquifer exchange
3891  real(DP), intent(inout), optional :: gwfhcof !< diagonal coefficient term for reach
3892  real(DP), intent(inout), optional :: gwfrhs !< right-hand side term for reach
3893  ! -- local
3894  integer(I4B) :: node
3895  real(DP) :: tp
3896  real(DP) :: bt
3897  real(DP) :: hsfr
3898  real(DP) :: h_temp
3899  real(DP) :: cond
3900  real(DP) :: sat
3901  real(DP) :: derv
3902  real(DP) :: gwfhcof0
3903  real(DP) :: gwfrhs0
3904  !
3905  ! -- initialize qgwf
3906  qgwf = dzero
3907  !
3908  ! -- skip sfr-aquifer exchange in external cells
3909  node = this%igwfnode(n)
3910  if (node < 1) return
3911  !
3912  ! -- skip sfr-aquifer exchange in inactive cells
3913  if (this%ibound(node) == 0) return
3914  !
3915  ! -- calculate saturation
3916  call schsmooth(depth, sat, derv)
3917  !
3918  ! -- terms for calculating direction of gradient across streambed
3919  tp = this%strtop(n)
3920  bt = tp - this%bthick(n)
3921  hsfr = tp + depth
3922  h_temp = hgwf
3923  if (h_temp < bt) then
3924  h_temp = bt
3925  end if
3926  !
3927  ! -- calculate conductance
3928  call this%sfr_calc_cond(n, depth, cond, hsfr, h_temp)
3929  !
3930  ! -- calculate groundwater leakage
3931  qgwf = sat * cond * (h_temp - hsfr)
3932  gwfrhs0 = -sat * cond * hsfr
3933  gwfhcof0 = -sat * cond
3934  !
3935  ! Add density contributions, if active
3936  if (this%idense /= 0) then
3937  call this%sfr_calculate_density_exchange(n, hsfr, hgwf, cond, tp, &
3938  qgwf, gwfhcof0, gwfrhs0)
3939  end if
3940  !
3941  ! -- Set gwfhcof and gwfrhs if present
3942  if (present(gwfhcof)) gwfhcof = gwfhcof0
3943  if (present(gwfrhs)) gwfrhs = gwfrhs0
3944  end subroutine sfr_calc_qgwf
3945 
3946  !> @brief Determine if a reach is connected to a gwf cell
3947  !!
3948  !! Function to determine if a reach is connected to a gwf cell. If connected,
3949  !! the return value is 1. Otherwise, the return value is 0.
3950  !<
3951  function sfr_gwf_conn(this, n)
3952  ! -- return variable
3953  integer(I4B) :: sfr_gwf_conn !< flag indicating if reach is connected to a gwf cell
3954  ! -- dummy
3955  class(sfrtype) :: this !< SfrType object
3956  integer(I4B), intent(in) :: n !< reach number
3957  ! -- local
3958  integer(I4B) :: node
3959 
3960  sfr_gwf_conn = 0
3961  node = this%igwfnode(n)
3962  if (node > 0 .and. this%hk(n) > dzero) then
3963  sfr_gwf_conn = 1
3964  end if
3965  end function sfr_gwf_conn
3966 
3967  !> @brief Calculate reach-aquifer conductance
3968  !!
3969  !! Method to calculate the reach-aquifer conductance for a SFR package reach.
3970  !<
3971  subroutine sfr_calc_cond(this, n, depth, cond, hsfr, h_temp)
3972  ! -- dummy
3973  class(sfrtype) :: this !< SfrType object
3974  integer(I4B), intent(in) :: n !< reach number
3975  real(DP), intent(in) :: depth !< reach depth
3976  real(DP), intent(inout) :: cond !< reach-aquifer conductance
3977  real(DP), intent(in), optional :: hsfr !< stream stage
3978  real(DP), intent(in), optional :: h_temp !< head in gw cell
3979  ! -- local
3980  integer(I4B) :: node
3981  real(DP) :: wp
3982  real(DP) :: vscratio
3983  !
3984  ! -- initialize conductance
3985  cond = dzero
3986  !
3987  ! -- initial viscosity ratio to 1
3988  vscratio = done
3989  !
3990  ! -- calculate conductance if GWF cell is active
3991  ! rch-gwf flow will not occur if reach connected to an constant head cell
3992  node = this%igwfnode(n)
3993  if (node > 0) then
3994  if (this%ibound(node) > 0) then
3995  !
3996  ! -- direction of gradient across streambed determines which vsc ratio
3997  if (this%ivsc == 1) then
3998  if (hsfr > h_temp) then
3999  ! strm stg > gw head
4000  vscratio = this%viscratios(1, n)
4001  else
4002  vscratio = this%viscratios(2, n)
4003  end if
4004  end if
4005  wp = this%calc_perimeter_wet(n, depth)
4006  cond = this%hk(n) * vscratio * this%length(n) * wp / this%bthick(n)
4007  end if
4008  end if
4009  end subroutine sfr_calc_cond
4010 
4011  !> @brief Calculate diversion flow
4012  !!
4013  !! Method to calculate the diversion flow for a diversion connected
4014  !! to a SFR package reach. The downstream flow for a reach is passed
4015  !! in and adjusted by the diversion flow amount calculated in this
4016  !! method.
4017  !<
4018  subroutine sfr_calc_div(this, n, i, qd, qdiv)
4019  ! -- dummy
4020  class(sfrtype) :: this !< SfrType object
4021  integer(I4B), intent(in) :: n !< reach number
4022  integer(I4B), intent(in) :: i !< diversion number in reach
4023  real(DP), intent(inout) :: qd !< remaining downstream flow for reach
4024  real(DP), intent(inout) :: qdiv !< diversion flow for diversion i
4025  ! -- local
4026  character(len=10) :: cp
4027  integer(I4B) :: jpos
4028  integer(I4B) :: n2
4029  real(DP) :: v
4030  !
4031  ! -- set local variables
4032  jpos = this%iadiv(n) + i - 1
4033  n2 = this%divreach(jpos)
4034  cp = this%divcprior(jpos)
4035  v = this%divflow(jpos)
4036  !
4037  ! -- calculate diversion
4038  select case (cp)
4039  ! -- flood diversion
4040  case ('EXCESS')
4041  if (qd < v) then
4042  v = dzero
4043  else
4044  v = qd - v
4045  end if
4046  ! -- diversion percentage
4047  case ('FRACTION')
4048  v = qd * v
4049  ! -- STR priority algorithm
4050  case ('THRESHOLD')
4051  if (qd < v) then
4052  v = dzero
4053  end if
4054  ! -- specified diversion
4055  case ('UPTO')
4056  if (v > qd) then
4057  v = qd
4058  end if
4059  case default
4060  v = dzero
4061  end select
4062  !
4063  ! -- update upstream from for downstream reaches
4064  qd = qd - v
4065  qdiv = v
4066  end subroutine sfr_calc_div
4067 
4068  !> @brief Calculate the depth at the midpoint
4069  !!
4070  !! Method to calculate the depth at the midpoint of a reach.
4071  !<
4072  subroutine sfr_calc_reach_depth(this, n, q1, d1)
4073  ! -- dummy
4074  class(sfrtype) :: this !< SfrType object
4075  integer(I4B), intent(in) :: n !< reach number
4076  real(DP), intent(in) :: q1 !< streamflow
4077  real(DP), intent(inout) :: d1 !< stream depth at midpoint of reach
4078  ! -- local
4079  real(DP) :: w
4080  real(DP) :: s
4081  real(DP) :: r
4082  real(DP) :: qconst
4083  !
4084  ! -- initialize slope and roughness
4085  s = this%slope(n)
4086  r = this%rough(n)
4087  !
4088  ! -- calculate stream depth at the midpoint
4089  if (q1 > dzero) then
4090  if (this%ncrosspts(n) > 1) then
4091  call this%sfr_calc_xs_depth(n, q1, d1)
4092  else
4093  w = this%station(this%iacross(n))
4094  qconst = this%unitconv * w * sqrt(s) / r
4095  d1 = (q1 / qconst)**dp6
4096  end if
4097  else
4098  d1 = dzero
4099  end if
4100  end subroutine sfr_calc_reach_depth
4101 
4102  !> @brief Calculate the depth at the midpoint of a irregular cross-section
4103  !!
4104  !! Method to calculate the depth at the midpoint of a reach with a
4105  !! irregular cross-section using Newton-Raphson.
4106  !<
4107  subroutine sfr_calc_xs_depth(this, n, qrch, d)
4108  ! -- dummy
4109  class(sfrtype) :: this !< SfrType object
4110  integer(I4B), intent(in) :: n !< reach number
4111  real(DP), intent(in) :: qrch !< streamflow
4112  real(DP), intent(inout) :: d !< stream depth at midpoint of reach
4113  ! -- local
4114  integer(I4B) :: iter
4115  real(DP) :: perturbation
4116  real(DP) :: q0
4117  real(DP) :: q1
4118  real(DP) :: dq
4119  real(DP) :: derv
4120  real(DP) :: dd
4121  real(DP) :: residual
4122  !
4123  ! -- initialize variables
4124  perturbation = this%deps * dtwo
4125  d = dzero
4126  q0 = dzero
4127  residual = q0 - qrch
4128  !
4129  ! -- Newton-Raphson iteration
4130  nriter: do iter = 1, this%maxsfrit
4131  call this%sfr_calc_qman(n, d + perturbation, q1)
4132  dq = (q1 - q0)
4133  if (dq /= dzero) then
4134  derv = perturbation / (q1 - q0)
4135  else
4136  derv = dzero
4137  end if
4138  dd = derv * residual
4139  d = d - dd
4140  call this%sfr_calc_qman(n, d, q0)
4141  residual = q0 - qrch
4142  !
4143  ! -- check for convergence
4144  if (abs(dd) < this%dmaxchg) then
4145  exit nriter
4146  end if
4147  end do nriter
4148  end subroutine sfr_calc_xs_depth
4149 
4150  !> @brief Check unit conversion data
4151  !!
4152  !! Method to check unit conversion data for a SFR package. This method
4153  !! also calculates unitconv that is used in the Manning's equation.
4154  !<
4155  subroutine sfr_check_conversion(this)
4156  ! -- dummy
4157  class(sfrtype) :: this !< SfrType object
4158  ! -- local
4159  ! -- formats
4160  character(len=*), parameter :: fmtunitconv_error = &
4161  &"('SFR (',a,') UNIT_CONVERSION SPECIFIED VALUE (',g0,') AND', &
4162  &1x,'LENGTH_CONVERSION OR TIME_CONVERSION SPECIFIED.')"
4163  character(len=*), parameter :: fmtunitconv = &
4164  &"(1x,'SFR PACKAGE (',a,') CONVERSION DATA',&
4165  &/4x,'UNIT CONVERSION VALUE (',g0,').',/)"
4166  !
4167  ! -- check the reach data for simple errors
4168  if (this%lengthconv /= dnodata .or. this%timeconv /= dnodata) then
4169  if (this%unitconv /= done) then
4170  write (errmsg, fmtunitconv_error) &
4171  trim(adjustl(this%packName)), this%unitconv
4172  call store_error(errmsg)
4173  else
4174  if (this%lengthconv /= dnodata) then
4175  this%unitconv = this%unitconv * this%lengthconv**donethird
4176  end if
4177  if (this%timeconv /= dnodata) then
4178  this%unitconv = this%unitconv * this%timeconv
4179  end if
4180  write (this%iout, fmtunitconv) &
4181  trim(adjustl(this%packName)), this%unitconv
4182  end if
4183  end if
4184  end subroutine sfr_check_conversion
4185 
4186  !> @brief Check storage weight
4187  !!
4188  !! Method to check the kinematic storage weight for a SFR package.
4189  !! If the kinematic storage weight has not been set it is set to
4190  !! the default value.
4191  !<
4192  subroutine sfr_check_storage_weight(this)
4193  ! -- dummy
4194  class(sfrtype) :: this !< SfrType object
4195  ! -- formats
4196  character(len=*), parameter :: fmtweight = &
4197  &"(1x,'SFR PACKAGE (',a,') SETTING DEFAULT',&
4198  &/4x,'STORAGE_WEIGHT VALUE (',g0,').',/)"
4199  !
4200  ! -- set storage weight if it has not been defined yet
4201  if (this%istorage == 1) then
4202  if (this%storage_weight == dnodata) then
4203  this%storage_weight = done
4204  write (this%iout, fmtweight) &
4205  trim(adjustl(this%packName)), this%storage_weight
4206  end if
4207  end if
4208  end subroutine sfr_check_storage_weight
4209 
4210  !> @brief Check reach data
4211  !!
4212  !! Method to check specified data for a SFR package. This method
4213  !! also creates the tables used to print input data, if this
4214  !! option in enabled in the SFR package.
4215  !<
4216  subroutine sfr_check_reaches(this)
4217  ! -- dummy
4218  class(sfrtype) :: this !< SfrType object
4219  ! -- local
4220  character(len=5) :: crch
4221  character(len=10) :: cval
4222  character(len=30) :: nodestr
4223  character(len=LINELENGTH) :: title
4224  character(len=LINELENGTH) :: text
4225  integer(I4B) :: n
4226  integer(I4B) :: nn
4227  real(DP) :: btgwf
4228  real(DP) :: bt
4229  !
4230  ! -- setup inputtab tableobj
4231  if (this%iprpak /= 0) then
4232  title = trim(adjustl(this%text))//' PACKAGE ('// &
4233  trim(adjustl(this%packName))//') STATIC REACH DATA'
4234  call table_cr(this%inputtab, this%packName, title)
4235  call this%inputtab%table_df(this%maxbound, 10, this%iout)
4236  text = 'NUMBER'
4237  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4238  text = 'CELLID'
4239  call this%inputtab%initialize_column(text, 20, alignment=tableft)
4240  text = 'LENGTH'
4241  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4242  text = 'WIDTH'
4243  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4244  text = 'SLOPE'
4245  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4246  text = 'TOP'
4247  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4248  text = 'THICKNESS'
4249  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4250  text = 'HK'
4251  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4252  text = 'ROUGHNESS'
4253  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4254  text = 'UPSTREAM FRACTION'
4255  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4256  end if
4257  !
4258  ! -- check the reach data for simple errors
4259  do n = 1, this%maxbound
4260  write (crch, '(i5)') n
4261  nn = this%igwfnode(n)
4262  if (nn > 0) then
4263  btgwf = this%dis%bot(nn)
4264  call this%dis%noder_to_string(nn, nodestr)
4265  else
4266  nodestr = 'none'
4267  end if
4268  ! -- check reach length
4269  if (this%length(n) <= dzero) then
4270  errmsg = 'Reach '//crch//' length must be greater than 0.0.'
4271  call store_error(errmsg)
4272  end if
4273  ! -- check reach width
4274  if (this%width(n) <= dzero) then
4275  errmsg = 'Reach '//crch//' width must be greater than 0.0.'
4276  call store_error(errmsg)
4277  end if
4278  ! -- check reach slope
4279  if (this%slope(n) <= dzero) then
4280  errmsg = 'Reach '//crch//' slope must be greater than 0.0.'
4281  call store_error(errmsg)
4282  end if
4283  ! -- check bed thickness and bed hk for reaches connected to GWF
4284  if (nn > 0) then
4285  bt = this%strtop(n) - this%bthick(n)
4286  if (bt <= btgwf .and. this%icheck /= 0) then
4287  write (cval, '(f10.4)') bt
4288  errmsg = 'Reach '//crch//' bed bottom (rtp-rbth ='// &
4289  cval//') must be greater than the bottom of cell ('// &
4290  nodestr
4291  write (cval, '(f10.4)') btgwf
4292  errmsg = trim(adjustl(errmsg))//'='//cval//').'
4293  call store_error(errmsg)
4294  end if
4295  if (this%hk(n) < dzero) then
4296  errmsg = 'Reach '//crch//' hk must be greater than or equal to 0.0.'
4297  call store_error(errmsg)
4298  end if
4299  end if
4300  ! -- check reach roughness
4301  if (this%rough(n) <= dzero) then
4302  errmsg = 'Reach '//crch//" Manning's roughness "// &
4303  'coefficient must be greater than 0.0.'
4304  call store_error(errmsg)
4305  end if
4306  ! -- check reach upstream fraction
4307  if (this%ustrf(n) < dzero) then
4308  errmsg = 'Reach '//crch//' upstream fraction must be greater '// &
4309  'than or equal to 0.0.'
4310  call store_error(errmsg)
4311  end if
4312  ! -- write summary of reach information
4313  if (this%iprpak /= 0) then
4314  call this%inputtab%add_term(n)
4315  call this%inputtab%add_term(nodestr)
4316  call this%inputtab%add_term(this%length(n))
4317  call this%inputtab%add_term(this%width(n))
4318  call this%inputtab%add_term(this%slope(n))
4319  call this%inputtab%add_term(this%strtop(n))
4320  call this%inputtab%add_term(this%bthick(n))
4321  call this%inputtab%add_term(this%hk(n))
4322  call this%inputtab%add_term(this%rough(n))
4323  call this%inputtab%add_term(this%ustrf(n))
4324  end if
4325  end do
4326  end subroutine sfr_check_reaches
4327 
4328  !> @brief Check connection data
4329  !!
4330  !! Method to check connection data for a SFR package. This method
4331  !! also creates the tables used to print input data, if this
4332  !! option in enabled in the SFR package.
4333  !<
4334  subroutine sfr_check_connections(this)
4335  ! -- dummy
4336  class(sfrtype) :: this !< SfrType object
4337  ! -- local
4338  logical(LGP) :: lreorder
4339  character(len=5) :: crch
4340  character(len=5) :: crch2
4341  character(len=LINELENGTH) :: text
4342  character(len=LINELENGTH) :: title
4343  integer(I4B) :: n
4344  integer(I4B) :: nn
4345  integer(I4B) :: nc
4346  integer(I4B) :: i
4347  integer(I4B) :: ii
4348  integer(I4B) :: j
4349  integer(I4B) :: ifound
4350  integer(I4B) :: ierr
4351  integer(I4B) :: maxconn
4352  integer(I4B) :: ntabcol
4353  !
4354  ! -- determine if the reaches have been reordered
4355  lreorder = .false.
4356  do j = 1, this%MAXBOUND
4357  n = this%isfrorder(j)
4358  if (n /= j) then
4359  lreorder = .true.
4360  exit
4361  end if
4362  end do
4363  !
4364  ! -- write message that the solution order h
4365  if (lreorder) then
4366  write (this%iout, '(/,1x,a)') &
4367  trim(adjustl(this%text))//' PACKAGE ('// &
4368  trim(adjustl(this%packName))//') REACH SOLUTION HAS BEEN '// &
4369  'REORDERED USING A DAG'
4370  !
4371  ! -- print table
4372  if (this%iprpak /= 0) then
4373  !
4374  ! -- reset the input table object
4375  ntabcol = 2
4376  title = trim(adjustl(this%text))//' PACKAGE ('// &
4377  trim(adjustl(this%packName))//') REACH SOLUTION ORDER'
4378  call table_cr(this%inputtab, this%packName, title)
4379  call this%inputtab%table_df(this%maxbound, ntabcol, this%iout)
4380  text = 'ORDER'
4381  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4382  text = 'REACH'
4383  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4384  !
4385  ! -- upstream connection data
4386  do j = 1, this%maxbound
4387  n = this%isfrorder(j)
4388  call this%inputtab%add_term(j)
4389  call this%inputtab%add_term(n)
4390  end do
4391  end if
4392  end if
4393  !
4394  ! -- create input table for reach connections data
4395  if (this%iprpak /= 0) then
4396  !
4397  ! -- calculate the maximum number of connections
4398  maxconn = 0
4399  do n = 1, this%maxbound
4400  maxconn = max(maxconn, this%nconnreach(n))
4401  end do
4402  ntabcol = 1 + maxconn
4403  !
4404  ! -- reset the input table object
4405  title = trim(adjustl(this%text))//' PACKAGE ('// &
4406  trim(adjustl(this%packName))//') STATIC REACH CONNECTION DATA'
4407  call table_cr(this%inputtab, this%packName, title)
4408  call this%inputtab%table_df(this%maxbound, ntabcol, this%iout)
4409  text = 'REACH'
4410  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4411  do n = 1, maxconn
4412  write (text, '(a,1x,i6)') 'CONN', n
4413  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4414  end do
4415  end if
4416  !
4417  ! -- verify every listed connection is reciprocated: if reach n lists
4418  ! -- reach nn, reach nn must list reach n back
4419  do n = 1, this%MAXBOUND
4420  write (crch, '(i5)') n
4421  eachconn: do i = this%ia(n) + 1, this%ia(n + 1) - 1
4422  nn = this%ja(i)
4423  write (crch2, '(i5)') nn
4424  ifound = 0
4425  connreach: do ii = this%ia(nn) + 1, this%ia(nn + 1) - 1
4426  nc = this%ja(ii)
4427  if (nc == n) then
4428  ifound = 1
4429  exit connreach
4430  end if
4431  end do connreach
4432  if (ifound /= 1) then
4433  errmsg = 'Reach '//crch//' is connected to '// &
4434  'reach '//crch2//' but reach '//crch2// &
4435  ' is not connected to reach '//crch//'.'
4436  call store_error(errmsg)
4437  end if
4438  end do eachconn
4439  !
4440  ! -- write connection data to the table
4441  if (this%iprpak /= 0) then
4442  call this%inputtab%add_term(n)
4443  do i = this%ia(n) + 1, this%ia(n + 1) - 1
4444  call this%inputtab%add_term(this%ja(i))
4445  end do
4446  nn = maxconn - this%nconnreach(n)
4447  do i = 1, nn
4448  call this%inputtab%add_term(' ')
4449  end do
4450  end if
4451  end do
4452  !
4453  ! -- verify upstream connections don't form a mutual pair: two reaches
4454  ! -- cannot each list the other as upstream
4455  ierr = 0
4456  do n = 1, this%maxbound
4457  write (crch, '(i5)') n
4458  eachconnv: do i = this%ia(n) + 1, this%ia(n + 1) - 1
4459  !
4460  ! -- skip downstream connections
4461  if (this%idir(i) < 0) cycle eachconnv
4462  nn = this%ja(i)
4463  write (crch2, '(i5)') nn
4464  connreachv: do ii = this%ia(nn) + 1, this%ia(nn + 1) - 1
4465  ! -- skip downstream connections
4466  if (this%idir(ii) < 0) cycle connreachv
4467  nc = this%ja(ii)
4468  !
4469  ! -- if nc == n then that means reach n is an upstream connection for
4470  ! reach nn and reach nn is an upstream connection for reach n
4471  if (nc == n) then
4472  ierr = ierr + 1
4473  errmsg = 'Reach '//crch//' is connected to '// &
4474  'reach '//crch2//' but streamflow from reach '// &
4475  crch//' to reach '//crch2//' is not permitted.'
4476  call store_error(errmsg)
4477  exit connreachv
4478  end if
4479  end do connreachv
4480  end do eachconnv
4481  end do
4482  !
4483  ! -- terminate if connectivity errors
4484  if (count_errors() > 0) then
4485  call store_error_filename(this%input_fname)
4486  end if
4487  !
4488  ! -- check that downstream reaches for a reach are
4489  ! the upstream reaches for the reach
4490  do n = 1, this%maxbound
4491  write (crch, '(i5)') n
4492  eachconnds: do i = this%ia(n) + 1, this%ia(n + 1) - 1
4493  nn = this%ja(i)
4494  if (this%idir(i) > 0) cycle eachconnds
4495  write (crch2, '(i5)') nn
4496  ifound = 0
4497  connreachds: do ii = this%ia(nn) + 1, this%ia(nn + 1) - 1
4498  nc = this%ja(ii)
4499  if (nc == n) then
4500  if (this%idir(i) /= this%idir(ii)) then
4501  ifound = 1
4502  end if
4503  exit connreachds
4504  end if
4505  end do connreachds
4506  if (ifound /= 1) then
4507  errmsg = 'Reach '//crch//' downstream connected reach '// &
4508  'is reach '//crch2//' but reach '//crch//' is not'// &
4509  ' the upstream connected reach for reach '//crch2//'.'
4510  call store_error(errmsg)
4511  end if
4512  end do eachconnds
4513  end do
4514  !
4515  ! -- create input table for upstream and downstream connections
4516  if (this%iprpak /= 0) then
4517  !
4518  ! -- calculate the maximum number of upstream connections
4519  maxconn = 0
4520  do n = 1, this%maxbound
4521  ii = 0
4522  do i = this%ia(n) + 1, this%ia(n + 1) - 1
4523  if (this%idir(i) > 0) then
4524  ii = ii + 1
4525  end if
4526  end do
4527  maxconn = max(maxconn, ii)
4528  end do
4529  ntabcol = 1 + maxconn
4530  !
4531  ! -- reset the input table object
4532  title = trim(adjustl(this%text))//' PACKAGE ('// &
4533  trim(adjustl(this%packName))//') STATIC UPSTREAM REACH '// &
4534  'CONNECTION DATA'
4535  call table_cr(this%inputtab, this%packName, title)
4536  call this%inputtab%table_df(this%maxbound, ntabcol, this%iout)
4537  text = 'REACH'
4538  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4539  do n = 1, maxconn
4540  write (text, '(a,1x,i6)') 'UPSTREAM CONN', n
4541  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4542  end do
4543  !
4544  ! -- upstream connection data
4545  do n = 1, this%maxbound
4546  call this%inputtab%add_term(n)
4547  ii = 0
4548  do i = this%ia(n) + 1, this%ia(n + 1) - 1
4549  if (this%idir(i) > 0) then
4550  call this%inputtab%add_term(this%ja(i))
4551  ii = ii + 1
4552  end if
4553  end do
4554  nn = maxconn - ii
4555  do i = 1, nn
4556  call this%inputtab%add_term(' ')
4557  end do
4558  end do
4559  !
4560  ! -- calculate the maximum number of downstream connections
4561  maxconn = 0
4562  do n = 1, this%maxbound
4563  ii = 0
4564  do i = this%ia(n) + 1, this%ia(n + 1) - 1
4565  if (this%idir(i) < 0) then
4566  ii = ii + 1
4567  end if
4568  end do
4569  maxconn = max(maxconn, ii)
4570  end do
4571  ntabcol = 1 + maxconn
4572  !
4573  ! -- reset the input table object
4574  title = trim(adjustl(this%text))//' PACKAGE ('// &
4575  trim(adjustl(this%packName))//') STATIC DOWNSTREAM '// &
4576  'REACH CONNECTION DATA'
4577  call table_cr(this%inputtab, this%packName, title)
4578  call this%inputtab%table_df(this%maxbound, ntabcol, this%iout)
4579  text = 'REACH'
4580  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4581  do n = 1, maxconn
4582  write (text, '(a,1x,i6)') 'DOWNSTREAM CONN', n
4583  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4584  end do
4585  !
4586  ! -- downstream connection data
4587  do n = 1, this%maxbound
4588  call this%inputtab%add_term(n)
4589  ii = 0
4590  do i = this%ia(n) + 1, this%ia(n + 1) - 1
4591  if (this%idir(i) < 0) then
4592  call this%inputtab%add_term(this%ja(i))
4593  ii = ii + 1
4594  end if
4595  end do
4596  nn = maxconn - ii
4597  do i = 1, nn
4598  call this%inputtab%add_term(' ')
4599  end do
4600  end do
4601  end if
4602  end subroutine sfr_check_connections
4603 
4604  !> @brief Check diversions data
4605  !!
4606  !! Method to check diversion data for a SFR package. This method
4607  !! also creates the tables used to print input data, if this
4608  !! option in enabled in the SFR package.
4609  !<
4610  subroutine sfr_check_diversions(this)
4611  ! -- dummy
4612  class(sfrtype) :: this !< SfrType object
4613  ! -- local
4614  character(len=LINELENGTH) :: title
4615  character(len=LINELENGTH) :: text
4616  character(len=5) :: crch
4617  character(len=5) :: cdiv
4618  character(len=5) :: crch2
4619  character(len=10) :: cprior
4620  integer(I4B) :: maxdiv
4621  integer(I4B) :: n
4622  integer(I4B) :: nn
4623  integer(I4B) :: nc
4624  integer(I4B) :: ii
4625  integer(I4B) :: idiv
4626  integer(I4B) :: ifound
4627  integer(I4B) :: jpos
4628  ! -- format
4629 10 format('Diversion ', i0, ' of reach ', i0, &
4630  ' is invalid or has not been defined.')
4631  !
4632  ! -- write header
4633  if (this%iprpak /= 0) then
4634  !
4635  ! -- determine the maximum number of diversions
4636  maxdiv = 0
4637  do n = 1, this%maxbound
4638  maxdiv = maxdiv + this%ndiv(n)
4639  end do
4640  !
4641  ! -- reset the input table object
4642  title = trim(adjustl(this%text))//' PACKAGE ('// &
4643  trim(adjustl(this%packName))//') REACH DIVERSION DATA'
4644  call table_cr(this%inputtab, this%packName, title)
4645  call this%inputtab%table_df(maxdiv, 4, this%iout)
4646  text = 'REACH'
4647  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4648  text = 'DIVERSION'
4649  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4650  text = 'REACH 2'
4651  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4652  text = 'CPRIOR'
4653  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4654  end if
4655  !
4656  ! -- check that diversion data are correct
4657  do n = 1, this%maxbound
4658  if (this%ndiv(n) < 1) cycle
4659  write (crch, '(i5)') n
4660 
4661  do idiv = 1, this%ndiv(n)
4662  !
4663  ! -- determine diversion index
4664  jpos = this%iadiv(n) + idiv - 1
4665  !
4666  ! -- write idiv to cdiv
4667  write (cdiv, '(i5)') idiv
4668  !
4669  !
4670  nn = this%divreach(jpos)
4671  write (crch2, '(i5)') nn
4672  !
4673  ! -- make sure diversion reach is connected to current reach
4674  ifound = 0
4675  if (nn < 1 .or. nn > this%maxbound) then
4676  write (errmsg, 10) idiv, n
4677  call store_error(errmsg)
4678  cycle
4679  end if
4680  connreach: do ii = this%ia(nn) + 1, this%ia(nn + 1) - 1
4681  nc = this%ja(ii)
4682  if (nc == n) then
4683  if (this%idir(ii) > 0) then
4684  ifound = 1
4685  end if
4686  exit connreach
4687  end if
4688  end do connreach
4689  if (ifound /= 1) then
4690  errmsg = 'Reach '//crch//' is not a upstream reach for '// &
4691  'reach '//crch2//' as a result diversion '//cdiv// &
4692  ' from reach '//crch//' to reach '//crch2// &
4693  ' is not possible. Check reach connectivity.'
4694  call store_error(errmsg)
4695  end if
4696  ! -- iprior
4697  cprior = this%divcprior(jpos)
4698  !
4699  ! -- add terms to the table
4700  if (this%iprpak /= 0) then
4701  call this%inputtab%add_term(n)
4702  call this%inputtab%add_term(idiv)
4703  call this%inputtab%add_term(nn)
4704  call this%inputtab%add_term(cprior)
4705  end if
4706  end do
4707  end do
4708  end subroutine sfr_check_diversions
4709 
4710  !> @brief Check initial stage data
4711  !!
4712  !! Method to check initial data for a SFR package and calculates
4713  !! the initial upstream and downstream flows for the reach based
4714  !! on the initial staalso creates the tables used to print input
4715  !! data, if this option in enabled in the SFR package.
4716  !<
4717  subroutine sfr_check_initialstages(this)
4718  class(sfrtype) :: this !< SfrType object
4719 
4720  character(len=LINELENGTH) :: title
4721  character(len=LINELENGTH) :: text
4722  character(len=5) :: crch
4723  integer(I4B) :: n
4724  real(DP) :: qman
4725 
4726  ! skip check if storage is not activated
4727  if (this%istorage == 0) return
4728 
4729  ! write header
4730  if (this%iprpak /= 0) then
4731  !
4732  ! -- reset the input table object
4733  title = trim(adjustl(this%text))//' PACKAGE ('// &
4734  trim(adjustl(this%packName))//') REACH INITIAL STAGE DATA'
4735  call table_cr(this%inputtab, this%packName, title)
4736  call this%inputtab%table_df(this%maxbound, 4, this%iout)
4737  text = 'REACH'
4738  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4739  text = 'INITIAL STAGE'
4740  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4741  text = 'INITIAL DEPTH'
4742  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4743  text = 'INITIAL FLOW'
4744  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4745  end if
4746  !
4747  ! -- check that data are correct
4748  do n = 1, this%maxbound
4749  write (crch, '(i5)') n
4750 
4751  ! calculate the initial flows
4752  call this%sfr_calc_qman(n, this%depth(n), qman)
4753  this%usinflow(n) = qman
4754  this%dsflow(n) = qman
4755 
4756  ! add terms to the table
4757  if (this%iprpak /= 0) then
4758  call this%inputtab%add_term(n)
4759  call this%inputtab%add_term(this%stage(n))
4760  call this%inputtab%add_term(this%depth(n))
4761  call this%inputtab%add_term(qman)
4762  end if
4763  end do
4764  end subroutine sfr_check_initialstages
4765 
4766  !> @brief Check upstream fraction data
4767  !!
4768  !! Method to check upstream fraction data for a SFR package.
4769  !! This method also creates the tables used to print input data,
4770  !! if this option in enabled in the SFR package.
4771  !<
4772  subroutine sfr_check_ustrf(this)
4773  ! -- dummy
4774  class(sfrtype) :: this !< SfrType object
4775  ! -- local
4776  character(len=LINELENGTH) :: title
4777  character(len=LINELENGTH) :: text
4778  logical(LGP) :: lcycle
4779  logical(LGP) :: ladd
4780  character(len=5) :: crch
4781  character(len=5) :: crch2
4782  character(len=10) :: cval
4783  integer(I4B) :: maxcols
4784  integer(I4B) :: npairs
4785  integer(I4B) :: ipair
4786  integer(I4B) :: i
4787  integer(I4B) :: n
4788  integer(I4B) :: n2
4789  integer(I4B) :: idiv
4790  integer(I4B) :: i0
4791  integer(I4B) :: i1
4792  integer(I4B) :: jpos
4793  integer(I4B) :: ids
4794  real(DP) :: f
4795  real(DP) :: rval
4796  !
4797  ! -- write table header
4798  if (this%iprpak /= 0) then
4799  !
4800  ! -- determine the maximum number of columns
4801  npairs = 0
4802  do n = 1, this%maxbound
4803  ipair = 0
4804  ec: do i = this%ia(n) + 1, this%ia(n + 1) - 1
4805  !
4806  ! -- skip upstream connections
4807  if (this%idir(i) > 0) cycle ec
4808  n2 = this%ja(i)
4809  !
4810  ! -- skip inactive downstream reaches
4811  if (this%iboundpak(n2) == 0) cycle ec
4812  !
4813  ! -- increment ipair and see if it exceeds npairs
4814  ipair = ipair + 1
4815  npairs = max(npairs, ipair)
4816  end do ec
4817  end do
4818  maxcols = 1 + npairs * 2
4819  !
4820  ! -- reset the input table object
4821  title = trim(adjustl(this%text))//' PACKAGE ('// &
4822  trim(adjustl(this%packName))//') CONNECTED REACH UPSTREAM '// &
4823  'FRACTION DATA'
4824  call table_cr(this%inputtab, this%packName, title)
4825  call this%inputtab%table_df(this%maxbound, maxcols, this%iout)
4826  text = 'REACH'
4827  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4828  do i = 1, npairs
4829  write (cval, '(i10)') i
4830  text = 'DOWNSTREAM REACH '//trim(adjustl(cval))
4831  call this%inputtab%initialize_column(text, 10, alignment=tabcenter)
4832  text = 'FRACTION '//trim(adjustl(cval))
4833  call this%inputtab%initialize_column(text, 12, alignment=tabcenter)
4834  end do
4835  end if
4836  !
4837  ! -- fill diversion number for each connection
4838  do n = 1, this%maxbound
4839  do idiv = 1, this%ndiv(n)
4840  i0 = this%iadiv(n)
4841  i1 = this%iadiv(n + 1) - 1
4842  do jpos = i0, i1
4843  do i = this%ia(n) + 1, this%ia(n + 1) - 1
4844  n2 = this%ja(i)
4845  if (this%divreach(jpos) == n2) then
4846  this%idiv(i) = jpos - i0 + 1
4847  exit
4848  end if
4849  end do
4850  end do
4851  end do
4852  end do
4853  !
4854  ! -- check that the upstream fraction for reach connected by
4855  ! a diversion is zero
4856  do n = 1, this%maxbound
4857  !
4858  ! -- determine the number of downstream reaches
4859  ids = 0
4860  do i = this%ia(n) + 1, this%ia(n + 1) - 1
4861  if (this%idir(i) < 0) then
4862  ids = ids + 1
4863  end if
4864  end do
4865  !
4866  ! -- evaluate the diversions
4867  do idiv = 1, this%ndiv(n)
4868  jpos = this%iadiv(n) + idiv - 1
4869  n2 = this%divreach(jpos)
4870  f = this%ustrf(n2)
4871  if (f /= dzero) then
4872  write (errmsg, '(a,2(1x,i0,1x,a),1x,a,g0,a,2(1x,a))') &
4873  'Reach', n, 'is connected to reach', n2, 'by a diversion', &
4874  'but the upstream fraction is not equal to zero (', f, '). Check', &
4875  trim(this%packName), 'package diversion and package data.'
4876  if (ids > 1) then
4877  call store_error(errmsg)
4878  else
4879  write (warnmsg, '(a,3(1x,a))') &
4880  trim(warnmsg), &
4881  'A warning instead of an error is issued because', &
4882  'the reach is only connected to the diversion reach in the ', &
4883  'downstream direction.'
4884  call store_warning(warnmsg)
4885  end if
4886  end if
4887  end do
4888  end do
4889  !
4890  ! -- calculate the total fraction of connected reaches that are
4891  ! not diversions and check that the sum of upstream fractions
4892  ! is equal to 1 for each reach
4893  do n = 1, this%maxbound
4894  ids = 0
4895  rval = dzero
4896  f = dzero
4897  write (crch, '(i5)') n
4898  if (this%iprpak /= 0) then
4899  call this%inputtab%add_term(n)
4900  end if
4901  ipair = 0
4902  eachconn: do i = this%ia(n) + 1, this%ia(n + 1) - 1
4903  lcycle = .false.
4904  !
4905  ! -- initialize downstream connection q
4906  this%qconn(i) = dzero
4907  !
4908  ! -- skip upstream connections
4909  if (this%idir(i) > 0) then
4910  lcycle = .true.
4911  end if
4912  n2 = this%ja(i)
4913  !
4914  ! -- skip inactive downstream reaches
4915  if (this%iboundpak(n2) == 0) then
4916  lcycle = .true.
4917  end if
4918  if (lcycle) then
4919  cycle eachconn
4920  end if
4921  ipair = ipair + 1
4922  write (crch2, '(i5)') n2
4923  ids = ids + 1
4924  ladd = .true.
4925  f = f + this%ustrf(n2)
4926  write (cval, '(f10.4)') this%ustrf(n2)
4927  !
4928  ! -- write upstream fractions
4929  if (this%iprpak /= 0) then
4930  call this%inputtab%add_term(n2)
4931  call this%inputtab%add_term(this%ustrf(n2))
4932  end if
4933  eachdiv: do idiv = 1, this%ndiv(n)
4934  jpos = this%iadiv(n) + idiv - 1
4935  if (this%divreach(jpos) == n2) then
4936  ladd = .false.
4937  exit eachdiv
4938  end if
4939  end do eachdiv
4940  if (ladd) then
4941  rval = rval + this%ustrf(n2)
4942  end if
4943  end do eachconn
4944  this%ftotnd(n) = rval
4945  !
4946  ! -- write remaining table columns
4947  if (this%iprpak /= 0) then
4948  ipair = ipair + 1
4949  do i = ipair, npairs
4950  call this%inputtab%add_term(' ')
4951  call this%inputtab%add_term(' ')
4952  end do
4953  end if
4954  !
4955  ! -- evaluate if an error condition has occurred
4956  ! the sum of fractions is not equal to 1
4957  if (ids /= 0) then
4958  if (abs(f - done) > dem6) then
4959  write (errmsg, '(a,1x,i0,1x,a,g0,a,3(1x,a))') &
4960  'Upstream fractions for reach ', n, 'is not equal to one (', f, &
4961  '). Check', trim(this%packName), 'package reach connectivity and', &
4962  'package data.'
4963  call store_error(errmsg)
4964  end if
4965  end if
4966  end do
4967  end subroutine sfr_check_ustrf
4968 
4969  !> @brief Apply a PERIOD setting value to reach n.
4970  !!
4971  !! Shared by sfr_rp and sfr_ad; DIVERSION is handled separately by
4972  !! both callers because its target index requires its own validation.
4973  !<
4974  subroutine sfr_set_period_value(this, i, n, setting)
4975  ! -- dummy
4976  class(sfrtype), intent(inout) :: this
4977  integer(I4B), intent(in) :: i !< row index into input context arrays
4978  integer(I4B), intent(in) :: n !< reach number
4979  character(len=*), intent(in) :: setting !< uppercase mf6varname dispatch key
4980  !
4981  select case (trim(setting))
4982  case ('BEDK')
4983  this%bedk_set(n) = .true.
4984  case ('MANNING')
4985  this%manning_set(n) = .true.
4986  case ('UPSTREAM_FRAC')
4987  this%ustrf_set(n) = .true.
4988  end select
4989  end subroutine sfr_set_period_value
4990 
4991  !> @brief Setup budget object for package
4992  !!
4993  !! Method to set up the budget object that stores all the sfr flows
4994  !! The terms listed here must correspond in number and order to the ones
4995  !! listed in the sfr_fill_budobj method.
4996  !<
4997  subroutine sfr_setup_budobj(this)
4998  ! -- dummy
4999  class(sfrtype) :: this !< SfrType object
5000  ! -- local
5001  integer(I4B) :: nbudterm
5002  integer(I4B) :: i
5003  integer(I4B) :: n
5004  integer(I4B) :: n1
5005  integer(I4B) :: n2
5006  integer(I4B) :: maxlist
5007  integer(I4B) :: naux
5008  integer(I4B) :: idx
5009  real(DP) :: q
5010  character(len=LENBUDTXT) :: text
5011  character(len=LENBUDTXT), dimension(1) :: auxtxt
5012  !
5013  ! -- Determine the number of sfr budget terms. These are fixed for
5014  ! the simulation and cannot change. This includes FLOW-JA-FACE
5015  ! so they can be written to the binary budget files, but these internal
5016  ! flows are not included as part of the budget table.
5017  nbudterm = 8
5018  if (this%imover == 1) nbudterm = nbudterm + 2
5019  if (this%naux > 0) nbudterm = nbudterm + 1
5020  !
5021  ! -- set up budobj
5022  call budgetobject_cr(this%budobj, this%packName)
5023  call this%budobj%budgetobject_df(this%maxbound, nbudterm, 0, 0, &
5024  ibudcsv=this%ibudcsv)
5025  idx = 0
5026  !
5027  ! -- Go through and set up each budget term
5028  text = ' FLOW-JA-FACE'
5029  idx = idx + 1
5030  maxlist = this%nconn
5031  naux = 1
5032  auxtxt(1) = ' FLOW-AREA'
5033  call this%budobj%budterm(idx)%initialize(text, &
5034  this%name_model, &
5035  this%packName, &
5036  this%name_model, &
5037  this%packName, &
5038  maxlist, .false., .false., &
5039  naux, auxtxt)
5040  !
5041  ! -- store connectivity
5042  call this%budobj%budterm(idx)%reset(this%nconn)
5043  q = dzero
5044  do n = 1, this%maxbound
5045  n1 = n
5046  do i = this%ia(n) + 1, this%ia(n + 1) - 1
5047  n2 = this%ja(i)
5048  call this%budobj%budterm(idx)%update_term(n1, n2, q)
5049  end do
5050  end do
5051  !
5052  ! --
5053  text = ' GWF'
5054  idx = idx + 1
5055  maxlist = this%maxbound - this%ianynone
5056  naux = 1
5057  auxtxt(1) = ' FLOW-AREA'
5058  call this%budobj%budterm(idx)%initialize(text, &
5059  this%name_model, &
5060  this%packName, &
5061  this%name_model, &
5062  this%name_model, &
5063  maxlist, .false., .true., &
5064  naux, auxtxt)
5065  call this%budobj%budterm(idx)%reset(maxlist)
5066  q = dzero
5067  do n = 1, this%maxbound
5068  n2 = this%igwfnode(n)
5069  if (n2 > 0) then
5070  call this%budobj%budterm(idx)%update_term(n, n2, q)
5071  end if
5072  end do
5073  !
5074  ! --
5075  text = ' RAINFALL'
5076  idx = idx + 1
5077  maxlist = this%maxbound
5078  naux = 0
5079  call this%budobj%budterm(idx)%initialize(text, &
5080  this%name_model, &
5081  this%packName, &
5082  this%name_model, &
5083  this%packName, &
5084  maxlist, .false., .false., &
5085  naux)
5086  !
5087  ! --
5088  text = ' EVAPORATION'
5089  idx = idx + 1
5090  maxlist = this%maxbound
5091  naux = 0
5092  call this%budobj%budterm(idx)%initialize(text, &
5093  this%name_model, &
5094  this%packName, &
5095  this%name_model, &
5096  this%packName, &
5097  maxlist, .false., .false., &
5098  naux)
5099  !
5100  ! --
5101  text = ' RUNOFF'
5102  idx = idx + 1
5103  maxlist = this%maxbound
5104  naux = 0
5105  call this%budobj%budterm(idx)%initialize(text, &
5106  this%name_model, &
5107  this%packName, &
5108  this%name_model, &
5109  this%packName, &
5110  maxlist, .false., .false., &
5111  naux)
5112  !
5113  ! --
5114  text = ' EXT-INFLOW'
5115  idx = idx + 1
5116  maxlist = this%maxbound
5117  naux = 0
5118  call this%budobj%budterm(idx)%initialize(text, &
5119  this%name_model, &
5120  this%packName, &
5121  this%name_model, &
5122  this%packName, &
5123  maxlist, .false., .false., &
5124  naux)
5125  !
5126  ! --
5127  text = ' EXT-OUTFLOW'
5128  idx = idx + 1
5129  maxlist = this%maxbound
5130  naux = 0
5131  call this%budobj%budterm(idx)%initialize(text, &
5132  this%name_model, &
5133  this%packName, &
5134  this%name_model, &
5135  this%packName, &
5136  maxlist, .false., .false., &
5137  naux)
5138  !
5139  ! --
5140  text = ' STORAGE'
5141  idx = idx + 1
5142  maxlist = this%maxbound
5143  naux = 1
5144  auxtxt(1) = ' VOLUME'
5145  call this%budobj%budterm(idx)%initialize(text, &
5146  this%name_model, &
5147  this%packName, &
5148  this%name_model, &
5149  this%packName, &
5150  maxlist, .false., .false., &
5151  naux, auxtxt)
5152  !
5153  ! --
5154  if (this%imover == 1) then
5155  !
5156  ! --
5157  text = ' FROM-MVR'
5158  idx = idx + 1
5159  maxlist = this%maxbound
5160  naux = 0
5161  call this%budobj%budterm(idx)%initialize(text, &
5162  this%name_model, &
5163  this%packName, &
5164  this%name_model, &
5165  this%packName, &
5166  maxlist, .false., .false., &
5167  naux)
5168  !
5169  ! --
5170  text = ' TO-MVR'
5171  idx = idx + 1
5172  maxlist = this%maxbound
5173  naux = 0
5174  call this%budobj%budterm(idx)%initialize(text, &
5175  this%name_model, &
5176  this%packName, &
5177  this%name_model, &
5178  this%packName, &
5179  maxlist, .false., .false., &
5180  naux)
5181  end if
5182  !
5183  ! --
5184  naux = this%naux
5185  if (naux > 0) then
5186  !
5187  ! --
5188  text = ' AUXILIARY'
5189  idx = idx + 1
5190  maxlist = this%maxbound
5191  call this%budobj%budterm(idx)%initialize(text, &
5192  this%name_model, &
5193  this%packName, &
5194  this%name_model, &
5195  this%packName, &
5196  maxlist, .false., .false., &
5197  naux, this%auxname)
5198  end if
5199  !
5200  ! -- if sfr flow for each reach are written to the listing file
5201  if (this%iprflow /= 0) then
5202  call this%budobj%flowtable_df(this%iout, cellids='GWF')
5203  end if
5204  end subroutine sfr_setup_budobj
5205 
5206  !> @brief Copy flow terms into budget object for package
5207  !!
5208  !! Method to copy flows into the budget object that stores all the sfr flows
5209  !! The terms listed here must correspond in number and order to the ones
5210  !! added in the sfr_setup_budobj method.
5211  !<
5212  subroutine sfr_fill_budobj(this)
5213  ! -- dummy
5214  class(sfrtype) :: this !< SfrType object
5215  ! -- local
5216  integer(I4B) :: naux
5217  integer(I4B) :: i
5218  integer(I4B) :: n
5219  integer(I4B) :: n1
5220  integer(I4B) :: n2
5221  integer(I4B) :: ii
5222  integer(I4B) :: idx
5223  integer(I4B) :: idiv
5224  integer(I4B) :: jpos
5225  real(DP) :: q
5226  real(DP) :: qt
5227  real(DP) :: d
5228  real(DP) :: ca
5229  real(DP) :: a
5230  real(DP) :: wp
5231  real(DP) :: l
5232  !
5233  ! -- initialize counter
5234  idx = 0
5235  !
5236  ! -- FLOW JA FACE
5237  idx = idx + 1
5238  call this%budobj%budterm(idx)%reset(this%nconn)
5239  do n = 1, this%maxbound
5240  n1 = n
5241  q = dzero
5242  ca = dzero
5243  do i = this%ia(n) + 1, this%ia(n + 1) - 1
5244  n2 = this%ja(i)
5245  if (this%iboundpak(n) /= 0) then
5246  ! flow to downstream reaches
5247  if (this%idir(i) < 0) then
5248  qt = this%dsflow(n)
5249  q = -this%qconn(i)
5250  ! flow from upstream reaches
5251  else
5252  qt = this%usflow(n)
5253  do ii = this%ia(n2) + 1, this%ia(n2 + 1) - 1
5254  if (this%idir(ii) > 0) cycle
5255  if (this%ja(ii) /= n) cycle
5256  q = this%qconn(ii)
5257  exit
5258  end do
5259  end if
5260  ! calculate flow area
5261  call this%sfr_calc_reach_depth(n, qt, d)
5262  ca = this%calc_area_wet(n, d)
5263  else
5264  q = dzero
5265  ca = dzero
5266  end if
5267  this%qauxcbc(1) = ca
5268  call this%budobj%budterm(idx)%update_term(n1, n2, q, this%qauxcbc)
5269  end do
5270  end do
5271  !
5272  ! -- GWF (LEAKAGE)
5273  idx = idx + 1
5274  call this%budobj%budterm(idx)%reset(this%maxbound - this%ianynone)
5275  do n = 1, this%maxbound
5276  n2 = this%igwfnode(n)
5277  if (n2 > 0) then
5278  if (this%iboundpak(n) /= 0) then
5279  ! -- calc_perimeter_wet() does not enforce depth dependence
5280  if (this%depth(n) > dzero) then
5281  wp = this%calc_perimeter_wet(n, this%depth(n))
5282  else
5283  wp = dzero
5284  end if
5285  l = this%length(n)
5286  a = wp * l
5287  this%qauxcbc(1) = a
5288  q = -this%gwflow(n)
5289  else
5290  this%qauxcbc(1) = dzero
5291  q = dzero
5292  end if
5293  call this%budobj%budterm(idx)%update_term(n, n2, q, this%qauxcbc)
5294  end if
5295  end do
5296  !
5297  ! -- RAIN
5298  idx = idx + 1
5299  call this%budobj%budterm(idx)%reset(this%maxbound)
5300  do n = 1, this%maxbound
5301  if (this%iboundpak(n) /= 0) then
5302  a = this%calc_surface_area(n)
5303  q = this%rain(n) * a
5304  else
5305  q = dzero
5306  end if
5307  call this%budobj%budterm(idx)%update_term(n, n, q)
5308  end do
5309  !
5310  ! -- EVAPORATION
5311  idx = idx + 1
5312  call this%budobj%budterm(idx)%reset(this%maxbound)
5313  do n = 1, this%maxbound
5314  if (this%iboundpak(n) /= 0) then
5315  q = -this%simevap(n)
5316  else
5317  q = dzero
5318  end if
5319  call this%budobj%budterm(idx)%update_term(n, n, q)
5320  end do
5321  !
5322  ! -- RUNOFF
5323  idx = idx + 1
5324  call this%budobj%budterm(idx)%reset(this%maxbound)
5325  do n = 1, this%maxbound
5326  if (this%iboundpak(n) /= 0) then
5327  q = this%simrunoff(n)
5328  else
5329  q = dzero
5330  end if
5331  call this%budobj%budterm(idx)%update_term(n, n, q)
5332  end do
5333  !
5334  ! -- INFLOW
5335  idx = idx + 1
5336  call this%budobj%budterm(idx)%reset(this%maxbound)
5337  do n = 1, this%maxbound
5338  if (this%iboundpak(n) /= 0) then
5339  q = this%inflow(n)
5340  else
5341  q = dzero
5342  end if
5343  call this%budobj%budterm(idx)%update_term(n, n, q)
5344  end do
5345  !
5346  ! -- EXTERNAL OUTFLOW
5347  idx = idx + 1
5348  call this%budobj%budterm(idx)%reset(this%maxbound)
5349  do n = 1, this%maxbound
5350  q = dzero
5351  if (this%iboundpak(n) /= 0) then
5352  do i = this%ia(n) + 1, this%ia(n + 1) - 1
5353  if (this%idir(i) > 0) cycle
5354  idiv = this%idiv(i)
5355  if (idiv > 0) then
5356  jpos = this%iadiv(n) + idiv - 1
5357  q = q + this%divq(jpos)
5358  else
5359  q = q + this%qconn(i)
5360  end if
5361  end do
5362  q = q - this%dsflow(n)
5363  if (this%imover == 1) then
5364  q = q + this%pakmvrobj%get_qtomvr(n)
5365  end if
5366  else
5367  if (this%imover == 1) then
5368  q = this%pakmvrobj%get_qfrommvr(n)
5369  end if
5370  end if
5371  call this%budobj%budterm(idx)%update_term(n, n, q)
5372  end do
5373  !
5374  ! -- STORAGE
5375  idx = idx + 1
5376  call this%budobj%budterm(idx)%reset(this%maxbound)
5377  do n = 1, this%maxbound
5378  q = dzero
5379  if (this%iboundpak(n) /= 0) then
5380  d = this%depth(n)
5381  a = this%calc_surface_area_wet(n, d)
5382  this%qauxcbc(1) = a * d
5383  if (this%gwfiss == 0 .and. this%istorage == 1) then
5384  q = this%storage(n)
5385  end if
5386  else
5387  q = dzero
5388  this%qauxcbc(1) = dzero
5389  end if
5390  call this%budobj%budterm(idx)%update_term(n, n, q, this%qauxcbc)
5391  end do
5392  !
5393  ! -- MOVER
5394  if (this%imover == 1) then
5395  !
5396  ! -- FROM MOVER
5397  idx = idx + 1
5398  call this%budobj%budterm(idx)%reset(this%maxbound)
5399  do n = 1, this%maxbound
5400  q = dzero
5401  if (this%iboundpak(n) /= 0) then
5402  q = this%pakmvrobj%get_qfrommvr(n)
5403  end if
5404  call this%budobj%budterm(idx)%update_term(n, n, q)
5405  end do
5406  !
5407  ! -- TO MOVER
5408  idx = idx + 1
5409  call this%budobj%budterm(idx)%reset(this%maxbound)
5410  do n = 1, this%maxbound
5411  if (this%iboundpak(n) /= 0) then
5412  q = this%pakmvrobj%get_qtomvr(n)
5413  if (q > dzero) then
5414  q = -q
5415  end if
5416  else
5417  q = dzero
5418  end if
5419  call this%budobj%budterm(idx)%update_term(n, n, q)
5420  end do
5421  end if
5422  !
5423  ! -- AUXILIARY VARIABLES
5424  naux = this%naux
5425  if (naux > 0) then
5426  idx = idx + 1
5427  call this%budobj%budterm(idx)%reset(this%maxbound)
5428  do n = 1, this%maxbound
5429  q = dzero
5430  call this%budobj%budterm(idx)%update_term(n, n, q, this%auxvar(:, n))
5431  end do
5432  end if
5433  !
5434  ! --Terms are filled, now accumulate them for this time step
5435  call this%budobj%accumulate_terms()
5436  end subroutine sfr_fill_budobj
5437 
5438  !> @brief Setup stage table object for package
5439  !!
5440  !! Method to set up the table object that is used to write the sfr
5441  !! stage data. The terms listed here must correspond in number and
5442  !! order to the ones written to the stage table in the sfr_ot method.
5443  !<
5444  subroutine sfr_setup_tableobj(this)
5445  ! -- dummy
5446  class(sfrtype) :: this !< SfrType object
5447  ! -- local
5448  integer(I4B) :: nterms
5449  character(len=LINELENGTH) :: title
5450  character(len=LINELENGTH) :: text
5451  !
5452  ! -- setup stage table
5453  if (this%iprhed > 0) then
5454  !
5455  ! -- Determine the number of sfr budget terms. These are fixed for
5456  ! the simulation and cannot change. This includes FLOW-JA-FACE
5457  ! so they can be written to the binary budget files, but these internal
5458  ! flows are not included as part of the budget table.
5459  nterms = 8
5460  if (this%inamedbound == 1) then
5461  nterms = nterms + 1
5462  end if
5463  !
5464  ! -- set up table title
5465  title = trim(adjustl(this%text))//' PACKAGE ('// &
5466  trim(adjustl(this%packName))//') STAGES FOR EACH CONTROL VOLUME'
5467  !
5468  ! -- set up stage tableobj
5469  call table_cr(this%stagetab, this%packName, title)
5470  call this%stagetab%table_df(this%maxbound, nterms, this%iout, &
5471  transient=.true.)
5472  !
5473  ! -- Go through and set up table budget term
5474  if (this%inamedbound == 1) then
5475  text = 'NAME'
5476  call this%stagetab%initialize_column(text, lenboundname, &
5477  alignment=tableft)
5478  end if
5479  !
5480  ! -- reach number
5481  text = 'NUMBER'
5482  call this%stagetab%initialize_column(text, 10, alignment=tabcenter)
5483  !
5484  ! -- cellids
5485  text = 'CELLID'
5486  call this%stagetab%initialize_column(text, 20, alignment=tableft)
5487  !
5488  ! -- reach stage
5489  text = 'STAGE'
5490  call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
5491  !
5492  ! -- reach depth
5493  text = 'DEPTH'
5494  call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
5495  !
5496  ! -- reach width
5497  text = 'WIDTH'
5498  call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
5499  !
5500  ! -- gwf head
5501  text = 'GWF HEAD'
5502  call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
5503  !
5504  ! -- streambed conductance
5505  text = 'STREAMBED CONDUCTANCE'
5506  call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
5507  !
5508  ! -- streambed gradient
5509  text = 'STREAMBED GRADIENT'
5510  call this%stagetab%initialize_column(text, 12, alignment=tabcenter)
5511  end if
5512  !
5513  ! -- setup Courant number table
5514  if (this%istorage == 1) then
5515  nterms = 4
5516  if (this%inamedbound == 1) then
5517  nterms = nterms + 1
5518  end if
5519  !
5520  ! -- set up table title
5521  title = trim(adjustl(this%text))//' PACKAGE ('// &
5522  trim(adjustl(this%packName))//') COURANT NUMBER FOR EACH REACH'
5523  !
5524  ! -- set up Courant tableobj
5525  call table_cr(this%couranttab, this%packName, title)
5526  call this%couranttab%table_df(this%maxbound, nterms, this%iout)
5527  !
5528  if (this%inamedbound == 1) then
5529  text = 'NAME'
5530  call this%couranttab%initialize_column(text, lenboundname, &
5531  alignment=tableft)
5532  end if
5533  !
5534  ! -- reach number
5535  text = 'NUMBER'
5536  call this%couranttab%initialize_column(text, 10, alignment=tabcenter)
5537  !
5538  ! -- minimum Courant number
5539  text = 'MINIMUM'
5540  call this%couranttab%initialize_column(text, 16, alignment=tabcenter)
5541  !
5542  ! -- maximum Courant number
5543  text = 'MAXIMUM'
5544  call this%couranttab%initialize_column(text, 16, alignment=tabcenter)
5545  !
5546  ! -- mean Courant number
5547  text = 'MEAN'
5548  call this%couranttab%initialize_column(text, 16, alignment=tabcenter)
5549  end if
5550  end subroutine sfr_setup_tableobj
5551 
5552  ! -- reach geometry functions
5553 
5554  !> @brief Calculate wetted area
5555  !!
5556  !! Function to calculate the wetted area for a SFR package reach.
5557  !<
5558  function calc_area_wet(this, n, depth)
5559  ! -- return variable
5560  real(dp) :: calc_area_wet !< wetted area
5561  ! -- dummy
5562  class(sfrtype) :: this !< SfrType object
5563  integer(I4B), intent(in) :: n !< reach number
5564  real(dp), intent(in) :: depth !< reach depth
5565  ! -- local
5566  integer(I4B) :: npts
5567  integer(I4B) :: i0
5568  integer(I4B) :: i1
5569  !
5570  ! -- Calculate wetted area
5571  npts = this%ncrosspts(n)
5572  i0 = this%iacross(n)
5573  i1 = this%iacross(n + 1) - 1
5574  if (npts > 1) then
5575  calc_area_wet = get_cross_section_area(npts, this%station(i0:i1), &
5576  this%xsheight(i0:i1), depth)
5577  else
5578  calc_area_wet = this%station(i0) * depth
5579  end if
5580  end function calc_area_wet
5581 
5582  !> @brief Calculate wetted perimeter
5583  !!
5584  !! Function to calculate the wetted perimeter for a SFR package reach.
5585  !<
5586  function calc_perimeter_wet(this, n, depth)
5587  ! -- return variable
5588  real(dp) :: calc_perimeter_wet !< wetted perimeter
5589  ! -- dummy
5590  class(sfrtype) :: this !< SfrType object
5591  integer(I4B), intent(in) :: n !< reach number
5592  real(dp), intent(in) :: depth !< reach depth
5593  ! -- local
5594  integer(I4B) :: npts
5595  integer(I4B) :: i0
5596  integer(I4B) :: i1
5597  !
5598  ! -- Calculate wetted perimeter
5599  npts = this%ncrosspts(n)
5600  i0 = this%iacross(n)
5601  i1 = this%iacross(n + 1) - 1
5602  if (npts > 1) then
5603  calc_perimeter_wet = get_wetted_perimeter(npts, this%station(i0:i1), &
5604  this%xsheight(i0:i1), depth)
5605  else
5606  calc_perimeter_wet = this%station(i0) ! no depth dependence in original implementation
5607  end if
5608  end function calc_perimeter_wet
5609 
5610  !> @brief Calculate maximum surface area
5611  !!
5612  !! Function to calculate the maximum surface area for a SFR package reach.
5613  !<
5614  function calc_surface_area(this, n)
5615  ! -- return variable
5616  real(dp) :: calc_surface_area !< surface area
5617  ! -- dummy
5618  class(sfrtype) :: this !< SfrType object
5619  integer(I4B), intent(in) :: n !< reach number
5620  ! -- local
5621  integer(I4B) :: npts
5622  integer(I4B) :: i0
5623  integer(I4B) :: i1
5624  real(dp) :: top_width
5625  !
5626  ! -- Calculate surface area
5627  npts = this%ncrosspts(n)
5628  i0 = this%iacross(n)
5629  i1 = this%iacross(n + 1) - 1
5630  if (npts > 1) then
5631  top_width = get_saturated_topwidth(npts, this%station(i0:i1))
5632  else
5633  top_width = this%station(i0)
5634  end if
5635  calc_surface_area = top_width * this%length(n)
5636  end function calc_surface_area
5637 
5638  !> @brief Calculate wetted surface area
5639  !!
5640  !! Function to calculate the wetted surface area for a SFR package reach.
5641  !<
5642  function calc_surface_area_wet(this, n, depth)
5643  ! -- return variable
5644  real(dp) :: calc_surface_area_wet !< wetted surface area
5645  ! -- dummy
5646  class(sfrtype) :: this !< SfrType object
5647  integer(I4B), intent(in) :: n !< reach number
5648  real(dp), intent(in) :: depth !< reach depth
5649  ! -- local
5650  real(dp) :: top_width
5651  !
5652  ! -- Calculate wetted surface area
5653  top_width = this%calc_top_width_wet(n, depth)
5654  calc_surface_area_wet = top_width * this%length(n)
5655  end function calc_surface_area_wet
5656 
5657  !> @brief Calculate wetted top width
5658  !!
5659  !! Function to calculate the wetted top width for a SFR package reach.
5660  !<
5661  function calc_top_width_wet(this, n, depth)
5662  ! -- return variable
5663  real(dp) :: calc_top_width_wet !< wetted top width
5664  ! -- dummy
5665  class(sfrtype) :: this !< SfrType object
5666  integer(I4B), intent(in) :: n !< reach number
5667  real(dp), intent(in) :: depth !< reach depth
5668  ! -- local
5669  integer(I4B) :: npts
5670  integer(I4B) :: i0
5671  integer(I4B) :: i1
5672  real(dp) :: sat
5673  !
5674  ! -- Calculate wetted top width
5675  npts = this%ncrosspts(n)
5676  i0 = this%iacross(n)
5677  i1 = this%iacross(n + 1) - 1
5678  sat = scubicsaturation(dem5, dzero, depth, dem5)
5679  if (npts > 1) then
5680  calc_top_width_wet = sat * get_wetted_topwidth(npts, &
5681  this%station(i0:i1), &
5682  this%xsheight(i0:i1), &
5683  depth)
5684  else
5685  calc_top_width_wet = sat * this%station(i0)
5686  end if
5687  end function calc_top_width_wet
5688 
5689  !> @brief Activate density terms
5690  !!
5691  !! Method to activate addition of density terms for a SFR package reach.
5692  !<
5693  subroutine sfr_activate_density(this)
5694  ! -- modules
5696  ! -- dummy
5697  class(sfrtype), intent(inout) :: this !< SfrType object
5698  ! -- local
5699  integer(I4B) :: i
5700  integer(I4B) :: j
5701  !
5702  ! -- Set idense and reallocate denseterms to be of size MAXBOUND
5703  this%idense = 1
5704  call mem_reallocate(this%denseterms, 3, this%MAXBOUND, 'DENSETERMS', &
5705  this%memoryPath)
5706  do i = 1, this%maxbound
5707  do j = 1, 3
5708  this%denseterms(j, i) = dzero
5709  end do
5710  end do
5711  write (this%iout, '(/1x,a)') 'DENSITY TERMS HAVE BEEN ACTIVATED FOR SFR &
5712  &PACKAGE: '//trim(adjustl(this%packName))
5713  end subroutine sfr_activate_density
5714 
5715  !> @brief Activate viscosity terms
5716  !!
5717  !! Method to activate addition of viscosity terms for exchange
5718  !! with groundwater along a SFR package reach.
5719  !<
5720  subroutine sfr_activate_viscosity(this)
5721  ! -- modules
5723  ! -- dummy
5724  class(sfrtype), intent(inout) :: this !< SfrType object
5725  ! -- local
5726  integer(I4B) :: i
5727  integer(I4B) :: j
5728  !
5729  ! -- Set ivsc and reallocate viscratios to be of size MAXBOUND
5730  this%ivsc = 1
5731  call mem_reallocate(this%viscratios, 2, this%MAXBOUND, 'VISCRATIOS', &
5732  this%memoryPath)
5733  do i = 1, this%maxbound
5734  do j = 1, 2
5735  this%viscratios(j, i) = done
5736  end do
5737  end do
5738  write (this%iout, '(/1x,a)') 'VISCOSITY HAS BEEN ACTIVATED FOR SFR &
5739  &PACKAGE: '//trim(adjustl(this%packName))
5740  end subroutine sfr_activate_viscosity
5741 
5742  !> @brief Calculate density terms
5743  !!
5744  !! Method to calculate groundwater-reach density exchange terms for a
5745  !! SFR package reach.
5746  !!
5747  !! Member variable used here
5748  !! denseterms : shape (3, MAXBOUND), filled by buoyancy package
5749  !! col 1 is relative density of sfr (densesfr / denseref)
5750  !! col 2 is relative density of gwf cell (densegwf / denseref)
5751  !! col 3 is elevation of gwf cell
5752  !<
5753  subroutine sfr_calculate_density_exchange(this, n, stage, head, cond, &
5754  tops, flow, gwfhcof, gwfrhs)
5755  ! -- dummy
5756  class(sfrtype), intent(inout) :: this !< SfrType object
5757  integer(I4B), intent(in) :: n !< reach number
5758  real(DP), intent(in) :: stage !< reach stage
5759  real(DP), intent(in) :: head !< head in connected GWF cell
5760  real(DP), intent(in) :: cond !< reach conductance
5761  real(DP), intent(in) :: tops !< top elevation of streambed
5762  real(DP), intent(inout) :: flow !< calculated flow, updated here with density terms
5763  real(DP), intent(inout) :: gwfhcof !< GWF diagonal coefficient, updated here with density terms
5764  real(DP), intent(inout) :: gwfrhs !< GWF right-hand-side value, updated here with density terms
5765  ! -- local
5766  real(DP) :: ss
5767  real(DP) :: hh
5768  real(DP) :: havg
5769  real(DP) :: rdensesfr
5770  real(DP) :: rdensegwf
5771  real(DP) :: rdenseavg
5772  real(DP) :: elevsfr
5773  real(DP) :: elevgwf
5774  real(DP) :: elevavg
5775  real(DP) :: d1
5776  real(DP) :: d2
5777  logical(LGP) :: stage_below_bot
5778  logical(LGP) :: head_below_bot
5779  !
5780  ! -- Set sfr density to sfr density or gwf density
5781  if (stage >= tops) then
5782  ss = stage
5783  stage_below_bot = .false.
5784  rdensesfr = this%denseterms(1, n) ! sfr rel density
5785  else
5786  ss = tops
5787  stage_below_bot = .true.
5788  rdensesfr = this%denseterms(2, n) ! gwf rel density
5789  end if
5790  !
5791  ! -- set hh to head or tops (top elev of streambed)
5792  if (head >= tops) then
5793  hh = head
5794  head_below_bot = .false.
5795  rdensegwf = this%denseterms(2, n) ! gwf rel density
5796  else
5797  hh = tops
5798  head_below_bot = .true.
5799  rdensegwf = this%denseterms(1, n) ! sfr rel density
5800  end if
5801  !
5802  ! -- todo: hack because denseterms not updated in a cf calculation
5803  if (rdensegwf == dzero) return
5804  !
5805  ! -- Update flow
5806  if (stage_below_bot .and. head_below_bot) then
5807  !
5808  ! -- flow is zero, so no terms are updated
5809  !
5810  else
5811  !
5812  ! -- calculate average relative density
5813  rdenseavg = dhalf * (rdensesfr + rdensegwf)
5814  !
5815  ! -- Add contribution of first density term:
5816  ! cond * (denseavg/denseref - 1) * (hgwf - hsfr)
5817  d1 = cond * (rdenseavg - done)
5818  gwfhcof = gwfhcof - d1
5819  gwfrhs = gwfrhs - d1 * ss
5820  d1 = d1 * (hh - ss)
5821  flow = flow + d1
5822  !
5823  ! -- Add second density term if stage and head not below bottom
5824  if (.not. stage_below_bot .and. .not. head_below_bot) then
5825  !
5826  ! -- Add contribution of second density term:
5827  ! cond * (havg - elevavg) * (densegwf - densesfr) / denseref
5828  elevgwf = this%denseterms(3, n)
5829  elevsfr = tops
5830  elevavg = dhalf * (elevsfr + elevgwf)
5831  havg = dhalf * (hh + ss)
5832  d2 = cond * (havg - elevavg) * (rdensegwf - rdensesfr)
5833  gwfrhs = gwfrhs + d2
5834  flow = flow + d2
5835  end if
5836  end if
5837  end subroutine sfr_calculate_density_exchange
5838 
5839  !> @brief Bind SfrInputType PERIOD pointers to input context arrays.
5840  !!
5841  !! Called once from sfr_ar; PACKAGEDATA pointers are set separately
5842  !! in sfr_source_packagedata.
5843  !<
5844  subroutine sfr_input_init(this, mempath, naux)
5845  use memorymanagermodule, only: mem_setptr
5846  class(sfrinputtype), intent(inout) :: this
5847  character(len=*), intent(in) :: mempath
5848  integer(I4B), intent(in) :: naux
5849  call mem_setptr(this%nbound, 'NBOUND', mempath)
5850  call mem_setptr(this%ifno, 'IFNO', mempath)
5851  call mem_setptr(this%setting, 'SETTING', mempath)
5852  call mem_setptr(this%status, 'STATUS', mempath)
5853  call mem_setptr(this%idv, 'IDV', mempath)
5854  call mem_setptr(this%tab6_filename, 'TAB6_FILENAME', mempath)
5855  if (naux > 0) then
5856  call mem_setptr(this%auxname, 'AUXNAME', mempath)
5857  call mem_setptr(this%auxval, 'AUXVAL', mempath)
5858  end if
5859  end subroutine sfr_input_init
5860 
5861  !> @brief Nullify all SfrInputType pointers.
5862  !<
5863  subroutine sfr_input_destroy(this)
5864  class(sfrinputtype), intent(inout) :: this
5865  nullify (this%rhk)
5866  nullify (this%man)
5867  nullify (this%ustrf)
5868  nullify (this%rhk_tslink)
5869  nullify (this%man_tslink)
5870  nullify (this%ustrf_tslink)
5871  nullify (this%nbound)
5872  nullify (this%ifno)
5873  nullify (this%status)
5874  nullify (this%setting)
5875  nullify (this%idv)
5876  nullify (this%tab6_filename)
5877  nullify (this%auxname)
5878  nullify (this%auxval)
5879  end subroutine sfr_input_destroy
5880 
5881 end module sfrmodule
subroutine init()
Definition: GridSorting.f90:25
This module contains the extended boundary package.
This module contains the base boundary package.
This module contains the BudgetModule.
Definition: Budget.f90:20
subroutine, public budgetobject_cr(this, name)
Create a new budget object.
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
real(dp), parameter dhdry
real dry cell constant
Definition: Constants.f90:94
@ tabcenter
centered table column
Definition: Constants.f90:173
@ tabright
right justified table column
Definition: Constants.f90:174
@ tableft
left justified table column
Definition: Constants.f90:172
@ mnormal
normal output mode
Definition: Constants.f90:207
real(dp), parameter dtwothirds
real constant 2/3
Definition: Constants.f90:70
integer(i4b), parameter lenpackagename
maximum length of the package name
Definition: Constants.f90:23
real(dp), parameter dp9
real constant 9/10
Definition: Constants.f90:72
real(dp), parameter deight
real constant 8
Definition: Constants.f90:83
real(dp), parameter dfivethirds
real constant 5/3
Definition: Constants.f90:78
real(dp), parameter dp999
real constant 999/1000
Definition: Constants.f90:74
integer(i4b), parameter namedboundflag
named bound flag
Definition: Constants.f90:49
real(dp), parameter donethird
real constant 1/3
Definition: Constants.f90:67
real(dp), parameter dnodata
real no data constant
Definition: Constants.f90:95
real(dp), parameter d1p1
real constant 1.1
Definition: Constants.f90:77
real(dp), parameter dhnoflo
real no flow constant
Definition: Constants.f90:93
real(dp), parameter dhundred
real constant 100
Definition: Constants.f90:86
integer(i4b), parameter lenpakloc
maximum length of a package location
Definition: Constants.f90:50
real(dp), parameter dep20
real constant 1e20
Definition: Constants.f90:91
real(dp), parameter dp6
real constant 3/5
Definition: Constants.f90:69
integer(i4b), parameter maxadpit
maximum advanced package Newton-Raphson iterations
Definition: Constants.f90:53
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
real(dp), parameter dhalf
real constant 1/2
Definition: Constants.f90:68
integer(i4b), parameter lenftype
maximum length of a package type (DIS, WEL, OC, etc.)
Definition: Constants.f90:39
real(dp), parameter dpi
real constant
Definition: Constants.f90:128
real(dp), parameter dp99
real constant 99/100
Definition: Constants.f90:73
integer(i4b), parameter lenboundname
maximum length of a bound name
Definition: Constants.f90:36
real(dp), parameter dem4
real constant 1e-4
Definition: Constants.f90:107
real(dp), parameter dem30
real constant 1e-30
Definition: Constants.f90:118
real(dp), parameter dem6
real constant 1e-6
Definition: Constants.f90:109
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter dem5
real constant 1e-5
Definition: Constants.f90:108
real(dp), parameter dprec
real constant machine precision
Definition: Constants.f90:120
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:47
real(dp), parameter dp7
real constant 7/10
Definition: Constants.f90:71
real(dp), parameter dem2
real constant 1e-2
Definition: Constants.f90:105
real(dp), parameter dtwo
real constant 2
Definition: Constants.f90:79
integer(i4b), parameter lenbudtxt
maximum length of a budget component names
Definition: Constants.f90:37
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
This module contains stateless sfr subroutines and functions.
real(dp) function, public get_wetted_topwidth(npts, stations, heights, d)
Calculate the wetted top width for a reach.
real(dp) function, public get_wetted_perimeter(npts, stations, heights, d)
Calculate the wetted perimeter for a reach.
real(dp) function, public get_cross_section_area(npts, stations, heights, d)
Calculate the cross-sectional area for a reach.
real(dp) function, public get_saturated_topwidth(npts, stations)
Calculate the saturated top width for a reach.
real(dp) function, public get_mannings_section(npts, stations, heights, roughfracs, roughness, conv_fact, slope, d)
Calculate the manning's discharge for a reach.
subroutine, public assign_iounit(iounit, errunit, description)
@ brief assign io unit number
subroutine, public extract_idnum_or_bndname(line, icol, istart, istop, idnum, bndname)
Starting at position icol, define string as line(istart:istop).
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public upcase(word)
Convert to upper case.
subroutine, public ulasav(buf, text, kstp, kper, pertim, totim, ncol, nrow, ilay, ichn)
Save 1 layer array on disk.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
This module defines variable data types.
Definition: kind.f90:8
Previous variable names checked in as deprecated aliases.
Definition: MemoryAlias.f90:7
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
subroutine, public memorystore_release(varname, memory_path)
Release a single variable from the memory store.
subroutine, public get_isize(name, mem_path, isize)
@ brief Get the number of elements for this variable
This module contains the derived types ObserveType and ObsDataType.
Definition: Observe.f90:15
character(len=20) access
Definition: OpenSpec.f90:7
character(len=20) form
Definition: OpenSpec.f90:7
subroutine, public cross_section_cr(this, iout, iprpak, nreaches)
Create a cross-section object.
This module contains the SFR package methods.
Definition: gwf-sfr.f90:7
subroutine sfr_source_connectiondata(this)
Source CONNECTIONDATA block from input context.
Definition: gwf-sfr.f90:1276
subroutine sfr_source_initialstages(this)
Source INITIALSTAGES block from input context.
Definition: gwf-sfr.f90:1614
subroutine sfr_calc_celerity(this, n, q, celerity)
Kinematic-wave celerity from a flow perturbation (0 if dry)
Definition: gwf-sfr.f90:2841
real(dp) function calc_top_width_wet(this, n, depth)
Calculate wetted top width.
Definition: gwf-sfr.f90:5662
subroutine sfr_precompute_tvd(this)
Pre-compute the single upstream reach index for the TVD limiter.
Definition: gwf-sfr.f90:3029
subroutine sfr_setup_tableobj(this)
Setup stage table object for package.
Definition: gwf-sfr.f90:5445
subroutine sfr_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak)
@ brief Convergence check for package.
Definition: gwf-sfr.f90:2310
subroutine sfr_cq(this, x, flowja, iadv)
@ brief Calculate package flows.
Definition: gwf-sfr.f90:2511
subroutine sfr_ot_package_flows(this, icbcfl, ibudfl)
@ brief Output package flow terms.
Definition: gwf-sfr.f90:2588
subroutine sfr_activate_viscosity(this)
Activate viscosity terms.
Definition: gwf-sfr.f90:5721
subroutine sfr_da(this)
@ brief Deallocate package memory
Definition: gwf-sfr.f90:2868
subroutine sfr_calc_reach_depth(this, n, q1, d1)
Calculate the depth at the midpoint.
Definition: gwf-sfr.f90:4073
real(dp) function calc_surface_area(this, n)
Calculate maximum surface area.
Definition: gwf-sfr.f90:5615
subroutine sfr_check_ustrf(this)
Check upstream fraction data.
Definition: gwf-sfr.f90:4773
subroutine sfr_source_packagedata(this)
Source PACKAGEDATA block from input context.
Definition: gwf-sfr.f90:1010
subroutine sfr_calc_xs_depth(this, n, qrch, d)
Calculate the depth at the midpoint of a irregular cross-section.
Definition: gwf-sfr.f90:4108
subroutine sfr_check_diversions(this)
Check diversions data.
Definition: gwf-sfr.f90:4611
subroutine sfr_ot_dv(this, idvsave, idvprint)
@ brief Output package dependent-variable terms.
Definition: gwf-sfr.f90:2641
subroutine, public sfr_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, mempath)
@ brief Create a new package object
Definition: gwf-sfr.f90:369
subroutine sfr_dt(this)
Submit the ATS time step for the most Courant-constraining reach.
Definition: gwf-sfr.f90:2803
subroutine sfr_fc(this, rhs, ia, idxglo, matrix_sln)
@ brief Copy hcof and rhs terms into solution.
Definition: gwf-sfr.f90:2160
subroutine sfr_fn(this, rhs, ia, idxglo, matrix_sln)
@ brief Add Newton-Raphson terms for package into solution.
Definition: gwf-sfr.f90:2260
subroutine define_listlabel(this)
@ brief Define the list label for the package
Definition: gwf-sfr.f90:3060
subroutine sfr_df_obs(this)
Define the observation types available in the package.
Definition: gwf-sfr.f90:3104
subroutine sfr_calc_cond(this, n, depth, cond, hsfr, h_temp)
Calculate reach-aquifer conductance.
Definition: gwf-sfr.f90:3972
subroutine sfr_check_connections(this)
Check connection data.
Definition: gwf-sfr.f90:4335
subroutine sfr_source_options(this)
Source OPTIONS from input context.
Definition: gwf-sfr.f90:756
subroutine sfr_input_destroy(this)
Nullify all SfrInputType pointers.
Definition: gwf-sfr.f90:5864
subroutine sfr_allocate_arrays(this)
@ brief Allocate arrays
Definition: gwf-sfr.f90:484
subroutine sfr_bd_obs(this)
Save observations for the package.
Definition: gwf-sfr.f90:3200
subroutine sfr_source_crosssections(this)
Source CROSSSECTIONS block from input context.
Definition: gwf-sfr.f90:1186
subroutine sfr_setup_budobj(this)
Setup budget object for package.
Definition: gwf-sfr.f90:4998
subroutine sfr_check_initialstages(this)
Check initial stage data.
Definition: gwf-sfr.f90:4718
subroutine sfr_rp(this)
@ brief Read and prepare period data for package
Definition: gwf-sfr.f90:1784
subroutine sfr_input_init(this, mempath, naux)
Bind SfrInputType PERIOD pointers to input context arrays.
Definition: gwf-sfr.f90:5845
subroutine sfr_ar(this)
@ brief Allocate and read method for package
Definition: gwf-sfr.f90:1683
subroutine sfr_calc_qman(this, n, depth, qman)
Calculate streamflow.
Definition: gwf-sfr.f90:3815
subroutine sfr_fp(this)
Write the Courant-number summary table to the listing file.
Definition: gwf-sfr.f90:2768
subroutine sfr_check_reaches(this)
Check reach data.
Definition: gwf-sfr.f90:4217
real(dp) function calc_perimeter_wet(this, n, depth)
Calculate wetted perimeter.
Definition: gwf-sfr.f90:5587
subroutine sfr_update_flows(this, n, qd, qgwf)
Update flow terms.
Definition: gwf-sfr.f90:3624
subroutine sfr_calc_qd(this, n, depth, hgwf, qgwf, qd)
Calculate downstream flow term.
Definition: gwf-sfr.f90:3734
subroutine sfr_fill_budobj(this)
Copy flow terms into budget object for package.
Definition: gwf-sfr.f90:5213
subroutine sfr_cf(this)
@ brief Formulate the package hcof and rhs terms.
Definition: gwf-sfr.f90:2132
subroutine sfr_ot_bdsummary(this, kstp, kper, iout, ibudfl)
@ brief Output advanced package budget summary.
Definition: gwf-sfr.f90:2753
subroutine sfr_calc_div(this, n, i, qd, qdiv)
Calculate diversion flow.
Definition: gwf-sfr.f90:4019
subroutine sfr_calc_qgwf(this, n, depth, hgwf, qgwf, gwfhcof, gwfrhs)
Calculate reach-aquifer exchange.
Definition: gwf-sfr.f90:3885
character(len=lenftype) ftype
package ftype string
Definition: gwf-sfr.f90:50
subroutine sfr_calculate_density_exchange(this, n, stage, head, cond, tops, flow, gwfhcof, gwfrhs)
Calculate density terms.
Definition: gwf-sfr.f90:5755
subroutine sfr_source_dimensions(this)
Source DIMENSIONS block from input context and load static data.
Definition: gwf-sfr.f90:940
character(len=lenpackagename) text
package budget string
Definition: gwf-sfr.f90:51
subroutine sfr_set_period_value(this, i, n, setting)
Apply a PERIOD setting value to reach n.
Definition: gwf-sfr.f90:4975
subroutine sfr_calc_qsource(this, n, depth, qsrc)
Calculate sum of sources.
Definition: gwf-sfr.f90:3767
subroutine sfr_checkin_deprecated_names(this)
Alias deprecated SFR variable names to their current storage.
Definition: gwf-sfr.f90:709
subroutine sfr_allocate_scalars(this)
@ brief Allocate scalars
Definition: gwf-sfr.f90:413
logical function sfr_obs_supported(this)
Determine if observations are supported.
Definition: gwf-sfr.f90:3092
subroutine sfr_source_diversions(this)
Source DIVERSIONS block from input context.
Definition: gwf-sfr.f90:1463
subroutine sfr_check_storage_weight(this)
Check storage weight.
Definition: gwf-sfr.f90:4193
subroutine sfr_solve(this, n, h, hcof, rhs, update)
Solve reach continuity equation.
Definition: gwf-sfr.f90:3440
real(dp) function calc_area_wet(this, n, depth)
Calculate wetted area.
Definition: gwf-sfr.f90:5559
subroutine sfr_rp_obs(this)
Read and prepare observations for a package.
Definition: gwf-sfr.f90:3292
subroutine sfr_activate_density(this)
Activate density terms.
Definition: gwf-sfr.f90:5694
subroutine sfr_adjust_ro_ev(this, qc, qu, qi, qr, qro, qe, qfrommvr)
Adjust runoff and evaporation.
Definition: gwf-sfr.f90:3694
subroutine sfr_check_conversion(this)
Check unit conversion data.
Definition: gwf-sfr.f90:4156
real(dp) function calc_surface_area_wet(this, n, depth)
Calculate wetted surface area.
Definition: gwf-sfr.f90:5643
integer(i4b) function sfr_gwf_conn(this, n)
Determine if a reach is connected to a gwf cell.
Definition: gwf-sfr.f90:3952
subroutine sfr_ad(this)
@ brief Advance the package
Definition: gwf-sfr.f90:2034
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_warning(msg, substring)
Store warning message.
Definition: Sim.f90:237
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
integer(i4b) function, public count_errors()
Return number of errors.
Definition: Sim.f90:59
subroutine, public deprecation_warning(cblock, cvar, cver, endmsg, iunit)
Store deprecation warning message.
Definition: Sim.f90:257
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition: Sim.f90:204
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
character(len=maxcharlen) warnmsg
warning message string
real(dp) function squadraticsaturation(top, bot, x, eps)
@ brief sQuadraticSaturation
real(dp) function scubicsaturation(top, bot, x, eps)
@ brief sCubicSaturation
real(dp) function squadraticsaturationderivative(top, bot, x, eps)
@ brief Derivative of the quadratic saturation function
real(dp) function sqsaturationderivative(top, bot, x, c1, c2)
@ brief sQSaturationDerivative
subroutine schsmooth(d, smooth, dwdh)
@ brief sChSmooth
real(dp) function sqsaturation(top, bot, x, c1, c2)
@ brief sQSaturation
subroutine, public table_cr(this, name, title)
Definition: Table.f90:87
real(dp), pointer, public pertim
time relative to start of stress period
Definition: tdis.f90:33
real(dp), pointer, public totim
time relative to start of simulation
Definition: tdis.f90:35
class(atstype), pointer, public ats
Definition: tdis.f90:48
integer(i4b), pointer, public inats
flag indicating ats active for simulation
Definition: tdis.f90:28
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:27
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:26
real(dp), pointer, public delt
length of the current time step
Definition: tdis.f90:32
@ brief BndType
Derived type for the Budget object.
Definition: Budget.f90:40
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23
Input context array pointers for SFR.
Definition: gwf-sfr.f90:62