Wywołanie METIS API (napisany w języku C) w programie fortran
W ciągu 2 tygodni walczyłem z jednym z nichMETYS biblioteka napisana w C z mojego kodu fortran. I niestety nie wydaje się być SZCZĘŚLIWYM KONIECEM bez twojej pomocy. Znalazłem kilka postówbezpośrednie połączenie iza pomocą interfejsu. Wolę ten drugi, ponieważ mogę monitorować zmienne do debugowania. Załączam trzy kody.
1. Funkcja c Chciałbym użyć
2. Moduł interfejsu fortran
3. program fortran
(1) Funkcja 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)
Usunąłem ciało funkcji c. Nie trzeba rozumieć mojego problemu
Tutaj,idx_t jest liczbą całkowitą ireal_t jest pojedyncza lub podwójna precyzja. Zne doopcje są wejściowe i wyprowadzane są trzy ostatnie argumenty. Ivwgt, vsize, tpwgts iopcje może otrzymać wartość NULL jako dane wejściowe dla ustawień domyślnych Napisałem moduł interfejsu do używania funkcji c w ten sposób
(2) Moduł interfejsu Fortran
Naprawiony!Wstawićużyj iso_c_bind podużyj stałychPosługiwać sięliczba całkowita (c_int) zamiastliczba całkowita dlane, nn i inne zmienne.Usuń nieużywany modułstałe.
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
A oto mój kod programu wywołujący tę funkcję
(3) Program Fortran
Naprawiony!wielkość alokacjinpart jest naprawiony. Niene alenndodano opts (7) = 1, aby uzyskać tablicę epart w stylu Fortrana, npart (brak efektu do teraz).
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
Ale problem polega na tym, że otrzymuję komunikat o błędzie, jak poniżej, chociaż wprowadziłem wartość null dla tpwgt.
Błąd wejścia: niepoprawna suma 0,000000 dla tpwgts dla ograniczenia 0.
Ta wiadomość jest obsługiwana w poniższym kodzie.
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;
}
}
W każdym razie, aby zobaczyć, co bym dostał, gdybym wstawił tablicę dla tpwgts intead o wartości null,tpwgts (:) = 1.0 / nparts, co powoduje, że suma tpwgts równa się 1,0. Ale mam tę samą wiadomość1,75 za sumę.
To są moje pytania
1. Czy użyłem null () do poprawnego przekazywania argumentów?
2. Czy muszę przekazywać wskaźniki dla wszystkich argumentów funkcji c? więc jak?
3. Czy wprowadzenie liczby całkowitej do opcji (0:39) jest wystarczające do użycia? Na przykład w asłupek bez „modułu interfejsu” używany jest prosty kod, taki jak opcje (3) = 1. Ale w kodzie c opcje mają 16 nazwanych zmiennych, takich jak opcje [METIS_OPTION_NUMBERING], opcje [METIS_OPTION_UFACTOR]. Myślę, że konieczne jest ustawienie pewnych opcji, ale nie mam pojęcia. 4. Czy jest przykład METIS w fortran?
Wszelkie wskazówki / porady będą dla mnie wielką pomocą. Dziękuję Ci.
ZanieczyszczenieProblem, który miałem, był takiFunkcja c nie mogła rozpoznać wartości zerowej wskaźnik z kodu fortran.
W module interfejsu były pewne deklinacje zmiennych (patrz „Naprawiono” i komentarze)
Wygląda na to, że kod działa poprawnie. Aleopcja (7) = 1 dla stylu fortran wynik nie działał i teraz na niego patrzę.