ファイル名の長さの問題は簡単に対処できます: filename: を作成しcharacter(len_filename):: filename
、len_filename
fortran 関数のパラメーターとして使用し、 を使用しf2py intent(hide)
て Python インターフェイスから非表示にします (以下のコードを参照)。
渡す必要がなく、より複雑でnx
ありny
、本質的には f2py から割り当て可能な配列を返す方法の問題です。2 つの方法がありますが、どちらも (小さくて非常に軽い) Python ラッパーを使用して適切なインターフェイスを提供する必要があります。
csv ファイルの読み取り方法の問題に実際には対処していません。ダミー データを生成して返しただけです。そのための適切な実装があると思います。
方法 1: モジュール レベルの割付け配列
これはかなり標準的な方法のようです - これを推奨しているニュースグループの投稿を少なくとも 1 つ見つけました。基本的に、割り当て可能なグローバル変数があり、適切なサイズに初期化して書き込みます。
module mod
real, allocatable, dimension(:,:) :: genfromtxt_output
contains
subroutine genfromtxt_v1(filename, len_filename)
implicit none
character(len_filename), intent(in):: filename
integer, intent(in) :: len_filename
!f2py intent(hide) :: len_filename
integer :: row, col
! for the sake of a quick demo, assume 5*6
! and make it all 2
if (allocated(genfromtxt_output)) deallocate(genfromtxt_output)
allocate(genfromtxt_output(1:5,1:6))
do row = 1,5
do col = 1,6
genfromtxt_output(row,col) = 2
end do
end do
end subroutine genfromtxt_v1
end module mod
短い Python ラッパーは次のようになります。
import _genfromtxt
def genfromtxt_v1(filename):
_genfromtxt.mod.genfromtxt_v1(filename)
return _genfromtxt.mod.genfromtxt_output.copy()
# copy is needed, otherwise subsequent calls overwrite the data
これに関する主な問題は、スレッド セーフではないことです。2 つの Python スレッドがgenfromtxt_v1
非常に類似したタイミングで呼び出された場合、変更をコピーする前にデータが上書きされる可能性があります。
方法 2: データを保存する Python コールバック関数
これは少し複雑で、私自身の発明の恐ろしいハックです。配列をコールバック関数に渡し、それを保存します。Fortran コードは次のようになります。
subroutine genfromtxt_v2(filename,len_filename,callable)
implicit none
character(len_filename), intent(in):: filename
integer, intent(in) :: len_filename
!f2py intent(hide) :: len_filename
external callable
real, allocatable, dimension(:,:) :: result
integer :: row, col
integer :: rows,cols
! for the sake of a quick demo, assume 5*6
! and make it all 2
rows = 5
cols = 6
allocate(result(1:rows,1:cols))
do row = 1,rows
do col = 1,cols
result(row,col) = 2
end do
end do
call callable(result,rows,cols)
deallocate(result)
end subroutine genfromtxt_v2
次に、「署名ファイル」を生成する必要があります (が Fortran コードを含むファイルであるとf2py -m _genfromtxt -h _genfromtxt.pyf genfromtxt.f90
仮定します)。genfromtxt.f90
次に、「ユーザー ルーチン ブロック」を変更して、コールバックの署名を明確にします。
python module genfromtxt_v2__user__routines
interface genfromtxt_v2_user_interface
subroutine callable(result,rows,cols)
real, dimension(rows,cols) :: result
integer :: rows
integer :: cols
end subroutine callable
end interface genfromtxt_v2_user_interface
end python module genfromtxt_v2__user__routines
(つまり、寸法を指定します)。ファイルの残りの部分は変更されません。でコンパイルf2py -c genfromtxt.f90 _genfromtxt.pyf
小さな Python ラッパーは
import _genfromtxt
def genfromtxt_v2(filename):
class SaveArrayCallable(object):
def __call__(self,array):
self.array = array.copy() # needed to avoid data corruption
f = SaveArrayCallable()
_genfromtxt.genfromtxt_v2(filename,f)
return f.array
これはスレッドセーフであるべきだと思います: Python コールバック関数はグローバル変数として実装されていると思いますが、デフォルトの f2py は GIL を解放しないため、設定されているグローバルとコールバックが実行されている間で Python コードを実行することはできません。ただし、このアプリケーションのスレッドセーフについて気にかけているとは思えません...