MODFLOW 6  version 6.8.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 Clean up the initialized simulation
110  !!
111  !! Performs teardown tasks for the initialized simulation, this
112  !! call should match the call to bmi_initialize()
113  !<
114  function bmi_finalize() result(bmi_status) bind(C, name="finalize")
115  !DIR$ ATTRIBUTES DLLEXPORT :: bmi_finalize
116  ! -- modules
117  use simvariablesmodule, only: iforcestop
118  ! -- dummy variables
119  integer(kind=c_int) :: bmi_status !< BMI status code
120 
121  ! we don't want a full stop() here, this disables it:
122  iforcestop = 0
123  call mf6finalize()
124 
125  bmi_status = bmi_success
126 
127  end function bmi_finalize
128 
129  !> @brief Get the start time of the simulation
130  !!
131  !! As MODFLOW currently does not have internal time, this will be
132  !! returning 0.0 for now. New version...
133  !<
134  function get_start_time(start_time) result(bmi_status) &
135  bind(C, name="get_start_time")
136  !DIR$ ATTRIBUTES DLLEXPORT :: get_start_time
137  ! -- dummy variables
138  real(kind=c_double), intent(out) :: start_time !< start time
139  integer(kind=c_int) :: bmi_status !< BMI status code
140 
141  start_time = 0.0_dp
142  bmi_status = bmi_success
143 
144  end function get_start_time
145 
146  !> @brief Get the end time of the simulation
147  !!
148  !! As MODFLOW does currently does not have internal time, this will be
149  !! equal to the total runtime.
150  !<
151  function get_end_time(end_time) result(bmi_status) bind(C, name="get_end_time")
152  !DIR$ ATTRIBUTES DLLEXPORT :: get_end_time
153  ! -- modules
154  use tdismodule, only: totalsimtime
155  ! -- dummy variables
156  real(kind=c_double), intent(out) :: end_time !< end time
157  integer(kind=c_int) :: bmi_status !< BMI status code
158 
159  end_time = totalsimtime
160  bmi_status = bmi_success
161 
162  end function get_end_time
163 
164  !> @brief Get the current time of the simulation
165  !!
166  !! As MODFLOW currently does not have internal time, this will be
167  !! equal to the time passed w.r.t. the start time of the simulation.
168  !<
169  function get_current_time(current_time) result(bmi_status) &
170  bind(C, name="get_current_time")
171  !DIR$ ATTRIBUTES DLLEXPORT :: get_current_time
172  ! -- modules
173  use tdismodule, only: totim
174  ! -- dummy variables
175  real(kind=c_double), intent(out) :: current_time !< current time
176  integer(kind=c_int) :: bmi_status !< BMI status code
177 
178  current_time = totim
179  bmi_status = bmi_success
180 
181  end function get_current_time
182 
183  !> @brief Get the time step for the simulation
184  !!
185  !! Note that the returned value may vary between and within stress periods,
186  !! depending on your time discretization settings in the TDIS package.
187  !<
188  function get_time_step(time_step) result(bmi_status) &
189  bind(C, name="get_time_step")
190  !DIR$ ATTRIBUTES DLLEXPORT :: get_time_step
191  ! -- modules
192  use tdismodule, only: delt
193  ! -- dummy variables
194  real(kind=c_double), intent(out) :: time_step !< current time step
195  integer(kind=c_int) :: bmi_status !< BMI status code
196 
197  time_step = delt
198  bmi_status = bmi_success
199 
200  end function get_time_step
201 
202  !> @brief Get the number of input variables in the simulation
203  !!
204  !! This concerns all variables stored in the memory manager
205  !<
206  function get_input_item_count(count) result(bmi_status) &
207  bind(C, name="get_input_item_count")
208  !DIR$ ATTRIBUTES DLLEXPORT :: get_input_item_count
209  ! -- dummy variables
210  integer(kind=c_int), intent(out) :: count !< the number of input variables
211  integer(kind=c_int) :: bmi_status !< BMI status code
212 
213  count = memorystore%count()
214 
215  bmi_status = bmi_success
216 
217  end function get_input_item_count
218 
219  !> @brief Get the number of output variables in the simulation
220  !!
221  !! This concerns all variables stored in the memory manager
222  !<
223  function get_output_item_count(count) result(bmi_status) &
224  bind(C, name="get_output_item_count")
225  !DIR$ ATTRIBUTES DLLEXPORT :: get_output_item_count
226  ! -- dummy variables
227  integer(kind=c_int), intent(out) :: count !< the number of output variables
228  integer(kind=c_int) :: bmi_status !< BMI status code
229 
230  count = memorystore%count()
231 
232  bmi_status = bmi_success
233 
234  end function get_output_item_count
235 
236  !> @brief Returns all input variables in the simulation
237  !!
238  !! This functions returns the full address for all variables in the
239  !! memory manager
240  !!
241  !! The array @p c_names should be pre-allocated of proper size:
242  !!
243  !! size = BMI_LENVARADDRESS * get_input_item_count()
244  !!
245  !! The strings will be written contiguously with stride equal to
246  !! BMI_LENVARADDRESS and nul-terminated where the trailing spaces start:
247  !!
248  !! c_names = 'variable_address_1\x00 ... variable_address_2\x00 ... ' etc.
249  !<
250  function get_input_var_names(c_names) result(bmi_status) &
251  bind(C, name="get_input_var_names")
252  !DIR$ ATTRIBUTES DLLEXPORT :: get_input_var_names
253  ! -- dummy variables
254  character(kind=c_char, len=1), intent(inout) :: c_names(*) !< array with memory paths for input variables
255  integer(kind=c_int) :: bmi_status !< BMI status code
256  ! -- local variables
257  integer(I4B) :: start, i
258  type(memorycontaineriteratortype), allocatable :: itr
259  type(memorytype), pointer :: mt => null()
260  character(len=LENMEMADDRESS) :: var_address
261 
262  start = 1
263  itr = memorystore%iterator()
264  do while (itr%has_next())
265  call itr%next()
266  mt => itr%value()
267  var_address = create_mem_address(mt%path, mt%name)
268  do i = 1, len(trim(var_address))
269  c_names(start + i - 1) = var_address(i:i)
270  end do
271  c_names(start + i) = c_null_char
272  start = start + bmi_lenvaraddress
273  end do
274 
275  bmi_status = bmi_success
276 
277  end function get_input_var_names
278 
279  !> @brief Returns all output variables in the simulation
280  !!
281  !! This function works analogously to get_input_var_names(),
282  !! and currently returns the same set of memory variables,
283  !! which is all of them!
284  !<
285  function get_output_var_names(c_names) result(bmi_status) &
286  bind(C, name="get_output_var_names")
287  !DIR$ ATTRIBUTES DLLEXPORT :: get_output_var_names
288  ! -- dummy variables
289  character(kind=c_char, len=1), intent(inout) :: c_names(*) !< array with memory paths for output variables
290  integer(kind=c_int) :: bmi_status !< BMI status code
291  ! -- local variables
292  integer(I4B) :: start, i
293  type(memorycontaineriteratortype), allocatable :: itr
294  type(memorytype), pointer :: mt => null()
295  character(len=LENMEMADDRESS) :: var_address
296 
297  start = 1
298  itr = memorystore%iterator()
299  do while (itr%has_next())
300  call itr%next()
301  mt => itr%value()
302  var_address = create_mem_address(mt%path, mt%name)
303  do i = 1, len(trim(var_address))
304  c_names(start + i - 1) = var_address(i:i)
305  end do
306  c_names(start + i) = c_null_char
307  start = start + bmi_lenvaraddress
308  end do
309 
310  bmi_status = bmi_success
311 
312  end function get_output_var_names
313 
314  !> @brief Get the size (in bytes) of a single element of a variable
315  !<
316  function get_var_itemsize(c_var_address, var_size) result(bmi_status) &
317  bind(C, name="get_var_itemsize")
318  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_itemsize
319  ! -- dummy variables
320  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
321  integer(kind=c_int), intent(out) :: var_size !< size of the element in bytes
322  integer(kind=c_int) :: bmi_status !< BMI status code
323  ! -- local variables
324  character(len=LENMEMPATH) :: mem_path
325  character(len=LENVARNAME) :: var_name
326  logical(LGP) :: valid
327 
328  bmi_status = bmi_success
329 
330  call split_address(c_var_address, mem_path, var_name, valid)
331  if (.not. valid) then
332  bmi_status = bmi_failure
333  return
334  end if
335 
336  call get_mem_elem_size(var_name, mem_path, var_size)
337  if (var_size == -1) bmi_status = bmi_failure
338 
339  end function get_var_itemsize
340 
341  !> @brief Get size of the variable, in bytes
342  !<
343  function get_var_nbytes(c_var_address, var_nbytes) result(bmi_status) &
344  bind(C, name="get_var_nbytes")
345  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_nbytes
346  ! -- dummy variables
347  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
348  integer(kind=c_int), intent(out) :: var_nbytes !< size in bytes
349  integer(kind=c_int) :: bmi_status !< BMI status code
350  ! -- local variables
351  integer(I4B) :: var_size, isize
352  character(len=LENMEMPATH) :: mem_path
353  character(len=LENVARNAME) :: var_name
354  logical(LGP) :: valid
355 
356  bmi_status = bmi_success
357 
358  call split_address(c_var_address, mem_path, var_name, valid)
359  if (.not. valid) then
360  bmi_status = bmi_failure
361  return
362  end if
363 
364  call get_mem_elem_size(var_name, mem_path, var_size)
365  if (var_size == -1) bmi_status = bmi_failure
366  call get_isize(var_name, mem_path, isize)
367  if (isize == -1) bmi_status = bmi_failure
368 
369  var_nbytes = var_size * isize
370 
371  end function get_var_nbytes
372 
373  !> @brief Copy the double precision values of a variable into the array
374  !!
375  !! The copied variable us located at @p c_var_address. The caller should
376  !! provide @p c_arr_ptr pointing to an array of the proper shape (the
377  !! BMI function get_var_shape() can be used to create it). Multi-dimensional
378  !! arrays are supported.
379  !<
380  function get_value_double(c_var_address, c_arr_ptr) result(bmi_status) &
381  bind(C, name="get_value_double")
382  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_double
383  ! -- modules
385  ! -- dummy variables
386  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
387  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the double precision array
388  integer(kind=c_int) :: bmi_status !< BMI status code
389  ! -- local variables
390  character(len=LENMEMPATH) :: mem_path
391  character(len=LENVARNAME) :: var_name
392  logical(LGP) :: valid
393  integer(I4B) :: rank
394  real(dp), pointer :: src_ptr, tgt_ptr
395  real(dp), dimension(:), pointer, contiguous :: src1d_ptr, tgt1d_ptr
396  real(dp), dimension(:, :), pointer, contiguous :: src2d_ptr, tgt2d_ptr
397  real(dp), dimension(:, :, :), pointer, contiguous :: src3d_ptr, tgt3d_ptr
398  integer(I4B) :: i, j, k
399 
400  bmi_status = bmi_success
401 
402  call split_address(c_var_address, mem_path, var_name, valid)
403  if (.not. valid) then
404  bmi_status = bmi_failure
405  return
406  end if
407 
408  ! convert pointer and copy data from memory manager into
409  ! the passed array, using loops to avoid stack overflow
410  rank = -1
411  call get_mem_rank(var_name, mem_path, rank)
412 
413  if (rank == 0) then
414  call mem_setptr(src_ptr, var_name, mem_path)
415  call c_f_pointer(c_arr_ptr, tgt_ptr)
416  tgt_ptr = src_ptr
417  else if (rank == 1) then
418  call mem_setptr(src1d_ptr, var_name, mem_path)
419  call c_f_pointer(c_arr_ptr, tgt1d_ptr, shape(src1d_ptr))
420  do i = 1, size(tgt1d_ptr)
421  tgt1d_ptr(i) = src1d_ptr(i)
422  end do
423  else if (rank == 2) then
424  call mem_setptr(src2d_ptr, var_name, mem_path)
425  call c_f_pointer(c_arr_ptr, tgt2d_ptr, shape(src2d_ptr))
426  do j = 1, size(tgt2d_ptr, 2)
427  do i = 1, size(tgt2d_ptr, 1)
428  tgt2d_ptr(i, j) = src2d_ptr(i, j)
429  end do
430  end do
431  else if (rank == 3) then
432  call mem_setptr(src3d_ptr, var_name, mem_path)
433  call c_f_pointer(c_arr_ptr, tgt3d_ptr, shape(src3d_ptr))
434  do k = 1, size(tgt3d_ptr, 3)
435  do j = 1, size(tgt3d_ptr, 2)
436  do i = 1, size(tgt3d_ptr, 1)
437  tgt3d_ptr(i, j, k) = src3d_ptr(i, j, k)
438  end do
439  end do
440  end do
441  else
442  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
444  bmi_status = bmi_failure
445  return
446  end if
447 
448  end function get_value_double
449 
450  !> @brief Copy the integer values of a variable into the array
451  !!
452  !! The copied variable is located at @p c_var_address. The caller should
453  !! provide @p c_arr_ptr pointing to an array of the proper shape (the
454  !! BMI function get_var_shape() can be used to create it). Multi-dimensional
455  !! arrays are supported.
456  !<
457  function get_value_int(c_var_address, c_arr_ptr) result(bmi_status) &
458  bind(C, name="get_value_int")
459  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_int
460  ! -- modules
462  ! -- dummy variables
463  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
464  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the integer array
465  integer(kind=c_int) :: bmi_status !< BMI status code
466  ! -- local variables
467  character(len=LENMEMPATH) :: mem_path
468  character(len=LENVARNAME) :: var_name
469  logical(LGP) :: valid
470  integer(I4B) :: rank
471  integer(I4B), pointer :: src_ptr, tgt_ptr
472  integer(I4B), dimension(:), pointer, contiguous :: src1d_ptr, tgt1d_ptr
473  integer(I4B), dimension(:, :), pointer, contiguous :: src2d_ptr, tgt2d_ptr
474  integer(I4B), dimension(:, :, :), pointer, contiguous :: src3d_ptr, tgt3d_ptr
475  integer(I4B) :: i, j, k
476 
477  bmi_status = bmi_success
478 
479  call split_address(c_var_address, mem_path, var_name, valid)
480  if (.not. valid) then
481  bmi_status = bmi_failure
482  return
483  end if
484 
485  ! convert pointer and copy data from memory manager into
486  ! the passed array, using loops to avoid stack overflow
487  rank = -1
488  call get_mem_rank(var_name, mem_path, rank)
489 
490  if (rank == 0) then
491  call mem_setptr(src_ptr, var_name, mem_path)
492  call c_f_pointer(c_arr_ptr, tgt_ptr)
493  tgt_ptr = src_ptr
494  else if (rank == 1) then
495  call mem_setptr(src1d_ptr, var_name, mem_path)
496  call c_f_pointer(c_arr_ptr, tgt1d_ptr, shape(src1d_ptr))
497  do i = 1, size(tgt1d_ptr)
498  tgt1d_ptr(i) = src1d_ptr(i)
499  end do
500  else if (rank == 2) then
501  call mem_setptr(src2d_ptr, var_name, mem_path)
502  call c_f_pointer(c_arr_ptr, tgt2d_ptr, shape(src2d_ptr))
503  do j = 1, size(tgt2d_ptr, 2)
504  do i = 1, size(tgt2d_ptr, 1)
505  tgt2d_ptr(i, j) = src2d_ptr(i, j)
506  end do
507  end do
508  else if (rank == 3) then
509  call mem_setptr(src3d_ptr, var_name, mem_path)
510  call c_f_pointer(c_arr_ptr, tgt3d_ptr, shape(src3d_ptr))
511  do k = 1, size(tgt3d_ptr, 3)
512  do j = 1, size(tgt3d_ptr, 2)
513  do i = 1, size(tgt3d_ptr, 1)
514  tgt3d_ptr(i, j, k) = src3d_ptr(i, j, k)
515  end do
516  end do
517  end do
518  else
519  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
521  bmi_status = bmi_failure
522  return
523  end if
524 
525  end function get_value_int
526 
527  !> @brief Copy the logical scalar value into the array
528  !!
529  !! The copied variable us located at @p c_var_address. The caller should
530  !! provide @p c_arr_ptr pointing to a scalar array with rank=0.
531  !<
532  function get_value_bool(c_var_address, c_arr_ptr) result(bmi_status) &
533  bind(C, name="get_value_bool")
534  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_bool
535  ! -- modules
537  ! -- dummy variables
538  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
539  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the logical array
540  integer(kind=c_int) :: bmi_status !< BMI status code
541  ! -- local variables
542  character(len=LENMEMPATH) :: mem_path
543  character(len=LENVARNAME) :: var_name
544  logical(LGP) :: valid
545  integer(I4B) :: rank
546  logical(LGP), pointer :: src_ptr, tgt_ptr
547 
548  bmi_status = bmi_success
549 
550  call split_address(c_var_address, mem_path, var_name, valid)
551  if (.not. valid) then
552  bmi_status = bmi_failure
553  return
554  end if
555 
556  rank = -1
557  call get_mem_rank(var_name, mem_path, rank)
558 
559  ! convert pointer
560  if (rank == 0) then
561  call mem_setptr(src_ptr, var_name, mem_path)
562  call c_f_pointer(c_arr_ptr, tgt_ptr)
563  tgt_ptr = src_ptr
564  else
565  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
567  bmi_status = bmi_failure
568  return
569  end if
570 
571  end function get_value_bool
572 
573  !> @brief Copy the string(s) of a variable into the array
574  !!
575  !! The copied variable is located at @p c_var_address. The caller should
576  !! provide @p c_arr_ptr pointing to an array of the proper shape (the
577  !! BMI function get_var_shape() can be used to create it). For strings
578  !! currently scalars and 1d arrays (of CharacterStringType) are
579  !< supported
580  function get_value_string(c_var_address, c_arr_ptr) result(bmi_status) &
581  bind(C, name="get_value_string")
582  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_string
583  ! -- modules
584  ! -- dummy variables
585  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
586  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the string array
587  integer(kind=c_int) :: bmi_status !< BMI status code
588  ! -- local variables
589  character(len=LENMEMPATH) :: mem_path
590  character(len=LENVARNAME) :: var_name
591  logical(LGP) :: valid
592  integer(I4B) :: rank
593  character(len=:), pointer :: srcstr
594  character(kind=c_char), pointer :: tgtstr(:)
595  type(characterstringtype), dimension(:), pointer, contiguous :: srccharstr1d
596  character(kind=c_char), pointer :: tgtstr1d(:, :)
597  character(:), allocatable :: tempstr
598  integer(I4B) :: i, ilen, isize
599 
600  bmi_status = bmi_success
601 
602  call split_address(c_var_address, mem_path, var_name, valid)
603  if (.not. valid) then
604  bmi_status = bmi_failure
605  return
606  end if
607 
608  ! single string, or array of strings (CharacterStringType)
609  rank = -1
610  call get_mem_rank(var_name, mem_path, rank)
611 
612  if (rank == 0) then
613  ! a string scalar
614  call mem_setptr(srcstr, var_name, mem_path)
615  call get_mem_elem_size(var_name, mem_path, ilen)
616  call c_f_pointer(c_arr_ptr, tgtstr, shape=[ilen + 1])
617 
618  tgtstr(1:len(srcstr) + 1) = string_to_char_array(srcstr, len(srcstr))
619 
620  else if (rank == 1) then
621  ! an array of strings
622  call mem_setptr(srccharstr1d, var_name, mem_path)
623  if (.not. associated(srccharstr1d)) then
624  write (bmi_last_error, fmt_general_err) 'string type not supported in API'
626  bmi_status = bmi_failure
627  return
628  end if
629 
630  ! create fortran pointer to C data array
631  call get_isize(var_name, mem_path, isize)
632  call get_mem_elem_size(var_name, mem_path, ilen)
633  call c_f_pointer(c_arr_ptr, tgtstr1d, shape=[ilen + 1, isize])
634 
635  ! allocate work array to handle CharacterStringType,
636  ! and copy the strings
637  allocate (character(ilen) :: tempstr)
638  do i = 1, isize
639  tempstr = srccharstr1d(i)
640  tgtstr1d(1:ilen + 1, i) = string_to_char_array(tempstr, ilen)
641  end do
642  deallocate (tempstr)
643  else
644  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
646  bmi_status = bmi_failure
647  return
648  end if
649 
650  end function get_value_string
651 
652  !> @brief Copy the value of a variable into the array
653  !!
654  !! The copied variable is located at @p c_var_address. The caller should
655  !! provide @p c_arr_ptr pointing to an array of the proper shape (the
656  !! BMI function get_var_shape() can be used to create it). Multi-dimensional
657  !! arrays are supported.
658  !<
659  function get_value(c_var_address, c_arr_ptr) result(bmi_status) &
660  bind(C, name="get_value")
661  !DIR$ ATTRIBUTES DLLEXPORT :: get_value
662  ! -- modules
663  use constantsmodule, only: lenmemtype
664  ! -- dummy variables
665  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
666  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
667  integer(kind=c_int) :: bmi_status !< BMI status code
668  ! -- local variables
669  character(len=LENMEMPATH) :: mem_path
670  character(len=LENMEMTYPE) :: mem_type
671  character(len=LENVARNAME) :: var_name
672  logical(LGP) :: valid
673 
674  bmi_status = bmi_success
675 
676  call split_address(c_var_address, mem_path, var_name, valid)
677  if (.not. valid) then
678  bmi_status = bmi_failure
679  return
680  end if
681 
682  call get_mem_type(var_name, mem_path, mem_type)
683 
684  if (index(mem_type, "DOUBLE") /= 0) then
685  bmi_status = get_value_double(c_var_address, c_arr_ptr)
686  else if (index(mem_type, "INTEGER") /= 0) then
687  bmi_status = get_value_int(c_var_address, c_arr_ptr)
688  else if (index(mem_type, "LOGICAL") /= 0) then
689  bmi_status = get_value_bool(c_var_address, c_arr_ptr)
690  else if (index(mem_type, "STRING") /= 0) then
691  bmi_status = get_value_string(c_var_address, c_arr_ptr)
692  else
693  write (bmi_last_error, fmt_unsupported_type) trim(var_name)
695  bmi_status = bmi_failure
696  return
697  end if
698 
699  end function get_value
700 
701  !> @brief Get a pointer to an array
702  !!
703  !! The array is located at @p c_var_address. There is no copying of data involved.
704  !! Multi-dimensional arrays are supported and the get_var_rank() function
705  !! can be used to get the variable's dimensionality, and get_var_shape() for
706  !! its shape.
707  !<
708  function get_value_ptr(c_var_address, c_arr_ptr) result(bmi_status) &
709  bind(C, name="get_value_ptr")
710  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr
711  ! -- modules
712  use constantsmodule, only: lenmemtype
713  ! -- dummy variables
714  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
715  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
716  integer(kind=c_int) :: bmi_status !< BMI status code
717  ! -- local variables
718  character(len=LENMEMPATH) :: mem_path
719  character(len=LENMEMTYPE) :: mem_type
720  character(len=LENVARNAME) :: var_name
721  logical(LGP) :: valid
722 
723  bmi_status = bmi_success
724 
725  call split_address(c_var_address, mem_path, var_name, valid)
726  if (.not. valid) then
727  bmi_status = bmi_failure
728  return
729  end if
730 
731  call get_mem_type(var_name, mem_path, mem_type)
732 
733  if (index(mem_type, "DOUBLE") /= 0) then
734  bmi_status = get_value_ptr_double(c_var_address, c_arr_ptr)
735  else if (index(mem_type, "INTEGER") /= 0) then
736  bmi_status = get_value_ptr_int(c_var_address, c_arr_ptr)
737  else if (index(mem_type, "LOGICAL") /= 0) then
738  bmi_status = get_value_ptr_bool(c_var_address, c_arr_ptr)
739  else
740  write (bmi_last_error, fmt_unsupported_type) trim(var_name)
742  bmi_status = bmi_failure
743  return
744  end if
745 
746  end function get_value_ptr
747 
748  !> @brief Get a pointer to the array of double precision numbers
749  !!
750  !! The array is located at @p c_var_address. There is no copying of data involved.
751  !! Multi-dimensional arrays are supported and the get_var_rank() function
752  !! can be used to get the variable's dimensionality, and get_var_shape() for
753  !! its shape.
754  !<
755  function get_value_ptr_double(c_var_address, c_arr_ptr) result(bmi_status) &
756  bind(C, name="get_value_ptr_double")
757  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr_double
758  ! -- dummy variables
759  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
760  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
761  integer(kind=c_int) :: bmi_status !< BMI status code
762  ! -- local variables
763  character(len=LENMEMPATH) :: mem_path
764  character(len=LENVARNAME) :: var_name
765  logical(LGP) :: valid
766  real(dp), pointer :: scalar_ptr
767  real(dp), dimension(:), pointer, contiguous :: array_ptr
768  real(dp), dimension(:, :), pointer, contiguous :: array2d_ptr
769  real(dp), dimension(:, :, :), pointer, contiguous :: array3d_ptr
770  integer(I4B) :: rank
771 
772  bmi_status = bmi_success
773 
774  call split_address(c_var_address, mem_path, var_name, valid)
775  if (.not. valid) then
776  bmi_status = bmi_failure
777  return
778  end if
779 
780  rank = -1
781  call get_mem_rank(var_name, mem_path, rank)
782  if (rank == 0) then
783  call mem_setptr(scalar_ptr, var_name, mem_path)
784  c_arr_ptr = c_loc(scalar_ptr)
785  else if (rank == 1) then
786  call mem_setptr(array_ptr, var_name, mem_path)
787  c_arr_ptr = c_loc(array_ptr)
788  else if (rank == 2) then
789  call mem_setptr(array2d_ptr, var_name, mem_path)
790  c_arr_ptr = c_loc(array2d_ptr)
791  else if (rank == 3) then
792  call mem_setptr(array3d_ptr, var_name, mem_path)
793  c_arr_ptr = c_loc(array3d_ptr)
794  else
795  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
797  bmi_status = bmi_failure
798  return
799  end if
800 
801  end function get_value_ptr_double
802 
803  !> @brief Get a pointer to the array of integer numbers
804  !!
805  !! The array is located at @p c_var_address. There is no copying of data involved.
806  !! Multi-dimensional arrays are supported and the get_var_rank() function
807  !! can be used to get the variable's dimensionality.
808  !<
809  function get_value_ptr_int(c_var_address, c_arr_ptr) result(bmi_status) &
810  bind(C, name="get_value_ptr_int")
811  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr_int
812  ! -- dummy variables
813  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
814  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
815  integer(kind=c_int) :: bmi_status !< BMI status code
816  ! -- local variables
817  character(len=LENMEMPATH) :: mem_path
818  character(len=LENVARNAME) :: var_name
819  logical(LGP) :: valid
820  integer(I4B) :: rank
821  integer(I4B), pointer :: scalar_ptr
822  integer(I4B), dimension(:), pointer, contiguous :: array_ptr
823  integer(I4B), dimension(:, :), pointer, contiguous :: array2d_ptr
824  integer(I4B), dimension(:, :, :), pointer, contiguous :: array3d_ptr
825 
826  bmi_status = bmi_success
827 
828  call split_address(c_var_address, mem_path, var_name, valid)
829  if (.not. valid) then
830  bmi_status = bmi_failure
831  return
832  end if
833 
834  rank = -1
835  call get_mem_rank(var_name, mem_path, rank)
836 
837  if (rank == 0) then
838  call mem_setptr(scalar_ptr, var_name, mem_path)
839  c_arr_ptr = c_loc(scalar_ptr)
840  else if (rank == 1) then
841  call mem_setptr(array_ptr, var_name, mem_path)
842  c_arr_ptr = c_loc(array_ptr)
843  else if (rank == 2) then
844  call mem_setptr(array2d_ptr, var_name, mem_path)
845  c_arr_ptr = c_loc(array2d_ptr)
846  else if (rank == 3) then
847  call mem_setptr(array3d_ptr, var_name, mem_path)
848  c_arr_ptr = c_loc(array3d_ptr)
849  else
850  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
852  bmi_status = bmi_failure
853  return
854  end if
855 
856  end function get_value_ptr_int
857 
858  !> @brief Get a pointer to the logical scalar value
859  !!
860  !! Only scalar values (with rank=0) are supported.
861  !<
862  function get_value_ptr_bool(c_var_address, c_arr_ptr) result(bmi_status) &
863  bind(C, name="get_value_ptr_bool")
864  !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr_bool
865  ! -- dummy variables
866  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
867  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
868  integer(kind=c_int) :: bmi_status !< BMI status code
869  ! -- local variables
870  character(len=LENMEMPATH) :: mem_path
871  character(len=LENVARNAME) :: var_name
872  logical(LGP) :: valid
873  logical(LGP), pointer :: scalar_ptr
874  integer(I4B) :: rank
875 
876  bmi_status = bmi_success
877 
878  call split_address(c_var_address, mem_path, var_name, valid)
879  if (.not. valid) then
880  bmi_status = bmi_failure
881  return
882  end if
883 
884  rank = -1
885  call get_mem_rank(var_name, mem_path, rank)
886  if (rank == 0) then
887  call mem_setptr(scalar_ptr, var_name, mem_path)
888  c_arr_ptr = c_loc(scalar_ptr)
889  else
890  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
892  bmi_status = bmi_failure
893  return
894  end if
895 
896  end function get_value_ptr_bool
897 
898  !> @brief Set new values for a given variable
899  !!
900  !! The array pointed to by @p c_arr_ptr can have rank equal to 0, 1, or 2
901  !! and should have a C-style layout, which is particularly important for
902  !! rank > 1.
903  !<
904  function set_value(c_var_address, c_arr_ptr) result(bmi_status) &
905  bind(C, name="set_value")
906  !DIR$ ATTRIBUTES DLLEXPORT :: set_value
907  ! -- modules
908  use constantsmodule, only: lenmemtype
909  ! -- dummy variables
910  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
911  type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array
912  integer(kind=c_int) :: bmi_status !< BMI status code
913  ! -- local variables
914  character(len=LENMEMPATH) :: mem_path
915  character(len=LENMEMTYPE) :: mem_type
916  character(len=LENVARNAME) :: var_name
917  logical(LGP) :: valid
918 
919  bmi_status = bmi_success
920 
921  call split_address(c_var_address, mem_path, var_name, valid)
922  if (.not. valid) then
923  bmi_status = bmi_failure
924  return
925  end if
926 
927  call get_mem_type(var_name, mem_path, mem_type)
928 
929  if (index(mem_type, "DOUBLE") /= 0) then
930  bmi_status = set_value_double(c_var_address, c_arr_ptr)
931  else if (index(mem_type, "INTEGER") /= 0) then
932  bmi_status = set_value_int(c_var_address, c_arr_ptr)
933  else if (index(mem_type, "LOGICAL") /= 0) then
934  bmi_status = set_value_bool(c_var_address, c_arr_ptr)
935  else
936  write (bmi_last_error, fmt_unsupported_type) trim(var_name)
938  bmi_status = bmi_failure
939  return
940  end if
941 
942  end function set_value
943 
944  !> @brief Set new values for a variable of type double
945  !!
946  !! The array pointed to by @p c_arr_ptr can have rank equal to 0, 1, or 2
947  !! and should have a C-style layout, which is particularly important for
948  !! rank > 1.
949  !<
950  function set_value_double(c_var_address, c_arr_ptr) result(bmi_status) &
951  bind(C, name="set_value_double")
952  !DIR$ ATTRIBUTES DLLEXPORT :: set_value_double
953  ! -- modules
955  ! -- dummy variables
956  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
957  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the double precision array
958  integer(kind=c_int) :: bmi_status !< BMI status code
959  ! -- local variables
960  character(len=LENMEMPATH) :: mem_path
961  character(len=LENVARNAME) :: var_name
962  logical(LGP) :: valid
963  integer(I4B) :: rank
964  real(dp), pointer :: src_ptr, tgt_ptr
965  real(dp), dimension(:), pointer, contiguous :: src1d_ptr, tgt1d_ptr
966  real(dp), dimension(:, :), pointer, contiguous :: src2d_ptr, tgt2d_ptr
967  integer(I4B) :: i, j
968  integer(I4B) :: status
969 
970  bmi_status = bmi_success
971 
972  call split_address(c_var_address, mem_path, var_name, valid)
973  if (.not. valid) then
974  bmi_status = bmi_failure
975  return
976  end if
977 
978  ! convert pointer and copy, using loops to avoid stack overflow
979  rank = -1
980  call get_mem_rank(var_name, mem_path, rank)
981 
982  if (rank == 0) then
983  call mem_setptr(tgt_ptr, var_name, mem_path)
984  call c_f_pointer(c_arr_ptr, src_ptr)
985  tgt_ptr = src_ptr
986  else if (rank == 1) then
987  call mem_setptr(tgt1d_ptr, var_name, mem_path)
988  call c_f_pointer(c_arr_ptr, src1d_ptr, shape(tgt1d_ptr))
989  do i = 1, size(tgt1d_ptr)
990  tgt1d_ptr(i) = src1d_ptr(i)
991  end do
992  else if (rank == 2) then
993  call mem_setptr(tgt2d_ptr, var_name, mem_path)
994  call c_f_pointer(c_arr_ptr, src2d_ptr, shape(tgt2d_ptr))
995  do j = 1, size(tgt2d_ptr, 2)
996  do i = 1, size(tgt2d_ptr, 1)
997  tgt2d_ptr(i, j) = src2d_ptr(i, j)
998  end do
999  end do
1000  else
1001  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
1003  bmi_status = bmi_failure
1004  return
1005  end if
1006 
1007  ! trigger event:
1008  call on_memory_set(var_name, mem_path, status)
1009  if (status /= 0) then
1010  ! something went terribly wrong here, aborting
1011  write (bmi_last_error, fmt_invalid_mem_access) trim(var_name)
1013  bmi_status = bmi_failure
1014  return
1015  end if
1016 
1017  end function set_value_double
1018 
1019  !> @brief Set new values for a variable of type integer
1020  !!
1021  !! The array pointed to by @p c_arr_ptr can have rank equal to 0, 1, or 2.
1022  !<
1023  function set_value_int(c_var_address, c_arr_ptr) result(bmi_status) &
1024  bind(C, name="set_value_int")
1025  !DIR$ ATTRIBUTES DLLEXPORT :: set_value_int
1026  ! -- modules
1028  ! -- dummy variables
1029  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1030  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the integer array
1031  integer(kind=c_int) :: bmi_status !< BMI status code
1032  ! -- local variables
1033  character(len=LENMEMPATH) :: mem_path
1034  character(len=LENVARNAME) :: var_name
1035  logical(LGP) :: valid
1036  integer(I4B) :: rank
1037  integer(I4B), pointer :: src_ptr, tgt_ptr
1038  integer(I4B), dimension(:), pointer, contiguous :: src1d_ptr, tgt1d_ptr
1039  integer(I4B), dimension(:, :), pointer, contiguous :: src2d_ptr, tgt2d_ptr
1040  integer(I4B) :: i, j
1041  integer(I4B) :: status
1042 
1043  bmi_status = bmi_success
1044 
1045  call split_address(c_var_address, mem_path, var_name, valid)
1046  if (.not. valid) then
1047  bmi_status = bmi_failure
1048  return
1049  end if
1050 
1051  ! convert pointer and copy, using loops to avoid stack overflow
1052  rank = -1
1053  call get_mem_rank(var_name, mem_path, rank)
1054 
1055  if (rank == 0) then
1056  call mem_setptr(tgt_ptr, var_name, mem_path)
1057  call c_f_pointer(c_arr_ptr, src_ptr)
1058  tgt_ptr = src_ptr
1059  else if (rank == 1) then
1060  call mem_setptr(tgt1d_ptr, var_name, mem_path)
1061  call c_f_pointer(c_arr_ptr, src1d_ptr, shape(tgt1d_ptr))
1062  do i = 1, size(tgt1d_ptr)
1063  tgt1d_ptr(i) = src1d_ptr(i)
1064  end do
1065  else if (rank == 2) then
1066  call mem_setptr(tgt2d_ptr, var_name, mem_path)
1067  call c_f_pointer(c_arr_ptr, src2d_ptr, shape(tgt2d_ptr))
1068  do j = 1, size(tgt2d_ptr, 2)
1069  do i = 1, size(tgt2d_ptr, 1)
1070  tgt2d_ptr(i, j) = src2d_ptr(i, j)
1071  end do
1072  end do
1073  else
1074  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
1076  bmi_status = bmi_failure
1077  return
1078  end if
1079 
1080  ! trigger event:
1081  call on_memory_set(var_name, mem_path, status)
1082  if (status /= 0) then
1083  ! something went terribly wrong here, aborting
1084  write (bmi_last_error, fmt_invalid_mem_access) trim(var_name)
1086  bmi_status = bmi_failure
1087  return
1088  end if
1089 
1090  end function set_value_int
1091 
1092  !> @brief Set new value for a logical scalar variable
1093  !!
1094  !! The array pointed to by @p c_arr_ptr must have a rank equal to 0.
1095  !<
1096  function set_value_bool(c_var_address, c_arr_ptr) result(bmi_status) &
1097  bind(C, name="set_value_bool")
1098  !DIR$ ATTRIBUTES DLLEXPORT :: set_value_bool
1099  ! -- modules
1101  ! -- dummy variables
1102  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1103  type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the logical array
1104  integer(kind=c_int) :: bmi_status !< BMI status code
1105  ! -- local variables
1106  character(len=LENMEMPATH) :: mem_path
1107  character(len=LENVARNAME) :: var_name
1108  logical(LGP) :: valid
1109  integer(I4B) :: rank
1110  logical(LGP), pointer :: src_ptr, tgt_ptr
1111  integer(I4B) :: status
1112 
1113  bmi_status = bmi_success
1114 
1115  call split_address(c_var_address, mem_path, var_name, valid)
1116  if (.not. valid) then
1117  bmi_status = bmi_failure
1118  return
1119  end if
1120 
1121  rank = -1
1122  call get_mem_rank(var_name, mem_path, rank)
1123 
1124  ! convert pointer
1125  if (rank == 0) then
1126  call mem_setptr(tgt_ptr, var_name, mem_path)
1127  call c_f_pointer(c_arr_ptr, src_ptr)
1128  tgt_ptr = src_ptr
1129  else
1130  write (bmi_last_error, fmt_unsupported_rank) trim(var_name)
1132  bmi_status = bmi_failure
1133  return
1134  end if
1135 
1136  ! trigger event:
1137  call on_memory_set(var_name, mem_path, status)
1138  if (status /= 0) then
1139  ! something went terribly wrong here, aborting
1140  write (bmi_last_error, fmt_invalid_mem_access) trim(var_name)
1142  bmi_status = bmi_failure
1143  return
1144  end if
1145 
1146  end function set_value_bool
1147 
1148  !> @brief Get the variable type as a string
1149  !!
1150  !! The type returned is that of a single element.
1151  !! When the variable cannot be found, the string
1152  !< 'UNKNOWN' is assigned.
1153  function get_var_type(c_var_address, c_var_type) result(bmi_status) &
1154  bind(C, name="get_var_type")
1155  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_type
1156  ! -- modules
1157  use constantsmodule, only: lenmemtype
1158  ! -- dummy variables
1159  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1160  character(kind=c_char), intent(out) :: c_var_type(bmi_lenvartype) !< variable type as a string
1161  integer(kind=c_int) :: bmi_status !< BMI status code
1162  ! -- local variables
1163  character(len=LENMEMPATH) :: mem_path
1164  character(len=LENVARNAME) :: var_name
1165  character(len=LENMEMTYPE) :: mem_type
1166  logical(LGP) :: valid
1167 
1168  bmi_status = bmi_success
1169 
1170  call split_address(c_var_address, mem_path, var_name, valid)
1171  if (.not. valid) then
1172  bmi_status = bmi_failure
1173  return
1174  end if
1175 
1176  call get_mem_type(var_name, mem_path, mem_type)
1177  c_var_type(1:len(trim(mem_type)) + 1) = &
1178  string_to_char_array(trim(mem_type), len(trim(mem_type)))
1179 
1180  if (mem_type == 'UNKNOWN') then
1181  write (bmi_last_error, fmt_general_err) 'unknown memory type'
1183  bmi_status = bmi_failure
1184  end if
1185 
1186  end function get_var_type
1187 
1188  !> @brief Get the variable rank (non-BMI)
1189  !!
1190  !! In order to support multi-dimensional arrays, this function gives
1191  !! access to the rank of the array.
1192  !<
1193  function get_var_rank(c_var_address, c_var_rank) result(bmi_status) &
1194  bind(C, name="get_var_rank")
1195  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_rank
1196  ! -- dummy variables
1197  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1198  integer(kind=c_int), intent(out) :: c_var_rank !< variable rank
1199  integer(kind=c_int) :: bmi_status !< BMI status code
1200  ! -- local variables
1201  character(len=LENMEMPATH) :: mem_path
1202  character(len=LENVARNAME) :: var_name
1203  logical(LGP) :: valid
1204 
1205  bmi_status = bmi_success
1206 
1207  call split_address(c_var_address, mem_path, var_name, valid)
1208  if (.not. valid) then
1209  bmi_status = bmi_failure
1210  return
1211  end if
1212 
1213  call get_mem_rank(var_name, mem_path, c_var_rank)
1214  if (c_var_rank == -1) then
1215  bmi_status = bmi_failure
1216  return
1217  end if
1218 
1219  end function get_var_rank
1220 
1221  !> @brief Get the shape of the array for the variable (non-BMI)
1222  !!
1223  !! The shape is an integer array with size equal to the rank of
1224  !! the variable (see get_var_rank()) and values that give the
1225  !! length of the array in each dimension. The target shape array
1226  !! @p c_var_shape should be allocated before calling this routine.
1227  !!
1228  !! Note that the returned shape representation will has been converted
1229  !! to C-style.
1230  !<
1231  function get_var_shape(c_var_address, c_var_shape) result(bmi_status) &
1232  bind(C, name="get_var_shape")
1233  !DIR$ ATTRIBUTES DLLEXPORT :: get_var_shape
1234  ! -- modules
1235  use constantsmodule, only: maxmemrank
1236  ! -- dummy variables
1237  character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable
1238  integer(c_int), intent(inout) :: c_var_shape(*) !< 1D array with the variable's shape
1239  integer(kind=c_int) :: bmi_status !< BMI status code
1240  ! -- local variables
1241  integer(I4B), dimension(MAXMEMRANK) :: var_shape
1242  integer(I4B) :: var_rank
1243  character(len=LENMEMPATH) :: mem_path
1244  character(len=LENVARNAME) :: var_name
1245  logical(LGP) :: valid
1246 
1247  bmi_status = bmi_success
1248 
1249  call split_address(c_var_address, mem_path, var_name, valid)
1250  if (.not. valid) then
1251  bmi_status = bmi_failure
1252  return
1253  end if
1254 
1255  var_shape = 0
1256  var_rank = 0
1257  call get_mem_rank(var_name, mem_path, var_rank)
1258  call get_mem_shape(var_name, mem_path, var_shape)
1259  if (var_shape(1) == -1 .or. var_rank == -1) then
1260  bmi_status = bmi_failure
1261  return
1262  end if
1263 
1264  ! External calls to this BMI are assumed C style, so if the internal shape
1265  ! is (100,1) we get (100,1,undef) from the call get_mem_shape
1266  ! This we need to convert to C-style which should be (1,100).
1267  ! Hence, we reverse the array and drop undef:
1268  c_var_shape(1:var_rank) = var_shape(var_rank:1:-1)
1269 
1270  end function get_var_shape
1271 
1272 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
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
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:152
integer(kind=c_int) function get_input_var_names(c_names)
Returns all input variables in the simulation.
Definition: mf6bmi.f90:252
integer(kind=c_int) function get_input_item_count(count)
Get the number of input variables in the simulation.
Definition: mf6bmi.f90:208
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:757
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:811
integer(kind=c_int) function get_current_time(current_time)
Get the current time of the simulation.
Definition: mf6bmi.f90:171
integer(kind=c_int) function get_var_rank(c_var_address, c_var_rank)
Get the variable rank (non-BMI)
Definition: mf6bmi.f90:1195
integer(kind=c_int) function get_output_item_count(count)
Get the number of output variables in the simulation.
Definition: mf6bmi.f90:225
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:864
integer(kind=c_int) function set_value(c_var_address, c_arr_ptr)
Set new values for a given variable.
Definition: mf6bmi.f90:906
integer(kind=c_int) function get_time_step(time_step)
Get the time step for the simulation.
Definition: mf6bmi.f90:190
integer(kind=c_int) function get_var_nbytes(c_var_address, var_nbytes)
Get size of the variable, in bytes.
Definition: mf6bmi.f90:345
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:952
integer(kind=c_int) function get_start_time(start_time)
Get the start time of the simulation.
Definition: mf6bmi.f90:136
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:1025
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:318
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:710
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:1233
integer(kind=c_int) function bmi_initialize()
Initialize the computational core.
Definition: mf6bmi.f90:69
integer(kind=c_int) function bmi_finalize()
Clean up the initialized simulation.
Definition: mf6bmi.f90:115
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:459
integer(kind=c_int) function get_output_var_names(c_names)
Returns all output variables in the simulation.
Definition: mf6bmi.f90:287
integer(kind=c_int) function get_var_type(c_var_address, c_var_type)
Get the variable type as a string.
Definition: mf6bmi.f90:1155
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:382
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:1098
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:661
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:582
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:534
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=lenerrmessage) bmi_last_error
module variable containing the last error as a Fortran string
Definition: mf6bmiError.f90:20
subroutine report_bmi_error(err_msg)
Sets the last BMI error message and copies it to an exported C-string.
Definition: mf6bmiError.f90:47
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:26
integer(c_int), bind(C, name="BMI_LENCOMPONENTNAME") bmi_lencomponentname
component name length, i.e. 'MODFLOW 6'
Definition: mf6bmiUtil.f90:38
subroutine split_address(c_var_address, mem_path, var_name, success)
Split the variable address string.
Definition: mf6bmiUtil.f90:54
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:149
integer(c_int), bind(C, name="BMI_LENVARADDRESS") bmi_lenvaraddress
max. length for the variable's address C-string
Definition: mf6bmiUtil.f90:34
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
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.