This is a program that finds roots of a polynomial - fortran

This program approximates the roots of the polynomial using the false position method. The program prompts the user to input the coefficients of the polynomial, root approximations, and number of iterations. The code won't compile because of the error.
I don't understand why the line after Do while gives an Unclassifiable statement at (1) error.
integer aNew,bNew,cNew,dNew,eNew, n
real funcA, funcB, funcC, X0, X1, X2
Write(*,*) 'Please enter the coefficients for the polynomial'
Write(*,*) 'polynomial should be no more than order 4'
PRINT*, 'Enter values of A,B,C,D,E'
READ(*,*) aNew,bNew,cNew,dNew,eNew
Write(*,*) 'Enter initial approximation, '
Write(*,*) 'the values should be between -5 and 5 '
Read(*,*) X0,X1
Write(*,*) 'Enter number of tolerance (number of search iterations) '
Read(*,*) n
DO 10 I = 1,n
funcA = CALL F(aNew,bNew,cNew,dNew,eNew,X1)
funcB = CALL F(aNew,bNew,cNew,dNew,eNew,X0)
X2 = (X0*funcA - X1*funcB)/(funcA - funcB)
funcC = CALL F(aNew,bNew,cNew,dNew,eNew, X2)
IF(funcA*funcC .LT. 0.0)THEN
X0 = X2
ELSE
X1 = X2
END IF
10 Continue
Write(*,*) 'Value of the root',X2
CONTAINS
FUNCTION F(A,B,C,D,E,x)
integer A,B,C,D,E
real F
F = A*x**4 + B*x**3 + C*x**2 + D*x + E
END FUNCTION F
END Program

There were a few errors in your code.
Missing type declaration for i. Edit the following line to
integer aNew,bNew,cNew,dNew,eNew, i, n
Incorrect calling of a function F(). Remove the call keyword
funcA = F(aNew,bNew,cNew,dNew,eNew,X1)
Missing declaration for x in F(). Edit the following line
real F,x
The following are not errors, but best practices
Do not rely on implicit typing for variable declarations. Add the implicit none keyword under each program and each module.
Replace the do/continue loop with do/end do
Add intent(in) keywords for dummy arguments where applicable. Also declare function return type before function declaration, or using a result statement.
real FUNCTION F(A,B,C,D,E,x)
integer, intent(in) :: A,B,C,D,E
real, intent(in) :: x
F = A*x**4 + B*x**3 + C*x**2 + D*x + E
END FUNCTION F
Here is the full code with the above corrections
program Console1
implicit none
integer aNew,bNew,cNew,dNew,eNew, i, n
real funcA, funcB, funcC, X0, X1, X2
Write(*,*) 'Please enter the coefficients for the polynomial'
Write(*,*) 'polynomial should be no more than order 4'
PRINT*, 'Enter values of A,B,C,D,E'
READ(*,*) aNew,bNew,cNew,dNew,eNew
Write(*,*) 'Enter initial approximation, '
Write(*,*) 'the values should be between -5 and 5 '
Read(*,*) X0,X1
Write(*,*) 'Enter number of tolerance (number of search iterations) '
Read(*,*) n
DO I = 1,n
funcA = F(aNew,bNew,cNew,dNew,eNew,X1)
funcB = F(aNew,bNew,cNew,dNew,eNew,X0)
X2 = (X0*funcA - X1*funcB)/(funcA - funcB)
funcC = F(aNew,bNew,cNew,dNew,eNew, X2)
IF(funcA*funcC .LT. 0.0)THEN
X0 = X2
ELSE
X1 = X2
END IF
END DO
Write(*,*) 'Value of the root',X2
CONTAINS
real FUNCTION F(A,B,C,D,E,x)
integer, intent(in) :: A,B,C,D,E
real, intent(in) :: x
F = A*x**4 + B*x**3 + C*x**2 + D*x + E
END FUNCTION F
end program Console1
Note that because the function F() is defined within the program scope, and after the contains keyword, it does not need an interface block definition. If you move the function to another file (not inside a module) then you would might need to define an interface block with the function header.

Related

Is there any way in fortran such that real 4 or real 8 can be defined from outside?

