MODFLOW 6  version 6.7.0.dev0
USGS Modular Hydrologic Model
ArrayHandlers.f90
Go to the documentation of this file.
2 
3  use kindmodule, only: dp, i4b, lgp
4  use errorutilmodule, only: pstop
6  implicit none
7  private
9  public :: concatarray
10  public :: ifind
11  public :: remove_character
12 
14  module procedure expand_integer_wrapper
15  end interface
16 
17  interface expandarray
18  ! This interface is for use with ALLOCATABLE arrays.
19  ! IMPORTANT: Do not use pointers to elements of arrays when using
20  ! ExpandArray to increase the array size! The locations of array
21  ! elements in memory are changed when ExpandArray is invoked.
22  module procedure expand_integer, expand_double, expand_logical, &
24  end interface expandarray
25 
26  interface expandarray2d
27  ! This interface is for use with ALLOCATABLE arrays.
28  ! IMPORTANT: Do not use pointers to elements of arrays when using
29  ! ExpandArray2D to increase the array size! The locations of array
30  ! elements in memory are changed when ExpandArray2D is invoked.
31  module procedure expand_integer_2d, expand_double_2d
32  end interface expandarray2d
33 
34  interface extendptrarray
35  ! This interface is for use with POINTERS to arrays.
36  module procedure extend_double, extend_integer, &
38  end interface
39 
40  interface concatarray
41  module procedure concat_integer
42  end interface
43 
44  interface ifind
46  end interface ifind
47 
48 contains
49 
50  subroutine expand_integer_wrapper(nsize, array, minvalue, loginc)
51  ! -- dummy
52  integer(I4B), intent(in) :: nsize
53  integer(I4B), allocatable, intent(inout) :: array(:)
54  integer(I4B), intent(in), optional :: minvalue
55  logical(LGP), intent(in), optional :: loginc
56  ! -- local
57  logical(LGP) :: log_increment
58  integer(I4B) :: minimum_increment
59  integer(I4B) :: increment
60  integer(I4B) :: isize
61  integer(I4B) :: n
62  !
63  ! -- process optional variables
64  if (present(minvalue)) then
65  minimum_increment = minvalue
66  else
67  minimum_increment = 100
68  end if
69  if (present(loginc)) then
70  log_increment = loginc
71  else
72  log_increment = .false.
73  end if
74  !
75  ! -- determine current size of the array
76  isize = size(array)
77  !
78  ! -- expand the array if necessary
79  if (nsize > isize) then
80  !
81  ! -- increase array size by 1, 10, 100, 1000, etc.
82  ! from 1 to 9, 10 to 99, 100 to 999, 1000 to 10000, etc.
83  if (loginc) then
84  increment = int(log10(real(nsize, dp)), i4b)
85  increment = int(dten**increment, i4b)
86  !
87  ! -- increase increment by a multiplier and a value no
88  ! smaller than a default or specified minimum size
89  else
90  increment = int(nsize * 0.2_dp)
91  increment = max(minimum_increment, increment)
92  end if
93  !
94  ! -- expand the array
95  call expandarray(array, increment)
96  !
97  ! -- initialize expanded array elements
98  do n = isize + 1, size(array)
99  array(n) = 0
100  end do
101  end if
102 
103  end subroutine expand_integer_wrapper
104 
105  ! -- Specific procedures that implement ExpandArray for allocatable arrays
106 
107  subroutine expand_integer(array, increment)
108  ! -- dummy
109  integer(I4B), allocatable, intent(inout) :: array(:)
110  integer(I4B), optional, intent(in) :: increment
111  ! -- local
112  integer(I4B) :: inc, lb, n
113  integer(I4B), allocatable, dimension(:) :: temp
114 
115  ! -- default to expanding by 1
116  if (present(increment)) then
117  inc = increment
118  if (inc == 0) return
119  if (inc < 0) call pstop(1, "increment must be nonnegative")
120  else
121  inc = 1
122  end if
123 
124  ! -- expand array to the requested size, keeping
125  ! existing items and the existing lower bound,
126  ! or allocate the array if still unallocated
127  if (allocated(array)) then
128  lb = lbound(array, 1)
129  n = size(array)
130  allocate (temp(lb:(lb + n + inc - 1)))
131  temp(lb:(lb + n - 1)) = array
132  deallocate (array)
133  call move_alloc(temp, array)
134  else
135  allocate (array(inc))
136  end if
137  end subroutine expand_integer
138 
139  subroutine expand_double(array, increment)
140  ! -- dummy
141  real(DP), allocatable, intent(inout) :: array(:)
142  integer(I4B), optional, intent(in) :: increment
143  ! -- local
144  integer(I4B) :: inc, lb, n
145  real(DP), allocatable, dimension(:) :: temp
146 
147  ! -- default to expanding by 1
148  if (present(increment)) then
149  inc = increment
150  if (inc == 0) return
151  if (inc < 0) call pstop(1, "increment must be nonnegative")
152  else
153  inc = 1
154  end if
155 
156  ! -- expand array to the requested size, keeping
157  ! existing items and the existing lower bound,
158  ! or allocate the array if still unallocated
159  if (allocated(array)) then
160  lb = lbound(array, 1)
161  n = size(array)
162  allocate (temp(lb:(lb + n + inc - 1)))
163  temp(lb:(lb + n - 1)) = array
164  deallocate (array)
165  call move_alloc(temp, array)
166  else
167  allocate (array(inc))
168  end if
169 
170  end subroutine expand_double
171 
172  subroutine expand_logical(array, increment)
173  ! -- dummy
174  logical(LGP), allocatable, intent(inout) :: array(:)
175  integer(I4B), optional, intent(in) :: increment
176  ! -- local
177  integer(I4B) :: inc, lb, n
178  logical(LGP), allocatable, dimension(:) :: temp
179 
180  ! -- default to expanding by 1
181  if (present(increment)) then
182  inc = increment
183  if (inc == 0) return
184  if (inc < 0) call pstop(1, "increment must be nonnegative")
185  else
186  inc = 1
187  end if
188 
189  ! -- expand array to the requested size, keeping
190  ! existing items and the existing lower bound,
191  ! or allocate the array if still unallocated
192  if (allocated(array)) then
193  lb = lbound(array, 1)
194  n = size(array)
195  allocate (temp(lb:(lb + n + inc - 1)))
196  temp(lb:(lb + n - 1)) = array
197  deallocate (array)
198  call move_alloc(temp, array)
199  else
200  allocate (array(inc))
201  end if
202 
203  end subroutine expand_logical
204 
205  subroutine expand_character(array, increment)
206  ! -- dummy
207  character(len=*), allocatable, intent(inout) :: array(:)
208  integer(I4B), optional, intent(in) :: increment
209  ! -- local
210  character(len=MAXCHARLEN), allocatable, dimension(:) :: temp
211  integer(I4B) :: i, inc, nold, nnew, lenc
212 
213  ! -- check character length
214  lenc = len(array)
215  if (lenc > maxcharlen) &
216  call pstop(138, 'Error in ArrayHandlersModule: '// &
217  'Need to increase MAXCHARLEN. Stopping...')
218 
219  ! -- default to expanding by 1
220  if (present(increment)) then
221  inc = increment
222  if (inc == 0) return
223  if (inc < 0) call pstop(1, "increment must be nonnegative")
224  else
225  inc = 1
226  end if
227 
228  ! -- expand array to the requested size, keeping
229  ! existing items, or allocate if still needed
230  ! TODO: may be able to use mold here, e.g.:
231  ! allocate(values(num), mold=proto)
232  if (allocated(array)) then
233  nold = size(array)
234  nnew = nold + inc
235  allocate (temp(nold))
236  do i = 1, nold
237  temp(i) = array(i)
238  end do
239  deallocate (array)
240  allocate (array(nnew))
241  do i = 1, nold
242  array(i) = temp(i)
243  end do
244  do i = nold + 1, nnew
245  array(i) = ''
246  end do
247  deallocate (temp)
248  else
249  allocate (array(inc))
250  end if
251 
252  end subroutine expand_character
253 
254  ! -- Specific procedures that implement ExtendArray2D
255 
256  subroutine expand_integer_2d(array, increment1, increment2)
257  ! -- dummy
258  integer(I4B), allocatable, intent(inout) :: array(:, :)
259  integer(I4B), optional, intent(in) :: increment1
260  integer(I4B), optional, intent(in) :: increment2
261  ! -- local
262  integer(I4B) :: inc1, inc2, lb1, lb2, n1, n2
263  integer(I4B), allocatable, dimension(:, :) :: temp
264 
265  ! -- default to expanding both dimensions by 1
266  if (present(increment1)) then
267  inc1 = increment1
268  else
269  inc1 = 1
270  end if
271  if (present(increment2)) then
272  inc2 = increment2
273  else
274  inc2 = 1
275  end if
276  if (inc1 == 0 .and. inc2 == 0) return
277  if (inc1 < 0 .or. inc2 < 0) &
278  call pstop(1, "increments must be nonnegative")
279 
280  ! -- expand array to the requested size, keeping
281  ! existing items and the existing lower bound,
282  ! or allocate the array if still unallocated
283  if (allocated(array)) then
284  lb1 = lbound(array, 1)
285  lb2 = lbound(array, 2)
286  n1 = size(array, 1)
287  n2 = size(array, 2)
288  allocate (temp( &
289  lb1:(lb1 + n1 + inc1 - 1), &
290  lb2:(lb2 + n2 + inc2 - 1)))
291  temp( &
292  lb1:(lb1 + n1 - 1), &
293  lb2:(lb2 + n2 - 1)) = array
294  deallocate (array)
295  call move_alloc(temp, array)
296  else
297  allocate (array(inc1, inc2))
298  end if
299 
300  end subroutine expand_integer_2d
301 
302  subroutine expand_double_2d(array, increment1, increment2)
303  ! -- dummy
304  real(DP), allocatable, intent(inout) :: array(:, :)
305  integer(I4B), optional, intent(in) :: increment1
306  integer(I4B), optional, intent(in) :: increment2
307  ! -- local
308  integer(I4B) :: inc1, inc2, lb1, lb2, n1, n2
309  real(DP), allocatable, dimension(:, :) :: temp
310 
311  ! -- default to expanding both dimensions by 1
312  if (present(increment1)) then
313  inc1 = increment1
314  else
315  inc1 = 1
316  end if
317  if (present(increment2)) then
318  inc2 = increment2
319  else
320  inc2 = 1
321  end if
322  if (inc1 == 0 .and. inc2 == 0) return
323  if (inc1 < 0 .or. inc2 < 0) &
324  call pstop(1, "increments must be nonnegative")
325 
326  ! -- expand array to the requested size, keeping
327  ! existing items and the existing lower bound,
328  ! or allocate the array if still unallocated
329  if (allocated(array)) then
330  lb1 = lbound(array, 1)
331  lb2 = lbound(array, 2)
332  n1 = size(array, 1)
333  n2 = size(array, 2)
334  allocate (temp( &
335  lb1:(lb1 + n1 + inc1 - 1), &
336  lb2:(lb2 + n2 + inc2 - 1)))
337  temp( &
338  lb1:(lb1 + n1 - 1), &
339  lb2:(lb2 + n2 - 1)) = array
340  deallocate (array)
341  call move_alloc(temp, array)
342  else
343  allocate (array(inc1, inc2))
344  end if
345 
346  end subroutine expand_double_2d
347 
348  ! -- Specific procedures that implement ExtendPtrArray for pointer arrays
349 
350  subroutine extend_double(array, increment)
351  ! -- dummy
352  real(DP), dimension(:), pointer, contiguous, intent(inout) :: array
353  integer(I4B), optional, intent(in) :: increment
354  ! -- local
355  character(len=100) :: ermsg
356  integer(I4B) :: i, inc, lb, n, istat
357  real(DP), dimension(:), pointer, contiguous :: temp => null()
358 
359  ! -- default to expanding by 1
360  if (present(increment)) then
361  inc = increment
362  if (inc == 0) return
363  if (inc < 0) call pstop(1, "increment must be nonnegative")
364  else
365  inc = 1
366  end if
367 
368  ! -- expand array to the requested size, keeping
369  ! existing items and the existing lower bound,
370  ! or allocate the array if still unallocated
371  if (associated(array)) then
372  lb = lbound(array, 1)
373  n = size(array)
374  allocate (temp(lb:(lb + n + inc - 1)), stat=istat, errmsg=ermsg)
375  if (istat /= 0) &
376  call pstop(138, 'Error in ArrayHandlersModule, '// &
377  'could not increase array size:'//ermsg)
378  do i = lb, lb + n - 1
379  temp(i) = array(i)
380  end do
381  deallocate (array)
382  array => temp
383  else
384  allocate (array(inc))
385  end if
386 
387  end subroutine extend_double
388 
389  subroutine extend_integer(array, increment)
390  ! -- dummy
391  integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: array
392  integer(I4B), optional, intent(in) :: increment
393  ! -- local
394  character(len=100) :: ermsg
395  integer(I4B) :: i, inc, lb, n, istat
396  integer(I4B), dimension(:), pointer, contiguous :: temp => null()
397 
398  ! -- default to expanding by 1
399  if (present(increment)) then
400  inc = increment
401  if (inc == 0) return
402  if (inc < 0) call pstop(1, "increment must be nonnegative")
403  else
404  inc = 1
405  end if
406 
407  ! -- expand array to the requested size, keeping
408  ! existing items and the existing lower bound,
409  ! or allocate the array if still unallocated
410  if (associated(array)) then
411  lb = lbound(array, 1)
412  n = size(array)
413  allocate (temp(lb:(lb + n + inc - 1)), stat=istat, errmsg=ermsg)
414  if (istat /= 0) &
415  call pstop(138, 'Error in ArrayHandlersModule, '// &
416  'could not increase array size:'//ermsg)
417  do i = lb, lb + n - 1
418  temp(i) = array(i)
419  end do
420  deallocate (array)
421  array => temp
422  else
423  allocate (array(inc))
424  end if
425 
426  end subroutine extend_integer
427 
428  subroutine extend_string(array, increment)
429  ! -- dummy
430  character(len=*), dimension(:), pointer, contiguous :: array
431  integer(I4B), optional :: increment
432  ! -- local
433  integer(I4B) :: inc, i, n
434  character(len=len(array)), dimension(:), pointer, contiguous :: temp
435 
436  if (present(increment)) then
437  inc = increment
438  if (inc == 0) return
439  if (inc < 0) call pstop(1, "increment must be nonnegative")
440  else
441  inc = 1
442  end if
443 
444  if (associated(array)) then
445  n = size(array)
446  temp => array
447  allocate (array(n + inc))
448  do i = 1, n
449  array(i) = temp(i)
450  end do
451  deallocate (temp)
452  else
453  allocate (array(inc))
454  end if
455 
456  end subroutine extend_string
457 
458  !> @brief Concatenate integer arrays.
459  subroutine concat_integer(array, array_to_add)
460  integer(I4B), dimension(:), pointer, contiguous :: array
461  integer(I4B), dimension(:), pointer, contiguous :: array_to_add
462  ! local
463  integer(I4B) :: i, n
464 
465  n = size(array)
466  call extendptrarray(array, increment=size(array_to_add))
467  do i = 1, size(array_to_add)
468  array(n + i) = array_to_add(i)
469  end do
470  end subroutine concat_integer
471 
472  !> @brief Find the 1st array element containing str, or -1 if not found.
473  function ifind_character(array, str)
474  ! -- return
475  integer(I4B) :: ifind_character
476  ! -- dummy
477  character(len=*), dimension(:) :: array
478  character(len=*) :: str
479  ! -- local
480  integer(I4B) :: i
481 
482  ifind_character = -1
483  findloop: do i = 1, size(array)
484  if (array(i) == str) then
485  ifind_character = i
486  exit findloop
487  end if
488  end do findloop
489  end function ifind_character
490 
491  !> @brief Find the 1st array element containing str, or -1 if not found.
492  !<
493  function ifind_charstring(array, str)
495  ! -- return
496  integer(I4B) :: ifind_charstring
497  ! -- dummy
498  type(characterstringtype), dimension(:) :: array
499  type(characterstringtype) :: str
500  ! -- local
501  integer(I4B) :: i
502 
503  ifind_charstring = -1
504  findloop: do i = 1, size(array)
505  if (array(i) == str) then
506  ifind_charstring = i
507  exit findloop
508  end if
509  end do findloop
510  end function ifind_charstring
511 
512  !> @brief Find the first element containing ival, or -1 if not found.
513  function ifind_integer(iarray, ival)
514  ! -- return
515  integer(I4B) :: ifind_integer
516  ! -- dummy
517  integer(I4B), dimension(:) :: iarray
518  integer(I4B) :: ival
519  ! -- local
520  integer(I4B) :: i
521 
522  ifind_integer = -1
523  findloop: do i = 1, size(iarray)
524  if (iarray(i) == ival) then
525  ifind_integer = i
526  exit findloop
527  end if
528  end do findloop
529  end function ifind_integer
530 
531  !> @brief Remove the element at ipos from the array.
532  subroutine remove_character(array, ipos)
533  ! -- dummy
534  character(len=*), allocatable, intent(inout) :: array(:)
535  integer(I4B), intent(in) :: ipos
536  ! -- local
537  character(len=MAXCHARLEN), allocatable, dimension(:) :: temp
538  integer(I4B) :: i, inew, n
539 
540  ! -- check character length
541  if (len(array) > maxcharlen) &
542  call pstop(138, 'Error in ArrayHandlersModule: '// &
543  'Need to increase MAXCHARLEN. Stopping...')
544 
545  ! -- calculate size
546  n = size(array)
547 
548  ! -- copy array to temp
549  allocate (temp(n))
550  do i = 1, n
551  temp(i) = array(i)
552  end do
553 
554  ! -- de/reallocate and copy back to array,
555  ! omitting the specified element
556  deallocate (array)
557  allocate (array(n - 1))
558  inew = 1
559  do i = 1, n
560  if (i /= ipos) then
561  array(inew) = temp(i)
562  inew = inew + 1
563  end if
564  end do
565  deallocate (temp)
566 
567  end subroutine remove_character
568 
569 end module arrayhandlersmodule
subroutine concat_integer(array, array_to_add)
Concatenate integer arrays.
subroutine expand_integer_2d(array, increment1, increment2)
subroutine expand_character(array, increment)
subroutine expand_double(array, increment)
subroutine expand_double_2d(array, increment1, increment2)
subroutine, public remove_character(array, ipos)
Remove the element at ipos from the array.
subroutine extend_integer(array, increment)
subroutine extend_string(array, increment)
integer(i4b) function ifind_integer(iarray, ival)
Find the first element containing ival, or -1 if not found.
subroutine extend_double(array, increment)
subroutine expand_integer_wrapper(nsize, array, minvalue, loginc)
integer(i4b) function ifind_character(array, str)
Find the 1st array element containing str, or -1 if not found.
subroutine expand_integer(array, increment)
subroutine expand_logical(array, increment)
integer(i4b) function ifind_charstring(array, str)
Find the 1st array element containing str, or -1 if not found.
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter dten
real constant 10
Definition: Constants.f90:84
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:47
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
Definition: ErrorUtil.f90:24
This module defines variable data types.
Definition: kind.f90:8
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23