I have a Fortran problem. I want to read in data with different length.
they begin with:
<TITLE>University of Wyoming - Radiosonde Data</TITLE>
<LINK REL="StyleSheet" HREF="/resources/select.css" TYPE="text/css">
<BODY BGCOLOR="white">
<H2>08190 Barcelona Observations at 12Z 11 Feb 2015</H2>
<PRE>
-----------------------------------------------------------------------------
PRES HGHT TEMP DWPT RELH MIXR DRCT SKNT THTA THTE THTV
hPa m C C % g/kg deg knot K K K
-----------------------------------------------------------------------------
1012.0 98 14.0 -1.0 36 3.53 0 0 286.2 296.5 286.8
from this point the file is for example 77 lines long. but others have only 55 , and the end is reached when this part comes
</PRE><H3>Station information and sounding indices</H3><PRE>
Station number: 8190
So I think I need a condition which runs out of the do loop?
I get my data with :
wget 'http://weather.uwyo.edu/cgi-bin/sounding?region=europe& TYPE=TEXT%3ALIST&YEAR=2015&MONTH=02&FROM=1112&TO=1112&STNM=08190' -0 data.dat
open(33, file=infilename, form='formatted',&
access='sequential',action='read')
open(34, file=outfilename, form='formatted',&
access='sequential',action='write')
read(33,'(11/)')
do i=1,77
read(33, '(f7.1,2x,i5,2x,a5,2x,a5,4x,a3,3x,f4.2,4x,a3,4x,a3)') pres,height,tmp,tmp_dew,rel_hum,mixing,wind_dir,wind_speed
write(34,'(f7.1,2x,i5,2x,a5,2x,a5,4x,a3,3x,f4.2,4x,a3,4x,a3)') pres,height,tmp,tmp_dew,rel_hum,mixing,wind_dir,wind_speed
end do
close(33)
close(34)
I hope you can help me.
one approach is to read each line as a string, check for the end and process accordingly:
character*1000 wholeline
do while( .true. )
read(33,'(a)')wholeline
if ( index(wholeline,'</PRE>' ).ne.0 )exit
read(wholeline,*)pres,height,tmp,tmp,dew ...
enddo
You can also perhaps more simply just read and exit on an error..
do while( .true. )
read(33,*,err=100)pres,height,tmp,tmp,dew ...
enddo
100 continue
I'm not a fan of deliberately throwing errors if it can be avoided though.
As an aside you do not need that messy format, list directed will work fine for this example. In fact if all you are doing is transferring the data to another file, simply rewrite the string as: write(34,'(a)')trim(wholeline)
Related
I'm trying to read a file in the format specified below using FORTRAN 66.
1000
MS 1 - Join Grps Group Project 5 5
Four Programs Programming 15 9
Quiz 1 Quizzes 10 7
FORTRAN Programming 25 18
Quiz 2 Quizzes 10 9
HW 1 - Looplang Homework 20 15
I execute and read the file like so:
program < grades.txt
The first line is the total number of points that can be earned in a class
The rest of the lines are assignments in a class
Each line is formatted as such: Assignment name(20 chars) category (20 chars) possible points(14 chars) earned points(14 chars)
For some reason, when the code runs and reads the file, starting at the first assignment record, I get error 5006, and cannot find an explanation of the error code. The output of the program while debugging looks like this:
$ file < grades.txt
MS 1 - Join Grps Group Project 5 6417876
NOT EOF
EOF 5006
NAME CATEGORY POSSIBLE EARNED
My goal is to be able to read each line and put each column into it's appropriate array, then reference those arrays later on to print a report for each category, with each assignment, points possible, earned, and total percentage for the category, then loop, etc.
I do not understand where the "6417876" in the output is coming from, it is definitely not part of the file that's being piped into stdin while the program reads.
The code for the program is as follows:
CHARACTER*20 ASSIGNMENTT(100)
CHARACTER*20 CATEGORY(100)
INTEGER POSSIBLE(100)
INTEGER EARNED(100)
INTEGER TOTALPTS
INTEGER REASON
INTEGER I, N
READ(5,50)TOTALPTS
50 FORMAT(I4)
c Read the arrays in
I=1
100 READ(5,110,IOSTAT=REASON)ASSIGNMENTT(I),CATEGORY(I),POSSIBLE(I),EARNED(I)
110 FORMAT(2A20x,2I14x)
WRITE(*,110)ASSIGNMENTT(I),CATEGORY(I),POSSIBLE(I),EARNED(I)
I=I+1
IF (REASON < 0) GOTO 120
WRITE(*,*)"NOT EOF"
IF (I<100 .AND. REASON == 0) GOTO 100
WRITE(*,*)"EOF", REASON
c Get the number of items (For some reason stdin adds an extra item that's not in the file, so I subtract 2 instead of 1
120 N=I-2
c Display the Names and Ages
WRITE(*,200)
200 FORMAT("NAME",T20,"CATEGORY",T40,"POSSIBLE",T54,"EARNED",T68)
DO 300 I=1,N
210 FORMAT(A20,A20,I14,I14)
300 WRITE(*,210)ASSIGNMENTT(I),CATEGORY(I),POSSIBLE(I),EARNED(I)
END
What could be causing the read issues I'm facing?
The line to read the file contents was too long, so I shortened the names of the variables to save some space and the problem was solved.
I try in a small code to write output results with numerical values between various text.
For the moment, I do :
! Print results
write(*,*)
write(*,*) ' Time step = ',dt
write(*,*)
write(*,1001) epsilon,step
write(*,*)
write(*,*) ' Problem size = ',size_x*size_y
write(*,*)
write(*,1002) elapsed_time
write(*,*)
write(*,*) ' Computed solution in seq.dat file '
write(*,*)
! Formats available to display the computed values on the grid
1001 format(' Convergence = ',f11.9,' after ',i9,' steps ')
1002 format(' Wall Clock = ',f15.6)
which produces at the execution :
Time step = 0.000003755783907217
Convergence = 0.100000000 after 8882 steps
Problem size = 24576
Wall Clock = 5.213814
Computed solution in Seq.dat
My issue is about the line "Wall Clock = 5.213814", I would like to get only one space juste after "Wall Clock =" before the value "5.213814". Currently, I think these multiple spaces that I get come from the "f15.6" with 1002 format(' Wall Clock = ',f15.6).
Here's what I want to get (with another value for steps) :
Time step = 0.000003755783907217
Convergence = 0.100000000 after 20910988821 steps
Problem size = 24576
Wall Clock = 5.213814
Computed solution in Seq.dat
I have set "f15.6" since I can get high number for "Wall Clock", same thing for espilon and step variables.
I don't know in all cases how to set just one space between words and values to write between them, as when I printf, in C language, different values and words on the same line.
I know there's a simple solution but can't find it.
UPDATE 1 :
I tried the solution indicated in the first answer.
Here's what I have done :
write(*,1001) epsilon,step
write(*,1002) elapsed_time
1001 format(' Convergence = ',f0.9,' after ',i9,' steps ')
1002 format(' Wall Clock = ',f0.6)
and I get :
Convergence = .100000000 after 8882 steps
Problem size = 24576
Wall Clock = 2.492813
As you can see, "Convergence" value is .100000000 instead of 0.100000000 (leading zero has disappeared).
And what about the integers values, can I write "i0" to have as few as possible ?
Thanks
Modern Fortran compilers understand a 'length' of 0 to mean: As few as possible:
program write_format
use iso_fortran_env, only: real64
implicit none
print 1001, 5.213814
print 1001, 12345678.901234_real64
1001 format("Wall Clock = ", f0.6)
end program write_format
Output:
Wall Clock = 5.213814
Wall Clock = 12345678.901234
Cheers
Usually it's not liked to update the question after the answer to ask additional questions, but since they're quite similar, I think it's okay.
Firstly, yes, format I0 means as few digits as necessary, and probably is what you want.
The second part is trickier, it seems to boil down to 'at least that many digits, but more if needed' -- and I don't think there's a format specifier for that (but I might be wrong).
I'd probably cheat and use something like this:
if (epsilon < 10.) then
write(*, 1002) epsilon
else
write(*, 1003) epsilon
end if
1002 format("Convergenge = ", f11.9)
1003 format("Convergence = ", f0.9)
But then again, I also found this answer quite intuitive: How to pad FORTRAN floating point output with leading zeros?
Adapted for you, it would mean splitting the floating point number into an integer and the rest, and putting it back together again:
write(*, 1002) int(epsilon), epsilon-int(epsilon)
1002 format("Convergence = ", I0, F0.9)
this is a bit cumbersome, but one way to get minimum width and preserve the lead zero is to use an internal write like this:
character*30 val
write(val,'(f11.9)')0.1d0
write(*,'(3a,i0,a)')'converge = ',trim(adjustl(val)),' after ',32432,' steps'
converge = 0.100000000 after 32432 steps
I have a input file (filename: L0analysis) like below
...... !headers
3 2.1 2.4 2.5 !ntfmr rcut(1) rcut(2) rcut(3)
...... !other data
The index i in rcut(i) is determined by ntfmr
in my program,
......
ncrit=55
open(ncrit,file='Lanalysis')
......!(read the headers. skipped here)
read(ncrit,*) ntfmr, (rcut(i),i=1,ntfmr)
do i=1,ntfmr ! # of network formers and their cutoffs
rcut2(i)=rcut(i)*rcut(i)
write(*,*)'ntfmr',ntfmr,'i=',i,rcut(i)
enddo
.......
.......
My output is
ntfmr 3 i= 1 2.10000000000000
ntfmr 3 i= 2 2.40000000000000
ntfmr 3 i= 3 4.41000000000000
I tried to initialize rcut(i)=0. It does not work. I cannot find any place to change this value.
I am unable to figure it out what is going wrong. Any suggestion or comment will be highly appreciated.
I have recently changed my f90 editor to CodeBlocks for Mac OS X, and when I try to open a file located in the project folder to read the data, the next error message appears on screen when the code is run:
Fortran runtime error: Bad integer for item 0 in list input
I have introduced the same code I used to write in Windows 7 using the intel compiler for fortran and Visual Studio.
The code itself is:
subroutine read_input_data
use input_data
implicit none
integer i,j
open(UNIT=5, FILE='lifting_line_input_data.txt', STATUS='old', FORM='formatted', ACCESS='sequential')
read(5,*) C
read(5,*) U
read(5,*) alpha
read(5,*) rho
read(5,*) wake_length
read(5,*) wake_eps
read(5,*) n_chord
read(5,*) n_twist
if (n_chord .GE. n_twist ) then
i = n_chord
else
i = n_twist
end if
allocate(chord_twist(5,i))
do j = 1, i
read(5,*) chord_twist(:,j)
end do
close(5)
end subroutine read_input_data
Could you help me to solve this problem? Thank you very much.
PD. the data file is obtain from an Excel sheet saved as a .txt delimited by tabulations
! LIFTING-LINE WING
! Number of panels
6
! Free stream speed [m/s]
50
! Angle of attack [rad]
0.15
! Air density [kg/m^3]
1.225
! Wake length [m]
100
! Convergence parameter
0.01
! Number of data points given for the chord distribution
2
! Number of data points given for the twist distribution
2
! Y coord [m] ! X_LE [m] ! X_TE [m] ! Y coord [m] ! Twist [rad]
0 0 2 0 0
10 0 0.5 10 0.052359878
PD2. I have change the format of the .txt file to make it equal to the input files I had used in Visual Studio. Now the file is:
6 ! Number of panels
50 ! Free stream speed [m/s]
0.15 ! Angle of attack [rad]
1.225 ! Air density [kg/m^3]
100 ! Wake length [m]
0.01 ! Convergence parameter
2 ! Number of data points given for the chord distribution
2 ! Number of data points given for the twist distribution
0 0 2 0 0 ! Y coord [m] ! X_LE [m] ! X_TE [m] ! Y coord [m] !Twist [rad]
10 0 0.5 10 0.052359878
And now the error given at the terminal is that the file is not found. As I am a beginner in CodeBlocks, I will explain what I have done step by step because I do not find where I am wrong and I am starting to get desperate:
New Project -> Fortran application -> I indicate where I want to create the project file.
I remove the main.f95 file and I add the .f90 file with the code.
I write the code.
I save the .txt file in the same folder than all the files of the Project.
When I run the code it appears the error message of file not found.
The code is:
!************************************************
subroutine read_input_data
use input_data
implicit none
integer i,j
open(UNIT=10, FILE='lifting_line_wing_input.txt', STATUS='old', ACCESS='sequential')
read(10,*) C
read(10,*) U
read(10,*) alpha
read(10,*) rho
read(10,*) wake_length
read(10,*) wake_eps
read(10,*) n_chord
read(10,*) n_twist
if (n_chord .GE. n_twist ) then
i = n_chord
else
i = n_twist
end if
allocate(chord_twist(5,i))
do j = 1, i
read(10,*) chord_twist(:,j)
end do
close(10)
end subroutine read_input_data
!************************************************
Thank you very much for your time and help
This looks like your old system did something non-standard with exclamation marks on list-directed input.
Try reformatting your input data like
6 / number of panels
(the slash will terminate the READ).
i don't believe any fortran compiler ever automagically handled those comments.
If you want to read this file the way it is, one approach is to make each read handle the error, eg,
integer ios
ios = 1
do while(ios.ne.0)
read(unit,*,iostat=ios)c
end do
ios=1
do while(ios.ne.0)
read(unit,*,iostat=ios)u
end do
etc..
if its a one-off you could just edit the file and delete all the comments as well.
I need to read some values from a table. These are the first five rows, to give you some idea of what it should look like:
1 + 3 98 96 1
2 + 337 2799 2463 1
3 + 2801 3733 933 1
4 + 3734 5020 1287 1
5 + 5234 5530 297 1
My interest is in the first four columns of each row. I need to read these into arrays. I used the following code:
program ----
implicit none
integer, parameter :: totbases = 4639675, totgenes = 4395
integer :: codtot, ks
integer, dimension(totgenes) :: ngene, lend, rend
character :: genome*4639675, sign*4
open(1,file='e_coli_g_info')
open(2,file='e_coli_g_str')
do ks = 1, totgenes
read(1,100) ngene(ks),sign(ks:ks),lend(ks), rend(ks)
end do
100 format(1x,i4,8x,a1, 2(5x,i7), 22x)
do ks = 1, 100
write(*,*) ngene(ks), sign(ks:ks),lend(ks), rend(ks)
end do
end program
The loop at the end of the program is to print the first hundred entries to test that they are being read correctly. The problem is that I am getting this garbage (the fourth row is the problem):
1 + 3 757934891
2 + 337 724249387
3 + 2801 757803819
4 + 3734 757803819
5 + 5234 757935405
Clearly, the fourth column is way off. In fact, I cannot find these values anywhere in the file that I am reading from. I am using the gfortran compiler for Ubuntu 12.04. I would greatly appreciate if somebody would point me in the right direction. I'm sure it's likely that I'm missing something very obvious because I'm new at Fortran.
Fortran formats are (traditionally, there's some newer stuff that I won't go into here) fixed format, that is, they are best suited for file formats with fixed columns. I.e. column N always starts at character position M, no ifs or buts. If your file format is more "free format"-like, that is, columns are separated by whitespace, it's often easier and more robust to read data using list formatting. That is, try to do your read loop as
do ks = 1, totgenes
read(1, *) ngene(ks), sign(ks:ks), lend(ks), rend(ks)
end do
Also, as a general advice, when opening your own files, start from unit 10 and go upwards from there. Fortran implementations typically use some of the low-numbered units for standard input, output, and error (a common choice is units 1, 5, and 6). You probably don't want to redirect those.
PS 2: I haven't tried your code, but it seems that you have a bounds overflow in the sign variable. It's declared of length 4, but then you assign to index ks which goes all the way up to totgenes. As you're using gfortran on Ubuntu 12.04 (that is, gfortran 4.6), when developing compile with options "-O1 -Wall -g -fcheck=all"