FORTRAN 77 Simple input/out - fortran

I am new to FORTRAN, and must write a FORTRAN 77 program to read the following format from a file redirection or standard input:
[CHARACTER] [REAL] [REAL] [REAL] ... (can have any number of these)
D [INTEGER] (only one of these)
[REAL] [REAL] [REAL] ... (can have any number of these)
example input could be:
T 1.0 2.0 3.0
S 1.0 2.0 4.0
Y 3.0 4.0 5.0
D 2
3.0 5.0 6.0
4.5 4.6 5.6
My native language is C++, so I'm new to this whole idea of a read statement going to the next line automatically.
So far, I have the following code:
c234567
character*1 D
character*1 LETTER
real X, Y, Z
integer lines
real point1, point2, point3
85 format (3F10.6)
100 format (A1, 5X, F10.6, 5X, F10.6, 4X, F10.6)
990 format (A, I10)
MAX = 6
LETTER = 'Z'
D = 'D'
read *, LETTER, X, Y, Z
10 if(LETTER .ne. D) then
write (6, 100) LETTER, X, Y, Z
read *, LETTER, X, Y, Z
goto 10
else
goto 20
endif
C =====================================================
20 lines = aint(X)
write (*,990) 'LINES: ', lines
write (6, 85) X, Y, Z
read *, Z
write (6, 85) X, Y, Z
end
As you can see, I get the first portion of the input fine, but after that it kind of all goes to mush because of the read statement: read*, Z going to the next line. In my specific input file provided above, I get the 2 after the D, and the next two values (3.0, 5.0) but I skip the 6.0
Any help would be great. Thanks.

If you know that your lines will never exceed a maximum length, I suggest to read the whole line and then to parse the line according to your rules.
An example using a maximum line length of 1024 characters:
CHARACTER*1024 line
CHARACTER letter
100 FORMAT (A)
READ(*,100) line
READ(line, *) letter
IF (letter .eq. 'T') THEN
...
END IF
Maybe this technique works for you.

I haven't even looked at you code but I would suggest a strategy like this
(1) read the initial character of the line
if not "D" then
read reals
store the line
loop to (1)
else
read one integer
store the line
break
endif
read lines of reals until end-of-file
My fortran is very rusty, but I believe that there are constructs that will help you with this. Certainly the END modifier to READ is going to be helpful with the last bit.
After a little experimenting, I find that gfortran seems to support the old trailing $ for non-advancing input convention and advance='no'. However, g77 does not. I can't speak to any other compiler--as far as I know this was never standardized until fortran 90 where advance='no' was introduced.
Demo code that works in gfortran, but not in g77
program temp
c234567
character a
integer i
real x, y, z, w(50)
c This or with (*,'(A1 $)')
read (*,'(A1)',advance='no') a
if (a .eq. 'D') then
read (*,*) i
write (*,*) a, i
endif
end
This should be enough to make the incremental strategy work if you compiler supports non-advancing input somehow.
The alternative is to read the letter plus the rest of the line into a large character buffer, then parse the buffer separately along the lines of
character a, buf(1024)
read (*,'(a1, a1024)') a, buf
if (a .eq. d) then
read (buf,*) i
endif

Related

`Unexpected attribute declaration statement` in data statement

I tried to write some data in Fortran:
program Problem
DIMENSION X(8), W(8)
DATA X /0.0950125098D0, 0.2816035507D0, 0.4580167776D0, 0.6178762444D0
+ , 0.7554044083D0, 0.8656312023D0, 0.9445750230D0, 0.9894009349D0/
DATA W /0.1894506104D0, 0.1826034150D0, 0.1691565193D0, 0.1495959888D0
+ , 0.1246289712D0, 0.0951585116D0, 0.0622535239D0, 0.0271524594D0/
D = 0.D0
DO NJ=1,8
D = D + X(NJ) + W(NJ)
ENDDO
write(*,*) D
end
But I always get the following error message: Unexpected attribute declaration statement at (1).
Does anybody know why?
As already stated by others you should use the new fortran standard. If you do that you can just remove the "+" you used to indicate a continuation line (should have been in column 6) and instead add an ampersand "&" at the end of the line that should be continued.
Then the program compiles and runs. But as X and W are single precision you use too many digits in your data statement. Use implicit none and declare all variables. And get a textbook.
Below you find a minor update to your code which allows it to compile:
program Problemless
dimension X(8), W(8)
data X /0.0950125098D0, 0.2816035507D0, 0.4580167776D0,
+ 0.6178762444D0, 0.7554044083D0, 0.8656312023D0,
+ 0.9445750230D0, 0.9894009349D0/
data W /0.1894506104D0, 0.1826034150D0, 0.1691565193D0,
+ 0.1495959888D0, 0.1246289712D0, 0.0951585116D0,
+ 0.0622535239D0, 0.0271524594D0/
D = 0.D0
do NJ=1,8
D = D + X(NJ) + W(NJ)
enddo
write(*,*) D
end
Your code is written in Fixed-source form (See Section 6.3.3 of the Fortran standard). This implies that you cannot have anything beyond column 72. All I've done is to correct this in the above.
If you are learning fortran, I would suggest to stop using the fixed format and start using the free format.
no upvotes required for this post

