質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.62%

装置番号を引数とするFortranのサブルーチンをpythonから呼ぶ方法

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,043

syoukera

score 10

前提・実現したいこと

燃焼の化学反応解析コードCHEMKIN-II(Fortran77で作成)を使用しております.Pythonのリッチなデータ入出力およびデータ可視化機能を使いたく,PythonからFortran77のsubroutineを使用したいと思っております.

CHEMKIN-IIの内部で実行しているmainのProgramでは装置番号のopenと,装置番号を引数としたサブルーチンの呼び出しが行われております.

質問

PythonでOpenと同等の操作により装置番号を作成し,それを引数としてサブルーチンを呼ぶことは可能でしょうか.可能であればその方法を教えていただきたく.

該当のソースコード

参考までにPythonで再現したい箇所のCHEMKIIN-IIコードを記載します.

      PROGRAM DRIVER
C
C*****DOUBLE PRECISION
      IMPLICIT DOUBLE PRECISION (A-H, O-Z), INTEGER (I-N)
C*****END DOUBLE PRECISION
C*****SINGLE PRECISION
C      IMPLICIT REAL (A-H, O-Z), INTEGER (I-N)
C*****END SINGLE PRECISION
      PARAMETER ( LENIWK = 25000, LENRWK = 250000, LENCWK = 200,
     1            LENSYM = 16)
      DIMENSION IWORK (LENIWK), RWORK (LENRWK)
      LOGICAL LEXIST
      CHARACTER CWORK(LENCWK)*(LENSYM)
      DATA LIN/5/, LOUT/6/, LINKCK/25/, LSAVE/7/, LIGN/9/, LREST/10/
C
C     LIN    = Unit number for Keyword input
C     LOUT   = Unit number for text output to terminal
C     LIGN   = Unit number for text output file
C     LSAVE  = Unit number for binary output file
C     LINKCK = Unit number for CHENKIN linking file
C     LREST  = Unit number for binary restart file
C     LENIWK = Length of integer work array
C     LENRWK = Length of real work array
C     LENCWK = Length of character work array
C     LENSYM = Length of a character string in character work array
C     IWORK  = Integer work array
C     RWORK  = Real work array
C     CWORK  = Character work array
C
C*****vms
C      SET I/O UNITS AND OPEN FILES. OPERATING SYSTEM IS vms VMS.
C      OPEN (LINKCK, STATUS='OLD', FORM='UNFORMATTED')
C      OPEN (LSAVE, STATUS='NEW', FORM='UNFORMATTED')
C      OPEN (LOUT, STATUS='NEW', FORM='FORMATTED')
C      OPEN (LIGN, STATUS='NEW', FORM='FORMATTED')
C      OPEN (LIN, STATUS='OLD', FORM='FORMATTED')
C      INQUIRE (FILE='restart', EXIST=LEXIST)
C      IF (LEXIST) OPEN (LREST,STATUS='OLD',FORM='UNFORMATTED')
C*****END vms
C
C*****unix
      OPEN (LINKCK, FORM='UNFORMATTED', FILE='cklink')
      OPEN (LSAVE, FORM='UNFORMATTED', FILE ='save')
      OPEN (LOUT, FORM='FORMATTED', FILE='terminalout')
      OPEN (LIGN, FORM='FORMATTED', FILE = 'skout')
      OPEN (LIN, FORM='FORMATTED', FILE='inp')
      INQUIRE (FILE='restart', EXIST=LEXIST)
      IF (LEXIST) THEN 
        OPEN (LREST, FORM='UNFORMATTED',
     1        FILE='restart')
      ENDIF
C*****END unix
C
C     PASS CONTROL TO SENKIN
C
      CALL SENKIN (LIN, LOUT, LINKCK, LSAVE, LIGN, LREST,
     1             LENRWK, RWORK, LENIWK, IWORK, LENCWK, CWORK)
C
      STOP
      END
C
      SUBROUTINE TEMPT (TIME, TEMP)
      IMPLICIT DOUBLE PRECISION (A-H, O-Z), INTEGER (I-N)
      RETURN
      END
C
      SUBROUTINE VOLT (TIME, VOL, DVDT)
      IMPLICIT DOUBLE PRECISION (A-H, O-Z), INTEGER (I-N)
      RETURN
      END

