Fortran Coding Advice - fortran

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.

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

Set negative values in a array to zero by using the if conditional

I have a function of some variables, which will yield an array consisted of both negative and positive values (Real). But since only positive values are physically meaningful to me, I want to set all negative values inside the array to be zero.
I have provided my code related to this function below:
The reason I declare a temporary variable 'res' is that I try to build in an IF-ELSE in the position I marked in code as follows:
If (res >= 0) Then
result = res
Else
result = 0
End If
But the error says a scalar-valued expression for S_A if required here.
If instead of res we use res(il,ir) is used,
If (res(il,ir) >= 0) Then
result(il,ir) = res(il,ir)
Else
result = 0
End If
the error says error #6351: The number of subscripts is incorrect.
Is there any way to implement this idea?
Function somefunction(x,y,il,ir) Result(result)
!! ---- begin of declaration ---------------------------
Implicit None
!! boundary indices
Integer, Intent ( in ) :: il,ir
!! the vars
Real ( kind = rk ), Intent ( in ), Dimension ( il:ir ) :: x,y
!! the result
Real ( kind = rk ), Dimension ( il:ir ) :: result
!! temp vars
Real ( kind = rk ), Dimension ( il:ir ) :: res
!! loop index
Integer :: i
!! ---- end of declaration -----------------------------
res = x+y
SA = S_A
!!IF-ELSE!!
End Function somefunction
If you want to have an if statement element wise on an array, you should use the where statement, for example:
program min0
implicit none
real :: res(5, 5), result(5, 5)
call random_number(res)
res=res-0.5
print '(5(F5.2,X))', res
where (res>=0)
result = res
elsewhere
result = 0
end where
print *, '---------------------------------------'
print '(5(F5.2,X))', result
end program min0
I don't know why you get a subscript error, it might help if you tell us which line of the code the error occurs. But of course in the second code, you update a single element of result if res is larger than 0, but set the whole array result to 0 if it isn't. This is almost certainly not what you want.
Cheers
The function appears to take in X and Y dimensioned from (il:if)... say from (3:6), so a vector. However the index later says (il,ir) which means it is a 2 dimensional array.
WHERE seems like a good choice. Another would be a logical MASK to associate the where-positions. It makes sense is PACK and unpack are usd,
Why even say what size the vectors are?
ELEMENTAL Function somefunction(x,y) Result(Res)
!! ---- begin of declaration ---------------------------
Implicit None
Real ( kind = rk ), Intent (IN), Dimension (:) :: x,y
!! the result
Real ( kind = rk ), Dimension ( il:ir ) :: res
!! loop index
Integer :: i
!! ---- end of declaration -----------------------------
res = x+y
WHERE res <= 0
Res = 0
ENDWHERE
!!IF-ELSE!!
End Function somefunction
Then on the calling side... call the function over the range of undecided you want.
Z(1:5) = somefunction(X(1:5),Y(1:5))

Return type missmatch calling function

