Fortran write to same file from inside if statement - fortran

I am currently working on some fortran code and getting an error of.
`Duplicate statement label 201 at (1) and (2)`
My code is long but simplified looks like so:
integer :: y,x,method
x = 0
print*, "Please enter a value (1 or 2)."
read(*,*) method
if (method .EQ. 1) then
x = 10
do i=1,1000
y = x * i
Call OtherFile(y,x,i)
write(6,201) long,list,of,variables
201 format('OUTPUT: ',i5,1p,7d10.2)
enddo
stop
else if (method .EQ. 2) then
x = 10
do i=1,1000
y = x * i * i
Call OtherFile(y,x,i)
write(6,201) long,list,of,variables,
201 format('OUTPUT: ',i5,1p,7d10.2)
enddo
stop
end if
Edit: After posting earlier I realised this code would work. I cannot post the original work so I have best tried to recreate the problem.
Edit2: I have made the mistake in labelling this as Fortran77, it is infact an older version as it is written in punchcard format.
The lines in question are the ones beginning with 201.
I can resolve the issue simply by chosing 201 and 202 before each FORMAT section respectively, however there are other files reliant upon the argument 201 as statement number.
Can anyone tell if there is a solution to this?

I think this warrants a full explanation which does not fit in a comment. The FORMAT is not an executable statement. It just instructs the compiler in which format print or read DATA. There can always only be one FORMAT statement with the same label in a given scope. It does not matter on which line that exactly is.
In particular, when executing the write, print or read statement, the program does not in any way jump to the FORMAT statement. The compiler just uses the format description defined there.
Therefore:
write(6,201) something
201 format('OUTPUT: ',i5,1p,7d10.2)
or
201 format('OUTPUT: ',i5,1p,7d10.2)
write(*,201) something
or
201 format('OUTPUT: ',i5,1p,7d10.2)
!many lines here
write(*,201) something
or
write(*,201) something
!many lines here
201 format('OUTPUT: ',i5,1p,7d10.2)
or
write(*,"('OUTPUT: ',i5,1p,7d10.2)") something
or
write(*,"(i5,1p,7d10.2)") 'OUTPUT: ', something
will all do the same thing and all will work just fine.
The last way with a character constant (or variable) inside the write statement instead of the FORMAT statement label is the modern way to go.

format statements are not executable statements. Except as noted below their location in the code isn't important. So, while it may be tempting to put a format together with the output statement
write(6,201) long,list,of,variables
201 format('OUTPUT: ',i5,1p,7d10.2)
that isn't necessary. When one wants to duplicate that output a little later, simply copying the two lines doesn't help: the error message shown can pop up.
As detail: write(unit=6,fmt=201) (keywords added for clarity) is asking to write to unit 6 using the format of the format statement labelled 201 which occurs in the same inclusive scope of that write. A line later 201 format (...) is providing such a thing.
The error is that no two statements in the same scope may have the same label. Deleting one of them, or changing the label (and its reference) would be suitable.
Vladimir F's answer goes into more detail about other approaches to address the format re-use.

Related

Proper Fortran compiler to execute a program

I have little knowledge of the Fortran language. I have come across some programs written in the 90s (see attached snapshot showing just a portion of a long script).
I'd like to know what kind of compiler is appropriate to execute such codes? I have installed gfortran-4.2.3 on my mac. I'm also not sure about the indentation in the attached code: if C (comment) is at column 1, does the main code start at column 9 or 7? what about the position of numbers placed in between referred by GO TO?
This is not Fortran 90. This is Fortran 77.
That said, gfortran is able to compile this code. Make sure that the file extension for the file is .f so that gfortran realises it's fixed-form.
The C needs to be in the first column, the numbers that you reference are labels, they can be between column 1 and 5. The asterisk at line 198 is a continuation character, meaning that this should be treated as part of the previous line. It must be in column 6. Everything else needs to be between columns 7 and 72 (inclusive)
Oh, and the 3-digit numbers at the very beginning are line numbers, and must not be in the source code.
Edited to add: Since you have to type it all again anyway, you might as well make it free-form:
Replace the C in the first column with !, and change the way continuation lines are marked: Turn this:
write (*, *) "This is some long text,
* which doesn't fit into a line"
Into this:
write(*, *) "This is some long text, " // &
"which doesn't fit into a line"
Everything else can stay like it is. (You can now use proper indentation, too!)
New Edit
So you've pasted the code that you wrote and the error messages, so I'm replying to that now.
In Fixed Form, any character past column 72 is ignored. You have a few lines with long strings, where the terminating quotation mark is in that ignored region.
Make sure that no line exceeds the 72nd row.

