One too many new lines in a WRITE statement [duplicate] - fortran

This is my code:
Program Output_Format
Implicit none
Integer::k
Integer,parameter:: Br_nn_mre = 5
Character(56),parameter:: FMT_01 = '(1x,"NN_DM:",1x,*("NN_",i2.2,1x))'
Open( 15 , File = 'Output.txt' , Status = 'Unknown' , Action = 'Write' )
Write( 15 , FMT_01 ) ( k , k = 1 , Br_nn_mre )
Close( 15 , Status = 'Keep' )
End Program Output_Format
The content of Output.txt file is:
NN_DM: NN_01 NN_02 NN_03 NN_04 NN_05 NN_
I want to get this content in Output.txt:
NN_DM: NN_01 NN_02 NN_03 NN_04 NN_05
That is, without the trailing NN_
What is wrong with * IN FMT_01 format? For example if I put a 5 in place of * I will get what I want. How can I use the unlimited repeat count and still get the desired output? I won't always know how many times to repeat.

This is related to how formats are processed, and in particular, when a data transfer statement terminates.
For an output statement such as you have, transfer terminates when either:
a data edit descriptor is reached and there is no remaining element in the output list; or
the final closing parenthesis is reached and there is no remaining element in the output list.
In your formats
'(1x,"NN_DM:",1x,*("NN_",i2.2,1x))'
and
'(1x,"NN_DM:",1x,5("NN_",i2.2,1x))'
the single data edit descriptor there is the i2.2. The 1xs are control edit descriptors and the "NN_DM" and "NN_" are character string edit descriptors.
Let's look at how your format is processed in the case of 5 as the repeat count. The first part of the format 1x,"NN_DM:",1x is processed without issue giving output NN_DM: moving us on to 5("NN_",i2.2,1x)). Corresponding to this repeated fragment are five data items, so they are processed (giving output NN_01 NN_02 NN_03 NN_04 NN_5).
The important part is what happens next. After completing this 5(..) part we reach the final closing parenthesis of the format specification and there is no remaining output item, so processing of the format comes to an end.
What's different with the *(..) case?
Well, when we reach the end of *(..) we go back round to the start of that repeated format; we don't move on to the final closing parenthesis.1 That leaves us to process the edit descriptors until we reach a data edit descriptor. This means that "NN_" is processed (resulting in NN_ being output) before we notice that we are out of data items for output.
Coming to the fix: use the colon edit descriptor. The colon edit descriptor acts like a data edit descriptor in the sense that format processing terminates immediately if there is no remaining data item.
Character(56),parameter:: FMT_01 = '(1x,"NN_DM:",1x,*("NN_",i2.2,:,1x))'
Personally, I would write this as
Character(*),parameter:: FMT_01 = '(" NN_DM:",*(" NN_",i2.2,:))'
1 This would be no different if we had 6 as the repeat count; * isn't special except that it is a "very large repeat count".

Related

Asking user for raw_input to open a file, when attempting to run program comes back with mode 'r'

