I'm using this code below to generate a file with i number (i=200 for instance) of rows, but the first and the second rows are fixed and I just want to create another i rows using a random extraction in a sphere of unitary radius in Fortran. Each row should start with m1 and then 6 random numbers between a range [0,1].
program InputGen
implicit none
integer :: i,n,j
character(len=500) :: firstLine, secondLine
real *8 :: m1
real:: r(10)
m1=1.d0
firstLine='3 5 1.d-4 1.d5 0.e-3 0.0 1. 0.1 0.e0 1'
secondLine='4.d6 0. 0. 0. 0. 0. 0. '
call random_seed()
call random_number(r)
open(unit=100, file='INPUT.TXT',Action='write', Status='replace')
write(100,'(A)') trim(firstLine)
write(100,'(A)') trim(secondLine)
do i=1,200
write(100,'(A)') '',m1,' ',(r(n),n=1,10),
' ',(r(n),n=1,10),'0.0',&
' ',(r(n),n=1,10),&
' ',(r(n),n=1,10),'0.0'
end do
write(*,*) 'Input file generated.'
write(*,*) 'Press Enter to exit...'
read(*,*)
end program InputGen
The first and second lines create perfectly, but the other rows in the loop not.
You did not tell us what is wrong (how the problem exhibits), but I suspect the format is incorrect. You are just specifying (A), but you have a mixed output list with strings and numbers.
You can just use a simple general format like (*(g0)) that will apply the generic g0 format to all items in the input list. You will want to add some manual spaces (although you already have some) in the input list to avoid joining two unrelated output items on the line.
Or you can just follow the input list and add a specific format for each item, like (a,1x,f12.6,a,10(f12.6,1x),a ... and so on. Adjust as needed, especially the spaces (either keep them as ' ' with the a descriptor, or use the 1x descriptor.
You are also currently writing the same r all the time. You should generate more numbers and re-generate them an each loop iteration
real:: r(40)
do i=1,200
call random_number(r)
write(100,'(*(g0))') '',m1,' ',r(1:10),
' ',r(11:20),'0.0',&
' ',r(21:30),&
' ',r(31:40),'0.0'
end do
This does not do anything with points in a sphere or anything similar, this just prints random numbers. I hope that is clear.
Related
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
Suppose I have the matrix c(i,j). I want to write it on the screen on oldest Fortran77 language with three signs after comma. I write
do i=1,N
write(*,"(F8.3)") ( c(i,j), j=1,N )
end do
but the output is in the form
c(1,1)
c(1,2)
...
c(1,10) c(2,1)
c(2,2)
...
Finally, I may simply write
do i=1,N
write(*,*) ( c(i,j), j=1,N )
end do
and then the output is like the matrix, but, of course, it is not formatted.
How to get the correct output in Fortran77?
An edit. It seems that one of solutions is to write
do i=1, N
do j=1, N
write(*,'(F9.3,A,$)') c(i,j), ' '
end do
write(*,*) ' '
end do
Your format only specifies a single float but you actually want to write N per line.
A fairly general solution for this simple case would be something like
program temp
implicit none
integer, parameter :: N=3
real, dimension(N,N) :: c
integer :: i,j
character(len=20) :: exFmt
c = 1.0
write(exFmt,'("(",I0,"(F8.3))")') N
do i=1,N
write(*,exFmt) (c(i,j), j=1,N)
end do
end program
This will make exFmt be '(3(F8.3))', which specifies printing three floats (note you probably really want '(3(F8.3," "))' to explicitly include some spacing).
Note some compilers will allow for exFmt to be just '(*(F8.3))'. This is part of the fortran 2008 specification so may not be provided by all compilers you have access to. See here for a summary of compiler support (see Unlimited format item, thanks to HighPerformanceMark for this)
Finally an easy bodge is to use a format statment like '(1000(F8.3))' where 1000 is larger than you will ever need.
I am trying to change the stiffness of a fastener depending on a pressure on it. I am approaching this problem by using field variables and extracting the forces in a fastener from .fil file.
The problem is that I need to relate the node number provided by UFIELD to element number of the fastener in .fil file. I know that the .fil file contains that information in record no. 1900 but when I set if statement for that record, it is never hit in my subroutine. Although, when I convert my .fil file to ASCII I can see that information there.
The records No. 1 and No. 495 are hit properly and I can obtain the element number and internal forces in it.
Moreover, I have tried using GETPARTINFO both on the node I have and on the element. But it returns number not related to the node of my fastener or the element itself.
Additionally, I could not obtain fastener CTF from the node itself or the material point as the fasteners do not have material points.
If I assume that the nodes and the fastener are in the same order and just match them, my code works nicely on just few element in a tiny model. But in a large model with lots of fasteners, everything gets mixed up.
Any Ideas how to solve this or maybe some remarks on why I cant access key 1900 from my subroutine or why GETPARTINFO does not return what is to be expected?
Ok, I figured this out. The key 1900 in .fil file is printed before the default reading position of command
call DBFILE(0,ARRAY,JRCD)
In order to obtain the required key the file read position must be reset
call DBFILE(2,ARRAY,JRCD)
But the problem is that keys 1900, 1901, 1933 etc. are generated for every element in the model regardless of your specified elset. Thus I wrote a little subroutine to generate an array of fasteners with their element number and corresponding node number.
subroutine obtain_relation(REL)
INCLUDE 'ABA_PARAM.INC'
DIMENSION ARRAY(513),JRRAY(NPRECD,513),REL(500,3)
character*8 CVALUE
EQUIVALENCE (ARRAY(1),JRRAY(1,1)), (ARRAY(4),CVALUE)
!Rewinding the file
CALL DBFILE(2,ARRAY,JRCD)
i = 1
DO K1=1,999999
!Start reading output file
CALL DBFILE(0,ARRAY,JRCD)
!If the end of the end of pre-step records go to 120
IF (KEY .EQ. 2000) GO TO 120
!If the end of all records is reached go to position 120
IF (JRCD .NE. 0) GO TO 120
!The key of the output table is at second possition (first is length of
!the array)
KEY=JRRAY(1,2)
! Record 1900 contains information about element conectivity
IF (KEY .EQ. 1900) THEN
IF(trim(CVALUE).eq."CONN3D2") then
Rel(i,1) = JRRAY (1,3) ! <- Element number
Rel(i,2) = JRRAY (1,5) ! <- First node number
i = i + 1
END IF
END IF
ENDDO
120 Continue
Return
end
Call this subroutine only once at the start of the analysis after calling POSFIL inside URDFIL and it will return a double precision 3 dimensional matrix with first column containing fastener element number, second column - first node of corresponding fastener and the last one empty. I used the last column to store the corresponding forces.
Hope this was helpful for somebody.
I have some issues about opening and reading multiple files. I have to write a code which reads two columns in n files formatted in the same way (they are different only for the values...). Before this, I open another input file and an output file in which I will write my results. I read other questions in this forum (such as this one) and tried to do the same thing, but I receive these errors:
read(fileinp,'(I5)') i-49
1
devstan.f90:20.24:
fileLoop : do i = 50,52
2
Error: Variable 'i' at (1) cannot be redefined inside loop beginning at (2)
and
read(fileinp,'(I5)') i-49
1
Error: Invalid character in name at (1)
My files are numbered from 1 to n and are named 'lin*27-n.dat' (where n is the index starts from 1) and the code is:
program deviation
implicit none
character(len=15) :: filein,fileout,fileinp
integer :: row,i,h
real :: usv,usf,tsv,tsf,diff
write(*,'(2x,''Input file .......''/)')
read(*,'(a12)') filein
write(*,'(2x,''Output file........''/)')
read(*,'(a12)') fileout
open(unit = 30,File=filein)
open(unit = 20,File=fileout)
fileLoop : do i = 50,52
fileinp = 'lin*27-'
read(fileinp,'(I5)') i-49
open(unit = i,File=fileinp)
do row = 1,24
read(30,*) h,usv,tsv
read(i,*) h,usf,tsf
diff = usf - usv
write(20,*) diff
enddo
close(i)
enddo fileLoop
end program deviation
How can I solve it? I am not pro in Fortran, so please don't use difficult language, thanks.
The troublesome line is
read(fileinp,'(I5)') i-49
You surely mean to do a write (as in the example linked): this read statement attempts to read from the variable fileinp rather than writing to it.
That said, simply replacing with write is probably not what you need either. This will ignore the previous line
fileinp = 'lin*27-'
merely setting to, in turn, "1", "2", "3" (with leading blanks). Something like (assuming you intend that * to be there)
write(fileinp, '("lin*27-",I1)') i-49
Note also the use of I1 in the format, rather than I5: one may want to avoid blanks in the filename. [This is suitable when there is exactly one digit; look up Iw.m and I0 when generalizing.]
I am using FORTRAN to read in data from an ASCII text file. The file contains multiple data values per line but the number of values per line is not constant.
101.5 201.6 21.4 2145.5
45.6 21.2
478.5
...
Normally after a read statement, Fortran would go to the next line. What I want to be able to do is read one data value at a time. If it hits the end of the line, it should just continue reading on the next line. Is this possible?
As pointed out by IRO-bot in their comment to your question, the answer has already been given by M.S.B. Below I have merely provided some code illustrating that answer (as M.S.B.'s post contained none):
program test
character(len=40) :: line
integer :: success, i, indx, prev, beginning
real :: value
open(1,file='test.txt')
do
read(1,'(A)',iostat=success) line
if (success.ne.0) exit
prev = 1
beginning = 1
do i=1,len(line)
! is the current character one out of the desired set? (if you
! have got negative numbers as well, don't forget to add a '-')
indx = index('0123456789.', line(i:i))
! store value when you have reached a blank (or any other
! non-real number character)
if (indx.eq.0 .and. prev.gt.0) then
read(line(beginning:i-1), *) value
print *, value
else if (indx.gt.0 .and. prev.eq.0) then
beginning = i
end if
prev = indx
end do
end do
close(1)
end program test
When running this program using the sample lines you provided the output is
101.5000
201.6000
21.40000
2145.500
45.60000
21.20000
478.5000
I hope you will find this helpful.