lifetime of variables and static arrays in Fortran - fortran

I heard that, in Fortran77, all local variables in a function are created at the beginning of the main program execution and exist during the whole runtime, rather than being created on entry to the function and being destroyed on exit. I do not know whether this is still true in newer Fortran. Is there any way that can test this out?
One test that meight help is to check whether variables retain their values between invocations. Here is a simple test:
program main
call p()
call p()
call p()
end program main
subroutine p()
real :: a(3)
a=a+1
write(*,*) a(1), a(2), a(3)
end subroutine p
My test using gfortran indicates array a retains its values between invocations, the same behavior as save attribute being used.
I am wondering whether this is a standard in Fortran Language or depends on compiler implementations.

Such a test cannot prove anything. The fact that some garbage remains in the stack between two function invocations can be a pure coincidence.
Local function variables are only valid during the function invocation in which their value was defined. That is also true in Fortran 77. If the value should be retained, the variables hhave to be declared SAVE.

Just for fun, we can try a program where some other routine (e.g.foo()) may be called between successive calls of p():
program main
call p()
! call foo() ! (*)
call p()
! call foo() ! (*)
call p()
end
subroutine p()
real :: a(3)
a = a + 1
write(*,*) "a = ", a
end
subroutine foo()
real :: b(3)
b = b * 10
write(*,*) "b = ", b
end
With the lines (*) commented, we get
! gfortran-8.2
a = 1.00000000 4.74066630E+21 1.00000000
a = 2.00000000 4.74066630E+21 2.00000000
a = 3.00000000 4.74066630E+21 3.00000000
! PGI18.10
a = 1.000000 1.000000 1.000000
a = 2.000000 2.000000 2.000000
a = 3.000000 3.000000 3.000000
while with the lines (*) uncommented, we get
! gfortran-8.2
a = 1.00000000 4.74066630E+21 1.00000000
b = 10.0000000 4.74066641E+22 10.0000000
a = 11.0000000 4.74066641E+22 11.0000000
b = 110.000000 4.74066623E+23 110.000000
a = 111.000000 4.74066623E+23 111.000000
! PGI18.10
a = 1.000000 1.000000 1.000000
b = 0.000000 0.000000 0.000000
a = 2.000000 2.000000 2.000000
b = 0.000000 0.000000 0.000000
a = 3.000000 3.000000 3.000000
(This is just an experiment/illustration of the behavior of local variables (i.e. not necessarily "SAVE-ed" as it might appear in a simpler case), and please see the other answer and comments for detailed explanations.)

Related

How do I print/write data from unfomatted file?

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

Unexpected behaviour for Fortran, C++ API [duplicate]

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

Trouble loading simple mesh into OpenGL