Reading an image into an array?

I'm attempting to write a program that utilizes the sobel filter to detect edges in images. So first off, I've written down some of the requirements in some basic code, such as the x and y direction filters as arrays and also an attempt to read in a pgm image:
program edges
implicit none
integer, dimension(:,:), allocatable :: inp, outim, GX, GY
integer, parameter :: dp = selected_real_kind(15,300)
integer :: ky, kx, x, y, out_unit = 10, M, N, sx, sy, i, j
real(kind=dp) :: G
M = 5
N = 5
allocate(inp(M,N))
allocate(outim(M-2,N-2))
allocate(GX(3,3))
allocate(GY(3,3))
open(file = 'clown.pgm',unit=out_unit,status= 'unknown') !opening file to write to inp
read (out_unit,11) 'P2' !pgm magic number
read (out_unit,12) 50,50 !width, height
read (out_unit,13) 1 !max gray value
do M=-25,25
do N=-25,25
read (out_unit,*) inp(M,N)
end do
end do
11 format(a2)
12 format(i3,1x,i3)
13 format(i5)
This is my first time working with image manipulation in FORTRAN, apart from once when I printed an image out as a pbm file. The code for reading the image in is a replicate of what I used to print one out before, except I changed write to read.
So my question is, how can I read in an image that's in pgm format into the "inp" array, so that I can apply the sobel filter? When I run my attempt, I get the following errors:
read (out_unit,11) 'P2' !pgm magic number
1
Error: Expected variable in READ statement at (1)
sobel.f90:41:18:
read (out_unit,12) 50,50 !width, height
1
Error: Expected variable in READ statement at (1)
sobel.f90:42:18:
read (out_unit,13) 1 !max gray value
1
Error: Expected variable in READ statement at (1)
Thank you
The first mistake is, as the compiler states quite clearly, in this line:
read (out_unit,11) 'P2'
The compiler expects, because that's the way that Fortran is defined, to be told to read a value from out_unit into a variable, but 'P2' is a character literal (or whatever the heck the standard calls them), it's a string, it's not a variable.
The same mistake occurs in the next lines too. The compiler expects something like
integer :: p2 ! pgm magic number
...
read (out_unit,11) p2
etc. After execution of this version of the read statement the variable p2 holds the magic number read from the pgm file.
While I'm writing, calling the unit to be read from out_unit is just perverse and will, eventually, confuse you.

Fortran code won't write to file

