How can I count the number of columns in a file? - fortran

I am trying to code a program that allows me to count the number of columns in a file (in the example below datos.txt). However, gfortran tells me there is an error:
"Expected variable in read statement".
How can I solve this? In the example, I used 100 as the maximum number of columns possible. The real value is 5.
What I have tried is this:
program contarcolumnas
implicit double precision (a-h,o-z)
implicit integer*8 (i-n)
open (50, file="datos.txt")
m=1
dimension matrizfichero(1,100)
do i=1,1
read(50,*)(matrizfichero(i,j),j=1,m)
if (iostat /= 0) then
m=m+1
else
print*,m
end if
end do
close(50)
end program contarcolumnas

Related

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 error when calculating cosx

I was assigned the following problem:
Make a Fortran program which will be able to read a degree[0-360] checking validity range(not type) and it will be able to calculate and print the cos(x) from the following equation, where x is in radians:
cos(x)=1-x^2/2! + x^4/4!-x^6/6!+x^8/8!-...
As a convergence criteria assume 10^(-5) using the absolute error between two successive repeats (I suppose it means do's).
For the calculation of the ! the greatest possible kind of integer should be used. Finally the total number of repeats should be printed on screen.
So my code is this:
program ex6_pr2
implicit none
!Variables and Constants
integer::i
real*8::fact,fact2 !fact=factorial
real,parameter::pi=3.14159265
double precision::degree,radiants,cosradiants,s,oldcosradiants,difference !degree,radiants=angle
print*,'This program reads and calculates an angle`s co-sinus'
print*,'Please input the degrees of the angle'
read*,degree
do while(degree<0 .or. degree>360) !number range
read*,degree
print*,'Error input degree'
cycle
end do
radiants=(degree*pi/180)
fact=1
fact2=1
s=0
cosradiants=0
!repeat structure
do i=2,200,1
fact=fact*i
fact2=fact2*(i+2)
oldcosradiants=cosradiants
cosradiants=(-(radiants)**i/fact)+(((radiants)**(i+2))/fact2)
difference=cosradiants-oldcosradiants
s=s+cosradiants
if(abs(difference)<1e-5) exit
end do
!Printing results
print*,s+1.
end program
I get right results for angles such as 45 degrees (or pi/4) and wrong for other for example 90 degrees or 180.
I have checked my factorials where I believe the error is hidden (at least for me).
Well I created another code which seems unable to run due to the following error:FUNCTION name,(RESULT of PROJECT2_EX6~FACT),used where not expected,perhaps missing '()'
program project2_ex6
implicit none
integer(kind=3)::degrees,i,sign
integer::n
double precision::x,err_limit,s_old,s
real,parameter::pi=3.14159265359
print*,'This program calculates the cos(x)'
print*,"Enter the angle's degrees"
read*,degrees
do
if(degrees<0.or.degrees>360) then
print*,'Degrees must be between 0-360'
else
x=pi*degrees/180
exit
end if
end do
sign=1
sign=sign*(-1)
err_limit=1e-5
n=0
s=0
s_old=0
do
do i=1,n
end do
s=(((-1.)**n/(fact(2.*n)))*x**(2.*n))*sign
s=s+s_old
n=n+1
if(abs(s-s_old)<1e-5) then
exit
else
s_old=s
cycle
end if
end do
print*,s,i,n
contains
real function fact(i)
double precision::fact
integer::i
if(i>=1) then
fact=i*fact(i-1)
else
fact=1
end if
return
end function
end program
Although it is your homework, I will help you here. The first thing which is wrong is ýour factorial which you need to replace with
fact = 1
do j = 1,i
fact = fact*j
enddo
second it is easier if you let your do loop do the job so run it as
do i=4,200,2
and predefine cosradians outside the do loob with
cosradiants = 1-radiants**2/2
additionally you need to take into account the changing sign which you can do in the loop using
sign = sign*(-1)
and starting it off with sign = 1 before the loop
in the loop its then
cosradiants= cosradiants+sign*radiants**i/fact
If you have included these things it should work (at least with my code it does)

End of record error in file opening

I am currently writing a code to simulate particle collisions. I am trying to open as much files as there are particles (N) and then put the data for positions and velocities in each of these files for each step of the time integration (using Euler's method, but that is not relevant). For that, I tried using a do loop so it will open all the files I need - then I put all the data in them with a different do loop later - and then close them all.
I first tried just doing a do loop to open the files - but it gave errors of the type "file already open in another unit", so I did the following:
module parameters
implicit none
character :: posvel
integer :: i, j, N
real :: tmax
real, parameter :: tmin=0.0, pi=3.14159265, k=500.0*10E3, dt=10.0E-5, dx=10.0E-3, g=9.806, ro=1.5*10E3
real, dimension(:), allocatable :: xold, xnew, vold, vnew, m, F, r
end module parameters
PROGRAM Collision
use parameters
implicit none
write(*,*) 'Enter total number of particles (integer number):'
read(*,*) N
allocate(xold(N))
allocate(vold(N))
allocate(xnew(N))
allocate(vnew(N))
allocate(m(N))
allocate(F(N))
allocate(r(N))
xold(1) = 0.0
vold(1) = 0.0
m(1) = 6.283*10E-9
r(1) = 10E-4
xold(2) = 5.0
vold(2) = 0.0
m(2) = 6.283*10E-9
r(2) = 10E-4
write(*,*) 'Type total time elapsed for the simulation(real number):'
read(*,*) tmax
do i = 1, N
write(posvel,"(a,i3.3,a)") "posveldata",i,".txt"
open(unit=i,file=posvel, status="unknown")
end do
do i = 1, N
close(unit=i)
end do
END PROGRAM Collision
The last ten lines are the ones that regard to my problem.
That worked in codeblocks - it opened just the number of files I needed, but I'm actually using gfortran and it gives me and "end of record" error in the write statement.
How can I make it to execute properly and give me the N different files that I need?
P.S.: It is not a problem of compilation, but after I execute the program.
Your character string in the parameter module has only 1 character length, so it cannot contain the full file name. So please use a longer string, for example
character(100) :: posvel
Then you can open each file as
do i = 1, N
write(posvel,"(a,i0,a)") "posveldata",i,".txt"
open(unit=i,file=trim(posvel), status="unknown")
end do
Here, I have used the format i0 to automatically determine a proper width for integer, and trim() for removing unnecessary blanks in the file name (though they may not be necessary). The write statement can also be written more compactly as
write(posvel,"('posveldata',i0,'.txt')") i
by embedding character literals into the format specification.
The error message "End of record" comes from the above issue. This can be confirmed by the following code
character c
write(c,"(a)") "1"
print *, "c = ", c
write(c,"(a)") "23" !! line 8 in test.f90
print *, "c = ", c
for which gfortran gives
c = 1
At line 8 of file test.f90
Fortran runtime error: End of record
This means that while c is used as an internal file, this "file" does not have enough space to accommodate two characters (here "23"). For comparison, ifort14 gives
c = 1
forrtl: severe (66): output statement overflows record, unit -5, file Internal Formatted Write
while Oracle Fortran12 gives
c = 1
****** FORTRAN RUN-TIME SYSTEM ******
Error 1010: record too long
Location: the WRITE statement at line 8 of "test.f90"
Aborted
(It is interesting that Oracle Fortran reports the record to be "too long", which may refer to the input string.)

Simple read function error

I imagine this is something silly I've missed but I've asked my whole class and noone can seem to work it out. Making a simple program calling in a subroutine and I'm having trouble with the do loop reading in the entries of the matrix.
program Householder_Program
use QR_Factorisation
use numeric_kinds
complex(dp), dimension(:,:), allocatable :: A, Q, R, V
integer :: i, j, n, m
print *, 'Enter how many rows in the matrix A'
read *, m
print *, 'Enter how many columns in the matrix A'
read *, n
allocate(A(m,n), Q(m,n), R(n,n), V(n,n))
do i = 1,m
do j = 1,n
Print *, 'Enter row', i, 'and column', j, 'of matrix A'
read *, A(i,j)
end do
end do
call Householder_Triangularization(A,V,R,n,m)
print *, R
end program
It will ask me for A(1,1) but when I type in a number it will not ask me for A(1,2), it will leave a blank line. When I try to put in a 2nd number it will error and say :
Enter row 1 and column 1 of matrix A
1
2
At line 22 of file HouseholderProgram.f90 (unit = 5, file = 'stdin')
Fortran runtime error: Bad repeat count in item 1 of list input
Your variable A is (an array) of type complex. This means that when you attempt to do the list-directed input of the element values you cannot just specify a single number. So, in your case the problem is not with the program but with the input.
From the Fortran 2008 standard, 10.10.3
When the next effective item is of type complex, the input form consists of a left parenthesis followed by an ordered pair of numeric input fields separated by a comma (if the decimal edit mode is POINT) or semicolon (if the decimal edit mode is COMMA), and followed by a right parenthesis.
Input, then, must be something like (1., 12.).
You are trying to read in complex numbers (A is complex)! As such, you should specify complex numbers to the code... Since you are providing just one integer, the program does not know what to do.
Providing (1,0) and (2,0) instead of 1 and 2 will do the trick.
In case the user input is always real, and you want to read it into a complex type array you can do something like this:
Print *, 'Enter row', i, 'and column', j, 'of matrix A'
read *, dummy
A(i,j)=dummy
where dummy is declared real. This will save the user from the need to key in the parenthesis required for complex numbers. ( The conversion to complex is automatic )