У меня есть какой-то старый код Fortran, который я хочу обернуть с помощью f2py и который мне не разрешено изменять.
Ядром программы является некоторая подпрограмма, которая зависит от пользовательских подпрограмм. Все этих подпрограмм совместно используют массивы общих параметров для обмена предоставленными пользователем данными между подпрограммами.Эти массивы параметров являются одномерными и поэтому не ожидают какого-либо предварительно определенного размера ввода в основных заголовках подпрограмм.
Однако, похоже, что заголовкам функций обратного вызова python требуется точная информация о фактическом размеремассивы.
Давайте рассмотрим пример:
Это мой код Fortran:
Subroutine myscript(x,fun,o,n,rpar, ipar)
external fun
integer n
double precision x(n,*)
double precision o(n)
double precision rpar(*)
integer ipar(*)
write(*,*) n
!write(*,*) x(1,:)
call fun(n,x,o,rpar,ipar)
write(*,*) o
write(*,*) rpar(1)
end
А это моя часть Python:
import numpy as np
import routine
import ipdb
def fun(X, rpar):
print("In Callback function")
ipdb.set_trace()
print(X)
O = X[1,:]
print(O)
return O
O = np.array([1.,0.])
X = np.identity(2)
rpar = np.array([1.,1.])
routine.myscript(X, fun, rpar)
Я скомпилировал с f2py -c routine.pyf routine.f
и следующий заголовочный файл
! -*- f90 -*-
! Note: the context of this file is case sensitive.
python module myscript__user__routines
interface myscript_user_interface
subroutine fun(n,x,o,rpar,ipar) ! in :routine:routine.f:myscript:unknown_interface
integer, optional,intent(hide),check(shape(x,0)==n),depend(x) :: n=shape(x,0)
double precision dimension(n,n),intent(in) :: x
double precision dimension(n),intent(out),depend(n) :: o
double precision dimension(100),intent(in) :: rpar
integer, optional, dimension(*) :: ipar
end subroutine fun
end interface myscript_user_interface
end python module myscript__user__routines
python module routine ! in
interface ! in :routine
subroutine myscript(x,fun,o,n,rpar,ipar) ! in :routine:routine.f
use myscript__user__routines
double precision dimension(n,*),intent(in,copy) :: x
external fun
double precision dimension(n),intent(out),depend(n) :: o
integer, optional,intent(hide),check(shape(x,0)==n),depend(x) :: n=shape(x,0)
double precision dimension(shape(rpar,0)) :: rpar
integer, optional, dimension(2) :: ipar
end subroutine myscript
end interface
end python module routine
! This file was auto-generated with f2py (version:2).
! See http://cens.ioc.ee/projects/f2py2e/
Важная строка в заголовочном файле
double precision dimension(100),intent(in) :: rpar
, когда в отладчике Python rpar
теперь является100-мерный массив, где последние 98 значений являются мусором (не удивительно).
изменение размера на *
просто возвращает пустой массив
ipdb> rpar
array([], dtype=float64)
изменение размеров на shape(rpar,0)
какв основной подпрограмме выдает ошибку
ValueError: negative dimensions are not allowed
Существует ли элегантный способ позволить пользователю python динамически определять размерность массива параметров rpar
?Ожидаемое значение в примере - 2
, потому что это размер входного массива.
Полагаю, я мог бы изменить интерфейс и добавить еще одну целочисленную переменную, объявляющую размер этого массива.Однако это означает изменение всех вызовов этой подпрограммы при каждом появлении в коде;что-то, чего я хочу избежать