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 つの引数が出力されます。そしてvwgt、vsize、tpwgtsとoptionsはデフォルト設定の入力として null を受け取ることができます 私はこのような c 関数を使用するためのインターフェース モジュールを書きました
(2) Fortran インターフェースモジュール
修理済み!
- use 定数の下にuse iso_c_bindを挿入します。
- ne、nn、およびその他の変数には、 integerの代わりにinteger(c_int)を使用します。
- 未使用のモジュール定数を削除する
.
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 プログラム
修理済み!
- npartの割り当てサイズは固定です。ねじゃなくてん
- 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が機能しなかったので、今調べています。