I need to import a 3D object mesh into my OpenGL code on Visual Studio 2010. I'm relateively new to OpenGL so I've been learning from the following tutorial (Number 7):
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-7-model-loading/
Now, the tutorial uses a simple code rather than a library to import ".obj" files
Those who've used the tutorial will know that the "cube.obj" that has been provided by the creator of the tutorial works just fine.
However, the moment I try loading my own simple cube mesh, the program notifies me that "Our simple parser cannot handle the .obj file. Please try exporting with other options".
I figured this to be a problem with the code and moved on to his Assimp tutorial:
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/
This time around, "Suzanne.obj" has been provided as a sample. Yet again, whenever I try exporting my own object into the code, the program now crashes saying "Visual Studio has stopped working". This only occurs with the objects I export.
In an attempt to narrow down the cause of the problem, I used the "cube.obj" provided in Tutorial 7 with Tutorial 9, and it worked just fine. So it seems for now as though the issue lies in the export of the object from Blender.
I've followed all the instructions in Tutorial 7 regarding to what options need be checked while exporting objects. It is worth noting however, the ".obj" code of the objects I export appear in a single line without any line breaks. This is the obj code of a simple cube mesh I exported:
# Blender v2.73 (sub 0) OBJ File: 'ROOM.blend'
# www.blender.org
mtllib room.mtl
o Cube_Cube.004
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 1.000000 1.000000 1.000000
vn -1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
usemtl None
s off
f 6//1 2//1 1//1
f 7//2 3//2 2//2
f 8//3 4//3 3//3
f 5//4 1//4 4//4
f 2//5 3//5 4//5
f 7//6 6//6 5//6
f 5//1 6//1 1//1
f 6//2 7//2 2//2
f 7//3 8//3 3//3
f 8//4 5//4 4//4
f 1//5 2//5 4//5
f 8//6 7//6 5//6
The .obj code of the cube provided in the tutorial in comparison is as follows:
# Blender3D v249 OBJ File: untitled.blend
# www.blender3d.org
mtllib cube.mtl
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.748573 0.750412
vt 0.749279 0.501284
vt 0.999110 0.501077
vt 0.999455 0.750380
vt 0.250471 0.500702
vt 0.249682 0.749677
vt 0.001085 0.750380
vt 0.001517 0.499994
vt 0.499422 0.500239
vt 0.500149 0.750166
vt 0.748355 0.998230
vt 0.500193 0.998728
vt 0.498993 0.250415
vt 0.748953 0.250920
vn 0.000000 0.000000 -1.000000
vn -1.000000 -0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn -0.000001 0.000000 1.000000
vn 1.000000 -0.000000 0.000000
vn 1.000000 0.000000 0.000001
vn 0.000000 1.000000 -0.000000
vn -0.000000 -1.000000 0.000000
usemtl Material_ray.png
s off
f 5/1/1 1/2/1 4/3/1
f 5/1/1 4/3/1 8/4/1
f 3/5/2 7/6/2 8/7/2
f 3/5/2 8/7/2 4/8/2
f 2/9/3 6/10/3 3/5/3
f 6/10/4 7/6/4 3/5/4
f 1/2/5 5/1/5 2/9/5
f 5/1/6 6/10/6 2/9/6
f 5/1/7 8/11/7 6/10/7
f 8/11/7 7/12/7 6/10/7
f 1/2/8 2/9/8 3/13/8
f 1/2/8 3/13/8 4/14/8
On debugging the crashed program, the following exception occurs:
Unhandled exception at 0x00007FF76255E2D5 in tutorial09_AssImp.exe:
0xC0000005: Access violation reading location 0x0000000000000000.
The call stack is as follows:
tutorial09_AssImp.exe!aiVector3t::aiVector3t(const aiVector3t & o) Line 67 C++
tutorial09_AssImp.exe!loadAssImp(const char * path,
std::vector > & indices,
std::vector,std::allocator
& vertices, std::vector,std::allocator
& uvs, std::vector,std::allocator
& normals) Line 149 C++ tutorial09_AssImp.exe!main() Line 92 C++
Moreover, the exception occurs in vector3.h which looks as so:
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2012, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** #file aiVector3D.h
* #brief 3D vector structure, including operators when compiling in C++
*/
#ifndef AI_VECTOR3D_H_INC
#define AI_VECTOR3D_H_INC
#include <math.h>
#include "./Compiler/pushpack1.h"
#ifdef __cplusplus
template<typename TReal> class aiMatrix3x3t;
template<typename TReal> class aiMatrix4x4t;
// ---------------------------------------------------------------------------
/** Represents a three-dimensional vector. */
template <typename TReal>
class aiVector3t
{
public:
aiVector3t () : x(), y(), z() {}
aiVector3t (TReal _x, TReal _y, TReal _z) : x(_x), y(_y), z(_z) {}
explicit aiVector3t (TReal _xyz) : x(_xyz), y(_xyz), z(_xyz) {}
aiVector3t (const aiVector3t& o) : x(o.x), y(o.y), z(o.z) {} //exception generated here
public:
// combined operators
const aiVector3t& operator += (const aiVector3t& o);
const aiVector3t& operator -= (const aiVector3t& o);
const aiVector3t& operator *= (TReal f);
const aiVector3t& operator /= (TReal f);
// transform vector by matrix
aiVector3t& operator *= (const aiMatrix3x3t<TReal>& mat);
aiVector3t& operator *= (const aiMatrix4x4t<TReal>& mat);
// access a single element
TReal operator[](unsigned int i) const;
TReal& operator[](unsigned int i);
// comparison
bool operator== (const aiVector3t& other) const;
bool operator!= (const aiVector3t& other) const;
template <typename TOther>
operator aiVector3t<TOther> () const;
public:
/** #brief Set the components of a vector
* #param pX X component
* #param pY Y component
* #param pZ Z component */
void Set( TReal pX, TReal pY, TReal pZ);
/** #brief Get the squared length of the vector
* #return Square length */
TReal SquareLength() const;
/** #brief Get the length of the vector
* #return length */
TReal Length() const;
/** #brief Normalize the vector */
aiVector3t& Normalize();
/** #brief Componentwise multiplication of two vectors
*
* Note that vec*vec yields the dot product.
* #param o Second factor */
const aiVector3t SymMul(const aiVector3t& o);
TReal x, y, z;
} PACK_STRUCT;
typedef aiVector3t<float> aiVector3D;
#else
struct aiVector3D {
float x,y,z;
} PACK_STRUCT;
#endif // __cplusplus
#include "./Compiler/poppack1.h"
#ifdef __cplusplus
#endif // __cplusplus
#endif // AI_VECTOR3D_H_INC
Apparently I'm not doing something right while exporting my models. What could I possible be doing wrong? Is there a step I'm missing?
The program crashes at line 149 of objloader.cpp (says the callstack)
This line is about UV coordinates.
You model doesn't have any, which should ring a bell =)
You will have the same problem with normals, btw.
So, you have 2 options :
Make the object have UVs and normals
Make the loader support meshes without UVs or normals.
Since you'll need them anyway, I'd recommend the first one.
In Blender :
For the UVs, go to edit mode, select all vertices ('A' key), mesh->UVs->automatic unwrap ; If you struggle, Tutorial 15 contains a video which shows everything you need.
For normals, just tick the "export normals" option when exporting to OBJ.
In any case, the output OBJ must have v (position), vn (normals), vt (UVs) and f (connectivity between the 'v's )
EDIT : Explanation on why the top of the callstack talks about aiVector3Dt :
line 148 is
aiVector3D UVW = mesh->mTextureCoords[0][i];
UVW is a copy of mesh->mTextureCoords[0][i], which doesn't point to a valid place in memory, because the buffer wasn't allocated, because your OBJ doesn't have any. So the constructor (in the callstack : aiVector3Dt::aiVector3Dt() ) crashes when trying to copy this memory block to UVW. There's a small difference here, because the crash happens one line later, but it's just a compiler optimization. So, the code of aiVector3D is perfectly correct, but you're giving him a bad adress. You can see this in the debugger by setting the current frame to loadAssImp(), and spy on mesh->mTextureCoords[0].

