I have to read a file that contains numerical data (mostly reals) but there are also some missing data that are denoted by an asterisk(*). I don't know the positions of the asterisks in advance and I have to find the total valid (numerical) data and the total missing data (asterisks).
I tried doing this with a 'select case' nested in a do loop but failed because
I can't use real type for the selector
I don't think I can put the asterisks in a real matrix
The data file looks something like this
1 0.673070
2 0.750597
3 *
4 0.484100
Any suggestions?
Yes in the future, please provide some more information and post a [Minimal, Complete, and Verifiable example] (https://stackoverflow.com/help/mcve) of some code that tries to read it.
But, assuming you know every line has either a real number or an *, I would do something like this:
Character(len=8) :: LineRead
Real :: RealNumber
open(42,file='MyFile.txt')
do (whichever kind of loop you need to control the input)
read(42,'(a8)') LineRead
if (LineRead <> '* ')
read(LineRead,'(f8.6)') RealNumber
! Increment some sort of valid data counter
end if
end do
If you are not familiar with this technique, it is called reading from an internal file. Any character variable can be 'read' this way.
Related
300 do i=1,counter
open(1,file='Pcow_pd.txt')
write(1,*),Sw_pd(i), Pcow_pd(i)
open(2,file='Krw_pd.txt')
write(2,*),Sw_pd(i), Krw_pd(i)
open(3,file='Kro_pd.txt')
write(3,*),Sw_pd(i), Kro_pd(i)
print*, counter
end do
print *,"filled =",filled
When I compile the code I get an error message at write lines which I cannot fix
Compile error: error 573 - Missing expression
As has been commented, there should be no comma before the list of items for output. You should simply have
write(1,*) Sw_pd(i), Pcow_pd(i)
and so on.
The later line
print*, counter
where the comma before counter is absolutely necessary, may add a little confusion on writing. This is perhaps increased by how read is used: there are two forms:
read *, x
read (*,*) y
The first example without an explicit statement of unit implies the same unit as the * in the second and it requires a comma. The second must not have a comma.
A simple way to remember whether the output list has a comma first: if the format comes in isolation use the comma; if the unit is specified, don't.
I am new to Fortran 77. I need to read the data from a given text file into two arrays, but there are some lines that either are blank or contain descriptive information on the data set before the lines containing the data I need to read. How do I skip those lines?
Also, is there a way my code can count the number of lines containing the data I'm interested in in that file? Or do I necessarily have to count them by hand to build my do-loops for reading the data?
I have tried to find examples online and in Schaum's Programming with Fortran 77, but couldn't find anything too specific on that.
Part of the file I need to read data from follows below. I need to build an array with the entries under each column.
Data from fig. 3 in Klapdor et al., MPLA_17(2002)2409
E(keV) counts_in_bin
2031.5 5.4
2032.5 0
2033.5 0
I am assuming this question is very basic, but I've been fighting with this for a while now, so I thought I would ask.
If you know where the lines are that you don't need/want to read, you can advance the IO with a call to read with no input items.
You can use:
read(input-unit,*)
to read a line from your input file, discard its contents and advance IO to the next line.
It has been a long time since I have looked at F77 code, but in general if your read statement in a DO loop can deal with finding empty lines, or even a record that contains only blanks, then you could write logic to trap that condition and go to a break or continue statement. I just don't recall if read can deal with the situation intelligently.
Alternatively, if you are using a UNIX shell and coreutils, you can use sed to remove empty line, /^$/
or /^ *$/ to preprocess the file before you send it onto F77
Something like
$ sed infile -e 'd/^$/;d/^ *$/' > outfile
It should look something like this:-
C Initialise
integer i
character*80 t1,t2,t3
real*8 x,y
open(unit=1,file='qdata.txt')
C Read headers
read(1,100)t1
100 format(A80)
write(6,*) t1
read(1,100)t2
write(6,*) t2
read(1,100)t3
write(6,*) t3
write(6,*)
C Read data
do 10 i=1,10
read(1,*,end=99) x,y
write(6,*) x,y
10 continue
99 continue
end
So I've used a classic formatted read to read in the header lines, then free-format to read the numbers. The free-format read with the asterisk skips white space including blank lines so it does what you want, and when there is no more data it will go to statement 99 and finish.
The output looks like this:-
Data from fig. 3 in Klapdor et al., MPLA_17(2002)2409
E(keV) counts_in_bin
2031.5000000000000 5.4000000000000004
2032.5000000000000 0.0000000000000000
2033.5000000000000 0.0000000000000000
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.
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.
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.