Looping over variable file names [duplicate] - fortran

This question already has answers here:
Convert integers to strings to create output filenames at run time
(9 answers)
Closed 7 years ago.
I am using Fortran to do calculation on huge data set which was split into many files. The names of the files are:
maltoLyo12per-reimage-set1.traj
maltoLyo12per-reimage-set2.traj
maltoLyo12per-reimage-set3.traj
The code I wrote to do the calculation is as below:
fileLoop: do j = 31, 34
OPEN(unit=31,status='old',file=fileplace//'maltoLyo12per-reimage-set1.traj')
OPEN(unit=32,status='old',file=fileplace//'maltoLyo12per-reimage-set2.traj')
OPEN(unit=33,status='old',file=fileplace//'maltoLyo12per-reimage-set3.traj')
OPEN(unit=34,status='old',file=fileplace//'maltoLyo12per-reimage-set4.traj')
... operation....
close (j)
end do fileLoop
During the run I want the code to open each file at a time and close them after finish calculation. But the above code will open all the files at once and close them one after one upon finish calculation.
So I tried to alter the code something like below:
fileLoop: do j = 31, 34
OPEN(unit=j,status='old',file=fileplace//'maltoLyo12per-reimage-set1.traj')
close (j)
end do fileLoop
But here I am facing a problem with the file name. Each time the loop run, the file name doesn't change because of the phrase "set1" in the file name. I want the number in the file name to change like set1, set2, set3, etc., subsequently with file unit number 31,32,33,34, etc.

Something like this: (edited to have unit numbers 31 to 34, filenames 1 to 4.)
character (len=90) :: filename
fileLoop: do j = 31, 34
write (filename, '( "maltoLyo12per-reimage-set", I1, ".traj" )' ) j - 30
OPEN(unit=j,status='old',file=filename)
close (j)
end do fileLoop

Related

Continue strings into next line in Fortran 77 [duplicate]

This question already has answers here:
Line continuation of strings in Fortran
(4 answers)
Closed 4 years ago.
I have this code in FORTRAN 77 (I have to use this because it is used as a subroutine for my Abaqus program) where I am asking the subroutine to print my stresses and strain results, for each element and after each time increment, in a particular place. Now, my directory path is long (because of several reasons). Therefore, I have to write the path to the directory in two lines since FORTRAN 77 only recognizes anything written between columns 6 to 77 (I believe!).
Now, I have tried many things!
I have put & symbol at column 6 on the next line, a number (like 1) at column 6 on the next line, and even a star symbol (*) at the same place!
However, I keep getting error# 5082!
Here is the part of the code that is not being accepted in ifort compiler:
subroutine uvarm(uvar,direct,t,time,dtime,cmname,orname,
1 nuvarm,noel,npt,layer,kspt,kstep,kinc,ndi,nshr,coord,
2 jmac,jmatyp,matlayo,laccfla)
include 'aba_param.inc'
character*80 cmname, orname
character*3 flgray(15)
character*80 file1, file2
dimension uvar(nuvarm),direct(3,3),t(3,3),time(2)
dimension array(15),jarray(15),jmac(*),jmatyp(*),coord(*)
C integer i
call getvrm('E',array,jarray,flgray,jrcd,jmac,jmatyp,
1 matlayo,laccfla)
uvar(1) = array(1)
uvar(2) = array(2)
uvar(3) = array(4)
call getvrm('S',array,jarray,flgray,jrcd,jmac,jmatyp,
1 matlayo,laccfla)
uvar(4) = array(1)
uvar(5) = array(2)
uvar(6) = array(4)
file1 = '/gpfs/work/m/mfg5310/fracture/ResearchWork'
1 '/fracture_subroutines/frac_in_mid_Mode2_case1_strains.txt'
file2 = '/gpfs/work/m/mfg5310/fracture/ResearchWork'
2 '/fracture_subroutines/frac_in_mid_Mode2_case1_stress.txt'
open(unit=101,file=file1)
open(unit=103,file=file2)
write(101,350) uvar(1),uvar(2),uvar(3),coord(1),coord(2)
write(103,350) uvar(4),uvar(5),uvar(6),coord(1),coord(2)
350 format(e12.5,6x,e12.5,6x,e12.5,6x,e12.5,6x,e12.5)
C close(unit=101)
C close(unit=103)
return
end
What should I do?
I know I can always shorten the path so that the entire directory fits in one line. But for two reasons, I want to know how to continue the string into the next line in Fortran 77:
Reason 1: I just really want to know this.
Reason 2: The files printed are more organized this way! I will be able to name the file exactly what I want to.
Simply use the Fortran string concatenation operator // like this
file1 = '/gpfs/work/m/mfg5310/fracture/ResearchWork'//
& '/fracture_subroutines/frac_in_mid_Mode2_case1_strains.txt'

How to fix Fortran runtime error: End of file?

I am trying to read a file called "syerasg.txt" in Fortran90. This text file includes panel data on 91 variables (columns) for 8984 individuals for 16 years (143 744 rows). This variables are divided in 7 groups and this groups are divided in 13 subgroups. I am trying to read this file with the following code:
PROGRAM main
IMPLICIT NONE
INTEGER, PARAMETER :: p=8984, tf=16, sem=53, emp=7, gap=13
INTEGER :: r, t, j, m, g, x, i, IOstatus
INTEGER, DIMENSION (p,tf,emp) :: yemp
INTEGER, DIMENSION (p,tf,emp,gap) :: gaps
OPEN(UNIT=4, FILE='syearsg.txt',STATUS='old') !start gap years
DO i=1,p
DO t=1,tf
DO j=1,emp
IF (j==1) THEN
READ(4,*)(gaps(i,t,j,g),g=1,13)
ELSE IF (j==2) THEN
READ(4,*)(gaps(i,t,j,g-13),g=14,26)
ELSE IF (j==3) THEN
READ(4,*)(gaps(i,t,j,g-26),g=27,39)
ELSE IF (j==4) THEN
READ(4,*)(gaps(i,t,j,g-39),g=40,52)
ELSE IF (j==5) THEN
READ(4,*)(gaps(i,t,j,g-52),g=53,65)
ELSE IF (j==6) THEN
READ(4,*)(gaps(i,t,j,g-65),g=66,78)
ELSE IF (j==7) THEN
READ(4,*)(gaps(i,t,j,g-78),g=79,91)
END IF
END DO
END DO
END DO
CLOSE(4)
END PROGRAM main
When, running the code I get the following message:
Fortran runtime error: End of file
Any ideas on how to solve this?
Your loop nest issues 1,006,208 (that is p*tf*emp) read statements. It's no surprise that the program runs past the end of a file with only 143,744 lines. read reads the values it is asked to read, then skips to the start of the next line ready for the next read.
You might be able to fix your program by fiddling around with non-advancing input, ie telling the read statements not to skip to the start of the next line. But it would be easier not to.
From what you write you should only be issuing p*tf read statements, then reading a single line containing 91 elements, then distributing those elements into gaps as your logic demands.
You might revise your code to something like this (untested and not very carefully checked)
INTEGER, DIMENSION(91) :: workvec
...
DO i=1,p
DO t=1,tf
READ(4,*) workvec
gaps(i,t,1,1:13) = workvec( 1:13)
gaps(i,t,2,1:13) = workvec(14:26)
...
END DO
END DO

How to read the last array line in text file in Fortran 77 and save it in an array?

For example, I have a write command to save an array with 6 fields in a text file like this:
OPEN(UNIT=26,FILE='W:\Partikeltemperaturfeld.txt',
&FORM ='FORMATTED',STATUS='UNKNOWN',
&ACTION='READWRITE')
C
WRITE (26,FMT='(6(F8.3,3X))') TFIELD(1,1:6)
C
REWIND(26)
Now I want to read and save the 6 values of the last line of my text file in another array with 6 fields like:
IOS = 0
DO WHILE (IOS.EQ.0)
READ(UNIT=26,FMT='(6(F8.3,3X))',IOSTAT=IOS) TEST(1:6)
END DO
This could be the content of the last line in my file:
1377.445 1373.171 1363.639 1352.062 1341.476 1334.764
The aim is to save the last line in existing format.
But after doing this I always get values 0.000000E+00. How can I read and save the last line of my 'W:\Partikeltemperaturfeld.txt' file in array TEST(1:6)?
If you do
DO WHILE (IOS.EQ.0)
READ(UNIT=26,FMT='(6(F8.3,3X))',IOSTAT=IOS) TEST(1:6)
END DO
the loop will exit when there was some problem (end of file or an error condition) reading the array in the input list. The value of the variable being read is than undefined. You cannot use it. It can contain anything.
BTW your code is not Fortran 77 conforming (it is Fortran 90 or later) so I will not try to make my suggestion 100% Fortran 77 either. You can do
DO
READ(UNIT=26,FMT='(6(F8.3,3X))',IOSTAT=IOS) TMP
IF (IOS.EQ.0) THEN
TEST = TMP
ELSE
EXIT
END DO
END DO
where TEST and TMP are arrays of size 6

Python: Extracting floats from files in a complex directory tree - Are loops the answer?

I have just started doing my first research project, and I have just begun programming (approximately 2 weeks ago). Excuse me if my questions are naive. I might be using python very inefficiently. I am eager to improve here.
I have experimental data that I want to analyse. My goal is to create a python script that takes the data as input, and that for output gives me graphs, where certain parameters contained in text files (within the experimental data folders) are plotted and fitted to certain equations. This script should be as generalizable as possible so that I can use it for other experiments.
I'm using the Anaconda, Python 2.7, package, which means I have access to various libraries/modules related to science and mathematics.
I am stuck at trying to use For and While loops (for the first time).
The data files are structured like this (I am using regex brackets here):
.../data/B_foo[1-7]/[1-6]/D_foo/E_foo/text.txt
What I want to do is to cycle through all the 7 top directories and each of their 6 subdirectories (named 1,2,3...6). Furthermore, within these 6 subdirectories, a text file can be found (always with the same filename, text.txt), which contain the data I want to access.
The 'text.txt' files is structured something like this:
1 91.146 4.571 0.064 1.393 939.134 14.765
2 88.171 5.760 0.454 0.029 25227.999 137.883
3 88.231 4.919 0.232 0.026 34994.013 247.058
4 ... ... ... ... ... ...
The table continues down. Every other row is empty. I want to extract information from 13 rows starting from the 8th line, and I'm only interested in the 2nd, 3rd and 5th columns. I want to put them into lists 'parameter_a' and 'parameter_b' and 'parameter_c', respectively. I want to do this from each of these 'text.txt' files (of which there is a total of 7*6 = 42), and append them to three large lists (each with a total of 7*6*13 = 546 items when everything is done).
This is my attempt:
First, I made a list, 'list_B_foo', containing the seven different 'B_foo' directories (this part of the script is not shown). Then I made this:
parameter_a = []
parameter_b = []
parameter_c = []
j = 7 # The script starts reading 'text.txt' after the j:th line.
k = 35 # The script stops reading 'text.txt' after the k:th line.
x = 0
while x < 7:
for i in range(1, 7):
path = str(list_B_foo[x]) + '/%s/D_foo/E_foo/text.txt' % i
m = open(path, 'r')
line = m.readlines()
while j < k:
line = line[j]
info = line.split()
print 'info:', info
parameter_a.append(float(info[1]))
parameter_b.append(float(info[2]))
parameter_c.append(float(info[5]))
j = j + 2
x = x + 1
parameter_a_vect = np.array(parameter_a)
parameter_b_vect = np.array(parameter_b)
parameter_c_vect = np.array(parameter_c)
print 'a_vect:', parameter_a_vect
print 'b_vect:', parameter_b_vect
print 'c_vect:', parameter_c_vect
I have tried to fiddle around with indentation without getting it to work (receiving either syntax error or indentation errors). Currently, I get this output:
info: ['1', '90.647', '4.349', '0.252', '0.033', '93067.188', '196.142']
info: ['.']
Traceback (most recent call last):
File "script.py", line 104, in <module>
parameter_a.append(float(info[1]))
IndexError: list index out of range
I don't understand why I get the "list index out of range" message. If anyone knows why this is the case, I would be happy to hear you out.
How do I solve this problem? Is my approach completely wrong?
EDIT: I went for a pure while-loop solution, taking RebelWithoutAPulse and CamJohnson26's suggestions into account. This is how I solved it:
parameter_a=[]
parameter_b=[]
parameter_c=[]
k=35 # The script stops reading 'text.txt' after the k:th line.
x=0
while x < 7:
y=1
while y < 7:
j=7
path1 = str(list_B_foo[x]) + '/%s/pdata/999/dcon2dpeaks.txt' % (y)
m = open(path, 'r')
lines = m.readlines()
while j < k:
line = lines[j]
info = line.split()
parameter_a.append(float(info[1]))
parameter_b.append(float(info[2]))
parameter_c.append(float(info[5]))
j = j+2
y = y+1
x = x+1
Meta: I am not sure If I should give the answer to the person who answered the quickest and who helped me finish my task. Or the person with the answer which I learned most from. I am sure this is a common issue that I can find an answer to by reading the rules or going to Stackexchange Meta. Until I've read up on the recomendations, I will hold off on marking the question as answered by any of you two.
Welcome to stack overflow!
The error is due to name collision that you inadvertenly have created. Note the output before the exception occurs:
info: ['1', '90.647', '4.349', '0.252', '0.033', '93067.188', '196.142']
info: ['.']
Traceback (most recent call last):
...
The line[1] cannot compute - there is no "1"-st element in the list, containing only '.' - in python the lists start with 0 position.
This happens in your nested loop,
while j < k
where you redefine the very line you read previously created:
line = m.readlines()
while j < k:
line = line[j]
info = line.split()
...
So what happens is on first run of the loop, your read the lines of the files into line list, then you take one line from the list, assign it to line again, and continue with the loop. At this point line contains a string.
On the next run reading from line via specified index reads the character from the string on the j-th position and the code malfunctions.
You could fix this with different naming.
P.S. I would suggest using with ... as ... syntax while working with files, it is briefly described here - this is called a context manager and it takes care of opening and closing the files for you.
P.P.S. I would also suggest reading the naming conventions
Looks like you are overwriting the line array with the first line of the file. You call line = m.readlines(), which sets line equal to an array of lines. You then set line = line[j], so now the line variable is no longer an array, it's a string equal to
1 91.146 4.571 0.064 1.393 939.134 14.765
This loop works fine, but the next loop will treat line as an array of chars and take the 4th element, which is just a period, and set it equal to itself. That explains why the info variable only has one element on the second pass through the loop.
To solve this, just use 2 line variables instead of one. Call one lines and the other line.
lines = m.readlines()
while j < k:
line = lines[j]
info = line.split()
May be other errors too but that should get you started.

Fortran Print Line Number While Reading Input File

I am receiving a formatting error from an input file, and I would like to determine where the formatting error is occurring in the input file.
My question is: Is there a way to print the line number of the input file where the error is occurring in my fortran code?
This is the error I get:
fmt: read unexpected character
apparent state: unit 4 named input_file
last format: (6(I3,X,F7.2,X,I2,X))
lately reading sequential formatted external IO
Which means that the code is getting hung up on some line in my input file that doesn't correspond with the above format.
Here is the part of my code where Fortran is reading in the input file:
DO 20 K = 1,NUMB
READ(4,200) (NSTN(J),TT(J),IKPS(J),J=1,6)
DO 30 J = 1,6
L = L+1
ISTO(L,N) = NSTN(J)
SECT(L,N) = TT(J)
KWV(L,N) = IKPS(J)
30 CONTINUE
20 CONTINUE
KOBS(N) = NSTM
10 CONTINUE
100 FORMAT(5(I2,X),F6.2,X,F5.2,X,F7.3,X,F6.3,X,F8.3,X,F6.3,
& X,F6.2,X,F5.2,X,I3,X,F4.1,X,F5.2,X,F7.3)
200 FORMAT(6(I3,X,F7.2,X,I2,X))
RETURN
END
I'd like to add a line in the above piece of code to identify the current line the code is reading, so that when it gets hung up, I'll know which line contains the error. Thank you for your help.
Here's what I tried and it's giving me another error:
c READ(4,200) (NSTN(J),TT(J),IKPS(J),J=1,6)
READ(4,200)line
READ(line,*,iostat=ios) (NSTN(J),TT(J),IKPS(J),J=1,6)
IF(ios>0)THEN
WRITE(*,*)'Error Reading Line',line
STOP
ENDIF
INTEGER ios
CHARACTER*(200)line
With a read statement like
READ(4,200) (NSTN(J),TT(J),IKPS(J),J=1,6)
an error in the input results in (error) termination of the program. One has no control over this termination, and in particular one can't do further processing.
There are two ways to avoid this termination, and both involve using an additional specifier in the read statement. One is iostat= and the other err=. If either of these is present then an error doesn't result in termination.
With iostat (for integer istat):
READ(4,200,iostat=istat) (NSTN(J),TT(J),IKPS(J),J=1,6)
then on an error condition, istat will have a (processor-dependent) positive value. It will be zero when (and only when) there is no error.
With err (for some label, say, 991):
READ(4,200,err=991) (NSTN(J),TT(J),IKPS(J),J=1,6)
Putting all that together, let's imagine an outer loop
DO 100 LINE=1,91959
READ(4,200,IOSTAT=ISTAT) (NSTN(J),TT(J),IKPS(J),J=1,6)
IF (ISTAT.NE.0) THEN
PRINT *, 'It went wrong on line', LINE
STOP
END IF
...
100 CONTINUE
or
DO 100 LINE=1,91959
READ(4,200,ERR=991) (NSTN(J),TT(J),IKPS(J),J=1,6)
...
100 CONTINUE
...
991 PRINT *, 'It went wrong on line', LINE
STOP
[I couldn't bring myself to write that code like it really was 1980.]
Add an explicit loop to read your data like:
DO 20 J = 1,6
write (*,*) 'Reading line = ', J
READ(4,100) NSTN(J),TT(J),IKPS(J)
20 CONTINUE
100 FORMAT(I3,X,F7.2,X,I2,X)
This way, you will know exactly where it stopped thank to the write statement in the reading loop. Note that I added two new labels, 20 to control the new loop and 100 for the new format statement. Adapt accordingly.
==============
DO 20 K = 1,NUMB
WRITE (*,*) 'Reading line = ', K
READ(4,200) (NSTN(J),TT(J),IKPS(J),J=1,6)
DO 30 J = 1,6
L = L+1
ISTO(L,N) = NSTN(J)
SECT(L,N) = TT(J)
KWV(L,N) = IKPS(J)
30 CONTINUE
20 CONTINUE
KOBS(N) = NSTM
200 FORMAT(6(I3,X,F7.2,X,I2,X))
RETURN
END