Chamando a API METIS (escrita em linguagem C) no programa fortran
Mais de 2 semanas, tenho lutado para chamar um dosMETIS biblioteca escrita em C do meu código fortran. E, infelizmente, não parece ser um HAPPY END sem a sua ajuda. Eu encontrei alguns posts sobrechamadas diretas eusando interface. Eu prefiro o último porque eu poderia monitorar as variáveis para depuração. Existem três códigos que eu anexei.
1. c função eu gostaria de usar
2. módulo de interface fortran
3. programa fortran
(1) função 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)
Eu removi o corpo c funciton. Não é necessário entender meu problema
Aqui,idx_t é inteiro ereal_t é de precisão simples ou dupla. Dene paraopções são entradas e os últimos três argumentos são enviados. Evwgt, vsize, tpwgts eopções pode receber null como uma entrada para a configuração padrão Eu escrevi o módulo de interface para usar a função c como este
(2) módulo de interface Fortran
Fixo!Inseriruse iso_c_bind debaixousar constantesUsarinteiro (c_int) ao invés deinteiro parane, nn e outras variáveis.Remover módulo não utilizadoconstantes.
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
E aqui está o meu código de programa chamando a função
(3) programa Fortran
Fixo!tamanho de alocação denpart está consertado. Nãone masnnopts (7) = 1 é adicionado para obter a matriz de estilo de Fortran de epart, npart (sem efeito até agora).
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
Mas o problema é que recebo uma mensagem de erro como abaixo, embora eu tenha colocado null para o tpwgt.
Erro de entrada: soma incorreta de 0,000000 para tpwgts para restrição 0.
E esta mensagem é tratada no código abaixo.
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;
}
}
De qualquer forma, a fim de ver o que eu iria conseguir se eu colocar uma matriz para tpwgts intead de nulo,tpwgts (:) = 1,0 / nparts, o que torna a soma de tpwgts igual a 1.0. Mas eu recebi a mesma mensagem com1,75 para a soma.
Estas são minhas perguntas
1. Eu usei null () para passar argumentos corretamente?
2. Tenho que passar ponteiros para todos os argumentos para a função c? então como?
3. Está colocando um inteiro para opts (0:39) o suficiente para usar? Por exemplo, em umpostar sem 'módulo de interface', código simples como opções (3) = 1 é usado. Mas no código c, as opções têm 16 variáveis nomeadas como opções [METIS_OPTION_NUMBERING], opções [METIS_OPTION_UFACTOR]. Eu acho que algo é necessário para definir opções, mas não tenho ideia. 4. Existe um exemplo para o METIS no fortran?
Qualquer tipo de sugestão / conselho será uma grande ajuda para mim. Obrigado.
ConclusãoO problema que tive foi quefunção c não pôde reconhecer nulo ponteiro do código fortran.
Houve algumas descrições erradas de variáveis no módulo de interface (veja 'Fixo' e comentários)
Parece que o código funciona corretamente. Masopção (7) = 1 para saída de estilo fortran não funcionou e agora estou olhando para ele.