resueltos - ISO_C_BINDING Llamando a la rutina C desde Fortran(con dobles y matrices)
programas en fortran ejemplos (1)
Publiqué una pregunta similar hace unas semanas ( iso_c_binding llamando a la rutina C con punteros de Fortran con matrices ) y encontré una solución a mi problema. Ahora modifiqué algunas cosas y estoy teniendo algunos problemas otra vez. A continuación, una versión simplificada de mi problema.
Tengo un programa principal en fortran:
program main_dummy
! compile: gcc -c dummy_trace.c
! f95 raytracing.f90 main_dummy.f90 dummy_trace.o -o main
use, intrinsic :: ISO_C_BINDING
use raytracing
implicit none
!real(kind=8) :: x_in(4), x_fin(4)
real(C_DOUBLE), dimension(0:3) :: x_in, x_fin
real(C_DOUBLE) :: spin
integer :: rt_ok
x_in = (/1,2,3,4/)
x_fin = (/0,0,0,0/)
spin = 0.7
write(*,*)''x_in, x_fin before = '', x_in, x_fin
rt_ok = photon_trace(spin,x_in,x_fin)
write(*,*)''return rt = '', rt_ok
write(*,*)''x_in, x_fin after = '', x_in, x_fin
end program main_dummy
Que usan una subrutina que contiene la interfaz para la rutina C:
module raytracing
Interface
integer (C_INT) function photon_trace(BHsp, x_init, x_final) &
bind(C, name=''photon_trace'')
use , intrinsic :: ISO_C_BINDING
implicit none
real(C_DOUBLE) :: BHsp, x_init(4), x_final(4)
end function photon_trace
end interface
end module raytracing
y esta es la rutina C:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#undef I
int photon_trace(double BHsp, double x_init[4], double x_final[4])
//***************************************************
{
printf("BHsp %f/n", BHsp);
double r,m,t,phi;
t = x_init[0];
r = x_init[1];
m = x_init[2];
phi = x_init[3];
printf("t0 %f/n", t);
printf("r0 %f/n", r);
printf("m0 %f/n", t);
printf("phi0 %f/n", r);
t=t+1.0;
r=r+1.0;
m=m+1.0;
phi=phi+1.0;
printf("t1 %f/n", t);
printf("r1 %f/n", r);
printf("m1 %f/n", t);
printf("phi1 %f/n", r);
x_final[0] = t;
x_final[1] = r;
x_final[2] = m;
x_final[3] = phi;
return 0;
}
Si compilo y ejecuto el programa, esto es lo que obtengo:
x_in, x_fin before = 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
BHsp 0.000000
t0 0.700000
r0 0.000000
m0 0.700000
phi0 0.000000
t1 1.700000
r1 1.000000
m1 1.700000
phi1 1.000000
return rt = 0
x_in, x_fin después = 1.6999999880790710 1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
Tenga en cuenta que antes de poner la variable "spin" todo estaba funcionando. Podría leer la matriz de entrada, hacer la opración y dar la salida correcta.
Ahora que agregué esta variable, hay algunos problemas para la rutina C al leer lo que estoy pasando y no puedo entender qué sucede. Cualquier sugerencia ?
(Tenga en cuenta que en el caso real voy a pasar varias variables, así como 2 matrices de entrada y 2 de salida con dimensión 4).
¡¡Muchas gracias de antemano!!
Cambie su interfaz a:
module raytracing
Interface
integer (C_INT) function photon_trace(BHsp, x_init, x_final) &
bind(C, name=''photon_trace'')
use , intrinsic :: ISO_C_BINDING
implicit none
real(C_DOUBLE) :: x_init(4), x_final(4)
real(c_double), value :: BHsp
end function photon_trace
end interface
end module raytracing
Su función C toma un double
lugar de un double*
por lo que debe pasar el escalar con el atributo de value
para que el Fortran sepa pasar el valor en lugar de su pase predeterminado por referencia.
Con este pequeño cambio (y algunos cambios menores en su C para imprimir realmente los valores de m
y phi
) este es el resultado de su código de ejemplo:
% ./main
x_in, x_fin before = 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
BHsp 0.700000
t0 1.000000
r0 2.000000
m0 3.000000
phi0 4.000000
t1 2.000000
r1 3.000000
m1 4.000000
phi1 5.000000
return rt = 0
x_in, x_fin after = 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 5.0000000000000000