Standard Input and Command line file in Fortran77

I've been given the challenge to port a Fortran 77 program into C#.
I've found out that read(5,*) read from the standard input, i.e. the keyboard.
Now I'm trying to understand how the following works:
1. When I run the program, I have to run it as cheeseCalc<blue.dat>output.txt
, which read a blue.dat file and produces a output.txt file. How does read work in this case?
In the same program, there is READ(5,* )IDUM and later it also has read(5,*)idum,idum,tinit. What is happening in this case?
The blue.dat file has the following lines:
HEAD make new cake
INPUT VARIABLES
MFED MASS-FEED 30 ;1001 1 100 PEOPLE TO FEED
TOVE TEMP-IN-OVEN 150.0 ;1001 20 100 TEMPERATURE OF OVEN, C
UPDATED: Just for context, the initial lines of code in the program are:
program cheeseCalc
CHARACTER*76 IDENT
CHARACTER*1 IDUM
READ(5,104)IDENT
104 FORMAT(4X,A)
READ(5,*)IDUM
c write start record
write(6,102)IDENT
102 format('**START',/,4X,A,/)
read(5,*)idum,idum,frate
110 format(f10.0)
frate2=frate/3.6
read(5,*)idum,idum,tempo
* Do calculation *
write(6,*)frate2,tempo
end
Any help will be appreciated!! Thanks!
The full detail of the general read statement is documented elsewhere, but there is an idiom here which is perhaps worth elaborating on.
The statement read(5,*) ... is list-directed input from the external unit number 5. Let's assume (it's not guaranteed, but it's likely and you seem happy with that for your setup) that this external unit is standard input.
The idiomatic part is the repeated use of a single variable in an input list such as
read(5,*) idum, idum, ...
This (and the fact that idum is an (awfully named) length-1 character variable) signifies that the user doesn't care about the input in the first two fields). The first string, delimited by blanks, is read then the first character is assigned to idum. Then idum is immediately set to the first character of the next string.
The purpose of this is to set the place in the record to the third field, which is read into the (real) variable frate (in the first case).
Equally
read(5,*) idum
is just skipping the second line (strictly, reading the first character, but that's not used anywhere before the next read into idum): the first blank-delimited field is read but the next read moves on to the next line rather than continuing with that one.

Unclassifiable statement at 1 , Non-numeric character in statement label at 1

i'm totally new to Fortran, and i want to write a test program using a real*8 function called NeQuick, so i've written the following program :
program test
implicit real*8 (a-h,o-z)
aNe=NeQuick(400.0D0,45.0D0,15.0D0,10,1.929D2,15.0D0)
write(6,'(A,E12.5,A)')
& ' NeQuick electron density =',aNE,' m^-3'
call sleep(10)
end program
At the end when i compile it I have the following errors in each line of the little program : -Non-numeric character in statement label at 1 or
-Unclassifiable statement at 1
Can you guys please explain me what's wrong with my program ?
The way this code is written tells me that it was intended to be fixed-form source. This requires that all of the code start in column 7, except for the & in the second line of the WRITE statement which should be in column 6. Often when such code is pasted into an editor, the leading blanks are removed. If you do this, though, you will have to rename the source file to have a .f or .for file type so that the compiler knows it is fixed-form.
Another, perhaps easier solution is to put an & at the end of the first line of the WRITE - this will then make the source as you have it valid free-form.
For some perspective on this, please read Source Form Just Wants to be Free.

Save data in another external file name output.txt?

The program can run, I am not sure how to use open() and save the data in another external file name output.txt. My questions are stated below - please have a look and help.
program start
implicit none
integer ::n
real(kind=8)::x,h,k
real(kind=8),external:: taylorq
x=1.0
n=20
h=exp(x)
k=taylorq(x,n)
open(10,'output.txt') ----------- *question1:(when should i put this open file?)*
write(*,*)"The exact value=",h
write(*,*)"The approximate value=",k
write(*,*)"The error=",h-k
end program start
function taylorq(x,n)
implicit none
integer::n,i
real(kind=8):: x,taylor,taylor2,taylorq,h
h=exp(x)
taylor=1.
taylor2=taylor
write(*,*)"i exact appro error"-----------question2:(actually I want to draw a table with subtitle i, exact, appro, error in each column, is there a nice way to arrange them like eg.we can use %5s)
do i=1,n
taylor=taylor*x/i
taylor2=taylor2+taylor
write(10,*)i,h,taylor2,taylor2-h --------question3:*(I want to save the data written here into file output.txt)*
end do
close(10)
taylorq=taylor2
end function taylorq
1. where to open
You should put open(10,...) so it executes before any write(10,...) -- or read(10,...) if this was input.
Since your writes occur in the function taylorq, you should open() before the statement that calls taylorq.
For programs that do very large computations, which Fortran is suited/famous for, it is often best to do
all file open's very near the beginning of the program, so that if there is a problem opening any file,
it is caught and fixed without wasting hours or days of work. But your program is much simpler than that.
2. formatting
Yes, Fortran can do formatted output -- and also formatted input. Instead of a text string with
interpolated specifiers (like C and the C part of C++, and Java, and awk and perl and shell) it uses specifiers
with optionally interpolated text values, and the specifiers are written with the format letter on
the left followed by the width (almost always) and other parameters (sometimes).
You can either put the format directly in the WRITE (or READ) statement, or in a separate FORMAT
statement referred to by its label in the I/O statement.
write (10, '(I4,F10.2,F10.2,F10.2)' ) i,h,taylor2,taylor2-h
or
write (10, 900) i,h,taylor2,taylor2-h
! this next line can be anywhere in the same program-unit
900 format (I4,F10.2,F10.2,F10.2)
Unlike C-family languages, Fortran will always output the specified width; if the value doesn't fit,
it prints asterisks ***** instead of forcing the field wider (and thus misaligned) (or truncating as
COBOL does!). Your series grows fast enough you might want to use scientific notation like E10.3.
(The format letters can be in either case, but I find them easier to read in upper. YMMV.)
There are many, MANY, more options. Any textbook or your compiler manual should cover this.

Writing on the same line in FORTRAN

In Fortran, each time one uses WRITE a new line is produced. In order to control the working of a program that is being executed, I would like to write on screen the current value of a variable, but always on the same line (erasing the previous value and starting at the beginning of the line). That is, something like
1 CONTINUE
"update the value of a"
WRITE(*,*) a
BACKSPACE "screen"
GOTO 1
Something like WRITE(*,*,ADVANCE='NO') (incorrect anyway) is not quite what I
need: this would write all the values of a one after another on a very long
line.
A trick that I was shown for what you want is as follows
do l=1,lmax
...update a...
write(*,'(1a1,<type>,$)') char(13), a
enddo
where <type> is your format specifier for a (i.e., i0 for integer).
The key is the char(13), which is the carriage return, and the $ in the format descriptor. I really don't know if there is a name for $, I just know that it works for displaying on the screen--for output to file you get an a on each line.