Program Listing for File mf6bmiGrid.f90¶
↰ Return to documentation for file (srcbmi/mf6bmiGrid.f90)
module mf6bmigrid
use bmif, only: bmi_success, bmi_failure
use mf6bmiutil
use iso_c_binding, only: c_double, c_ptr, c_loc
use constantsmodule, only: lenmodelname, lenmempath
use kindmodule, only: dp, i4b
use memorymanagermodule, only: mem_setptr
use memoryhelpermodule, only: create_mem_path
implicit none
contains
! Get the grid identifier for the given variable.
function get_var_grid(c_var_address, var_grid) result(bmi_status) bind(C, name="get_var_grid")
!DEC$ ATTRIBUTES DLLEXPORT :: get_var_grid
use listsmodule, only: basemodellist
use basemodelmodule, only: basemodeltype, getbasemodelfromlist
character (kind=c_char), intent(in) :: c_var_address(*)
integer(kind=c_int), intent(out) :: var_grid
integer(kind=c_int) :: bmi_status
! local
character(len=LENMODELNAME) :: model_name
character(len=LENMEMPATH) :: var_address
integer(I4B) :: i
class(basemodeltype), pointer :: basemodel
bmi_status = bmi_failure
var_address = char_array_to_string(c_var_address, strlen(c_var_address))
model_name = extract_model_name(var_address)
var_grid = 0
do i = 1,basemodellist%Count()
basemodel => getbasemodelfromlist(basemodellist, i)
if (basemodel%name == model_name) then
var_grid = basemodel%id
bmi_status = bmi_success
return
end if
end do
end function get_var_grid
! Get the grid type as a string.
function get_grid_type(grid_id, grid_type) result(bmi_status) bind(C, name="get_grid_type")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_type
integer(kind=c_int), intent(in) :: grid_id
character(kind=c_char), intent(out) :: grid_type(bmi_lengridtype)
integer(kind=c_int) :: bmi_status
! local
character(len=LENGRIDTYPE) :: grid_type_f
character(len=LENMODELNAME) :: model_name
bmi_status = bmi_failure
model_name = get_model_name(grid_id)
if (model_name == '') return
call get_grid_type_model(model_name, grid_type_f)
if (grid_type_f == "DIS") then
grid_type_f = "rectilinear"
else if ((grid_type_f == "DISV") .or. (grid_type_f == "DISU")) then
grid_type_f = "unstructured"
else
return
end if
grid_type = string_to_char_array(trim(grid_type_f), len_trim(grid_type_f))
bmi_status = bmi_success
end function get_grid_type
! Get number of dimensions of the computational grid.
function get_grid_rank(grid_id, grid_rank) result(bmi_status) bind(C, name="get_grid_rank")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_rank
integer(kind=c_int), intent(in) :: grid_id
integer(kind=c_int), intent(out) :: grid_rank
integer(kind=c_int) :: bmi_status
! local
character(len=LENMODELNAME) :: model_name
integer(I4B), dimension(:), pointer, contiguous :: grid_shape
bmi_status = bmi_failure
! TODO: It is currently only implemented for DIS grids
if (.not. confirm_grid_type(grid_id, "DIS")) return
! get shape array
model_name = get_model_name(grid_id)
call mem_setptr(grid_shape, "MSHAPE", create_mem_path(model_name, 'DIS'))
if (grid_shape(1) == 1) then
grid_rank = 2
else
grid_rank = 3
end if
bmi_status = bmi_success
end function get_grid_rank
! Get the total number of elements in the computational grid.
function get_grid_size(grid_id, grid_size) result(bmi_status) bind(C, name="get_grid_size")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_size
integer(kind=c_int), intent(in) :: grid_id
integer(kind=c_int), intent(out) :: grid_size
integer(kind=c_int) :: bmi_status
! local
character(len=LENMODELNAME) :: model_name
integer(I4B), dimension(:), pointer, contiguous :: grid_shape
character(kind=c_char) :: grid_type(bmi_lengridtype)
character(len=LENGRIDTYPE) :: grid_type_f
integer(I4B) :: status
bmi_status = bmi_failure
if (get_grid_type(grid_id, grid_type) /= bmi_success) return
grid_type_f = char_array_to_string(grid_type, strlen(grid_type))
model_name = get_model_name(grid_id)
if (grid_type_f == "rectilinear") then
call mem_setptr(grid_shape, "MSHAPE", create_mem_path(model_name, 'DIS'))
grid_size = grid_shape(1) * grid_shape(2) * grid_shape(3)
bmi_status = bmi_success
return
else if (grid_type_f == "unstructured") then
status = get_grid_node_count(grid_id, grid_size)
bmi_status = bmi_success
return
end if
end function get_grid_size
! Get the dimensions of the computational grid.
function get_grid_shape(grid_id, grid_shape) result(bmi_status) bind(C, name="get_grid_shape")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_shape
integer(kind=c_int), intent(in) :: grid_id
integer(kind=c_int), intent(out) :: grid_shape(*)
integer(kind=c_int) :: bmi_status
! local
integer, dimension(:), pointer, contiguous :: grid_shape_ptr
character(len=LENMODELNAME) :: model_name
character(kind=c_char) :: grid_type(bmi_lengridtype)
bmi_status = bmi_failure
! make sure function is only used for implemented grid_types
if (get_grid_type(grid_id, grid_type) /= bmi_success) return
! get shape array
model_name = get_model_name(grid_id)
call mem_setptr(grid_shape_ptr, "MSHAPE", create_mem_path(model_name, 'DIS'))
if (grid_shape_ptr(1) == 1) then
grid_shape(1:2) = grid_shape_ptr(2:3) ! 2D
else
grid_shape(1:3) = grid_shape_ptr ! 3D
end if
bmi_status = bmi_success
end function get_grid_shape
! Provides an array (whose length is the number of rows) that gives the x-coordinate for each row.
function get_grid_x(grid_id, grid_x) result(bmi_status) bind(C, name="get_grid_x")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_x
integer(kind=c_int), intent(in) :: grid_id
real(kind=c_double), intent(out) :: grid_x(*)
integer(kind=c_int) :: bmi_status
! local
integer(I4B) :: i
integer, dimension(:), pointer, contiguous :: grid_shape_ptr
character(len=LENMODELNAME) :: model_name
character(kind=c_char) :: grid_type(bmi_lengridtype)
real(DP), dimension(:,:), pointer, contiguous :: vertices_ptr
character(len=LENGRIDTYPE) :: grid_type_f
integer(I4B) :: x_size
bmi_status = bmi_failure
! make sure function is only used for implemented grid_types
if (get_grid_type(grid_id, grid_type) /= bmi_success) return
grid_type_f = char_array_to_string(grid_type, strlen(grid_type))
model_name = get_model_name(grid_id)
if (grid_type_f == "rectilinear") then
call mem_setptr(grid_shape_ptr, "MSHAPE", create_mem_path(model_name, 'DIS'))
! The dimension of x is in the last element of the shape array.
! + 1 because we count corners, not centers.
x_size = grid_shape_ptr(size(grid_shape_ptr)) + 1
grid_x(1:x_size) = [ (i, i=0,x_size-1) ]
else if (grid_type_f == "unstructured") then
call mem_setptr(vertices_ptr, "VERTICES", create_mem_path(model_name, 'DIS'))
! x-coordinates are in the 1st column
x_size = size(vertices_ptr(1, :))
grid_x(1:x_size) = vertices_ptr(1, :)
else
bmi_status = bmi_failure
return
end if
bmi_status = bmi_success
end function get_grid_x
! Provides an array (whose length is the number of rows) that gives the y-coordinate for each row.
function get_grid_y(grid_id, grid_y) result(bmi_status) bind(C, name="get_grid_y")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_y
integer(kind=c_int), intent(in) :: grid_id
real(kind=c_double), intent(out) :: grid_y(*)
integer(kind=c_int) :: bmi_status
! local
integer(I4B) :: i
integer, dimension(:), pointer, contiguous :: grid_shape_ptr
character(len=LENMODELNAME) :: model_name
character(kind=c_char) :: grid_type(bmi_lengridtype)
real(DP), dimension(:,:), pointer, contiguous :: vertices_ptr
character(len=LENGRIDTYPE) :: grid_type_f
integer(I4B) :: y_size
bmi_status = bmi_failure
if (get_grid_type(grid_id, grid_type) /= bmi_success) return
grid_type_f = char_array_to_string(grid_type, strlen(grid_type))
model_name = get_model_name(grid_id)
if (grid_type_f == "rectilinear") then
call mem_setptr(grid_shape_ptr, "MSHAPE", create_mem_path(model_name, 'DIS'))
! The dimension of y is in the second last element of the shape array.
! + 1 because we count corners, not centers.
y_size = grid_shape_ptr(size(grid_shape_ptr-1)) + 1
grid_y(1:y_size) = [ (i, i=y_size-1,0,-1) ]
else if (grid_type_f == "unstructured") then
call mem_setptr(vertices_ptr, "VERTICES", create_mem_path(model_name, 'DIS'))
! y-coordinates are in the 2nd column
y_size = size(vertices_ptr(2, :))
grid_y(1:y_size) = vertices_ptr(2, :)
else
bmi_status = bmi_failure
return
end if
bmi_status = bmi_success
end function get_grid_y
! NOTE: node in BMI-terms is a vertex in Modflow terms
! Get the number of nodes in an unstructured grid.
function get_grid_node_count(grid_id, count) result(bmi_status) bind(C, name="get_grid_node_count")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_node_count
integer(kind=c_int), intent(in) :: grid_id
integer(kind=c_int), intent(out) :: count
integer(kind=c_int) :: bmi_status
! local
character(len=LENMODELNAME) :: model_name
integer(I4B), pointer :: nvert_ptr
! make sure function is only used for DISU grids
bmi_status = bmi_failure
if (.not. confirm_grid_type(grid_id, "DISU")) return
model_name = get_model_name(grid_id)
call mem_setptr(nvert_ptr, "NVERT", create_mem_path(model_name, 'DIS'))
count = nvert_ptr
bmi_status = bmi_success
end function get_grid_node_count
! TODO_JH: This currently only works for 2D DISU models
! Get the number of faces in an unstructured grid.
function get_grid_face_count(grid_id, count) result(bmi_status) bind(C, name="get_grid_face_count")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_face_count
use listsmodule, only: basemodellist
use numericalmodelmodule, only: numericalmodeltype, getnumericalmodelfromlist
integer(kind=c_int), intent(in) :: grid_id
integer(kind=c_int), intent(out) :: count
integer(kind=c_int) :: bmi_status
! local
character(len=LENMODELNAME) :: model_name
integer(I4B) :: i
class(numericalmodeltype), pointer :: numericalmodel
! make sure function is only used for DISU grids
bmi_status = bmi_failure
if (.not. confirm_grid_type(grid_id, "DISU")) return
model_name = get_model_name(grid_id)
do i = 1,basemodellist%Count()
numericalmodel => getnumericalmodelfromlist(basemodellist, i)
if (numericalmodel%name == model_name) then
count = numericalmodel%dis%nodes
end if
end do
bmi_status = bmi_success
end function get_grid_face_count
! Get the face-node connectivity.
function get_grid_face_nodes(grid_id, face_nodes) result(bmi_status) bind(C, name="get_grid_face_nodes")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_face_nodes
integer(kind=c_int), intent(in) :: grid_id
integer(kind=c_int), intent(out) :: face_nodes(*)
integer(kind=c_int) :: bmi_status
! local
character(len=LENMODELNAME) :: model_name
integer, dimension(:), pointer, contiguous :: javert_ptr
integer, dimension(:), allocatable :: nodes_per_face
integer :: face_count
integer :: face_nodes_count
! make sure function is only used for DISU grids
bmi_status = bmi_failure
if (.not. confirm_grid_type(grid_id, "DISU")) return
model_name = get_model_name(grid_id)
call mem_setptr(javert_ptr, "JAVERT", create_mem_path(model_name, 'DIS'))
bmi_status = get_grid_face_count(grid_id, face_count)
if (bmi_status == bmi_failure) return
allocate(nodes_per_face(face_count))
bmi_status = get_grid_nodes_per_face(grid_id, nodes_per_face)
if (bmi_status == bmi_failure) return
face_nodes_count = sum(nodes_per_face + 1)
face_nodes(1:face_nodes_count) = javert_ptr(:)
bmi_status = bmi_success
end function get_grid_face_nodes
! Get the number of nodes for each face.
function get_grid_nodes_per_face(grid_id, nodes_per_face) result(bmi_status) bind(C, name="get_grid_nodes_per_face")
!DEC$ ATTRIBUTES DLLEXPORT :: get_grid_nodes_per_face
integer(kind=c_int), intent(in) :: grid_id
integer(kind=c_int), intent(out) :: nodes_per_face(*)
integer(kind=c_int) :: bmi_status
! local
integer(I4B) :: i
character(len=LENMODELNAME) :: model_name
integer, dimension(:), pointer, contiguous :: iavert_ptr
! make sure function is only used for DISU grids
bmi_status = bmi_failure
if (.not. confirm_grid_type(grid_id, "DISU")) return
model_name = get_model_name(grid_id)
call mem_setptr(iavert_ptr, "IAVERT", create_mem_path(model_name, 'DIS'))
do i = 1, size(iavert_ptr)-1
nodes_per_face(i) = iavert_ptr(i+1) - iavert_ptr(i) - 1
end do
bmi_status = bmi_success
end function get_grid_nodes_per_face
end module mf6bmigrid