i have one data file in which data are filled in this manner
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
.
.
.
.
.
91 92 93 94 95 96 97 98 99 100
i want to store this data in a matrix of (10,10)
this is my program
program test
integer j,n,m
character,dimension(10,10) ::text
character*50 line
open(unit=3,file="tmp.txt",status='old')
n=1
read(3,"(a50)"),line
read(line,*,end=1),(text(1,i),i=1,10)
1 read(3,"(a50)",end=3),line
n=n+1
read(line,*,end=1)(text(n,i),i=i,10)
3 close(3)
end program test
but i am not getting correct values.
Assuming you are happy with having the numbers stored as integers, the simplest way is to do it like this:
PROGRAM read_data
integer :: i
integer :: numbers(39,39)
character(10) :: infile = "data.dat"
character(10) :: outfile = "output.dat"
open(1,file=infile)
open(2,file=outfile)
do i=1,39
read(1,*) numbers(i,1:39)
end do
!write output to check
do i=1,39
write(2,'(39I5)') numbers(i,1:39)
end do
close(1)
close(2)
END PROGRAM
I wouldn't recommend using strings to store variables of any kind as Fortran is not very good at string handling. If you at some point need to use your data as strings, write it to a string variable like you would write to a file:
write(my_string,'(I5)') numbers(1,1)
Edit: changed code to read in 39x39 size array instead of 10x10.
I don't think doing the reading into a string first and then trying to parse that is the way to go; just let Fortran to break the space-delimited line up into character strings for you. Also note that you want your character array to be an array of something-length character strings, not just of characters:
program test
character(len=3),dimension(10,10) ::text
character(len=7), parameter :: filename="tmp.txt"
integer :: i,j
integer :: nlines
open(unit=3,file=filename)
do i=1,10
write(3,fmt="(10(i3,1x))"), (10*(i-1)+j, j=1,10)
enddo
close(unit=3)
open(unit=4,file=filename,status='old')
do i=1,10
read(4,*,end=1), (text(i,j),j=1,10)
enddo
1 nlines = i
close(unit=4)
print *,' Read in character array: '
do i=1,nlines-1
print "(10('<',a,'>',1x))", (trim(text(i,j)), j=1,10)
enddo
end program test
Running this gives
$ ./test
Read in character array:
<1> <2> <3> <4> <5> <6> <7> <8> <9> <10>
<11> <12> <13> <14> <15> <16> <17> <18> <19> <20>
<21> <22> <23> <24> <25> <26> <27> <28> <29> <30>
<31> <32> <33> <34> <35> <36> <37> <38> <39> <40>
<41> <42> <43> <44> <45> <46> <47> <48> <49> <50>
<51> <52> <53> <54> <55> <56> <57> <58> <59> <60>
<61> <62> <63> <64> <65> <66> <67> <68> <69> <70>
<71> <72> <73> <74> <75> <76> <77> <78> <79> <80>
<81> <82> <83> <84> <85> <86> <87> <88> <89> <90>
<91> <92> <93> <94> <95> <96> <97> <98> <99> <100>
Related
I have a problem how to print only specific three numbers, which are in a file with no format. I have no idea how to read it and print because if I use read from higher i, it does not start reading e.g. for i = 4, the line 4. I need only numbers 88.98, 65.50, and 30.
text
678 people
450 girls
22 old people
0 cats
0 dogs
4 girls blond
1 boy blond
1 old man
0 88.9814 xo xi
0 65.508 yo yi
0 30 zo zi
I tried this, but this is not working at all.
program souradnice
implicit none
integer :: i, k
character*100 :: yo, zo, line, name, text
real :: xo
open(10,file="text.dat", status='old')
do i=20,20
read(10,fmt='(a)') line
read(unit=line, fmt='(a100)') text
if(name=="xo") then
print *, trim(text)
endif
enddo
close(10)
end program souradnice
You need to read the whole file line by line, and check each line to see if it's the one you want, e.g. by using the index intrinsic. For example,
program souradnice
implicit none
character(100) :: line
character(5) :: matches(3)
real :: numbers(3)
character(10) :: dummy
integer :: i, ierr
! Substrings to match to find the relevant lines
matches = ["xo xi", "yo yi", "zo zi"]
open(10,file="text.dat", status='old')
do
! Read a line from the file, and exit the loop if the file end is reached.
read(10,fmt='(a)',iostat=ierr) line
if (ierr<0) then
exit
endif
do i=1,3
! Check if `line` matches any of the i'th line we want.
if (index(line, matches(i))>0) then
! If it matches, read the relevant number into `numbers`.
read(line,*) dummy, numbers(i)
endif
enddo
enddo
write(*,*) numbers
end program
I am using Fortran 90 to read a file that contains data in the following format
number# 125 var1= 2 var2= 1 var3: 4
.
.
.
.
number# 234 var1= 3 var2= 5 var3: 1
I tried the following command and works fine
read (2,*) tempstr , my_param(1), tempstr , my_param(2), tempstr , my_param(3)
Problem is when the numbers become larger and there is no space between string and number, i.e. the data looks as following:
number# 125 var1= 2 var2=124 var3: 4
I tried
read (2,512) my_param(1), my_param(2), my_param(3)
512 format('number#', i, 'var1=', i, 'var2=', i, 'var3:', i)
It reads all number as zero
I can't switch to some other language. The data set is huge, so I can't pre-process it. Also, the delimiters are not the same every time.
Can someone please help with the problem?
Thanks in advance
First up, 720 thousand lines is not too much for pre-processing. Tools like sed and awk work mostly on a line-by-line basis, so they scale really well.
What I have actually done was to convert the data in such a way that I could use namelists:
$ cat preprocess.sed
# Add commas between values
# Space followed by letter -> insert comma
s/ \([[:alpha:]]\)/ , \1/g
# "number" is a key word in Fortran, so replace it with num
s/number/num/g
# Replace all possible data delimitors with the equals character
s/[#:]/=/g
# add the '&mydata' namelist descriptor to the beginning
s/^/\&mydata /1
# add the namelist closing "/" character to the end of the line:
s,$,/,1
$ sed -f preprocess.sed < data.dat > data.nml
Check that the data was correctly preprocessed:
$ tail -3 data.dat
number#1997 var1=114 var2=130 var3:127
number#1998 var1=164 var2=192 var3: 86
number#1999 var1=101 var2= 48 var3:120
$ tail -3 data.nml
&mydata num=1997 , var1=114 , var2=130 , var3=127/
&mydata num=1998 , var1=164 , var2=192 , var3= 86/
&mydata num=1999 , var1=101 , var2= 48 , var3=120/
Then you can read it with this fortran program:
program read_mixed
implicit none
integer :: num, var1, var2, var3
integer :: io_stat
namelist /mydata/ num, var1, var2, var3
open(unit=100, file='data.nml', status='old', action='read')
do
read(100, nml=mydata, iostat=io_stat)
if (io_stat /= 0) exit
print *, num, var1, var2, var3
end do
close(100)
end program read_mixed
While I still stand with my original answer, particularly because the input data is already so close to what a namelist file would look like, let's assume that you really can't make any preprocessing of the data beforehand.
The next best thing is to read in the whole line into a character(len=<enough>) variable, then extract the values out of that with String Manipulation. Something like this:
program mixed2
implicit none
integer :: num, val1, val2, val3
character(len=50) :: line
integer :: io_stat
open(unit=100, file='data.dat', action='READ', status='OLD')
do
read(100, '(A)', iostat=io_stat) line
if (io_stat /= 0) exit
call get_values(line, num, val1, val2, val3)
print *, num, val1, val2, val3
end do
close(100)
contains
subroutine get_values(line, n, v1, v2, v3)
implicit none
character(len=*), intent(in) :: line
integer, intent(out) :: n, v1, v2, v3
integer :: idx
! Search for "number#"
idx = index(line, 'number#') + len('number#')
! Get the integer after that word
read(line(idx:idx+3), '(I4)') n
idx = index(line, 'var1') + len('var1=')
read(line(idx:idx+3), '(I4)') v1
idx = index(line, 'var2') + len('var3=')
read(line(idx:idx+3), '(I4)') v2
idx = index(line, 'var3') + len('var3:')
read(line(idx:idx+3), '(I4)') v3
end subroutine get_values
end program mixed2
Please note that I have not included any error/sanity checking. I'll leave that up to you.
My program works, but it does not show all P(I) values.
When its work it show only P(1) value. and stop it. But i want to know all values. P(1) to P(121).
Where is the problem? Are there any problem about loops?
PROGRAM odev
dimension P(121)
c div(ro.v.fi)=div(r.gradfi)+a-bfi
c P(1)=P(2)=P(3)=P(4)=P(5)=P(6)=P(7)=P(8)=P(9)=P(10)=P(11)=100
c P(12)=P(23)=P(34)=P(45)=P(56)=P(67)=P(78)=P(89)=P(100)=P(111)=100
c P(22)=P(33)=P(44)=P(55)=P(66)=P(77)=P(88)=P(99)=P(110)=P(121)=0
c P(112)=P(113)=P(114)=P(115)=P(116)=P(117)=P(118)=P(119)=P(120)=0
50 PRINT *, "Hangi yontemle cozum yapmak istiyorsunuz?"
PRINT *, "Merkezi farklar icin 1"
PRINT *, "Upwind icin 2"
PRINT *, "Hybrid icin 3"
PRINT *, "Powerlaw icin 4 giriniz"
READ *, DE
PRINT *, "iterasyon saysn giriniz"
read*, iter
IF (DE.eq.1) THEN
GO TO 10
ELSE IF (DE.eq.2) THEN
GO TO 20
ELSE IF (DE.eq.3) THEN
GO TO 30
ELSE IF (DE.eq.4) THEN
GO TO 40
ELSE
PRINT *, "Lutfen 1-4 aral§nda giriŸ yapnz"
GO TO 50
END IF
5 do I=1,11
P(I)=100
end do
6 do I=12,111,11
P(I)= 100
end do
7 do I=22,121,11
P(I)=0
end do
8 do I=112,120
P(I)=0
end do
10 PRINT *, "Merkezi farklar metodu"
c tanimlanan formule gore 10*10 hucreli grid
c sistem icin hesap yapar
do 3 n=1, iter
DO 4 I=13, 109
P(I)=(0.5*P(I+1)+1.5*P(I-1)-P(I-11)+3*P(I+11)+10)/6
4 continue
3 continue
GO TO 60
20 PRINT *, "Upwind metodu "
do n=1, iter
DO I=13, 109
P(I)=(P(I+1)+2*P(I-1)+P(I-11)+5*P(I+11)+10)/11
END DO
end do
GO TO 60
30 PRINT *, "Hybrid metodu "
do n=1, iter
DO I=13, 109
P(I)=(0.5*P(I+1)+1.5*P(I-1)+4*P(I+11)+10)/8
END DO
end do
GO TO 60
40 PRINT *, "Powerlaw metodu "
do n=1, iter
DO I=13, 109
P(I)=(0.591*P(I+1)+1.591*P(I-1)+0.078*P(I-11)+4.078*P(I+11)+10)/8.338
END DO
end do
GO TO 60
60 PRINT *, "Tesekkurler"
do 11 I=1,121
print *, I, P(I)
pause
11 continue
END
Edit;
From #High Performance Mark advices
60 PRINT *, "Tesekkurler"
do 11 I=1,121
print *, I, P(I)
c pause
11 continue
It's work now. But P(13) to P(109) values shown >Nan
P(1) to P(12) nearly 1e-40 (Must be 100)
P(110) to P(121) nearly 1e-38
I think there is another problem...
Edit 2;
From #francescalus advices
c P(112)=P(113)=P(114)=P(115)=P(116)=P(117)=P(118)=P(119)=P(120)=0
5 do I=1,11
P(I)=100
end do
6 do I=12,111,11
P(I)= 100
end do
7 do I=22,121,11
P(I)=0
end do
8 do I=112,120
P(I)=0
end do
50 PRINT *, "Hangi yontemle cozum yapmak istiyorsunuz?"
From #agentp advices
SELECT CASE (N)
CASE (1)
PRINT *, "Merkezi farklar metodu"
do 3 n=1, iter
DO 4 I=13, 109
P(I)=(0.5*P(I+1)+1.5*P(I-1)-P(I-11)+3*P(I+11)+10)/6
4 continue
3 continue
GO TO 60
CASE (2)
PRINT *, "Upwind metodu "
do n=1, iter
DO I=13, 109
P(I)=(P(I+1)+2*P(I-1)+P(I-11)+5*P(I+11)+10)/11
END DO
end do
GO TO 60
CASE (3)
PRINT *, "Hybrid metodu "
do n=1, iter
DO I=13, 109
P(I)=(0.5*P(I+1)+1.5*P(I-1)+4*P(I+11)+10)/8
END DO
end do
GO TO 60
CASE (4)
PRINT *, "Powerlaw metodu "
do n=1, iter
DO I=13, 109
Z=8.338
P(I)=(0.591*P(I+1)+1.591*P(I-1)+0.078*P(I-11)+4.078*P(I+11)+10)/Z
END DO
end do
GO TO 60
END SELECT
Finally works now...
These lines
print *, I, P(I)
pause
tell the program to print the first element of P and then to pause. On many computers any user input at that time, such as pressing a key, will cause the program to continue. In your code that would result in the next element of P being written to the terminal, and the program pausing again.
Try taking the line pause out and see what happens. Or sit there like a monkey and press a key 120 times.
Then throw the program away and rewrite it in modern Fortran; it causes me pain to look at FORTRAN77 .
I am new to Fortran but I am trying to adapt a Fortran code and I am having trouble doing something which I think is probably quite simple.
I want to adapt a Fortran file called original.f so that it makes an input file called input.inp and populates it with 4 integers calculated earlier in original.f so that input.inp looks like, for example:
&input
A = 1
B = 2
C = 3
D = 4
&end
I know how to write this format:
OPEN(UNIT=10,FILE='input.inp')
WRITE (10,00001) 1,2,3,4
...
...
...
00001 Format (/2x,'&input',
& /2x,'A = ',i4,
& /2x,'B = ',i4,
& /2x,'C = ',i4,
& /2x,'D = ',i4,
& /2x,'&end')
(or something like this that I can fiddle with when I get it working) but I am not sure how to create the input.inp file write this into it and then use this input file.
The input file needs to be used to run an executable called "exec". I would run this in bash as:
./exec < input.inp > output.out
Where output.out contains two arrays called eg(11) and ai(11,6,2) (with dimensions given) like:
eg(1)= 1
eg(2)= 2
...
...
...
eg(11)= 11
ai(1,1,1)= 111
ai(1,2,1)= 121
...
...
...
ai(11,6,2)=1162
Finally I need to read these inputs back into original.f so that they can be used further down in file. I have defined these arrays at the beginning of original.f as:
COMMON /DATA / eg(11),ai(11,6,2)
But I am not sure of the Fortran to read data line by linw from output.out to populate these arrays.
Any help for any of the stages in this process would be hugely appreciated.
Thank you very much
James
Since you have shown how you create the input file, I assume the question is how to read it. The code shows how "a" and "b" can be read from successive lines after skipping the first line. On Windows, if the resulting executable is a.exe, the commands a.exe < data.txt or type data.txt | a.exe will read from data.txt.
program xread
implicit none
character (len=10) :: words(3)
integer, parameter :: iu = 5 ! assuming unit 5 is standard input
integer :: a,b
read (iu,*) ! skip line with &input
read (iu,*) words ! read "a", "=", and "1" into 3 strings
read (words(3),*) a ! read integer from 3rd string
read (iu,*) words ! read "b", "=", and "1" into 3 strings
read (words(3),*) b ! read integer from 3rd string
print*,"a =",a," b =",b
end program xread
If I understand the expanded question correctly, you have to work with an output file, produced by some other code you did not write, with lines like eg(1) = ....
For the simplest case where you know the number of elements and their ordering beforehand, you can simply search each line for the equals sign from behind:
program readme
implicit none
character(100) :: buffer
integer :: i, j, k, pos, eg(11), ai(11,6,2)
do i = 1,11
read*, buffer
pos = index(buffer, '=', back = .true.)
read(buffer(pos+1:), *) eg(i)
enddo
! I have assumed an arbitrary ordering here
do k = 1,2
do i = 1,11
do j = 1,6
read*, buffer
pos = index(buffer, '=', back = .true.)
read(buffer(pos+1:), *) ai(i,j,k)
enddo
enddo
enddo
end program
Assuming here for simplicity that the data are provided to standard input.
I need to write a formated output to a string DTSTR. It use to work under layhe fortran but not gfortran
INTEGER*2 MON,DAY,YEAR,HR,MINUTE,SEC,HUND
CHARACTER DY*2
CHARACTER DTSTR*24
COMMON /RD/ DTSTR
...
...
WRITE(DTSTR,10)MON,DAY,YEAR,HR,MINUTE,DY,' ]'
10 FORMAT('[ ',I2,'-',I2.2,'-',I4,2X,I2,':',I2.2,1X,2A2)
it empty just a empty line. If i use following it correctly output. But i want to store this string. Is it possible to do that with gnu fortran.
WRITE(*,10)MON,DAY,YEAR,HR,MINUTE,DY,' ]'
update
I am trying to compile following file. I think the problem might be with the COMMON.
PROGRAM HELO
CALL DOTIME
WRITE(*,5700)DTSTR
5700 FORMAT(24X,A24/)
END
SUBROUTINE DOTIME
C
IMPLICIT NONE
INTEGER*2 MON,DAY,YEAR,HR,MINUTE,SEC,HUND
CHARACTER DY*2
CHARACTER DTSTR*24
COMMON /RD/ DTSTR
integer values(8)
call date_and_time(VALUES=values)
YEAR = values(1)
MON = values(2)
DAY = values(3)
HR = values(5)
MINUTE = values(6)
SEC = values(7)
HUND = values(8)
C =================================================
C
C Incompitable function => CALL GETDAT(YEAR,MON,DAY)
C Incompitable function => GETTIM(HR,MINUTE,SEC,HUND)
IF(HR .GE. 12)THEN
IF(HR .NE. 12)HR=HR-12
DY='PM'
ELSE
DY='AM'
ENDIF
WRITE(DTSTR,10)MON,DAY,YEAR,HR,MINUTE,DY,' ]'
10 FORMAT('[ ',I2,'-',I2.2,'-',I4,2X,I2,':',I2.2,1X,2A2)
RETURN
END
Hmm? It works just fine for me:
program testwrite
implicit none
INTEGER :: MON,DAY,YEAR,HR,MINUTE,SEC,HUND
CHARACTER(LEN=2) :: DY
CHARACTER(LEN=24) :: DTSTR
MON = 4
DAY = 27
YEAR= 2010
HR = 13
MINUTE = 27
SEC = 0
HUND = 0
DY ='WE'
WRITE(DTSTR,10)MON,DAY,YEAR,HR,MINUTE,DY,' ]'
10 FORMAT('[ ',I2,'-',I2.2,'-',I4,2X,I2,':',I2.2,1X,2A2)
print *,'<',trim(DTSTR),'>'
end program testwrite
gives
<[ 4-27-2010 13:27 WE ]>
just as one would expect. Works with several versions of gfortran I have kicking around.
Update: Yes, the problem is in your common block. The common block isn't declared in the main program. But really, it's much simpler and much, much better practice just to pass the string as an argument:
PROGRAM HELO
IMPLICIT NONE
CHARACTER(LEN=24) :: DTSTR
CALL DOTIME(DTSTR)
WRITE(*,5700)DTSTR
5700 FORMAT(24X,A24/)
END
SUBROUTINE DOTIME(DTSTR)
C
IMPLICIT NONE
INTEGER*2 MON,DAY,YEAR,HR,MINUTE,SEC,HUND
CHARACTER DY*2
CHARACTER(LEN=24), INTENT(OUT) :: DTSTR