MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
Disu.f90
Go to the documentation of this file.
1 module disumodule
2 
4  use kindmodule, only: dp, i4b, lgp
13  use basedismodule, only: disbasetype
18  use tdismodule, only: kstp, kper, pertim, totim, delt
19  use disvgeom, only: line_unit_vector
20 
21  implicit none
22 
23  private
24  public :: disutype
25  public :: disu_cr
26  public :: castasdisutype
27 
28  !> @brief Unstructured grid discretization
29  type, extends(disbasetype) :: disutype
30  integer(I4B), pointer :: njausr => null() ! user-specified nja size
31  integer(I4B), pointer :: nvert => null() ! number of x,y vertices
32  real(dp), pointer :: voffsettol => null() ! vertical offset tolerance
33  real(dp), dimension(:, :), pointer, contiguous :: vertices => null() ! cell vertices stored as 2d array of x and y
34  real(dp), dimension(:, :), pointer, contiguous :: cellxy => null() ! cell center stored as 2d array of x and y
35  real(dp), dimension(:), pointer, contiguous :: top1d => null() ! (size:nodesuser) cell top elevation
36  real(dp), dimension(:), pointer, contiguous :: bot1d => null() ! (size:nodesuser) cell bottom elevation
37  real(dp), dimension(:), pointer, contiguous :: area1d => null() ! (size:nodesuser) cell area, in plan view
38  integer(I4B), dimension(:), pointer, contiguous :: iainp => null() ! (size:nodesuser+1) user iac converted ia
39  integer(I4B), dimension(:), pointer, contiguous :: jainp => null() ! (size:njausr) user-input ja array
40  integer(I4B), dimension(:), pointer, contiguous :: ihcinp => null() ! (size:njausr) user-input ihc array
41  real(dp), dimension(:), pointer, contiguous :: cl12inp => null() ! (size:njausr) user-input cl12 array
42  real(dp), dimension(:), pointer, contiguous :: hwvainp => null() ! (size:njausr) user-input hwva array
43  real(dp), dimension(:), pointer, contiguous :: angldegxinp => null() ! (size:njausr) user-input angldegx array
44  integer(I4B), pointer :: iangledegx => null() ! =1 when angle information was present in input, 0 otherwise
45  integer(I4B), dimension(:), pointer, contiguous :: iavert => null() ! cell vertex pointer ia array
46  integer(I4B), dimension(:), pointer, contiguous :: javert => null() ! cell vertex pointer ja array
47  integer(I4B), dimension(:), pointer, contiguous :: idomain => null() ! idomain (nodes)
48  logical(LGP) :: readfromfile ! True, when DIS is read from file (almost always)
49 
50  contains
51 
52  procedure :: dis_df => disu_df
53  procedure :: disu_load
54  procedure :: dis_da => disu_da
55  procedure :: get_dis_type => get_dis_type
56  procedure :: get_dis_enum => get_dis_enum
57  procedure :: disu_ck
58  procedure :: grid_finalize
59  procedure :: get_nodenumber_idx1
60  procedure :: nodeu_to_string
61  procedure :: nodeu_to_array
62  procedure :: nodeu_from_string
63  procedure :: nodeu_from_cellid
64  procedure :: connection_normal
65  procedure :: connection_vector
66  procedure :: supports_layers
67  procedure :: get_ncpl
68  procedure, public :: record_array
69  procedure, public :: record_srcdst_list_header
70  ! -- private
71  procedure :: allocate_scalars
72  procedure :: allocate_arrays
73  procedure :: allocate_arrays_mem
74  procedure :: source_options
75  procedure :: source_dimensions
76  procedure :: source_griddata
77  procedure :: source_connectivity
78  procedure :: source_vertices
79  procedure :: source_cell2d
80  procedure :: log_options
81  procedure :: log_dimensions
82  procedure :: log_griddata
83  procedure :: log_connectivity
84  procedure :: define_cellverts
85  procedure :: write_grb
86  !
87  ! -- Read a node-sized model array (reduced or not)
88  procedure :: read_int_array
89  procedure :: read_dbl_array
90 
91  end type disutype
92 
94  logical :: length_units = .false.
95  logical :: nogrb = .false.
96  logical :: xorigin = .false.
97  logical :: yorigin = .false.
98  logical :: angrot = .false.
99  logical :: voffsettol = .false.
100  logical :: nodes = .false.
101  logical :: nja = .false.
102  logical :: nvert = .false.
103  logical :: top = .false.
104  logical :: bot = .false.
105  logical :: area = .false.
106  logical :: idomain = .false.
107  logical :: iac = .false.
108  logical :: ja = .false.
109  logical :: ihc = .false.
110  logical :: cl12 = .false.
111  logical :: hwva = .false.
112  logical :: angldegx = .false.
113  logical :: iv = .false.
114  logical :: xv = .false.
115  logical :: yv = .false.
116  logical :: icell2d = .false.
117  logical :: xc = .false.
118  logical :: yc = .false.
119  logical :: ncvert = .false.
120  logical :: icvert = .false.
121  end type disufoundtype
122 
123 contains
124 
125  !> @brief Create a new unstructured discretization object
126  !<
127  subroutine disu_cr(dis, name_model, input_mempath, inunit, iout)
128  ! -- dummy
129  class(disbasetype), pointer :: dis
130  character(len=*), intent(in) :: name_model
131  character(len=*), intent(in) :: input_mempath
132  integer(I4B), intent(in) :: inunit
133  integer(I4B), intent(in) :: iout
134  ! -- local
135  type(disutype), pointer :: disnew
136  character(len=*), parameter :: fmtheader = &
137  "(1X, /1X, 'DISU -- UNSTRUCTURED GRID DISCRETIZATION PACKAGE,', &
138  &' VERSION 2 : 3/27/2014 - INPUT READ FROM MEMPATH: ', A, //)"
139  !
140  ! -- Create a new discretization object
141  allocate (disnew)
142  dis => disnew
143  !
144  ! -- Allocate scalars and assign data
145  call dis%allocate_scalars(name_model, input_mempath)
146  dis%inunit = inunit
147  dis%iout = iout
148  !
149  ! -- If disu is enabled
150  if (inunit > 0) then
151  !
152  ! -- Identify package
153  if (iout > 0) then
154  write (iout, fmtheader) dis%input_mempath
155  end if
156  !
157  ! -- load disu
158  call disnew%disu_load()
159  end if
160  !
161  end subroutine disu_cr
162 
163  !> @brief Transfer IDM data into this discretization object
164  !<
165  subroutine disu_load(this)
166  ! -- dummy
167  class(disutype) :: this
168  !
169  ! -- source input data
170  call this%source_options()
171  call this%source_dimensions()
172  call this%source_griddata()
173  call this%source_connectivity()
174  !
175  ! -- If NVERT specified and greater than 0, then source VERTICES and CELL2D
176  if (this%nvert > 0) then
177  call this%source_vertices()
178  call this%source_cell2d()
179  else
180  ! -- connection direction information cannot be calculated
181  this%icondir = 0
182  end if
183  !
184  ! -- Make some final disu checks on the non-reduced user-provided
185  ! input
186  call this%disu_ck()
187  !
188  end subroutine disu_load
189 
190  !> @brief Define the discretization
191  !<
192  subroutine disu_df(this)
193  ! -- dummy
194  class(disutype) :: this
195  !
196  call this%grid_finalize()
197  !
198  end subroutine disu_df
199 
200  !> @brief Finalize the grid
201  !<
202  subroutine grid_finalize(this)
203  ! -- dummy
204  class(disutype) :: this
205  ! -- locals
206  integer(I4B) :: n
207  integer(I4B) :: node
208  integer(I4B) :: noder
209  integer(I4B) :: nrsize
210  ! -- formats
211  character(len=*), parameter :: fmtdz = &
212  "('CELL (',i0,',',i0,',',i0,') THICKNESS <= 0. ', &
213  &'TOP, BOT: ',2(1pg24.15))"
214  character(len=*), parameter :: fmtnr = &
215  "(/1x, 'The specified IDOMAIN results in a reduced number of cells.',&
216  &/1x, 'Number of user nodes: ',I0,&
217  &/1X, 'Number of nodes in solution: ', I0, //)"
218  !
219  ! -- count active cells
220  this%nodes = 0
221  do n = 1, this%nodesuser
222  if (this%idomain(n) > 0) this%nodes = this%nodes + 1
223  end do
224  !
225  ! -- Check to make sure nodes is a valid number
226  if (this%nodes == 0) then
227  call store_error('Model does not have any active nodes. &
228  &Ensure IDOMAIN array has some values greater &
229  &than zero.')
230  call store_error_filename(this%input_fname)
231  end if
232  !
233  ! -- Write message if reduced grid
234  if (this%nodes < this%nodesuser) then
235  write (this%iout, fmtnr) this%nodesuser, this%nodes
236  end if
237  !
238  ! -- Array size is now known, so allocate
239  call this%allocate_arrays()
240  !
241  ! -- Fill the nodereduced array with the reduced nodenumber, or
242  ! a negative number to indicate it is a pass-through cell, or
243  ! a zero to indicate that the cell is excluded from the
244  ! solution. (negative idomain not supported for disu)
245  if (this%nodes < this%nodesuser) then
246  noder = 1
247  do node = 1, this%nodesuser
248  if (this%idomain(node) > 0) then
249  this%nodereduced(node) = noder
250  noder = noder + 1
251  elseif (this%idomain(node) < 0) then
252  this%nodereduced(node) = -1
253  else
254  this%nodereduced(node) = 0
255  end if
256  end do
257  end if
258  !
259  ! -- Fill nodeuser if a reduced grid
260  if (this%nodes < this%nodesuser) then
261  noder = 1
262  do node = 1, this%nodesuser
263  if (this%idomain(node) > 0) then
264  this%nodeuser(noder) = node
265  noder = noder + 1
266  end if
267  end do
268  end if
269  !
270  ! -- Move top1d, bot1d, and area1d into top, bot, and area
271  do node = 1, this%nodesuser
272  noder = node
273  if (this%nodes < this%nodesuser) noder = this%nodereduced(node)
274  if (noder <= 0) cycle
275  this%top(noder) = this%top1d(node)
276  this%bot(noder) = this%bot1d(node)
277  this%area(noder) = this%area1d(node)
278  end do
279  !
280  ! -- fill cell center coordinates
281  if (this%nvert > 0) then
282  do node = 1, this%nodesuser
283  noder = node
284  if (this%nodes < this%nodesuser) noder = this%nodereduced(node)
285  if (noder <= 0) cycle
286  this%xc(noder) = this%cellxy(1, node)
287  this%yc(noder) = this%cellxy(2, node)
288  end do
289  else
290  call mem_reallocate(this%xc, 0, 'XC', this%memoryPath)
291  call mem_reallocate(this%yc, 0, 'YC', this%memoryPath)
292  end if
293  !
294  ! -- create and fill the connections object
295  nrsize = 0
296  if (this%nodes < this%nodesuser) nrsize = this%nodes
297  allocate (this%con)
298  call this%con%disuconnections(this%name_model, this%nodes, &
299  this%nodesuser, nrsize, &
300  this%nodereduced, this%nodeuser, &
301  this%iainp, this%jainp, &
302  this%ihcinp, this%cl12inp, &
303  this%hwvainp, this%angldegxinp, &
304  this%iangledegx)
305  this%nja = this%con%nja
306  this%njas = this%con%njas
307  !
308  end subroutine grid_finalize
309 
310  !> @brief Check discretization info
311  !<
312  subroutine disu_ck(this)
313  ! -- dummy
314  class(disutype) :: this
315  ! -- local
316  integer(I4B) :: n, m
317  integer(I4B) :: ipos
318  integer(I4B) :: ihc
319  real(DP) :: dz
320  ! -- formats
321  character(len=*), parameter :: fmtidm = &
322  &"('Invalid idomain value ', i0, ' specified for node ', i0)"
323  character(len=*), parameter :: fmtdz = &
324  &"('Cell ', i0, ' with thickness <= 0. Top, bot: ', 2(1pg24.15))"
325  character(len=*), parameter :: fmtarea = &
326  &"('Cell ', i0, ' with area <= 0. Area: ', 1(1pg24.15))"
327  character(len=*), parameter :: fmtjan = &
328  &"('Cell ', i0, ' must have its first connection be itself. Found: ', i0)"
329  character(len=*), parameter :: fmtjam = &
330  &"('Cell ', i0, ' has invalid connection in JA. Found: ', i0)"
331  character(len=*), parameter :: fmterrmsg = &
332  "('Top elevation (', 1pg15.6, ') for cell ', i0, ' is above bottom &
333  &elevation (', 1pg15.6, ') for cell ', i0, '. Based on node numbering &
334  &rules cell ', i0, ' must be below cell ', i0, '.')"
335  !
336  ! -- Check connectivity
337  do n = 1, this%nodesuser
338  !
339  ! -- Ensure first connection is to itself, and
340  ! that ja(ia(n)) is positive
341  ipos = this%iainp(n)
342  m = this%jainp(ipos)
343  if (m < 0) then
344  m = abs(m)
345  this%jainp(ipos) = m
346  end if
347  if (n /= m) then
348  write (errmsg, fmtjan) n, m
349  call store_error(errmsg)
350  end if
351  !
352  ! -- Check for valid node numbers in connected cells
353  do ipos = this%iainp(n) + 1, this%iainp(n + 1) - 1
354  m = this%jainp(ipos)
355  if (m < 0 .or. m > this%nodesuser) then
356  ! -- make sure first connection is to itself
357  write (errmsg, fmtjam) n, m
358  call store_error(errmsg)
359  end if
360  end do
361  end do
362  !
363  ! -- terminate if errors found
364  if (count_errors() > 0) then
365  if (this%inunit > 0) then
366  call store_error_filename(this%input_fname)
367  end if
368  end if
369  !
370  ! -- Ensure idomain values are valid
371  do n = 1, this%nodesuser
372  if (this%idomain(n) > 1 .or. this%idomain(n) < 0) then
373  write (errmsg, fmtidm) this%idomain(n), n
374  call store_error(errmsg)
375  end if
376  end do
377  !
378  ! -- Check for zero and negative thickness and zero or negative areas
379  ! for cells with idomain == 1
380  do n = 1, this%nodesuser
381  if (this%idomain(n) == 1) then
382  dz = this%top1d(n) - this%bot1d(n)
383  if (dz <= dzero) then
384  write (errmsg, fmt=fmtdz) n, this%top1d(n), this%bot1d(n)
385  call store_error(errmsg)
386  end if
387  if (this%area1d(n) <= dzero) then
388  write (errmsg, fmt=fmtarea) n, this%area1d(n)
389  call store_error(errmsg)
390  end if
391  end if
392  end do
393  !
394  ! -- check to make sure voffsettol is >= 0
395  if (this%voffsettol < dzero) then
396  write (errmsg, '(a, 1pg15.6)') &
397  'Vertical offset tolerance must be greater than zero. Found ', &
398  this%voffsettol
399  call store_error(errmsg)
400  if (this%inunit > 0) then
401  call store_error_filename(this%input_fname)
402  end if
403  end if
404  !
405  ! -- For cell n, ensure that underlying cells have tops less than
406  ! or equal to the bottom of cell n
407  do n = 1, this%nodesuser
408  do ipos = this%iainp(n) + 1, this%iainp(n + 1) - 1
409  m = this%jainp(ipos)
410  ihc = this%ihcinp(ipos)
411  if (ihc == 0 .and. m > n) then
412  dz = this%top1d(m) - this%bot1d(n)
413  if (dz > this%voffsettol) then
414  write (errmsg, fmterrmsg) this%top1d(m), m, this%bot1d(n), n, m, n
415  call store_error(errmsg)
416  end if
417  end if
418  end do
419  end do
420  !
421  ! -- terminate if errors found
422  if (count_errors() > 0) then
423  if (this%inunit > 0) then
424  call store_error_filename(this%input_fname)
425  end if
426  end if
427  !
428  end subroutine disu_ck
429 
430  !> @brief Deallocate variables
431  !<
432  subroutine disu_da(this)
433  ! -- dummy
434  class(disutype) :: this
435  !
436  ! -- Deallocate idm memory
437  call memorystore_remove(this%name_model, 'DISU', idm_context)
438  call memorystore_remove(component=this%name_model, &
439  context=idm_context)
440  !
441  ! -- scalars
442  call mem_deallocate(this%njausr)
443  call mem_deallocate(this%nvert)
444  call mem_deallocate(this%voffsettol)
445  call mem_deallocate(this%iangledegx)
446  !
447  ! -- arrays
448  if (this%readFromFile) then
449  call mem_deallocate(this%top1d)
450  call mem_deallocate(this%bot1d)
451  call mem_deallocate(this%area1d)
452  if (associated(this%iavert)) then
453  call mem_deallocate(this%iavert)
454  call mem_deallocate(this%javert)
455  end if
456  call mem_deallocate(this%vertices)
457  call mem_deallocate(this%iainp)
458  call mem_deallocate(this%jainp)
459  call mem_deallocate(this%ihcinp)
460  call mem_deallocate(this%cl12inp)
461  call mem_deallocate(this%hwvainp)
462  call mem_deallocate(this%angldegxinp)
463  end if
464  !
465  call mem_deallocate(this%idomain)
466  call mem_deallocate(this%cellxy)
467  !
468  call mem_deallocate(this%nodeuser)
469  call mem_deallocate(this%nodereduced)
470  !
471  ! -- DisBaseType deallocate
472  call this%DisBaseType%dis_da()
473  !
474  end subroutine disu_da
475 
476  !> @brief Convert a user nodenumber to a string (nodenumber)
477  !<
478  subroutine nodeu_to_string(this, nodeu, str)
479  ! -- dummy
480  class(disutype) :: this
481  integer(I4B), intent(in) :: nodeu
482  character(len=*), intent(inout) :: str
483  ! -- local
484  character(len=10) :: nstr
485  !
486  write (nstr, '(i0)') nodeu
487  str = '('//trim(adjustl(nstr))//')'
488  !
489  end subroutine nodeu_to_string
490 
491  !> @brief Convert a user nodenumber to an array (nodenumber)
492  !<
493  subroutine nodeu_to_array(this, nodeu, arr)
494  class(disutype) :: this
495  integer(I4B), intent(in) :: nodeu
496  integer(I4B), dimension(:), intent(inout) :: arr
497  ! -- local
498  integer(I4B) :: isize
499  !
500  ! -- check the size of arr
501  isize = size(arr)
502  if (isize /= this%ndim) then
503  write (errmsg, '(a,i0,a,i0,a)') &
504  'Program error: nodeu_to_array size of array (', isize, &
505  ') is not equal to the discretization dimension (', this%ndim, ')'
506  call store_error(errmsg, terminate=.true.)
507  end if
508  !
509  ! -- fill array
510  arr(1) = nodeu
511  !
512  end subroutine nodeu_to_array
513 
514  !> @brief Copy options from IDM into package
515  !<
516  subroutine source_options(this)
517  ! -- dummy
518  class(disutype) :: this
519  ! -- locals
520  character(len=LENVARNAME), dimension(3) :: lenunits = &
521  &[character(len=LENVARNAME) :: 'FEET', 'METERS', 'CENTIMETERS']
522  type(disufoundtype) :: found
523  !
524  ! -- update defaults with idm sourced values
525  call mem_set_value(this%lenuni, 'LENGTH_UNITS', this%input_mempath, &
526  lenunits, found%length_units)
527  call mem_set_value(this%nogrb, 'NOGRB', this%input_mempath, found%nogrb)
528  call mem_set_value(this%xorigin, 'XORIGIN', this%input_mempath, found%xorigin)
529  call mem_set_value(this%yorigin, 'YORIGIN', this%input_mempath, found%yorigin)
530  call mem_set_value(this%angrot, 'ANGROT', this%input_mempath, found%angrot)
531  call mem_set_value(this%voffsettol, 'VOFFSETTOL', this%input_mempath, &
532  found%voffsettol)
533  !
534  ! -- log values to list file
535  if (this%iout > 0) then
536  call this%log_options(found)
537  end if
538  !
539  end subroutine source_options
540 
541  !> @brief Write user options to list file
542  !<
543  subroutine log_options(this, found)
544  ! -- dummy
545  class(disutype) :: this
546  type(disufoundtype), intent(in) :: found
547  !
548  write (this%iout, '(1x,a)') 'Setting Discretization Options'
549  !
550  if (found%length_units) then
551  write (this%iout, '(4x,a,i0)') 'Model length unit [0=UND, 1=FEET, &
552  &2=METERS, 3=CENTIMETERS] set as ', this%lenuni
553  end if
554  !
555  if (found%nogrb) then
556  write (this%iout, '(4x,a,i0)') 'Binary grid file [0=GRB, 1=NOGRB] &
557  &set as ', this%nogrb
558  end if
559  !
560  if (found%xorigin) then
561  write (this%iout, '(4x,a,G0)') 'XORIGIN = ', this%xorigin
562  end if
563  !
564  if (found%yorigin) then
565  write (this%iout, '(4x,a,G0)') 'YORIGIN = ', this%yorigin
566  end if
567  !
568  if (found%angrot) then
569  write (this%iout, '(4x,a,G0)') 'ANGROT = ', this%angrot
570  end if
571  !
572  if (found%voffsettol) then
573  write (this%iout, '(4x,a,G0)') 'VERTICAL_OFFSET_TOLERANCE = ', &
574  this%voffsettol
575  end if
576  !
577  write (this%iout, '(1x,a,/)') 'End Setting Discretization Options'
578  !
579  end subroutine log_options
580 
581  !> @brief Copy dimensions from IDM into package
582  !<
583  subroutine source_dimensions(this)
584  ! -- dummy
585  class(disutype) :: this
586  ! -- locals
587  integer(I4B) :: n
588  type(disufoundtype) :: found
589  !
590  ! -- update defaults with idm sourced values
591  call mem_set_value(this%nodesuser, 'NODES', this%input_mempath, found%nodes)
592  call mem_set_value(this%njausr, 'NJA', this%input_mempath, found%nja)
593  call mem_set_value(this%nvert, 'NVERT', this%input_mempath, found%nvert)
594  !
595  ! -- log simulation values
596  if (this%iout > 0) then
597  call this%log_dimensions(found)
598  end if
599  !
600  ! -- verify dimensions were set
601  if (this%nodesuser < 1) then
602  call store_error( &
603  'NODES was not specified or was specified incorrectly.')
604  end if
605  if (this%njausr < 1) then
606  call store_error( &
607  'NJA was not specified or was specified incorrectly.')
608  end if
609  !
610  ! -- terminate if errors were detected
611  if (count_errors() > 0) then
612  call store_error_filename(this%input_fname)
613  end if
614  !
615  ! -- allocate vectors that are the size of nodesuser
616  this%readFromFile = .true.
617  call mem_allocate(this%top1d, this%nodesuser, 'TOP1D', this%memoryPath)
618  call mem_allocate(this%bot1d, this%nodesuser, 'BOT1D', this%memoryPath)
619  call mem_allocate(this%area1d, this%nodesuser, 'AREA1D', this%memoryPath)
620  call mem_allocate(this%idomain, this%nodesuser, 'IDOMAIN', this%memoryPath)
621  call mem_allocate(this%vertices, 2, this%nvert, 'VERTICES', this%memoryPath)
622  call mem_allocate(this%iainp, this%nodesuser + 1, 'IAINP', this%memoryPath)
623  call mem_allocate(this%jainp, this%njausr, 'JAINP', this%memoryPath)
624  call mem_allocate(this%ihcinp, this%njausr, 'IHCINP', this%memoryPath)
625  call mem_allocate(this%cl12inp, this%njausr, 'CL12INP', this%memoryPath)
626  call mem_allocate(this%hwvainp, this%njausr, 'HWVAINP', this%memoryPath)
627  call mem_allocate(this%angldegxinp, this%njausr, 'ANGLDEGXINP', &
628  this%memoryPath)
629  if (this%nvert > 0) then
630  call mem_allocate(this%cellxy, 2, this%nodesuser, 'CELLXY', this%memoryPath)
631  else
632  call mem_allocate(this%cellxy, 2, 0, 'CELLXY', this%memoryPath)
633  end if
634  !
635  ! -- initialize all cells to be active (idomain = 1)
636  do n = 1, this%nodesuser
637  this%idomain(n) = 1
638  end do
639  !
640  end subroutine source_dimensions
641 
642  !> @brief Write dimensions to list file
643  !<
644  subroutine log_dimensions(this, found)
645  class(disutype) :: this
646  type(disufoundtype), intent(in) :: found
647  !
648  write (this%iout, '(1x,a)') 'Setting Discretization Dimensions'
649  !
650  if (found%nodes) then
651  write (this%iout, '(4x,a,i0)') 'NODES = ', this%nodesuser
652  end if
653  !
654  if (found%nja) then
655  write (this%iout, '(4x,a,i0)') 'NJA = ', this%njausr
656  end if
657  !
658  if (found%nvert) then
659  write (this%iout, '(4x,a,i0)') 'NVERT = ', this%nvert
660  end if
661  !
662  write (this%iout, '(1x,a,/)') 'End Setting Discretization Dimensions'
663  !
664  end subroutine log_dimensions
665 
666  !> @brief Copy grid data from IDM into package
667  !<
668  subroutine source_griddata(this)
669  ! -- dummy
670  class(disutype) :: this
671  ! -- locals
672  type(disufoundtype) :: found
673  !
674  ! -- update defaults with idm sourced values
675  call mem_set_value(this%top1d, 'TOP', this%input_mempath, found%top)
676  call mem_set_value(this%bot1d, 'BOT', this%input_mempath, found%bot)
677  call mem_set_value(this%area1d, 'AREA', this%input_mempath, found%area)
678  call mem_set_value(this%idomain, 'IDOMAIN', this%input_mempath, found%idomain)
679  !
680  ! -- log simulation values
681  if (this%iout > 0) then
682  call this%log_griddata(found)
683  end if
684  !
685  end subroutine source_griddata
686 
687  !> @brief Write griddata found to list file
688  !<
689  subroutine log_griddata(this, found)
690  ! -- dummy
691  class(disutype) :: this
692  type(disufoundtype), intent(in) :: found
693  !
694  write (this%iout, '(1x,a)') 'Setting Discretization Griddata'
695  !
696  if (found%top) then
697  write (this%iout, '(4x,a)') 'TOP set from input file'
698  end if
699  !
700  if (found%bot) then
701  write (this%iout, '(4x,a)') 'BOT set from input file'
702  end if
703  !
704  if (found%area) then
705  write (this%iout, '(4x,a)') 'AREA set from input file'
706  end if
707  !
708  if (found%idomain) then
709  write (this%iout, '(4x,a)') 'IDOMAIN set from input file'
710  end if
711  !
712  write (this%iout, '(1x,a,/)') 'End Setting Discretization Griddata'
713  !
714  end subroutine log_griddata
715 
716  !> @brief Copy grid connectivity info from IDM into package
717  !<
718  subroutine source_connectivity(this)
719  ! -- dummy
720  class(disutype) :: this
721  ! -- locals
722  type(disufoundtype) :: found
723  integer(I4B), dimension(:), contiguous, pointer :: iac => null()
724  ! -- formats
725  !
726  ! -- update defaults with idm sourced values
727  call mem_set_value(this%jainp, 'JA', this%input_mempath, found%ja)
728  call mem_set_value(this%ihcinp, 'IHC', this%input_mempath, found%ihc)
729  call mem_set_value(this%cl12inp, 'CL12', this%input_mempath, found%cl12)
730  call mem_set_value(this%hwvainp, 'HWVA', this%input_mempath, found%hwva)
731  call mem_set_value(this%angldegxinp, 'ANGLDEGX', this%input_mempath, &
732  found%angldegx)
733  !
734  ! -- set pointer to iac input array
735  call mem_setptr(iac, 'IAC', this%input_mempath)
736  !
737  ! -- Convert iac to ia
738  if (associated(iac)) call iac_to_ia(iac, this%iainp)
739  !
740  ! -- Set angldegx flag if found
741  if (found%angldegx) this%iangledegx = 1
742  !
743  ! -- log simulation values
744  if (this%iout > 0) then
745  call this%log_connectivity(found, iac)
746  end if
747  !
748  end subroutine source_connectivity
749 
750  !> @brief Write griddata found to list file
751  !<
752  subroutine log_connectivity(this, found, iac)
753  class(disutype) :: this
754  type(disufoundtype), intent(in) :: found
755  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: iac
756  !
757  write (this%iout, '(1x,a)') 'Setting Discretization Connectivity'
758  !
759  if (associated(iac)) then
760  write (this%iout, '(4x,a)') 'IAC set from input file'
761  end if
762  !
763  if (found%ja) then
764  write (this%iout, '(4x,a)') 'JA set from input file'
765  end if
766  !
767  if (found%ihc) then
768  write (this%iout, '(4x,a)') 'IHC set from input file'
769  end if
770  !
771  if (found%cl12) then
772  write (this%iout, '(4x,a)') 'CL12 set from input file'
773  end if
774  !
775  if (found%hwva) then
776  write (this%iout, '(4x,a)') 'HWVA set from input file'
777  end if
778  !
779  if (found%angldegx) then
780  write (this%iout, '(4x,a)') 'ANGLDEGX set from input file'
781  end if
782  !
783  write (this%iout, '(1x,a,/)') 'End Setting Discretization Connectivity'
784  !
785  end subroutine log_connectivity
786 
787  !> @brief Copy grid vertex data from IDM into package
788  !<
789  subroutine source_vertices(this)
790  ! -- dummy
791  class(disutype) :: this
792  ! -- local
793  integer(I4B) :: i
794  real(DP), dimension(:), contiguous, pointer :: vert_x => null()
795  real(DP), dimension(:), contiguous, pointer :: vert_y => null()
796  ! -- formats
797  !
798  ! -- set pointers to memory manager input arrays
799  call mem_setptr(vert_x, 'XV', this%input_mempath)
800  call mem_setptr(vert_y, 'YV', this%input_mempath)
801  !
802  ! -- set vertices 2d array
803  if (associated(vert_x) .and. associated(vert_y)) then
804  do i = 1, this%nvert
805  this%vertices(1, i) = vert_x(i)
806  this%vertices(2, i) = vert_y(i)
807  end do
808  else
809  call store_error('Required Vertex arrays not found.')
810  end if
811  !
812  ! -- log
813  if (this%iout > 0) then
814  write (this%iout, '(1x,a)') 'Discretization Vertex data loaded'
815  end if
816  !
817  call memorystore_release('XV', this%input_mempath)
818  call memorystore_release('YV', this%input_mempath)
819  end subroutine source_vertices
820 
821  !> @brief Build data structures to hold cell vertex info
822  !<
823  subroutine define_cellverts(this, icell2d, ncvert, icvert)
824  ! -- modules
825  use sparsemodule, only: sparsematrix
826  ! -- dummy
827  class(disutype) :: this
828  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: icell2d
829  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: ncvert
830  integer(I4B), dimension(:), contiguous, pointer, intent(in) :: icvert
831  ! -- locals
832  type(sparsematrix) :: vert_spm
833  integer(I4B) :: i, j, ierr
834  integer(I4B) :: icv_idx, startvert, maxnnz = 5
835  !
836  ! -- initialize sparse matrix
837  call vert_spm%init(this%nodesuser, this%nvert, maxnnz)
838  !
839  ! -- add sparse matrix connections from input memory paths
840  icv_idx = 1
841  do i = 1, this%nodesuser
842  if (icell2d(i) /= i) call store_error('ICELL2D input sequence violation.')
843  do j = 1, ncvert(i)
844  call vert_spm%addconnection(i, icvert(icv_idx), 0)
845  if (j == 1) then
846  startvert = icvert(icv_idx)
847  elseif (j == ncvert(i) .and. (icvert(icv_idx) /= startvert)) then
848  call vert_spm%addconnection(i, startvert, 0)
849  end if
850  icv_idx = icv_idx + 1
851  end do
852  end do
853  !
854  ! -- allocate and fill iavert and javert
855  call mem_allocate(this%iavert, this%nodesuser + 1, 'IAVERT', this%memoryPath)
856  call mem_allocate(this%javert, vert_spm%nnz, 'JAVERT', this%memoryPath)
857  call vert_spm%filliaja(this%iavert, this%javert, ierr)
858  call vert_spm%destroy()
859  !
860  end subroutine define_cellverts
861 
862  !> @brief Copy cell2d data from IDM into package
863  !<
864  subroutine source_cell2d(this)
865  ! -- dummy
866  class(disutype) :: this
867  ! -- locals
868  integer(I4B), dimension(:), contiguous, pointer :: icell2d => null()
869  integer(I4B), dimension(:), contiguous, pointer :: ncvert => null()
870  integer(I4B), dimension(:), contiguous, pointer :: icvert => null()
871  real(DP), dimension(:), contiguous, pointer :: cell_x => null()
872  real(DP), dimension(:), contiguous, pointer :: cell_y => null()
873  integer(I4B) :: i
874  !
875  ! -- set pointers to input path ncvert and icvert
876  call mem_setptr(icell2d, 'ICELL2D', this%input_mempath)
877  call mem_setptr(ncvert, 'NCVERT', this%input_mempath)
878  call mem_setptr(icvert, 'ICVERT', this%input_mempath)
879  !
880  ! --
881  if (associated(icell2d) .and. associated(ncvert) &
882  .and. associated(icvert)) then
883  call this%define_cellverts(icell2d, ncvert, icvert)
884  else
885  call store_error('Required cell vertex arrays not found.')
886  end if
887  !
888  ! -- set pointers to cell center arrays
889  call mem_setptr(cell_x, 'XC', this%input_mempath)
890  call mem_setptr(cell_y, 'YC', this%input_mempath)
891  !
892  ! -- set cell centers
893  if (associated(cell_x) .and. associated(cell_y)) then
894  do i = 1, this%nodesuser
895  this%cellxy(1, i) = cell_x(i)
896  this%cellxy(2, i) = cell_y(i)
897  end do
898  else
899  call store_error('Required cell center arrays not found.')
900  end if
901  !
902  ! -- log
903  if (this%iout > 0) then
904  write (this%iout, '(1x,a)') 'Discretization Cell2d data loaded'
905  end if
906  !
907  call memorystore_release('ICELL2D', this%input_mempath)
908  call memorystore_release('NCVERT', this%input_mempath)
909  call memorystore_release('ICVERT', this%input_mempath)
910  call memorystore_release('XC', this%input_mempath)
911  call memorystore_release('YC', this%input_mempath)
912  end subroutine source_cell2d
913 
914  !> @brief Write a binary grid file
915  !<
916  subroutine write_grb(this, icelltype)
917  ! -- modules
918  use openspecmodule, only: access, form
919  use constantsmodule, only: lenbigline
920  ! -- dummy
921  class(disutype) :: this
922  integer(I4B), dimension(:), intent(in) :: icelltype
923  ! -- local
924  integer(I4B) :: i, iunit, ntxt, version
925  integer(I4B), parameter :: lentxt = 100
926  character(len=50) :: txthdr
927  character(len=lentxt) :: txt
928  character(len=LINELENGTH) :: fname
929  character(len=LENBIGLINE) :: crs
930  logical(LGP) :: found_crs
931  ! -- formats
932  character(len=*), parameter :: fmtgrdsave = &
933  "(4X,'BINARY GRID INFORMATION WILL BE WRITTEN TO:', &
934  &/,6X,'UNIT NUMBER: ', I0,/,6X, 'FILE NAME: ', A)"
935  !
936  ! -- Initialize
937  version = 1
938  ntxt = 11
939  if (this%nvert > 0) ntxt = ntxt + 5
940  !
941  call mem_set_value(crs, 'CRS', this%input_mempath, found_crs)
942  !
943  ! -- set version
944  if (found_crs) then
945  ntxt = ntxt + 1
946  version = 2
947  end if
948  !
949  ! -- Open the file
950  fname = trim(this%output_fname)
951  iunit = getunit()
952  write (this%iout, fmtgrdsave) iunit, trim(adjustl(fname))
953  call openfile(iunit, this%iout, trim(adjustl(fname)), 'DATA(BINARY)', &
954  form, access, 'REPLACE')
955  !
956  ! -- write header information
957  write (txthdr, '(a)') 'GRID DISU'
958  txthdr(50:50) = new_line('a')
959  write (iunit) txthdr
960  write (txthdr, '(a)') 'VERSION 1'
961  txthdr(50:50) = new_line('a')
962  write (iunit) txthdr
963  write (txthdr, '(a, i0)') 'NTXT ', ntxt
964  txthdr(50:50) = new_line('a')
965  write (iunit) txthdr
966  write (txthdr, '(a, i0)') 'LENTXT ', lentxt
967  txthdr(50:50) = new_line('a')
968  write (iunit) txthdr
969  !
970  ! -- write variable definitions
971  write (txt, '(3a, i0)') 'NODES ', 'INTEGER ', 'NDIM 0 # ', this%nodesuser
972  txt(lentxt:lentxt) = new_line('a')
973  write (iunit) txt
974  write (txt, '(3a, i0)') 'NJA ', 'INTEGER ', 'NDIM 0 # ', this%con%nja
975  txt(lentxt:lentxt) = new_line('a')
976  write (iunit) txt
977  write (txt, '(3a, 1pg24.15)') 'XORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%xorigin
978  txt(lentxt:lentxt) = new_line('a')
979  write (iunit) txt
980  write (txt, '(3a, 1pg24.15)') 'YORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%yorigin
981  txt(lentxt:lentxt) = new_line('a')
982  write (iunit) txt
983  write (txt, '(3a, 1pg24.15)') 'ANGROT ', 'DOUBLE ', 'NDIM 0 # ', this%angrot
984  txt(lentxt:lentxt) = new_line('a')
985  write (iunit) txt
986  write (txt, '(3a, i0)') 'TOP ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser
987  txt(lentxt:lentxt) = new_line('a')
988  write (iunit) txt
989  write (txt, '(3a, i0)') 'BOT ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser
990  txt(lentxt:lentxt) = new_line('a')
991  write (iunit) txt
992  write (txt, '(3a, i0)') 'IA ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1
993  txt(lentxt:lentxt) = new_line('a')
994  write (iunit) txt
995  write (txt, '(3a, i0)') 'JA ', 'INTEGER ', 'NDIM 1 ', this%con%nja
996  txt(lentxt:lentxt) = new_line('a')
997  write (iunit) txt
998  write (txt, '(3a, i0)') 'IDOMAIN ', 'INTEGER ', 'NDIM 1 ', this%nodesuser
999  txt(lentxt:lentxt) = new_line('a')
1000  write (iunit) txt
1001  write (txt, '(3a, i0)') 'ICELLTYPE ', 'INTEGER ', 'NDIM 1 ', this%nodesuser
1002  txt(lentxt:lentxt) = new_line('a')
1003  write (iunit) txt
1004  !
1005  ! -- if vertices have been read then write additional header information
1006  if (this%nvert > 0) then
1007  write (txt, '(3a, i0)') 'VERTICES ', 'DOUBLE ', 'NDIM 2 2 ', this%nvert
1008  txt(lentxt:lentxt) = new_line('a')
1009  write (iunit) txt
1010  write (txt, '(3a, i0)') 'CELLX ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser
1011  txt(lentxt:lentxt) = new_line('a')
1012  write (iunit) txt
1013  write (txt, '(3a, i0)') 'CELLY ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser
1014  txt(lentxt:lentxt) = new_line('a')
1015  write (iunit) txt
1016  write (txt, '(3a, i0)') 'IAVERT ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1
1017  txt(lentxt:lentxt) = new_line('a')
1018  write (iunit) txt
1019  write (txt, '(3a, i0)') 'JAVERT ', 'INTEGER ', 'NDIM 1 ', size(this%javert)
1020  txt(lentxt:lentxt) = new_line('a')
1021  write (iunit) txt
1022  end if
1023  !
1024  ! -- if version 2 write character array headers
1025  if (version == 2) then
1026  if (found_crs) then
1027  write (txt, '(3a, i0)') 'CRS ', 'CHARACTER ', 'NDIM 1 ', &
1028  len_trim(crs)
1029  txt(lentxt:lentxt) = new_line('a')
1030  write (iunit) txt
1031  end if
1032  end if
1033  !
1034  ! -- write data
1035  write (iunit) this%nodesuser ! nodes
1036  write (iunit) this%nja ! nja
1037  write (iunit) this%xorigin ! xorigin
1038  write (iunit) this%yorigin ! yorigin
1039  write (iunit) this%angrot ! angrot
1040  write (iunit) this%top1d ! top
1041  write (iunit) this%bot1d ! bot
1042  write (iunit) this%con%iausr ! ia
1043  write (iunit) this%con%jausr ! ja
1044  write (iunit) this%idomain ! idomain
1045  write (iunit) icelltype ! icelltype
1046  !
1047  ! -- if vertices have been read then write additional data
1048  if (this%nvert > 0) then
1049  write (iunit) this%vertices ! vertices
1050  write (iunit) (this%cellxy(1, i), i=1, this%nodesuser) ! cellx
1051  write (iunit) (this%cellxy(2, i), i=1, this%nodesuser) ! celly
1052  write (iunit) this%iavert ! iavert
1053  write (iunit) this%javert ! javert
1054  end if
1055  !
1056  ! -- if version 2 write character array data
1057  if (version == 2) then
1058  if (found_crs) write (iunit) trim(crs) ! crs user input
1059  end if
1060  !
1061  ! -- Close the file
1062  close (iunit)
1063  !
1064  end subroutine write_grb
1065 
1066  !> @brief Get reduced node number from user node number
1067  !<
1068  function get_nodenumber_idx1(this, nodeu, icheck) result(nodenumber)
1069  class(disutype), intent(in) :: this
1070  integer(I4B), intent(in) :: nodeu
1071  integer(I4B), intent(in) :: icheck
1072  integer(I4B) :: nodenumber
1073  !
1074  if (icheck /= 0) then
1075  if (nodeu < 1 .or. nodeu > this%nodesuser) then
1076  write (errmsg, '(a,i0,a,i0,a)') &
1077  'Node number (', nodeu, ') is less than 1 or greater than nodes (', &
1078  this%nodesuser, ').'
1079  call store_error(errmsg)
1080  end if
1081  end if
1082  !
1083  ! -- set node number to passed in nodenumber since there is a one to one
1084  ! mapping for an unstructured grid
1085  if (this%nodes == this%nodesuser) then
1086  nodenumber = nodeu
1087  else
1088  nodenumber = this%nodereduced(nodeu)
1089  end if
1090  !
1091  end function get_nodenumber_idx1
1092 
1093  !> @brief Get normal vector components between the cell and a given neighbor
1094  !!
1095  !! The normal points outward from the shared face between noden and nodem.
1096  !<
1097  subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, &
1098  ipos)
1099  ! -- dummy
1100  class(disutype) :: this
1101  integer(I4B), intent(in) :: noden !< cell (reduced nn)
1102  integer(I4B), intent(in) :: nodem !< neighbor (reduced nn)
1103  integer(I4B), intent(in) :: ihc !< horizontal connection flag
1104  real(DP), intent(inout) :: xcomp
1105  real(DP), intent(inout) :: ycomp
1106  real(DP), intent(inout) :: zcomp
1107  integer(I4B), intent(in) :: ipos
1108  ! -- local
1109  real(DP) :: angle, dmult
1110  !
1111  ! -- Set vector components based on ihc
1112  if (ihc == 0) then
1113  !
1114  ! -- connection is vertical
1115  xcomp = dzero
1116  ycomp = dzero
1117  if (nodem < noden) then
1118  !
1119  ! -- nodem must be above noden, so upward connection
1120  zcomp = done
1121  else
1122  !
1123  ! -- nodem must be below noden, so downward connection
1124  zcomp = -done
1125  end if
1126  else
1127  ! -- find from anglex, since anglex is symmetric, need to flip vector
1128  ! for lower triangle (nodem < noden)
1129  angle = this%con%anglex(this%con%jas(ipos))
1130  dmult = done
1131  if (nodem < noden) dmult = -done
1132  xcomp = cos(angle) * dmult
1133  ycomp = sin(angle) * dmult
1134  zcomp = dzero
1135  end if
1136  !
1137  end subroutine connection_normal
1138 
1139  !> @brief Get unit vector components between the cell and a given neighbor
1140  !!
1141  !! Saturation must be provided to compute cell center vertical coordinates.
1142  !! Also return the straight-line connection length.
1143  !<
1144  subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, &
1145  xcomp, ycomp, zcomp, conlen)
1146  ! -- dummy
1147  class(disutype) :: this
1148  integer(I4B), intent(in) :: noden
1149  integer(I4B), intent(in) :: nodem
1150  logical, intent(in) :: nozee
1151  real(DP), intent(in) :: satn
1152  real(DP), intent(in) :: satm
1153  integer(I4B), intent(in) :: ihc
1154  real(DP), intent(inout) :: xcomp
1155  real(DP), intent(inout) :: ycomp
1156  real(DP), intent(inout) :: zcomp
1157  real(DP), intent(inout) :: conlen
1158  ! -- local
1159  real(DP) :: xn, xm, yn, ym, zn, zm
1160  !
1161  ! -- Terminate with error if requesting unit vector components for problems
1162  ! without cell data
1163  if (size(this%cellxy, 2) < 1) then
1164  write (errmsg, '(a)') &
1165  'Cannot calculate unit vector components for DISU grid if VERTEX '// &
1166  'data are not specified'
1167  call store_error(errmsg, terminate=.true.)
1168  end if
1169  !
1170  ! -- get xy center coords
1171  xn = this%xc(noden)
1172  yn = this%yc(noden)
1173  xm = this%xc(nodem)
1174  ym = this%yc(nodem)
1175  !
1176  ! -- Set vector components based on ihc
1177  if (ihc == 0) then
1178  !
1179  ! -- vertical connection, calculate z as cell center elevation
1180  zn = this%bot(noden) + dhalf * (this%top(noden) - this%bot(noden))
1181  zm = this%bot(nodem) + dhalf * (this%top(nodem) - this%bot(nodem))
1182  else
1183  !
1184  ! -- horizontal connection, with possible z component due to cell offsets
1185  ! and/or water table conditions
1186  if (nozee) then
1187  zn = dzero
1188  zm = dzero
1189  else
1190  zn = this%bot(noden) + dhalf * satn * (this%top(noden) - this%bot(noden))
1191  zm = this%bot(nodem) + dhalf * satm * (this%top(nodem) - this%bot(nodem))
1192  end if
1193  end if
1194  !
1195  ! -- Use coords to find vector components and connection length
1196  call line_unit_vector(xn, yn, zn, xm, ym, zm, xcomp, ycomp, zcomp, &
1197  conlen)
1198  !
1199  end subroutine connection_vector
1200 
1201  !> @brief Get the discretization type
1202  !<
1203  subroutine get_dis_type(this, dis_type)
1204  ! -- dummy
1205  class(disutype), intent(in) :: this
1206  character(len=*), intent(out) :: dis_type
1207  !
1208  dis_type = "DISU"
1209  !
1210  end subroutine get_dis_type
1211 
1212  !> @brief Get the discretization type enumeration
1213  function get_dis_enum(this) result(dis_enum)
1214  use constantsmodule, only: disu
1215  class(disutype), intent(in) :: this
1216  integer(I4B) :: dis_enum
1217  dis_enum = disu
1218  end function get_dis_enum
1219 
1220  !> @brief Allocate and initialize scalar variables
1221  !<
1222  subroutine allocate_scalars(this, name_model, input_mempath)
1223  ! -- dummy
1224  class(disutype) :: this
1225  character(len=*), intent(in) :: name_model
1226  character(len=*), intent(in) :: input_mempath
1227  !
1228  ! -- Allocate parent scalars
1229  call this%DisBaseType%allocate_scalars(name_model, input_mempath)
1230  !
1231  ! -- Allocate variables for DISU
1232  call mem_allocate(this%njausr, 'NJAUSR', this%memoryPath)
1233  call mem_allocate(this%nvert, 'NVERT', this%memoryPath)
1234  call mem_allocate(this%voffsettol, 'VOFFSETTOL', this%memoryPath)
1235  call mem_allocate(this%iangledegx, 'IANGLEDEGX', this%memoryPath)
1236  !
1237  ! -- Set values
1238  this%ndim = 1
1239  this%njausr = 0
1240  this%nvert = 0
1241  this%voffsettol = dzero
1242  this%iangledegx = 0
1243  this%readFromFile = .false.
1244  !
1245  end subroutine allocate_scalars
1246 
1247  !> @brief Allocate and initialize arrays
1248  !<
1249  subroutine allocate_arrays(this)
1250  ! -- dummy
1251  class(disutype) :: this
1252  !
1253  ! -- Allocate arrays in DisBaseType (mshape, top, bot, area)
1254  call this%DisBaseType%allocate_arrays()
1255  !
1256  ! -- Allocate arrays in DISU
1257  if (this%nodes < this%nodesuser) then
1258  call mem_allocate(this%nodeuser, this%nodes, 'NODEUSER', this%memoryPath)
1259  call mem_allocate(this%nodereduced, this%nodesuser, 'NODEREDUCED', &
1260  this%memoryPath)
1261  else
1262  call mem_allocate(this%nodeuser, 1, 'NODEUSER', this%memoryPath)
1263  call mem_allocate(this%nodereduced, 1, 'NODEREDUCED', this%memoryPath)
1264  end if
1265  !
1266  ! -- Initialize
1267  this%mshape(1) = this%nodesuser
1268  !
1269  end subroutine allocate_arrays
1270 
1271  !> @brief Allocate arrays in memory manager
1272  !<
1273  subroutine allocate_arrays_mem(this)
1274  ! -- modules
1276  ! -- dummy
1277  class(disutype) :: this
1278  !
1279  call mem_allocate(this%idomain, this%nodes, 'IDOMAIN', this%memoryPath)
1280  call mem_allocate(this%vertices, 2, this%nvert, 'VERTICES', this%memoryPath)
1281  if (this%icondir > 0) then
1282  call mem_allocate(this%cellxy, 2, this%nodes, 'CELLXY', this%memoryPath)
1283  else
1284  call mem_allocate(this%cellxy, 2, 0, 'CELLXY', this%memoryPath)
1285  end if
1286  !
1287  end subroutine allocate_arrays_mem
1288 
1289  !> @brief Convert a string to a user nodenumber
1290  !!
1291  !! Parse and return user nodenumber.
1292  !! If flag_string is present and true, the first token may be
1293  !! non-numeric (e.g. boundary name). In this case, return -2.
1294  !<
1295  function nodeu_from_string(this, lloc, istart, istop, in, iout, line, &
1296  flag_string, allow_zero) result(nodeu)
1297  ! -- dummy
1298  class(disutype) :: this
1299  integer(I4B), intent(inout) :: lloc
1300  integer(I4B), intent(inout) :: istart
1301  integer(I4B), intent(inout) :: istop
1302  integer(I4B), intent(in) :: in
1303  integer(I4B), intent(in) :: iout
1304  character(len=*), intent(inout) :: line
1305  logical, optional, intent(in) :: flag_string
1306  logical, optional, intent(in) :: allow_zero
1307  integer(I4B) :: nodeu
1308  ! -- local
1309  integer(I4B) :: lloclocal, ndum, istat, n
1310  real(dp) :: r
1311  !
1312  if (present(flag_string)) then
1313  if (flag_string) then
1314  ! Check to see if first token in line can be read as an integer.
1315  lloclocal = lloc
1316  call urword(line, lloclocal, istart, istop, 1, ndum, r, iout, in)
1317  read (line(istart:istop), *, iostat=istat) n
1318  if (istat /= 0) then
1319  ! First token in line is not an integer; return flag to this effect.
1320  nodeu = -2
1321  return
1322  end if
1323  end if
1324  end if
1325  !
1326  call urword(line, lloc, istart, istop, 2, nodeu, r, iout, in)
1327  !
1328  if (nodeu == 0) then
1329  if (present(allow_zero)) then
1330  if (allow_zero) then
1331  return
1332  end if
1333  end if
1334  end if
1335  !
1336  if (nodeu < 1 .or. nodeu > this%nodesuser) then
1337  write (errmsg, '(a,i0,a)') &
1338  "Node number in list (", nodeu, ") is outside of the grid. "// &
1339  "Cell number cannot be determined in line '"// &
1340  trim(adjustl(line))//"'."
1341  call store_error(errmsg)
1342  call store_error_unit(in)
1343  end if
1344  !
1345  end function nodeu_from_string
1346 
1347  !> @brief Convert a cellid string to a user nodenumber
1348  !!
1349  !! If flag_string is present and true, the first token may be
1350  !! non-numeric (e.g. boundary name). In this case, return -2.
1351  !!
1352  !! If allow_zero is present and true, and all indices are zero, the
1353  !! result can be zero. If allow_zero is false, a zero in any index is an error.
1354  !<
1355  function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, &
1356  allow_zero) result(nodeu)
1357  ! -- return
1358  integer(I4B) :: nodeu
1359  ! -- dummy
1360  class(disutype) :: this
1361  character(len=*), intent(inout) :: cellid
1362  integer(I4B), intent(in) :: inunit
1363  integer(I4B), intent(in) :: iout
1364  logical, optional, intent(in) :: flag_string
1365  logical, optional, intent(in) :: allow_zero
1366  ! -- local
1367  integer(I4B) :: lloclocal, istart, istop, ndum, n
1368  integer(I4B) :: istat
1369  real(dp) :: r
1370  !
1371  if (present(flag_string)) then
1372  if (flag_string) then
1373  ! Check to see if first token in cellid can be read as an integer.
1374  lloclocal = 1
1375  call urword(cellid, lloclocal, istart, istop, 1, ndum, r, iout, inunit)
1376  read (cellid(istart:istop), *, iostat=istat) n
1377  if (istat /= 0) then
1378  ! First token in cellid is not an integer; return flag to this effect.
1379  nodeu = -2
1380  return
1381  end if
1382  end if
1383  end if
1384  !
1385  lloclocal = 1
1386  call urword(cellid, lloclocal, istart, istop, 2, nodeu, r, iout, inunit)
1387  !
1388  if (nodeu == 0) then
1389  if (present(allow_zero)) then
1390  if (allow_zero) then
1391  return
1392  end if
1393  end if
1394  end if
1395  !
1396  if (nodeu < 1 .or. nodeu > this%nodesuser) then
1397  write (errmsg, '(a,i0,a)') &
1398  "Cell number cannot be determined for cellid ("// &
1399  trim(adjustl(cellid))//") and results in a user "// &
1400  "node number (", nodeu, ") that is outside of the grid."
1401  call store_error(errmsg)
1402  call store_error_unit(inunit)
1403  end if
1404  !
1405  end function nodeu_from_cellid
1406 
1407  !> @brief Indicates whether the grid discretization supports layers
1408  !<
1409  logical function supports_layers(this)
1410  ! -- dummy
1411  class(disutype) :: this
1412  !
1413  supports_layers = .false.
1414  !
1415  end function supports_layers
1416 
1417  !> @brief Get number of cells per layer (total nodes since DISU isn't layered)
1418  !<
1419  function get_ncpl(this)
1420  ! -- return
1421  integer(I4B) :: get_ncpl
1422  ! -- dummy
1423  class(disutype) :: this
1424  !
1425  get_ncpl = this%nodesuser
1426  !
1427  end function get_ncpl
1428 
1429  !> @brief Read an integer array
1430  !<
1431  subroutine read_int_array(this, line, lloc, istart, istop, iout, in, &
1432  iarray, aname)
1433  ! -- dummy
1434  class(disutype), intent(inout) :: this
1435  character(len=*), intent(inout) :: line
1436  integer(I4B), intent(inout) :: lloc
1437  integer(I4B), intent(inout) :: istart
1438  integer(I4B), intent(inout) :: istop
1439  integer(I4B), intent(in) :: in
1440  integer(I4B), intent(in) :: iout
1441  integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: iarray
1442  character(len=*), intent(in) :: aname
1443  ! -- local
1444  integer(I4B) :: nval
1445  integer(I4B), dimension(:), pointer, contiguous :: itemp
1446  !
1447  ! -- Point the temporary pointer array, which is passed to the reading
1448  ! subroutine. The temporary array will point to ibuff if it is a
1449  ! reduced structured system, or to iarray if it is an unstructured
1450  ! model.
1451  if (this%nodes < this%nodesuser) then
1452  nval = this%nodesuser
1453  itemp => this%ibuff
1454  else
1455  nval = this%nodes
1456  itemp => iarray
1457  end if
1458  !
1459  ! -- Read the array
1460  ! -- Read unstructured input
1461  call readarray(in, itemp, aname, this%ndim, nval, iout, 0)
1462  !
1463  ! -- If reduced model, then need to copy from itemp(=>ibuff) to iarray
1464  if (this%nodes < this%nodesuser) then
1465  call this%fill_grid_array(itemp, iarray)
1466  end if
1467  !
1468  end subroutine read_int_array
1469 
1470  !> @brief Read a double precision array
1471  !<
1472  subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, &
1473  darray, aname)
1474  ! -- dummy
1475  class(disutype), intent(inout) :: this
1476  character(len=*), intent(inout) :: line
1477  integer(I4B), intent(inout) :: lloc
1478  integer(I4B), intent(inout) :: istart
1479  integer(I4B), intent(inout) :: istop
1480  integer(I4B), intent(in) :: in
1481  integer(I4B), intent(in) :: iout
1482  real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray
1483  character(len=*), intent(in) :: aname
1484  ! -- local
1485  integer(I4B) :: nval
1486  real(DP), dimension(:), pointer, contiguous :: dtemp
1487  !
1488  ! -- Point the temporary pointer array, which is passed to the reading
1489  ! subroutine. The temporary array will point to dbuff if it is a
1490  ! reduced structured system, or to darray if it is an unstructured
1491  ! model.
1492  if (this%nodes < this%nodesuser) then
1493  nval = this%nodesuser
1494  dtemp => this%dbuff
1495  else
1496  nval = this%nodes
1497  dtemp => darray
1498  end if
1499  !
1500  ! -- Read the array
1501  call readarray(in, dtemp, aname, this%ndim, nval, iout, 0)
1502  !
1503  ! -- If reduced model, then need to copy from dtemp(=>dbuff) to darray
1504  if (this%nodes < this%nodesuser) then
1505  call this%fill_grid_array(dtemp, darray)
1506  end if
1507  !
1508  end subroutine read_dbl_array
1509 
1510  !> @brief Record a double precision array
1511  !!
1512  !! The array is written to a formatted or unformatted external file
1513  !! depending on the arguments.
1514  !<
1515  subroutine record_array(this, darray, iout, iprint, idataun, aname, &
1516  cdatafmp, nvaluesp, nwidthp, editdesc, dinact)
1517  ! -- dummy
1518  class(disutype), intent(inout) :: this
1519  real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray !< double precision array to record
1520  integer(I4B), intent(in) :: iout !< ascii output unit number
1521  integer(I4B), intent(in) :: iprint !< whether to print the array
1522  integer(I4B), intent(in) :: idataun !< binary output unit number
1523  character(len=*), intent(in) :: aname !< text descriptor
1524  character(len=*), intent(in) :: cdatafmp ! write format
1525  integer(I4B), intent(in) :: nvaluesp !< values per line
1526  integer(I4B), intent(in) :: nwidthp !< number width
1527  character(len=*), intent(in) :: editdesc !< format type (I, G, F, S, E)
1528  real(DP), intent(in) :: dinact !< double precision value for cells excluded from model domain
1529  ! -- local
1530  integer(I4B) :: k, ifirst
1531  integer(I4B) :: nlay
1532  integer(I4B) :: nrow
1533  integer(I4B) :: ncol
1534  integer(I4B) :: nval
1535  integer(I4B) :: nodeu, noder
1536  integer(I4B) :: istart, istop
1537  real(DP), dimension(:), pointer, contiguous :: dtemp
1538  ! -- formats
1539  character(len=*), parameter :: fmthsv = &
1540  "(1X,/1X,a,' WILL BE SAVED ON UNIT ',I4, &
1541  &' AT END OF TIME STEP',I5,', STRESS PERIOD ',I4)"
1542  !
1543  ! -- set variables
1544  nlay = 1
1545  nrow = 1
1546  ncol = this%mshape(1)
1547  !
1548  ! -- If this is a reduced model, then copy the values from darray into
1549  ! dtemp.
1550  if (this%nodes < this%nodesuser) then
1551  nval = this%nodes
1552  dtemp => this%dbuff
1553  do nodeu = 1, this%nodesuser
1554  noder = this%get_nodenumber(nodeu, 0)
1555  if (noder <= 0) then
1556  dtemp(nodeu) = dinact
1557  cycle
1558  end if
1559  dtemp(nodeu) = darray(noder)
1560  end do
1561  else
1562  nval = this%nodes
1563  dtemp => darray
1564  end if
1565  !
1566  ! -- Print to iout if iprint /= 0
1567  if (iprint /= 0) then
1568  istart = 1
1569  do k = 1, nlay
1570  istop = istart + nrow * ncol - 1
1571  call ulaprufw(ncol, nrow, kstp, kper, k, iout, dtemp(istart:istop), &
1572  aname, cdatafmp, nvaluesp, nwidthp, editdesc)
1573  istart = istop + 1
1574  end do
1575  end if
1576  !
1577  ! -- Save array to an external file.
1578  if (idataun > 0) then
1579  ! -- write to binary file by layer
1580  ifirst = 1
1581  istart = 1
1582  do k = 1, nlay
1583  istop = istart + nrow * ncol - 1
1584  if (ifirst == 1) write (iout, fmthsv) &
1585  trim(adjustl(aname)), idataun, &
1586  kstp, kper
1587  ifirst = 0
1588  call ulasav(dtemp(istart:istop), aname, kstp, kper, &
1589  pertim, totim, ncol, nrow, k, idataun)
1590  istart = istop + 1
1591  end do
1592  elseif (idataun < 0) then
1593  !
1594  ! -- write entire array as one record
1595  call ubdsv1(kstp, kper, aname, -idataun, dtemp, ncol, nrow, nlay, &
1596  iout, delt, pertim, totim)
1597  end if
1598  !
1599  end subroutine record_array
1600 
1601  !> @brief Record list header for imeth=6
1602  !<
1603  subroutine record_srcdst_list_header(this, text, textmodel, textpackage, &
1604  dstmodel, dstpackage, naux, auxtxt, &
1605  ibdchn, nlist, iout)
1606  ! -- dummy
1607  class(disutype) :: this
1608  character(len=16), intent(in) :: text
1609  character(len=16), intent(in) :: textmodel
1610  character(len=16), intent(in) :: textpackage
1611  character(len=16), intent(in) :: dstmodel
1612  character(len=16), intent(in) :: dstpackage
1613  integer(I4B), intent(in) :: naux
1614  character(len=16), dimension(:), intent(in) :: auxtxt
1615  integer(I4B), intent(in) :: ibdchn
1616  integer(I4B), intent(in) :: nlist
1617  integer(I4B), intent(in) :: iout
1618  ! -- local
1619  integer(I4B) :: nlay, nrow, ncol
1620  !
1621  nlay = 1
1622  nrow = 1
1623  ncol = this%mshape(1)
1624  !
1625  ! -- Use ubdsv06 to write list header
1626  call ubdsv06(kstp, kper, text, textmodel, textpackage, dstmodel, dstpackage, &
1627  ibdchn, naux, auxtxt, ncol, nrow, nlay, &
1628  nlist, iout, delt, pertim, totim)
1629  !
1630  end subroutine record_srcdst_list_header
1631 
1632  !> @brief Cast base to DISU
1633  !<
1634  function castasdisutype(dis) result(disu)
1635  ! -- dummy
1636  class(*), pointer :: dis !< base pointer to DISU object
1637  ! -- return
1638  class(disutype), pointer :: disu !< the resulting DISU pointer
1639  !
1640  disu => null()
1641  select type (dis)
1642  class is (disutype)
1643  disu => dis
1644  end select
1645  !
1646  end function castasdisutype
1647 
1648 end module disumodule
subroutine, public iac_to_ia(iac, ia)
Convert an iac array into an ia array.
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 lenbigline
maximum length of a big line
Definition: Constants.f90:15
@ disu
DISV6 discretization.
Definition: Constants.f90:157
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
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
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
subroutine allocate_scalars(this, name_model, input_mempath)
Allocate and initialize scalar variables.
Definition: Disu.f90:1223
subroutine write_grb(this, icelltype)
Write a binary grid file.
Definition: Disu.f90:917
subroutine allocate_arrays(this)
Allocate and initialize arrays.
Definition: Disu.f90:1250
subroutine disu_load(this)
Transfer IDM data into this discretization object.
Definition: Disu.f90:166
subroutine source_connectivity(this)
Copy grid connectivity info from IDM into package.
Definition: Disu.f90:719
subroutine, public disu_cr(dis, name_model, input_mempath, inunit, iout)
Create a new unstructured discretization object.
Definition: Disu.f90:128
subroutine source_dimensions(this)
Copy dimensions from IDM into package.
Definition: Disu.f90:584
subroutine source_options(this)
Copy options from IDM into package.
Definition: Disu.f90:517
subroutine log_dimensions(this, found)
Write dimensions to list file.
Definition: Disu.f90:645
subroutine disu_da(this)
Deallocate variables.
Definition: Disu.f90:433
class(disutype) function, pointer, public castasdisutype(dis)
Cast base to DISU.
Definition: Disu.f90:1635
integer(i4b) function get_ncpl(this)
Get number of cells per layer (total nodes since DISU isn't layered)
Definition: Disu.f90:1420
subroutine define_cellverts(this, icell2d, ncvert, icvert)
Build data structures to hold cell vertex info.
Definition: Disu.f90:824
subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, darray, aname)
Read a double precision array.
Definition: Disu.f90:1474
integer(i4b) function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, allow_zero)
Convert a cellid string to a user nodenumber.
Definition: Disu.f90:1357
subroutine log_options(this, found)
Write user options to list file.
Definition: Disu.f90:544
subroutine record_srcdst_list_header(this, text, textmodel, textpackage, dstmodel, dstpackage, naux, auxtxt, ibdchn, nlist, iout)
Record list header for imeth=6.
Definition: Disu.f90:1606
subroutine get_dis_type(this, dis_type)
Get the discretization type.
Definition: Disu.f90:1204
subroutine source_vertices(this)
Copy grid vertex data from IDM into package.
Definition: Disu.f90:790
subroutine source_cell2d(this)
Copy cell2d data from IDM into package.
Definition: Disu.f90:865
subroutine log_griddata(this, found)
Write griddata found to list file.
Definition: Disu.f90:690
subroutine allocate_arrays_mem(this)
Allocate arrays in memory manager.
Definition: Disu.f90:1274
subroutine source_griddata(this)
Copy grid data from IDM into package.
Definition: Disu.f90:669
subroutine nodeu_to_array(this, nodeu, arr)
Convert a user nodenumber to an array (nodenumber)
Definition: Disu.f90:494
subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, xcomp, ycomp, zcomp, conlen)
Get unit vector components between the cell and a given neighbor.
Definition: Disu.f90:1146
subroutine record_array(this, darray, iout, iprint, idataun, aname, cdatafmp, nvaluesp, nwidthp, editdesc, dinact)
Record a double precision array.
Definition: Disu.f90:1517
subroutine disu_df(this)
Define the discretization.
Definition: Disu.f90:193
logical function supports_layers(this)
Indicates whether the grid discretization supports layers.
Definition: Disu.f90:1410
subroutine read_int_array(this, line, lloc, istart, istop, iout, in, iarray, aname)
Read an integer array.
Definition: Disu.f90:1433
subroutine grid_finalize(this)
Finalize the grid.
Definition: Disu.f90:203
integer(i4b) function get_nodenumber_idx1(this, nodeu, icheck)
Get reduced node number from user node number.
Definition: Disu.f90:1069
subroutine nodeu_to_string(this, nodeu, str)
Convert a user nodenumber to a string (nodenumber)
Definition: Disu.f90:479
integer(i4b) function nodeu_from_string(this, lloc, istart, istop, in, iout, line, flag_string, allow_zero)
Convert a string to a user nodenumber.
Definition: Disu.f90:1297
subroutine disu_ck(this)
Check discretization info.
Definition: Disu.f90:313
integer(i4b) function get_dis_enum(this)
Get the discretization type enumeration.
Definition: Disu.f90:1214
subroutine log_connectivity(this, found, iac)
Write griddata found to list file.
Definition: Disu.f90:753
subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, ipos)
Get normal vector components between the cell and a given neighbor.
Definition: Disu.f90:1099
subroutine, public line_unit_vector(x0, y0, z0, x1, y1, z1, xcomp, ycomp, zcomp, vmag)
Calculate the vector components (xcomp, ycomp, and zcomp) for a line defined by two points,...
Definition: DisvGeom.f90:475
subroutine, public ubdsv1(kstp, kper, text, ibdchn, buff, ncol, nrow, nlay, iout, delt, pertim, totim)
Record cell-by-cell flow terms for one component of flow as a 3-D array with extra record to indicate...
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public ulaprufw(ncol, nrow, kstp, kper, ilay, iout, buf, text, userfmt, nvalues, nwidth, editdesc)
Print 1 layer array with user formatting in wrap format.
subroutine, public ubdsv06(kstp, kper, text, modelnam1, paknam1, modelnam2, paknam2, ibdchn, naux, auxtxt, ncol, nrow, nlay, nlist, iout, delt, pertim, totim)
Write header records for cell-by-cell flow terms for one component of flow.
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
subroutine, public urword(line, icol, istart, istop, ncode, n, r, iout, in)
Extract a word from a string.
This module defines variable data types.
Definition: kind.f90:8
subroutine, public memorystore_remove(component, subcomponent, context)
subroutine, public memorystore_release(varname, memory_path)
Release a single variable from the memory store.
character(len=20) access
Definition: OpenSpec.f90:7
character(len=20) form
Definition: OpenSpec.f90:7
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
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition: Sim.f90:203
subroutine, public store_error_unit(iunit, terminate)
Store the file unit number.
Definition: Sim.f90:168
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
character(len=linelength) idm_context
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
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
Unstructured grid discretization.
Definition: Disu.f90:29