在 fortran 程序中调用 METIS API(用 C 语言编写) [英] Calling METIS API(wrtten in C language) in fortran program
问题描述
两周多来,我一直在努力给其中一个 METIS 从我的 fortran 代码中用 C 语言编写的库.而且,不幸的是,没有你的帮助,这似乎不是一个快乐的结局.我发现了一些关于 直接调用 和 使用界面.我更喜欢后者,因为我可以监视变量以进行调试.我附上了三个代码.
1.我要使用的c函数
2. fortran接口模块
3. fortran程序
Over 2 weeks, I've struggled to call one of the METIS library written in C from my fortran code. And, unfortunately, It doesn't seem to be a HAPPY END without your help. I found some posts about direct calling and using interface. I prefer the latter because I could monitor the variables for debugging. There are three codes I attached.
1. c function I'd like to use
2. fortran interface module
3. fortran program
(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 是输入,最后三个参数是输出.并且 vwgt、vsize、tpwgts 和 options 可以接收 null 作为默认设置的输入 我编写了界面模块像这样使用 c 函数
Here, idx_t is integer and real_t is single or double precision. From ne to options are input and last three arguments are output. And vwgt, vsize, tpwgts and options can receive null as an input for default setting I wrote the interface module for using c function like this
(2) Fortran 接口模块
(2) Fortran interface module
- 在使用常量 下插入use iso_c_bind
- 对 ne、nn 和其他变量使用 integer(c_int) 而不是 integer.
- 删除未使用的模块常量
- Insert use iso_c_bind under use constants
- Use integer(c_int) instead of integer for ne, nn and other variables.
- Remove unused module constants
.
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
这是我调用该函数的程序代码
And here is my program code calling the function
(3) Fortran 程序
(3) Fortran program
- npart 的分配大小是固定的.不是 ne 而是 nn
- 增加了opts(7)=1来获取epart、npart的Fortran风格数组(目前无效)
- allocation size of npart is fixed. Not ne but nn
- opts(7)=1 is added to get Fortran-style array of epart, npart(no effect until now)
.
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.
But the problem is that I get an error message as below though I put null for tpwgt.
输入错误:约束 0 的 tpwgts 的 0.000000 总和不正确.
并且这条消息在下面的代码中处理.
And this message is handled in the code below.
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".
", sum, i));
return 0;
}
}
无论如何,为了看看如果我为 tpwgts 放入一个数组而不是 null 会得到什么,tpwgts(:) = 1.0/nparts,这使得 tpwgts 的总和等于 1.0.但我得到了与 1.75 相同的信息.
Anyway, in order to see what I would get if I put an array for tpwgts intead of null, tpwgts(:) = 1.0/nparts, which makes sum of tpwgts equal 1.0. But I got same message with 1.75 for the sum.
这是我的问题
1. 我是否使用 null() 正确传递参数?
2. 我必须将所有参数的指针传递给 c 函数吗?那怎么办?
3. 将整数放入 opts(0:39) 是否足够使用?例如,在没有接口模块"的 post 中,简单的代码像 options(3)=1 被使用.但在 c 代码中,options 有 16 个命名变量,如 options[METIS_OPTION_NUMBERING]、options[METIS_OPTION_UFACTOR].我认为设置选项是必要的,但我不知道.4. METIS有fortran的例子吗?
These are my questions
1. Did I use null() for passing arguments correctly?
2. Do I have to pass pointers for all arguments to c function? then how?
3. Is putting an integer to opts(0:39) enough for use? For example, in a post without 'interface module', simple code like options(3)=1 is used. But in the c code, options has 16 named variable like options[METIS_OPTION_NUMBERING], options[METIS_OPTION_UFACTOR]. I think some thing is necessary to set options but I have no idea.
4. Is there an example for METIS in fortran?
任何类型的提示/建议都会对我有很大帮助.谢谢你.
Any kind of hint/advice will be a great help for me. Thank you.
我遇到的问题是 c 函数无法识别 fortran 代码中的空指针.
接口模块中有一些变量的错误声明(请参阅已修复"和注释)
There were some miss declations of variables in interface module(see 'Fixed' and comments)
看起来代码工作正常.但是 fortran 样式输出的 option(7) = 1 不起作用,现在我正在研究它.
It looks like the code works properly. But option(7) = 1 for fortran style output didn't work and now I'm looking at it.
推荐答案
不,你不能传递
null()
,这是一个 Fortran 指针常量.您必须从模块ISO_C_BINDING
传递C_NULL_PTR
并且接口必须反映这一点.虚拟参数必须是type(c_ptr)
,很可能带有VALUE
属性.由于相同的内部表示,它实际上可能会起作用,但我不会指望它.
No, you cannot pass
null()
, that is a Fortran pointer constant. You must passC_NULL_PTR
from the moduleISO_C_BINDING
and the interface must reflect this. The dummy argument must betype(c_ptr)
, most probably withVALUE
attribute. It may actually work because of the same internal representation, but I wouldn't count on it.
不,如果你传递一些普通的变量,你可以直接通过引用传递.就像通常在 Fortran 中一样.如果接口是BIND(C)
,编译器知道它必须发送一个指针.
No, if you pass some normal variable, you can pass it directly by reference. Just like normally in Fortran. If the interface is BIND(C)
, the compiler knows it must send a pointer.
有一个更新 Fortran 2008 的新 TS,您可以在其中将可互操作过程中的虚拟参数定义为 OPTIONAL
.然后你可以通过省略它们来传递空指针.Gfortran 应该已经支持这个了.
There is a new TS to update Fortran 2008, where you can define dummy arguments in the interoperable procedures as OPTIONAL
. Then you can pass the null pointer just by omitting them. Gfortran should already support this.
注意:在这里我可以看到你的函数的一个非常不同的 C 签名,你确定你的函数没问题吗?http://charm.cs.uiuc.edu/doxygen/charm/meshpart_8c.shtml
Note: Here I can see a much different C signature of your function, are you sure yours is OK? http://charm.cs.uiuc.edu/doxygen/charm/meshpart_8c.shtml
这篇关于在 fortran 程序中调用 METIS API(用 C 语言编写)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!