I am trying to run the following code:
fname = raw_input ('Enter file name:')
fh = open (fname)
count = 0
for line in fh:
if not line.startswith ('X-DSPAM-Confidence:') : continue
else:
count = count + 1
new = fh #this new = fh is supposed to be fh stripped of the non- x-dspam lines
for line in new: # this seperates the lines in new and allows `finding the floats on each line`
numpos = new.find ('0')
endpos = new.find ('5', numpos)
num = new[numpos:endpos + 1]
float (num)
# should now have a list of floats
print num
The intention of this code is to prompt the user for a file name, open the file, read through the file, compile all the lines that start with X-DSPAM, and extract the float number on these lines. I am fairly new to coding so I realise I may have committed a number of errors, but currently when I try to run it, after putting in the file name I get the return:
I looked around and I have seen that mode 'r' refers to different file modes in python in relation to how the end of the line is handled. However the code I am trying to run is similar to other code I have formulated and it does not have any non-text files inside, the file being opened is a .txt file. Is it something to do with converting a list of strings line by line to a list of float numbers?
Any ideas on what I am doing wrong would be appreciated.
The default mode of handling a file is 'r' - which means 'read', which is what you want. It means the program is going to read the file (as opposed to 'w' - write, or 'a' - append, for example - which would allow you to overwrite the file or append to it, which you don't want in this case).
There are some bugs in your code, which I've tried to indicate in the edited code below.
You don't need to assign new = fh - you're not grabbing lines and passing them to a new file. Rather, you're checking each line against the 'XDSPAM' criteria and if it's a match, you can proceed to parse out the desired numbers. If not, you ignore it and go to the next line.
With that in mind, you can move all of the code from the for line in new to be part of the original if not ... else block.
How you find the end of the number is also a bit off. You set endpos by searching for an occurence of the number 5 - but what I think you want is to find a position 5 characters from the start position (numpos + 5).
(There are other ways to parse the line and pull the number, but I'm going to stick with your logic as indicated by your code, so nothing fancy here.)
You can convert to float in the same statement where you slice the number from the line (as below). It's acceptable to do:
num = line[numpos:endpos+1]
float_num = float(num)
but not necessary. In any event, you want to assign the conversion (float(num)) to a variable - just having float(num) doesn't allow you to pass the converted value to another statement (including print).
You say that you should have 'a list of floats' - the code as corrected below - will give you a display of all the floats, but if you want an actual Python list, there are other steps involved. I don't think you wanted a Python list, but just in case:
numlist = [] # at the beginning, declare a new, empty list
...
# after converting to float, append number to list
XDSPAM.append(num)
print XDSPAMs # at end of program, to print full list
In any event, this edited code works for me with an appropriate file of test data, and outputs the desired float numbers:
fname = raw_input ('Enter file name:')
fh = open (fname)
count = 0
for line in fh:
if not line.startswith ('X-DSPAM-Confidence:') : continue
else:
# there's no need to create the 'new' variable
# any lines that meet the criteria can be processed for numbers
count = count + 1
numpos = line.find ('0')
# i think what you want here is to set an endpoint 5 positions to the right
# but your code was looking for the position of a '5' in the line
endpos = numpos + 5
# you can convert to float and slice in the same statement
num = float(line[numpos:endpos+1])
print num

Program compiling but not printing results

I have been trying to write a program in Fortran77 and am not able to finish it up, so I need a bit help to make it work.
At first I am just trying to open a .txt file read the file and write the file.
the .txt file is of the format shown below.
001,0.02014,3.1217
002,0.09611,3.1203
003,0.23753,3.1128
004,0.45527,3.0884
005,0.75772,3.0285
where the first column is integer and the second column coma separated contains a real number with 5 digits after the decimal point and third column again a real number with four digits after the decimal point.
My program looks as follows:
PROGRAM FIRST
IMPLICIT NONE
REAL,DIMENSION(304,3)::A
OPEN(UNIT =7 , FILE = "Pressure_values.txt",
1 FORM = "FORMATTED", STATUS = "OLD", ACTION = "READ")
READ(*,100) ((A(I,J),J=1,3), I=1,304)
WRITE(*,100) ((A(I,J),J=1,3), I=1,304)
100 FORMAT(I3,F10.5,F10.4)
STOP
END
Where am I going wrong?
You are not reading from the file. You need to read from unit 7.
read(7,100)
your code:
READ(*,100) ((A(I,J),J=1,3), I=1,304)
means "read from STDIN with format No.100", not the file you just opened. STDIN normally means the keyboard input stream. use:
READ(7,100) ((A(I,J),J=1,3), I=1,304)
instead.

FORTRAN code with ascii data

I have a data in ASCII format (.txt file) in which date is given in a column in format yearmonthday (i.e.19900601). I want to separate this column into three columns with year, month and date in each column. Can anyone tell how to do this in Fortran? My data file and code is as following:
datum nied
19480501 -1
19480502 -1
19480503 2
19480504 -1
19480505 2
19480506 -1
19480507 -1
19480508 -1
19480509 -1
19480510 -1
19480511 -1
19480512 2
. .
. .
Code:
program ascii_read
!real(kind=8):: rain(np)
real,allocatable:: rain(:)
integer::np=15739
!integer(kind=8)::day(np)
integer,allocatable::day(:)
character(len = 80)::firstline
integer::i,j
integer,allocatable:: year(:)
allocate (year(np-1))
allocate (rain(np))
allocate (day(np))
open(1243,file="11700.text",status="unknown")
open(12,file="11700_output.text",status="unknown")
read(1243,*)firstline
do i=2,np
read(1243,1111)day(i),rain(i)
end do
1111 Format(i6,F5.2)
write(*,*)day
do j = 1,np-1
year(j)=day(j)
end do
write(*,fmt='(i4)')year
1 format(I4)
!write(*,*)year
return
stop
end program
This gives only year separate in a column,NOT month and day. Any idea how to separate month and day from this data file?
you can use a formatted read to explicitly pull out each of the fields:
integer year,month,day,rain
...
read(1234,'(i4,i2,i2,i3)')year,month,day,rain
In your code you use i6 so day(i) holds things like '194805', then rain(i) is read from the remainder of the line (ie. the last two digits of the "date" integer a space and another integer). I don't know what the f5.2 format does with that but it can't be what you want)
You have to analyse the relationship between your input and the output that you want and then implement the relationship; that is how programming works. You have to first know a method to solve the problem by yourself and then teach the computer how to do it.
For this problem, you can simply see that the first 4 digits represent the year, the next two the month and the last 2 the date. To get the first 4, you divide the full number by 10000, it simply reject the last 4 (month and day). You use the modulo operation to get the last four. And do the same to extract the month from the last two.
Define new array variables month and date and allocate them to the same size as day, also add a new integer variable tmp and change your second loop to this:
do j = 1,np-1
year(j)=day(j)/10000
tmp = mod(day(j), 10000)
month(j) = tmp/100
date(j) = mod(tmp,100)
end do
I will also advise you to use free formatting for reading. You can use fixed format for writing to align data and make it easy to visualize.
Go for modern programming when you start. Litteral numbers are not a good idea in a code, so use named constants for file ids. Make sure that you close files when you do not need them anymore. When you are openning file for reading, use status='old', you want the file to be there or you want you program to stop with an appropriate message. When you are using format, use the format parameter of read and write instead of format statement, for example with the name arg fmt as you did at some places. This make it easy to debug. So your program could look like this.
program ascii_read
!real(kind=8):: rain(np)
integer, parameter :: inputId = 1243
integer, parameter :: outputId = 12
real,allocatable,dimension(:):: rain
integer::np=12
!integer(kind=8)::day(np)
character(len = 80)::firstline
integer::i,j, tmp
integer,allocatable,dimension(:):: day, year, month, date
allocate ( year(np-1), rain(np), day(np), month(np), date(np) )
open(inputId,file="11700.text",status="old")
open(outputId,file="11700_output.text",status="unknown")
read(inputId,*)firstline
do i=2,np
read(inputId,*)day(i),rain(i)
end do
close(inputId)
write(*,*) day
do j = 1,np-1
year(j)=day(j)/10000
tmp = mod(day(j), 10000)
month(j) = tmp/100
date(j) = mod(tmp,100)
! just to see what we get.
write(*, *) day(j), year(j), month(j), date(j)
end do
!write(*,fmt='(i4)')year
!1 format(I4)
!write(*,*)year
return
stop
end program
Thank to IanH for the comment, latest version of fortran included a newunit option that takes care of the IO unit number for programmers. This frees you from defining named constant for unit number. If you do not work with a latest version (Some companies do not upgrade often), there is one ready for use in fortranwiki.
A "hybrid" approach of the other two answers is to first read in the data into a buffer and then split it into integers
character(50) buf
integer year, month, day, rain
read( 10, * ) buf, rain
read( buf, "(i4,i2,i2)" ) year, month, day
! or equivalently
! read( buf(1:4), * ) year
! read( buf(5:6), * ) month
! read( buf(7:8), * ) day
Here, list-directed I/O is used to skip possible spaces before the first column, while integers are extracted based on widths. Also, comment lines starting with "#" (if any) can be skipped by inserting if ( buf(1:1) == "#" ) cycle after the first read statement, for example.

Reading data from files of varying length and varying columns

I've been reading stackoverflow questions all morning, trying different approaches with no headway.
I'm trying to automate the process of reading data from 318 qdp files for plotting onto a graph (plus a few other things). The reason I'm doing this and not using qdp is because it's not helpful for what I'm trying to do.
The qdp file is just like any other .txt file, except with hidden characters of \n after each line and \t between each data entry so reading from it in a pythonic way should be straightforward. However the file format is giving me a headache.
A typical file has the following format:
Header - 8 Lines
space
qdp code line
datatype header \ Data Group
data column header / 1
data - 6 columns /
qdp code line
datatype header \ Data Group
data column header / 2
data - 6 columns /
This seems straightforward enough, however each file has varying numbers of data groups (between 1 and 3), of which only 1 I want to extract. So sometimes the data I want is the first group, sometimes it's the second and sometimes there isn't a data group after the data I want and thus the extra qdp code line isn't there.
Each line (except data) has varying amount of columns, so np.genfromtxt doesn't work. I've tried telling it to ignore every line till it finds the specific datatype header which heads the data I want and then extract from there but I can't seem to figure out how to do that. I've tried reading the file, assigning each line an index and then going back to find the index of the datatype header and going from there but with no success either.
Like my previous questions its seems like such a trivial issue, and yet I can't figure it out.
Appreciate the help.
So after more reading and trying all sorts of solutions, I've come up with a rather inelegant solution.
with open(file, "r") as f:
index = 0
data_start = 0
data_end = 0
EOF = 0
for line in f:
temp = line.strip()
datatemp.append(temp)
if line.strip() == "datatype header":
index += 1
data_start = index + 2
elif line.strip() == "next datatype header":
index += 1
data_end = index - 3
else:
index += 1
if f.readline() = "":
EOF = index
if data_end == 0:
data_end = EOF
Thus in the case when there is a data group after the one I want to extract, it uses that groups header to point back to end of data to be extracted, and when the data group I want to extract is the last group in the file it uses the EOF marker to point back.
After this I then split datatemp into 6 columns, assigning each to a list. Finally I can then manipulate the data I wanted and the program runs through all 318 files yey!

How to replay a list of event consistently

I have a file containing a list of event spaced with some time. Here is an example:
0, Hello World
0.5, Say Hi
2, Say Bye
I would like to be able to replay this sequence of events. The first column is the delta between the two consecutive events ( the first starts immendiately, the second happens 0.5s later, the third 2s later, ... )
How can i do that on Windows . Is there anything that can ensure that I am very accurate on the timing ? The idea is to be as close as what you would have listneing some music , you don't want your audio event to happen close to the right time but just on time .
This can be done easily by using the sleep function from the time module. The exact code should work like this:
import time
# Change data.txt to the name of your file
data_file = open("data.txt", "r")
# Get rid of blank lines (often the last line of the file)
vals = [i for i in data_file.read().split('\n') if i]
data_file.close()
for i in vals:
i = i.split(',')
i[1] = i[1][1:]
time.sleep(float(i[0]))
print i[1]
This is an imperfect algorithm, but it should give you an idea of how this can be done. We read the file, split it to a newline delimited list, then go through each comma delimited couplet sleeping for the number of seconds specified, and printing the specified string.
You're looking for time.sleep(...) in Python.
If you load that file as a list, and then print the values,
import time
with open("datafile.txt", "r") as infile:
lines = infile.read().split('\n')
for line in lines:
wait, response = line.split(',')
time.sleep(float(wait))
print response