Unclassifiable statement in Fortran 95 when declaring function - fortran

I would appreciate some help on this. The point of the program is to take a lower bound, an upper bound, and the number of steps, and then input them into the respective chosen equation to create a matrix that is the length of the steps, that contains the values for for the equation that was chosen. I'm getting an unclassifiable statement at:
array(i)=function1(x)
array(i)=function2(x)
array(i)=function3(x)
I feel like it has something to do with how I declared my function, but I cannot figure out a fix to it. Any help would be appreciated.
PROGRAM stuff1
IMPLICIT NONE
!variables
INTEGER::i,step
REAL::lower,upper,function1,function2,function3,x,q,w,e
CHARACTER(20)::option
REAL,ALLOCATABLE::array(:)
!formats
101 FORMAT(A) !single text element only
102 FORMAT() ! <description>
!-------Variable Definitions-------!
!
!
!
!----------------------------------!
!x= .1(upper-lower)
!<Begin Coding Here>
WRITE(*,101)"Hello User, please select a function to evaluate:"
WRITE(*,101)
WRITE(*,101)"A) f(x)=x^2+2x+4"
WRITE(*,101)"B) f(x)=|x+4|"
WRITE(*,101)"C) f(x)=sin(x)+42"
WRITE(*,101)"Enter A,B,or C"
DO
READ(*,101)option
IF ((option.EQ."A") .OR. (option.EQ."a")) THEN
ELSE IF((option.EQ.'B') .OR. (option.EQ.'b'))THEN
ELSE IF((option.EQ.'c') .OR. (option.EQ.'c'))THEN
ELSE
WRITE(*,*)"Please enter A,B,or C"
CYCLE
END IF
EXIT
END DO
WRITE(*,101)"please enter an lower bound:"
READ(*,*)lower
WRITE(*,101)
WRITE(*,101)"please enter an upper bound:"
READ(*,*)upper
WRITE(*,101)
WRITE(*,101)"please enter a step size"
READ(*,*)step
function1=((x**2)+(2*x)+4)
function2=(abs(x+4))
function3=(sin(x)+42)
ALLOCATE(array(step))
x=lower
DO i=1,step
IF ((option.EQ."A") .OR. (option.EQ."a")) THEN
array(i)=function1(x)
ELSE IF((option.EQ.'B') .OR. (option.EQ.'b'))THEN
array(i)=function2(x)
ELSE IF((option.EQ.'c') .OR. (option.EQ.'c'))THEN
array(i)=function3(x)
END IF
x=x+(upper-lower)/step
END DO
DO i=1,step
WRITE(*,'(4F6.2)')array(i)
END DO
END PROGRAM

These lines
function1=((x**2)+(2*x)+4)
function2=(abs(x+4))
function3=(sin(x)+42)
appear to be three statement functions. This is an obsolescent feature which you should not use, instead you should define functions along the lines
real function one(x)
real, intent(in) :: x
one = x**2 + 2*x + 4
end function one
If you must program like it's 1979 then the correct form for a statement function would be
function1(x)=((x**2)+(2*x)+4)
You have omitted the dummy argument in the definitions, it's no surprise to me that the compiler gets angry and issues that error.

That's not how to define a function in Fortran!
After the END PROGRAM, define your functions like:
real function function1(x)
real,intent(in) :: x
function1=((x**2)+(2*x)+4)
end function
real function function2(x)
real,intent(in) :: x
function2=(abs(x+4))
end function
real function function3(x)
real,intent(in) :: x
function3=(sin(x)+42)
end function
Or, even better, put them into a module!

Related

Arrays, functions, variables, and size() in Fortran 90