I have a fortran.f file and whant to compile it in Linux. I dont't know what I am doing wrong. I get the following error in my subroutine:
VHImpUmat.f:476:20:
sv%Fm = get_Fm(T) ! $F_M(\Tb)$ limit stress obliquity (depends on $\theta$)
1
Error: Return type mismatch of function ‘get_fm’ at (1) (UNKNOWN/REAL(8))
AVHImpUmat.f:476:14:
sv%Fm = get_Fm(T) ! $F_M(\Tb)$ limit stress obliquity (depends on $\theta$)
1
Error: Function ‘get_fm’ at (1) has no IMPLICIT type
My subroutine:
subroutine stiffness_and_derivatives(T,sv,mat,d,msg)
use tools_lt
use constitutive_names
implicit none
type (MATERIALCONSTANTS),intent(in) :: mat
type (STATEVARIABLES),intent(inout) :: sv
type (DERIVATIVES), intent(inout) :: d
type (MESSAGE),intent(inout) :: msg
character*40 :: whereIam
real(8), intent(in) :: T(3,3)
real(8), dimension(3,3,3,3,3,3) :: c,ctransp
real(8) :: trT3,fac
sv%Fm = get_Fm(T) ! $F_M(\Tb)$ limit stress obliquity (depends on $\theta$)
sv%That = hated(T) ! $\hat {\Tb} = \Tb / \tr \Tb$
sv%LLhat= sv%Fm*sv%Fm*Idelta+mat%az2*(sv%That .out. sv%That) ! linear hp stiffness $ \hat{\cE} = a^2 \left[ \left(\Frac{F_M}{a}\right)^2 \cI + \hTb \hTb \right] $
sv%LL = -( sv%trT/(3.0d0*mat%Cs) )* sv%LLhat ! $ \cE = \frac{-\tr\Tb}{3 \kappa} \hat{\cE}$
!----- dLLhatdT ----------
trT3 = sv%trT**3 ! $\tr^3 \Tb$
fac = mat%az2 / trT3
c = (Idelta .out. T) ! $c_{ijmnkl}= I_{ijmn}T_{kl}$
ctransp = tpose35i46(c) ! $c^T= c_{ijklmn}$
d%dLLhatdT = fac * ( sv%trT*ctransp + sv%trT*(T .out. Idelta)
& - 2.0d0*( T .out. ( T .out. delta) ) ) ! $ \hat E_{ijklmn}'=a^2\left(\dfrac{ T_{rr} I_{ijmn}T_{kl} + T_{rr} T_{ij}I_{klmn}-2 T_{ij}T_{kl} \delta_{mn} }{ (T_{rr})^3} + 2 \dfrac{F_M}{a} I_{ijkl}F'_{M\, mn} \right)$
! $F'_M \approx 0$ is assumed
d%dLLdT = -(1.0d0/(3.0d0*mat%Cs) )*((sv%LLhat .out. delta) ! $\cE_{ }' = \frac{-1}{3 \kappa} \hat\cE \oneb + \dfrac{-\tr \Tb}{3\kappa}\hat\cE'$
& + sv%trT*d%dLLhatdT )
end subroutine stiffness_and_derivatives
In your subroutine, you have the statement implicit none. This is very good and is considered good programming practice.
With this, you must specifically declare any user functions with their return type just like you declare your variables.
We really cannot see what kind of variable sv%Fm is since it is likely defined in one of those modules you use. For the sake of answering, lets say the Fm component of sv is a real(8) (hint in the error message): You would declare the function like this:
real(8) :: get_fm
You would do this at the top with the rest of the variable declarations.
The second error message Error: Function ‘get_fm’ at (1) has no IMPLICIT type essentially tells you you did not declare the return type of your function when there is no implicit typing.
The first error message Error: Return type mismatch of function ‘get_fm’ at (1) (UNKNOWN/REAL(8)) always lists 2 types. The first type is in the using program unit and the second type is the return value type in the function itself. Since you did not declare the function in your subroutine, it reports 'unknown' for that one. If, for example, you accidentally declared it as an integer function, it would have (integer/real(8)) there and that is a little more self-explanatory about the type mismatch.
So adding the 1 declaration makes both errors go away.

Line truncated, Syntax error in argument list

