Here's a part of my fortran code after compiling gives me an error saying that 'icount at (1) is not a variable
Here goes my code:
integer*4 iy1
integer*2 id1,im1
parameter (month=12,maxper=5,specmax=8)
real conc(month,8,icount(8,month))
integer smonth(12),icount(8,month)
real per(maxper),rper(maxper)
data smonth/12,1,2,3,4,5,6,7,8,9,10,11/
data per/0.10,0.25,0.5,0.75,0.90/
open(unit=1`,file='data_co.txt',status='old')
open(unit=2,file='chennai_alldatatop10.txt',status='unknown',iostat=ierr)
if(ierr.eq.0)close(2,status='delete')
open(unit=2, file='chennai_alldatatop10.txt',status='unknown')
inum=0
2 read(2,*,end=3)id1,im1,iy1,conc1
icount(1,im1)=inum+1
conc(im1,1,icount(1,im1))=conc1
goto 2
3 continue
end
In your variable declarations at the top of your code, you switched the order:
real conc(month,8,icount(8,month))
integer smonth(12),icount(8,month)
You are using icount before you defined it, so your code should look like this:
integer smonth(12),icount(8,month)
real conc(month,8,icount(8,month))
But actually, this doesn't make any sense either, if icount(8, month) has not yet been initialized to a value. So your code should look like this:
integer smonth(12), icount(8,month)
real conc(month, 8, some_scalar_value)
Related
I am writing a Fortran program to solve Euler Project problems. In my implementation each problem is a function, for example:
character(len=20) function euler_problem_0001()
use some_external_lib
...
end function euler_problem_0001
and if I print the function I simply get the answer.
print *, euler_problem_0001()
Now I have finished quite a few problems and I find it a bit tedious to write print *, euler_problem_xxxx() over and over again. So my questions is: Is there a way that I can construct a derived type that could link an integer (number of the problem) with the actual procedure? Something like
type, public :: int_to_proc
character(len=:) :: proc_name
procedure(proc_x), pointer :: proc_p
end type int_to_proc
so that if I initialize the type with an integer,
call int_to_proc%init(2)
then the type bound procedure pointer will point to the function euler_problem_0002(). In this case I only have to write a loop similar to this
type(int_to_proc) :: prob
do i = 1, 500
call prob%init(i)
print *, prob%proc_p()
end do
instead of writing 500 lines of print *, euler_problem_xxxx(). Also, any work-around is also welcome. Thanks!
This question already has an answer here:
Function in fortran, passing array in, receiving array out
(1 answer)
Closed 4 years ago.
INTEGER FUNCTION NUMTOLIST(NUM) RESULT(LI)
IMPLICIT NONE
! FUNCTION TO CONVERT NUMBERS INTO ARRAYS OF NUMBERS, BY DIGIT
! PROBLEM 1: X IS NOT BEING PASSED
INTEGER :: NUM
INTEGER :: I,J
INTEGER :: LI(0:5) ! G95 COMPILER SAYS THAT 'LI ALREADY HAS BASIC TYPE INTEGER', DOESN'T RECOGNISE AS ARRAY
PRINT *,'NUM: ',NUM ! DEBUGGING LINE, CONFIRMS THAT X IS NOT BEING PASSED INTO THE FUNCTION
DO I = 0,5
J = 0
DO WHILE (J*10**(5-I)<=NUM)
J = J+1
END DO
J = J-1
LI(I) = J
NUM = NUM-(J*10**(5-I))
END DO
PRINT *,'LI: ',LI ! DEBUGGING LINE, SHOWS THAT FUNCTION IS AS IS SUPPOSED TO, EXCEPT FOR ON SOME SORT OF DEFAULT INTEGER
RETURN
END FUNCTION NUMTOLIST
PROGRAM NUMTOLISTTEST
IMPLICIT NONE
INTEGER FUNCTION, NUMTOLIST
INTEGER :: X
INTEGER :: F(1:6)
READ *,X
PRINT *,X
F = NUMTOLIST(X)
! PROBLEM 2: THE RESULT OF NUMTOLIST SHOULD BE A LIST, BUT F IS JUST BEING ASSIGNED NUM, NOT THE OUTPUT OF NUMTOLIST
PRINT *,F
READ *,X
END PROGRAM NUMTOLISTTEST
Here is my full code. As the name suggests, this is a test for a function of a larger code. There are several problems but the one that is most pressing is that for some reason a variable is not being passed to a function. I am using the silverfrost compiler, and for some reason although everything in the function itself is working as it should, it neither inputs nor returns properly. The input itself is completely disregarded, leading to num being undefined, and the return isn't being read as a list type, as F, when printed, is a list of the arbitrary number num took on. It's completely beyond me why any of this is happening, and I've been on and off looking at this for a couple of days.
Much more trivially, when I try to compile using G95, it won't. It claims that 'Li already has basic type 'Integer'', and then won't recognise Li as a list. The method I'm using to declare an integer as a list has worked in the past for me, and fits the documentation I've seen, so I'm confused why it's throwing an error.
I've been stuck on this for a while, and I just can't seem to fix it on my own. Whatever help is offered will be greatly appreciated, and thank you in advance.
You are indeed declaring a type for the variable LI twice in the function. Look:
INTEGER FUNCTION NUMTOLIST(NUM) RESULT(LI)
! (...)
INTEGER :: LI(0:5)
Notice the INTEGER keyword before function declaration. It applies to the variable name declared as result in result(LI). The second declaration of LI gives the error.
Solutions:
Remove the INTEGER from the function declaration (preferred);
Remove the second type declaration of LI. You can specify a dimension without type declaration, with the dimension specification statement.
like this:
DIMENSION LI(0:5)
Besides that, to call a function with an array as a returning value, you will need an explicit interface.
I am new to Fortran, writing some practice code with a function that returns Farenheit from Celsius
program Console1
implicit none
real, parameter :: ikind = selected_real_kind(p=15)
real (kind = ikind):: c,f,o,faren
print *, "enter a temperature in degrees celsius"
read *, c
write(*,10) "farenheit =", faren(c)
10 format(a,f10.8)
end program Console1
function faren(c)
real, parameter :: ikind = selected_real_kind(p=15)
real (kind = ikind):: c,f
faren = (9/5)*c + 32
end function faren
I get an error #7977 : The type of the function reference does not match the type of the function definition.
So with that if i change function faren(c) to real function faren(c)
I get the same error, but the types are the same?
Am i missing something? Do I have to define the function in the main program?
There are several issues in addition to the structural/code arrangement ones already noted.
First, KIND is an integer, so you want to change
real, parameter :: ikind = selected_real_kind(p=15)
to
integer, parameter :: ikind = selected_real_kind(p=15)
Ideally, you want to define that in only one place (i.e. in a module) and reference it from both your main program and the function, but the code should be fine as it is for test purposes.
A second issue that often trips up newcomers to Fortran (and Python2) is that real numbers and integers are distinct types and are not generally interchangeable.
faren = (9/5)*c + 32
simplifies to
faren = (1)*c + 32
because integer division has an integer result; 9/5 = 1
Fortran is picky about numerical values (that's sort of the whole point of the language) so what you probably want is:
faren = (9.0 / 5.0) * c + 32.0
Or more precisely, if faren is defined with a specific precision of ikind,
faren = (real(9.0,ikind) / real_(5.0,ikind)) * c + real(32.0,ikind)
or
faren = (9.0_ikind / 5.0_ikind) * c + 32.0_ikind
This syntax tends to make people's heads explode. Welcome to modern fortran ;)
The last issue deals with the horrors of Fortran I/O. From a design standpoint, you need to know what results the user expects and make sure the output format can display them. The legitimate range of input values for c is -273.15 (give or take) to some upper bound which relies on the use case for the code. If you're dealing with cooking temperatures, you probably won't exceed 400.0; if you're doing fusion research, you could be going much higher. Are 8 figures past the decimal useful or believable? In this case, we're just testing the code so we may not need a lot of precision in the output; you'll want to change the output format to something like:
10 format(a,es10.2)
or
10 format(a,g16.8)
You need to ensure the total field width (the number before the dot) can contain the decimal part (the number after the dot) along with the integer part of the number, plus the space needed to show sign and exponent. For scientific notation, four characters are eaten by mantissa sign, decimal point, 'E' and exponent sign. It may be safer just starting out to use an output format of *; it's frustrating to fight with numerics and formatting simultaneously.
That is a good effort and simple start to work through the nuance, so a good question.
Personally I would use reals for the math, rather the 9/5, and use a module. In this example you could pass in a real or a double to C2Faren and the interface/procedure will sort out whether to use the real or the double version. Then you have a few options in case you want different precision.
You could also use the ISO_C_BINDING if you do mixed language...
MODULE MyTEMPS
PRIVATE
DOUBLE PRECISION, PARAMETER :: C2F_ScaleFact = 1.8D0
DOUBLE PRECISION, PARAMETER :: F2C_ScaleFact = /(1.0D0 / 1.8D0)/
DOUBLE PRECISION, PARAMETER :: F2C_Offset = 32.0D0
PUBLIC Faren2C
INTERFACE C2Faren
MODULE PROCEDURE C2Faren_Real, C2Faren_DBL
END INTERFACE
CONTAINS
!========= REAL VERISON =========
REAL FUNCTION C2Faren_Real(c)
IMPLICIT NONE
real, INTENT(IN ) :: c
C2Faren_Real = ( C*F2C_ScaleFact ) + F2C_Offset
RETURN
END FUNCTION C2Faren_Real
!========= DOUBLE VERSION =========
DOUBLE PRECISION FUNCTION C2Faren_DBL(c)
IMPLICIT NONE
DOUBLE PRECISION , INTENT(IN ) :: c
C2Faren_DBL = ( C*F2C_ScaleFact ) + F2C_Offset
RETURN
END FUNCTION C2Faren_DBL
!========= REAL VERSION (Faren to Centigrade) =========
REAL FUNCTION faren2C(Faren)
IMPLICIT NONE
REAL, INTENT(IN ) :: Faren
faren2C = (faren - F2C_Offset) / F2C_ScaleFact
RETURN
END FUNCTION faren2C
END MODULE MyTEMPS
Then your program uses the module via USE n the second line...
program Console1
USE MyTEMPS !<== Here
implicit none
real :: c, f
DOUBLE PRECISION :: Dc, Df ! No way to get Df to C or DC in the module (yet)!
print *, "enter a temperature in degrees celsius"
read *, c
write(*,10) "farenheit =", C2faren(c)
10 format(a,f10.6)
Dc = C
write(*,12) "farenheit =", C2faren(Dc)
12 format("DBL:",A,f10.6)
F = Dc
write(*,14) "Centigrade =", faren2C(F)
14 format("DBL:",A,f10.6)
end program Console1
So/and the main advantage of the module is when you end up wanting to use this stuff in a variety of programs and test and sort out the module once... Usually people put this sort of stuff (lots of modules) in a library, when the module(s) have lot of functions.
You could also put just the real, parameter :: ikind = selected_real_kind(p=15) into a module and use that in both the program and the function and you would be there. You were real close, and it mostly a matter of style and utility.
For Intel Fortran you can use REAL(KIND=4) and REAL(KIND=8)... Which I do, but that is not portable to gfortran, so it is probably a better habit to use the ISO_C_BINDING or just use REAL and DOUBLE PRECISION.
Modules are great but if you have a very simple code another way to work is to put the subroutines and functions in your main program. The trick is to put them after the word contains:
program xxx
stuff
contains
subroutine yyy
function zzz
end program xxx
In this way the functions can see into the contents of the main program so you don't have to re-declare your parameters and you are likely to get more meaningful error messages.
Since you are new I have a great resource I learned a lot from to share:
http://www.uv.es/dogarcar/man/IntrFortran90.pdf
I'm converting some F77 files to F90. However, there are some common blocks that did not converted. I'm a novice in F90 and have no experience in F77.
Could someone show me how to covert the following example code to F90?
BLOCK DATA SETUP
INTEGER A,B,C
REAL I,J,K,L
COMMON /AREA1/ A,B,C
COMMON /AREA2/ I,J,K,L
DATA A,B,C,I,J,K,L/0,1,2,10.0,-20.0,30.0,-40.0/
END
My idea is to put the arrays A, B, and C in a module. The main thing I don't get here is the AREA1 and AREA2. How are these used in F77 and how do I translate those? My first guess is to discard them and simply define A,B, & C in the module. However, are they a kind of derive type within which A, B, & C are contained?
First up, the original code should compile in Fortran 90 and later. So if it isn't broken, don't try to fix it.
COMMON blocks are basically global variables. In every procedure that the global variables are used, they have to be declared in the same way1, and then they are shared everywhere. Something like this:
integer a, b
common /globals/ a, b
A more modern approach would be to convert globals into a module:
module globals
implicit none
integer a, b
end module globals
And then use that module everywhere you need access to a and b
program main
use globals
implicit none
a = 4
b = 2
end program main
You could either put the DATA statement into the module, or, even easier, initialise every variable in the declaration:
module AREA1
implicit none
integer :: a = 0
integer :: b = 1
integer :: c = 2
end module AREA1
module AREA2
implicit none
real :: i = 10.0
real :: j = -20.0
real :: k = 30.0
real :: l = -40.0
end module AREA2
Then, you can replace the whole thing by just use AREA1 and use AREA2 before the implicit none everywhere you need access to their variables.
Edit: Forgot the footnote
1The rules for common blocks are more flexible, in that the values for the different variables are stored in a common memory location, in the order that they are named. So while it is not technically necessary to always use the same COMMON statement, you can very easily introduce bugs if you don't.
If you have differently named variables (but of the same type), then adapting that is not that hard. Say you have
integer a, b
common /globals/ a, b
in the main program and
integer i, j
common /globals/ i, j
in a subroutine. Assuming that you create a module with a and b, you can then in the subroutine use it in this way:
use globals, only: i => a, j => b
(Note that if you use only, you have to list every variable that you want to use out of the module. You could use something like: only: a, i => b if you want a and i.)
Of course, the following would also be compatible with the previous globals common block, but might lead to more trouble:
integer k(2)
common /globals/ k
So I've been avoiding Fortran like the plague, but finally my time has come... I need to take part of someone else's Fortran code (let's call it program A) and do two things with it:
(1) Merge it with a third person's Fortran code (let's call it program B) so that B can call A
(2) Merge it with my C++ code (program C) so that C can call A
B and C are optimization algorithms, and A is a collection of benchmark functions... But before all that awesomeness can happen, I must first compile the portion of A that I need. All the subroutines of A that I need are contained in one file. I've been getting it into shape based on information I got online (e.g. adding "IMPLICIT NONE" to the code and making it suitable for gfortran). But I've got two stubborn bugs and a warning (I'll leave the warning for another post).
Here's how I am currently compiling it (via a Makefile):
all:
gfortran progA.FOR
g++ -c progC.cpp
g++ -o Program.out progA.o progC.o
rm *.o
But the first line fails to complete with the following errors,
FIRST ERROR:
SUBROUTINE TP1(MODE)
1
Error: Unclassifiable statement at (1)
RELEVANT CODE (starting from the top of the file):
IMPLICIT NONE
INTEGER NMAX,MMAX,LMAX,MNNMAX,LWA,LIWA,LACTIV,N,NILI,NINL,
/ NELI,NENL,NEX, MODE
PARAMETER (NMAX = 101,
/ MMAX = 50,
/ LMAX = 50,
/ MNNMAX = NMAX + NMAX + MMAX + 2,
/ LWA = 2*NMAX*NMAX + 33*NMAX + 10*MMAX + 200,
/ LIWA = MMAX + NMAX + 150,
/ LACTIV = 2*MMAX + 15)
LOGICAL INDEX1,INDEX2
SUBROUTINE TP1(MODE)
COMMON/L1/N,NILI,NINL,NELI,NENL
COMMON/L2/X(2)
COMMON/L4/GF(2)
COMMON/L6/FX
COMMON/L9/INDEX1
COMMON/L10/INDEX2
COMMON/L11/LXL
COMMON/L12/LXU
COMMON/L13/XL(2)
COMMON/L20/LEX,NEX,FEX,XEX(2)
REAL*8 X,G,GF,GG,FX,XL,XU,FEX,XEX
LOGICAL LXL(2),LXU(2),LEX
GOTO (1,2,3,4,4),MODE
1 N=2
NILI=0
NINL=0
NELI=0
NENL=0
X(1)=-2.D0
X(2)=1.D0
LXL(1)=.FALSE.
LXL(2)=.TRUE.
LXU(1)=.FALSE.
LXU(2)=.FALSE.
XL(2)=-1.5D0
LEX=.TRUE.
NEX=1
XEX(1)=1.D0
XEX(2)=1.D0
FEX=0.D0
RETURN
2 FX=100.D0*(X(2)-X(1)**2)**2+(1.D0-X(1))**2
RETURN
3 GF(2)=200.D0*(X(2)-X(1)**2)
GF(1)=-2.D0*(X(1)*(GF(2)-1.D0)+1.D0)
4 RETURN
END
I do not understand why this error appears since there are over 300 other subroutines declared exactly the same way (e.g. SUBROUTINE TP2(MODE), ..., SUBROUTINE TP300(MODE) ).
SECOND ERROR:
HX=TP273A(X)
1
Error: Return type mismatch of function 'tp273a' at (1) (REAL(4)/REAL(8))
RELEVANT CODE:
SUBROUTINE TP273(MODE)
COMMON/L1/N,NILI,NIML,NELI,NENL
COMMON/L2/X
COMMON/L4/GF
COMMON/L6/FX
COMMON/L11/LXL
COMMON/L12/LXU
COMMON/L20/LEX,NEX,FEX,XEX
LOGICAL LEX,LXL(6),LXU(6)
REAL*8 X(6),FX,GF(6),FEX,XEX(6),HX,DFLOAT
GOTO (1,2,3,4,4)MODE
1 N=6
NILI=0
NINL=0
NELI=0
NENL=0
DO 6 I=1,6
X(I)=0.D+0
XEX(I)=0.1D+1
LXL(I)=.FALSE.
6 LXU(I)=.FALSE.
LEX=.TRUE.
NEX=1
FEX=0.D+0
RETURN
2 HX=TP273A(X)
FX=0.1D+2*HX*(0.1D+1+HX)
RETURN
3 HX=TP273A(X)
DO 7 I=1,6
7 GF(I)=0.2D+2*(0.16D+2-DFLOAT(I))*(X(I)-0.1D+1)
1 *(0.1D+1+0.2D+1*HX)
4 RETURN
END
REAL*8 FUNCTION TP273A (X)
REAL*8 X(6),DFLOAT
TP273A=0
DO 10 I=1,6
10 TP273A=TP273A+(0.16D+2-DFLOAT(I))*(X(I)-0.1D+1)**2
RETURN
END
After reading Physics Forums I tried renaming the variable "TP273A" to "TP273Avar" so that it would not have the same name as the function. This did not resolve the error. Also, I replaced the "1" with "F" just below "7 GF(I) = ..." and recompiled. Nothing changed. I'm pretty sure the changes I just mentioned are necessary anyway, but there must be something else going on.
I have also read Data type mismatch in fortran and Function return type mismatch, so I naively tried adding "module mycode" to the top and "end module mycode" to the bottom of the file to no avail.
After this is all said and done, my goal is to call these subroutines from C++ using a code similar to:
#include <kitchensink>
extern"C"
{
void TP1_(int *mode);
}
int main()
{
TP1_(2);
return 0;
}
Once the Fortran Code compiles, I want to modify the subroutines so that C++ can pass std::vector X to TP#_(2,*X,*Y) and get back the computed value for Y. My std::vector X will replace COMMON/L2 X in each of the subroutines, and Y will be the value of FX computed in the subroutines. I used Mixing Fortran and C as guidance for the above C++ code.
As for the B calls A part, I hope that it will be as simple as compiling A along with B, and adding "CALL TP1(MODE)" lines wherever I need them.
Any and all guidance will be greatly appreciated!!!
You cannot have statements just in a file outside of a compilation unit. These can be subroutines, functions, modules or programs. In your case you have some statements( first of them being implicit none) and only after them there is the beginning of the subroutine TP1.
Either organize the procedures in a module and leave the common part before the contains section (more work with the C++ interoperability will follow if you are a Fortran newbie) or you must include the implicit none and others in every subroutine separately. Are you sure you even need this if the code worked before?