I am trying to understand a part of code written in fortran. The code contains the following part:
REAL(KIND=8), DIMENSION(x,y), INTENT(INOUT) :: AR
_REAL_, DIMENSION(x,y), INTENT(INOUT) :: BR
From this page , i came to know that _REAL_ is a preprocessor for precision control.
What does _REAL_ actually do in this code?
Can AR values be assigned to BR ? Is there type incompatibility problem between them?
I was trying to assign the values of AR to BR using a C function extern "C" void assign_(double *AR, double *BR , int *x, int*y)But I am having a problem, and it seems like the problem is due to the incompatibility issue between AR and BR because if I change the above code to:
REAL(KIND=8), DIMENSION(x,y), INTENT(INOUT) :: AR
REAL(KIND=8), DIMENSION(x,y), INTENT(INOUT) :: BR ,
the problem is solved. Is there any problem if I changed the code this way?
The page that you referenced seems to be a bug report on building the Molecular Dynamics software package, Amber. I infer this from the link (.../gcc-bugs/...), from the second line of the page which states:
!+ Specification and control of Amber's working precision
and finally from the description which explains how to change the precision of the Amber build (installing a single or double precision version the software).
If the written code you are looking at is a part of Amber, then the page you have referenced does explain what _REAL_ does in the code. Namely, it's a general type definition that based on the working precision either is replaced at compile time with real(kind=4) or real(kind=8). According to the description for Amber, the default build is double precision, which implies that when compiled, _REAL_ would be replaced with real(kind=8). This should answer question 1.
Note that in fortran values of AR can always be assigned to BR, but they will require casting to the appropriate type. I.e. if BR is an integer array, the values of AR will be need to be casted into integers. Assuming that the written code you are looking at is for Amber again, and that the default double precision is not overriden, then BR is a double precision array just as AR is, so values can be freely assigned between them.
As for question 3., you maybe need to define a macro so that _REAL_ actually does mean double precision. While not often discussed, many fortran compilers will happily apply a preprocessor. For automatic preprocessing (allowing the compiler to determine the flags), one just needs to ensure that the fortran source file has the correct extension, such as .F90, .F, .fpp, or .FPP as outlined in the first paragraph on this documentation page for gfortran (quick note that these are understood by the intel compilers as well). As I usually code in Fortran 90 or later, the extension .F90 works wonders for me. Then, probably in the header of your source file, just add the following line:
#define _REAL_ real(kind=8)
note that I add more than one space between the last underscore and real as to emphasize that there must be a space there. Doing this will allow the Fortran compiler to replace all occurrences of _REAL_ with real(kind=8) and give you a way to globally modify real precision by modifying one line without invoking a compiler flag.
I think that doing this might get your external C reference to work.
Related
I want to specify as type of a subroutine a floating point value (real) of 8 bytes precision.
I have read here that the modern way to do it would be:
real(real64), intent(out) :: price_open(length)
However, iso_fortran_env is not supported by f2py (same as it does not support iso_c_bindings either).
I get errors of this type:
94 | real(kind=real64) price_open(length)
| 1
Error: Parameter 'real64' at (1) has not been declared or is a variable, which does not reduce to a constant expression
The link referenced before states that using kind would be the proper way if iso_fortran_env is not available and that real*8 shall be avoided.
I have been using real(8) is that equivalent to using kinds? If not, what shall I use?
What is wrong with real*8 if I want to always enforce 8 bytes floating point values?
You say you are specifically interested in interoperability with C. However, iso_c_binding, nor iso_fortran_env are supported. These modules have constants that help you to set the right kind constant for a given purpose. The one from iso_fortran_env would NOT be the right one to choose anyway, it would be c_double.
If these constants meant to help you in your choice are not available, you are on your own. Now you can choose any other method freely.
It is completely legitimate to use just kind(1.d0) and just check that the connection to C works. Automake had been doing that for ages.
Or use selected_real_kind(), it does not matter, it is really up to you. Just check that double in C ended up being the same numeric type.
The traditional thing in automatic build processes was to do many tests about which (mainly C) constant ended up having which value. You just need to check that double precision in Fortran does indeed correspond to double in C. It is very likely, but just check it. You can have a macro that changes the choice if not, but probably it is a needless work untill you actually meet such a system.
I've always been using the -fdefault-real-8 option of gfortran to automatically promote every single REAL declared anywhere in the program to double precision, along with any constant, e.g. 1.23. If I ever wanted to switch back to single precision, I only had to remove that option and recompile, without changing a single character in the source code.
At a point I started using ISO_FORTRAN_ENV module, since it allows me to use constants like INPUT|OUTPUT|ERROR_UNIT, as well as IOSTAT_END and IOSTAT_EOR and others (which seemed to be a good and easy move in the direction of portability, am I wrong?). From then on, I've been seeing and ignoring the following warning
Warning: Use of the NUMERIC_STORAGE_SIZE named constant from intrinsic module ISO_FORTRAN_ENV at (1) is incompatible with option -fdefault-real-8
since such incompatibility seems to have no effect so far.
Now I'd like to get rid of this warning if it is possible and worth it.
If I correctly understood, to avoid this warning I should give up on -fdefault-real-8 option and change every REAL to REAL(real64) and/or to REAL(dp) (provided that, in the latter case, the statement USE, INTRINSIC :: ISO_FORTRAN_ENV, dp => real64 is put in that unit), which is not a difficult task for sed or vim.
Nevertheless, it seems to me that this change wouldn't be the same as using -fdefault-real-8 option, since all constants would stay single precision as long as I don't add d0 to them.
Assumed the -fdefault-real-8 option is removed and ISO_FORTRAN_ENV is used anywhere, is there any way to make any constant across the program behave as each had d0 suffix?
Whether or not this is possible, have I correctly extrapolated that I can put the following lines in a single module which is used by all others program units, each of which can then use dp as kind type parameter?
USE, INTRINSIC :: ISO_FORTRAN_ENV
INTEGER, PARAMETER :: dp = real64
I would prefer this way since I could switch to real32 or real128 or whatever by changing only that line.
If you just want to silence the warning and you do not care about the implications -fdefault-real-8 has on storage association and some Fortran standard requirements, just do not import NUMERIC_STORAGE_SIZE from the module. For example,
USE, INTRINSIC :: ISO_FORTRAN_ENV, only: INPUT_UNIT,OUTPUT_UNIT,ERROR_UNIT
Assumed the -fdefault-real-8 option is removed and ISO_FORTRAN_ENV is used anywhere, is there any way to make any constant across the program behave as each had d0 suffix?
No.
By the way, d0 is exactly the same as double precision, so that doesn't fixate much either, since the meaning of double precision is allowed to vary as much as real.
Whether or not this is possible, have I correctly extrapolated that I can put the following lines in a single module which is used by all others program units, each of which can then use dp as kind type parameter?
Yes. That is a common practice.
I have downloaded the following fortran program dragon.f at http://www.iamg.org/documents/oldftp/VOL32/v32-10-11.zip
I need to do a minor modification to the program which requires the program to be translated to fortran90 (see below to confirm if this is truly needed).
I have managed to do this (translation only) by three different methods:
replacing comment line indicators (c for !) and line continuation
indicators (* in column 6 for & at the end of last line)
using convert.f90 (see https ://wwwasdoc.web.cern.ch/wwwasdoc/WWW/f90/convert.f90)
using f2f.pl (see https :// bitbucket.org/lemonlab/f2f/downloads)
Both 1) and 3) worked (i.e. managed to compile program) while 2) didn't work straight away.
However, after testing the program I found that the results are different.
With the fortran77 program, I get the "expected" results for the example provided with the program (the program comes with an example data "grdata.txt", and its example output "flm.txt" and "check.txt"). However, after running the translated (fortran90) program the results I get are different.
I suspect there are some issues with the way some variables are declared.
Can you give me recommendations in how to properly translate this program so I get the exact same results?
The reason I need to do it in fortran90 is because I need to input the parameters via a text file instead of modifying the program. This shouldnt be an issue for most of the parameters involved, except for the declaration of the last one, in which the size is determined from parameters that the program does not know a priori (see below):
implicit double precision(a-h,o-z)
parameter(lmax=90,imax=45,jmax=30)
parameter(dcta=4.0d0,dfai=4.0d0)
parameter(thetaa=0.d0,thetab=180.d0,phaia=0.d0,phaib=120.d0)
dimension f(0:imax,0:jmax),coe(imax,jmax,4),coew(4),fw(4)
So for example, I will read lmax, imax, jmax, dcta, dfai, thetaa, thetab, phaia, and phaib and the program needs to declare f and coe but as far as I read after googling this issue, they cannot be declared with an unknown size in fortran77.
Edit: This was my attempt to do this modification:
character fname1*100
call getarg(1,fname1)
open(10,file=fname1)
read(10,*)lmax,imax,jmax,dcta,dfai,thetaa,thetab,phaia,phaib
close(10)
So the program will read these constants from a file (e.g. params.txt), where the name of the file is supplied as an argument when invoking the program. The problem when I do this is that I do not know how to modify the line
dimension f(0:imax,0:jmax)...
in order to declare this array when the values imax and jmax are not known when compiling the program (they depend on the size of the data that the user will use).
As has been pointed out in the comments above, parameters cannot be read from file since they are set at compile time. Read them in as integer, declare the arrays as allocatable, and then allocate.
integer imax,jmax
real(8), allocatable :: f(:,:),coe(:,:,:)
read(10,*) imax,jmax
allocate(f(0:imax,0:jmax),coe(imax,jmax,4))
I found out that the differences in the results were attributed to using different compilers.
PS I ended up adding a lot more code than I intended at the beginning to allow reading data from netcdf files. This program in particular is really helpful for spherical harmonic expansion. [tag:spherical harmonics]
I have written program with implicit real*8. The program is working fine but as soon as i inserted another data file that contains the data of long and double precision digits than the results i found were not appropriate. Experts and the program developers adviced me to change implicit real*16. But it is not working in my fortran power station 4.0 and giving implicit error. How to convert or upgrade the power station so that it can work with implicit real*16 or more?
Powerstation is too old. Not every compiler supports real*16 even now. Consider to obtain a new compiler. I suggest to begin with gfortran, that does support quad precision for sure.
Also I am worried that with that implicit things there might be many other problems hidden. Consider also explicit typing for your variables and using implicit none.
What are the values in your file? integers and double precision floating point values? Then it seems very unlikely that the problem is caused by your not reading them into quad-precision real variables. Only rarely do calculations need quad-precision. Are you reading the integer values into integer variables and the floats into Fortran reals? As the others have written, implicit typing is the worst approach ... it is still part of Fortran only to support legacy code. Best practice is to use "implicit none" and explicitly type all of your variables. This will allow the compiler to catch mistakes such as typos in variable names. For more about variable typing see Fortran: integer*4 vs integer(4) vs integer(kind=4) and Extended double precision
I am having trouble understanding Fortran 90's kind parameter. As far as I can tell, it does not determine the precision (i.e., float or double) of a variable, nor does it determine the type of a variable.
So, what does it determine and what exactly is it for?
The KIND of a variable is an integer label which tells the compiler which of its supported kinds it should use.
Beware that although it is common for the KIND parameter to be the same as the number of bytes stored in a variable of that KIND, it is not required by the Fortran standard.
That is, on a lot of systems,
REAl(KIND=4) :: xs ! 4 byte ieee float
REAl(KIND=8) :: xd ! 8 byte ieee float
REAl(KIND=16) :: xq ! 16 byte ieee float
but there may be compilers for example with:
REAL(KIND=1) :: XS ! 4 BYTE FLOAT
REAL(KIND=2) :: XD ! 8 BYTE FLOAT
REAL(KIND=3) :: XQ ! 16 BYTE FLOAT
Similarly for integer and logical types.
(If I went digging, I could probably find examples. Search the usenet group comp.lang.fortran for kind to find examples. The most informed discussion of Fortran occurs there, with some highly experienced people contributing.)
So, if you can't count on a particular kind value giving you the same data representation on different platforms, what do you do? That's what the intrinsic functions SELECTED_REAL_KIND and SELECTED_INT_KIND are for. Basically, you tell the function what sort of numbers you need to be able to represent, and it will return the kind you need to use.
I usually use these kinds, as they usually give me 4 byte and 8 byte reals:
!--! specific precisions, usually same as real and double precision
integer, parameter :: r6 = selected_real_kind(6)
integer, parameter :: r15 = selected_real_kind(15)
So I might subsequently declare a variable as:
real(kind=r15) :: xd
Note that this may cause problems where you use mixed language programs, and you need to absolutely specify the number of bytes that variables occupy. If you need to make sure, there are enquiry intrinsics that will tell you about each kind, from which you can deduce the memory footprint of a variable, its precision, exponent range and so on. Or, you can revert to the non-standard but commonplace real*4, real*8 etc declaration style.
When you start with a new compiler, it's worth looking at the compiler specific kind values so you know what you're dealing with. Search the net for kindfinder.f90 for a handy program that will tell you about the kinds available for a compiler.
I suggest using the Fortran 2008 and later; INT8, INT16, INT32, INT64, REAL32, REAL64, REAL128. This is done by calling ISO_FORTRAN_ENV in Fortran 2003 and later. Kind parameters provides inconsistent way to ensure you always get the appropriate number of bit representation
Just expanding the other (very good) answers, specially Andrej Panjkov's answer:
The KIND of a variable is an integer label which tells the compiler
which of its supported kinds it should use.
Exactly. Even though, for all the numeric intrinsic types, the KIND parameter is used to specify the "model for the representation and behavior of numbers on a processor" (words from the Section 16.5 of the standard), that in practice means their bit model, that's not the only thing a KIND parameter may represent.
A KIND parameter for a type is any variation in its nature, model or behavior that is avaliable for the programmer to choose at compile time. For example, for the intrinsic character type, the kind parameter represents the character sets avaliable on the processor (ASCII, UCS-4,...).
You can even define your own model/behaviour variations on you defined Derived Types (from Fortran 2003 afterwards). You can create a Transform Matrix type and have a version with KIND=2 for 2D space (in which the underlying array would be 3x3) and KIND=3 for 3D space (with a 4x4 underlying array). Just remember that there is no automatic kind conversion for non-intrinsic types.
From the Portland Group Fortran Reference, the KIND parameter "specifies a precision for intrinsic data types." Thus, in the declaration
real(kind=4) :: float32
real(kind=8) :: float64
the variable float64 declared as an 8-byte real (the old Fortran DOUBLE PRECISION) and the variable float32 is declared as a 4-byte real (the old Fortran REAL).
This is nice because it allows you to fix the precision for your variables independent of the compiler and machine you are running on. If you are running a computation that requires more precision that the traditional IEEE-single-precision real (which, if you're taking a numerical analysis class, is very probable), but declare your variable as real :: myVar, you'll be fine if the compiler is set to default all real values to double-precision, but changing the compiler options or moving your code to a different machine with different default sizes for real and integer variables will lead to some possibly nasty surprises (e.g. your iterative matrix solver blows up).
Fortran also includes some functions that will help pick a KIND parameter to be what you need - SELECTED_INT_KIND and SELECTED_REAL_KIND - but if you are just learning I wouldn't worry about those at this point.
Since you mentioned that you're learning Fortran as part of a class, you should also see this question on Fortran resources and maybe look at the reference manuals from the compiler suite that you are using (e.g. Portland Group or Intel) - these are usually freely available.
One of the uses of kind could be to make sure that for different machine or OS, they truly use the same precision and the result should be the same. So the code is portable. E.g.,
integer, parameter :: r8 = selected_real_kind(15,9)
real(kind=r8) :: a
Now this variable a is always r8 type, which is a true "double precision" (so it occupies 64 bits of memory on the electronic computer), no matter what machine/OS the code is running on.
Also, therefore you can write things like,
a = 1.0_r8
and this _r8 make sure that 1.0 is converted to r8 type.
To summarize other answers: the kind parameter specifies storage size (and thus indirectly, the precision) for intrinsic data types, such as integer and real.
However, the recommended way now is NOT to specify the kind value of variables in source code, instead, use compiler options to specify the precision we want. For example, we write in the code: real :: abc and then compile the code by using the compiling option -fdefault-real-8 (for gfortran) to specify a 8 byte float number. For ifort, the corresponding option is -r8.
Update:
It seems Fortran experts here strongly object to the recommended way stated above. In spite of this, I still think the above way is a good practice that helps reduce the chance of introducing bugs in Fortran codes because it guarantees that you are using the same kind-value throughout your program (the chance that you do need use different kind-values in different parts of a code is rare) and thus avoids the frequently encountered bugs of kind-value mismatch between dummy and actual arguments in a function call.