在调用Fortran程序METIS API(C语言wrtten)(Calling METIS API

2019-07-19 09:45发布

超过2周,我挣扎着打电话的一个METIS从我的Fortran代码写在C库。 而且,不幸的是,它似乎并没有在未经您的帮助幸福的终点。 我发现的一些帖子直接调用和使用界面 。 我倾向于后者,因为我可以监视调试的变量。 有我连着三个代码。

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是单或双精度。 从东北选项输入和最后三个参数是输出。 和vwgtvsize,tpwgts期权可以收到NULL作为默认设置的输入我写的接口模块使用C函数像这样

(2)的Fortran接口模块

固定!

  1. 插入使用的情况下使用的常量 iso_c_bind
  2. 使用整数(c_int的),而不是整数NE,NN和其他变量。
  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的分配尺寸是固定的。 不是NE但是NN
  2. OPTS(7)= 1被添加到得到的epart Fortran的式阵列,npart(无直到现在效果)

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。

输入错误:tpwgts的约束0 0.000000 Inorrect总和。

而这个消息在下面的代码来处理。

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;
    }
  }

总之,为了看看,如果我把一个数组tpwgts这一翻译的空,tpwgts(:) = 1.0 / nparts,这使得总和等于tpwgts 1.0我会得到。 但我得到了同样的消息,1.75的总和。

这是我的问题
1.我有没有使用正确的参数传递空()?
2.我是否必须通过指针所有参数c函数? 那么如何?
3.是把一个整数选择采用(0:39)足够用? 例如,在一个交而不“接口模块”,简单的代码类似的选项(3)= 1时使用。 但是在c代码,选择具有类似的选项[METIS_OPTION_NUMBERING]项[METIS_OPTION_UFACTOR] 16命名的变量。 我觉得有些事情是需要设置的选项,但我不知道。 4.是否有在FORTRAN METIS的例子吗?

任何一种暗示/建议将是对我有很大的帮助。 谢谢。

结论

我的问题是,C函数无法从Fortran代码识别空指针。

有一些变量小姐declations接口模块(见“固定”和评论)

它看起来像代码工作正常。 但是选项(7)= 1,FORTRAN风格输出没有工作,现在我看着它。

Answer 1:

  1. 不,你不能传递null()这是一个Fortran指针常量。 你必须通过C_NULL_PTR从模块ISO_C_BINDING和接口必须反映这一点。 伪参数必须是type(c_ptr)最有可能与VALUE属性。 它实际上可能因为同样的内部表示的工作,但我不会指望它。

  2. 不,如果你通过一些正常的变量,你可以直接通过引用传递它。 就像通常的Fortran。 如果接口是BIND(C)编译器知道它必须发送一个指针。

    有一个新的TS更新的Fortran 2008年,在那里你可以在互操作的程序定义为伪参数OPTIONAL 。 然后,你可以通过省略它们传递空指针。 Gfortran应该已经支持这一点。

注:在这里,我可以看到你的函数的多不同的C签名,你确定你是OK? http://charm.cs.uiuc.edu/doxygen/charm/meshpart_8c.shtml



Answer 2:

我觉得你的opts(7)不工作,因为你还需要为METIS功能的接口METIS_SetDefaultOptions 。 基于从答案http://glaros.dtc.umn.edu/gkhome/node/877 ,我创建了一个包装器模块( metisInterface.F90 )与我所需要的接口:

module metisInterface
! module to allows us to call METIS C functions from the main Fortran code

   use,intrinsic :: ISO_C_BINDING

   integer :: ia,ic
   integer(C_INT) :: metis_ne,metis_nn
   integer(C_INT) :: ncommon,objval
   integer(C_INT) :: nparts
   integer(C_INT),allocatable,dimension(:) :: eptr,eind,perm,iperm
   integer(C_INT),allocatable,dimension(:) :: epart,npart
   type(C_PTR) :: vwgt,vsize,twgts,tpwgts
   integer(C_INT) :: opts(0:40)


   interface
      integer(C_INT) function METIS_SetDefaultOptions(opts) bind(C,name="METIS_SetDefaultOptions")
         use,intrinsic :: ISO_C_BINDING
         implicit none
         integer(C_INT) :: opts(0:40)
      end function METIS_SetDefaultOptions
   end interface 

   interface
      integer(C_INT) function METIS_PartMeshDual(ne,nn,eptr,eind,vwgt,vsize,ncommon,nparts,tpwgts, &
                              opts,objval,epart,npart) bind(C,name="METIS_PartMeshDual")
         use,intrinsic :: ISO_C_BINDING
         implicit none
         integer(C_INT):: ne, nn
         integer(C_INT):: ncommon, objval
         integer(C_INT):: nparts
         integer(C_INT),dimension(*) :: eptr, eind
         integer(C_INT),dimension(*) :: epart, npart
         type(C_PTR),value :: vwgt, vsize, tpwgts
         integer(C_INT) :: opts(0:40)
      end function METIS_PartMeshDual
   end interface    

end module metisInterface

然后,在主程序(或任何你拨打电话到METIS功能),你需要有(的完整性,我还添加了调用METIS_PartMeshDual ):

use metisInterface

integer :: metis_call_status
.
.
.
metis_call_status = METIS_SetDefaultOptions(opts)

! METIS_OPTION_NUMBERING for Fortran
opts(17) = 1

metis_call_status = METIS_PartMeshDual(metis_ne,metis_nn,eptr,eind, &
                    vwgt,vsize,ncommon,nparts,tpwgts,opts,objval,epart,npart)

需要注意的是epartnpart将有Fortran的编号,只要你想(从1开始)。 然而,该处理器也将开始以1。例如编号,如果在4个处理器运行时,根处理器是1,则可能有epart(n)=4 ,并且你将不会有任何epart(n)=0

最后,文件metis.c也需要有一行:

#include "metis.h"

编制说明

  1. 编译metis.c用C语言编译器
  2. 编译metisInterface.F90用Fortran编译与所述编译的C对象链接
  3. 用Fortran编译与链接编译主程序metisInterface.o


文章来源: Calling METIS API(wrtten in C language) in fortran program