This question already has answers here:
Fortran function in a module not found by subroutine in the same module [duplicate]
(1 answer)
Why is this a function declared inside the module and then used somewhere else in the same module not seen by the linker?
(2 answers)
Closed 4 years ago.
I am trying to get familiarize with modules in fortran and for that I have created a simple code with module. The source code is attached.
MAIN PROGRAM
program main_prog
use mod_f_g_h
!
implicit none
! f,g,h,s are defined in mod_f_g_h
real :: x,y
!
! read x,y
print *, "enter x and y "
read*, x, y
!
! check
if( y == 0 ) then
print*, "y must be non-zero"
stop
end if
!
! print on screen
print*, ' x = ', x
print*, ' y = ', y
print*, 'x + y = ', f(x,y)
print*, 'x * y = ', g(x,y)
print*, 'x * x = ', s(x)
print*, 'y * y = ', s(y)
print*, 'x / y = ', h(x,y)
end program main_prog
MODULE
module mod_f_g_h
!
! use other modules
implicit none
!
contains
!
real function s(x)
implicit none
real :: x,g
s = g(x,x)
end function s
!
real function f(x,y)
implicit none
real :: x,y
f = x+y
end function f
!
real function g(x,y)
implicit none
real :: x,y
g = x*y
end function g
!
real function h(x,y)
implicit none
real :: x,y
h = x/y
end function h
end module mod_f_g_h
But when I try to compile and link the code, using
gfortran -c mod_f_g_h.f90
gfortran -c main.f90
gfortran *.o -o run.x
Got the following error (in last step)
mod_f_g_h.o: In function `__mod_f_g_h_MOD_s':
mod_f_g_h.f90:(.text+0xb6): undefined reference to `g_'
collect2: ld returned 1 exit status
I think, I have defined all the variables, moreover I am not linking any external library, so I don't know why this error is appearing? Any comment/idea?
It should read
real function s(x)
implicit none
real :: x
s = g(x,x)
end function s
inside the module.
Further explanation by VladimirF:
By real g you were declaring the function g inside s as an external real function distinct from that one in the module.
Related
My goal is to find a way to call Fortran subroutine in Excel VBA (can be found on Prof Alan Genz. The program is MVNPACK) to compute the CDF of multivariate normal distribution. Ideally, I would like to be able to use a version of DLL compiled from that source code in a C# project as well in the future. However, I am not sure how to troubleshoot and proceed further. I typically code in Python, have some exposure in C, Java, etc., but never use Fortran and not too familiar with what's going on when one calls a function in a DLL. To the best of my knowledge, this computation is not that widely available, and compiling the Fortran source code is my best bet.
I have been closely following the example here about creating the DLL, and here about using that in Excel VBA, and been trying to mimic the result. Starting from the MVNPACK source code mentioned above, I figured that what I need is to pass the inputs to the subroutine MVNDST, and get the result back by passing the pointers as arguments to the subroutine. So the first thing I did was trying to modify the code based on what the examples did. My modified version MVNDSTC looks like this.
SUBROUTINE MVNDSTC( N, LOWERC, UPPERC, INFINC, CORRELC, MAXPTS,
& ABSEPS, RELEPS, ERRORC, VALUEC, INFORMC)
& bind(c)
use ISO_C_BINDING
implicit none
cGCC$ ATTRIBUTES STDCALL, DLLEXPORT :: MVNDSTC
EXTERNAL MVNDFN
integer(kind=c_long), value:: N, MAXPTS
real(kind=c_double), value:: ABSEPS, RELEPS
type(c_ptr), value:: LOWERC, UPPERC, INFINC, CORRELC
type(c_ptr), value:: ERRORC, VALUEC, INFORMC
real(kind=c_double), dimension(:), pointer:: LOWER, UPPER, CORREL
integer(kind=c_long), dimension(:), pointer:: INFIN
real(kind=c_double), dimension(:), pointer:: ERROR_OUT, VALUE_OUT
integer(kind=c_int), dimension(:), pointer:: INFORM_OUT
INTEGER NN
INTEGER INFORM, INFIS, IVLS
DOUBLE PRECISION ERROR, VALUE, E, D, MVNDNT, MVNDFN
COMMON /DKBLCK/IVLS
NN = (N - 1) * N / 2
call C_F_POINTER(LOWERC, LOWER, [N])
call C_F_POINTER(UPPERC, UPPER, [N])
call C_F_POINTER(INFINC, INFIN, [N])
call C_F_POINTER(CORRELC, CORREL, [NN])
call C_F_POINTER(ERRORC, ERROR_OUT, [1])
call C_F_POINTER(VALUEC, VALUE_OUT, [1])
call C_F_POINTER(INFORMC, INFORM_OUT, [1])
IF ( N .GT. 500 .OR. N .LT. 1 ) THEN
INFORM = 2
VALUE = 0
ERROR = 1
ELSE
INFORM = MVNDNT(N, CORREL, LOWER, UPPER, INFIN, INFIS, D, E)
IF ( N-INFIS .EQ. 0 ) THEN
VALUE = 1
ERROR = 0
ELSE IF ( N-INFIS .EQ. 1 ) THEN
VALUE = E - D
ERROR = 2D-16
ELSE
*
* Call the lattice rule integration subroutine
*
IVLS = 0
CALL DKBVRC( N-INFIS-1, IVLS, MAXPTS, MVNDFN,
& ABSEPS, RELEPS, ERROR, VALUE, INFORM )
ENDIF
ENDIF
VALUE_OUT(0) = VALUE
ERROR_OUT(0) = ERROR
INFORM_OUT(0) = INFORM
END
Then I created a small subroutine with the mvndstc declaration on top. The VBA code is as follows.
Private Declare PtrSafe Sub mvndstc Lib "C:\Users\poopa\Desktop\mvn\mvn_project\fortran-library.dll" _
(ByVal N As Integer, _
ByRef LOWER As Single, _
ByRef UPPER As Single, _
ByRef INFIN As Single, _
ByRef CORREL As Single, _
ByVal MAXPTS As Integer, _
ByVal ABSEPS As Double, _
ByVal RELEPS As Double, _
ByRef ERROR As Single, _
ByRef VALUE As Single, _
ByRef INFORM As Single)
Sub mvn_test()
Dim value_1(1 To 1) As Single ' Result of the function
Dim inform_1(1 To 1) As Single ' Information
Dim error_1(1 To 1) As Single ' Error estimate
Dim upper_1() As Single
Dim lower_1() As Single
Dim infin_1() As Single
Dim correl_1() As Single
Dim n_1 As Long, n_1_2 As Long, max_pts_1 As Long
n_1 = 5
ReDim lower_1(1 To n_1)
ReDim upper_1(1 To n_1)
ReDim infin_1(1 To n_1)
lower_1(1) = 0#
lower_1(2) = 0#
lower_1(3) = 1.7817
lower_1(4) = 0.14755
lower_1(5) = 0#
upper_1(1) = 0#
upper_1(2) = 1.5198
upper_1(3) = 0#
upper_1(4) = 0#
upper_1(5) = 1.5949
infin_1(1) = 1
infin_1(2) = 2
infin_1(3) = 1
infin_1(4) = 1
infin_1(5) = 0
n_1_2 = Int(n_1 / 2 * (n_1 - 1))
ReDim correl_1(1 To n_1_2)
correl_1(1) = -0.707107 ' 12
correl_1(2) = 0# ' 13
correl_1(3) = 0.5 ' 14
correl_1(4) = 0# ' 15
correl_1(5) = 0.5 ' 23
correl_1(6) = 0.5 ' 24
correl_1(7) = 0# ' 25
correl_1(8) = 0.5 ' 34
correl_1(9) = 0.5 ' 35
correl_1(10) = 0.5 ' 45
max_pts_1 = 625000
mvndstc n_1, lower_1(1), upper_1(1), infin_1(1), correl_1(1), max_pts_1, 0.00005, 0, error_1(1), value_1(1), inform_1(1)
Debug.Print "Value = " & (value_1(1))
Debug.Print "Error Est = " & (error_1(1))
Debug.Print "Inform = " & inform_1(1)
End Sub
Now my first attempt I did not modify ERROR, VALUE, INFORM parameters at all and simply declare then in Fortran as theirs respective primitive types. I can actually run the VBA subroutine, but I got all zeros for the results. So I was speculating that the program runs but perhaps I didn't get the result back properly and I should treat these three outputs as pointers with size of 1. That way I just keep whatever procedure exactly the same in Fortran and then if I put VALUE_OUT(0) = VALUE and so on, before the function ends I should be get the results just fine. Right now using the code I posted here, I can actually see the results printed out in VBA, still all zeros, but right after that Excel would immediately crash.
So I want to ask how do I proceed from here? What did I got wrong here? Is there any resource worth looking into?
Thanks in advance.
I fixed this yesterday, the problem is indeed about the data types. When I read the tutorial I was assuming Single is some kind of object type in VBA. Little did I know that Single is actually the single precision of Double! I tried debugging all this by letting the DLL print out all the values inside the function to a file.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
Here is my code for a bisection method. If I input 4 and 5 the program loops infinitely. There is a problem with it running.
Sub TheBisectionMethod1()
Dim a, b As Double 'Taking two variables, A and B
Console.Write(vbLf & "Input A: ")
a = Double.Parse(Console.ReadLine()) 'This is where user inputs and value stored for A
Console.Write(vbLf & "Input B: ")
b = Double.Parse(Console.ReadLine()) 'This is where user inputs and value stored for B
line1:
Dim c As Double
c = (a + b) / 2 'declearing variable c for the sum of half of the user entered values
If ((Math.Abs(func(c))) < 0.0001) Then 'in flow chart the value of C remians unchange so the program will not run, so it will run if i is >0.0001
Console.Write(vbLf & "C : {0}", c)
ElseIf (Math.Sign(func(c)) = Math.Sign(func(a))) Then
Console.WriteLine("Hello")
a = c
GoTo line1
ElseIf (Math.Sign(func(c)) <> Math.Sign(func(a))) Then
b = c
GoTo line1
End If
End Sub
Function func(x As Double) As Double
Dim y As Double
y = x ^ 2 - 2
Return y
End Function
Don't use a GoTo. There's no need. Also, remove the user interaction from the method that does the actual work. Read the data in one place, pass it to a method (usually a Function rather than a Sub) that does the work and returns a result, and then show the result to the user after the function ends.
That makes this question tricky, because the only result we see in the original code is writing "Hello" to the Console, and that's clearly just a debugging statement. What do you want this code to do? (I'm gonna assume you mean this)
Function Bisect(a as Double, b As Double) As Double
Dim c As Double = (a + b) / 2
Dim d As Double = func(c)
While Math.Abs(d) >= 0.0001
If Math.Sign(d) = Math.Sign(func(a)) Then
a = c
Else
b = c
End If
c = (a + b) / 2
d = func(c)
End While
Return c
End Function
Function func(x As Double) As Double
Return x ^ 2 - 2
End Function
And really, it should look like this:
Function Bisect(a as Double, b As Double, f As Function(Of Double, Double)) As Double
Dim c As Double = (a + b) / 2
Dim d As Double = f(c)
While Math.Abs(d) >= 0.0001
If Math.Sign(d) = Math.Sign(f(a)) Then
a = c
Else
b = c
End If
c = (a + b) / 2
d = f(c)
End While
Return c
End Function
and be called like this:
Bisect(a, b, Function(x) x ^ 2 - 2)
Also, the algorithm here is slightly off based the wikipedia article. This is more precise:
Function Bisect(a as Double, b As Double, f As Function(Of Double, Double)) As Double
Dim TOL As Double = 0.0001
Dim MaxSteps As Integer = 1000
Dim c As Double = (a + b) / 2
While Math.Abs(f(c)) >= TOL AndAlso (b-a)/2 >= TOL AndAlso MaxSteps > 0
If Math.Sign(f(c)) = Math.Sign(f(a)) Then
a = c
Else
b = c
End If
MaxSteps -= 1
c = (a + b) / 2
End While
If MaxSteps = 0 Then
Throw New ArgumentException("The bisection fails to converge within the allowed time for the supplied arguments.")
End If
Return c
End Function
I bring it up, because the complaint in the original question is this:
the program loops infinently[sic]
and one of the tenants of the algorithm is it's not guaranteed to converge, hence the step counter.
Finally, this looks to me like it might do well as a recursive function. Recursion can improve things here because we can rely on the call stack overflowing rather than needing to implement a step counter:
Function Bisect(a as Double, b As Double, f As Function(Of Double, Double)) As Double
Dim c As Double = (a + b) / 2
If Math.Abs(f(c)) < TOL OrElse (b-a)/2 < TOL Then Return c
If Math.Sign(f(c)) = Math.Sign(f(a)) Then
Return Bisect(c, b, f)
Else
Return Bisect(a, c, f)
End If
End Function
Of course, catching that StackOverflowException is a trick in itself, so you may still want that step counter. But I need to leave something for you to do yourself.
This also helps demonstrate part of why I recommend removing all user I/O from the Bisect() method. If this method were also responsible for talking to the end user, it would not be possible to even consider the recursive option, where the code is clearly far shorter and simpler than any of the others.
I am trying to write down a Fortran subroutine for my code in order to read a data from a file (which is a huge data set on itself).The data file contains the Location (nx0,ny0,nz0) and the field related to that location (Bx,By,Bz).
(Ex: lets say the range for nx0, ny0 and nz0 is from [-15,15].
so the number of rows will be 31*31*31=29791)
-15.00000 -15.00000 -15.00000 700.00000 -590.00000 100.00000
-15.00000 -15.00000 -14.00000 -110.00000 -570.00000 100.00000
-15.00000 -15.00000 -13.00000 -550.00000 -200.00000 100.00000
-15.00000 -15.00000 -12.00000 -540.00000 -230.00000 100.00000
-15.00000 -15.00000 -11.00000 -140.00000 -50.00000 100.00000
. . . . . .
. . . . . .
. . . . . .
15.00000 15.00000 15.00000 140.00000 50.00000 100.000
What I want to do is to look for a specific location within my file (xi,yi and zi) and read the field related to that location then use it for further analysis. Not only the related field to the target position itself but also the surrounding field of that location (Like the three other side of the square around the target point).
subroutine read_data(xi,yi,zi,Bxij,Byij)
real*8,intent(in) :: xi,yi,zi !,time
real*8,intent(out) :: Bxij(4),Byij(4) !,Bzij(4)
integer,parameter :: step = 1 ,cols = 6, rows = 29791 !!!15,000,000
real,dimension(rows) :: nx0,ny0,nz0,Bx,By,Bz
character*15 filein
character*35 path_file
path_file = '/home/mehdi/Desktop/'
filein= 'test-0001'
open(7,file=trim(path_file)//filein, status='old',action='read')
xi_1 = xi +step
yi_1 = yi +step
do i = 1,rows
read(7,*) nx0(i),ny0(i),nz0(i),Bx(i),By(i),Bz(i)
c
if ( xi == nx0(i) .and. yi == ny0(i) .and.
& zi == nz0(i)) then
Bxij(1) = Bx(i)
Byij(1) = By(i)
cycle
endif
c
if ( xi == nx0(i) .and. yi_1 == ny0(i) .and.
& zi == nz0(i)) then
Bxij(2) = Bx(i)
Byij(2) = By(i)
cycle
endif
c
if ( xi_1 == nx0(i) .and. yi == ny0(i) .and.
& zi == nz0(i)) then
Bxij(3) = Bx(i)
Byij(3) = By(i)
cycle
endif
c
if ( xi_1 == nx0(i) .and. yi_1 == ny0(i) .and.
& zi == nz0(i)) then
Bxij(4) = Bx(i)
Byij(4) = By(i)
exit
endif
c
close(7)
enddo
end
I have done it this way but it is too slow. One of the most important things for me is the speed (which even for this small fraction of data set is really time consuming).
I know this slow mode is for the needs to read the whole data set each time in order to look for the target points. This subroutine is called couple times within the code and for the further steps the code is going to do the same thing over and over again, so it is time consuming.
How can I make this code work more efficiently?
Before I begin this answer, let me reiterate what I said in the comments to your question:
Do not underestimate how much data you can put into a single array. Reading once, and then having everything in memory is still the fastest way possible.
But let's assume that the data really gets too big.
Your main issue seems to be that you have to re-read all the data from the beginning until you find the value you're looking for. That takes the time.
If you can calculate which line of the data file the value you are interested in is, it might help to convert the file into an unformatted direct access file.
Here is an example code for the conversion. It's using Fortran 2008 features, so if your compiler can't do it, you have to modify it:
program convert
use iso_fortran_env, only: real64
implicit none
integer, parameter :: reclength = 6*8 ! Six 8-byte values
integer :: ii, ios
integer :: u_in, u_out
real(kind=real64) :: pos(3), B(3)
open(newunit=u_in, file='data.txt', form='formatted', &
status='old', action='read', access='sequential')
open(newunit=u_out, file='data.bin', form='unformatted', &
status='new', action='write', access='direct', recl=reclength)
ii = 0
do
ii = ii + 1
read(u_in, *, iostat=ios) pos, B
if (ios /= 0) exit
write(u_out, rec=ii) pos, B
end do
close(u_out)
close(u_in)
end program convert
Once you have converted the data, you can read only the record you need, as long as you can calculate which one it is. I have assumed that just like in your example, the z-coordinate changes fastest and the x-coordinate changes slowest.
program read_txt
use iso_fortran_env, only: real64
implicit none
integer, parameter :: nx=601, ny=181, nz=61
real(kind=real64), parameter :: x_min=real(-nx/2, kind=real64)
real(kind=real64), parameter :: y_min=real(-ny/2, kind=real64)
real(kind=real64), parameter :: z_min=real(-nz/2, kind=real64)
real(kind=real64), parameter :: x_step = 1.0_real64
real(kind=real64), parameter :: y_step = 1.0_real64
real(kind=real64), parameter :: z_step = 1.0_real64
real(kind=real64) :: request(3), pos(3), B(3)
integer :: ios, u_in
integer :: ii, jj, kk, record
integer, parameter :: reclength = 6 * 8 ! Six 8-byte values
open(newunit=u_in, file='data.bin', access='direct', form='unformatted', &
status='old', action='read', recl=reclength)
mainloop : do
read(*, *, iostat=ios) request
if (ios /= 0) exit mainloop
write(*, '(A, 3F7.2)') 'searching for ', request
! Calculate record
ii = nint((request(1)-x_min)/x_step)
jj = nint((request(2)-y_min)/y_step)
kk = nint((request(3)-z_min)/z_step)
record = kk + jj * nz + ii * nz * ny + 1
read(u_in, rec=record, iostat=ios) pos, B
if (ios /= 0) then
print *, 'failure to read'
cycle mainloop
end if
write(*, '(2(A, 3F7.2))') "found pos: ", pos, " Bx, By, Bz: ", B
end do mainloop
close(u_in)
end program read_txt
Note that the unformatted is not compiler- and system independent. A file created on one computer or with a program compiled by one compiler might not be able to be read with another program or on another computer.
But if you have control over it, it might be a useful way to speed things up.
PS: I left the x, y, and z coordinates in the file so that you can check whether the values are actually what you wanted. Always good to verify these things.
I need to use Newton's method on closures.
Function f (x as Double, y as Double) as Double
f = x^3-y
End Function
I get the value of y from a cell and then I would like to find out when f is zero. In the toy example above, if the cell contains y=8, then I would expect Newton's method to find a solution close to x=2.
My solution was to make a newton_solve_f function:
Function newton_solve_f (y as Double as Double) as Double
Dim x as Double
x = 0 'initial guess for x
'do Newton's method to find x
...
newton_solve_f = x
End Function
so in effect, I copy paste my code for Newton's method (taken from here) into newton_solve_f.
The problem is that I have several such fs (some with more than two arguments), and it would be really neat if I didn't have to make a separate almost identical newton_solve_f for every one of them.
How would you solve this in VBA?
In Python, for example, it's possible to solve this problem as follows:
def f(y):
def g(x):
return x^3-y
return g
def newton_solve(f):
#do newton's method on f(x)
newton_solve(f(3))
Here f(3) is a function, a closure of one variable. (The closure example on wikipedia is almost identical to this one.)
ps. I know Newton's method also needs the (partial) derivative of f, I'm actually doing something that's more like the secant method, but that's irrelevant for what I'm asking about
Closures are not part of VBA. But you can use static variables within a method scope. They cannot be used outside the method. If you want a variable to visible outside, then you have to use global variable. Preferable declare it public in a module.
We cannot define function inside function in VB. Tried to convert the code given in the link you have mentioned. I hope it helps you. Not well versed with php, but you can see the approach below and make changes accordingly.
Sub Test()
Dim x As Double
Dim y As Double
Dim z As Double
x = Cells(1, 1).Value
y = Cells(1, 2).Value
z = NewtRap("Fun1", "dFun1", x, y)
Cells(1, 3).Value = z
End Sub
Private Function NewtRap(fname As String, dfname As String, x_guess As Double, y_value As Double) As Double
Dim cur_x As Double
Dim Maxiter As Double
Dim Eps As Double
Maxiter = 500
Eps = 0.00001
cur_x = x_guess
For i = 1 To Maxiter
If (fname = "Fun1") Then
fx = Fun1(cur_x)
ElseIf (fname = "dFun1") Then
fx = dFun1(cur_x)
ElseIf (fname = "f") Then
fx = f(cur_x, y_value)
End If
If (dfname = "Fun1") Then
fx = Fun1(cur_x)
ElseIf (dfname = "dFun1") Then
fx = dFun1(cur_x)
ElseIf (dfname = "f") Then
fx = f(cur_x, y_value)
End If
If (Abs(dx) < Eps) Then Exit For
cur_x = cur_x - (fx / dx)
Next i
NewtRap = cur_x
End Function
Function f(x As Double, y As Double) As Double
f = x ^ 3 - y
End Function
Function Fun1(x As Double) As Double
Fun1 = x ^ 2 - 7 * x + 10
End Function
Function dFun1(x As Double) As Double
dFun1 = 2 * x - 7
End Function
So to first summarise: You want to create a function that will find (using Newton-Raphson method) the roots of a function. You already have this written and working for certain functions but would like help expanding your code so it will work with a variety of functions with varying numbers of parameters?
I think you first need to think about what input functions you want it to cover. If you are only dealing with polynomials (as your example suggests), this should be fairly straightforward.
You could have general functions of:
Function fnGeneralCase (x, y, z, w, a1, a2, a3, b1, b2, b3, c1, c2, c3 as Double) as Double
fnGeneralCase = a1*x^3 + a2*x^2 + a3*x + b1*y^3 + b2*y^2 + b3*y + c1*z^3 + c2*z^2 + c3*z + w
End Function
Function fnDerivGeneralCase (x, y, z, w, a1, a2, a3, b1, b2, b3, c1, c2, c3 as Double) as Double
fnDerivGeneralCase = a1*3*x^2 + a2*2*x + a3 + b1*3*y^2 + b2*2*y + b3 + c1*3*z^2 + c2*2*z + c3
End Function
And just set the inputs to zero when you don't need them (which will be for the majority of the time).
So for your example calling:
answer = fnGeneralCase(guess, 0, 0, -8, 1, 0, 0, 0, 0, 0, 0, 0, 0)
basically gives:
function = x^3-8
If you want to include more than polynomials, this will get more complicated but you could still use the above approach...
This seems to be asking 2 related questions:
how to pass a function as an argument in vba.
how to create a closure out of an existing function.
Unfortunately neither of these are really supported, however,
for 1 you can generally work around this by passing a string function name and using 'Application.Run' to invoke the function.
2 is trickier if you have lots of functions with different numbers of parameters, but for a set number of parameters you could add extra parameters to the newton_solve function or maybe use global variables.
e.g.
Public Function f(x as Double, y as Double) as Double
f = x^3-y
End Function
Function newton_solve_f (function_name as String, y as Double) as Double
Dim x as Double
x = 0 'initial guess for x
'do Newton's method to find x
...
' invoke function_name
x = Application.Run(function_name, x, y)
...
newton_solve_f = x
End Function
Assuming f is in a module called 'Module1' you can call this with:
x = newton_solve('Module1.f', 3)
Note that the function you want to call must be public.
I'm at a beginner level in FORTRAN.
I need to use the READ-Opiton END. But i get an Error that there is no END tag label defined...
Here is my Code:
subroutine readfiles
implicit none
integer :: N, l
real, allocatable :: pos(:,:)
N = 2 !Number of Lines
allocate(orte(N,3))
open (unit=99, file='positions.txt', status='old', action='read',)
do l=1,N
read (99,* ,END=999) pos(l,1), pos(l,2), pos(l,3)
enddo
do l=1,N
print *, pos(l,1), pos(l,2), pos(l,3)
enddo
return
END subroutine readfiles
And here is the error:
gfortran -c -O3 -fdefault-real-8 -I/usr/include readfiles.f90
readfiles.f90:22.25:
read (99,* ,END=999) pos(l,1), pos(l,2), pos(l,3)
1
Error: END tag label 999 at (1) not defined
make: *** [readfiles.o] Fehler 1
Any Ideas? Thanks
As the error message indicates, you need a line number labeled 999 to which control is transferred when the end of the file is reached, as shown below.
subroutine readfiles
implicit none
integer :: N, l
real, allocatable :: pos(:,:)
N = 2 !Number of Lines
allocate(orte(N,3))
open (unit=99, file='positions.txt', status='old', action='read',)
do l=1,N
read (99,* ,END=999) pos(l,1), pos(l,2), pos(l,3)
enddo
999 continue
N = l-1
do l=1,N
print *, pos(l,1), pos(l,2), pos(l,3)
enddo
return
END subroutine readfiles
Btw I advise against using variables named "l", since "l" looks like 1.