2

2 週間以上、C で書かれたMETISライブラリの 1 つを自分の fortran コードから呼び出すのに苦労しました。残念ながら、あなたの助けがなければ HAPPY END にはなりません。直接呼び出しインターフェイスの使用に関する投稿をいくつか見つけました。デバッグのために変数を監視できるので、私は後者を好みます。私が添付した3つのコードがあります。

1. 使いたいc関数
2. fortranインターフェースモジュール
3. fortranプログラム

(1)c関数

int METIS_PartMeshNodal(idx_t *ne, idx_t *nn, idx_t *eptr, idx_t *eind, 
      idx_t *vwgt, idx_t *vsize, idx_t *nparts, real_t *tpwgts, 
      idx_t *options, idx_t *objval, idx_t *epart, idx_t *npart)

c 関数本体を削除しました。私の問題を理解する必要はない

ここで、idx_tは整数で、 real_tは単精度または倍精度です。neからoptionsまでが入力され、最後の 3 つの引数が出力されます。そしてvwgtvsizetpwgtsoptionsはデフォルト設定の入力として null を受け取ることができます 私はこのような c 関数を使用するためのインターフェース モジュールを書きました

(2) Fortran インターフェースモジュール

修理済み!

  1. use 定数の下にuse iso_c_bindを挿入します。
  2. nenn、およびその他の変数には、 integerの代わりにinteger(c_int)を使用します。
  3. 未使用のモジュール定数を削除する

.

module Calling_METIS

  !use constants,  only : p2 !this is for double precision
  use iso_c_bind            !inserted later

  implicit none

  !integer                                    :: ne, nn              !modified
  integer(c_int)                              :: ne, nn 
  !integer,  dimension(:), allocatable        :: eptr, eind          !modified
  integer(c_int),  dimension(:), allocatable  :: eptr, eind
  !integer,  dimension(:), allocatable        :: vwgt, vsize         !modified
  type(c_ptr)                                 :: vwgt, vsize         
  !integer                                    :: nparts              !modified
  integer(c_int)                              :: nparts
  !real(p2), dimension(:), allocatable        :: tpwgts              !modified 
  type(c_ptr)                                 :: tpwgts      
  !integer,  dimension(0:39)                  :: opts                !modified
  integer(c_int),  dimension(0:39)            :: opts        
  !integer                                    :: objval              !modified
  integer(c_int)                              :: objval
  !integer,  dimension(:), allocatable        :: epart, npart        !modified 
  integer(c_int),  dimension(:), allocatable  :: epart, npart 

  interface
    subroutine METIS_PartMeshNodal( ne, nn, eptr, eind, vwgt, vsize, nparts, tpwgt, &
                                    opts, objval, epart, npart) bind(c)
      use intrinsic        :: iso_c_binding
      !use constants,  only  : p2

      implicit none

      integer (c_int),                  intent(in)  :: ne, nn
      integer (c_int), dimension(*),    intent(in)  :: eptr, eind
      !integer (c_int), dimension(*),    intent(in) :: vwgt, vsize  !modified
      type(c_ptr),                          value   :: vwgt, vsize   
      integer (c_int),                  intent(in)  :: nparts
      !real(c_double),  dimension(*),    intent(in) :: tpwgt        !modified
      type(c_ptr),                          value   :: tpwgt
      integer (c_int), dimension(0:39), intent(in)  :: opts
      integer (c_int),                  intent(out) :: objval
      integer (c_int), dimension(*),    intent(out) :: epart
      integer (c_int), dimension(*),    intent(out) :: npart

    end subroutine METIS_PartMeshNodal  
  end interface
end module

そして、これが関数を呼び出す私のプログラムコードです

(3) Fortran プログラム

修理済み!

  1. npartの割り当てサイズは固定です。じゃなくて
  2. epart、npart の Fortran スタイルの配列を取得するために opts(7)=1 が追加されました (今のところ影響はありません)。

.

