MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
Budget.f90
Go to the documentation of this file.
1 !> @brief This module contains the BudgetModule
2 !!
3 !! New entries can be added for each time step, however, the same number of
4 !! entries must be provided, and they must be provided in the same order. If not,
5 !! the module will terminate with an error.
6 !!
7 !! Maxsize is required as part of the df method and the arrays will be allocated
8 !! to maxsize. If additional entries beyond maxsize are added, the arrays
9 !! will dynamically increase in size, however, to avoid allocation and copying,
10 !! it is best to set maxsize large enough up front.
11 !!
12 !! vbvl(1, :) contains cumulative rate in
13 !! vbvl(2, :) contains cumulative rate out
14 !! vbvl(3, :) contains rate in
15 !! vbvl(4, :) contains rate out
16 !! vbnm(:) contains a LENBUDTXT character text string for each entry
17 !! rowlabel(:) contains a LENBUDROWLABEL character text string to write as a label for each entry
18 !!
19 !<
21 
22  use kindmodule, only: dp, i4b
25  dtwo, dhundred
26 
27  implicit none
28  private
29  public :: budgettype
30  public :: budget_cr
31  public :: rate_accumulator
32  public :: value_to_string
33 
34  !> @brief Derived type for the Budget object
35  !!
36  !! This derived type stores and prints information about a
37  !! model budget.
38  !!
39  !<
41  integer(I4B), pointer :: msum => null()
42  integer(I4B), pointer :: maxsize => null()
43  real(dp), pointer :: budperc => null()
44  logical, pointer :: written_once => null()
45  real(dp), dimension(:, :), pointer :: vbvl => null()
46  character(len=LENBUDTXT), dimension(:), pointer, contiguous :: vbnm => null()
47  character(len=20), pointer :: bdtype => null()
48  character(len=5), pointer :: bddim => null()
49  character(len=LENBUDROWLABEL), &
50  dimension(:), pointer, contiguous :: rowlabel => null()
51  character(len=16), pointer :: labeltitle => null()
52  character(len=20), pointer :: bdzone => null()
53  logical, pointer :: labeled => null()
54  !
55  ! -- csv output
56  integer(I4B), pointer :: ibudcsv => null()
57  integer(I4B), pointer :: icsvheader => null()
58 
59  contains
60  procedure :: budget_df
61  procedure :: budget_ot
62  procedure :: budget_da
63  procedure :: set_ibudcsv
64  procedure :: reset
65  procedure :: add_single_entry
66  procedure :: add_multi_entry
67  generic :: addentry => add_single_entry, add_multi_entry
68  procedure :: finalize_step
69  procedure :: writecsv
70  ! -- private
71  procedure :: allocate_scalars
72  procedure, private :: allocate_arrays
73  procedure, private :: resize
74  procedure, private :: write_csv_header
75  end type budgettype
76 
77 contains
78 
79  !> @ brief Create a new budget object
80  !!
81  !! Create a new budget object.
82  !!
83  !<
84  subroutine budget_cr(this, name_model)
85  ! -- modules
86  ! -- dummy
87  type(budgettype), pointer :: this !< BudgetType object
88  character(len=*), intent(in) :: name_model !< name of the model
89  !
90  ! -- Create the object
91  allocate (this)
92  !
93  ! -- Allocate scalars
94  call this%allocate_scalars(name_model)
95  end subroutine budget_cr
96 
97  !> @ brief Define information for this object
98  !!
99  !! Allocate arrays and set member variables
100  !!
101  !<
102  subroutine budget_df(this, maxsize, bdtype, bddim, labeltitle, bdzone)
103  class(budgettype) :: this !< BudgetType object
104  integer(I4B), intent(in) :: maxsize !< maximum size of budget arrays
105  character(len=*), optional :: bdtype !< type of budget, default is VOLUME
106  character(len=*), optional :: bddim !< dimensions of terms, default is L**3
107  character(len=*), optional :: labeltitle !< budget label, default is PACKAGE NAME
108  character(len=*), optional :: bdzone !< corresponding zone, default is ENTIRE MODEL
109  !
110  ! -- Set values
111  this%maxsize = maxsize
112  !
113  ! -- Allocate arrays
114  call this%allocate_arrays()
115  !
116  ! -- Set the budget type
117  if (present(bdtype)) then
118  this%bdtype = bdtype
119  else
120  this%bdtype = 'VOLUME'
121  end if
122  !
123  ! -- Set the budget dimension
124  if (present(bddim)) then
125  this%bddim = bddim
126  else
127  this%bddim = 'L**3'
128  end if
129  !
130  ! -- Set the budget zone
131  if (present(bdzone)) then
132  this%bdzone = bdzone
133  else
134  this%bdzone = 'ENTIRE MODEL'
135  end if
136  !
137  ! -- Set the label title
138  if (present(labeltitle)) then
139  this%labeltitle = labeltitle
140  else
141  this%labeltitle = 'PACKAGE NAME'
142  end if
143  end subroutine budget_df
144 
145  !> @ brief Convert a number to a string
146  !!
147  !! This is sometimes needed to avoid numbers that do not fit
148  !! correctly into a text string
149  !!
150  !<
151  subroutine value_to_string(val, string, big, small)
152  real(dp), intent(in) :: val !< value to convert
153  character(len=*), intent(out) :: string !< string to fill
154  real(dp), intent(in) :: big !< big value
155  real(dp), intent(in) :: small !< small value
156  real(dp) :: absval
157  !
158  absval = abs(val)
159  if (val /= dzero .and. (absval >= big .or. absval < small)) then
160  if (absval >= 9.99995d99 .or. absval < 1.d-99) then
161  ! -- if exponent has 3 digits, then need to explicitly use the ES
162  ! format to force writing the E character. the upper bound
163  ! accounts for values that round up to 1.0000E+100.
164  write (string, '(es17.4E3)') val
165  else
166  write (string, '(1pe17.4)') val
167  end if
168  else
169  ! -- value is within range where number looks good with F format
170  write (string, '(f17.4)') val
171  end if
172  end subroutine value_to_string
173 
174  !> @ brief Output the budget table
175  !!
176  !! Write the budget table for the current set of budget
177  !! information.
178  !!
179  !<
180  subroutine budget_ot(this, kstp, kper, iout)
181  class(budgettype) :: this !< BudgetType object
182  integer(I4B), intent(in) :: kstp !< time step
183  integer(I4B), intent(in) :: kper !< stress period
184  integer(I4B), intent(in) :: iout !< output unit number
185  character(len=17) :: val1, val2
186  integer(I4B) :: msum1, l
187  real(DP) :: two, hund, bigvl1, bigvl2, small, &
188  totrin, totrot, totvin, totvot, diffr, adiffr, &
189  pdiffr, pdiffv, avgrat, diffv, adiffv, avgvol
190  !
191  ! -- Set constants
192  two = 2.d0
193  hund = 100.d0
194  bigvl1 = 9.99999d11
195  bigvl2 = 9.99999d10
196  small = 0.1d0
197  !
198  ! -- Determine number of individual budget entries.
199  this%budperc = dzero
200  msum1 = this%msum - 1
201  if (msum1 <= 0) return
202  !
203  ! -- Clear rate and volume accumulators.
204  totrin = dzero
205  totrot = dzero
206  totvin = dzero
207  totvot = dzero
208  !
209  ! -- Add rates and volumes (in and out) to accumulators.
210  do l = 1, msum1
211  totrin = totrin + this%vbvl(3, l)
212  totrot = totrot + this%vbvl(4, l)
213  totvin = totvin + this%vbvl(1, l)
214  totvot = totvot + this%vbvl(2, l)
215  end do
216  !
217  ! -- Print time step number and stress period number.
218  if (this%labeled) then
219  write (iout, 261) trim(adjustl(this%bdtype)), trim(adjustl(this%bdzone)), &
220  kstp, kper
221  write (iout, 266) trim(adjustl(this%bdtype)), trim(adjustl(this%bddim)), &
222  trim(adjustl(this%bddim)), this%labeltitle
223  else
224  write (iout, 260) trim(adjustl(this%bdtype)), trim(adjustl(this%bdzone)), &
225  kstp, kper
226  write (iout, 265) trim(adjustl(this%bdtype)), trim(adjustl(this%bddim)), &
227  trim(adjustl(this%bddim))
228  end if
229  !
230  ! -- Print individual inflow rates and volumes and their totals.
231  do l = 1, msum1
232  call value_to_string(this%vbvl(1, l), val1, bigvl1, small)
233  call value_to_string(this%vbvl(3, l), val2, bigvl1, small)
234  if (this%labeled) then
235  write (iout, 276) this%vbnm(l), val1, this%vbnm(l), val2, this%rowlabel(l)
236  else
237  write (iout, 275) this%vbnm(l), val1, this%vbnm(l), val2
238  end if
239  end do
240  call value_to_string(totvin, val1, bigvl1, small)
241  call value_to_string(totrin, val2, bigvl1, small)
242  write (iout, 286) val1, val2
243  !
244  ! -- Print individual outflow rates and volumes and their totals.
245  write (iout, 287)
246  do l = 1, msum1
247  call value_to_string(this%vbvl(2, l), val1, bigvl1, small)
248  call value_to_string(this%vbvl(4, l), val2, bigvl1, small)
249  if (this%labeled) then
250  write (iout, 276) this%vbnm(l), val1, this%vbnm(l), val2, this%rowlabel(l)
251  else
252  write (iout, 275) this%vbnm(l), val1, this%vbnm(l), val2
253  end if
254  end do
255  call value_to_string(totvot, val1, bigvl1, small)
256  call value_to_string(totrot, val2, bigvl1, small)
257  write (iout, 298) val1, val2
258  !
259  ! -- Calculate the difference between inflow and outflow.
260  !
261  ! -- Calculate difference between rate in and rate out.
262  diffr = totrin - totrot
263  adiffr = abs(diffr)
264  !
265  ! -- Calculate percent difference between rate in and rate out.
266  pdiffr = dzero
267  avgrat = (totrin + totrot) / two
268  if (avgrat /= dzero) pdiffr = hund * diffr / avgrat
269  this%budperc = pdiffr
270  !
271  ! -- Calculate difference between volume in and volume out.
272  diffv = totvin - totvot
273  adiffv = abs(diffv)
274  !
275  ! -- Get percent difference between volume in and volume out.
276  pdiffv = dzero
277  avgvol = (totvin + totvot) / two
278  if (avgvol /= dzero) pdiffv = hund * diffv / avgvol
279  !
280  ! -- Print differences and percent differences between input
281  ! -- and output rates and volumes.
282  call value_to_string(diffv, val1, bigvl2, small)
283  call value_to_string(diffr, val2, bigvl2, small)
284  write (iout, 299) val1, val2
285  write (iout, 300) pdiffv, pdiffr
286  !
287  ! -- flush the file
288  flush (iout)
289  !
290  ! -- set written_once to .true.
291  this%written_once = .true.
292  !
293  ! -- formats
294 260 FORMAT(//2x, a, ' BUDGET FOR ', a, ' AT END OF' &
295  , ' TIME STEP', i5, ', STRESS PERIOD', i4 / 2x, 78('-'))
296 261 FORMAT(//2x, a, ' BUDGET FOR ', a, ' AT END OF' &
297  , ' TIME STEP', i5, ', STRESS PERIOD', i4 / 2x, 99('-'))
298 265 FORMAT(1x, /5x, 'CUMULATIVE ', a, 6x, a, 7x &
299  , 'RATES FOR THIS TIME STEP', 6x, a, '/T'/5x, 18('-'), 17x, 24('-') &
300  //11x, 'IN:', 38x, 'IN:'/11x, '---', 38x, '---')
301 266 FORMAT(1x, /5x, 'CUMULATIVE ', a, 6x, a, 7x &
302  , 'RATES FOR THIS TIME STEP', 6x, a, '/T', 10x, a16, &
303  /5x, 18('-'), 17x, 24('-'), 21x, 16('-') &
304  //11x, 'IN:', 38x, 'IN:'/11x, '---', 38x, '---')
305 275 FORMAT(1x, 3x, a16, ' =', a17, 6x, a16, ' =', a17)
306 276 FORMAT(1x, 3x, a16, ' =', a17, 6x, a16, ' =', a17, 5x, a)
307 286 FORMAT(1x, /12x, 'TOTAL IN =', a, 14x, 'TOTAL IN =', a)
308 287 FORMAT(1x, /10x, 'OUT:', 37x, 'OUT:'/10x, 4('-'), 37x, 4('-'))
309 298 FORMAT(1x, /11x, 'TOTAL OUT =', a, 13x, 'TOTAL OUT =', a)
310 299 FORMAT(1x, /12x, 'IN - OUT =', a, 14x, 'IN - OUT =', a)
311 300 FORMAT(1x, /1x, 'PERCENT DISCREPANCY =', f15.2 &
312  , 5x, 'PERCENT DISCREPANCY =', f15.2/)
313  end subroutine budget_ot
314 
315  !> @ brief Deallocate memory
316  !!
317  !! Deallocate budget memory
318  !!
319  !<
320  subroutine budget_da(this)
321  class(budgettype) :: this !< BudgetType object
322  !
323  ! -- Scalars
324  deallocate (this%msum)
325  deallocate (this%maxsize)
326  deallocate (this%budperc)
327  deallocate (this%written_once)
328  deallocate (this%labeled)
329  deallocate (this%bdtype)
330  deallocate (this%bddim)
331  deallocate (this%labeltitle)
332  deallocate (this%bdzone)
333  deallocate (this%ibudcsv)
334  deallocate (this%icsvheader)
335  !
336  ! -- Arrays
337  deallocate (this%vbvl)
338  deallocate (this%vbnm)
339  deallocate (this%rowlabel)
340  end subroutine budget_da
341 
342  !> @ brief Reset the budget object
343  !!
344  !! Reset the budget object in preparation for next set of entries
345  !!
346  !<
347  subroutine reset(this)
348  ! -- modules
349  ! -- dummy
350  class(budgettype) :: this !< BudgetType object
351  ! -- local
352  integer(I4B) :: i
353  !
354  this%msum = 1
355  do i = 1, this%maxsize
356  this%vbvl(3, i) = dzero
357  this%vbvl(4, i) = dzero
358  end do
359  end subroutine reset
360 
361  !> @ brief Add a single row of information
362  !!
363  !! Add information corresponding to one row in the budget table
364  !! rin the inflow rate
365  !! rout is the outflow rate
366  !! delt is the time step length
367  !! text is the name of the entry
368  !! isupress_accumulate is an optional flag. If specified as 1, then
369  !! the volume is NOT added to the accumulators on vbvl(1, :) and vbvl(2, :).
370  !! rowlabel is a LENBUDROWLABEL character text entry that is written to the
371  !! right of the table. It can be used for adding package names to budget
372  !! entries.
373  !!
374  !<
375  subroutine add_single_entry(this, rin, rout, delt, text, &
376  isupress_accumulate, rowlabel)
377  ! -- dummy
378  class(budgettype) :: this !< BudgetType object
379  real(DP), intent(in) :: rin !< inflow rate
380  real(DP), intent(in) :: rout !< outflow rate
381  real(DP), intent(in) :: delt !< time step length
382  character(len=LENBUDTXT), intent(in) :: text !< name of the entry
383  integer(I4B), optional, intent(in) :: isupress_accumulate !< accumulate flag
384  character(len=*), optional, intent(in) :: rowlabel !< row label
385  ! -- local
386  character(len=LINELENGTH) :: errmsg
387  character(len=*), parameter :: fmtbuderr = &
388  &"('Error in MODFLOW 6.', 'Entries do not match: ', (a), (a) )"
389  integer(i4b) :: iscv
390  integer(I4B) :: maxsize
391  !
392  iscv = 0
393  if (present(isupress_accumulate)) then
394  iscv = isupress_accumulate
395  end if
396  !
397  ! -- ensure budget arrays are large enough
398  maxsize = this%msum
399  if (maxsize > this%maxsize) then
400  call this%resize(maxsize)
401  end if
402  !
403  ! -- If budget has been written at least once, then make sure that the present
404  ! text entry matches the last text entry
405  if (this%written_once) then
406  if (trim(adjustl(this%vbnm(this%msum))) /= trim(adjustl(text))) then
407  write (errmsg, fmtbuderr) trim(adjustl(this%vbnm(this%msum))), &
408  trim(adjustl(text))
409  call store_error(errmsg, terminate=.true.)
410  end if
411  end if
412  !
413  this%vbvl(3, this%msum) = rin
414  this%vbvl(4, this%msum) = rout
415  this%vbnm(this%msum) = adjustr(text)
416  if (present(rowlabel)) then
417  this%rowlabel(this%msum) = adjustl(rowlabel)
418  this%labeled = .true.
419  end if
420  this%msum = this%msum + 1
421  end subroutine add_single_entry
422 
423  !> @ brief Add multiple rows of information
424  !!
425  !! Add information corresponding to one multiple rows in the budget table
426  !! budterm is an array with inflow in column 1 and outflow in column 2
427  !! delt is the time step length
428  !! budtxt is the name of the entries. It should have one entry for each
429  !! row in budterm
430  !! isupress_accumulate is an optional flag. If specified as 1, then
431  !! the volume is NOT added to the accumulators on vbvl(1, :) and vbvl(2, :).
432  !! rowlabel is a LENBUDROWLABEL character text entry that is written to the
433  !! right of the table. It can be used for adding package names to budget
434  !! entries. For multiple entries, the same rowlabel is used for each entry.
435  !!
436  !<
437  subroutine add_multi_entry(this, budterm, delt, budtxt, &
438  isupress_accumulate, rowlabel)
439  ! -- dummy
440  class(budgettype) :: this !< BudgetType object
441  real(DP), dimension(:, :), intent(in) :: budterm !< array of budget terms
442  real(DP), intent(in) :: delt !< time step length
443  character(len=LENBUDTXT), dimension(:), intent(in) :: budtxt !< name of the entries
444  integer(I4B), optional, intent(in) :: isupress_accumulate !< suppress accumulate
445  character(len=*), optional, intent(in) :: rowlabel !< row label
446  ! -- local
447  character(len=LINELENGTH) :: errmsg
448  character(len=*), parameter :: fmtbuderr = &
449  &"('Error in MODFLOW 6.', 'Entries do not match: ', (a), (a) )"
450  integer(i4b) :: iscv, i
451  integer(I4B) :: nbudterms, maxsize
452  !
453  iscv = 0
454  if (present(isupress_accumulate)) then
455  iscv = isupress_accumulate
456  end if
457  !
458  ! -- ensure budget arrays are large enough
459  nbudterms = size(budtxt)
460  maxsize = this%msum - 1 + nbudterms
461  if (maxsize > this%maxsize) then
462  call this%resize(maxsize)
463  end if
464  !
465  ! -- Process each of the multi-entry budget terms
466  do i = 1, size(budtxt)
467  !
468  ! -- If budget has been written at least once, then make sure that the present
469  ! text entry matches the last text entry
470  if (this%written_once) then
471  if (trim(adjustl(this%vbnm(this%msum))) /= &
472  trim(adjustl(budtxt(i)))) then
473  write (errmsg, fmtbuderr) trim(adjustl(this%vbnm(this%msum))), &
474  trim(adjustl(budtxt(i)))
475  call store_error(errmsg)
476  end if
477  end if
478  !
479  this%vbvl(3, this%msum) = budterm(1, i)
480  this%vbvl(4, this%msum) = budterm(2, i)
481  this%vbnm(this%msum) = adjustr(budtxt(i))
482  if (present(rowlabel)) then
483  this%rowlabel(this%msum) = adjustl(rowlabel)
484  this%labeled = .true.
485  end if
486  this%msum = this%msum + 1
487  !
488  end do
489  !
490  ! -- Check for errors
491  if (count_errors() > 0) then
492  call store_error('Could not add multi-entry', terminate=.true.)
493  end if
494  end subroutine add_multi_entry
495 
496  !> @ brief Update accumulators
497  !!
498  !! This must be called before any output is written
499  !! in order to update the accumulators in vbvl(1,:)
500  !! and vbl(2,:).
501  !<
502  subroutine finalize_step(this, delt)
503  ! -- modules
504  ! -- dummy
505  class(budgettype) :: this !< BudgetType object
506  real(DP), intent(in) :: delt
507  ! -- local
508  integer(I4B) :: i
509  !
510  do i = 1, this%msum - 1
511  this%vbvl(1, i) = this%vbvl(1, i) + this%vbvl(3, i) * delt
512  this%vbvl(2, i) = this%vbvl(2, i) + this%vbvl(4, i) * delt
513  end do
514  end subroutine finalize_step
515 
516  !> @ brief allocate scalar variables
517  !!
518  !! Allocate scalar variables of this budget object
519  !!
520  !<
521  subroutine allocate_scalars(this, name_model)
522  ! -- modules
523  ! -- dummy
524  class(budgettype) :: this !< BudgetType object
525  character(len=*), intent(in) :: name_model !< name of the model
526  !
527  allocate (this%msum)
528  allocate (this%maxsize)
529  allocate (this%budperc)
530  allocate (this%written_once)
531  allocate (this%labeled)
532  allocate (this%bdtype)
533  allocate (this%bddim)
534  allocate (this%labeltitle)
535  allocate (this%bdzone)
536  allocate (this%ibudcsv)
537  allocate (this%icsvheader)
538  !
539  ! -- Initialize values
540  this%msum = 0
541  this%maxsize = 0
542  this%written_once = .false.
543  this%labeled = .false.
544  this%bdtype = ''
545  this%bddim = ''
546  this%labeltitle = ''
547  this%bdzone = ''
548  this%ibudcsv = 0
549  this%icsvheader = 0
550  end subroutine allocate_scalars
551 
552  !> @ brief allocate array variables
553  !!
554  !! Allocate array variables of this budget object
555  !!
556  !<
557  subroutine allocate_arrays(this)
558  ! -- modules
559  ! -- dummy
560  class(budgettype) :: this !< BudgetType object
561  !
562  ! -- If redefining, then need to deallocate/reallocate
563  if (associated(this%vbvl)) then
564  deallocate (this%vbvl)
565  nullify (this%vbvl)
566  end if
567  if (associated(this%vbnm)) then
568  deallocate (this%vbnm)
569  nullify (this%vbnm)
570  end if
571  if (associated(this%rowlabel)) then
572  deallocate (this%rowlabel)
573  nullify (this%rowlabel)
574  end if
575  !
576  ! -- Allocate
577  allocate (this%vbvl(4, this%maxsize))
578  allocate (this%vbnm(this%maxsize))
579  allocate (this%rowlabel(this%maxsize))
580  !
581  ! -- Initialize values
582  this%vbvl(:, :) = dzero
583  this%vbnm(:) = ''
584  this%rowlabel(:) = ''
585  end subroutine allocate_arrays
586 
587  !> @ brief Resize the budget object
588  !!
589  !! If the size wasn't allocated to be large enough, then the budget object
590  !! we reallocate itself to a larger size.
591  !!
592  !<
593  subroutine resize(this, maxsize)
594  ! -- modules
595  ! -- dummy
596  class(budgettype) :: this !< BudgetType object
597  integer(I4B), intent(in) :: maxsize !< maximum size
598  ! -- local
599  real(DP), dimension(:, :), allocatable :: vbvl
600  character(len=LENBUDTXT), dimension(:), allocatable :: vbnm
601  character(len=LENBUDROWLABEL), dimension(:), allocatable :: rowlabel
602  integer(I4B) :: maxsizeold
603  !
604  ! -- allocate and copy into local storage
605  maxsizeold = this%maxsize
606  allocate (vbvl(4, maxsizeold))
607  allocate (vbnm(maxsizeold))
608  allocate (rowlabel(maxsizeold))
609  vbvl(:, :) = this%vbvl(:, :)
610  vbnm(:) = this%vbnm(:)
611  rowlabel(:) = this%rowlabel(:)
612  !
613  ! -- Set new size and reallocate
614  this%maxsize = maxsize
615  call this%allocate_arrays()
616  !
617  ! -- Copy from local back into member variables
618  this%vbvl(:, 1:maxsizeold) = vbvl(:, 1:maxsizeold)
619  this%vbnm(1:maxsizeold) = vbnm(1:maxsizeold)
620  this%rowlabel(1:maxsizeold) = rowlabel(1:maxsizeold)
621  !
622  ! - deallocate local copies
623  deallocate (vbvl)
624  deallocate (vbnm)
625  deallocate (rowlabel)
626  end subroutine resize
627 
628  !> @ brief Rate accumulator subroutine
629  !!
630  !! Routing for tallying inflows and outflows of an array
631  !!
632  !<
633  subroutine rate_accumulator(flow, rin, rout)
634  ! -- modules
635  ! -- dummy
636  real(dp), dimension(:), contiguous, intent(in) :: flow !< array of flows
637  real(dp), intent(out) :: rin !< calculated sum of inflows
638  real(dp), intent(out) :: rout !< calculated sum of outflows
639  integer(I4B) :: n
640  !
641  rin = dzero
642  rout = dzero
643  do n = 1, size(flow)
644  if (flow(n) < dzero) then
645  rout = rout - flow(n)
646  else
647  rin = rin + flow(n)
648  end if
649  end do
650  end subroutine rate_accumulator
651 
652  !> @ brief Set unit number for csv output file
653  !!
654  !! This routine can be used to activate csv output
655  !! by passing in a valid unit number opened for output
656  !!
657  !<
658  subroutine set_ibudcsv(this, ibudcsv)
659  ! -- modules
660  ! -- dummy
661  class(budgettype) :: this !< BudgetType object
662  integer(I4B), intent(in) :: ibudcsv !< unit number for csv budget output
663  this%ibudcsv = ibudcsv
664  end subroutine set_ibudcsv
665 
666  !> @ brief Write csv output
667  !!
668  !! This routine will write a row of output to the
669  !! csv file, if it is available for output. Upon first
670  !! call, it will write the csv header.
671  !!
672  !<
673  subroutine writecsv(this, totim)
674  ! -- modules
675  ! -- dummy
676  class(budgettype) :: this !< BudgetType object
677  real(DP), intent(in) :: totim !< time corresponding to this data
678  ! -- local
679  integer(I4B) :: i
680  real(DP) :: totrin
681  real(DP) :: totrout
682  real(DP) :: diffr
683  real(DP) :: pdiffr
684  real(DP) :: avgrat
685  !
686  if (this%ibudcsv > 0) then
687  !
688  ! -- write header
689  if (this%icsvheader == 0) then
690  call this%write_csv_header()
691  this%icsvheader = 1
692  end if
693  !
694  ! -- Calculate in and out
695  totrin = dzero
696  totrout = dzero
697  do i = 1, this%msum - 1
698  totrin = totrin + this%vbvl(3, i)
699  totrout = totrout + this%vbvl(4, i)
700  end do
701  !
702  ! -- calculate percent difference
703  diffr = totrin - totrout
704  pdiffr = dzero
705  avgrat = (totrin + totrout) / dtwo
706  if (avgrat /= dzero) then
707  pdiffr = dhundred * diffr / avgrat
708  end if
709  !
710  ! -- write data
711  write (this%ibudcsv, '(*(G0,:,","))') &
712  totim, &
713  (this%vbvl(3, i), i=1, this%msum - 1), &
714  (this%vbvl(4, i), i=1, this%msum - 1), &
715  totrin, totrout, pdiffr
716  !
717  ! -- flush the file
718  flush (this%ibudcsv)
719  end if
720  end subroutine writecsv
721 
722  !> @ brief Write csv header
723  !!
724  !! This routine will write the csv header based on the
725  !! names in vbnm
726  !!
727  !<
728  subroutine write_csv_header(this)
729  ! -- modules
730  ! -- dummy
731  class(budgettype) :: this !< BudgetType object
732  ! -- local
733  integer(I4B) :: l
734  character(len=LINELENGTH) :: txt, txtl
735  write (this%ibudcsv, '(a)', advance='NO') 'time,'
736  !
737  ! -- first write IN
738  do l = 1, this%msum - 1
739  txt = this%vbnm(l)
740  txtl = ''
741  if (this%labeled) then
742  txtl = '('//trim(adjustl(this%rowlabel(l)))//')'
743  end if
744  txt = trim(adjustl(txt))//trim(adjustl(txtl))//'_IN,'
745  write (this%ibudcsv, '(a)', advance='NO') trim(adjustl(txt))
746  end do
747  !
748  ! -- then write OUT
749  do l = 1, this%msum - 1
750  txt = this%vbnm(l)
751  txtl = ''
752  if (this%labeled) then
753  txtl = '('//trim(adjustl(this%rowlabel(l)))//')'
754  end if
755  txt = trim(adjustl(txt))//trim(adjustl(txtl))//'_OUT,'
756  write (this%ibudcsv, '(a)', advance='NO') trim(adjustl(txt))
757  end do
758  write (this%ibudcsv, '(a)') 'TOTAL_IN,TOTAL_OUT,PERCENT_DIFFERENCE'
759  end subroutine write_csv_header
760 
761 end module budgetmodule
This module contains the BudgetModule.
Definition: Budget.f90:20
subroutine budget_ot(this, kstp, kper, iout)
@ brief Output the budget table
Definition: Budget.f90:181
subroutine budget_da(this)
@ brief Deallocate memory
Definition: Budget.f90:321
subroutine, public budget_cr(this, name_model)
@ brief Create a new budget object
Definition: Budget.f90:85
subroutine allocate_scalars(this, name_model)
@ brief allocate scalar variables
Definition: Budget.f90:522
subroutine add_single_entry(this, rin, rout, delt, text, isupress_accumulate, rowlabel)
@ brief Add a single row of information
Definition: Budget.f90:377
subroutine writecsv(this, totim)
@ brief Write csv output
Definition: Budget.f90:674
subroutine write_csv_header(this)
@ brief Write csv header
Definition: Budget.f90:729
subroutine resize(this, maxsize)
@ brief Resize the budget object
Definition: Budget.f90:594
subroutine, public rate_accumulator(flow, rin, rout)
@ brief Rate accumulator subroutine
Definition: Budget.f90:634
subroutine, public value_to_string(val, string, big, small)
@ brief Convert a number to a string
Definition: Budget.f90:152
subroutine allocate_arrays(this)
@ brief allocate array variables
Definition: Budget.f90:558
subroutine budget_df(this, maxsize, bdtype, bddim, labeltitle, bdzone)
@ brief Define information for this object
Definition: Budget.f90:103
subroutine add_multi_entry(this, budterm, delt, budtxt, isupress_accumulate, rowlabel)
@ brief Add multiple rows of information
Definition: Budget.f90:439
subroutine finalize_step(this, delt)
@ brief Update accumulators
Definition: Budget.f90:503
subroutine reset(this)
@ brief Reset the budget object
Definition: Budget.f90:348
subroutine set_ibudcsv(this, ibudcsv)
@ brief Set unit number for csv output file
Definition: Budget.f90:659
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
integer(i4b), parameter lenbudrowlabel
maximum length of the rowlabel string used in the budget table
Definition: Constants.f90:25
real(dp), parameter dhundred
real constant 100
Definition: Constants.f90:86
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
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
This module defines variable data types.
Definition: kind.f90:8
This module contains simulation methods.
Definition: Sim.f90:10
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
Derived type for the Budget object.
Definition: Budget.f90:40