I posted a similar question few weeks ago (iso_c_binding calling C routine with pointers from Fortran with arrays) and I found a solution to my problem.
Now I modified few things and I am having some problems again.
In the following a simplified version of my problem.
I have a main program in 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
Which use a subroutine containing the interface for the C routine:
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
and this is the C routine:
#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;
}
If I compile and run the program, this is what I get:
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 after = 1.6999999880790710 1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
Notice that before putting the variable "spin" everything was working. It could read the input array, make the opration, and give the right output.
Now that I added ths variable, there are some problems for the C routine in reading what I'm passing and I cannot understand what's wrong.
Any suggestion ?
(Consider that in the real case I'm going to pass several variables as well as 2 input and 2 output arrays with dimension 4).
Many thanks in advance!!
Change your interface to:
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
Your C function takes a double rather than double* so you need to pass the scalar with the value attribute so that the Fortran knows to pass by value rather than its default pass by reference.
With this small change (and some minor changes to your C to actually print the values of m and phi) this is the output of your example code:
% ./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
Related
I tried to solve a generalized eigenvalue problem for both eigenvalue and eigenvectors, at least for the lowest one.
A x = lambda B x
where A and B are two real symmetric matrices. B is positive semi definite.(in practice, positive definite)
Looks like dgeev/dsygv is the right tool, http://www.netlib.org/lapack/explore-html/d9/d8e/group__double_g_eeigen_ga66e19253344358f5dee1e60502b9e96f.html http://www.netlib.org/lapack/explore-html/d2/d8a/group__double_s_yeigen_ga007d33bcdcc697e17c6d15432f159b73.html
As an initial step, I would to see if dgeev/dsygv can reproduce the problem for standard eigenvalue problem, namely when B is a unit matrix, by comparing with dsyev. However, I got different eigenvectors. Here is my fortran code
Program eigen_test
integer, parameter :: dp = selected_real_kind(15, 307)
real(dp) :: A(2,2), B(2,2), work(2), w(2), wr(2), wi(2), vl(2,2), vr(2)
integer :: i,j,N, info, lwork, LDA, LDB, LDVL, LDVR, ITYPE
character :: jobz, uplo, JOBVL, JOBVR
external dsyev, dgeev, DSYGV
N = 2
jobz = "V"
uplo = "U"
lwork = 6 * N
A(1,1) = 1.0_dp
A(1,2) = 0.2_dp
A(2,2) = 1.0_dp
A(2,1) = A(1,2)
B(1,1) = 1.0_dp
B(1,2) = 0.0_dp
B(2,2) = 1.0_dp
B(2,1) = B(1,2)
JOBVL = 'N'
JOBVR = 'V'
LDA = N
LDB = N
LDVL = N
LDVR = N
write (*,*) 'before dsyev', A
call dsyev(jobz, uplo, N, A, N, w, work, lwork, info)
write (*,*) 'after A dsyev', A
A(1,1) = 1.0_dp
A(1,2) = 0.2_dp
A(2,2) = 1.0_dp
A(2,1) = A(1,2)
write (*,*) 'A before dgeev', A
call dgeev(JOBVL, JOBVR, N, A, LDA, WR, WI, VL, LDVL, VR, LDVR, WORK, LWORK, INFO)
write (*,*) 'A after dgeev', A
write (*,*) 'VR',VR
A(1,1) = 1.0_dp
A(1,2) = 0.2_dp
A(2,2) = 1.0_dp
A(2,1) = A(1,2)
B(1,1) = 1.0_dp
B(1,2) = 0.0_dp
B(2,2) = 1.0_dp
B(2,1) = B(1,2)
write (*,*) 'A before DSYGV', A
ITYPE = 1
call DSYGV(ITYPE, JOBZ, UPLO, N, A, LDA, B, LDB, W, WORK, LWORK, INFO)
write (*,*) 'A after DSYGV', A
end program eigen_test
By gfortran eigen.f90 -L/opt/OpenBLAS/lib -lopenblas, (I tried to call it from lopenblas), I got
after A dsyev 6.4512101403162237E-003 -0.99997919072734975 -0.99997919072734975 -6.4512101403162237E-003
A before dgeev 1.0000000000000000 0.20000000000000001 0.20000000000000001 1.0000000000000000
A after dgeev 1.2000000000000000 0.0000000000000000 0.0000000000000000 0.79999999999999993
VR 0.70710678118654746 0.70710678118654746
A before DSYGV 1.0000000000000000 0.20000000000000001 0.20000000000000001 1.0000000000000000
A after DSYGV 6.4512101403162237E-003 -0.99997919072734975 -0.99997919072734975 -6.4512101403162237E-003
I expect the eigenvector to be -0.70710678118654746 0.70710678118654746 or 0.70710678118654746 0.70710678118654746, which can be verified from https://www.emathhelp.net/calculators/linear-algebra/eigenvalue-and-eigenvector-calculator/?i=%5B%5B1%2C0.2%5D%2C%5B0.2%2C1%5D%5D
but it is similar to the result from dgeev, not dsyev or DSYGV. My question is, why dsyev and DSYGV provide different results? Should I somehow input in an upper triangle type of array A?
How do I write out data from an unformatted file in the terminal, in Fortran?
Is it possible to do something similar to:
write(*,*) file_with_data
The reason is that I'm using a program where I try to run this code in a do loop:
read(lun) Vl0
But I get an error message in the first iteration. The error message is
"forrtl: severe (67): input statement requires too much data, unit 99" (lun=99)
So I'm trying to understand why there is a mismatch between the amount of data in the lun-file and the allocated array Vlm. Because I don't really understand why there is a mismatch. I thought it would be a good idea to print the data from the lun file and the pre-allocated array for Vlm to see if they match in size.
For further details of the code see below:
The error message appears when the program uses a specific subroutine. Here is a part of the subroutine. I have only selected the lines that I find relevant (The entire subroutine is much longer).
double complex, allocatable :: Vlm(:)
allocate (Vlm((grid%Lmax+1)**2))
open(lun, file=vgrdfile,iostat=ios,form='unformatted')
read(lun) ! Skip the header
do i = 1, grid%nrp
read(lun) Vlm !Error appears here
end
When I run the program that uses this subroutine I get an error message "forrtl: severe (67): input statement requires too much data, unit 99" (lun=99). In the test I'm running, grid%Lmax=1. So Vlm is really allocated as allocate (Vlm(4)). So for every iteration it should read a line in lun and store that to Vlm. So in the end Vlm should be a double complex array with 4 columns and grid%nrp rows.
The vgrdfile is named chiral-RNN1000-Vlm-L01-R0400-NR00004 and is generated by the following fortran code called potV_chiral.f95 :
program h_pot
integer(kind=4) :: lmax, nr, lmax_pot
real(kind=8) :: rmax
integer(kind=1) :: spherical, linear, even
integer :: i
real(kind=8) :: pi, r
double complex, allocatable :: Vc(:)
real, allocatable :: Vr(:)
real, allocatable :: Vi(:)
nr = 4
lmax = 1
lmax_pot = 1
rmax = 400d0
spherical = 0
linear = 0
even = 0
pi = acos(-1d0)
allocate (Vc( (lmax+1)**2 ))
allocate (Vr( (lmax+1)**2 ))
allocate (Vi( (lmax+1)**2 ))
open(1,file="chiral-RNN1000-Vlm-L01-R0400-NR00004",form="unformatted")
open(2,file="test.txt",form="formatted")
write(1) lmax,nr,rmax,spherical,linear,even !Creating header
do i = 1, nr
do l=1, (lmax_pot+1)**2
read(*,*) Vr(l), Vi(l)
Vc(l)=dcmplx(Vr(l),Vi(l))
end do
write(1) Vc
write(2,*) Vc
end do
close(1)
end program h_pot
The unformatted vgrdfile is created writing "f95 potV_chiral.f95" and "./a.out <complex_sample "
Where the complex_sample file consists of two columns:
1.0 1.0
1.0 2.0
1.0 1.0
1.0 0.0
1.0 2.0
1.0 1.0
2.0 0.0
2.0 1.0
0.0 1.0
1.0 1.0
3.0 1.0
2.0 1.0
2.0 1.0
5.0 1.0
5.0 1.0
-1.0 1.0
The test.txt file looks like this:
( 1.00000000 , 1.00000000 ) ( 1.00000000 , 2.00000000 ) ( 1.00000000 , 1.00000000 ) ( 1.00000000 , 0.00000000 )
( 1.00000000 , 2.00000000 ) ( 1.00000000 , 1.00000000 ) ( 2.00000000 , 0.00000000 ) ( 2.00000000 , 1.00000000 )
( 0.00000000 , 1.00000000 ) ( 1.00000000 , 1.00000000 ) ( 3.00000000 , 1.00000000 ) ( 2.00000000 , 1.00000000 )
( 2.00000000 , 1.00000000 ) ( 5.00000000 , 1.00000000 ) ( 5.00000000 , 1.00000000 ) ( -1.00000000 , 1.00000000 )
Note that I have very little experience with Fortran and working with binary files.
Edit: As #IanBush suggested. It might be because there is insufficient data. But personally I suspect that the reason is that I store the data in the unformatted file wrong, and not so much because of too little or too much data.
The reason for this is that In the code I can run a similar case, where I instead make a double-precision array (with a different dimension) and create the unformatted file by reading a single data column. This case works perfectly.
double precision, allocatable :: Vl0(:)
! File header
integer(kind=1) :: head_sym(3)
integer(kind=4) :: head_lmax, head_nr
real(kind=8) :: head_rmax
lun = 99
open(lun, file=vgrdfile,iostat=ios,form='unformatted')
read(lun) head_lmax,head_nr,head_rmax,head_sym
close(lun)
open(lun, file=vgrdfile,iostat=ios,form='unformatted')
read(lun) ! Skip the header
allocate (Vl0(head_lmax+1))
do i = 1, grid%nrp
read(lun) Vl0 !works
end
Where the program I use to create the vgridfile is
program pot1
integer(kind=4) :: lmax, nr
real(kind=8) :: rmax
integer(kind=1) :: spherical, linear, even
integer :: i
real(kind=8) :: pi, r
double precision, allocatable :: vl0(:)
pi = acos(-1d0)
lmax=2
nr=4
rmax=160
spherical=0
linear=1
even=1
open(1,file="hyd_lineven-RNN1000-Vlm-L02-R0160-NR01024",form="unformatted")
open(2,file="output_lineven",form="formatted")
write(1) lmax,nr,rmax,spherical,linear,even
! Linear and even potential saved as
! V00(r1) V20(r1) V40(r1) V60(r1) ...
! V00(r2) V20(r2) V40(r2) V60(r2) ...
! ...
! V00(rn) V20(rn) V40(rn) V60(rn) ...
allocate ( vl0(lmax+1) )
do i=1,nr
read(*,*) vl0
write(*,*) vl0
write(1) vl0
write(2,*) vl0
end do
close(1)
end program pot1
Where the output_even.txt looks like this
0.0000000000000000 0.0000000000000000 0.0000000000000000
-22.687409291590601 0.0000000000000000 0.0000000000000000
-11.343704645795301 0.0000000000000000 0.0000000000000000
-7.5624697638635299 0.0000000000000000 0.0000000000000000
I'd like to use FFTW to compute the Fourier Harmonics for a 2D dataset. And I think I'm getting the hang of it but I need to 'decipher' the complex output in terms of harmonics. First here's my toy code:
PROGRAM FFTW_TEST
USE, intrinsic :: iso_c_binding
IMPLICIT NONE
INTEGER :: i, j, n, m, l, k
REAL :: pi2, norm, norm2
REAL(C_DOUBLE), POINTER, DIMENSION(:) :: theta, func
COMPLEX(C_DOUBLE_COMPLEX), POINTER, DIMENSION(:) :: fmn_1d
REAL(C_DOUBLE), POINTER, DIMENSION(:,:) :: func_2d, r_2d, i_2d
COMPLEX(C_DOUBLE_COMPLEX), POINTER, DIMENSION(:,:) :: fmn_2d
INCLUDE 'fftw3.f03'
TYPE(C_PTR) :: plan
TYPE(C_PTR) :: real_1d, complex_1d
TYPE(C_PTR) :: real_2d, complex_2d
pi2 = 8.0 * ATAN(1.0)
!------ 1D Example
n = 64
real_1d = FFTW_ALLOC_REAL(INT(n,C_SIZE_T))
complex_1d = FFTW_ALLOC_COMPLEX(INT(n,C_SIZE_T))
CALL C_F_POINTER(real_1d, func, [n])
CALL C_F_POINTER(complex_1d, fmn_1d, [n])
ALLOCATE(theta(n))
FORALL(i=1:n) theta(i) = DBLE(i-1)/DBLE(n)
FORALL(i=1:n) func(i) = 1.0+2.0*cos(2*pi2*theta(i))-3.0*cos(3*pi2*theta(i)) ! Even Values
! FORALL(i=1:n) func(i) = 0.0+2.0*sin(4*pi2*theta(i))-3.0*sin(5*pi2*theta(i)) ! Odd Values
WRITE(401,*) func(1:n)
CALL FLUSH(401)
norm = n/2
norm2 = n
plan = FFTW_PLAN_DFT_R2C_1D(n, func, fmn_1d, FFTW_ESTIMATE)
CALL FFTW_EXECUTE_DFT_R2C(plan, func, fmn_1d)
CALL FFTW_DESTROY_PLAN(plan)
func = REAL(fmn_1d)/norm
func(1) = 2*func(1)
WRITE(402,*) func; CALL FLUSH(402)
func = -AIMAG(fmn_1d)/norm
func(1) = 2*func(1) ! note should be zero
WRITE(403,*) func; CALL FLUSH(403)
plan = FFTW_PLAN_DFT_C2R_1D(n, fmn_1d, func, FFTW_ESTIMATE)
CALL FFTW_EXECUTE_DFT_C2R(plan, fmn_1d, func)
CALL FFTW_DESTROY_PLAN(plan)
WRITE(404,*) func/norm2; CALL FLUSH(404)
CALL FFTW_FREE(real_1d)
CALL FFTW_FREE(complex_1d)
IF (ASSOCIATED(theta)) DEALLOCATE(theta)
!------- 2D Example
m=16
n=8
real_2d = FFTW_ALLOC_REAL(INT(m*n,C_SIZE_T))
complex_2d = FFTW_ALLOC_COMPLEX(INT(m*n,C_SIZE_T))
CALL C_F_POINTER(real_2d, func_2d, [m,n])
CALL C_F_POINTER(complex_2d, fmn_2d, [m,n])
PRINT *,LBOUND(func_2d,DIM=1)
ALLOCATE(fmn_1d(m),r_2d(m,n),i_2d(m,n))
func_2d = 0.5
DO i = 1, m
DO j = 1, n
DO l = 0, 8
DO k = -4,4
func_2d(i,j) = func_2d(i,j) + (l*100+k) * cos(l*pi2*(i-1)/m + k*pi2*(j-1)/n)
END DO
END DO
END DO
WRITE(501,*) func_2d(i,1:n); CALL FLUSH(501)
END DO
! Note in the m direction we read m=0,1,2,3,4...
! in the n direction we read n=0..nx/2,-nx/2+1...-1
norm = m*n/2
norm2 = norm*2
plan = FFTW_PLAN_DFT_R2C_2D(n, m, func_2d, fmn_2d, FFTW_ESTIMATE)
CALL FFTW_EXECUTE_DFT_R2C(plan, func_2d, fmn_2d)
CALL FFTW_DESTROY_PLAN(plan)
r_2d = REAL(fmn_2d)/norm
r_2d(1,1) = r_2d(1,1)/2
DO i = 1, m
WRITE(502,*) r_2d(i,1:n); CALL FLUSH(502)
END DO
i_2d = -AIMAG(fmn_2d)/norm
i_2d(1,1) = i_2d(1,1)/2
DO i = 1, m
WRITE(503,*) i_2d(i,1:n); CALL FLUSH(503)
END DO
DO i = 1, m
DO j = 1, n
IF (abs(r_2d(i,j))>1.0E-5 .or. ABS(i_2d(i,j))>1.0E-5) &
WRITE(6,*) i,j,r_2d(i,j),i_2d(i,j)
END DO
END DO
plan = FFTW_PLAN_DFT_C2R_2D(n, m, fmn_2d, func_2d, FFTW_ESTIMATE)
CALL FFTW_EXECUTE_DFT_C2R(plan, fmn_2d, func_2d)
CALL FFTW_DESTROY_PLAN(plan)
DO i = 1, m
WRITE(504,*) func_2d(i,1:n)/norm2; CALL FLUSH(504)
END DO
CALL FFTW_FREE(real_2d)
CALL FFTW_FREE(complex_2d)
IF (ASSOCIATED(fmn_1d)) DEALLOCATE(fmn_1d)
END PROGRAM FFTW_TEST
Now I'd like to extract the harmonics of a function which looks like:
$A_{mn} \cos(m\theta+n\phi)$, where $\theta$ and $\phi$ are the real-space grid. First, taking the real part of the complex array appears to be correct. The harmonics seem correct for simple functions. However, in the final test case it seems that the array has an odd ordering. Here's the ordering
m/n
0/0 1/0 2/0 3/0 4/0 5/0 6/0 7/0 8/0 0/1 1/1 2/1 3/1 4/1 5/1 6/1
7/1 8/1 0/2 1/2 2/2 3/2 4/2 5/2 6/2 7/2 8/2 0/3 1/3 2/3 3/3 4/3
5/3 6/3 7/3 8/3 0/4 1/4 2/4 3/4 5/4 6/4 7/4 8/4 ?/? ?/? ?/? ?/?
For reference here's what I'd expect the ordering to look like:
m/n
0/0 1/0 2/0 3/0 4/0 5/0 6/0 7/0 8/0 -7/0 -6/0 -5/0 -4/0 -3/0 -2/0 -1/0
0/1 1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 -7/1 -6/1 -5/1 -4/1 -3/1 -2/1 -1/1
0/2 1/2 2/2 3/2 4/2 5/2 6/2 7/2 8/2 -7/2 -6/2 -5/2 -4/2 -3/2 -2/2 -1/2
It seems like the code is just treating the array like a linear array. But what what I can read in the FFTW documentation this should not be the case. One dimension of the array should correspond to the transforms along one dimension and the other the other. Thus in some sense we should be able to read off m and n harmonics.
Can someone explain how the complex array should be ordered in terms of harmonics and the proper normalizations?
I posted a similar question few weeks ago (iso_c_binding calling C routine with pointers from Fortran with arrays) and I found a solution to my problem.
Now I modified few things and I am having some problems again.
In the following a simplified version of my problem.
I have a main program in 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
Which use a subroutine containing the interface for the C routine:
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
and this is the C routine:
#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;
}
If I compile and run the program, this is what I get:
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 after = 1.6999999880790710 1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
Notice that before putting the variable "spin" everything was working. It could read the input array, make the opration, and give the right output.
Now that I added ths variable, there are some problems for the C routine in reading what I'm passing and I cannot understand what's wrong.
Any suggestion ?
(Consider that in the real case I'm going to pass several variables as well as 2 input and 2 output arrays with dimension 4).
Many thanks in advance!!
Change your interface to:
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
Your C function takes a double rather than double* so you need to pass the scalar with the value attribute so that the Fortran knows to pass by value rather than its default pass by reference.
With this small change (and some minor changes to your C to actually print the values of m and phi) this is the output of your example code:
% ./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
i try to solve this simple three body problem with the following code:
Program Main
Implicit real*8 (A-H,O-Z)
real*8 ome,mu, rho, R
duepi=8*datan(1.d0)
ome=1
mu=0.001
T_per=duepi/ome
rho=0.1
R=1.0
N_step=100
c Open the file
OPEN(unit=11, file="prova1.txt")
c Nested do loops
do iy0=1,100
do iP0=1,100
c Calc value for 0
y0 = real(iy0)/100.
x0 = 0
c Calc value for py0
py0 = real(iP0)/100.
px0 = 0
x=x0
y=y0
px=px0
py=py0
dt=T_per/N_step
E0=H(x,y,px,py)
k_max=100*N_step
k=0
t=0
errh=0
c---------
c start integration loop
c--------
do k=1,k_max
call sym4(x,y,px,py,dt)
E= H(x,y,px,py)
errh=abs(E-E0)
t=k*dt
enddo
do k=1,k_max
call sym4(x,y,px,py,-dt)
E= H(x,y,px,py)
errh=abs(E-E0)
t=t-dt
enddo
write(11,*) y0, py0, errh
enddo ! iP0
enddo ! iy0
close(11)
end
subroutine sym1(x,y,px,py,dt)
Implicit real*8 (A-H,O-Z)
c
call f(x,y,fx,fy)
pxnew=px+dt*fx
pynew=py+dt*fy
xnew=x+dt*pxnew
ynew=y+dt
c
x=xnew
y=ynew
px=pxnew
py=pynew
end
subroutine sym1_B(x,y,px,py,dt)
Implicit real*8 (A-H,O-Z)
c
xnew=x+dt*px
ynew=y+dt
call f(xnew,ynew,fxnew,fynew)
pxnew=px+dt*fxnew
pynew=py+dt*fynew
c
x=xnew
y=ynew
px=pxnew
py=pynew
end
subroutine f(x,y,fx,fy)
Implicit real*8 (A-H,O-Z)
real*8 ome,mu,rho,R
fx = ((1-mu)*(rho+x))/((rho*rho+2*rho*x+y*y)**(1.5)) -
& (mu*(R+x))/((R**2-2*R*x+x*x+y*y)**(1.5))
fy = ((1-mu)*(rho+x))/((rho**2+x**2+2*rho*x+y**2)**(1.5))/
& + (mu*y)/((R**2-2*R*x+x**2+y**2)**(1.5))
return
end
real*8 function H(x,y,px,py)
Implicit real*8 (A-H,O-Z)
real*8 ome,mu,rho,R
c h=px*px/2.d0+ py +(1+eps*cos(ome*y))*x*x/2
c h=px*px/2.d0+ py -(1+eps*cos(ome*y))*cos(x)
r12 = sqrt( ( (x*cos(ome*y)-y*sin(ome*y))+rho*cos(ome*y) )**2
& + ( x*sin(ome*y)+y*cos(ome*y) + rho*sin(ome*y) )**2 )
r13 = sqrt( ( (x*cos(ome*y)-y*sin(ome*y))-R*cos(ome*y) )**2
& + ( x*sin(ome*y)+y*cos(ome*y) - R*sin(ome*y) )**2 )
h=(px**2+py**2)/2.d0 - (1-mu)/r12 - mu/r13 + py
return
end
subroutine sym2(x,y,px,py,dt)
Implicit real*8 (A-H,O-Z)
call f(x,y,fx,fy)
xnew= x+ px*dt + fx*dt**2/2.d0
ynew= y+ dt ! così è giusto
call f(xnew,ynew,fxnew,fynew)
pxnew= px+ dt*(fx+fxnew )/2.d0
pynew= py+ dt*(fy+fynew )/2.d0
x=xnew
y=ynew
px=pxnew
py=pynew
end
subroutine sym4(x,y,px,py,dt)
Implicit real*8 (A-H,O-Z)
sq2=2**(1.d0/3.d0)
alpha= 1.d0/(2-sq2)
beta= sq2/(2-sq2)
dt1= dt*alpha
dt2=-dt*beta
call sym2(x,y,px,py,dt1)
call sym2(x,y,px,py,dt2)
call sym2(x,y,px,py,dt1)
return
end
the code calls sympletic integrators and solve the 3body problem. But when i try to run it, there aren't compiling errors, the output.txt file show only the initial grid and not the errh this column give me only NaN, can someone help me?
Is maybe an initial condition errors (strange initial conditions for velocities or positions, omega is wrong ...)?
As stated already in the comments, your program has many code style problems (wrong intentation, ...) as well as not using best Fortran practises (e.g. implicit none). Your problem can be solved by trivial usage of a debugger.
An obvious problem is that you are using uninitialized variables in the functions:
subroutine f(x,y,fx,fy) : rho, mu, R in calculation of fx and fy, which produces NaN
function H() : ome, rho, mu, ...
and similarly on other places