We know we can optimise our code from outside.
We know in fortran programming we define variables first in the program. Then we can take inputs from outside (via read statements) but can we make a small code that take kind of variable from outside.
I.e. if we put in the terminal 4 kind 4(i.e.real(kind =4) ) variable is introduced ie if we put 8 kind 8(i.e real(kind=8) variable is introduced . Is there any way.
I know we can do three separate if loops to define the variables (namely kind 4 , kind 8 ,kind 16 and repeat the program the program three times ).
The code i wrote was for findinding value of y using eulers method.
I want to generalise to any kind and calculate the time taken. I hope this can be done in lesser cumbersome way.
The code I wrote:
program euler
implicit none
real(kind=4)::t,h,y,s,e,r
real(kind=8)::t8,h8,y8,s8,e8,r8
real(kind=16)::t16,h16,y16,s16,e16,r16
integer::k,i
t=0
t8=0
t16=0
y=10
y8=10
y16=10
print *,"enter the kind you want to work with"
read(*,*) k
!so if user writes 4 kind 4 variables would do the work
if(k==4) then
print *,"enter the grid step"
read(*,*) h
r=10*exp(-5.0)
call cpu_time(s)
do i=1,999999999
if(0.le.t.and.t.le.25) then
y=y-h*y/5.0
t=t+h
end if
end do
call cpu_time(e)
print *,"solution is",y
print *,"the error is",(r-y)/r
print *,"time taken in seconds =",e-s
else if(k==8) then
print *,"enter the grid step"
read(*,*) h8
r8=10*exp(-5.0D0)
call cpu_time(s8)
do i=1,999999999
if(0.le.t8.and.t8.le.25) then
y8=y8-h8*y8/5.0
t8=t8+h8
end if
end do
call cpu_time(e8)
print *,"solution is",y8
print *,"the error is",(r8-y8)/r8
print *,"time taken in seconds for kind 8 =",e8-s8
else if(k==16) then
print *,"enter the grid step"
read(*,*) h16
r16=10*exp(-5.0D0)
call cpu_time(s16)
do i=1,999999999
if(0.le.t16.and.t16.le.25) then
y16=y16-h16*y16/5.0
t16=t16+h16
end if
end do
call cpu_time(e16)
print *,"solution is",y16
print *,"the error is",(r16-y16)/r16
print *,"time taken in seconds for kind 16 =",e16-s16
end if
end program euler
But im looking something more smart and less cumbersome.
I don't think this is 100% what you want because there are still three separate subroutines each for a different kind, but they are called using the interface euler which determines which one to use based on the arguments
program SO_Euler
use iso_fortran_env, only : sp=>real32, dp=>real64, qp=>real128, i4=>int32, i8=>int64
implicit none
interface euler
procedure euler_driver_sp, euler_driver_dp, euler_driver_qp
end interface
real(sp), parameter :: r4 = 10*exp(-5.0)
real(dp), parameter :: r8 = 10*exp(-5d0)
real(qp), parameter :: r16 = 10*exp(-5q0)
real(sp) :: h
print *,"enter the grid step"
read(*,*) h
print *, ""
call euler(r4, h)
call euler(r8, h)
call euler(r16, h)
contains
subroutine euler_driver_sp(r,h_in)
real(sp), intent(in) :: r
real(sp), intent(in) :: h_in
real(sp) :: h, y, t
integer(i8) :: s, e, rate
integer :: i
print '(a15,1x,g0)', "kind is ", kind(r)
h = h_in
t = 0
y = 10
call SYSTEM_CLOCK(s,rate)
do i=1,999999999
if(0<=t .and. t<=25) then
y=y-h*y/5
t=t+h
else
exit
end if
end do
call SYSTEM_CLOCK(e,rate)
print '(a15,1x,g0.15)',"solution is", y
print '(a15,1x,g0.15)',"the error is", (r-y)/r
print '(a15,1x,g0.4,1x,a)',"time taken is", real(e-s)/rate,"seconds"
print *, ""
end subroutine
subroutine euler_driver_dp(r, h_in)
real(dp), intent(in) :: r
real(sp), intent(in) :: h_in
real(dp) :: h, y, t
integer(i8) :: s, e, rate
integer :: i
print '(a15,1x,g0)', "kind is ", kind(r)
h = h_in !! convert sp=>dp
t = 0
y = 10
call SYSTEM_CLOCK(s,rate)
do i=1,999999999
if(0<=t .and. t<=25) then
y=y-h*y/5
t=t+h
else
exit
end if
end do
call SYSTEM_CLOCK(e,rate)
print '(a15,1x,g0.15)',"solution is", y
print '(a15,1x,g0.15)',"the error is", (r-y)/r
print '(a15,1x,g0.4,1x,a)',"time taken is", real(e-s)/rate,"seconds"
print *, ""
end subroutine
subroutine euler_driver_qp(r, h_in)
real(qp), intent(in) :: r
real(sp), intent(in) :: h_in
real(qp) :: h, y, t
integer(i8) :: s, e, rate
integer :: i
print '(a15,1x,g0)', "kind is ", kind(r)
h = h_in ! convert sp=>qp
t = 0
y = 10
call SYSTEM_CLOCK(s,rate)
do i=1,999999999
if(0<=t .and. t<=25) then
y=y-h*y/5
t=t+h
else
exit
end if
end do
call SYSTEM_CLOCK(e,rate)
print '(a15,1x,g0.15)',"solution is", y
print '(a15,1x,g0.15)',"the error is", (r-y)/r
print '(a15,1x,g0.4,1x,a)',"time taken is", real(e-s)/rate,"seconds"
print *, ""
end subroutine
end program
here is some sample output of the procedure
enter the grid step
0.000002
kind is 4
solution is .547848604619503E-01
the error is .186920538544655
time taken is .1020 seconds
kind is 8
solution is .673793765102040E-01
the error is .138737586862949E-05
time taken is .7200E-01 seconds
kind is 16
solution is .673793765102226E-01
the error is .138737559174033E-05
time taken is 1.535 seconds
Note that I am compiling in 64bit release mode, and have floating-point model not fast, but strict as well as the option to extend the precision of real constants.

Why do I get run time error Reference at undefined variable?

I am using the Runge-Kutta 4th order method to integrate the motion of a point like satellite. The compilation of the program is OK. But when I try to run it Run time error 112
Reference at undefined variable,array element or function result (/UNDEF)
shows up at line 19. I have changed the loop condition many times and nothing changes. I am pretty sure I have declared every quantity that appears in line 19 (where I write the equation for K1). The code I am using is in Fortran 95.
The code:
program SatelliteMonopoleNoDrag
implicit none
real, external :: F1,F2,F3,F4
real :: t,x,y,u,v,K0,K1,K2,K3,M0,M1,M2,M3,N0,N1,N2,N3,P0,P1,P2,P3,h
print*, " Insert t0 "
read*, t
print*, " Insert x0 "
read*, x
print*, " Insert y0 "
read*, y
print*, " Insert u0 "
read*, u
print*, " Insert v0 "
read*, v
print*, " Insert h "
read*, h
do while (t<=86400)
K0=h*F1(t,x,y,u,v)
K1=h*F1(t+h/2.,x+K0/2.,y+M0/2.,u+N0/2.,v+P0/2.)
K2=h*F1(t+h/2.,x+K1/2.,y+M1/2.,u+N1/2.,v+P1/2.)
K3=h*F1(t+h,x+K2,y+M2,u+N2,v+P2)
M0=h*F2(t,x,y,u,v)
M1=h*F2(t+h/2.,x+K0/2.,y+M0/2.,u+N0/2.,v+P0/2.)
M2=h*F2(t+h/2.,x+K1/2.,y+M1/2.,u+N1/2.,v+P1/2.)
M3=h*F2(t+h,x+K2,y+M2,u+N2,v+P2)
N0=h*F3(t,x,y,u,v)
N1=h*F3(t+h/2.,x+K0/2.,y+M0/2.,u+N0/2.,v+P0/2.)
N2=h*F3(t+h/2.,x+K1/2.,y+M1/2.,u+N1/2.,v+P1/2.)
N3=h*F3(t+h,x+K2,y+M2,u+N2,v+P2)
P0=h*F4(t,x,y,u,v)
P1=h*F4(t+h/2.,x+K0/2.,y+M0/2.,u+N0/2.,v+P0/2.)
P2=h*F4(t+h/2.,x+K1/2.,y+M1/2.,u+N1/2.,v+P1/2.)
P3=h*F4(t+h,x+K2,y+M2,u+N2,v+P2)
x=x+(1/6.)*(K0+2*K1+2*K2+K3)
y=y+(1/6.)*(M0+2*M1+2*M2+M3)
u=u+(1/6.)*(N0+2*N1+2*N2+N3)
v=v+(1/6.)*(P0+2*P1+2*P2+P3)
t=t+h
print*, " The values of t,x,y,u,v are " ,t,x,y,u,v
end do
print*, " The values of t,x,y,u,v are " , t,x,y,u,v
end
real function F1(t,x,y,u,v)
real :: t,x,y,u,v
F1=u
end
real function F2(t,x,y,u,v)
real :: t,x,y,u,v
F2=v
end
real function F3(t,x,y,u,v)
real, parameter :: G=6.674*(10.)**(-11)
real, parameter :: M=5.9722*10**(24)
real :: t,x,y,u,v
F3=-G*M*x/(sqrt(x**2+y**2))**3
end
real function F4(t,x,y,u,v)
real, parameter :: G=6.674*(10.)**(-11)
real, parameter :: M=5.9722*10**(24)
real :: t,x,y,u,v
F4=-G*M*y/(sqrt(x**2+y**2))**3
end
M0, M1, M2, N0,N1,N2, and P0,P1,P2 aren't initialized in your first iteration, but you use their value for the calulation of the Ks

How to fix solution with double integration

The solution for this double integration is -0.083 but in the final compliation it appears -Infinity. It seems that the error is very simple, but I really can't find it.
I have been searching specially in the module section but I don't see why it appears like -Infinity. For example, if you change the two functions between them (x in f2 and x^2 in f1) the solution for the integration is 0.083 and the code gives it correct. Can annyone find the error? Thanks a lot.
module funciones
contains
function f(x,y)
implicit none
real*8:: x,y,f
f=2d0*x*y
end function
function f1(x)
real*8::x,f1
f1=x
end function
function f2(x)
real*8::x,f2
f2=x**2d0
end function
function g(x,c,d,h)
implicit none
integer::m,j
real*8::x,y,c,d,k,s,h,g
m=nint(((d-c)/h)+1d0)
k=(d-c)/dble(m)
s=0.
do j=1d0,m-1d0
y=c+dble(j)*k
s=s+f(x,y)
end do
g=k*(0.5d0*(f(x,c)+f(x,d))+s)
return
end function
subroutine trapecio(a,b,n,integral)
implicit none
integer::n,i
real*8::a,b,c,d,x,h,s,a1,a2,b1,b2,integral
h=(b-a)/dble(n)
s=0d0
do i=1d0,n-1d0
x=a+dble(i)*h
c=f1(x)
d=f2(x)
s=s+g(x,c,d,h)
end do
a1=f1(a)
a2=f2(a)
b1=f1(b)
b2=f2(b)
integral=h*(0.5d0*g(a,a1,a2,h)+0.5d0*g(b,b1,b2,h)+s)
end subroutine
end module
program main
use funciones
implicit none
integer::n,i
real*8::a,b,c,d,x,s,h,integral
print*, "introduzca los valores de a, b y n"
read(*,*) a, b, n
call trapecio (a,b,n,integral)
print*,integral
end program
The main program is simple, just calling the subroutine and using the module. It also prints the final result.
First of all, like mentioned in the comments: your problem is not clear. Which input parameters a, b and n do you use and which result do you expect?
Other than that: the code you posted used deprecated features and non-standard types and bad code style.
Some general hints:
real*8 is non-standard Fortran. Use real(real64) instead. real64 has to be imported by use :: iso_fotran_env, only: real64.
non-integer expressions (do i=1d0,n-1d0) in do-loops are a deleted feature in modern Fortran. Use integers instead.
code should be formatted with white spaces and indentations
print*, should be replaced with write(*,*)
code should always use English names
write implicit none in the beginning of the module, not for every function.
make the module/program interface clear by using the statements private, public, and only
if You want to convert to type real, use the function REAL instead of DBLE
I prefer the cleaner function definition using result
use intent keywords: intent(in) passes the variable as a const reference.
the variables c,d,x,s,h in the main program are unused. Compile with warnings to detect unused variables.
This is the code changed with the suggestions I made:
module funciones
use :: iso_fortran_env, only: real64
implicit none
private
public :: trapecio, r8
integer, parameter :: r8 = real64
contains
function f(x,y) result(value)
real(r8), intent(in) :: x,y
real(r8) :: value
value = 2._r8*x*y
end function
function f1(x) result(value)
real(r8), intent(in) :: x
real(r8) :: value
value = x
end function
function f2(x) result(value)
real(r8), intent(in) :: x
real(r8) :: value
value = x**2._r8
end function
function g(x,c,d,h) result(value)
real(r8), intent(in) :: x, c, d, h
real(r8) :: value
real(r8) :: y, k, s
integer :: m, j
m = NINT(((d-c)/h)+1._r8)
k = (d-c)/REAL(m, r8)
s = 0._r8
do j = 1, m-1
y = c + REAL(j,r8)*k
s = s + f(x,y)
end do
value = k*(0.5_r8*(f(x,c)+f(x,d))+s)
end function
subroutine trapecio(a, b, n, integral)
real(r8), intent(in) :: a, b
integer, intent(in) :: n
real(r8), intent(out) :: integral
integer :: i
real(r8) :: c, d, x, h, s, a1, a2, b1, b2
h = (b-a)/REAL(n,r8)
s = 0._r8
do i = 1, n-1
x = a + REAL(i,r8)*h
c = f1(x)
d = f2(x)
s = s + g(x,c,d,h)
end do
a1 = f1(a)
a2 = f2(a)
b1 = f1(b)
b2 = f2(b)
integral = h*(0.5_r8*g(a,a1,a2,h) + 0.5_r8*g(b,b1,b2,h) + s)
end subroutine
end module
program main
use funciones, only: trapecio, r8
implicit none
integer :: n,i
real(r8) :: a,b,integral
write(*,*) "introduzca los valores de a, b y n"
read(*,*) a, b, n
call trapecio (a,b,n,integral)
write(*,*) integral
end program

Rank 1 Transposition in Fortran-95 - Recursive I/O Operation Error [duplicate]

I'm trying to learn Fortran (unfortunately a necessity for my research group) - one of the tasks I set myself was to package one of the necessary functions (Associated Legendre polynomials) from the Numerical Recipes book into a fortran 03 compliant module. The original program (f77) has some error handling in the form of the following:
if(m.lt.0.or.m.gt.1.or.abs(x).gt.1)pause 'bad arguments in plgndr'
Pause seems to have been deprecated since f77 as using this line gives me a compiling error, so I tried the following:
module sha_helper
implicit none
public :: plgndr, factorial!, ylm
contains
! numerical recipes Associated Legendre Polynomials rewritten for f03
function plgndr(l,m,x) result(res_plgndr)
integer, intent(in) :: l, m
real, intent(in) :: x
real :: res_plgndr, fact, pll, pmm, pmmp1, somx2
integer :: i,ll
if (m.lt.0.or.m.gt.l.or.abs(x).gt.1) then
write (*, *) "bad arguments to plgndr, aborting", m, x
res_plgndr=-10e6 !return a ridiculous value
else
pmm = 1.
if (m.gt.0) then
somx2 = sqrt((1.-x)*(1.+x))
fact = 1.
do i = 1, m
pmm = -pmm*fact*somx2
fact = fact+2
end do
end if
if (l.eq.m) then
res_plgndr = pmm
else
pmmp1 = x*(2*m+1)*pmm
if(l.eq.m+1) then
res_plgndr = pmmp1
else
do ll = m+2, l
pll = (x*(2*ll-1)*pmmp1-(ll+m-1)*pmm)/(ll-m)
pmm = pmmp1
pmmp1 = pll
end do
res_plgndr = pll
end if
end if
end if
end function plgndr
recursive function factorial(n) result(factorial_result)
integer, intent(in) :: n
integer, parameter :: RegInt_K = selected_int_kind(20) !should be enough for the factorials I am using
integer (kind = RegInt_K) :: factorial_result
if (n <= 0) then
factorial_result = 1
else
factorial_result = n * factorial(n-1)
end if
end function factorial
! function ylm(l,m,theta,phi) result(res_ylm)
! integer, intent(in) :: l, m
! real, intent(in) :: theta, phi
! real :: res_ylm, front_block
! real, parameter :: pi = 3.1415926536
! front_block = sqrt((2*l+1)*factorial(l-abs(m))/(4*pi*))
! end function ylm
end module sha_helper
The main code after the else works, but if I execute my main program and call the function with bad values, the program freezes before executing the print statement. I know that the print statement is the problem, as commenting it out allows the function to execute normally, returning -10e6 as the value. Ideally, I would like the program to crash after giving a user readable error message, as giving bad values to the plgndr function is a fatal error for the program. The function plgndr is being used by the program sha_lmc. Currently all this does is read some arrays and then print a value of plgndr for testing (early days). The function ylm in the module sha_helper is also not finished, hence it is commented out. The code compiles using gfortran sha_helper.f03 sha_lmc.f03 -o sha_lmc, and
gfortran --version
GNU Fortran (GCC) 4.8.2
!Spherical Harmonic Bayesian Analysis testbed for Lagrangian Dynamical Monte Carlo
program sha_analysis
use sha_helper
implicit none
!Analysis Parameters
integer, parameter :: harm_order = 6
integer, parameter :: harm_array_length = (harm_order+1)**2
real, parameter :: coeff_lo = -0.1, coeff_hi = 0.1, data_err = 0.01 !for now, data_err fixed rather than heirarchical
!Monte Carlo Parameters
integer, parameter :: run = 100000, burn = 50000, thin = 100
real, parameter :: L = 1.0, e = 1.0
!Variables needed by the program
integer :: points, r, h, p, counter = 1
real, dimension(:), allocatable :: x, y, z
real, dimension(harm_array_length) :: l_index_list, m_index_list
real, dimension(:,:), allocatable :: g_matrix
!Open the file, allocate the x,y,z arrays and read the file
open(1, file = 'Average_H_M_C_PcP_boschi_1200.xyz', status = 'old')
read(1,*) points
allocate(x(points))
allocate(y(points))
allocate(z(points))
print *, "Number of Points: ", points
readloop: do r = 1, points
read(1,*) x(r), y(r), z(r)
end do readloop
!Set up the forwards model
allocate(g_matrix(harm_array_length,points))
!Generate the l and m values of spherical harmonics
hloop: do h = 0, harm_order
ploop: do p = -h,h
l_index_list(counter) = h
m_index_list(counter) = p
counter = counter + 1
end do ploop
end do hloop
print *, plgndr(1,2,0.1)
!print *, ylm(1,1,0.1,0.1)
end program sha_analysis
Your program does what is known as recursive IO - the initial call to plgndr is in the output item list of an IO statement (a print statement) [directing output to the console] - inside that function you then also attempt to execute another IO statement [that outputs to the console]. This is not permitted - see 9.11p2 and p3 of F2003 or 9.12p2 of F2008.
A solution is to separate the function invocation from the io statement in the main program, i.e.
REAL :: a_temporary
...
a_temporary = plgndr(1,2,0.1)
PRINT *, a_temporary
Other alternatives in F2008 (but not F2003 - hence the [ ] parts in the first paragraph) include directing the output from the function to a different logical unit (note that WRITE (*, ... and PRINT ... reference the same unit).
In F2008 you could also replace the WRITE statement with a STOP statement with a message (the message must be a constant - which wouldn't let you report the problematic values).
The potential for inadvertently invoking recursive IO is part of the reason that some programming styles discourage conducting IO in functions.
Try:
if (m.lt.0.or.m.gt.l.or.abs(x).gt.1) then
write (*, *) "bad arguments to plgndr, aborting", m, x
stop
else
...
end if

Print to standard output from a function defined in an Fortran module

I'm trying to learn Fortran (unfortunately a necessity for my research group) - one of the tasks I set myself was to package one of the necessary functions (Associated Legendre polynomials) from the Numerical Recipes book into a fortran 03 compliant module. The original program (f77) has some error handling in the form of the following:
if(m.lt.0.or.m.gt.1.or.abs(x).gt.1)pause 'bad arguments in plgndr'
Pause seems to have been deprecated since f77 as using this line gives me a compiling error, so I tried the following:
module sha_helper
implicit none
public :: plgndr, factorial!, ylm
contains
! numerical recipes Associated Legendre Polynomials rewritten for f03
function plgndr(l,m,x) result(res_plgndr)
integer, intent(in) :: l, m
real, intent(in) :: x
real :: res_plgndr, fact, pll, pmm, pmmp1, somx2
integer :: i,ll
if (m.lt.0.or.m.gt.l.or.abs(x).gt.1) then
write (*, *) "bad arguments to plgndr, aborting", m, x
res_plgndr=-10e6 !return a ridiculous value
else
pmm = 1.
if (m.gt.0) then
somx2 = sqrt((1.-x)*(1.+x))
fact = 1.
do i = 1, m
pmm = -pmm*fact*somx2
fact = fact+2
end do
end if
if (l.eq.m) then
res_plgndr = pmm
else
pmmp1 = x*(2*m+1)*pmm
if(l.eq.m+1) then
res_plgndr = pmmp1
else
do ll = m+2, l
pll = (x*(2*ll-1)*pmmp1-(ll+m-1)*pmm)/(ll-m)
pmm = pmmp1
pmmp1 = pll
end do
res_plgndr = pll
end if
end if
end if
end function plgndr
recursive function factorial(n) result(factorial_result)
integer, intent(in) :: n
integer, parameter :: RegInt_K = selected_int_kind(20) !should be enough for the factorials I am using
integer (kind = RegInt_K) :: factorial_result
if (n <= 0) then
factorial_result = 1
else
factorial_result = n * factorial(n-1)
end if
end function factorial
! function ylm(l,m,theta,phi) result(res_ylm)
! integer, intent(in) :: l, m
! real, intent(in) :: theta, phi
! real :: res_ylm, front_block
! real, parameter :: pi = 3.1415926536
! front_block = sqrt((2*l+1)*factorial(l-abs(m))/(4*pi*))
! end function ylm
end module sha_helper
The main code after the else works, but if I execute my main program and call the function with bad values, the program freezes before executing the print statement. I know that the print statement is the problem, as commenting it out allows the function to execute normally, returning -10e6 as the value. Ideally, I would like the program to crash after giving a user readable error message, as giving bad values to the plgndr function is a fatal error for the program. The function plgndr is being used by the program sha_lmc. Currently all this does is read some arrays and then print a value of plgndr for testing (early days). The function ylm in the module sha_helper is also not finished, hence it is commented out. The code compiles using gfortran sha_helper.f03 sha_lmc.f03 -o sha_lmc, and
gfortran --version
GNU Fortran (GCC) 4.8.2
!Spherical Harmonic Bayesian Analysis testbed for Lagrangian Dynamical Monte Carlo
program sha_analysis
use sha_helper
implicit none
!Analysis Parameters
integer, parameter :: harm_order = 6
integer, parameter :: harm_array_length = (harm_order+1)**2
real, parameter :: coeff_lo = -0.1, coeff_hi = 0.1, data_err = 0.01 !for now, data_err fixed rather than heirarchical
!Monte Carlo Parameters
integer, parameter :: run = 100000, burn = 50000, thin = 100
real, parameter :: L = 1.0, e = 1.0
!Variables needed by the program
integer :: points, r, h, p, counter = 1
real, dimension(:), allocatable :: x, y, z
real, dimension(harm_array_length) :: l_index_list, m_index_list
real, dimension(:,:), allocatable :: g_matrix
!Open the file, allocate the x,y,z arrays and read the file
open(1, file = 'Average_H_M_C_PcP_boschi_1200.xyz', status = 'old')
read(1,*) points
allocate(x(points))
allocate(y(points))
allocate(z(points))
print *, "Number of Points: ", points
readloop: do r = 1, points
read(1,*) x(r), y(r), z(r)
end do readloop
!Set up the forwards model
allocate(g_matrix(harm_array_length,points))
!Generate the l and m values of spherical harmonics
hloop: do h = 0, harm_order
ploop: do p = -h,h
l_index_list(counter) = h
m_index_list(counter) = p
counter = counter + 1
end do ploop
end do hloop
print *, plgndr(1,2,0.1)
!print *, ylm(1,1,0.1,0.1)
end program sha_analysis
Your program does what is known as recursive IO - the initial call to plgndr is in the output item list of an IO statement (a print statement) [directing output to the console] - inside that function you then also attempt to execute another IO statement [that outputs to the console]. This is not permitted - see 9.11p2 and p3 of F2003 or 9.12p2 of F2008.
A solution is to separate the function invocation from the io statement in the main program, i.e.
REAL :: a_temporary
...
a_temporary = plgndr(1,2,0.1)
PRINT *, a_temporary
Other alternatives in F2008 (but not F2003 - hence the [ ] parts in the first paragraph) include directing the output from the function to a different logical unit (note that WRITE (*, ... and PRINT ... reference the same unit).
In F2008 you could also replace the WRITE statement with a STOP statement with a message (the message must be a constant - which wouldn't let you report the problematic values).
The potential for inadvertently invoking recursive IO is part of the reason that some programming styles discourage conducting IO in functions.
Try:
if (m.lt.0.or.m.gt.l.or.abs(x).gt.1) then
write (*, *) "bad arguments to plgndr, aborting", m, x
stop
else
...
end if