MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
mf6bmi.f90
Go to the documentation of this file.
1 !> @brief This module contains the MODFLOW 6 BMI
2 !!
3 !! This BMI interface matches the CSDMS standard, with a few modifications:
4 !!
5 !! - This interface will build into a shared library that can be called from other
6 !! executables and scripts, not necessarily written in Fortran. Therefore we have
7 !! omitted the type-boundness of the routines, since they cannot have the
8 !! bind(C,"...") attribute.
9 !! - MODFLOW has internal data arrays with rank > 1 that we would like to expose. An
10 !! example would be access to data in the BOUND array of GWF boundary packages (BndType).
11 !! The get_value_ptr calls below support this, returning a C-style pointer to the arrays
12 !! and methods have been added to query the variable's rank and shape.
13 !!
14 !! Note on style: BMI apparently uses underscores, we use underscores in some
15 !! places but camelcase in other. Since this is a dedicated BMI interface module,
16 !! we'll use underscores here as well.
17 !<
18 module mf6bmi
19  use mf6bmiutil
20  use mf6bmierror
21  use mf6coremodule
22  use tdismodule, only: kper, kstp
23  use iso_c_binding, only: c_int, c_char, c_double, c_null_char, c_loc, c_ptr, &
24  c_f_pointer
25  use kindmodule, only: dp, i4b, lgp
32  use memorytypemodule, only: memorytype
35  use inputoutputmodule, only: getunit
36  implicit none
37 
38  integer(c_int), bind(C, name="ISTDOUTTOFILE") :: istdout_to_file = 1 !< output control: =0 to screen, >0 to file
39  !DIR$ ATTRIBUTES DLLEXPORT :: istdout_to_file
40 
41 contains
42 
43  function bmi_get_component_name(name) result(bmi_status) &
44  bind(C, name="get_component_name")
45  !DIR$ ATTRIBUTES DLLEXPORT :: bmi_get_component_name
46  ! -- dummy variables
47  character(kind=c_char), intent(inout) :: name(bmi_lencomponentname)
48  integer(kind=c_int) :: bmi_status !< BMI status code
49  ! -- local variables
50  character(len=*), parameter :: component_name = 'MODFLOW 6'
51 
52  name(1:len(component_name) + 1) = &
53  string_to_char_array(component_name, len(component_name))
54  bmi_status = bmi_success
55 
56  end function bmi_get_component_name
57 
58  !> @brief Initialize the computational core
59  !!
60  !! It is required to have the MODFLOW 6 configuration file 'mfsim.nam'
61  !! available in the current working directory when calling this routine.
62  !!
63  !! NOTE: initialization should always be matched with a call to
64  !! bmi_finalize(). However, we currently do not support the reinitialization
65  !! of a model in the same memory space... You would have to create a new
66  !! process for that.
67  !<
68  function bmi_initialize() result(bmi_status) bind(C, name="initialize")
69  !DIR$ ATTRIBUTES DLLEXPORT :: bmi_initialize
70  ! -- dummy variables
71  integer(kind=c_int) :: bmi_status !< BMI status code
72  ! -- local variables
73 
74  if (istdout_to_file > 0) then
75  ! -- open stdout file mfsim.stdout
76  istdout = getunit()
77  !
78  ! -- set STDOUT to a physical file unit
79  open (unit=istdout, file=simstdout)
80  end if
81  !
82  ! -- initialize MODFLOW 6
83  call mf6initialize()
84 
85  bmi_status = bmi_success
86 
87  end function bmi_initialize
88 
89  !> @brief Perform a computational time step
90  !!
91  !! It will prepare the timestep, call the calculation routine
92  !! on all the solution groups in the simulation, and finalize
93  !! the timestep by printing out diagnostics and writing output.
94  !! It can be called in succession to perform multiple steps up
95  !! to the simulation's end time is reached.
96  !<
97  function bmi_update() result(bmi_status) bind(C, name="update")
98  !DIR$ ATTRIBUTES DLLEXPORT :: bmi_update
99  ! -- dummy variables
100  integer(kind=c_int) :: bmi_status !< BMI status code
101  ! -- local variables
102  logical :: hasconverged
103 
104  hasconverged = mf6update()
105 
106  bmi_status = bmi_success
107  end function bmi_update
108 
109  !> @brief Perform time steps until the current time reaches @p time
110  !!
111  !! Time steps are not split, so the current time can pass @p time. A time
112  !! before the current time or after the end time is an error.
113  !<
114  function bmi_update_until(time) result(bmi_status) &
115  bind(C, name="update_until")
116  !DIR$ ATTRIBUTES DLLEXPORT :: bmi_update_until
117  ! -- modules
118  use constantsmodule, only: done, dprec
120  ! -- dummy variables
121  real(kind=c_double), value, intent(in) :: time !< time to advance the simulation to
122  integer(kind=c_int) :: bmi_status !< BMI status code
123  ! -- local variables
124  real(dp) :: tol
125  logical :: hasconverged
126 
127  bmi_status = bmi_failure
128 
129  ! -- times that differ by roundoff are the same time
130  tol = dprec * max(done, abs(time))
131  if (time < totim - tol) then
132  write (bmi_last_error, fmt_invalid_time) time, &
133  'which is before the current time'
135  return
136  end if
137  if (time > totalsimtime + tol) then
138  write (bmi_last_error, fmt_invalid_time) time, &
139  'which is after the end time'
141  return
142  end if
143 
144  do while (totim < time - tol .and. .not. endofsimulation)
145  hasconverged = mf6update()
146  end do
147 
148  bmi_status = bmi_success
149  end function bmi_update_until
150 
151  !> @brief Clean up the initialized simulation
152  !!
153  !! Performs teardown tasks for the initialized simulation, this
154  !! call should match the call to bmi_initialize()
155  !<
156  function bmi_finalize() result(bmi_status) bind(C, name="finalize")
157  !DIR$ ATTRIBUTES DLLEXPORT :: bmi_finalize
158  ! -- modules
159  use simvariablesmodule, only: iforcestop
160  ! -- dummy variables
161  integer(kind=c_int) :: bmi_status !< BMI status code
162 
163  ! we don't want a full stop() here, this disables it:
164  iforcestop = 0
165  call mf6finalize()
166 
167  bmi_status = bmi_success
168 
169  end function bmi_finalize
170 
171  !> @brief Get the start time of the simulation
172  !!
173  !! As MODFLOW currently does not have internal time, this will be
174  !! returning 0.0 for now. New version...
175  !<
176  function get_start_time(start_time) result(bmi_status) &
177  bind(C, name="get_start_time")
178  !DIR$ ATTRIBUTES DLLEXPORT :: get_start_time
179  ! -- dummy variables
180  real(kind=c_double), intent(out) :: start_time !< start time
181  integer(kind=c_int) :: bmi_status !< BMI status code
182 
183  start_time = 0.0_dp
184  bmi_status = bmi_success
185 
186  end function get_start_time
187 
188  !> @brief Get the end time of the simulation
189  !!
190  !! As MODFLOW does currently does not have internal time, this will be
191  !! equal to the total runtime.
192  !<
193  function get_end_time(end_time) result(bmi_status) bind(C, name="get_end_time")
194  !DIR$ ATTRIBUTES DLLEXPORT :: get_end_time
195  ! -- modules
196  use tdismodule, only: totalsimtime
197  ! -- dummy variables
198  real(kind=c_double), intent(out) :: end_time !< end time
199  integer(kind=c_int) :: bmi_status !< BMI status code
200 
201  end_time = totalsimtime
202  bmi_status = bmi_success
203 
204  end function get_end_time
205 
206  !> @brief Get the current time of the simulation
207  !!
208  !! As MODFLOW currently does not have internal time, this will be
209  !! equal to the time passed w.r.t. the start time of the simulation.
210  !<
211  function get_current_time(current_time) result(bmi_status) &
212  bind(C, name="get_current_time")
213  !DIR$ ATTRIBUTES DLLEXPORT :: get_current_time
214  ! -- modules
215  use tdismodule, only: totim
216  ! -- dummy variables
217  real(kind=c_double), intent(out) :: current_time !< current time
218  integer(kind=c_int) :: bmi_status !< BMI status code
219 
220  current_time = totim
221  bmi_status = bmi_success
222 
223  end function get_current_time
224 
225  !> @brief Get the time step for the simulation
226  !!
227  !! Note that the returned value may vary between and within stress periods,
228  !! depending on your time discretization settings in the TDIS package.
229  !<
230  function get_time_step(time_step) result(bmi_status) &
231  bind(C, name="get_time_step")
232  !DIR$ ATTRIBUTES DLLEXPORT :: get_time_step
233  ! -- modules
234  use tdismodule, only: delt
235  ! -- dummy variables
236  real(kind=c_double), intent(out) :: time_step !< current time step
237  integer(kind=c_int) :: bmi_status !< BMI status code
238 
239  time_step = delt
240  bmi_status = bmi_success
241 
242  end function get_time_step
243 
244  !> @brief Get the time units of the simulation
245  !!
246  !! The units are those of TIME_UNITS in the TDIS Package, as UDUNITS
247  !! symbols, or 'unknown' when TIME_UNITS is not given.
248  !<
249  function get_time_units(c_time_units) result(bmi_status) &
250  bind(C, name="get_time_units")
251  !DIR$ ATTRIBUTES DLLEXPORT :: get_time_units
252  ! -- modules
253  use tdismodule, only: itmuni
254  ! -- dummy variables
255  character(kind=c_char), intent(out) :: c_time_units(bmi_lenunits) !< time units as a string
256  integer(kind=c_int) :: bmi_status !< BMI status code
257  ! -- local variables
258  character(len=LENUNITS) :: time_units
259 
260  select case (itmuni)
261  case (1)
262  time_units = 's'
263  case (2)
264  time_units = 'min'
265  case (3)
266  time_units = 'h'
267  case (4)
268  time_units = 'd'
269  case (5)
270  time_units = 'year'
271  case default
272  time_units = 'unknown'
273  end select
274  c_time_units(1:len_trim(time_units) + 1) = &
275  string_to_char_array(trim(time_units), len_trim(time_units))
276  bmi_status = bmi_success
277 
278  end function get_time_units
279 
280  !> @brief Get the number of input variables in the simulation
281  !!
282  !! This concerns all variables stored in the memory manager
283  !<
284  function get_input_item_count(count) result(bmi_status) &
285  bind(C, name="get_input_item_count")
286  !DIR$ ATTRIBUTES DLLEXPORT :: get_input_item_count
287  ! -- dummy variables
288  integer(kind=c_int), intent(out) :: count !< the number of input variables
289  integer(kind=c_int) :: bmi_status !< BMI status code
290 
291  count = memorystore%count()
292 
293  bmi_status = bmi_success
294 
295  end function get_input_item_count
296 
297  !> @brief Get the number of output variables in the simulation
298  !!
299  !! This concerns all variables stored in the memory manager
300  !<
301  function get_output_item_count(count) result(bmi_status) &
302  bind(C, name="get_output_item_count")
303  !DIR$ ATTRIBUTES DLLEXPORT :: get_output_item_count
304  ! -- dummy variables
305  integer(kind=c_int), intent(out) :: count !< the number of output variables
306  integer(kind=c_int) :: bmi_status !< BMI status code
307 
308  count = memorystore%count()
309 
310  bmi_status = bmi_success
311 
312  end function get_output_item_count
313 
314  !> @brief Returns all input variables in the simulation
315  !!
316  !! This functions returns the full address for all variables in the
317  !! memory manager
318  !!
319  !! The array @p c_names should be pre-allocated of proper size:
320  !!
321  !! size = BMI_LENVARADDRESS * get_input_item_count()
322  !!
323  !! The strings will be written contiguously with stride equal to
324  !! BMI_LENVARADDRESS and nul-terminated where the trailing spaces start:
325  !!
326  !! c_names = 'variable_address_1\x00 ... variable_address_2\x00 ... ' etc.
327  !<
328  function get_input_var_names(c_names) result(bmi_status) &
329  bind(C, name="get_input_var_names")
330  !DIR$ ATTRIBUTES DLLEXPORT :: get_input_var_names
331  ! -- dummy variables
332  character(kind=c_char, len=1), intent(inout) :: c_names(*) !< array with memory paths for input variables
333  integer(kind=c_int) :: bmi_status !< BMI status code
334  ! -- local variables
335  integer(I4B) :: start, i
336  type(memorycontaineriteratortype), allocatable :: itr
337  type(memorytype), pointer :: mt => null()
338  character(len=LENMEMADDRESS) :: var_address
339 
340  start = 1
341  itr = memorystore%iterator()
342  do while (itr%has_next())
343  call itr%next()
344  mt => itr%value()
345  var_address = create_mem_address(mt%path, mt%name)
346  do i = 1, len(trim(var_address))
347  c_names(start + i - 1) = var_address(i:i)
348  end do
349  c_names(start + i) = c_null_char
350  start = start + bmi_lenvaraddress
351  end do
352 
353  bmi_status = bmi_success
354 
355  end function get_input_var_names
356 
357  !> @brief Returns all output variables in the simulation
358  !!
359  !! This function works analogously to get_input_var_names(),
360  !! and currently returns the same set of memory variables,
361  !! which is all of them!
362  !<
363  function get_output_var_names(c_names) result(bmi_status) &
364  bind(C, name="get_output_var_names")
365  !DIR$ ATTRIBUTES DLLEXPORT :: get_output_var_names
366  ! -- dummy variables
367  character(kind=c_char, len=1), intent(inout) :: c_names(*) !< array with memory paths for output variables
368  integer(kind=c_int) :: bmi_status !< BMI status code
369  ! -- local variables
370  integer(I4B) :: start, i
371  type(memorycontaineriteratortype), allocatable :: itr
372  type(memorytype), pointer :: mt => null()
373  character(len=LENMEMADDRESS) :: var_address
374 
375  start = 1
376  itr = memorystore%iterator()
377  do while (itr%has_next())
378  call itr%next()
379  mt => itr%value()
380  var_address = create_mem_address(mt%path, mt%name)
381  do i = 1, len(trim(var_address))
382  c_names(start + i - 1) = var_address(i:i)
383  end do
384  c_names(start + i) = c_null_char
385  start = start + bmi_lenvaraddress
386  end do
387 
388  bmi_status = bmi_success
389 
390  end function get_output_var_names
391 
392  !> @brief Get the size (in bytes) of a single element of a variable
393  !<
394  function get_var_itemsize(c_var_address, var_size) result(bmi_status) &
395  bind(C, name="get_var_itemsize")
396  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_itemsize
397  ! -- dummy variables
398  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
399  integer(kind=c_int), intent(out) :: var_size !< size of the element in bytes
400  integer(kind=c_int) :: bmi_status !< BMI status code
401  ! -- local variables
402  character(len=LENMEMPATH) :: mem_path
403  character(len=LENVARNAME) :: var_name
404  logical(LGP) :: valid
405 
406  bmi_status = bmi_success
407 
408  call split_address(c_var_address, mem_path, var_name, valid)
409  if (.not. valid) then
410  bmi_status = bmi_failure
411  return
412  end if
413 
414  call get_mem_elem_size(var_name, mem_path, var_size)
415  if (var_size == -1) bmi_status = bmi_failure
416 
417  end function get_var_itemsize
418 
419  !> @brief Get size of the variable, in bytes
420  !<
421  function get_var_nbytes(c_var_address, var_nbytes) result(bmi_status) &
422  bind(C, name="get_var_nbytes")
423  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_nbytes
424  ! -- dummy variables
425  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
426  integer(kind=c_int), intent(out) :: var_nbytes !< size in bytes
427  integer(kind=c_int) :: bmi_status !< BMI status code
428  ! -- local variables
429  integer(I4B) :: var_size, isize
430  character(len=LENMEMPATH) :: mem_path
431  character(len=LENVARNAME) :: var_name
432  logical(LGP) :: valid
433 
434  bmi_status = bmi_success
435 
436  call split_address(c_var_address, mem_path, var_name, valid)
437  if (.not. valid) then
438  bmi_status = bmi_failure
439  return
440  end if
441 
442  call get_mem_elem_size(var_name, mem_path, var_size)
443  if (var_size == -1) bmi_status = bmi_failure
444  call get_isize(var_name, mem_path, isize)
445  if (isize == -1) bmi_status = bmi_failure
446 
447  var_nbytes = var_size * isize
448 
449  end function get_var_nbytes
450 
451  !> @brief Copy the double precision values of a variable into the array
452  !!
453  !! The copied variable us located at @p c_var_address. The caller should
454  !! provide @p c_arr_ptr pointing to an array of the proper shape (the
455  !! BMI function get_var_shape() can be used to create it). Multi-dimensional
456  !! arrays are supported.
457  !<
458  function get_value_double(c_var_address, c_arr_ptr) result(bmi_status) &
459  bind(C, name="get_value_double")
460  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_double
461  ! -- modules
463  ! -- dummy variables
464  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
465  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the double precision array
466  integer(kind=c_int) :: bmi_status !< BMI status code
467  ! -- local variables
468  character(len=LENMEMPATH) :: mem_path
469  character(len=LENVARNAME) :: var_name
470  logical(LGP) :: valid
471  integer(I4B) :: rank
472  real(dp), pointer :: src_ptr, tgt_ptr
473  real(dp), dimension(:), pointer, contiguous :: src1d_ptr, tgt1d_ptr
474  real(dp), dimension(:, :), pointer, contiguous :: src2d_ptr, tgt2d_ptr
475  real(dp), dimension(:, :, :), pointer, contiguous :: src3d_ptr, tgt3d_ptr
476  integer(I4B) :: i, j, k
477 
478  bmi_status = bmi_success
479 
480  call split_address(c_var_address, mem_path, var_name, valid)
481  if (.not. valid) then
482  bmi_status = bmi_failure
483  return
484  end if
485 
486  ! convert pointer and copy data from memory manager into
487  ! the passed array, using loops to avoid stack overflow
488  rank = -1
489  call get_mem_rank(var_name, mem_path, rank)
490 
491  if (rank == 0) then
492  call mem_setptr(src_ptr, var_name, mem_path)
493  call c_f_pointer(c_arr_ptr, tgt_ptr)
494  tgt_ptr = src_ptr
495  else if (rank == 1) then
496  call mem_setptr(src1d_ptr, var_name, mem_path)
497  call c_f_pointer(c_arr_ptr, tgt1d_ptr, shape(src1d_ptr))
498  do i = 1, size(tgt1d_ptr)
499  tgt1d_ptr(i) = src1d_ptr(i)
500  end do
501  else if (rank == 2) then
502  call mem_setptr(src2d_ptr, var_name, mem_path)
503  call c_f_pointer(c_arr_ptr, tgt2d_ptr, shape(src2d_ptr))
504  do j = 1, size(tgt2d_ptr, 2)
505  do i = 1, size(tgt2d_ptr, 1)
506  tgt2d_ptr(i, j) = src2d_ptr(i, j)
507  end do
508  end do
509  else if (rank == 3) then
510  call mem_setptr(src3d_ptr, var_name, mem_path)
511  call c_f_pointer(c_arr_ptr, tgt3d_ptr, shape(src3d_ptr))
512  do k = 1, size(tgt3d_ptr, 3)
513  do j = 1, size(tgt3d_ptr, 2)
514  do i = 1, size(tgt3d_ptr, 1)
515  tgt3d_ptr(i, j, k) = src3d_ptr(i, j, k)
516  end do
517  end do
518  end do
519  else
520  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
522  bmi_status = bmi_failure
523  return
524  end if
525 
526  end function get_value_double
527 
528  !> @brief Copy the integer values of a variable into the array
529  !!
530  !! The copied variable is located at @p c_var_address. The caller should
531  !! provide @p c_arr_ptr pointing to an array of the proper shape (the
532  !! BMI function get_var_shape() can be used to create it). Multi-dimensional
533  !! arrays are supported.
534  !<
535  function get_value_int(c_var_address, c_arr_ptr) result(bmi_status) &
536  bind(C, name="get_value_int")
537  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_int
538  ! -- modules
540  ! -- dummy variables
541  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
542  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the integer array
543  integer(kind=c_int) :: bmi_status !< BMI status code
544  ! -- local variables
545  character(len=LENMEMPATH) :: mem_path
546  character(len=LENVARNAME) :: var_name
547  logical(LGP) :: valid
548  integer(I4B) :: rank
549  integer(I4B), pointer :: src_ptr, tgt_ptr
550  integer(I4B), dimension(:), pointer, contiguous :: src1d_ptr, tgt1d_ptr
551  integer(I4B), dimension(:, :), pointer, contiguous :: src2d_ptr, tgt2d_ptr
552  integer(I4B), dimension(:, :, :), pointer, contiguous :: src3d_ptr, tgt3d_ptr
553  integer(I4B) :: i, j, k
554 
555  bmi_status = bmi_success
556 
557  call split_address(c_var_address, mem_path, var_name, valid)
558  if (.not. valid) then
559  bmi_status = bmi_failure
560  return
561  end if
562 
563  ! convert pointer and copy data from memory manager into
564  ! the passed array, using loops to avoid stack overflow
565  rank = -1
566  call get_mem_rank(var_name, mem_path, rank)
567 
568  if (rank == 0) then
569  call mem_setptr(src_ptr, var_name, mem_path)
570  call c_f_pointer(c_arr_ptr, tgt_ptr)
571  tgt_ptr = src_ptr
572  else if (rank == 1) then
573  call mem_setptr(src1d_ptr, var_name, mem_path)
574  call c_f_pointer(c_arr_ptr, tgt1d_ptr, shape(src1d_ptr))
575  do i = 1, size(tgt1d_ptr)
576  tgt1d_ptr(i) = src1d_ptr(i)
577  end do
578  else if (rank == 2) then
579  call mem_setptr(src2d_ptr, var_name, mem_path)
580  call c_f_pointer(c_arr_ptr, tgt2d_ptr, shape(src2d_ptr))
581  do j = 1, size(tgt2d_ptr, 2)
582  do i = 1, size(tgt2d_ptr, 1)
583  tgt2d_ptr(i, j) = src2d_ptr(i, j)
584  end do
585  end do
586  else if (rank == 3) then
587  call mem_setptr(src3d_ptr, var_name, mem_path)
588  call c_f_pointer(c_arr_ptr, tgt3d_ptr, shape(src3d_ptr))
589  do k = 1, size(tgt3d_ptr, 3)
590  do j = 1, size(tgt3d_ptr, 2)
591  do i = 1, size(tgt3d_ptr, 1)
592  tgt3d_ptr(i, j, k) = src3d_ptr(i, j, k)
593  end do
594  end do
595  end do
596  else
597  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
599  bmi_status = bmi_failure
600  return
601  end if
602 
603  end function get_value_int
604 
605  !> @brief Copy the logical scalar value into the array
606  !!
607  !! The copied variable us located at @p c_var_address. The caller should
608  !! provide @p c_arr_ptr pointing to a scalar array with rank=0.
609  !<
610  function get_value_bool(c_var_address, c_arr_ptr) result(bmi_status) &
611  bind(C, name="get_value_bool")
612  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_bool
613  ! -- modules
615  ! -- dummy variables
616  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
617  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the logical array
618  integer(kind=c_int) :: bmi_status !< BMI status code
619  ! -- local variables
620  character(len=LENMEMPATH) :: mem_path
621  character(len=LENVARNAME) :: var_name
622  logical(LGP) :: valid
623  integer(I4B) :: rank
624  logical(LGP), pointer :: src_ptr, tgt_ptr
625 
626  bmi_status = bmi_success
627 
628  call split_address(c_var_address, mem_path, var_name, valid)
629  if (.not. valid) then
630  bmi_status = bmi_failure
631  return
632  end if
633 
634  rank = -1
635  call get_mem_rank(var_name, mem_path, rank)
636 
637  ! convert pointer
638  if (rank == 0) then
639  call mem_setptr(src_ptr, var_name, mem_path)
640  call c_f_pointer(c_arr_ptr, tgt_ptr)
641  tgt_ptr = src_ptr
642  else
643  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
645  bmi_status = bmi_failure
646  return
647  end if
648 
649  end function get_value_bool
650 
651  !> @brief Copy the string(s) of a variable into the array
652  !!
653  !! The copied variable is located at @p c_var_address. The caller should
654  !! provide @p c_arr_ptr pointing to an array of the proper shape (the
655  !! BMI function get_var_shape() can be used to create it). For strings
656  !! currently scalars and 1d arrays (of CharacterStringType) are
657  !< supported
658  function get_value_string(c_var_address, c_arr_ptr) result(bmi_status) &
659  bind(C, name="get_value_string")
660  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_string
661  ! -- modules
662  ! -- dummy variables
663  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
664  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the string array
665  integer(kind=c_int) :: bmi_status !< BMI status code
666  ! -- local variables
667  character(len=LENMEMPATH) :: mem_path
668  character(len=LENVARNAME) :: var_name
669  logical(LGP) :: valid
670  integer(I4B) :: rank
671  character(len=:), pointer :: srcstr
672  character(kind=c_char), pointer :: tgtstr(:)
673  type(characterstringtype), dimension(:), pointer, contiguous :: srccharstr1d
674  character(kind=c_char), pointer :: tgtstr1d(:, :)
675  character(:), allocatable :: tempstr
676  integer(I4B) :: i, ilen, isize
677 
678  bmi_status = bmi_success
679 
680  call split_address(c_var_address, mem_path, var_name, valid)
681  if (.not. valid) then
682  bmi_status = bmi_failure
683  return
684  end if
685 
686  ! single string, or array of strings (CharacterStringType)
687  rank = -1
688  call get_mem_rank(var_name, mem_path, rank)
689 
690  if (rank == 0) then
691  ! a string scalar
692  call mem_setptr(srcstr, var_name, mem_path)
693  call get_mem_elem_size(var_name, mem_path, ilen)
694  call c_f_pointer(c_arr_ptr, tgtstr, shape=[ilen + 1])
695 
696  tgtstr(1:len(srcstr) + 1) = string_to_char_array(srcstr, len(srcstr))
697 
698  else if (rank == 1) then
699  ! an array of strings
700  call mem_setptr(srccharstr1d, var_name, mem_path)
701  if (.not. associated(srccharstr1d)) then
702  write (bmi_last_error, fmt_general_err) 'string type not supported in API'
704  bmi_status = bmi_failure
705  return
706  end if
707 
708  ! create fortran pointer to C data array
709  call get_isize(var_name, mem_path, isize)
710  call get_mem_elem_size(var_name, mem_path, ilen)
711  call c_f_pointer(c_arr_ptr, tgtstr1d, shape=[ilen + 1, isize])
712 
713  ! allocate work array to handle CharacterStringType,
714  ! and copy the strings
715  allocate (character(ilen) :: tempstr)
716  do i = 1, isize
717  tempstr = srccharstr1d(i)
718  tgtstr1d(1:ilen + 1, i) = string_to_char_array(tempstr, ilen)
719  end do
720  deallocate (tempstr)
721  else
722  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
724  bmi_status = bmi_failure
725  return
726  end if
727 
728  end function get_value_string
729 
730  !> @brief Copy the value of a variable into the array
731  !!
732  !! The copied variable is located at @p c_var_address. The caller should
733  !! provide @p c_arr_ptr pointing to an array of the proper shape (the
734  !! BMI function get_var_shape() can be used to create it). Multi-dimensional
735  !! arrays are supported.
736  !<
737  function get_value(c_var_address, c_arr_ptr) result(bmi_status) &
738  bind(C, name="get_value")
739  !DIR$ ATTRIBUTES DLLEXPORT :: get_value
740  ! -- modules
741  use constantsmodule, only: lenmemtype
742  ! -- dummy variables
743  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
744  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
745  integer(kind=c_int) :: bmi_status !< BMI status code
746  ! -- local variables
747  character(len=LENMEMPATH) :: mem_path
748  character(len=LENMEMTYPE) :: mem_type
749  character(len=LENVARNAME) :: var_name
750  logical(LGP) :: valid
751 
752  bmi_status = bmi_success
753 
754  call split_address(c_var_address, mem_path, var_name, valid)
755  if (.not. valid) then
756  bmi_status = bmi_failure
757  return
758  end if
759 
760  call get_mem_type(var_name, mem_path, mem_type)
761 
762  if (index(mem_type, "DOUBLE") /= 0) then
763  bmi_status = get_value_double(c_var_address, c_arr_ptr)
764  else if (index(mem_type, "INTEGER") /= 0) then
765  bmi_status = get_value_int(c_var_address, c_arr_ptr)
766  else if (index(mem_type, "LOGICAL") /= 0) then
767  bmi_status = get_value_bool(c_var_address, c_arr_ptr)
768  else if (index(mem_type, "STRING") /= 0) then
769  bmi_status = get_value_string(c_var_address, c_arr_ptr)
770  else
771  write (bmi_last_error, fmt_unsupported_type) trim(var_name)
773  bmi_status = bmi_failure
774  return
775  end if
776 
777  end function get_value
778 
779  !> @brief Get a pointer to an array
780  !!
781  !! The array is located at @p c_var_address. There is no copying of data involved.
782  !! Multi-dimensional arrays are supported and the get_var_rank() function
783  !! can be used to get the variable's dimensionality, and get_var_shape() for
784  !! its shape.
785  !<
786  function get_value_ptr(c_var_address, c_arr_ptr) result(bmi_status) &
787  bind(C, name="get_value_ptr")
788  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr
789  ! -- modules
790  use constantsmodule, only: lenmemtype
791  ! -- dummy variables
792  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
793  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
794  integer(kind=c_int) :: bmi_status !< BMI status code
795  ! -- local variables
796  character(len=LENMEMPATH) :: mem_path
797  character(len=LENMEMTYPE) :: mem_type
798  character(len=LENVARNAME) :: var_name
799  logical(LGP) :: valid
800 
801  bmi_status = bmi_success
802 
803  call split_address(c_var_address, mem_path, var_name, valid)
804  if (.not. valid) then
805  bmi_status = bmi_failure
806  return
807  end if
808 
809  call get_mem_type(var_name, mem_path, mem_type)
810 
811  if (index(mem_type, "DOUBLE") /= 0) then
812  bmi_status = get_value_ptr_double(c_var_address, c_arr_ptr)
813  else if (index(mem_type, "INTEGER") /= 0) then
814  bmi_status = get_value_ptr_int(c_var_address, c_arr_ptr)
815  else if (index(mem_type, "LOGICAL") /= 0) then
816  bmi_status = get_value_ptr_bool(c_var_address, c_arr_ptr)
817  else
818  write (bmi_last_error, fmt_unsupported_type) trim(var_name)
820  bmi_status = bmi_failure
821  return
822  end if
823 
824  end function get_value_ptr
825 
826  !> @brief Get a pointer to the array of double precision numbers
827  !!
828  !! The array is located at @p c_var_address. There is no copying of data involved.
829  !! Multi-dimensional arrays are supported and the get_var_rank() function
830  !! can be used to get the variable's dimensionality, and get_var_shape() for
831  !! its shape.
832  !<
833  function get_value_ptr_double(c_var_address, c_arr_ptr) result(bmi_status) &
834  bind(C, name="get_value_ptr_double")
835  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr_double
836  ! -- dummy variables
837  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
838  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
839  integer(kind=c_int) :: bmi_status !< BMI status code
840  ! -- local variables
841  character(len=LENMEMPATH) :: mem_path
842  character(len=LENVARNAME) :: var_name
843  logical(LGP) :: valid
844  real(dp), pointer :: scalar_ptr
845  real(dp), dimension(:), pointer, contiguous :: array_ptr
846  real(dp), dimension(:, :), pointer, contiguous :: array2d_ptr
847  real(dp), dimension(:, :, :), pointer, contiguous :: array3d_ptr
848  integer(I4B) :: rank
849 
850  bmi_status = bmi_success
851 
852  call split_address(c_var_address, mem_path, var_name, valid)
853  if (.not. valid) then
854  bmi_status = bmi_failure
855  return
856  end if
857 
858  rank = -1
859  call get_mem_rank(var_name, mem_path, rank)
860  if (rank == 0) then
861  call mem_setptr(scalar_ptr, var_name, mem_path)
862  c_arr_ptr = c_loc(scalar_ptr)
863  else if (rank == 1) then
864  call mem_setptr(array_ptr, var_name, mem_path)
865  c_arr_ptr = c_loc(array_ptr)
866  else if (rank == 2) then
867  call mem_setptr(array2d_ptr, var_name, mem_path)
868  c_arr_ptr = c_loc(array2d_ptr)
869  else if (rank == 3) then
870  call mem_setptr(array3d_ptr, var_name, mem_path)
871  c_arr_ptr = c_loc(array3d_ptr)
872  else
873  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
875  bmi_status = bmi_failure
876  return
877  end if
878 
879  end function get_value_ptr_double
880 
881  !> @brief Get a pointer to the array of integer numbers
882  !!
883  !! The array is located at @p c_var_address. There is no copying of data involved.
884  !! Multi-dimensional arrays are supported and the get_var_rank() function
885  !! can be used to get the variable's dimensionality.
886  !<
887  function get_value_ptr_int(c_var_address, c_arr_ptr) result(bmi_status) &
888  bind(C, name="get_value_ptr_int")
889  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr_int
890  ! -- dummy variables
891  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
892  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
893  integer(kind=c_int) :: bmi_status !< BMI status code
894  ! -- local variables
895  character(len=LENMEMPATH) :: mem_path
896  character(len=LENVARNAME) :: var_name
897  logical(LGP) :: valid
898  integer(I4B) :: rank
899  integer(I4B), pointer :: scalar_ptr
900  integer(I4B), dimension(:), pointer, contiguous :: array_ptr
901  integer(I4B), dimension(:, :), pointer, contiguous :: array2d_ptr
902  integer(I4B), dimension(:, :, :), pointer, contiguous :: array3d_ptr
903 
904  bmi_status = bmi_success
905 
906  call split_address(c_var_address, mem_path, var_name, valid)
907  if (.not. valid) then
908  bmi_status = bmi_failure
909  return
910  end if
911 
912  rank = -1
913  call get_mem_rank(var_name, mem_path, rank)
914 
915  if (rank == 0) then
916  call mem_setptr(scalar_ptr, var_name, mem_path)
917  c_arr_ptr = c_loc(scalar_ptr)
918  else if (rank == 1) then
919  call mem_setptr(array_ptr, var_name, mem_path)
920  c_arr_ptr = c_loc(array_ptr)
921  else if (rank == 2) then
922  call mem_setptr(array2d_ptr, var_name, mem_path)
923  c_arr_ptr = c_loc(array2d_ptr)
924  else if (rank == 3) then
925  call mem_setptr(array3d_ptr, var_name, mem_path)
926  c_arr_ptr = c_loc(array3d_ptr)
927  else
928  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
930  bmi_status = bmi_failure
931  return
932  end if
933 
934  end function get_value_ptr_int
935 
936  !> @brief Get a pointer to the logical scalar value
937  !!
938  !! Only scalar values (with rank=0) are supported.
939  !<
940  function get_value_ptr_bool(c_var_address, c_arr_ptr) result(bmi_status) &
941  bind(C, name="get_value_ptr_bool")
942  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr_bool
943  ! -- dummy variables
944  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
945  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
946  integer(kind=c_int) :: bmi_status !< BMI status code
947  ! -- local variables
948  character(len=LENMEMPATH) :: mem_path
949  character(len=LENVARNAME) :: var_name
950  logical(LGP) :: valid
951  logical(LGP), pointer :: scalar_ptr
952  integer(I4B) :: rank
953 
954  bmi_status = bmi_success
955 
956  call split_address(c_var_address, mem_path, var_name, valid)
957  if (.not. valid) then
958  bmi_status = bmi_failure
959  return
960  end if
961 
962  rank = -1
963  call get_mem_rank(var_name, mem_path, rank)
964  if (rank == 0) then
965  call mem_setptr(scalar_ptr, var_name, mem_path)
966  c_arr_ptr = c_loc(scalar_ptr)
967  else
968  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
970  bmi_status = bmi_failure
971  return
972  end if
973 
974  end function get_value_ptr_bool
975 
976  !> @brief Set new values for a given variable
977  !!
978  !! The array pointed to by @p c_arr_ptr can have rank equal to 0, 1, or 2
979  !! and should have a C-style layout, which is particularly important for
980  !! rank > 1.
981  !<
982  function set_value(c_var_address, c_arr_ptr) result(bmi_status) &
983  bind(C, name="set_value")
984  !DIR$ ATTRIBUTES DLLEXPORT :: set_value
985  ! -- modules
986  use constantsmodule, only: lenmemtype
987  ! -- dummy variables
988  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
989  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
990  integer(kind=c_int) :: bmi_status !< BMI status code
991  ! -- local variables
992  character(len=LENMEMPATH) :: mem_path
993  character(len=LENMEMTYPE) :: mem_type
994  character(len=LENVARNAME) :: var_name
995  logical(LGP) :: valid
996 
997  bmi_status = bmi_success
998 
999  call split_address(c_var_address, mem_path, var_name, valid)
1000  if (.not. valid) then
1001  bmi_status = bmi_failure
1002  return
1003  end if
1004 
1005  call get_mem_type(var_name, mem_path, mem_type)
1006 
1007  if (index(mem_type, "DOUBLE") /= 0) then
1008  bmi_status = set_value_double(c_var_address, c_arr_ptr)
1009  else if (index(mem_type, "INTEGER") /= 0) then
1010  bmi_status = set_value_int(c_var_address, c_arr_ptr)
1011  else if (index(mem_type, "LOGICAL") /= 0) then
1012  bmi_status = set_value_bool(c_var_address, c_arr_ptr)
1013  else
1014  write (bmi_last_error, fmt_unsupported_type) trim(var_name)
1016  bmi_status = bmi_failure
1017  return
1018  end if
1019 
1020  end function set_value
1021 
1022  !> @brief Set new values for a variable of type double
1023  !!
1024  !! The array pointed to by @p c_arr_ptr can have rank equal to 0, 1, or 2
1025  !! and should have a C-style layout, which is particularly important for
1026  !! rank > 1.
1027  !<
1028  function set_value_double(c_var_address, c_arr_ptr) result(bmi_status) &
1029  bind(C, name="set_value_double")
1030  !DIR$ ATTRIBUTES DLLEXPORT :: set_value_double
1031  ! -- modules
1033  ! -- dummy variables
1034  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1035  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the double precision array
1036  integer(kind=c_int) :: bmi_status !< BMI status code
1037  ! -- local variables
1038  character(len=LENMEMPATH) :: mem_path
1039  character(len=LENVARNAME) :: var_name
1040  logical(LGP) :: valid
1041  integer(I4B) :: rank
1042  real(dp), pointer :: src_ptr, tgt_ptr
1043  real(dp), dimension(:), pointer, contiguous :: src1d_ptr, tgt1d_ptr
1044  real(dp), dimension(:, :), pointer, contiguous :: src2d_ptr, tgt2d_ptr
1045  integer(I4B) :: i, j
1046  integer(I4B) :: status
1047 
1048  bmi_status = bmi_success
1049 
1050  call split_address(c_var_address, mem_path, var_name, valid)
1051  if (.not. valid) then
1052  bmi_status = bmi_failure
1053  return
1054  end if
1055 
1056  ! convert pointer and copy, using loops to avoid stack overflow
1057  rank = -1
1058  call get_mem_rank(var_name, mem_path, rank)
1059 
1060  if (rank == 0) then
1061  call mem_setptr(tgt_ptr, var_name, mem_path)
1062  call c_f_pointer(c_arr_ptr, src_ptr)
1063  tgt_ptr = src_ptr
1064  else if (rank == 1) then
1065  call mem_setptr(tgt1d_ptr, var_name, mem_path)
1066  call c_f_pointer(c_arr_ptr, src1d_ptr, shape(tgt1d_ptr))
1067  do i = 1, size(tgt1d_ptr)
1068  tgt1d_ptr(i) = src1d_ptr(i)
1069  end do
1070  else if (rank == 2) then
1071  call mem_setptr(tgt2d_ptr, var_name, mem_path)
1072  call c_f_pointer(c_arr_ptr, src2d_ptr, shape(tgt2d_ptr))
1073  do j = 1, size(tgt2d_ptr, 2)
1074  do i = 1, size(tgt2d_ptr, 1)
1075  tgt2d_ptr(i, j) = src2d_ptr(i, j)
1076  end do
1077  end do
1078  else
1079  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
1081  bmi_status = bmi_failure
1082  return
1083  end if
1084 
1085  ! trigger event:
1086  call on_memory_set(var_name, mem_path, status)
1087  if (status /= 0) then
1088  ! something went terribly wrong here, aborting
1089  write (bmi_last_error, fmt_invalid_mem_access) trim(var_name)
1091  bmi_status = bmi_failure
1092  return
1093  end if
1094 
1095  end function set_value_double
1096 
1097  !> @brief Set new values for a variable of type integer
1098  !!
1099  !! The array pointed to by @p c_arr_ptr can have rank equal to 0, 1, or 2.
1100  !<
1101  function set_value_int(c_var_address, c_arr_ptr) result(bmi_status) &
1102  bind(C, name="set_value_int")
1103  !DIR$ ATTRIBUTES DLLEXPORT :: set_value_int
1104  ! -- modules
1106  ! -- dummy variables
1107  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1108  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the integer array
1109  integer(kind=c_int) :: bmi_status !< BMI status code
1110  ! -- local variables
1111  character(len=LENMEMPATH) :: mem_path
1112  character(len=LENVARNAME) :: var_name
1113  logical(LGP) :: valid
1114  integer(I4B) :: rank
1115  integer(I4B), pointer :: src_ptr, tgt_ptr
1116  integer(I4B), dimension(:), pointer, contiguous :: src1d_ptr, tgt1d_ptr
1117  integer(I4B), dimension(:, :), pointer, contiguous :: src2d_ptr, tgt2d_ptr
1118  integer(I4B) :: i, j
1119  integer(I4B) :: status
1120 
1121  bmi_status = bmi_success
1122 
1123  call split_address(c_var_address, mem_path, var_name, valid)
1124  if (.not. valid) then
1125  bmi_status = bmi_failure
1126  return
1127  end if
1128 
1129  ! convert pointer and copy, using loops to avoid stack overflow
1130  rank = -1
1131  call get_mem_rank(var_name, mem_path, rank)
1132 
1133  if (rank == 0) then
1134  call mem_setptr(tgt_ptr, var_name, mem_path)
1135  call c_f_pointer(c_arr_ptr, src_ptr)
1136  tgt_ptr = src_ptr
1137  else if (rank == 1) then
1138  call mem_setptr(tgt1d_ptr, var_name, mem_path)
1139  call c_f_pointer(c_arr_ptr, src1d_ptr, shape(tgt1d_ptr))
1140  do i = 1, size(tgt1d_ptr)
1141  tgt1d_ptr(i) = src1d_ptr(i)
1142  end do
1143  else if (rank == 2) then
1144  call mem_setptr(tgt2d_ptr, var_name, mem_path)
1145  call c_f_pointer(c_arr_ptr, src2d_ptr, shape(tgt2d_ptr))
1146  do j = 1, size(tgt2d_ptr, 2)
1147  do i = 1, size(tgt2d_ptr, 1)
1148  tgt2d_ptr(i, j) = src2d_ptr(i, j)
1149  end do
1150  end do
1151  else
1152  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
1154  bmi_status = bmi_failure
1155  return
1156  end if
1157 
1158  ! trigger event:
1159  call on_memory_set(var_name, mem_path, status)
1160  if (status /= 0) then
1161  ! something went terribly wrong here, aborting
1162  write (bmi_last_error, fmt_invalid_mem_access) trim(var_name)
1164  bmi_status = bmi_failure
1165  return
1166  end if
1167 
1168  end function set_value_int
1169 
1170  !> @brief Set new value for a logical scalar variable
1171  !!
1172  !! The array pointed to by @p c_arr_ptr must have a rank equal to 0.
1173  !<
1174  function set_value_bool(c_var_address, c_arr_ptr) result(bmi_status) &
1175  bind(C, name="set_value_bool")
1176  !DIR$ ATTRIBUTES DLLEXPORT :: set_value_bool
1177  ! -- modules
1179  ! -- dummy variables
1180  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1181  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the logical array
1182  integer(kind=c_int) :: bmi_status !< BMI status code
1183  ! -- local variables
1184  character(len=LENMEMPATH) :: mem_path
1185  character(len=LENVARNAME) :: var_name
1186  logical(LGP) :: valid
1187  integer(I4B) :: rank
1188  logical(LGP), pointer :: src_ptr, tgt_ptr
1189  integer(I4B) :: status
1190 
1191  bmi_status = bmi_success
1192 
1193  call split_address(c_var_address, mem_path, var_name, valid)
1194  if (.not. valid) then
1195  bmi_status = bmi_failure
1196  return
1197  end if
1198 
1199  rank = -1
1200  call get_mem_rank(var_name, mem_path, rank)
1201 
1202  ! convert pointer
1203  if (rank == 0) then
1204  call mem_setptr(tgt_ptr, var_name, mem_path)
1205  call c_f_pointer(c_arr_ptr, src_ptr)
1206  tgt_ptr = src_ptr
1207  else
1208  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
1210  bmi_status = bmi_failure
1211  return
1212  end if
1213 
1214  ! trigger event:
1215  call on_memory_set(var_name, mem_path, status)
1216  if (status /= 0) then
1217  ! something went terribly wrong here, aborting
1218  write (bmi_last_error, fmt_invalid_mem_access) trim(var_name)
1220  bmi_status = bmi_failure
1221  return
1222  end if
1223 
1224  end function set_value_bool
1225 
1226  !> @brief Copy the values of a variable at the given indices into the array
1227  !!
1228  !! The indices are zero-based positions in the variable's values in C-style
1229  !! (row-major) order, so a variable of rank > 1 is indexed as if flattened.
1230  !! The caller should provide @p c_arr_ptr pointing to an array of size
1231  !! @p count. Double precision and integer variables are supported.
1232  !<
1233  function get_value_at_indices(c_var_address, c_arr_ptr, c_inds, count) &
1234  result(bmi_status) bind(C, name="get_value_at_indices")
1235  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_at_indices
1236  ! -- modules
1237  use constantsmodule, only: lenmemtype
1238  ! -- dummy variables
1239  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1240  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the array to copy into
1241  integer(kind=c_int), intent(in) :: c_inds(*) !< zero-based indices of the values
1242  integer(kind=c_int), intent(in) :: count !< number of indices
1243  integer(kind=c_int) :: bmi_status !< BMI status code
1244  ! -- local variables
1245  character(len=LENMEMPATH) :: mem_path
1246  character(len=LENMEMTYPE) :: mem_type
1247  character(len=LENVARNAME) :: var_name
1248  logical(LGP) :: valid
1249  integer(I4B) :: i, nvalues
1250  type(c_ptr) :: var_ptr
1251  real(dp), dimension(:), pointer, contiguous :: src_dbl, tgt_dbl
1252  integer(I4B), dimension(:), pointer, contiguous :: src_int, tgt_int
1253 
1254  bmi_status = bmi_failure
1255 
1256  call split_address(c_var_address, mem_path, var_name, valid)
1257  if (.not. valid) return
1258  if (.not. valid_indices(mem_path, var_name, c_inds, count, nvalues)) return
1259 
1260  ! -- the variable's storage, viewed as a flat array in memory order
1261  call get_mem_type(var_name, mem_path, mem_type)
1262  if (index(mem_type, "DOUBLE") /= 0) then
1263  if (get_value_ptr_double(c_var_address, var_ptr) /= bmi_success) return
1264  call c_f_pointer(var_ptr, src_dbl, [nvalues])
1265  call c_f_pointer(c_arr_ptr, tgt_dbl, [count])
1266  do i = 1, count
1267  tgt_dbl(i) = src_dbl(c_inds(i) + 1)
1268  end do
1269  else if (index(mem_type, "INTEGER") /= 0) then
1270  if (get_value_ptr_int(c_var_address, var_ptr) /= bmi_success) return
1271  call c_f_pointer(var_ptr, src_int, [nvalues])
1272  call c_f_pointer(c_arr_ptr, tgt_int, [count])
1273  do i = 1, count
1274  tgt_int(i) = src_int(c_inds(i) + 1)
1275  end do
1276  else
1277  write (bmi_last_error, fmt_unsupported_type) trim(var_name)
1279  return
1280  end if
1281 
1282  bmi_status = bmi_success
1283 
1284  end function get_value_at_indices
1285 
1286  !> @brief Set the values of a variable at the given indices
1287  !!
1288  !! The indices are zero-based positions in the variable's values in C-style
1289  !! (row-major) order, as in get_value_at_indices(). The array pointed to by
1290  !! @p c_arr_ptr holds @p count values. Double precision and integer
1291  !! variables are supported. A new hydraulic conductivity does not change
1292  !! the saturated conductance until NPF recalculates it, as it does for TVK.
1293  !<
1294  function set_value_at_indices(c_var_address, c_inds, count, c_arr_ptr) &
1295  result(bmi_status) bind(C, name="set_value_at_indices")
1296  !DIR$ ATTRIBUTES DLLEXPORT :: set_value_at_indices
1297  ! -- modules
1298  use constantsmodule, only: lenmemtype
1300  ! -- dummy variables
1301  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1302  integer(kind=c_int), intent(in) :: c_inds(*) !< zero-based indices of the values
1303  integer(kind=c_int), intent(in) :: count !< number of indices
1304  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the array with the new values
1305  integer(kind=c_int) :: bmi_status !< BMI status code
1306  ! -- local variables
1307  character(len=LENMEMPATH) :: mem_path
1308  character(len=LENMEMTYPE) :: mem_type
1309  character(len=LENVARNAME) :: var_name
1310  logical(LGP) :: valid
1311  integer(I4B) :: i, nvalues, status
1312  type(c_ptr) :: var_ptr
1313  real(dp), dimension(:), pointer, contiguous :: src_dbl, tgt_dbl
1314  integer(I4B), dimension(:), pointer, contiguous :: src_int, tgt_int
1315 
1316  bmi_status = bmi_failure
1317 
1318  call split_address(c_var_address, mem_path, var_name, valid)
1319  if (.not. valid) return
1320  if (.not. valid_indices(mem_path, var_name, c_inds, count, nvalues)) return
1321 
1322  ! -- the variable's storage, viewed as a flat array in memory order
1323  call get_mem_type(var_name, mem_path, mem_type)
1324  if (index(mem_type, "DOUBLE") /= 0) then
1325  if (get_value_ptr_double(c_var_address, var_ptr) /= bmi_success) return
1326  call c_f_pointer(var_ptr, tgt_dbl, [nvalues])
1327  call c_f_pointer(c_arr_ptr, src_dbl, [count])
1328  do i = 1, count
1329  tgt_dbl(c_inds(i) + 1) = src_dbl(i)
1330  end do
1331  else if (index(mem_type, "INTEGER") /= 0) then
1332  if (get_value_ptr_int(c_var_address, var_ptr) /= bmi_success) return
1333  call c_f_pointer(var_ptr, tgt_int, [nvalues])
1334  call c_f_pointer(c_arr_ptr, src_int, [count])
1335  do i = 1, count
1336  tgt_int(c_inds(i) + 1) = src_int(i)
1337  end do
1338  else
1339  write (bmi_last_error, fmt_unsupported_type) trim(var_name)
1341  return
1342  end if
1343 
1344  ! trigger event:
1345  call on_memory_set(var_name, mem_path, status)
1346  if (status /= 0) then
1347  write (bmi_last_error, fmt_invalid_mem_access) trim(var_name)
1349  return
1350  end if
1351 
1352  bmi_status = bmi_success
1353 
1354  end function set_value_at_indices
1355 
1356  !> @brief Check that every index is within the variable, and count its values
1357  !<
1358  function valid_indices(mem_path, var_name, c_inds, count, nvalues) &
1359  result(valid)
1360  ! -- dummy variables
1361  character(len=*), intent(in) :: mem_path !< memory path of the variable
1362  character(len=*), intent(in) :: var_name !< name of the variable
1363  integer(kind=c_int), intent(in) :: c_inds(*) !< zero-based indices
1364  integer(kind=c_int), intent(in) :: count !< number of indices
1365  integer(I4B), intent(out) :: nvalues !< number of values in the variable
1366  logical(LGP) :: valid !< true when all indices are valid
1367  ! -- local variables
1368  integer(I4B) :: i, rank
1369 
1370  valid = .false.
1371  rank = -1
1372  call get_mem_rank(var_name, mem_path, rank)
1373  if (rank < 0 .or. rank > 3) then
1374  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
1376  return
1377  end if
1378 
1379  call get_isize(var_name, mem_path, nvalues)
1380  do i = 1, count
1381  if (c_inds(i) < 0 .or. c_inds(i) >= nvalues) then
1382  write (bmi_last_error, fmt_invalid_index) c_inds(i), trim(var_name)
1384  return
1385  end if
1386  end do
1387  valid = .true.
1388 
1389  end function valid_indices
1390 
1391  !> @brief Get the variable type as a string
1392  !!
1393  !! The type returned is that of a single element.
1394  !! When the variable cannot be found, the string
1395  !< 'UNKNOWN' is assigned.
1396  function get_var_type(c_var_address, c_var_type) result(bmi_status) &
1397  bind(C, name="get_var_type")
1398  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_type
1399  ! -- modules
1400  use constantsmodule, only: lenmemtype
1401  ! -- dummy variables
1402  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1403  character(kind=c_char), intent(out) :: c_var_type(bmi_lenvartype) !< variable type as a string
1404  integer(kind=c_int) :: bmi_status !< BMI status code
1405  ! -- local variables
1406  character(len=LENMEMPATH) :: mem_path
1407  character(len=LENVARNAME) :: var_name
1408  character(len=LENMEMTYPE) :: mem_type
1409  logical(LGP) :: valid
1410 
1411  bmi_status = bmi_success
1412 
1413  call split_address(c_var_address, mem_path, var_name, valid)
1414  if (.not. valid) then
1415  bmi_status = bmi_failure
1416  return
1417  end if
1418 
1419  call get_mem_type(var_name, mem_path, mem_type)
1420  c_var_type(1:len(trim(mem_type)) + 1) = &
1421  string_to_char_array(trim(mem_type), len(trim(mem_type)))
1422 
1423  if (mem_type == 'UNKNOWN') then
1424  write (bmi_last_error, fmt_general_err) 'unknown memory type'
1426  bmi_status = bmi_failure
1427  end if
1428 
1429  end function get_var_type
1430 
1431  !> @brief Get the units of a variable
1432  !!
1433  !! The memory manager does not store units, so 'unknown' is returned for
1434  !! every variable.
1435  !<
1436  function get_var_units(c_var_address, c_var_units) result(bmi_status) &
1437  bind(C, name="get_var_units")
1438  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_units
1439  ! -- dummy variables
1440  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1441  character(kind=c_char), intent(out) :: c_var_units(bmi_lenunits) !< variable units as a string
1442  integer(kind=c_int) :: bmi_status !< BMI status code
1443  ! -- local variables
1444  character(len=LENMEMPATH) :: mem_path
1445  character(len=LENVARNAME) :: var_name
1446  character(len=*), parameter :: var_units = 'unknown'
1447  logical(LGP) :: valid
1448 
1449  bmi_status = bmi_failure
1450 
1451  call split_address(c_var_address, mem_path, var_name, valid)
1452  if (.not. valid) return
1453 
1454  c_var_units(1:len(var_units) + 1) = &
1455  string_to_char_array(var_units, len(var_units))
1456  bmi_status = bmi_success
1457 
1458  end function get_var_units
1459 
1460  !> @brief Get the grid location of a variable
1461  !!
1462  !! Every variable is reported at the grid nodes.
1463  !<
1464  function get_var_location(c_var_address, c_var_location) result(bmi_status) &
1465  bind(C, name="get_var_location")
1466  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_location
1467  ! -- dummy variables
1468  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1469  character(kind=c_char), intent(out) :: c_var_location(bmi_lenvarlocation) !< variable location as a string
1470  integer(kind=c_int) :: bmi_status !< BMI status code
1471  ! -- local variables
1472  character(len=LENMEMPATH) :: mem_path
1473  character(len=LENVARNAME) :: var_name
1474  character(len=*), parameter :: var_location = 'node'
1475  logical(LGP) :: valid
1476 
1477  bmi_status = bmi_failure
1478 
1479  call split_address(c_var_address, mem_path, var_name, valid)
1480  if (.not. valid) return
1481 
1482  c_var_location(1:len(var_location) + 1) = &
1483  string_to_char_array(var_location, len(var_location))
1484  bmi_status = bmi_success
1485 
1486  end function get_var_location
1487 
1488  !> @brief Get the variable rank (non-BMI)
1489  !!
1490  !! In order to support multi-dimensional arrays, this function gives
1491  !! access to the rank of the array.
1492  !<
1493  function get_var_rank(c_var_address, c_var_rank) result(bmi_status) &
1494  bind(C, name="get_var_rank")
1495  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_rank
1496  ! -- dummy variables
1497  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1498  integer(kind=c_int), intent(out) :: c_var_rank !< variable rank
1499  integer(kind=c_int) :: bmi_status !< BMI status code
1500  ! -- local variables
1501  character(len=LENMEMPATH) :: mem_path
1502  character(len=LENVARNAME) :: var_name
1503  logical(LGP) :: valid
1504 
1505  bmi_status = bmi_success
1506 
1507  call split_address(c_var_address, mem_path, var_name, valid)
1508  if (.not. valid) then
1509  bmi_status = bmi_failure
1510  return
1511  end if
1512 
1513  call get_mem_rank(var_name, mem_path, c_var_rank)
1514  if (c_var_rank == -1) then
1515  bmi_status = bmi_failure
1516  return
1517  end if
1518 
1519  end function get_var_rank
1520 
1521  !> @brief Get the shape of the array for the variable (non-BMI)
1522  !!
1523  !! The shape is an integer array with size equal to the rank of
1524  !! the variable (see get_var_rank()) and values that give the
1525  !! length of the array in each dimension. The target shape array
1526  !! @p c_var_shape should be allocated before calling this routine.
1527  !!
1528  !! Note that the returned shape representation will has been converted
1529  !! to C-style.
1530  !<
1531  function get_var_shape(c_var_address, c_var_shape) result(bmi_status) &
1532  bind(C, name="get_var_shape")
1533  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_shape
1534  ! -- modules
1535  use constantsmodule, only: maxmemrank
1536  ! -- dummy variables
1537  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1538  integer(c_int), intent(inout) :: c_var_shape(*) !< 1D array with the variable's shape
1539  integer(kind=c_int) :: bmi_status !< BMI status code
1540  ! -- local variables
1541  integer(I4B), dimension(MAXMEMRANK) :: var_shape
1542  integer(I4B) :: var_rank
1543  character(len=LENMEMPATH) :: mem_path
1544  character(len=LENVARNAME) :: var_name
1545  logical(LGP) :: valid
1546 
1547  bmi_status = bmi_success
1548 
1549  call split_address(c_var_address, mem_path, var_name, valid)
1550  if (.not. valid) then
1551  bmi_status = bmi_failure
1552  return
1553  end if
1554 
1555  var_shape = 0
1556  var_rank = 0
1557  call get_mem_rank(var_name, mem_path, var_rank)
1558  call get_mem_shape(var_name, mem_path, var_shape)
1559  if (var_shape(1) == -1 .or. var_rank == -1) then
1560  bmi_status = bmi_failure
1561  return
1562  end if
1563 
1564  ! External calls to this BMI are assumed C style, so if the internal shape
1565  ! is (100,1) we get (100,1,undef) from the call get_mem_shape
1566  ! This we need to convert to C-style which should be (1,100).
1567  ! Hence, we reverse the array and drop undef:
1568  c_var_shape(1:var_rank) = var_shape(var_rank:1:-1)
1569 
1570  end function get_var_shape
1571 
1572 end module mf6bmi
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
integer(i4b), parameter, public maxmemrank
maximum memory manager length (up to 3-dimensional arrays)
Definition: Constants.f90:61
integer(i4b), parameter, public lenmemtype
maximum length of a memory manager type
Definition: Constants.f90:62
real(dp), parameter dprec
real constant machine precision
Definition: Constants.f90:120
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
integer(i4b) function, public getunit()
Get a free unit number.
This module defines variable data types.
Definition: kind.f90:8
character(len=lenmemaddress) function create_mem_address(mem_path, var_name)
returns the address string of the memory object
subroutine, public get_mem_type(name, mem_path, var_type)
@ brief Get the variable memory type
subroutine, public get_mem_shape(name, mem_path, mem_shape)
@ brief Get the variable memory shape
type(memorystoretype), public memorystore
subroutine, public get_isize(name, mem_path, isize)
@ brief Get the number of elements for this variable
subroutine, public get_mem_rank(name, mem_path, rank)
@ brief Get the variable rank
subroutine, public get_mem_elem_size(name, mem_path, size)
@ brief Get the memory size of a single element of the stored variable
subroutine, public on_memory_set(var_name, mem_path, status)
Triggers the calling of the side effect handler for this variable.
This module contains the MODFLOW 6 BMI.
Definition: mf6bmi.f90:18
integer(kind=c_int) function get_end_time(end_time)
Get the end time of the simulation.
Definition: mf6bmi.f90:194
integer(kind=c_int) function get_input_var_names(c_names)
Returns all input variables in the simulation.
Definition: mf6bmi.f90:330
integer(kind=c_int) function get_input_item_count(count)
Get the number of input variables in the simulation.
Definition: mf6bmi.f90:286
logical(lgp) function valid_indices(mem_path, var_name, c_inds, count, nvalues)
Check that every index is within the variable, and count its values.
Definition: mf6bmi.f90:1360
integer(kind=c_int) function get_value_ptr_double(c_var_address, c_arr_ptr)
Get a pointer to the array of double precision numbers.
Definition: mf6bmi.f90:835
integer(kind=c_int) function bmi_update_until(time)
Perform time steps until the current time reaches time.
Definition: mf6bmi.f90:116
integer(kind=c_int) function get_value_ptr_int(c_var_address, c_arr_ptr)
Get a pointer to the array of integer numbers.
Definition: mf6bmi.f90:889
integer(kind=c_int) function get_current_time(current_time)
Get the current time of the simulation.
Definition: mf6bmi.f90:213
integer(kind=c_int) function get_var_rank(c_var_address, c_var_rank)
Get the variable rank (non-BMI)
Definition: mf6bmi.f90:1495
integer(kind=c_int) function get_output_item_count(count)
Get the number of output variables in the simulation.
Definition: mf6bmi.f90:303
integer(kind=c_int) function get_value_ptr_bool(c_var_address, c_arr_ptr)
Get a pointer to the logical scalar value.
Definition: mf6bmi.f90:942
integer(kind=c_int) function set_value(c_var_address, c_arr_ptr)
Set new values for a given variable.
Definition: mf6bmi.f90:984
integer(kind=c_int) function get_time_step(time_step)
Get the time step for the simulation.
Definition: mf6bmi.f90:232
integer(kind=c_int) function get_var_nbytes(c_var_address, var_nbytes)
Get size of the variable, in bytes.
Definition: mf6bmi.f90:423
integer(kind=c_int) function set_value_double(c_var_address, c_arr_ptr)
Set new values for a variable of type double.
Definition: mf6bmi.f90:1030
integer(kind=c_int) function get_start_time(start_time)
Get the start time of the simulation.
Definition: mf6bmi.f90:178
integer(kind=c_int) function set_value_int(c_var_address, c_arr_ptr)
Set new values for a variable of type integer.
Definition: mf6bmi.f90:1103
integer(kind=c_int) function get_var_itemsize(c_var_address, var_size)
Get the size (in bytes) of a single element of a variable.
Definition: mf6bmi.f90:396
integer(kind=c_int) function get_time_units(c_time_units)
Get the time units of the simulation.
Definition: mf6bmi.f90:251
integer(kind=c_int) function bmi_get_component_name(name)
Definition: mf6bmi.f90:45
integer(kind=c_int) function bmi_update()
Perform a computational time step.
Definition: mf6bmi.f90:98
integer(kind=c_int) function get_value_ptr(c_var_address, c_arr_ptr)
Get a pointer to an array.
Definition: mf6bmi.f90:788
integer(kind=c_int) function get_var_shape(c_var_address, c_var_shape)
Get the shape of the array for the variable (non-BMI)
Definition: mf6bmi.f90:1533
integer(kind=c_int) function bmi_initialize()
Initialize the computational core.
Definition: mf6bmi.f90:69
integer(kind=c_int) function get_value_at_indices(c_var_address, c_arr_ptr, c_inds, count)
Copy the values of a variable at the given indices into the array.
Definition: mf6bmi.f90:1235
integer(kind=c_int) function set_value_at_indices(c_var_address, c_inds, count, c_arr_ptr)
Set the values of a variable at the given indices.
Definition: mf6bmi.f90:1296
integer(kind=c_int) function bmi_finalize()
Clean up the initialized simulation.
Definition: mf6bmi.f90:157
integer(kind=c_int) function get_value_int(c_var_address, c_arr_ptr)
Copy the integer values of a variable into the array.
Definition: mf6bmi.f90:537
integer(kind=c_int) function get_output_var_names(c_names)
Returns all output variables in the simulation.
Definition: mf6bmi.f90:365
integer(kind=c_int) function get_var_type(c_var_address, c_var_type)
Get the variable type as a string.
Definition: mf6bmi.f90:1398
integer(kind=c_int) function get_var_units(c_var_address, c_var_units)
Get the units of a variable.
Definition: mf6bmi.f90:1438
integer(kind=c_int) function get_value_double(c_var_address, c_arr_ptr)
Copy the double precision values of a variable into the array.
Definition: mf6bmi.f90:460
integer(kind=c_int) function set_value_bool(c_var_address, c_arr_ptr)
Set new value for a logical scalar variable.
Definition: mf6bmi.f90:1176
integer(kind=c_int) function get_value(c_var_address, c_arr_ptr)
Copy the value of a variable into the array.
Definition: mf6bmi.f90:739
integer(kind=c_int) function get_var_location(c_var_address, c_var_location)
Get the grid location of a variable.
Definition: mf6bmi.f90:1466
integer(kind=c_int) function get_value_string(c_var_address, c_arr_ptr)
Copy the string(s) of a variable into the array.
Definition: mf6bmi.f90:660
integer(kind=c_int) function get_value_bool(c_var_address, c_arr_ptr)
Copy the logical scalar value into the array.
Definition: mf6bmi.f90:612
integer(c_int), bind(C, name="ISTDOUTTOFILE") istdout_to_file
output control: =0 to screen, >0 to file
Definition: mf6bmi.f90:38
Detailed error information for the BMI.
Definition: mf6bmiError.f90:6
character(len= *), parameter fmt_general_err
Definition: mf6bmiError.f90:22
integer, parameter bmi_failure
BMI status code for failure (taken from bmi.f90, CSDMS)
Definition: mf6bmiError.f90:12
character(len= *), parameter fmt_unsupported_type
Definition: mf6bmiError.f90:31
character(len= *), parameter fmt_invalid_time
Definition: mf6bmiError.f90:40
character(len=lenerrmessage) bmi_last_error
module variable containing the last error as a Fortran string
Definition: mf6bmiError.f90:20
character(len= *), parameter fmt_invalid_index
Definition: mf6bmiError.f90:37
subroutine report_bmi_error(err_msg)
Sets the last BMI error message and copies it to an exported C-string.
Definition: mf6bmiError.f90:53
character(len= *), parameter fmt_invalid_mem_access
Definition: mf6bmiError.f90:34
character(len= *), parameter fmt_unsupported_rank
Definition: mf6bmiError.f90:28
integer, parameter bmi_success
BMI status code for success (taken from bmi.f90, CSDMS)
Definition: mf6bmiError.f90:13
This module contains helper routines and parameters for the MODFLOW 6 BMI.
Definition: mf6bmiUtil.f90:4
integer(c_int), bind(C, name="BMI_LENVARTYPE") bmi_lenvartype
max. length for variable type C-strings
Definition: mf6bmiUtil.f90:28
integer(c_int), bind(C, name="BMI_LENCOMPONENTNAME") bmi_lencomponentname
component name length, i.e. 'MODFLOW 6'
Definition: mf6bmiUtil.f90:48
subroutine split_address(c_var_address, mem_path, var_name, success)
Split the variable address string.
Definition: mf6bmiUtil.f90:64
pure character(kind=c_char, len=1) function, dimension(length+1) string_to_char_array(string, length)
Convert Fortran string to C-style character string.
Definition: mf6bmiUtil.f90:188
integer(c_int), bind(C, name="BMI_LENUNITS") bmi_lenunits
max. length for units C-strings
Definition: mf6bmiUtil.f90:36
integer(c_int), bind(C, name="BMI_LENVARLOCATION") bmi_lenvarlocation
max. length for variable location C-strings
Definition: mf6bmiUtil.f90:40
integer(c_int), bind(C, name="BMI_LENVARADDRESS") bmi_lenvaraddress
max. length for the variable's address C-string
Definition: mf6bmiUtil.f90:44
Core MODFLOW 6 module.
Definition: mf6core.f90:8
logical(lgp) function mf6update()
Run a time step.
Definition: mf6core.f90:120
subroutine mf6initialize()
Initialize a simulation.
Definition: mf6core.f90:71
subroutine mf6finalize()
Finalize the simulation.
Definition: mf6core.f90:146
This module contains simulation variables.
Definition: SimVariables.f90:9
integer(i4b) iforcestop
forced stop flag (1) forces a call to ustop(..) when the simulation has ended, (0) doesn't
character(len=linelength) simstdout
name of standard out file if screen output is piped to a file
integer(i4b) istdout
unit number for stdout
logical(lgp), pointer, public endofsimulation
flag indicating end of simulation
Definition: tdis.f90:31
integer(i4b), pointer, public itmuni
flag indicating time units
Definition: tdis.f90:25
real(dp), pointer, public totim
time relative to start of simulation
Definition: tdis.f90:35
real(dp), pointer, public totalsimtime
time at end of simulation
Definition: tdis.f90:40
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
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23
An iterator used to iterate through a MemoryContainer.