When I try to compile calrank.for (CALRANK_v7.0.0_L140912.zip) with gfortran I get this error:
> gfortran -m64 -c -o calrank.o calrank.for
calrank.for:1922:32:
write(io,'(2f10.3,1p1000(2x,e16.7,1x,2a10,1x))')
1
Error: Comma required after P descriptor in format string at (1)
When I make a comma I got the same error.
I note only that the code was compiled before with LF95.
subroutine xycout(io,nrank,nsp)
use userinf
use header
use rankdata
implicit none
integer :: io,nrank,nsp
integer :: k,ir,is,i
character(len=20) :: head1,head2,head3
character(len=40) :: add1x,add2x,add3x
character(len=40) :: add1(nsp),add2(nsp)
character(len=40) :: add3(nsp)
......
c --- Loop over receptors to write data records
do ir=1,ntotrec(k)
write(io,'(2f10.3,1p1000(2x,e16.7,1x,2a10,1x))')
& xreckm(ir,k),yreckm(ir,k),
& (xounit(is,k)*rankvalue(ir,is,nrank),
& arankdate(ir,is,nrank),
& aranktime(ir,is,nrank),is=1,nspout(k))
enddo
return
end
Some variables are defined in other place of the code as:
c --- Real arrays for header (derived)
allocate (xreckm(mxrec,k),yreckm(mxrec,k))
c --- Modified units multiplier
allocate (xounit(mxspout,k))
c --- Array of values (all species, receptors) for requested ranks
allocate (rankvalue(ntotrec(k),nspout(k),n_ranks))
allocate (arankdate(ntotrec(k),nspout(k),n_ranks))
allocate (aranktime(ntotrec(k),nspout(k),n_ranks))
c --- Integer arrays for header
deallocate (ndrec,nctrec,nspout,i2dmet,iutmzn)
#francescalus suggested I expand on my comment.
First, Fortran generally requires a comma between two "format items". A format item is an edit descriptor (F, E, etc.) with or without a repeat count preceding it, or a parenthesized group of format items (which may have its own repeat count; #Vladimir F mentioned * - this is an "unlimited repeat count" and may be used only with a parenthesized group.
The comma may be omitted:
between a P edit descriptor and an immediately following F, E, EN, ES, EX, D, or G edit descriptor, possibly preceded by a repeat specification,
before a slash edit descriptor when the optional repeat specification does not appear,
after a slash edit descriptor, or
before or after a colon edit descriptor
Now as for the P edit descriptor, this sets the scale factor and it is indeed strange and has very different effects depending on what kind of editing you're doing. It also is "sticky" and applies to all later editing in that format.
On input, it causes the read value to be divided by 10**k, where k is the scale factor (2P means k=2, etc.). So if the characters in the input is 123 and 2P is in effect, the value reads as 1.23. Similarly if -2P was in effect, 123 would read as 12300. A decimal point in the input doesn't change this, but an exponent removes the scaling. So 1.23 read with 2P is .0123 but 1.23E0 is 1.23.
On output with F editing, it makes the output value to be multiplied by 10**k, reversing the input scheme.
You may ask WHY??? The answer lies in punch cards, an input (and sometimes output) form used in the 1950s through the 70s. These had 80 columns and wasting a column on a decimal point could be a problem. So a scale factor allowed one to omit the decimal point but still get fractions.
But wait, it gets stranger! On output with E and D editing, the scale factor simply determines the number of leading digits to the left of the decimal point (and a subsequent reduction of the exponent. So for a value of 1.23 and a format of 2P,E11.3, you'll get b12.300E-01 (b=blank unless SP is in effect, which is a reply for another day.)
And for output with G format? Even weirder. If the value is in the range where you get the equivalent of F format, the scale factor has no effect, otherwise it behaves like E.
Lastly, the scale factor has no effect on EN, ES or EX editing. (EX? That's a F2018 feature for hexadecimal floating point output.)
One good use of P format is when doing currency calculations with integers instead of reals, as the latter can lose precision (.01, for example, has no exact binary float representation.) Assuming the values you're dealing with aren't too big, you can read dollars and cents into an integer with a -2P format and not lose any pennies doing addition, subtraction and multiplication. I once wrote a mortgage calculator this way that was precise.
You should do exactly what the error message says, put a comma after the p descriptor:
write(io,'(2f10.3,1p,1000(2x,e16.7,1x,2a10,1x))')
If you do not know what a p descriptor is, see, for example here, or any tutorial about Fortran edit descriptors. As Steven Lionel comments below, you can use the p descriptor without a comma in front of normal data edit descriptors.
Related
I have this line in fortran and I'm getting the compiler error in the title. dFeV is a 1d array of reals.
dFeV(x)=R1*5**(15) * (a**2) * EXP(-(VmigFe)/kbt)
for the record, the variable names are inherited and not my fault. I think this is an issue with not having the memory space to compute the value on the right before I store it on the left as a real (which would have enough room), but I don't know how to allocate more space for that computation.
The problem arises as one part of your computation is done using integer arithmetic of type integer(4).
That type has an upper limit of 2^31-1 = 2147483647 whereas your intermediate result 5^15 = 30517578125 is slightly larger (thanks to #evets comment).
As pointed out in your question: you save the result in a real variable.
Therefor, you could just compute that exponentiation using real data types: 5.0**15.
Your formula will end up like the following
dFeV(x)= R1 * (5.0**15) * (a**2) * exp(-(VmigFe)/kbt)
Note that integer(4) need not be the same implementation for every processor (thanks #IanBush).
Which just means that for some specific machines the upper limit might be different from 2^31-1 = 2147483647.
As indicated in the comment, the value of 5**15 exceeds the range of 4-byte signed integers, which are the typical default integer type. So you need to instruct the compiler to use a larger type for these constants. This program example shows one method. The ISO_FORTRAN_ENV module provides the int64 type. UPDATE: corrected to what I meant, as pointed out in comments.
program test_program
use ISO_FORTRAN_ENV
implicit none
integer (int64) :: i
i = 5_int64 **15_int64
write (*, *) i
end program
Although there does seem to be an additional point here that may be specific to gfortran:
integer(kind = 8) :: result
result = 5**15
print *, result
gives: Error: Result of exponentiation at (1) exceeds the range of INTEGER(4)
while
integer(kind = 8) :: result
result = 5**7 * 5**8
print *, result
gives: 30517578125
i.e. the exponentiation function seems to have an integer(4) limit even if the variable to which the answer is being assigned has a larger capacity.
I am working on numerical analysis using a solver (the programming is based on object-oriented C++) compiled with double precision, and my unit is 64-bits. My problem is that when the solver computes a large number - say -1.45 to the power 21, to take an actual example - and stacks it in the allocated memory by passing this value to an existing variable, it is converted to 0. So of course, when I later use this variable in a division I get a segmentation fault. I do not understand how this process works, and because I use the DP, I do not see how to fix the issue. Could anyone give me a hand with this matter please ?
In case it helps: I just ran a test where I state a=-1.45e+21, and "print" the value which is returned correctly by the solver. But when I do not use the "e" exponent and enter the full value (with 19 zeros) I get 0 in return. So I guess the issue/limitation comes from the number of digits, any ideas ?? Thanks !
Edit: I post a summary of the steps I go through to compute one of the variables which poses an issue. The others being similarly defined.
First I initialise the field pointer lists:
PtrList<volScalarField> fInvFluids(fluidRegions.size());
Where the class of volScalarField is just an array of double. Then I populate the field pointer lists:
fInvFluids.set
(
i,
new volScalarField
(
IOobject
(
"fInv",
runTime.timeName(),
fluidRegions[i],
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
fluidRegions[i],
dimensionedScalar
(
"fInv",
dimensionSet(3,1,-9,-1,0,0,0),
scalar(0)
)
)
);
After this, I set the field regions:
volScalarField& fInv = fInvFluids[i];
And finally I compute the value:
// Info<< " ** Calculating fInv **\n";
fInv = gT*pow(pow(T/Tlambda, 5.7)*(1 - pow(T/Tlambda, 5.7)), 3);
Where T is field variable and Tlambda a scalar value defined at run time.
A double variable probably can't hold 19 zeroes either. A (decimal) digit takes more than 3 bits, so 19 zeroes will take at least 57 bits. A double typically has a mantissa which is only 53 bits.
However, that doesn't sound like the problem you have. In C++ code, expressions have a type as well. 1 is not the same as 1.0. The first is an int and the second a double. While you can convert an int to double, they're not the same. An int most likely can hold values up to 2 billion , but formally it may have a limit as low as 32767. The solution to your problem might be as simple as adding a twentieth zero : 100000000000000000000.0 making it a double.
I installed gfortran on my Ubuntu 15.04 system. While compiling Fortran code, the DO loop asks to take integer parameters only and not real values or variables. That includes the loop variable and the step expression. Why can't it take real values too?
The following is a program taken from here, exercise 3.5 of the section nested do loops.
program xytab
implicit none
!constructs a table of z=x/y for values of x from 1 to 2 and
!y from 1 to 4 in steps of .5
real :: x, y, z
print *, ' x y z'
do x = 1,2
do y = 1,4,0.5
z = x/y
print *, x,y,z
end do
end do
end program xytab
The error shown after compiling is:
xytab.f95:8.4:
do y = 1,4,0.5
1
Warning: Deleted feature: Loop variable at (1) must be integer
xytab.f95:8.12:
do y = 1,4,0.5
1
Warning: Deleted feature: Step expression in DO loop at (1) must be integer
xytab.f95:7.3:
do x = 1,2
1
Warning: Deleted feature: Loop variable at (1) must be integer
The Fortran standard now requires that a do construct's loop control is given by (scalar) integer expressions and that the loop variable is a (scalar) integer variable. The loop control consists of the start, step, and stop expressions (your step expression is 0.5). See R818 and R819 (8.1.6.2) of the Fortran 2008 document. That, then, is the short and simple answer: the standard says so.
It's a little more complicated than that, as the messages from the compiler suggest. Using other forms for loop control was present in Fortran up until Fortran 95. That is, from Fortran 95 onward using real expressions is a deleted feature.
What harm is there in using real expressions? Used correctly, one could imagine, there is no harm. But there's real difficulty in portability with them.
Consider
do x=0., 1., 0.1
...
end do
How many iterations? That would be (under the rules of Fortran 90) MAX(INT((m2 – m1 + m3) / m3), 0) where (m1 is the start value (0.), m2 the stop value (1.) and m3 the step value (0.1)). Is that 10 or 11 (or even 9)? It depends entirely on your numeric representation: we recall that 0.1 may not be exactly representable as a real number and INT truncates in converting to integer. You'd also have to worry about repeated addition of real numbers.
So, use integers and do some arithmetic inside the loop
do y_loop = 0, 6
y = 1 + y_loop/2.
...
end do
or
y = 1
do
if (y>4) exit
...
y = y+0.5
end do
Finally, you mention .f90 and .f95 file suffixes. gfortran doesn't take the first to mean that the source code follows the Fortran 90 standard (where the code would be fine). Further, the messages from the compiler are merely warnings, and these can be suppressed using the -std=legacy option. Conversely, using -std=f95 (or later standards) these become errors.
As a bonus fun fact consider the following piece of Fortran 90 code.
real y
integer i
loop_real: do y=1, 4, 0.5
end do loop_real
loop_integer: do i=1, 4, 0.5
end do loop_integer
While the loop named loop_real is valid, that named loop_integer isn't. In the calculation of the iteration count the three expressions are converted to the kind, with kind parameters, of the loop variable. INT(0.5) is 0.
As the title states I'm using FFTW (version 3.2.2) with Fortran 90/95 to perform a 2D FFT of real data (actually a field of random numbers). I think the forward step is working (at least I am getting some ouput). However I wanted to check everything by doing the IFFT to see if I can re-construct the original input. Unfortunately when I call the complex to real routine, nothing happens and I obtain no error output, so I'm a bit confused. Here are some code snippets:
implicit none
include "fftw3.f"
! - im=501, jm=401, and lm=60
real*8 :: u(im,jm,lm),recov(im,jm,lm)
complex*8 :: cu(1+im/2,jm)
integer*8 :: planf,planb
real*8 :: dv
! - Generate array of random numbers
dv=4.0
call random_number(u)
u=u*dv
recov=0.0
k=30
! - Forward step (FFT)
call dfftw_plan_dft_r2c_2d(planf,im,jm,u(:,:,k),cu,FFTW_ESTIMATE)
call dfftw_execute_dft_r2c(planf,u(:,:,k),cu)
call dfftw_destroy_plan(planf)
! - Backward step (IFFT)
call dfftw_plan_dft_c2r_2d(planb,im,jm,cu,recov(:,:,k),FFTW_ESTIMATE)
call dfftw_execute_dft_c2r(planb,cu,recov(:,:,k))
call dfftw_destroy_plan(planb)
The above forward step seems to work (r2c) but the backward step does not seem to work. I checked this by differencing the u and recov arrays - which ended up not being zero. Additionally the max and min values of the recov array were both zero, which seems to indicate that nothing was changed.
I've looked around the FFTW documentation and based my implementation on the following page http://www.fftw.org/fftw3_doc/Fortran-Examples.html#Fortran-Examples . I am wondering if the problem is related to indexing, at least that's the direction I am leaning. Anyway, if any one could offer some help, that would be wonderful!
Thanks!
Not sure if this is the root of all troubles here, but the way you declare variables may be the culprit.
For most compilers (this is apparently not even a standard), Complex*8 is an old syntax for single precision: the complex variable occupies a total of 8 bytes, shared between the real and the imaginary part (4+4 bytes).
[Edit 1 following Vladimir F comment to my answer, see his link for details:] In my experience (i.e. the systems/compiler I ever used), Complex(Kind=8) corresponds to the declaration of a double precision complex number (a real and an imaginary part, both of which occupy 8 bytes).
On any system/compiler, Complex(Kind=Kind(0.d0)) should declare a double precision complex.
In short, your complex array does not have the right size. Replace occurences of Real*8 and Complex*8 by Real(kind=8) and Complex(Kind=8) (or Complex(Kind=kind(0.d0)) for a better portability), respectively.
I have 2 dimensional table in file, which look like this:
11, 12, 13, 14, 15
21, 22, 23, 24, 25
I want it to be imported in 2 dimensional array. I wrote this code:
INTEGER :: SMALL(10)
DO I = 1, 3
READ(UNIT=10, FMT='(5I4)') SMALL
WRITE(UNIT=*, FMT='(6X,5I4)') SMALL
ENDDO
But it imports everything in one dimensional array.
EDIT:
I've updated code:
program filet
integer :: reason
integer, dimension(2,5) :: small
open(10, file='boundary.inp', access='sequential', status='old', FORM='FORMATTED')
rewind(10)
DO
READ(UNIT=10, FMT='(5I4)', iostat=reason) SMALL
if (reason /= 0) exit
WRITE(UNIT=*, FMT='(6X,5I4)') SMALL
ENDDO
write (*,*) small(2,1)
end program
Here is output:
11 12 13 14 15
21 22 23 24 25
12
Well, you have defined SMALL to be a 1-D array, and Fortran is just trying to be helpful. You should perhaps have defined SMALL like this;
integer, dimension(2,5) :: small
What happened when the read statement was executed was that the system ran out of edit descriptor (you specified 5 integers) before either SMALL was full or the end of the file was encountered. If I remember rightly Fortran will re-use the edit descriptor until either SMALL is full or the end-of-file is encountered. But this behaviour has been changed over the years, according to Fortran standards, and various compilers have implemented various non-standard features in this part of the language, so you may need to check your compiler's documentation or do some more experiments to figure out exactly what happens.
I think your code is also a bit peculiar in that you read from SMALL 3 times. Why ?
EDIT: OK, we're getting there. You have just discovered that Fortran stores arrays in column-major order. I believe that most other programming languages store them in row-major order. In other words, the first element of your array is small(1,1), the second (in memory) is small(2,1), the third is small(1,2) and so forth. I think that your read (and write) statements are not standard but widely implemented (which is not unusual in Fortran compilers). I may be wrong, it may be standard. Either way, the read statement is being interpreted to read the elements of small in column-major order. The first number read is put in small(1,1), the second in small(2,1), the third in small(1,2) and so on.
Your write statement makes use of the same feature; you might have discovered this for yourself if you had written out the elements in loops with the indices printed too.
The idiomatic Fortran way of reading an array and controlling the order in which elements are placed into the array, is to include an implied-do loop in the read statement, like this:
READ(UNIT=10, FMT='(5I4)', iostat=reason) ((SMALL(row,col), col = 1,numCol), row=1,numRow)
You can also use this approach in write statements.
You should also study your compiler documentation carefully and determine how to switch on warnings for all non-standard features.
Adding to what High Performance Mark wrote...
If you want to use commas to separate the numbers, then you should use list-directed IO rather than formatted IO. (Sometimes this is called format-free IO, but that non-standard term is easy to confuse with binary IO). This is easier to use since you don't have to arrange the numbers precisely in columns and can separate them with spaces or commas. The read is simply "read (10, *) variables"
But sticking to formatted IO, here is some sample code:
program demo1
implicit none
integer, dimension (2,5) :: small
integer :: irow, jcol
open ( unit=10, file='boundary.txt', access='sequential', form='formatted' )
do irow=1, ubound (small, 1)
read (10, '(5I4)') (small (irow, jcol), jcol=1, ubound (small, 2))
end do
write (*, '( / "small (1,2) =", I2, " and small (2,1)=", I2 )' ) small (1,2), small (2,1)
end program demo1
Using the I4 formatted read, the data need to be in columns:
12341234123412341234
11 12 13 14 15
21 22 23 24 25
The data file shouldn't contain the first row "1234..." -- that is in the example to make the alignment required for the format 5I4 clear.
With my example program, there is an outer do loop for irow and an "implied do loop" as part of the read statement. You could also eliminate the outer do loop and use two implied do loops on the read statement, as High Performance Mark showed. In this case, if you kept the format specification (5I4), it would get reused to read the second line -- this is called format reversion. (On a more complicated format, one needs to read the rules to understand which part of the format is reused in format reversion.) This is standard, and has been so at least since FORTRAN 77 and probably FORTRAN IV. (Of course, the declarations and style of my example are Fortran 90).
I used "ubound" so that you neither have to carry around variables storing the dimensions of the array, nor use specific numeric values. The later method can cause problems if you later decide to change the dimension of the array -- then you have to hunt down all of the specific values (here 2 and 5) and change them.
There is no need for a rewind after an open statement.