Earlier today I posted about passing struct from Python to Fortran Pass struct from Python to Fortran that was kindly solved by @PierU
Now I am trying to pass an array of structs (kind of related topic here: Passing an array of structs from C to Fortran)
I think I am doing it correctly, and sometimes it works. Other times doesn’t.
Python side:
import ctypes as ct
import numpy as np
libtest = ct.CDLL('./pass_struct_array.so')
pass_struct_array = libtest.pass_struct_array
class StructTest(ct.Structure):
_fields_ = [
("nonzeros", ct.POINTER(ct.c_int)),
("values", ct.POINTER(ct.c_double)),
("n_nonzeros", ct.c_int),
]
nnz = 400
def set_struct_term():
values = np.zeros((2,nnz), dtype=np.float_, order="F")
nonzeros = np.zeros((2,nnz), dtype=np.intc, order="F")
for i in range(nnz):
values[0,i] = i
values[1,i] = 2*i
nonzeros[0,i] = i
nonzeros[1,i] = 2*i
v_ptr = values.ctypes.data_as(ct.POINTER(ct.c_double))
nnz_ptr = nonzeros.ctypes.data_as(ct.POINTER(ct.c_int))
return StructTest(nnz_ptr,
v_ptr,
ct.c_int(nnz),
)
if __name__ == "__main__":
n_terms = 2
not_working_terms = (StructTest * n_terms)()
for i in range(2):
not_working_terms[i] = set_struct_term()
# Create a double array, pass it to Fotran as a pointer
values = 10*np.ones((2,nnz), dtype=np.float_, order="F")
values[0,0] = 1.
values[0,1] = 2.
values[0,2] = 3.
values[1,0] = 11.
values[1,1] = 12.
values[1,2] = 13.
values[0,:] = 13.3
values[1,:] = np.arange(1.,(nnz+10)/10.,0.1)
values_ptr = values.ctypes.data_as(ct.POINTER(ct.c_double))
nonzeros = np.ones((2,nnz), dtype=np.intc, order="F")
nonzeros[0,0] = 1
nonzeros[0,1] = 2
nonzeros[0,2] = 3
nonzeros_ptr = nonzeros.ctypes.data_as(ct.POINTER(ct.c_int))
values2 = 20*np.ones((2,nnz), dtype=np.float_, order="F")
values2[0,0] = 2.
values2[0,1] = 3.
values2[0,2] = 4.
values2[1,0] = 21.
values2[1,1] = 31.
values2[1,2] = 41.
values2_ptr = values2.ctypes.data_as(ct.POINTER(ct.c_double))
nonzeros2 = np.ones((2,nnz), dtype=np.intc, order="F")
nonzeros2[0,0] = 2
nonzeros2[0,1] = 3
nonzeros2[0,2] = 4
nonzeros2_ptr = nonzeros2.ctypes.data_as(ct.POINTER(ct.c_int))
working_terms = (StructTest * n_terms)()
working_terms[0] = StructTest(nonzeros_ptr, values_ptr, ct.c_int(nnz))
working_terms[1] = StructTest(nonzeros2_ptr, values2_ptr, ct.c_int(nnz))
pass_struct_array.argtypes = [
ct.POINTER(StructTest * n_terms), ct.c_int,
]
pass_struct_array(
ct.byref(not_working_terms), ct.c_int(n_terms),
)
Fortran:
subroutine pass_struct_array(struct_terms, n_terms) bind(C, name="pass_struct_array")
use iso_c_binding
implicit none
type, bind(c) :: struct_element
type(c_ptr) :: nonzeros
type(c_ptr) :: values
integer(c_int) :: n_nonzeros
end type struct_element
real(c_double), pointer :: struct_element_values_ptr(:, :)
integer(c_int), pointer :: struct_element_nonzeros_ptr(:,:)
type(struct_element), intent(in) :: struct_terms(n_terms)
integer(c_int), intent(in), value :: n_terms
integer :: i
do i = 1, n_terms
call c_f_pointer(struct_terms(i) % values, struct_element_values_ptr, [2, struct_terms(i) % n_nonzeros])
call c_f_pointer(struct_terms(i) % nonzeros, struct_element_nonzeros_ptr, [2, struct_terms(i) % n_nonzeros])
print "('values(1,:)',/,10(F5.2,x))", struct_element_values_ptr(1,:)
print "('values(2,:)',/,10(F5.2,x))", struct_element_values_ptr(2,:)
print "('nonzeros(1,:)',/,10(i0,x))", struct_element_nonzeros_ptr(1,:)
print "('nonzeros(2,:)',/,10(i0,x))", struct_element_nonzeros_ptr(2,:)
end do
end subroutine pass_struct_array
Compilation with gfortran -shared pass_struct_array.f90 -o pass_struct_array.so
.
There are two ways of passing the array of structs in the Python code. In some cases the array pass works and in some other cases it does not:
- using
not_working_terms
works ifnnz
is small (for example 30) - using
not_working_terms
does not work ifnnz
is large (for example 400) - using
working_terms
works even with largernnz
(for example 400)
Could you help me to figure out why the other way does not always work?
Edit. By not working I mean, I get garbage like this:
nonzeros(2,:)
1076533657 1072693248 1076533657 1072798105 1076533657 1072902963 1076533657 1073007820 1076533657 1073112678
1076533657 1073217536 1076533657 1073322393 1076533657 1073427251 1076533657 1073532108 1076533657 1073636966
1076533657 1073741824 1076533657 1073794252 1076533657 1073846681 1076533657 1073899110 1076533657 1073951539
1076533657 1074003968 1076533657 1074056396 1076533657 1074108825 1076533657 1074161254 1076533657 1074213683
1076533657 1074266112 1076533657 1074318540 1076533657 1074370969 1076533657 1074423398 1076533657 1074475827
1076533657 1074528256 1076533657 1074580684 1076533657 1074633113 1076533657 1074685542 1076533657 1074737971
1076533657 1074790400 1076533657 1074816614 1076533657 1074842828 1076533657 1074869043 1076533657 1074895257
1076533657 1074921472 1076533657 1074947686 1076533657 1074973900 1076533657 1075000115 1076533657 1075026329
1076533657 1075052544 1076533657 1075078758 1076533657 1075104972 1076533657 1075131187 1076533657 1075157401
1076533657 1075183616 1076533657 1075209830 1076533657 1075236044 1076533657 1075262259 1076533657 1075288473
1076533657 1075314688 1076533657 1075340902 1076533657 1075367116 1076533657 1075393331 1076533657 1075419545
1076533657 1075445760 1076533657 1075471974 1076533657 1075498188 1076533657 1075524403 1076533657 1075550617
1076533657 1075576832 1076533657 1075603046 1076533657 1075629260 1076533657 1075655475 1076533657 1075681689
1076533657 1075707904 1076533657 1075734118 1076533657 1075760332 1076533657 1075786547 1076533657 1075812761
1076533657 1075838976 1076533657 1075852083 1076533657 1075865190 1076533657 1075878297 1076533657 1075891404
1076533657 1075904512 1076533657 1075917619 1076533657 1075930726 1076533657 1075943833 1076533657 1075956940
1076533657 1075970048 1076533657 1075983155 1076533657 1075996262 1076533657 1076009369 1076533657 1076022476
1076533657 1076035584 1076533657 1076048691 1076533657 1076061798 1076533657 1076074905 1076533657 1076088012
1076533657 1076101120 1076533657 1076114227 1076533657 1076127334 1076533657 1076140441 1076533657 1076153548
1076533657 1076166656 1076533657 1076179763 1076533657 1076192870 1076533657 1076205977 1076533657 1076219084
1076533657 1076232192 1076533657 1076245299 1076533657 1076258406 1076533657 1076271513 1076533657 1076284620
1076533657 1076297728 1076533657 1076310835 1076533657 1076323942 1076533657 1076337049 1076533657 1076350156
1076533657 1076363264 1076533657 1076376371 1076533657 1076389478 1076533657 1076402585 1076533657 1076415692
1076533657 1076428800 1076533657 1076441907 1076533657 1076455014 1076533657 1076468121 1076533657 1076481228
1076533657 1076494336 1076533657 1076507443 1076533657 1076520550 1076533657 1076533657 1076533657 1076546764
1076533657 1076559872 1076533657 1076572979 1076533657 1076586086 1076533657 1076599193 1076533657 1076612300
1076533657 1076625408 1076533657 1076638515 1076533657 1076651622 1076533657 1076664729 1076533657 1076677836
1076533657 1076690944 1076533657 1076704051 1076533657 1076717158 1076533657 1076730265 1076533657 1076743372
1076533657 1076756480 1076533657 1076769587 1076533657 1076782694 1076533657 1076795801 1076533657 1076808908
1076533657 1076822016 1076533657 1076835123 1076533657 1076848230 1076533657 1076861337 1076533657 1076874444
1076533657 1076887552 1076533657 1076894105 1076533657 1076900659 1076533657 1076907212 1076533657 1076913766
1076533657 1076920320 1076533657 1076926873 1076533657 1076933427 1076533657 1076939980 1076533657 1076946534
1076533657 1076953088 1076533657 1076959641 1076533657 1076966195 1076533657 1076972748 1076533657 1076979302
1076533657 1076985856 1076533657 1076992409 1076533657 1076998963 1076533657 1077005516 1076533657 1077012070
1076533657 1077018624 1076533657 1077025177 1076533657 1077031731 1076533657 1077038284 1076533657 1077044838
1076533657 1077051392 1076533657 1077057945 1076533657 1077064499 1076533657 1077071052 1076533657 1077077606
1076533657 1077084160 1076533657 1077090713 1076533657 1077097267 1076533657 1077103820 1076533657 1077110374
1076533657 1077116928 1076533657 1077123481 1076533657 1077130035 1076533657 1077136588 1076533657 1077143142
1076533657 1077149696 1076533657 1077156249 1076533657 1077162803 1076533657 1077169356 1076533657 1077175910
1076533657 1077182464 1076533657 1077189017 1076533657 1077195571 1076533657 1077202124 1076533657 1077208678