MODFLOW 6  version 6.7.0.dev1
USGS Modular Hydrologic Model
GridFileReader.f90
Go to the documentation of this file.
2 
3  use kindmodule
5  use simvariablesmodule, only: errmsg
6  use constantsmodule, only: linelength
10 
11  implicit none
12 
13  public :: gridfilereadertype
14 
16  private
17  integer(I4B), public :: inunit !< file unit
18  ! header
19  character(len=10), public :: grid_type !< DIS, DISV, DISU, etc
20  integer(I4B), public :: version !< binary grid file format version
21  integer(I4B) :: ntxt !< number of variables
22  integer(I4B) :: lentxt !< header line length per variable
23  ! index
24  type(hashtabletype), pointer :: dim !< map variable name to number of dims
25  type(hashtabletype), pointer :: pos !< map variable name to position in file
26  type(hashtabletype), pointer :: typ !< map variable name to type (1=int, 2=dbl)
27  type(hashtabletype), pointer :: shp_idx !< map variable name to index in shp
28  integer(I4B), allocatable :: shp(:) !< flat array of variable shapes
29  character(len=10), allocatable, public :: keys(:) !< variable names
30  contains
31  procedure, public :: initialize
32  procedure, public :: finalize
33  procedure, public :: read_int
34  procedure, public :: read_dbl
35  procedure, public :: read_int_1d
36  procedure, public :: read_dbl_1d
37  procedure, public :: read_grid_shape
38  procedure, private :: read_header
39  procedure, private :: read_header_meta
40  procedure, private :: read_header_body
41  end type gridfilereadertype
42 
43 contains
44 
45  !> @Brief Initialize the grid file reader.
46  subroutine initialize(this, iu)
47  class(gridfilereadertype) :: this
48  integer(I4B), intent(in) :: iu
49 
50  this%inunit = iu
51  call hash_table_cr(this%dim)
52  call hash_table_cr(this%pos)
53  call hash_table_cr(this%typ)
54  call hash_table_cr(this%shp_idx)
55  allocate (this%shp(0))
56  call this%read_header()
57 
58  end subroutine initialize
59 
60  !> @brief Finalize the grid file reader.
61  subroutine finalize(this)
62  class(gridfilereadertype) :: this
63 
64  close (this%inunit)
65  call hash_table_da(this%dim)
66  call hash_table_da(this%pos)
67  call hash_table_da(this%typ)
68  call hash_table_da(this%shp_idx)
69  deallocate (this%shp)
70 
71  end subroutine finalize
72 
73  !> @brief Read the file's self-describing header. Internal use only.
74  subroutine read_header(this)
75  class(gridfilereadertype) :: this
76  call this%read_header_meta()
77  call this%read_header_body()
78  end subroutine read_header
79 
80  !> @brief Read self-describing metadata (first four lines). Internal use only.
81  subroutine read_header_meta(this)
82  ! dummy
83  class(gridfilereadertype) :: this
84  ! local
85  character(len=50) :: line
86  integer(I4B) :: lloc, istart, istop
87  integer(I4B) :: ival
88  real(DP) :: rval
89 
90  ! grid type
91  read (this%inunit) line
92  lloc = 1
93  call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0)
94  if (line(istart:istop) /= 'GRID') then
95  call store_error('Binary grid file must begin with "GRID". '//&
96  &'Found: '//line(istart:istop))
97  call store_error_unit(this%inunit)
98  end if
99  call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0)
100  this%grid_type = line(istart:istop)
101 
102  ! version
103  read (this%inunit) line
104  lloc = 1
105  call urword(line, lloc, istart, istop, 0, ival, rval, 0, 0)
106  call urword(line, lloc, istart, istop, 2, ival, rval, 0, 0)
107  this%version = ival
108 
109  ! ntxt
110  read (this%inunit) line
111  lloc = 1
112  call urword(line, lloc, istart, istop, 0, ival, rval, 0, 0)
113  call urword(line, lloc, istart, istop, 2, ival, rval, 0, 0)
114  this%ntxt = ival
115 
116  ! lentxt
117  read (this%inunit) line
118  lloc = 1
119  call urword(line, lloc, istart, istop, 0, ival, rval, 0, 0)
120  call urword(line, lloc, istart, istop, 2, ival, rval, 0, 0)
121  this%lentxt = ival
122 
123  end subroutine read_header_meta
124 
125  !> @brief Read the header body section (text following first
126  !< four "meta" lines) and build an index. Internal use only.
127  subroutine read_header_body(this)
128  ! dummy
129  class(gridfilereadertype) :: this
130  ! local
131  character(len=:), allocatable :: body
132  character(len=:), allocatable :: line
133  character(len=10) :: key, dtype
134  real(DP) :: rval
135  integer(I4B) :: i, lloc, istart, istop, ival, pos
136  integer(I4B) :: nvars, ndim, dim, ishp
137  integer(I4B), allocatable :: shp(:)
138 
139  allocate (this%keys(this%ntxt))
140  allocate (character(len=this%lentxt*this%ntxt) :: body)
141  allocate (character(len=this%lentxt) :: line)
142 
143  nvars = 0
144  read (this%inunit) body
145  inquire (this%inunit, pos=pos)
146  do i = 1, this%lentxt * this%ntxt, this%lentxt
147  line = body(i:i + this%lentxt - 1)
148  lloc = 1
149 
150  ! key
151  lloc = 1
152  call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0)
153  key = line(istart:istop)
154  nvars = nvars + 1
155  this%keys(nvars) = key
156 
157  ! type
158  call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0)
159  dtype = line(istart:istop)
160  if (dtype == "INTEGER") then
161  call this%typ%add(key, 1)
162  else if (dtype == "DOUBLE") then
163  call this%typ%add(key, 2)
164  end if
165 
166  ! dims
167  call urword(line, lloc, istart, istop, 0, ival, rval, 0, 0)
168  call urword(line, lloc, istart, istop, 2, ival, rval, 0, 0)
169  ndim = ival
170  call this%dim%add(key, ndim)
171 
172  ! shape
173  if (allocated(shp)) deallocate (shp)
174  allocate (shp(ndim))
175  if (ndim > 0) then
176  do dim = 1, ndim
177  call urword(line, lloc, istart, istop, 2, ival, rval, 0, 0)
178  shp(dim) = ival
179  end do
180  ishp = size(this%shp)
181  call expandarray(this%shp, increment=ndim)
182  this%shp(ishp + 1:ishp + ndim) = shp
183  call this%shp_idx%add(key, ishp + 1)
184  end if
185 
186  ! position
187  call this%pos%add(key, pos)
188  if (ndim == 0) then
189  if (dtype == "INTEGER") then
190  pos = pos + 4
191  else if (dtype == "DOUBLE") then
192  pos = pos + 8
193  end if
194  else
195  if (dtype == "INTEGER") then
196  pos = pos + (product(shp) * 4)
197  else if (dtype == "DOUBLE") then
198  pos = pos + (product(shp) * 8)
199  end if
200  end if
201  end do
202 
203  rewind(this%inunit)
204 
205  end subroutine read_header_body
206 
207  !> @brief Read an integer scalar from a grid file.
208  function read_int(this, key) result(v)
209  class(gridfilereadertype), intent(inout) :: this
210  character(len=*), intent(in) :: key
211  integer(I4B) :: v
212  ! local
213  integer(I4B) :: ndim, pos, typ
214  character(len=:), allocatable :: msg
215 
216  msg = 'Variable '//trim(key)//' is not an integer scalar'
217  ndim = this%dim%get(key)
218  if (ndim /= 0) then
219  write (errmsg, '(a)') msg
220  call store_error(errmsg, terminate=.true.)
221  end if
222  typ = this%typ%get(key)
223  if (typ /= 1) then
224  write (errmsg, '(a)') msg
225  call store_error(errmsg, terminate=.true.)
226  end if
227  pos = this%pos%get(key)
228  read (this%inunit, pos=pos) v
229  rewind(this%inunit)
230 
231  end function read_int
232 
233  !> @brief Read a double precision scalar from a grid file.
234  function read_dbl(this, key) result(v)
235  class(gridfilereadertype), intent(inout) :: this
236  character(len=*), intent(in) :: key
237  real(dp) :: v
238  ! local
239  integer(I4B) :: ndim, pos, typ
240  character(len=:), allocatable :: msg
241 
242  msg = 'Variable '//trim(key)//' is not a double precision scalar'
243  ndim = this%dim%get(key)
244  if (ndim /= 0) then
245  write (errmsg, '(a)') msg
246  call store_error(errmsg, terminate=.true.)
247  end if
248  typ = this%typ%get(key)
249  if (typ /= 2) then
250  write (errmsg, '(a)') msg
251  call store_error(errmsg, terminate=.true.)
252  end if
253  pos = this%pos%get(key)
254  read (this%inunit, pos=pos) v
255  rewind(this%inunit)
256 
257  end function read_dbl
258 
259  !> @brief Read a 1D integer array from a grid file.
260  function read_int_1d(this, key) result(v)
261  class(gridfilereadertype), intent(inout) :: this
262  character(len=*), intent(in) :: key
263  integer(I4B), allocatable :: v(:)
264  ! local
265  integer(I4B) :: idx, ndim, nvals, pos, typ
266  character(len=:), allocatable :: msg
267 
268  msg = 'Variable '//trim(key)//' is not a 1D integer array'
269  ndim = this%dim%get(key)
270  if (ndim /= 1) then
271  write (errmsg, '(a)') msg
272  call store_error(errmsg, terminate=.true.)
273  end if
274  typ = this%typ%get(key)
275  if (typ /= 1) then
276  write (errmsg, '(a)') msg
277  call store_error(errmsg, terminate=.true.)
278  end if
279  idx = this%shp_idx%get(key)
280  pos = this%pos%get(key)
281  nvals = this%shp(idx)
282  allocate (v(nvals))
283  read (this%inunit, pos=pos) v
284  rewind(this%inunit)
285 
286  end function read_int_1d
287 
288  !> @brief Read a 1D double array from a grid file.
289  function read_dbl_1d(this, key) result(v)
290  class(gridfilereadertype), intent(inout) :: this
291  character(len=*), intent(in) :: key
292  real(dp), allocatable :: v(:)
293  ! local
294  integer(I4B) :: idx, ndim, nvals, pos, typ
295  character(len=:), allocatable :: msg
296 
297  msg = 'Variable '//trim(key)//' is not a 1D double array'
298  ndim = this%dim%get(key)
299  if (ndim /= 1) then
300  write (errmsg, '(a)') msg
301  call store_error(errmsg, terminate=.true.)
302  end if
303  typ = this%typ%get(key)
304  if (typ /= 2) then
305  write (errmsg, '(a)') msg
306  call store_error(errmsg, terminate=.true.)
307  end if
308  idx = this%shp_idx%get(key)
309  pos = this%pos%get(key)
310  nvals = this%shp(idx)
311  allocate (v(nvals))
312  read (this%inunit, pos=pos) v
313  rewind(this%inunit)
314 
315  end function read_dbl_1d
316 
317  !> @brief Read the grid shape from a grid file.
318  function read_grid_shape(this) result(v)
319  ! dummy
320  class(gridfilereadertype) :: this
321  integer(I4B), allocatable :: v(:)
322 
323  select case (this%grid_type)
324  case ("DIS")
325  allocate (v(3))
326  v(1) = this%read_int("NLAY")
327  v(2) = this%read_int("NROW")
328  v(3) = this%read_int("NCOL")
329  case ("DISV")
330  allocate (v(2))
331  v(1) = this%read_int("NLAY")
332  v(2) = this%read_int("NCPL")
333  case ("DISU")
334  allocate (v(1))
335  v(1) = this%read_int("NODES")
336  case ("DIS2D")
337  allocate (v(2))
338  v(1) = this%read_int("NROW")
339  v(2) = this%read_int("NCOL")
340  case ("DISV2D")
341  allocate (v(1))
342  v(1) = this%read_int("NODES")
343  case ("DISV1D")
344  allocate (v(1))
345  v(1) = this%read_int("NCELLS")
346  end select
347 
348  end function read_grid_shape
349 
350 end module gridfilereadermodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
subroutine initialize(this, iu)
@Brief Initialize the grid file reader.
subroutine read_header(this)
Read the file's self-describing header. Internal use only.
subroutine read_header_meta(this)
Read self-describing metadata (first four lines). Internal use only.
integer(i4b) function read_int(this, key)
Read an integer scalar from a grid file.
subroutine read_header_body(this)
Read the header body section (text following first.
subroutine finalize(this)
Finalize the grid file reader.
real(dp) function, dimension(:), allocatable read_dbl_1d(this, key)
Read a 1D double array from a grid file.
integer(i4b) function, dimension(:), allocatable read_int_1d(this, key)
Read a 1D integer array from a grid file.
real(dp) function read_dbl(this, key)
Read a double precision scalar from a grid file.
integer(i4b) function, dimension(:), allocatable read_grid_shape(this)
Read the grid shape from a grid file.
A chaining hash map for integers.
Definition: HashTable.f90:7
subroutine, public hash_table_cr(map)
Create a hash table.
Definition: HashTable.f90:46
subroutine, public hash_table_da(map)
Deallocate the hash table.
Definition: HashTable.f90:64
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
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
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