追記20190519

Python上で整数型の値を管理し,Fortranに渡して装置番号として使用するということを考えました.テストのためにPythonからOpen文を含むコードを書いて実行を.結果は以下.

実行環境 結果
Pythonで装置番号を定義,Fortranに渡す Segmentation fault
Pythonから引数なしでFortranを呼ぶ,Fortranで装置番号を定義 実行可能

Fortran上で整数型を定義して渡すうまくいきますが,Pythonで管理しようとするとOPENの過程で怒られました.
参考に使用したコードを置いておきます.

import ctypes
import numpy as np

# device number as argument
def call_openfiles(readDN, writeDN):
    f = np.ctypeslib.load_library("libfort.so", ".")
    f.openfiles_.argtypes = [
        ctypes.c_int32,
        ctypes.c_int32
        ]
    f.openfiles_.restype  = ctypes.c_void_p

    f.openfiles_(readDN, writeDN)

# non argument
def call_fortran():
    f = np.ctypeslib.load_library("libfort.so", ".")
    f.main_.restype  = ctypes.c_void_p

    f.main_()

# 装置番号を定義して引数として渡すとき
readDN  = 10
writeDN = 11
print("**call fortran from python with device number as argument")
call_openfiles(readDN, writeDN)

# 引数なしで渡すとき
# print("**call fortran from python with non argument")
# call_fortran()
subroutine main()
    implicit none
    integer :: readDN = 10
    integer :: writeDN = 11

    call openFiles(readDN, writeDN)
    call rwNumbers(readDN, writeDN)
    call closeFiles(readDN, writeDN)
end subroutine main

subroutine rwNumbers(readDN, writeDN)
    implicit none
    real,dimension(30)::numbers
    real temp
    integer i, j
    integer readDN 
    integer writeDN

    ! read numbers
    do i = 1, 30
        read(readDN, *) numbers(i)
    end do
    close(10)

    ! baggle sort
    do i = 2, 30
        do j = 2, 32-i
            if (numbers(j) < numbers(j-1)) then
                temp = numbers(j)
                numbers(j) = numbers(j-1)
                numbers(j-1) = temp
            end if
        end do
    end do

    ! print numbers
    print *, "Sorted numbers is written in sortedNumbers.txt"
    do i=1, 30
        write(writeDN,*) numbers(i)
    end do
end subroutine

subroutine openFiles(readDN, writeDN)
    implicit none
    integer(4),intent(in) :: readDN
    integer(4),intent(in) :: writeDN

    print *, "Open files from fortran"
    open(readDN , file='numbers.txt', status='old')
    open(writeDN , file='sortedNumbers.txt', status='replace')
end subroutine

subroutine closeFiles(readDN, writeDN)
    implicit none
    integer readDN, writeDN
    close(readDN)
    close(writeDN)
end subroutine
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

Fortran無知なので参考になりそうなページの紹介まで。
Pythonで簡単にFortranのsubroutineを用いる方法

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/14 21:37

    回答いただきありがとうございます.参考にいたします.

    キャンセル

0

装置番号という整数値と、実際のファイルはFortranランタイムの中で関連づけられていると思うので、文字通りには無理ではないかと。

ということでopen命令だけはFortranプログラムを呼ばないといけないでしょう。
出来るとすると、
1.装置番号を決めて、openだけするFortranサブルーチンを呼ぶ
2.Pythonの何らかの処理が必要ならする
3.装置番号を引数に指定して目的のFortranサブルーチンを呼ぶ
ですが、1で呼んだときのFortran実行環境が3と共有できなさそうな気がするので、駄目な気がします。
出来るかもしれないので、やってみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/14 21:40

    おっしゃる通りにopen文はfortranの呼び出しが必要なようですね.何かしらやってみて上手くいったか報告したいと思います.

    キャンセル

  • 2019/05/19 10:15

    やってみましたがOpen文の呼び出しでセグフォが出てしまいました.追記に記載しております.

    キャンセル

  • 2019/05/19 18:56

    Fortran側のopenFilesで、Pythonから渡された引数をそのままopenに渡すのでなく、Fortranのローカル変数に代入してから、そのFortranの変数をopenに渡したらどうでしょうか?

    あと、参考までに、libfort.so を作った方法を教えてください。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る