I'm having a runtime error when I run a code that works without problems using a different computer.
I'm wondering if the problem is the Fortran compiler of this machine (GCC 4.9.2) since the former computer used a previous version.
The issue comes when defining a variable like this:
In a module I define
character(30),allocatable,save :: sceneclass(:)
Then in the subroutine sceneclass is defined according to
character(30) surf, frac, scene
allocate(sceneclass(10))
do i=1,10
write(sceneclass(i),*) trim(scene)//trim(surf)//'_'//trim(frac)
enddo
In the first iteration I get the "End of record". But I don't know where is the problem. It seems to work fine in other computers.
You are probably writing a string to sceneclass(i) that is longer then the 30 chars you specified.
I can reproduce this with
program test
implicit none
character(10),allocatable :: sceneclass(:)
integer :: i
allocate( sceneclass(10) )
do i=1,10
write(sceneclass(i),*) 10**i
enddo
print *, ( trim(sceneclass(i)), i=1,10 )
end program
gfortran fails with
Fortran runtime error: End of record
while ifort reports the error correctly:
output statement overflows record, unit -5, file Internal List-Directed Write
Increasing the string length to 12 solves the issue in this case. You can (and should) use iostat within the write statement to capture this.
One thing to be aware of, when you specify a list directed * write of a character string, the compiler always(?) adds an extra lead blank, so the effective length of the string you can write is one less than you might expect.
To remedy that (and of course assuming you don't want the lead blank anyway ) use a string edit descriptor:
write(sceneclass(i),'(a)')...
Interestingly ifort (linux 11.1) actually allows you to overrun by one character:
character*5 c
write(c,*)'12345' ! result: " 1234"
which I would consider a bug. It seems they forgot to count the blank too.. ( gfortran throws the above error on this, and ifort balks if you add one more character )
see here if you wonder why the blank.. Are Fortran control characters (carriage control) still implemented in compilers?
and now I'm curious if some compiler somewhere didn't do that for an internal list write, or maybe your code was previously compiled with a flag to disable the "printer control" code
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.
I was trying to test my cryptography algorithm by [diehard tests] (http://stat.fsu.edu/pub/diehard/), that I realized my input file must be an unformatted and direct access file.
So I tried to write a simple program in Fortran to read from a file and write it to another.
First of all, is it the only way to make an unformatted or direct access file ?
If it is so, I've got this Error
open(unit=2, file='unf.BIN',RECL=rl , form='UNFORMATTED', access='direct')
1
Error: Syntax error in OPEN statement at (1)
I use RECL because of some missing RECL parameter in Open statement errors.(Fortran 90, Compiling program: Error messages)
Here is my Fortran code:
program BinaryWriter
implicit none
integer :: i
integer :: p
open(unit=1,file='encout')
open(unit=2, file='unf.BIN',RECL=rl , form='UNFORMATTED', access='direct')
do i=1 ,256
read (8,'(i1)') p
write(*,*) p
end do
close(1)
close(2)
end program BinaryWriter
Two things:
1) Please stop using unit numbers less than 10. Virtually all modern Fortran compilers do now have the newunit identifier, which, instead of the old unit actually picks an unused value, so always use a variable there. But even if you want to use unit, set it to a value of 10 or more.
2) For direct access, the program needs the record length. So if you have access="direct", you also need an recl=<some integer value> to tell the compiler where a new record starts.
Now in your case, you have a RECL=rl entry in the open statement, but I can't see what rl is. It needs to be a positive integer.
Edit to add: As #IanH pointed out in a comment below your question, it is possible that you are using fixed form fortran. This might be caused by the file extension of your source code file being .f or .f77. In that case, you'd have to wrap your lines manually:
program dir
implicit none
integer :: rl
open(unit=20, file='delme.bin', recl=<the record length>,
& form='unformatted', access='direct')
close(20)
end program dir
Note that the & is in the 6th position of the line. Fortran 77 code usually uses a + there, but & is also compatible with newer Fortran versions, that's why I prefer it. F77 standard is just any character in that 6th spot.
I have noticed the results of list-directed output write(*,*) in Fortran is compiler dependent.
Indeed, with the code:
program one
real(8), dimension(5):: r1
do i=1,5
r1(i)=sqrt(i*10.0)
end do
write(*,*) (r1(i), i =1,5)
end program one
intel compiler ifort gives standard output broken by a newline:
3.16227769851685 4.47213602066040 5.47722530364990
6.32455539703369 7.07106781005859
while gfortran gives the equivalent one line result:
3.1622776601683795 4.4721359549995796 5.4772255750516612 6.3245553203367590 7.0710678118654755
I think that ifort is writing maximum 3 items per line (when floating real numbers).
Is there any way to make the ifort output be like gfrotran, i.e. avoid the newline?
Ideally, I would like to keep list-directed output (*,*) instructions, so I am looking for something like a compiler option or so, if any.
Since verson 14, intel fortran compiler has the wrap-margin function. By default, the record is wrapped after 80 characters. For disabling this restriction, you should specify:
on Linux: -no-wrap-margin
on WIndows: /wrap-margin-
See more on Intel Fortran's reference guide
No. List-directed (free-format) output provides convenience, but you give up control. Various aspects of the output are unspecified and allowed to be chosen to the compiler. If you want full control, you have to use formatted output.
Look into edit descriptors in your favorite Fortran book or online documentation. You can use fmt specifier in the write statement to specify edit descriptors. For example:
write(*,fmt='(5(F6.4,3X))') (r1(i), i =1,5)
should output something similar to:
3.1623 4.4721 5.4772 6.3246 7.0711
See https://software.intel.com/en-us/forums/topic/401555
Specify FORT_FMT_RECL or use
write (,"(G0,1X))"
My Fortran code needs to read a initialize data (about 24000 real numbers) from a file. Are there any ways to put the data in the code so that I can avoid accessing the filesystem?
I tried to use a module and put all the data into a variable initialization like this:
real(kind=8) :: a(24000)=(/&
& 1. ,&
& 2. ,&
...
&/)
but because of there are 24000 lines for the source file, I keep receiving compiling error "Too many continuation lines". Are there any solution to this?
You can use DATA statements for this.
The fact that you can "slice" up your array into sections (such as setting a[1..100] in one section, a[101..200] in the next and so on) means that you should be able to avoid the massive-statement-size problem you're experiencing.
For such a large amount of data I would use some script language (or even Fortran) to generate a chunk of simple Fortran code like
a(1) = ..
a(2) = ..
a(3) = ..
This code could be then copy-pasted or include-d into your source code.
One option may be to instruct your compiler to allow unlimited line lengths
and put the whole darn thing on one line.
gfortran -ffree-line-length-none
I've verified this works. I've got a 2Mb source file with just 3 lines
real(kind=8) :: a(24000)=(/ ......... /)
write(*,*)a(24000)
end
I wouldn't be surprised if some compiler has a practical line length limit though.
By the way gfortran does not like using a big data statement.
No error it just hangs (or takes a very long time )
//
Imagine that, my big data version actually compiled (and runs fine ) after 1.5 hours. Why data is handled by the compiler so vastly differently from an initialization assignment is a good question.
As the previous author stated you can use the data statement, but it can be time consuming to enter it into the code manually. Is there a reason that you are apprehensive about the use of a READ statement in a do loop to read in the file? If you can provide us with any input on the data file format we can better help you.
It might seem to be archaic, but you could use INCLUDE. You'd need to modify your data file to have the form you gave,
real(8), dimension(24000) :: a=(/1.0,2.0,...24000./)
and then include it in the main program as such:
program main
implicit none
include "my_data_file.for"
< ... >
end program main
You won't need to change your compilation command, your Fortran compiler will import the included file on its own--so long as the included file is in the same directory.