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