program METIS_call_test

 !some 'use' statments
 use Calling_METIS
 use iso_c_binging         !added

 implicit none

 ! Local variable
 integer         :: iC
 character(80)   :: grid_file !grid_file

 grid_file = 'test.grid'

 ! (1) Read grid files
 call read_grid(grid_file)

 ! (2) Construction Input Data for calling METIS Function
 ! # of cells, vertices
 ne = ncells
 nn = nvtxs

 ! eptr, eind allocation 
 allocate(eptr(0:ne), eind(0:3*ntria + 4*nquad - 1))

 ! eptr and eind building
 eptr(0) = 0
 do iC=1, ncells
   eptr(iC) = eptr(iC-1) + cell(iC)%nvtxs
   eind(eptr(iC-1):eptr(iC)-1) = cell(iC)%vtx
 end do

 ! epart, npart building
 !allocate(epart(ne), npart(ne))
 allocate(epart(ne), npart(nn))   ! modified

 ! # of partition setting
 nparts = 2
 vwgt   = c_null_ptr    !added
 vsize  = c_null_ptr    !added
 tpwgt  = c_null_ptr    !added     

 ! (3) Call METIS_PartMeshNodal
 call METIS_SetDefaultOptions(opts)

 opts(7) = 1                      !Added. For fortran style output array epart, npart. 

 call METIS_PartMeshNodal(ne, nn, eptr, eind, vwgt, vsize, nparts, tpwgt, &
                           opts, objval, epart, npart)
 !call METIS_PartMeshNodal(ne, nn, eptr, eind, null(), null(), nparts, null(), &
 !                         opts, objval, epart, npart)         !wrong...

end program

ただ、tpwgtにnullを入れても以下のようなエラーメッセージが出てしまうのが難点です。

入力エラー: 制約 0 の tpwgts の合計 0.000000 が正しくありません。

そして、このメッセージは以下のコードで処理されます。

for (i=0; i<ctrl->ncon; i++) {
    sum = rsum(ctrl->nparts, ctrl->tpwgts+i, ctrl->ncon);
    if (sum < 0.99 || sum > 1.01) {
      IFSET(dbglvl, METIS_DBG_INFO, 
          printf("Input Error: Incorrect sum of %"PRREAL" for 
                  tpwgts for constraint %"PRIDX".\n", sum, i));
      return 0;
    }
  }

とにかく、null の代わりに tpwgts の配列を配置した場合に何が得られるかを確認するために、tpwgts(:) = 1.0/npartsを実行すると、tpwgts の合計が 1.0 になります。しかし、合計が1.75という同じメッセージが表示されました。

これらは私の質問
です 1. 引数を正しく渡すために null() を使用しましたか?
2. すべての引数のポインターを c 関数に渡す必要がありますか? ではどうやって?
3. opts(0:39) に整数を入れるだけで十分ですか? たとえば、 「インターフェイス モジュール」のない投稿では、 options(3)=1 のような単純なコードが使用されます。しかし、C コードでは、options には options[METIS_OPTION_NUMBERING]、options[METIS_OPTION_UFACTOR] のように 16 個の名前付き変数があります。オプションを設定するには何か必要だと思いますが、わかりません。4. fortran での METIS の例はありますか?

どんな種類のヒント/アドバイスも私にとって大きな助けになります。ありがとうございました。

結論

私が抱えていた問題は、c 関数がfortran コードからヌル ポインターを認識できないことでした。

インターフェースモジュールで変数の宣言ミスがいくつかありました (「修正済み」とコメントを参照)

コードは正常に動作しているようです。しかし、fortran スタイルの出力のoption(7) = 1が機能しなかったので、今調べています。

4

2 に答える 2

3
  1. null()いいえ、 Fortran ポインター定数である を渡すことはできません。C_NULL_PTRモジュールから渡す必要がISO_C_BINDINGあり、インターフェイスはこれを反映する必要があります。仮引数は でなければなりませんtype(c_ptr)。ほとんどの場合、VALUE属性が付きます。内部表現が同じであるため、実際には機能する可能性がありますが、私はそれを当てにはしません。

  2. いいえ、通常の変数を渡す場合は、参照によって直接渡すことができます。通常の Fortran と同じです。インターフェイスが の場合BIND(C)、コンパイラはポインターを送信する必要があることを認識しています。

    Fortran 2008 を更新するための新しい TS があり、相互運用可能なプロシージャで仮引数を として定義できますOPTIONAL。次に、それらを省略するだけでヌルポインターを渡すことができます。Gfortran はすでにこれをサポートしているはずです。

注:ここでは、関数の C シグネチャが大きく異なっていることがわかります。本当に大丈夫ですか? http://charm.cs.uiuc.edu/doxygen/charm/meshpart_8c.shtml

于 2013-02-06T14:26:42.360 に答える