Open zhucaoxiang opened 4 years ago
If Fortran 'owns' the array then the allocate()
call needs to be in Fortran - easiest way to achieve this is to wrap constructor/destructor routines.
However, it is possible to allocate a numpy array with Fortran memory ordering e.g. a = np.zeros((3, 2), order='F')
and pass this in as an intent in/out
argument which can be modified from Fortran. (For 1-D arrays order='C'
and order='F'
are equivalent so it doesn't matter).
Now that I read your code more carefully, it's interesting if this possible with native f2py
. Would be interesting to figure out where this goes wrong with f90wrap
.
@jameskermode Yes, I tested it and it is possible for f2py
. This comes from the documentation at the end of https://numpy.org/devdocs/f2py/python-usage.html.
As far as I remember f90wrap doesn't treat allocatable arrays specially, maybe that's the problem.
@jameskermode It is also possible for f2py-f90wrap
. The "problem" happens at generating the .fpp
file will treat b
array as a function.
@property
def b(self):
"""
Element b ftype=real pytype=float
Defined at library.fpp line 8
"""
array_ndim, array_type, array_shape, array_handle = \
_ExampleArray.f90wrap_library__array__b(f90wrap.runtime.empty_handle)
if array_handle in self._arrays:
b = self._arrays[array_handle]
else:
b = f90wrap.runtime.get_array(f90wrap.runtime.sizeof_fortran_t,
f90wrap.runtime.empty_handle,
_ExampleArray.f90wrap_library__array__b)
self._arrays[array_handle] = b
return b
@b.setter
def b(self, b):
self.b[...] = b
def __str__(self):
ret = ['<library>{\n']
ret.append(' b : ')
ret.append(repr(self.b))
ret.append('}')
return ''.join(ret)
_dt_array_initialisers = []
Aha. Would you be willing to remove the [...]
on the line self.b[...] = b
and see if this fixes the problem? You can edit the auto-generated code after running f90wrap.
@jameskermode By doing so, I got the following error.
In [4]: lib.library.b = [[1, 2, 3], [4, 5, 6]]
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
<ipython-input-4-3b18ccdd94cd> in <module>
----> 1 lib.library.b = [[1, 2, 3], [4, 5, 6]]
~/Documents/Code/TMP/f90wrap_test/ExampleArray.py in b(self, b)
98 @b.setter
99 def b(self, b):
--> 100 self.b = b
101
102 def __str__(self):
... last 1 frames repeated, from the frame below ...
~/Documents/Code/TMP/f90wrap_test/ExampleArray.py in b(self, b)
98 @b.setter
99 def b(self, b):
--> 100 self.b = b
101
102 def __str__(self):
RecursionError: maximum recursion depth exceeded
Ah, ok, yes, I see that. Maybe try removing the setter routine altogether.
Then it can not be set.
OK, this is a bit fiddly - I think I understand the problem at least, and I'll try to take a look myself, but won't manage it tonight. The raw array lives in self._arrays
dictionary, you may be able to experiment with assigning to that.
Thanks, I am not in a rush. When trying to access self._arrays
, I got ValueError: array is NULL
.
Yes, you need to get it via the property once first, then there will be a cached reference in self._arrays
. Assigning to this may well do what you want.
If that does work we could change the setter to do self._arrays[array_handle] = b
, but would need to look up the handle somehow.
Yes, you need to get it via the property once first, then there will be a cached reference in
self._arrays
. Assigning to this may well do what you want.
I tried to access the property. But on the first access, it is still going to call the get_array
method, which gives the error ValueError: array is NULL
. @jameskermode
@jameskermode Hi James, is there a way to allocate Fortran arrays from the Python side? With the native
f2py
, it is realized by direct assignment in Python. Somehow, this ability was lost when interfacing with the*.fpp
files. And I will get an error ofValueError: array is NULL
.Fortran 90 source code:
and wrap it using
f2py -c -m allocarr allocarr.f90
.In Python: