-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update from Deltares #7
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all, thanks a lot for all the work in updating the sfincs BMI!
I've been trying to use the new functionality today, but I've run into some issues that I haven't been able to resolve yet. I've left some comments below to try and explain. It seems the main problem is that we need the grid sizes to pass destination arrays to the getters (otherwise I get segfaults). However, the get_grid_size
/get_var_size
function doesn't seem to return the expected shapes.
I might continue to try and fix things over the weekend. Any help (also on Monday still) would be appreciated.
#include "sfincs_bmi.hxx" | ||
|
||
// sfincs_bmi.f90 implements/exports the following bmi functions: | ||
extern "C" int initialize(char *c_config_file); | ||
extern "C" int update(double dt); // Doesn't seem to update current time | ||
extern "C" int initialize(const char *c_config_file); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to work well
extern "C" int get_component_name(char *name); | ||
|
||
extern "C" int update(); | ||
extern "C" int update_until(double t); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The BMI spec expects the target time, I think what's implemented now is the dt
, i.e. target time - current time. I suppose we can work around that.
extern "C" void set_var(const char *c_var_name, float *xptr); // should be set get_value? | ||
extern "C" void get_var_shape(const char *c_var_name, int *var_shape); // should be get_grid_shape | ||
// extern "C" void get_var_rank(char *c_var_name, int *rank); // should be get_grid_rank | ||
extern "C" int get_value(const char *c_var_name, void *x); // not exported; should be get_value? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't seem to work like before, or as expected. Calling with
grid_id = 0
grid_rank = model.get_grid_rank(grid_id)
shape = model.get_grid_shape(grid_id, np.empty(grid_rank, dtype=int))
model.get_value('zs', np.zeros(shape[0]))
# or
model.get_value('zs', np.zeros(shape[1]))
# or
model.get_value('zs', np.zeros(886*908))
gives segmentation fault.
What is the shape supposed to be?
model.get_grid_shape(grid_id, np.empty(grid_rank, dtype=int))
gives array([313509, 32614]
, that seems very big!! In sfincs.ini, I have
mmax = 886
nmax = 908
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conclusion: the second number is meaningless, first number is total points. It is less than nmax*mmax, I guess because some points in the grid are masked/boundaries/...
extern "C" int set_value(const char *c_var_name, float *xptr); // should be set get_value? | ||
extern "C" int set_value_at_indices(const char *name, int *inds, int count, void *src); | ||
|
||
extern "C" int get_var_shape(const char *c_var_name, int *var_shape); // should be get_grid_shape |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BMI doesn't specify get_var_shape
. Instead, it defines get_grid_shape
for a grid_id
that you can get through get_var_grid
. I tried to implement a workaround in add99b2
However, it seems that the get_var_shape
implementation in fortran is not returning what we expect. According to bmi spec (also see get_grid_rank) this should return an array of len 2 (in case of a rank 2 array). In the fortran code, it seems a len(1) array is used for var_shape
instead.
Note: we use get_grid_shape
to transform the 1d array that we get from get_value
back to a 2d array
Okay, after looking into this some more:
Next challenge: PS: also unstructured meshes can (and should) be rank 2 according to BMI spec. |
Debugging in fortran code now:
case("zs") ! water level
call c_f_pointer(ptr, f_ptr, [np])
do i = 1, np
f_ptr(i) = zs(i)
end do The segfaults happen as soon as Changing the code above to case("zs") ! water level
call c_f_pointer(ptr, f_ptr, [np])
f_ptr => zs solves the segfaults and I get data back through bmi, although the values seem unrealistic and not stable (i.e. calling multiple times gives different results).
|
Seems that that's similar to Wflow.jl then. They use an unstructured grid . The required (grid) BMI functions would then be:
And In the ewatercycle-wflowjl plugin I have already managed to get the ewatercycle helper functions to work with unstructured grids. |
Trying to get
grpc4bmi allocates it's own arrays as well via https://github.com/eWaterCycle/grpc4bmi/blob/main/grpc4bmi/reserve.py#L7-L13, so these need to be correct as well. |
after 2dc147a |
Set values seems to work as expected. Calling
|
Modified function get_value(var_name, dest, n) result(ierr) bind(C, name="get_value")
!DEC$ ATTRIBUTES DLLEXPORT :: get_value
integer(kind=c_int) :: ierr, n
character(kind=c_char), intent(in) :: var_name(*)
real(c_float), dimension(n) :: dest
character(len=strlen(var_name)) :: f_var_name
f_var_name = char_array_to_string(var_name, strlen(var_name))
ierr = ret_code%success
write(*,*)'get_value called with', f_var_name
select case(f_var_name)
case("z_xz") ! x grid cell centre
dest = z_xz
case("z_yz") ! y grid cell centre
dest = z_yz
case("zs") ! water level
dest = zs
case("zb") ! bed level
if(subgrid) then
dest = subgrid_z_zmin
else
dest = subgrid_z_zmin
end if
case("qsrc_1")
dest = qsrc(:, 1)
case("qsrc_2")
dest = qsrc(:,2)
case("xsrc")
write(*,*)'xsrc', xsrc
dest = xsrc
case("ysrc")
dest = ysrc
case("tsrc")
dest = tsrc
case("zst_bnd")
dest = zst_bnd
case default
write(*,*) 'get_value error'
ierr = ret_code%failure
end select
end function get_value makes it work for inspired by https://stackoverflow.com/a/34562060 |
patch in Deltares/SFINCS@2a4f2a5 |
No description provided.