ISO_C_BINDING Calling C routine from Fortran (with doubles and arrays)

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

c++ stof() function wrong after working multiple times

I have written a function that reads an obj. file and converts the strings into floats. The code worked fine untill the stof() function stops working properly. I'm not sure how this part suddenly stops working since it seems such a straight-forward thing to do and it has worked everytime untill now.
ftemp = std::stof(stemp);
ftemp and stemp (storage for float and string) are declared at the beginning of my function and are overwritten for each number. I use fstream and iterators to find the numbers. The rest of the code is easy to imagine and works as expected so I'll ommit everything but the failing part.
this is in the .obj file and should represent a textured plane.
# Blender v2.68 (sub 0) OBJ File: ''
# www.blender.org
v -1.000000 1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v -1.000000 1.000000 1.000000
v 1.000000 1.000000 1.000000
vt 0.000100 0.000100
vt 0.999900 0.000100
vt 0.000100 0.999900
vt 0.999900 0.999900
s off
f 2/1 1/2 4/3
f 1/2 3/4 4/3
It fails at the point it reads the vt lines. So when stemp holds "0.000100" ftemp should hold 0.000100 yet it holds: 9.9999997e-005. The rest works the same way and does it correctly.
Any help would be greatly appreciated.
It's correct. IEEE754 for single precision which float implements, guarantees accuracy up to around 7 significant digits.
9.9999997e-005 is 0.00000999999997 so its close enough.