I'm very new to this language and have an assignment to convert some code from Fortran 77 to 90 and fix the code. I'm supposed to do the following:
Remove the implicit statement.
Convert array notation to fixed-shape [meaning IRAN(32) should be IRAN(:)]
Use the size() function to check the array size.
Any help on what to do here would be greatly appreciated. Based on the source code, I think I'm supposed to make a main program, then make subprogram makevec, which uses permutation function px(i); I'm not sure how to do this. Does this sound correct? What about the names of the variables? I looked up some of them (such as iran) and they seem to be related to random number generator modules (but again, I'm not sure of anything in this paragraph). I also found the modules "mod_kinds.F" and "ran_state.F" online but am not sure if they would help the purpose of this program.
I already removed the implicit statement in my program, declared some variables in the main program, and replaced the if loops with "select case (iran(i)." I also got rid of "return" and made everything lowercase.
Here is the source code :
SUBROUTINE MAKEVEC(NVAR,NOFIX,NRANFIX,IRAN,X,VALFIX,RANFIXEST,PX)
IMPLICIT REAL*8(A-H,O-Z)
DIMENSION IRAN(32),X(30),VALFIX(20),PX(32),RANFIXEST(20)
C THIS ROUTINE, CALLED BY MAIN, INPUTS NVAR, NOFIX, NRANFIX, IRAN,
C X, VALFIX, AND RANFIXEST, AND RETURNS PX(I) = A COMBINATION OF THE
C VALUES IN X, VALFIX, AND RANFIXEST, IN THE PROPER ORDER (AS
C DETERMINED BY IRAN).
NNNVAR = 0
NNNFIX = 0
NNNRANFIX = 0
DO I = 1,NVAR+NOFIX+NRANFIX
IF(IRAN(I) .EQ. 1) THEN
NNNVAR = NNNVAR+1
PX(I) = X(NNNVAR)
ENDIF
IF(IRAN(I) .EQ. 0) THEN
NNNFIX = NNNFIX+1
PX(I) = VALFIX(NNNFIX)
ENDIF
IF(IRAN(I) .EQ. 2) THEN
NNNRANFIX = NNNRANFIX+1
PX(I) = RANFIXEST(NNNRANFIX)
ENDIF
END DO
c write (,) "Initialized IG",NNNVAR,NNNFIX,NNNRANFIX
RETURN
END
This is what I have done so far (I know there is a lot of pseudocode and this won't compile):
program Initialized_IG
implicit none
interface
subroutine makevec(var,nofix,nranfix,iran,x,valfix,&
ranfixest,px)
real, intent (in) :: nvar,nofix,nranfix,iran,x,valfix,&
ranfixest
real, intent (out) :: px(i)
REAL(kind=8) :: i
real, dimension(32) :: iran, px
real, dimension(30) :: x
real, dimension(20) :: valfix, ranfixest
integer :: i,nnnvar,nofix,nranfix,sum
sum = nvar + nofix + nranfix
end interface
nnnvar = 0
nnnfix = 0
nnnranfix = 0
CALL RANDOM_NUMBER(i)
call subroutine makevec
select case (iran(i))
case (1)
nnnvar = nnnvar+1
px(i) = x(nnnvar)
case (0)
nnnfix = nnnfix+1
px(i) = valfix(nnnfix)
case (2)
nnnranfix = nnnranfix+1
px(i) = ranfixest(nnnranfix)
end select
write (*,*) "Initialized IG", nnnvar,nnnfix,nnnranfix
end program Initialized_IG

Call a subroutine for a list of points instead of a single point

I have a certain piece of code in fortran. The code takes 'pq' as an input from the user and is a single point. Instead of doing this I want to read a set of points 'pq' from a file points.txt and run it for those number of points instead of just one single user input. Is it possible? The code is as follows:
program prop
use module
implicit none
character(len=80) :: ErrorMsg
character(2) :: xy
real(8) :: Conc(20) = 0.d0
character(len=20) :: fn, fl
real(8) :: Mmolar, Tcritical, Pcritical, Tmininimum, Tmaximum, x, y
call Init_module()
write(*,*) 'Insert the gas name:'
read(*,*) fn
write(*,*) 'Insert the gas library:'
read(*,*) fl
write(*,*) 'Insert the copule pq:'
read(*,*) pq
write(*,*) 'Insert the value of ', pq(1:1)
read(*,*) x
write(*,*) 'Insert the value of ', pq(2:2)
read(*,*) y
write(*,*) 'Pres = ', Pres( pq, x, y, ErrorMsg)
write(*,*) 'Temp = ', Temperature( pq, x, y, ErrorMsg)
call ReleaseObjects()
end program prop
Instead of reading pq as a single point x,y from the user in the above code, I want to read a set of points from file.txt, for example 50 points and then run subroutines Pres and Temperature.
Each line of the file contains one point x,y and x and y in each line are separated by a few space characters.
The first few lines of file.txt are:
Ts
500
0.04781564 159.81587875
0.20396084 165.46398084
0.08159885 166.81382894
0.03879184 164.17497877
0.12585959 165.37000305
0.09895530 165.95997769
0.10389518 170.74235496
It must be noted that the length and the sign of the floating numbers can vary. The file.txt is originally written through python with the formatting for x, y being '%-12.8f %-12.8f\n'%. I have the following code to try and read the file but am not able to read from the 3rd line onwards:
real, allocatable :: x(:),y(:)
integer :: np
open(12,file=trim('file.txt'),status='old', &
access='sequential', form='formatted', action='read' )
read(12,*)pq
write(*,*)'pq:', pq
read(12,*)np
write(*,*)'number of points:',np
allocate (x(np))
allocate (y(np))
do i=1,np
read(12,*)x(i),y(i)
write(*,*)x(i),y(i)
enddo
Instead of using the READ statement with the asterisk (*) as the first argument asking for an user input, use a file identifier. You need to OPEN your file containing the set of points, assuming it is ASCII :
OPEN(UNIT=10,FILE=file.txt,ACTION='read',STATUS='old')
I think the arguments of this command are quite explanatory.
Then assuming your file contains multiple lines with x and y values, you can read each line of your file by doing :
READ(10,*) x,y
If you have multiple points to read, just use a DO if you know the number of points to read, a DO WHILE otherwise. To take your example with 50 points, something like this should work :
OPEN(UNIT=10,FILE=file.txt,ACTION='read',STATUS='old') ! Open file
DO i=1,50
READ(10,*) x,y
write(*,*) 'Pres = ', Pres( pq, x, y, ErrorMsg)
write(*,*) 'Temp = ', Temperature( pq, x, y, ErrorMsg)
END DO
CLOSE(10) ! Close file
EDIT
Your suggestion is almost correct. You forgot to declare pq as a character(len=2). You should not have been able to pass line 1 because of that.
As I said, there is a space separator that is naturally treated by a asterisk as a format. Anyway, if you want to exactly match the format, use the same with which you wrote your data. Reading your format Python, I assume you wrote two floats with a space separator, and indeed if you count the number of character of your digits :
0.04781564 159.81587875
^^^^^^^^^^^^|^^^^^^^^^^^^
1 12|1 12
|
space
which gives the following format in Fortran :
read(12,'(f12.8,1X,f12.8)') x(i),y(i)
X means a space separator in Fortran formats.
Then you can write you data onscreen with the same format to check :
write(*,'(f12.8,1X,f12.8)') x(i),y(i)
It gives :
pq:Ts
number of points: 500
0.04781564 159.81587219
0.20396084 165.46397400
0.08159885 166.81382751
0.03879184 164.17497253
0.12585959 165.37001038
0.09895530 165.95997620
0.10389518 170.74235535
You may have noticed that you lost precision on the last digits. It is because you have declared a simple real (4 bytes). Switch your real to 8 bytes with real(kind=8) or real*8 according to your compiler (be aware, not the right way to do it, not portable but sufficient in your case)
Do not forget to close your file when you are done dealing with it :
close(12)

I am trying to compile following code wrote in fortran but has many errors

I am trying to compile this following code in gfortran compiler:
do_cmd = .not. is_group
do while (.not. EOF(unit=100) .and. .not. flag_stop)
read (100, '(A)', iostat = ios) buf
if (buf(1:1)=="#") then
! comment line
elseif ((buf(1:2)=="v ") .and. do_cmd) then ! vertex
read(buf(2:), *, iostat=ios) p(1), p(2), p(3)
if (ios.ne.0) then
print "(/,2x,'Error of reading vertex position from obj-file (line #'(I3)');')", line_index
stop
end if
But I get these errors when the code is compiling:
do while (.not. EOF(unit=100) .and. .not. flag_stop)
1
Error: Keyword argument requires explicit interface for procedure ‘eof’ at (1)
and;
do while (.not. EOF(unit=100) .and. .not. flag_stop)
1
Error: Function ‘eof’ at (1) has no IMPLICIT type
I will be so grateful if anyone could help me.
edit:
I'm very new in fortran and couldn't find out how eof function works in gfortran.
What does it mean using unit=100 in argument?
And also Thought it is a logical function by default. How should I implicit its type?
As far as I know, EOF is not part of the Fortran Standard. At least I can't find it anywhere.
In most programming languages, EOF stands for "End of File", and it is fairly obvious to me that the EOF in your example is supposed to be a logical function that returns .TRUE. if and only if the read pointer associated with unit (in your case 100) points to the end of the file.
You can use the ios variable to check whether an EOF was encountered during the read. In that case, it will be -1. You can then use the exit statement to immediately quit the loop.
If you don't like the -1, and you use a Fortran 2003 compatible compiler, you might even use the module ISO_FORTRAN_ENV, which provides (amongst other things) the parameter IOSTAT_END.
Here's a very simple example:
program iso
use ISO_FORTRAN_ENV
implicit none
integer, parameter :: u = 100
character(len=80) :: buf
integer :: ios
open(unit=u, action='READ', status='OLD', file='data.dat')
read_loop : do
read(u, '(A)', iostat=ios) buf
if (ios == IOSTAT_END) exit read_loop ! EOF
if (buf(1:1) == '#') cycle read_loop ! This line is a comment
write(*, *) buf
end do read_loop
close(u)
end program iso
One note though: This code is meant as an example. It only exits the loop if it encounters an EOF -- not if the read fails for any other reason. (There are some other reasons that the the read would fail.) If that other error is persistent, then this will lead to an infinite loop.
It may be useful to try a user-defined EOF function (as shown below) to minimize the amount of code modifications; but because this function is rather inefficient, I guess it is probably better to rewrite the original code so as to utilize iostat in read statements directly (as suggested above)...
module eofmod !<-- please save this in a separate file, compile, and link with other programs
implicit none
contains
logical function EOF( unit )
integer, optional :: unit
integer :: ios
if ( .not. present( unit ) ) stop "no unit given"
read( unit, *, iostat=ios )
if ( ios == -1 ) then
EOF = .true.
else
EOF = .false. ; backspace( unit )
endif
end function
end module
program test
use eofmod !<-- needs to be inserted at the top of routines (or modules) where "EOF" is used
implicit none
character(200) :: buf
open(10, file="test.dat", status="old")
do while ( .not. EOF( unit=10 ) )
read( 10, "(a)" ) buf
print "(a)", trim( buf )
enddo
close(10)
end program

Fortran Coding Advice

I have to develop a linear interpolation program, but keep getting these errors.
Here is the source code:
!Interpolation program for exercise 1 of portfolio
PROGRAM interpolation
IMPLICIT NONE
!Specify table 1 for test of function linter
REAL, DIMENSION (5):: x,f
!Specify results for table 1 at intervals of 1
REAL, DIMENSION (10):: xd, fd
!Specify table 2 to gain linter results
REAL, DIMENSION (9):: xx,ff
!Specify results for table 2 of at intervals of 0.25
REAL, DIMENSION (36):: xxd, ffd
INTEGER :: i, j
!Write values for table dimensions
!Enter x values for Table 1
x(1)=-4.0
x(2)=-2.0
x(3)=0.0
x(4)=2.0
x(5)=4.0
f(1)=28.0
f(2)=11.0
f(3)=2.0
f(4)=1.0
f(5)=8.0
xd(1)=-4.0
xd(2)=-3.0
xd(3)=-1.0
xd(4)=0.0
xd(5)=1.0
xd(6)=2.0
xd(7)=3.0
xd(9)=4.0
!Print Table 1 Array
PRINT *,"Entered Table Values are", x,f
PRINT *,"Interpolation Results for Table 1", xd, fd
END PROGRAM
SUBROUTINE interpol(x,f, xd,fd)
DO i=1, 5
DO j=1, 5
IF (x(j) < xd(i) .AND. xd(i) <= x(j+1)) THEN
fd=linterp (x(j),x(j+1),f(j))
END IF
END DO
END DO
END SUBROUTINE interpol
!Linear Interpolation function
FUNCTION linterp(x(i),x(i+1),f(i),f(i+1),x)
linterp=f(i)+((x-x(i))/(x(i+1)-x(i)))*(f(i+1)-f(i))
END FUNCTION
With it giving these errors;
lin.f90:55:18: Error: Expected formal argument list in function definition at (1)
lin.f90:56:19:
linterp=f(i)+((x-x(i))/(x(i+1)-x(i)))*(f(i+1)-f(i))
1
Error: Expected a right parenthesis in expression at (1)
lin.f90:57:3:
END FUNCTION
1
Error: Expecting END PROGRAM statement at (1)
Could anyone please point me in the right direction?
It is exactly what the compiler complains about: you are missing a right parenthesis.
Either remove the superfluous left (:
linterp=f(i)+ ( x-x(i) ) / ( x(i+1)-x(i) )* ( f(i+1)-f(i) )
or add another )
linterp=f(i)+ ( (x-x(i)) ) / ( x(i+1)-x(i) )* ( f(i+1)-f(i) )
Note that I removed another miss-placed ) in the middle part.
Apart from that, your function declaration is broken! You cannot have x(i) in the declaration!
Try:
real FUNCTION linterp(xI,xIp1,fI,fIp1,x)
implicit none
real, intent(in) :: xI,xIp1,fI,fIp1,x
linterp = fI + (x-xI)/(xIp1-xI)*(fIp1-fI)
END FUNCTION
Alternatively, you can provide the whole arrays (including its length N) and the current index:
real FUNCTION linterp(x,f,N,i,xx)
implicit none
integer, intent(in) :: N
real, intent(in) :: x(N), f(N), xx
integer, intent(in) :: i
linterp = f(i) + (xx-x(i))/( x(i+1)-x(i) )*( f(i+1)-f(i) )
END FUNCTION
In addition to everything Alexander said. You also need to make sure that you have the same amount of inputs in your function declaration as you do when you call it:
fd=linterp (x(j),x(j+1),f(j))
has two less inputs than in your function declaration:
FUNCTION linterp(x(i),x(i+1),f(i),f(i+1),x)
Also, don't forget to add an index to fd, either i or j:
fd(i)=linterp (x(j),x(j+1),f(j))
otherwise you're replacing the entire array with the linterp result every time.

How to execute a number of statements based on a user input variable (fortran90)?

I am writing a Fortran90 subroutine, but the language does not matter for the purpose of this question. Feel free to provide answers in psuedocode if it's more convenient.
I have a number statements (or groups of statements) to execute based on an input parameter. Let the input variable be x and let's call the statements A, B, C,..., N. These statements do not share enough common properties to be combined, and should therefore be executed separately.
The conditions are:
if ( x .eq. 1 ) then
! execute A
endif
if ( x .eq. 2 ) then
! execute A
! execute B
if ( x .eq. 3 ) then
! execute A
! execute B
! execute C
endif
.
.
.
and so on...
(Note that all the ! execute statements are all mathematical calculations and variable assignments. Nothing is printed, no functions are called, etc...)
My attempt to simplify the code turned it into:
if ( x .ge. 1 ) then
! execute A
endif
if ( x .ge. 2 ) then
! execute B
endif
if ( x .ge. 3 ) then
! execute C
endif
.
.
.
This is still too much coding to do for a large value of x. I know that I have to code all the execute statements (and I have already done so), but I am hoping that there is still a faster way to only run the number that the user specifies without having to type over a hundred if statements. Any thoughts on that?
Oh what a shame that computed go to is frowned upon. No self-respecting Fortran programmer in C21 would write something like
...
read(*,*) x
go to (3,2,1) x
1 call C()
2 call B()
3 call A()
Of course, this executes the calls in the reverse order to that specified in the question, but the question also hints that the order doesn't matter.
I'll close this by reminding readers that this is definitely nasty old FORTRAN. Let us not speak of this again
Not exactly an ideal solution since F90 doesn't have function pointers. Could do it in F03 with function pointers but since you have specified F90
subroutine selector(howmany)
integer, intent(in):: howmany
integer:: ii
do ii = 1, howmany
select case(ii)
case (1)
! execute A
case (2)
! execute B
case (3)
! execute C
case default
continue
end select
end do
end subroutine selector
...
call selector(3)
Unlike C, fortran doesn't have a dropthrough
You could use one-line versions of if:
if ( x .ge. 1 ) call ... ! execute A
if ( x .ge. 2 ) call ... ! execute B
...
Or, if processed within a subroutine or function, you could use return:
call ... ! execute A
if ( x .lt. 2 ) return
call ... ! execute B
if ( x .lt. 3 ) return
...
It's also possible to do this in one line per statement:
call ... ; if ( x .lt. 2 ) return ! execute A
call ... ; if ( x .lt. 3 ) return ! execute B
I don't think it will get less than that, even when using function pointers you would have to point them to the corresponding function/subroutine (which also amounts to one line per function)...
What about a recursive subroutine? Something like this:
recursive subroutine select(x)
integer,intent(in) :: x
select case(x)
case(1)
!execute A
case(2)
!execute B
case(3)
!execute C
end select
if(x > 0) call select(x-1)
end subroutine select
Again, this goes backwards, but a forward version shouldn't be too hard. And there's always the stack overflow possibility if you have a lot of these. This is essentially getting rid of the explicit loop in the accepted answer.
I might do something like this:
i=howmany
do while(i.gt.0)
< a code >
i=i-1;if(i.eq.0)exit
< b code >
i=i-1;if(i.eq.0)exit
<c code>
i=i-1;if(i.eq.0)exit
<d code>
exit
enddo
or equivalently use a subroutine with return.
Note this is logically equivalent to where you started, but the conditional line is the same so a lazy typist can quickly do ctrl-y ctrl-y ctrl-y
Another advantage of this is, should you need to edit the lines you can insert/delete a line anywhere without manually reindexing.