When I compile the program below, I have an error and a warning in the call Coor_Trans command line as
Warning: Line truncated
Error: Syntax error in argument list
I compile the program several times, but it does not work. Maybe there is something wrong with my call command.
program 3D
implicit none
integer :: i,j,k
integer, parameter :: FN=2,FML=5,FMH=5
integer, parameter :: NBE=FN*FML*FMH
real, parameter :: pi = 4*atan(1.0)
real(kind=4), dimension(1:FN,1:FML+1,1:FMH+1) :: BEXL,BEYL,BEZL
real(kind=4), dimension(1:FN,1:FML,1:FMH) :: BEXC,BEYC,BEZC,BE2A,BE2B,ANGLE
real(kind=4), dimension(1:NBE,1:1,1:1) :: BEXC1,BEYC1,BEZC1,BE2A1,BE2B1,ANGLE1
real(kind=4), dimension(1:NBE,1:NBE) :: LOC_PTS1,LOC_PTS2,LOC_PTS3
real :: LOC_1,LOC_2,LOC_3
do i=1,FN
do j=1,FML
do k=1,FMH
BEXC(i,j,k) = 0.5*(BEXL(i,j,k) + BEXL(i,j+1,k))
BEYC(i,j,k) = 0.5*(BEYL(i,j,k) + BEYL(i,j+1,k))
BEZC(i,j,k) = 0.5*(BEZL(i,j,k) + BEZL(i,j,k+1))
BE2A(i,j,k) = FL(i)/FML + j*0 + k*0
BE2B(i,j,k) = FH(i)/FMH + j*0 + k*0
ANGLE(i,j,k) = BETA(i) + j*0 + k*0
end do
end do
end do
BEXC1 = reshape(BEXC,(/NBE,1,1/))
BEYC1 = reshape(BEYC,(/NBE,1,1/))
BEZC1 = reshape(BEZC,(/NBE,1,1/))
BE2A1 = reshape(BE2A,(/NBE,1,1/))
BE2B1 = reshape(BE2B,(/NBE,1,1/))
ANGLE1 = reshape(ANGLE,(/NBE,1,1/))
do i=1,NBE
do j=1,NBE
call Coor_Trans(BEXC1(i,1,1),BEYC1(i,1,1),BEZC1(i,1,1),BEXC1(j,1,1),BEYC1(j,1,1),BEZC1(j,1,1),ANGLE1(j,1,1),LOC_1,LOC_2,LOC_3)
LOC_PTS1(i,j) = LOC_1
LOC_PTS2(i,j) = LOC_2
LOC_PTS3(i,j) = LOC_3
end do
end do
end program 3D
subroutine Coor_Trans(GLOB_PTSX1,GLOB_PTSY1,GLOB_PTSZ1,GLOB_PTSX2,GLOB_PTSY2,GLOB_PTSZ2,BETA,LOC_PTS1,LOC_PTS2,LOC_PTS3)
implicit none
real(kind=4), intent(in) :: GLOB_PTSX1,GLOB_PTSY1,GLOB_PTSZ1,GLOB_PTSX2,GLOB_PTSY2,GLOB_PTSZ2,BETA
real(kind=4), intent(out) :: LOC_PTS1,LOC_PTS2,LOC_PTS3
real, parameter :: pi = 4*atan(1.0)
real :: E1,E2
E1 = cos(BETA/180*pi)
E2 = sin(BETA/180*pi)
LOC_PTS1 = (GLOB_PTSX1-GLOB_PTSX2)*E1 + (GLOB_PTSY1-GLOB_PTSY2)*E2
LOC_PTS2 = (GLOB_PTSZ1-GLOB_PTSZ2)
LOC_PTS3 = -(GLOB_PTSX1-GLOB_PTSX2)*E2 + (GLOB_PTSY1-GLOB_PTSY2)*E1
!return
end subroutine Coor_Trans
The length of your call statement is too long. The default maximum width of a line is 132.
The compiler will truncate input lines at that width [as it did--and said so with the warning]. After that, you had an incomplete line (e.g. call foo(a,b that was missing the closing )) which generated the second warning message.
The best solution is to break up the long line with a continuation character, namely &:
call Coor_Trans(BEXC1(i,1,1),BEYC1(i,1,1),BEZC1(i,1,1), &
BEXC1(j,1,1),BEYC1(j,1,1),BEZC1(j,1,1), &
ANGLE1(j,1,1),LOC_1,LOC_2,LOC_3)
Most C-style guides recommend keeping lines at <= 80 chars. IMO, that's a good practice even with fortran.
Note, with GNU fortran, you can increase the limit with the -ffree-line-length-<n> command line option. So, you could try -ffree-line-length-512, but, I'd do the continuation above
Historical footnote: 132 columns was the maximum width that a high speed, chain driven, sprocket feed, fanfold paper, line printer could print.
The Fortran standard imposes a limit on the length of line that compilers are required to deal with, these days it's 132 characters. You can break the line at a suitable place and use a continuation line. Something like this:
call Coor_Trans(BEXC1(i,1,1),BEYC1(i,1,1),BEZC1(i,1,1),BEXC1(j,1,1), &
BEYC1(j,1,1),BEZC1(j,1,1),ANGLE1(j,1,1),LOC_1,LOC_2,LOC_3)
Notice the & at the end of the continued line.
Once the line is truncated arbitrarily it is syntactically erroneous, which explains the second part of your compiler's complaint.
Your compiler probably has an option to force it to read longer lines.

Unclassifiable statement in Fortran 95 when declaring function

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!