Related
I have a project written in VS2010 with Intel Visual Fortran. I have a dump subroutine to write a 2D matrix into file:
subroutine Dump2D(Name,Nx,Ny,Res)
implicit none
integer i,j,Nx,Ny
real(8) :: Res(Nx,Ny)
character(len=30) name,Filename
logical alive
write(filename,*) trim(Name),".dat"
Write(*,*) "Saving ",trim(Name)," Please wait..."
open (10,file=filename)
do i=1,Ny
Write(10,FMt="(D21.13\)") (Res(j,i),j=1,Nx)
Write(10,*)
end do
close(10)
Write(*,*) "Save ",trim(Name),"Complete!"
return
end subroutine Dump2D
It is ok to compile and run. But when I compile in emacs using gfortran it gives me the error:
I think it's because the gfortran doesn't recognize \ in a format for a write command. How do I fix this problem?
Write(10,FMt="(D21.13\)") (Res(j,i),j=1,Nx)
1
Error: Unexpected element '\' in format string at (1)
The edit descriptor \ relates to backslash editing. This is a non-standard extension provided by the Intel compiler (and perhaps others). It is not supported by gfortran.
Such backslash editing is intended to affect carriage control. Much as in this answer such an effect can be handled with the (standard) non-advancing output.1
As you simply want to output each column of a matrix to a record/line you needn't bother with this effort.2 Instead (as you'll see in many other questions):
do i=1,Ny
write(10,fmt="(*(D21.13))") Res(:,i)
end do
There are also other approaches which a more general search will find.
1 The Intel compiler treats \ and $ in the same way.
2 There are subtle aspects of \, but I'll assume you don't care about those.
Another approach (although francescalus answer is better in your case) would be to build a format string that contains the number of elements to include in your row. One way of doing this is to use the following to build the format string (which uses an explicit space character to separate elements within a line in the file):
WRITE(fmtString, '(A,I0,A)') '(', Nx, '(D21.13,:,1X))' *
Then use the format string variable in your WRITE statement as so:
do i=1,Ny
Write(10,FMt=fmtString) (Res(j,i),j=1,Nx)
end do
This approach can also be very useful if you want to use something other than spaces to separate elements (e.g. commas or semicolons).
*As that's a little difficult to read, I will provide an example. For Nx = 3, this would be equivalent to:
fmtString = '(3(D21.13,:,1X))'
Which is 2 numbers formatted using D21.13, each followed by a space, and a final number formatted using D21.13, but without a space after it (as the ":" stops at the final item).
The backslash is not valid in Fortran 77 FORMAT statements. Gfortran will not compile it, unless you fix the code. There is no flag that will change that AFAIK (-fbackslash should not help here).
If I understand the intention correctly (and I may be wrong), the backslash does the same as the dollar sign in some other compilers and prevents terminating a record (line). In that case the advance="no" put in the write statement should help. It is Fortran 90, but you should not avoid it just for that reason.
I have a project written in VS2010 with Intel Visual Fortran. I have a dump subroutine to write a 2D matrix into file:
subroutine Dump2D(Name,Nx,Ny,Res)
implicit none
integer i,j,Nx,Ny
real(8) :: Res(Nx,Ny)
character(len=30) name,Filename
logical alive
write(filename,*) trim(Name),".dat"
Write(*,*) "Saving ",trim(Name)," Please wait..."
open (10,file=filename)
do i=1,Ny
Write(10,FMt="(D21.13\)") (Res(j,i),j=1,Nx)
Write(10,*)
end do
close(10)
Write(*,*) "Save ",trim(Name),"Complete!"
return
end subroutine Dump2D
It is ok to compile and run. But when I compile in emacs using gfortran it gives me the error:
I think it's because the gfortran doesn't recognize \ in a format for a write command. How do I fix this problem?
Write(10,FMt="(D21.13\)") (Res(j,i),j=1,Nx)
1
Error: Unexpected element '\' in format string at (1)
The edit descriptor \ relates to backslash editing. This is a non-standard extension provided by the Intel compiler (and perhaps others). It is not supported by gfortran.
Such backslash editing is intended to affect carriage control. Much as in this answer such an effect can be handled with the (standard) non-advancing output.1
As you simply want to output each column of a matrix to a record/line you needn't bother with this effort.2 Instead (as you'll see in many other questions):
do i=1,Ny
write(10,fmt="(*(D21.13))") Res(:,i)
end do
There are also other approaches which a more general search will find.
1 The Intel compiler treats \ and $ in the same way.
2 There are subtle aspects of \, but I'll assume you don't care about those.
Another approach (although francescalus answer is better in your case) would be to build a format string that contains the number of elements to include in your row. One way of doing this is to use the following to build the format string (which uses an explicit space character to separate elements within a line in the file):
WRITE(fmtString, '(A,I0,A)') '(', Nx, '(D21.13,:,1X))' *
Then use the format string variable in your WRITE statement as so:
do i=1,Ny
Write(10,FMt=fmtString) (Res(j,i),j=1,Nx)
end do
This approach can also be very useful if you want to use something other than spaces to separate elements (e.g. commas or semicolons).
*As that's a little difficult to read, I will provide an example. For Nx = 3, this would be equivalent to:
fmtString = '(3(D21.13,:,1X))'
Which is 2 numbers formatted using D21.13, each followed by a space, and a final number formatted using D21.13, but without a space after it (as the ":" stops at the final item).
The backslash is not valid in Fortran 77 FORMAT statements. Gfortran will not compile it, unless you fix the code. There is no flag that will change that AFAIK (-fbackslash should not help here).
If I understand the intention correctly (and I may be wrong), the backslash does the same as the dollar sign in some other compilers and prevents terminating a record (line). In that case the advance="no" put in the write statement should help. It is Fortran 90, but you should not avoid it just for that reason.
Part of a code in a Fortran project that I am trying to compile is
implicit double precision (a-h,o-z)
dimension fact(1:5)
data fact /
d660p=rpt1*dp(6,beta2,rpt1)*d3(0,6,0,beta2,rpt1,rpt2,rpt3)
1 +rpt2*dp(6,beta2,rpt2)*d3(6,0,0,beta2,rpt1,rpt2,rpt3)
d606p=rpt1*dp(6,beta2,rpt1)*d3(0,0,6,beta2,rpt1,rpt2,rpt3)
1 +rpt3*dp(6,beta2,rpt3)*d3(6,0,0,beta2,rpt1,rpt2,rpt3)
d066p=rpt2*dp(6,beta2,rpt2)*d3(0,0,6,beta2,rpt1,rpt2,rpt3)
1 +rpt3*dp(6,beta2,rpt3)*d3(0,6,0,beta2,rpt1,rpt2,rpt3)
d633p=rpt1*dp(6,beta3,rpt1)*d3(0,3,3,beta3,rpt1,rpt2,rpt3)
1 +rpt2*dp(3,beta3,rpt2)*d3(6,0,3,beta3,rpt1,rpt2,rpt3)
1 +rpt3*dp(3,beta3,rpt3)*d3(6,3,0,beta3,rpt1,rpt2,rpt3)
d363p=rpt1*dp(3,beta3,rpt1)*d3(0,6,3,beta3,rpt1,rpt2,rpt3)
1 +rpt2*dp(6,beta3,rpt2)*d3(3,0,3,beta3,rpt1,rpt2,rpt3)
1 +rpt3*dp(3,beta3,rpt3)*d3(3,6,0,beta3,rpt1,rpt2,rpt3)
d336p=rpt1*dp(3,beta3,rpt1)*d3(0,3,6,beta3,rpt1,rpt2,rpt3)
1 +rpt2*dp(3,beta3,rpt2)*d3(3,0,6,beta3,rpt1,rpt2,rpt3)
1 +rpt3*dp(6,beta3,rpt3)*d3(3,3,0,beta3,rpt1,rpt2,rpt3)/
however, compiling generates the following errors
mc.f(2003): error #5082: Syntax error, found END-OF-STATEMENT when expecting one of: ( <IDENTIFIER> <CHAR_CON_KIND_PARAM> <CHAR_NAM_KIND_PARAM> <CHARACTER_CONSTANT> <INTEGER_CONSTANT> ...
data fact /
------------------^
mc.f(2018): error #5082: Syntax error, found END-OF-STATEMENT when expecting one of: ( <IDENTIFIER> <CHAR_CON_KIND_PARAM> <CHAR_NAM_KIND_PARAM> <CHARACTER_CONSTANT> <INTEGER_CONSTANT> ...
1 +rpt3*dp(8,beta8,rpt3)*d3(0,6,0,beta8,rpt1,rpt2,rpt3) /
------------------------------------------------------------------^
compilation aborted for mc.f (code 1)
Does anybody knows how to get the code working?
The syntax error you get is because data fact / is on a line on its own with nothing after the opening slash. The compiler expects a constant or parameter name and tells you so. As is, the data statement is incomplete. (Thanks for High Performance Mark for pointing this out. I missed this in my earlier answer.)
You can make the compiler treat whole data statement up to the closing slash as a single line by using the continuation mark on every line after the data line. Your continuations continue only the expressions inside the data. (And the items inside datashould be separated by commas.)
Fixing the continuation and the commas will not make the code compile, though.
The data statement initialises variables when the program starts. The numbers between the slashes must therefore be constants or named parameters. You cannot use expressions, not even expressions on constants. (The expression 3*0.0 has a special meaning inside data; it means three times the value zero, i.e. 0.0, 0.0, 0.0.)
If you want to initialise your array, use assignments, which will calculate the entries based on the current value of the variables:
fact(1) = rpt1*dp(6,beta2,rpt1)*d3(0,6,0,beta2,rpt1,rpt2,rpt3)
1 + rpt2*dp(6,beta2,rpt2)*d3(6,0,0,beta2,rpt1,rpt2,rpt3)
or, if you also need the intermediary variables:
d660p = rpt1*dp(6,beta2,rpt1)*d3(0,6,0,beta2,rpt1,rpt2,rpt3)
1 + rpt2*dp(6,beta2,rpt2)*d3(6,0,0,beta2,rpt1,rpt2,rpt3)
fact(1) = d660p
By the way, your array has five entries, but you are trying to initialise six. And implicit variable naming isn't a good idea either.
I'm attempting to modernize an old code (or at least make it a bit more understandable) but I've run into an odd format for a, uh, FORMAT statement.
Specifically, it's a FORMAT statement with Hollerith constants in it (the nH where n is a number):
FORMAT(15H ((C(I,J),J=1,I3,12H),(D(J),J=1,I3, 6H),I=1,I3,') te'
1,'xt' )
This messes with the syntax highlighting as it appears this has unclosed parenthesis. It compiles fine with this format statement as is, but closing the parenthesis causes a compiling error (using either the intel or gfortran compiler).
As I understand it, Hollerith constants were a creature of Fortran 66 and were replaced with the advent of the CHARACTERin Fortran 77. I generally understand them when used as something like a character, but use as a FORMAT confuses me.
Further, if I change 15H ((... to 15H ((... (i.e. I remove one space) it won't compile. In fact, it won't compile even if I change the code to this:
FORMAT(15H ((C(I,J),J=1,I3,12H),(D(J),J=1,I3, 6H),I=1,I3,') text' )
I would like this to instead be in a more normal (F77+) format. Any help is appreciated.
What you have are actually Hollerith edit descriptors, not constants (which would occur in a DATA or CALL statement), although they use the same syntax. F77 replaced Hollerith constants outright; it added char-literal edit descriptor as a (much!) better alternative, but H edit descriptor remained in the standard until F95 (and even then some compilers still accepted it as a compatibility feature).
In any case, the number before the H takes that number of characters after the H, without any other delimiter; that's why deleting (or adding) a character after the H screws it up. Parsing your format breaks it into these pieces
15H ((C(I,J),J=1,
I3,
12H),(D(J),J=1,
I3,
6H),I=1,
I3,
') te'
'xt'
and thus a modern equivalent (with optional spaces for clarity) is
nn FORMAT( ' ((C(I,J),J=1,', I3, '),(D(J),J=1,', I3, '),I=1,', I3
1,') text' )
or if you prefer you can put that text after continuation (including the parens) in a CHARACTER value, variable or parameter, used in the I/O statement instead of a FORMAT label, but since you must double all the quote characters to get them in a CHARACTER value that's less convenient.
Your all-on-one-line version probably didn't compile because you were using fixed-form, perhaps by default, and only the first 72 characters of each source line are accepted in fixed-form, of which the first 6 are reserved for statement number and continuation indicator, leaving only 66 and that statement is 71 by my count. Practically any compiler you will find today also accepts free-form, which allows longer lines and has other advantages too for new code, but may require changes in existing code, sometimes extensive changes.
Is it possible to read a line with numerous numbers(integers) using Fortran?
lets say i have a file with only only line
1 2 3
the following program reads 3 integers in a line
program reading
implicit none
integer:: dump1,dump2,dump3
read(21,*) dump1,dump2,dump3
end
so dump1=1 dump2=3 dump3=3
If i have a file with only one line but with numerous integers like
1 2 3 4 5 6 7 8 ... 10000
is ti possible the above program to work without defining 10000 variables?
EDIT The first paragraph of this answer might seem rather strange as OP has modified the question.
Your use of the term string initially confused me, and I suspect that it may have confused you too. It's not incorrect to think of any characters in a file, or typed at a command-line as a string, but when all those characters are digits (interspersed with spaces) it is more useful to think of them as integers. The Fortran run-time system will
take care of translating a string of digit characters into an integer.
In that light I think your question might be better expressed as How to read a list of integers from an input line ? Here's one way:
Define an array. Here I define an array of fixed size:
integer, dimension(10**4) :: dump
(I often use expressions such as 10**4 to avoid having to count 0s carefully). This step, defining an array to capture all the values, seems to be the one you are missing.
To read those values from the terminal, at run-time, you might write
write(*,*) 'Enter ', 10**4, 'numbers now'
read(*,*) dump
and this will set dump(1) to the first number you type, dump(2) to the second, all the way to the 10**4-th. Needless to say, typing that number of numbers at the terminal is not recommended and a better approach would be to read them from a file. Which takes you back to your
read(21,*) dump
It wouldn't surprise me to find that your system imposes some limit on the length of a single line so you might have to be more sophisticated when trying to read as many as 10**4 integers, such as reading them in lines of 100 at a time, something like that. That's easy
read(*,*) dump(1:100)
will read 100 integers into the first 100 elements of the array. Write a loop to read 100 lines of 100 integers each.