I want to read in multiple files in Fortran in a loop by using the filename formatting system. Problem is the filenames have numbers that don't follow each other directly. Examples of the filenames are 4e3_2048_380_40_3e9.ksz_cl.txt, 4e3_2048_200_80_2e8.ksz_cl.txt. The 3rd, 4th and 5th numbers in the filenames form a 3x3 grid. The first number goes from 140-260, the second goes from 40-80 and the third number goes from 2e8-2e9.
I've searched for answers in threads like reading multiple files in fortran but it doesn't seem to answer my question. My code below currently print out 4e3_2048_01.ksz_cl.txt.
program readfiles
implicit none
integer :: i, N
Logical, Save :: first_time = .True.
CHARACTER(len=25) :: FN
N=3 !--arbitrary number of files
if(first_time) then
DO I=1,N
WRITE(FN,10)I
WRITE(6,*)FN
OPEN(1,FILE=FN, status='replace')
CLOSE(1)
END DO
10 FORMAT('4e3_2048_',I2.2,'.ksz_cl.txt')
endif
end program readfiles
Related
I'm trying to write a string filename in fortran using:
WRITE(FILENAME,'(A27,I3.3,A1,I3.3,A3)') NAME,MYPR,'_',IBL,'.nc'
where NAME is a string of variable lengths, and MYPR and IBL are integers.
I'm searching for a solution where I can dynamically write the format:
'(A27,I3.3,A1,I3.3,A3)',
where A27 will change depending on the length of NAME. I've tried 'A' alone but this caused an error. I'm not sure of what is possible here as many texts do not even cover something similar issues.
Would appreciate some ideas.
The obvious solution would be to use the format string '(A,I3.3,A1,I3.3,A3)', i.e. using just A for the name and letting the compiler choose the correct length. This is working perfectly for me.
As #agentp suggested, you might see issues due to whitespaces in the string. This might be resolved by using trim(name) to get rid of trailing whitespace, or even trim(adjustl(name)) which removes both leading and trailing whitespace. This solution is given below in subroutine print1().
The other option would be to generate the format string dynamically - after all, that is just a string as well. This is quite cumbersome, and an overkill in your situation - see print2().
module test_mod
implicit none
contains
subroutine print1(NAME,MYPR,IBL)
character(len=*),intent(in) :: NAME
integer,intent(in) :: MYPR,IBL
WRITE(*,'(A,I3.3,A1,I3.3,A3)') trim(adjustl(NAME)),MYPR,'_',IBL,'.nc'
end subroutine
subroutine print2(NAME,MYPR,IBL)
character(len=*),intent(in) :: NAME
integer,intent(in) :: MYPR,IBL
character(len=128) :: fmt
write(fmt,*) len_trim(adjustl(NAME))
fmt = '(A'//trim(adjustl(fmt))//',I3.3,A1,I3.3,A3)'
WRITE(*,fmt) trim(adjustl(NAME)),MYPR,'_',IBL,'.nc'
end subroutine
end module
program test
use test_mod
call print1(' Testfile ', 1, 2)
call print2(' Testfile ', 1, 2)
end program
Output:
./a.out
Testfile001_002.nc
Testfile001_002.nc
I need a help about implicit do loop in Fortran.
This is my simple code:
Program Simple
Implicit none
Integer::i,j
Integer,parameter::N=2,M=3
Real,dimension(N,M)::Pot
Open(1,File='First.txt',Status='old')
Read(1,'(M(f3.1,1x))') ((Pot(i,j),j=1,M),i=1,N)
Close(1)
Open(2,File='Second.txt',Status='Unknown')
Write(2,'(M(i0,1x,i0,1x,f3.1,1x))') ((i,j,Pot(i,j),j=1,M),i=1,N)
Close(2)
Stop
End program Simple
This is the file First.txt:
1.1 1.2 1.3
2.1 2.2 2.3
When I try to execute this program I got a this message:
Unexpected element 'N' in format string
Unexpected element 'M' in format string
I want to keep the name of integer variables N and M in write statement.
Is there any way to also keep their values from declaration part?
You are using M and N in the string (as characters), not as variables. In order to use the variables you need to write their values into the format string:
character(len=128) :: fmtString
!...
write(fmtString,*) M
fmtString = '('//trim(adjustl(fmtString))//'(f3.1,1x))'
Read(1,fmtString) ((Pot(i,j),j=1,M),i=1,N)
And similarly for the write statement.
However, you can probably use list-directed input (Read(1,*)) for the input, and let Fortran figure out the exact format.
Instead of this string manipulation you can use (*(f3.1,1x)) in modern compilers, or if you have an old one just specify a very large number, e.g. (99999(f3.1,1x)). In both cases, the correct number of values will be printed. However, this will result into writing all m*n values in one single line [thanks #agentp for pointing this out].
The following data is given in a file:
1 7 5 4 11 0 1 -13 -7
I want to form a 3x3 matrix from these columns. I have tried advance=no but receive a runtime error.
program form_matrix
implicit none
integer:: col,A(9)
open(unit=12,file='q10.txt')
do col=1,9
read(12,*,advance='no')(A(col))
end do
7 format(3i4)
write(*,7)(A(col),col=1,9)
close(12)
end program
Well, a couple of things:
To read into a variable, you need to specify that variable and not a statement containing the variable. A(col) instead of (A(col)).
Then, you are not allowed to use the list directed format (*) with an advance specifier, you need a format (which would be difficult in your case, because of the different widths of the columns).
It will probably be easier to read the whole line into the array in one go, without the loop and using the list directed format:
program form_matrix
implicit none
integer:: col,A(9)
open(unit=12,file='q10.txt')
read(12,*) A
7 format(3i4)
write(*,7)(A(col),col=1,9)
close(12)
end program
* enables list-directed formatting, where individual values are separated by commas or blanks. The type is determined by the RHS of the statement. So you read in a list of nine (because A is nine elements long) integers (because A is integer). For more details on this I suggest the Fortran 2008 Standard, Cl. 10.10 "List-directed formatting"
I am trying to read a list of real numbers from an external file into an array. I do not know how many records fields, separated by spaces, there are per record in a file, and I was therefore planning to use non-advancing I/O to first count the number of records fields, then allocate a real array of sufficient size, and to finally read the file into that same array.
Here is an example input file (where the edit descriptor should be f3.1 for every record field, i.e. a float 3 characters wide with one decimal, and counting the dot; although if I read Metcalf et al. correctly, the decimal is ignored):
1.0 2.0 3.0 4.0 5.0
And a MWE of my program looks like this
program testread
use iso_fortran_env
implicit none
character(len=255) :: filename
filename = 'read.dat'
print *, count_entries(filename)
contains
integer function count_entries(coefficient_file) result(n)
character(len=*), intent(in) :: coefficient_file
!real, dimension(:), allocatable :: coefficients
integer :: fileunit, stat
real :: temp
n=0
open(newunit=fileunit, file=coefficient_file, iostat=stat)
do
read(fileunit,'(f3.1)',advance='no',iostat=stat) temp
if (stat == iostat_end) then
exit
else
n = n + 1
end if
print *, stat, temp
end do
close(fileunit)
! What should happen in the future...
!allocate(coefficients(n))
!read(fileunit,*,iostat=stat) coefficients
end function count_entries
end program testread
If you save the sample input above as read.dat, compile the program with gfortran -o testread{,.f90} and execute it, you will get the following result:
0 1.00000000
0 2.00000000
0 0.300000012
0 0.00000000
0 4.00000000
0 5.00000000
-2 0.00000000
7
In other words, instead of counting 5 entries, it counts 7. And this is not surprising as it, for some reason, sees 7 numbers. But I wonder: why does it see 7 numbers? How can I extend my function to a) be able to also read larger reals and b) read reals of non-uniform width? For example, I would like to be able to read 1.01 1.003 2.1, etc.
It sees six numbers (the last one is an end of record condition) because your format specification specifies that three characters be read each time, but your data is spaced every four columns (three for the data, one for the separating blank).
If your input isn't fixed format (number of columns may vary), then read the whole record (line) into a character(:), allocatable variable and then manually chop that string up.
(Never use a format specification with a specified number of decimal places for input unless you know that your input will always suit that.)
You forgot to account for the spaces. Just use '(f3.1,1x)'.
I'm fairly new to Fortran and I am having trouble with my file names, I have a bunch of data in simuln#.res (where 1<#<20), I have multiple different directories with all the same simuln#.res names but they had different input parameters. The code looks like this:
character(len=11) :: theFileA
character(len=12) :: theFileB
character(len=:), allocatable :: fileplace
write(*,*) "the directory with the data sets, use quotations"
read(*,*) fileplace
fileLoop : do j=1,20
if (j .lt. 10) then
write(theFileA, '("simuln", I1,".res")' ) j
open(newunit= iin,file = fileplace//theFileA,status='old')
else
write(theFileB, '("simuln",I2,".res")') j
open(newunit= iin,file = fileplace//theFileB,status='old')
end if
does some stuff with the file
end do fileLoop
The code compiles with a gfortran compiler on my mac, but when I put in my path to the directory with the files, it gives the error simuln1.res does not exist (which it absolutely does, triple checked). I have tried changing the edit descriptor (and making real(j)), but I still get the same thing.
Can anyone help me?
You have fileplace of deferred length ((len=:)), but you appear to not allocate it before attempting the read.
That is, read(*,*) fileplace doesn't, under the F2003 rules of automatic allocation, allocate fileplace to the correct length and assign. That means that later on fileplace could well be being treated as a zero-length character variable ('') in the file to be opened.
To check this hypothesis, try print *, fileplace//theFileA. This could be supported by the fact that the error message refers to just the trailing part of the file's name.
If this is the case, then use a "large" variable. You say 90 characters is as long as you need, so:
character(len=90) :: fileplace ! Adjust length as desired
...
read(*,*) fileplace
...
open (newunit=iin, file=TRIM(fileplace)//theFileA, status='old')
...
Ensure you append the file's name to the trimmed directory name to avoid having spaces between the two parts.
[As a side note, you appear to not need theFileA and theFileB; just use the latter, considering that trailing blanks are ignored. And you may well want to force a trailing '/' on fileplace.]