I'm writing a preprocessor and postprocessor for Fortran input and output using FORMAT-like statements (there are reasons not to use a FORTRAN library). I want to treat the new line ("/") character correctly. I don't have a Fortran compiler immediately to hand. Is there a simple algorithm for working out how many newlines are written or consumed (This post just gives reading examples)
[Please assume a FORTRAN77-like mentality in the FORTRAN code and correct any FORTRAN syntax on my part]
UPDATE: no comments yet so I am reduced to finding a compiler and running it myself. I'll post the answers if I'm not beaten to it. No-one commented I had the format syntax wrong. I've changed it but there may still be errors
Assume datafile 1
a
b
c
d
etc...
(a) does the READ command always consume a newline? does
READ(1, '(A)') A
READ(1, '(A)') B
give A='a' and B='b'
(b) what does
READ(1,'(A,/)') A
READ(1,'(A)') B
give for B? (I would assume 'c')
(c) what does
READ(1, '(/)')
READ(1, '(A)') A
give for A (is it 'b' or 'c')
(d) what does
READ(1,'(A,/,A)') A, B
READ(1,'(A)') C
give for A and B and C(can I assume 'a' and 'b' and 'c')
(e) what does
READ(1,'(A,/,/,A)') A, B
READ(1,'(A)') C
give for A and B and C(can I assume 'a' and 'c' and 'd')?
Are there any cases in which the '/' is redundant?
To be precise the slash edit descriptor, represented by the character /, is actually the end of record specifier. I'm now going to quote from the draft Fortran 2008 standard, I don't think the programming language's behaviour has changed in this respect since FORTRAN77, but I'm not certain. I'm quoting from the standard because (a) if you are writing a pre- and post-processor I guess you will want it to adhere to the standard rather than to some ambiguous explanation of it which is all I could provide, and (b) there are so many variations in Fortran I/O statements that I am really familiar with only a few of them (and this isn't one of them).
10.8.2 Slash editing
1 The slash edit descriptor indicates the end of data transfer to or from the current record.
2 On input from a file connected for sequential or stream access, the remaining portion of the current record is skipped and the file is positioned at the beginning of the next record. This record becomes the current record. On output to a file connected for sequential or stream access, a new empty record is created following the current record; this new record then becomes the last and current record of the file and the file is positioned at the beginning of this new record.
3 For a file connected for direct access, the record number is increased by one and the file is positioned at the beginning of the record that has that record number, if there is such a record, and this record becomes the current record.
(NOTE 10.25 A record that contains no characters may be written on output. If the file is an internal file or a file connected for direct access, the record is filled with blank characters. An entire record may be skipped on input.)
4 The repeat specification is optional in the slash edit descriptor. If it is not specified, the default value is one.
So, the slash can be used to read to the end of a partially-read record and to skip a record entirely (mutatis mutandis for writing).
If I compile your program (Intel Fortran 11.1 on Mac OS X) I get the following output:
a
b
====== example b
a
c
====== example c
c
====== example d
a
b
c
====== example e
a
c
d
====== example f
a
b
which suggests that, based on my interpretation of the standard, gfortran exhibits non-standard behaviour. However, I suspect that if you are more specific in your I/O operations, you might perhaps want to specify record lengths in your READ and WRITEs, you may be able to achieve what you want.
As there have been no comments so far, I'm adding my own answer. (If anyone adds light to this I'll give them votes).
Program:
program TEST
character (len=80) :: a,b,c
write(6,'(a)') '====== example a'
open(1,file='test1.dat',form='formatted',status='old',action='read')
READ(1, '(A)') a
READ(1, '(A)') b
write(6,'(a)') a
write(6,'(a)') b
close(1)
write(6,'(a)') '====== example b'
open(1,file='test1.dat',form='formatted',status='old',action='read')
READ(1, '(A,/)') a
READ(1, '(A)') b
write(6,'(a)') a
write(6,'(a)') b
close(1)
write(6,'(a)') '====== example c'
open(1,file='test1.dat',form='formatted',status='old',action='read')
READ(1, '(/)')
READ(1, '(A)') A
write(6,'(a)') a
close(1)
write(6,'(a)') '====== example d'
open(1,file='test1.dat',form='formatted',status='old',action='read')
READ(1, '(A,/,A)') a,b
READ(1, '(A)') c
write(6,'(a)') a
write(6,'(a)') b
write(6,'(a)') c
close(1)
write(6,'(a)') '====== example e'
open(1,file='test1.dat',form='formatted',status='old',action='read')
READ(1,'(A,/,/,A)') a, b
READ(1,'(A)') c
write(6,'(a)') a
write(6,'(a)') b
write(6,'(a)') c
close(1)
write(6,'(a)') '====== example f'
open(1,file='test1.dat',form='formatted',status='old',action='read')
READ(1, '(A1)') a
READ(1, '(A1)') b
write(6,'(a)') a
write(6,'(a)') b
close(1)
end
compiled under gfortran gives:
gfortran -O2 -c test.f90
gfortran -o test.x *.o
C:\test>test.x
====== example a
a
b
====== example b
a
c
====== example c
c
====== example d
a
b
c
====== example e
a
c
d
====== example f
a
b
QUESTION:
why are there additional new lines between all the outputs? Is there a newline in the strings that have been read in?
Those new lines are really 79 printed spaces. Use the LEN_TRIM() function to your write statements like this:
write(6,'(a)') a(1:LEN_TRIM(a))
or change the length of your character field to (1)
Related
subroutine iswap (file, b)
integer b
open(1,file = "file",status='unknown',form="unformatted")
write (1) b
close(1)
end
program callex
open(22, file = 'data1.dat')
call iswap(file,2)
close(22)
stop
end
Output: empty dat1.dat file
I'm completely new to Fortran. I'm trying to write the code that produces an output file "dat1.dat" containing the value of b, i.e 2, by using the "iswap" subroutine, but I'm getting an empty file. Could you please tell me the mistake I made in the code?
Thanks in advance.
By
open(1,file = "file",status='unknown',form="unformatted")
you are opening (creating if does not exiat) creating a file called "file"
and by
write (1) b
you write the value of b to this file.
The file "data1.dat" is opened under unit 22 so you have to write to that unit if you want to write to this file.
write (22) b
There is no reason to open and close another file called "file" in your subroutine.
It is also very important to use implicit none. Otherwise you have will be surprised by having undeclared stuff like the file variable you use in call iswap(file,2).
You can pass the unit number to your subroutine
subroutine iswap (unit, b)
implicit none
integer unit, b
write (unit) b
end
program callex
implicit none
open(22, file = 'data1.dat')
call iswap(22,2)
close(22)
end
There is no reason for the stop statement before the end. It is useless and may indoce some surprising messages like the signalling FPE exceptions.
Finally, you should to learn how to put your subroutines into a module as soon as possible. I strongly suggest to avoid external subroutines if at all possible. Also use some consistent indentation (spaces at the start of the lines) so that the structure is better visible.
module subs
implicit none
contains
subroutine iswap (unit, b)
integer, intent(in) :: unit, b
write(unit) b
end subroutine
end module
program callex
use subs
implicit none
open(22, file = 'data1.dat')
call iswap(22, 2)
close(22)
end program
It is also quite useless to use status="unknown". If you want to specify status, choose something specific "old", "new", "replace", otherwise just leave it out. There are many other specifiers in the open statement that are worth learning, like action (read/write) and others that control other modes for binary files. This is not a place to show them, they are explained in various manuals, tutorials and textbooks.
I'm new to Fortran. I was given a file that is supposed to be in Fortran 90, but written to be compiled with the Lahey Fujitsu compiler (the sparse documentation states that it should be compiled with lf95 filename.f -out compiled_name #imsllf95.cmd). However, some lines are commented with c, which as I understand was the way to comment in Fortran 77. Also, matrices are declared like REAL*8, DIMENSION(23,8) :: xxx19, which again I think is from Fortran 77.
For the most part, I can compile the file with gfortran or ifort except for a section that requires the computation of a matrix inverse. Apparently, in the LF95 compiler (using a propietary module IMSLF90), a matrix inverse was computed with .i.. If I delete those inversions, the file compiles and runs with no problem (apart from the fact that it gives the wrong result).
I'm trying to find the version of Fortran this code is written in, so that I can then search for some code written in that same version so that I can invert the matrices in the code.
EDIT: The file has extension .f, even though the compiling instructions seem to imply that it is Fortran 95.
Here I have some sections of the code:
PROGRAM estimate_group
implicit none
INTEGER :: i,j,k,full,group1
REAL*8, DIMENSION(500) :: theta_start,theta_input
OPEN(68, STATUS="REPLACE",file='fit_measures.txt')
c OPEN(68, file='fit_measures.txt')
REWIND(68)
DO full=1,1
PRINT *, "=================================="
PRINT *, "FULL LOOP #: ", full
PRINT *, "=================================="
WRITE(68, *) "=================================="
WRITE(68, *) "FULL LOOP #: ", full
WRITE(68, *) "=================================="
DO group1=2,28
c Additional If statement to focus on top level and scale
c IF ( ((group1>=22) .AND. (group1<=28)) .OR. (group1==2)) THEN
IF ( group1==2) THEN
c READING IN THETA VECTOR FROM PREVIOUS ITERATIONS
c (starting values taken from prior runs theta output)
c ====================================================
IF ((group1==2) .AND. (full==1)) THEN
theta_input=0.0*theta_input
OPEN(67, file='theta_input1.txt')
REWIND(67)
DO i=1,500
READ(67,*) theta_input(i)
END DO
ELSE
theta_input=0.0*theta_input
OPEN(66,file='theta_input.txt')
REWIND(66)
DO i=1,500
READ(66,*) theta_input(i)
END DO
END IF
SUBROUTINE estimate(group1, theta_start)
INTEGER, INTENT(IN) :: group1
REAL*8, INTENT(IN), DIMENSION(500) :: theta_start
c Variable Declarations:\
INTEGER :: i,j,k,m,l,t0,i0,improve,max_m
REAL*8, DIMENSION(23,8) :: xxx19
xxx19(1:23,1) = (/554.0,541.1,583.3,593.2,615.8,582.0,582.5,546.5,
& 538.4,494.1,503.3,494.1,486.9,478.6,432.6,439.6,
& 380.4,355.4,305.9,271.8,254.6,208.8,202.8/)
Real*8 is not part of Fortran, and has never been part of Fortran. So the strict answer to your question is it is not Fortran of any vintage.
However going on what you have shown apart from Real*8 it is Fortran 90 or later. Fixed source form is still part of the language (though I would fail any students I have for using it) so it not an indicator of the vintage of the code. However after a quick look at the above I can see the following features which came into the standard language in Fortran 90:
Mixed case (outside character variables and constants)
Underscore in symbol name
Implicit None
:: in variable declarations and comma separated attribute lists
Variable names longer than 6 characters
Double inverted commas (") to delimit character strings
Do ... End Do (I assume you have missed out the End Do for some reason as otherwise the fragments above make no sense whatsoever)
== to test equality
Intent for dummy arguments
Array sections
Array constructors
There may be others.
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 am writing following fortran 90 program and compiling with GNU Fortran Compiler. However, I am getting some errors that I can't resolve. Can someone explain me where I am going wrong?
PROGRAM FILE1
IMPLICIT NONE
INTEGER:: status,a,b,c,i,j
a=5
b=6
c=1
REAL,ALLOCATABLE,DIMENSION (:,:) :: arr1
ALLOCATE (arr1(a,b))
DO i=1,a,1
DO j=1,b,1
arr1(i,j)=c
c=c+1
END DO
END DO
DO i=1,a,1
DO j=1,b,1
WRITE (*,100,ADVANCE=NO) arr1(i,j)
100 FORMAT (1X,I4.1)
END DO
WRITE (*,110)
110 FORMAT ('',/)
END DO
DEALLOCATE(arr1)
END PROGRAM
I got several errors, e.g. in statement REAL,ALLOCATABLE,DIMENSION (:,:) :: arr1 Error: Unexpected data declaration statement at (1). I checked syntax from several sources, but no luck. There is error in statement WRITE (*,100,ADVANCE=NO) arr1(i,j) too. Can someone comment?
The posted code has a couple of issues:
you need to define all your variables before you execute any other statement.
a=5
b=6
c=1
should come after your last variable definition:
REAL,ALLOCATABLE,DIMENSION (:,:) :: arr1
You need to quote NO in the WRITE statement:
WRITE (*,100,ADVANCE="NO") arr1(i,j)
Since you are writing a REAL value, you need to give a floating point format in such as f or g
100 FORMAT (1X,f7.3)
The working code would be:
PROGRAM FILE1
IMPLICIT NONE
INTEGER:: status,a,b,c,i,j
REAL,ALLOCATABLE,DIMENSION (:,:) :: arr1
a=5
b=6
c=1
ALLOCATE (arr1(a,b))
DO i=1,a,1
DO j=1,b,1
arr1(i,j)=c
c=c+1
END DO
END DO
DO i=1,a,1
DO j=1,b,1
WRITE (*,100,ADVANCE="NO") arr1(i,j)
100 FORMAT (1X,f7.3)
END DO
WRITE (*,110)
110 FORMAT ('',/)
END DO
DEALLOCATE(arr1)
END PROGRAM
I have the following FORTRAN
SUBROUTINE SETPATHS(INPUT)
!DEC$ ATTRIBUTES DLLEXPORT::SetPaths
CHARACTER*20 INPUT
CHARACTER*20 DIRECTORY
DIRECTORY = 'ABCDEFG'
WRITE(6, *) 'INPUT LEN_TRIM = ', LEN_TRIM(INPUT)
WRITE(6, *) 'DIRECTORYLEN_TRIM = ', LEN_TRIM(DIRECTORY)
END SUBROUTINE
And I'm calling the function from C#, passing in 'ABCDEFG'.
When I set a breakpoint on my debugger, INPUT and DIRECTORY have the exact same characters. Both have 'ABCDEFG' followed by the same number of trailing spaces.
However, the program outputs
INPUT LEN_TRIM = 20
DIRECTORYLEN_TRIM = 7
Is this correct behavior? If the two strings have the same values, why does LEN_TRIM give different results?
Update: I found this documented problem (although it's not my Intel 8.1 compiler). http://support.microsoft.com/kb/89131
sbo#dhcp-045:~ $ ./a.out
INPUT LEN_TRIM = 7
DIRECTORYLEN_TRIM = 7
sbo#dhcp-045:~ $ more test.f90
SUBROUTINE SETPATHS(INPUT)
CHARACTER*20 INPUT
CHARACTER*20 DIRECTORY
DIRECTORY = 'ABCDEFG'
WRITE(6, *) 'INPUT LEN_TRIM = ', LEN_TRIM(INPUT)
WRITE(6, *) 'DIRECTORYLEN_TRIM = ', LEN_TRIM(DIRECTORY)
END SUBROUTINE
program test
character*20 foo
foo = "ABCDEFG"
call setpaths(foo)
end program
What compiler are you using ? here gfortran.
Tried with ifort as well
$ ifort -v
Version 8.0
$ ifort test.f90
$ ./a.out
INPUT LEN_TRIM = 7
DIRECTORYLEN_TRIM = 7
I don't know how the C# interface can introduce problems, but the semantics of LEN_TRIM are quite easy... if you say that the strings appear as equal in the debug, there's something very fishy going on.
it may be looking for Terminator character, char(0). it could be different from \n character
other possibility the string length was not passed correctly. fortran 77 string is passed as two values, string pointer and string length. there is no standard how string length is passed, most compilers stick it as a hidden parameter in the end. could be 90 does the same thing for compatibility.
By explicitly padding my C# StringBuilder with trailing spaces, the LEN_TRIM behaved as expected. This Microsoft KB seems to be related.
It is strange, however, that in the debugger the trailing spaces appeared even before I did the explicit padding.