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