I am working on a program to calculate minimum nozzle length in supersonic nozzles (Method of Characteristics). I can't seem to figure out why my code won't write to my output file (the lines "write (6,1000)....). My code is below:
program tester
c----------------------------------------------------------------------c
implicit real (a-h,o-z)
integer count
real kminus(0:100),kplus(0:100),theta(0:100),nu(0:100),mach(0:100)
+ ,mu(0:100)
open (5,file='tester.in')
open (6,file='tester.out')
read (5,*) me
read (5,*) maxturn
read (5,*) nchar
read (5,*) theta0
close(5)
c.....set count to 0 and calculate dtheta
count=0
dtheta=(maxturn-theta0)/nchar
c.....first characteristic
do 10 an=1,nchar+1
count=count+1
c........these are already known
theta(count)=theta0+dtheta*(an-1)
nu(count)=theta(count)
c........trivial, but we will "calculate" them anyways
kminus(count)=2*theta(count)
kplus(count)=0
c........we feed it nu(count) and get m out
call pm_hall_approx(nu(count),m)
mach(count)=m
c........does not work with sqrt(...) for some reason
mu(count)=atan((1/(mach(count)**2)-1)**0.5)
write (6,1000) count,kminus(count),kplus(count),theta(count)
+ ,nu(count),mach(count),mu(count)
10 continue
c.....the other characteristics
do 30 bn=1,nchar
do 20 cn=1,(nchar+1-bn)
count=count+1
c...........these are given
kminus(count)=kminus(cn+bn)
kplus(count)=-1*kplus(bn+1)
c...........if this is the last point, copy the previous values
if (cn.eq.(nchar+1-bn)) then
kminus(count)=kminus(count-1)
kplus(count)=kplus(count-1)
endif
c...........calculate theta and nu
theta(count)=0.5*(kminus(count)+kplus(count))
nu(count)=0.5*(kminus(count)-kplus(count))
c...........calculate m
call pm_hall_approx(nu(count),m)
mach(count)=m
mu(count)=atan((1/(mach(count)**2)-1)**0.5)
write (6,1000) count,kminus(count),kplus(count),theta(count)
+ ,nu(count),mach(count),mu(count)
20 continue
30 continue
close(6)
stop
1000 format (11(1pe12.4))
end
c======================================================================c
include 'pm_hall_approx.f'
And my subroutine is given here:
subroutine pm_hall_approx(nu,mach)
c----------------------------------------------------------------------c
c Given a Mach number, use the Hall Approximation to calculate the
c Prandtl-Meyer Function.
c----------------------------------------------------------------------c
implicit real (a-h,o-z)
c.....set constants
parameter (a=1.3604,b=0.0962,c=-0.5127,d=-0.6722,e=-0.3278)
parameter (numax=2.2769)
y=nu/numax
mach=(1+a*y+b*y*y+c*y*y*y)/(1+d*y+e*y*y)
return
end
And here are the contents of tester.in
2.4 = mache
5.0 = maxturn
7 = nchar
0.375 = theta0
In fortran, unit number 6 is reserved for screen. Never use that as the unit number. Try changing it to some other number like write(7,1000) and then it should work.

Fortran read from fie into arrays

I need to read from a txt file into three arrays in order to calculate distances between coordinates. I have looked through other answers and pieced together the script bellow. The columns of the input file need to be come my x, y and z arrays respectively. There are 64 rows and 16 decimal places for each entry. Pointers would be greatly appreciated.
the data format:
0.8607595188703266 0.9252035918116585 0.4094258340665792
0.5246038490998378 0.9804633529144733 0.5325820695466118
0.6955271184611949 0.3304908806613460 0.7154502550542654
and my script so far:
PROGRAM readtest
use, intrinsic :: iso_fortran_env
implicit none
integer, parameter :: ArrayLen = 64
real(real64), DIMENSION(ArrayLen) :: x
real(real64), DIMENSION(ArrayLen) :: y
real(real64), DIMENSION(ArrayLen) :: z
integer :: i, ReadCode, num
OPEN(1, FILE='contcar.txt', STATUS='old', ACTION='read')
OPEN(2, FILE='xyz.txt', STATUS='replace', ACTION='write')
num = 0
ReadLoop: do i=1, ArrayLen
read (1, '(A,F18.16)', iostat=ReadCode ) x(i), y(i), z(i)
if ( ReadCode /= 0 ) then
if ( ReadCode == iostat_end ) then
exit ReadLoop
else
write ( *, '( / "Error on read: ", I0 )' ) ReadCode
stop
end if
end if
num = num + 1
end do ReadLoop
WRITE(3, 100) x, y, z
100 format (A,F18.16)
END PROGRAM readtest
The xyz.txt is appearing blank and I am not getting any errors at this stage, what is wrong here that is stopping the array filling and writing to the file?
Sorry, if this is too much of mess to approach, any help would be appreciated.
Thanks
You have two problems with you approach:
Your format specifications are wrong
Your write won't do what you want
First off, the format A,F18.16 reads two items, a character and a floating point number. What you want is to read 3 floating point numbers. With the file provided, there are two spaces before each number so you could use
read (1, '(3(2X,F18.16))', iostat=ReadCode ) x(i), y(i), z(i)
but this is not very flexible if your input format changes and it is easier to just do list-directed input:
read (1, *, iostat=ReadCode ) x(i), y(i), z(i)
which will do what you want and is not sensitive to the exact positioning of the numbers within the file and how many intervening spaces exist.
This will load your data into the arrays. Now for output you want the same thing. You want to duplicate the output so we can use the first format about to stipulate that output (3(2X,F18.16)). This will output 3 numbers per line with 2 spaces before each number. The next problem is that you are attempting
WRITE(3, 100) x, y, z
which will transpose your array. It will write all of the x, then all of the y and lastly all of the z. If you want the same output, put it in a loop. Putting the above together, use:
do i=1, ArrayLen
WRITE(2, 100) x(i), y(i), z(i)
end do
100 format (3(2X,F18.16))
As a note, don't use single digit unit numbers, particularly the first few which conflict with system defined standard input/output/error units on most compilers.

Reading formatted data - Fortran runtime error: Bad real number

I am trying to use the code below to read a formatted file and write it into another. However, on running it shows the following error
$ ./conv.sac.farm < i_conv.farm
# stn comp Delta Tr-time Start in record
At line 54 of file Main/conv.sac.farm.f (unit = 5, file = 'stdin')
Fortran runtime error: Bad real number in item 1 of list input
The source code is as follows
PARAMETER (nd0=100000,pi=3.1415926)
IMPLICIT COMPLEX*8 (Z)
CHARACTER name*6,comp*6,fname*60,event*20
- ,cmp(0:3)*5,fname0*60,charac*15,scode*60
REAL*8 GFACT(500),PP0(500),depth0
integer hr0,mnu0,yr,month,day,hr,mnu
REAL x(nd0),y(nd0)
DIMENSION Z(nd0),zpole(50),zero(50)
data np,cmp/8,'disp.','vel. ','acc. ','orig.'/
common /tbl/ip(110,14),is(110,14),secp(110,14),secs(110,14)
read(5,'(a)') event
read(5,*) alats,alons,depth,hr0,mnu0,sec0,id,delmin,delmax
depth0=depth
write(22,'(a,a5,3f7.2,2i3,f6.2)')
# event,cmp(id),alats,alons,depth,hr0,mnu0,sec0
* << J-B travel time table >>
OPEN(11,FILE='jb.ptime')
OPEN(12,FILE='jb.stime')
1000 read(11,*,end=1001) n,(ip(n,i),secp(n,i),i=1,14)
goto 1000
1001 read(12,*,end=1002) n,(is(n,i),secs(n,i),i=1,14)
goto 1001
1002 continue
close(11)
close(12)
* << Geometrical factor >>
OPEN(15,FILE='jb.table')
CALL GEOM(GFACT,PP0,depth0)
close(15)
nstn=0
print *,' # stn comp Delta Tr-time Start in record'
5 read(5,'(a)') fname
read(5,'(a)') scode
* ta=advance of start-time relative the standard P/S arrival
* du=duration
c
if(fname.eq.'dummy') goto 90
read(5,*) ta,du,dt,f1,f2,iph,nr,iuni
open(1,file=fname)
READ(1,'(g15.7)') dt0
read(1,'(/////5g15.7)') dum, alat, alon, elev
read(1,'(///////5i10)') yr, nday, hr,mnu, nsec
read(1,'(5i10)') nmsec,ndum,ndum,ndum,nd
read(1,'(/////)')
read(1,'(a6,2x,a13)') name,charac
read(1,'(////)')
And so on..
Line 54 is
read(5,*) ta,du,dt,f1,f2,iph,nr,iuni
I found a similar question following this link
Fortran runtime error: Bad real number
However, if I understand correctly, the corrections mentioned were pertaining to reading unformatted data. Despite this, I tried and failed as expected, given that the file I am trying to read is formatted.
here is a little trick if you can't readily find the offending line in the data file:
replace your read that throws the error with this:
read(5,'(a)')line
read(line,*,iostat=ios) ta,du,dt,f1,f2,iph,nr,iuni
if(ios>0)then
write(*,*)'error reading line:',line
stop
endif
with the declarations
integer ios
character*(200) line
Probably just do that for debugging then revert to the original once you fix the problem.