Fortran 77 codes works but does not show all values - fortran

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 .

Related

How can I make my program go back to a "main menu" after a subroutine?

I am making a physics calculator in Fortran and I have run into a problem. Recently I had some assistance with my code that makes it possible to do, say, a speed calculation, and then go back to the menu to do a time calculation. However, I just added 2 other settings (E= mc2 and current/charge/time), with another menu to choose which one you want to use. My current code (which I will input below) only takes you back to the calculation menu. How would I go about making it so that after you click a button you go back to the main menu?
module kinematics
implicit none
real :: t, d, s
contains
subroutine time_from_distance_and_speed()
print *, 'Input distance in metres'
read *, d
print *, 'Input speed in metres per second'
read *, s
t = d / s
print*, 'Time is ', s
end subroutine
subroutine distance_from_speed_and_time()
print *, 'Input speed in metres per second'
read *, s
print *, 'Input time in seconds'
read *, t
d = s * t
print*, 'Distance is ', d
end subroutine
subroutine speed_from_time_and_distance()
print *, 'Input distance in metres'
read *, d
print *, 'Input time in seconds'
read *, t
s = d / t
print *, 'Speed is ', s
end subroutine
end module
module electronics
implicit none
real :: Q, I, T
contains
subroutine charge_from_current_and_time()
print *, 'Input current in amps'
read *, I
print *, 'Input time in seconds'
read *, T
Q = I * T
print*, 'Charge is ', Q
end subroutine
subroutine current_from_charge_and_time()
print *, 'Input charge in coulombs'
read *, Q
print *, 'Input time in seconds'
read *, T
I = Q/T
print*, 'Current is ', I
end subroutine
subroutine time_from_current_and_charge()
print *, 'Input current in coulombs'
read *, Q
print *, 'Input charge in amps'
read *, I
T = Q/I
print*,'time is ', T
end subroutine
end module
module energy
implicit none
real :: e, m, c
contains
subroutine energy_from_mass_and_lspeed()
print *, 'Warning- speed of light rounded to 300000000'
read *,
print *, 'Input mass in kilograms'
read *, m
c = 300000000
e = m * c * c
print*, 'Energy is ', e
end subroutine
end module
program bike
use kinematics
use electronics
use energy
implicit none
integer :: gg, pp
print *, 'Press 0 for speed, distance, and time. Press 1 for current, charge and time. Press 2 for E= mc^2'
read *, pp
if ( pp == 0 ) then
do while(.true.)
print *, 'Press 1 for speed, 2 for distance, and 3 for time'
read *, gg
if(gg == 1) then
call speed_from_time_and_distance
else if(gg == 2) then
call distance_from_speed_and_time
else if(gg == 3) then
call time_from_distance_and_speed
end if
print *, 'Press 5 to exit the console, or press 4 to do another calculation'
read *, gg
if(gg== 5) then
exit
end if
end do
end if
if ( pp == 1 ) then
do while(.true.)
print *, 'Press 1 for charge, 2 for current, and 3 for time'
read *, gg
if(gg == 1) then
call charge_from_current_and_time
else if(gg == 2) then
call current_from_charge_and_time
else if(gg == 3) then
call time_from_current_and_charge
end if
print *, 'Press 5 to exit the console, or press 4 to do another calculation'
read *, gg
if(gg== 5) then
exit
end if
end do
end if
if ( pp == 2 ) then
do while(.true.)
call energy_from_mass_and_lspeed
print *, 'Press 5 to exit the console, or press 4 to do another calculation'
read *, gg
if(gg== 5) then
exit
end if
end do
end if
end program

Text input in fortran cases?

Im writing a piece of code in fortran:
write(*,*) "What do you want to do?"
read(*,*) question
select case(question)
case(1)
call sleep (1)
goto 10 (returns at the beginning)
case default
write(*,*) "Ok, then good job :)"
write(*,*) "I exit in 3 seconds..."
call sleep (1)
write(*,*) "I exit in 2 seconds.."
call sleep (1)
write(*,*) "I exit in 1 seconds."
call sleep (2)
goto 20 (kills the program)
Instead of "1" and "2" I'd like to use "Yes" and "No"
How can I do that? Thanks!
Here's an example that uses a string ("Title") in the select/case block:
https://pages.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/select.html
CHARACTER(LEN=4) :: Title
INTEGER :: DrMD = 0, PhD = 0, MS = 0, BS = 0, Others = 0
SELECT CASE (Title)
CASE ("DrMD")
DrMD = DrMD + 1
CASE ("PhD")
PhD = PhD + 1
CASE ("MS")
MS = MS + 1
CASE ("BS")
BS = BS + 1
CASE DEFAULT
Others = Others + 1
END SELECT

Fortran - Jump other subroutine

I am trying to jump other subroutine in Fortran code. I used the return function but it is not working in some cases. Is there any way to jump to other subroutine. I made a simple example to define the problem. If the condition is in the same subroutine, I can use goto label but I need to jump different subroutine. If the condition is correct (case = .True.), I don't want to calculate that subroutine so I will skip that subroutine, I will start to use the new data. For example, if i=3 and case=true, the program shouldn't print a=8 in the 3rd loop and jump the do loop in subroutine abc.
----------------------------------------------
subroutine abc()
do i=1, 5
!if case is true, start to program from here.
call vector ()
end do
end subroutine
-------------------------------------
subroutine vector()
if (case = .True.)then
*****JUMP call vector in main program *****
print *,"skip and jump "
return
a= 8
print *, a
else
b= 9
print *, b
print *, "continue the process "
end if
end subroutine
------------------------------------------------
-----output should be-------
9
9
skip and jump
9
9

data entrance error Fortran

I'm learning how to programming with fortran90 and i need receive data from a txt file by the command prompt (something like that:
program.exe"<"data.txt).
at the Input txt file I'll always have a single line with at least 6 numbers till infinity.
if the data was wrote line by line it runs fine but as single line I'm receiving the error: "traceback:not available,compile with - ftrace=frame or - ftrace=full fortran runtime error:end file"
*note: i'm using Force fortran 2.0
here is example of data:
0 1 0.001 5 3 1 0 -9 3
edit: just clarifying: the code is working fine itself except for the read statement, which is a simple "read*,". I want know how To read a entire line from a txt once the entrance will be made by the promt command with stream direction.
( you can see more about that here: https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx?mfr=true).
there is no need to read the code, i've posted it just for knowledge.
I'm sorry about the whole inconvenience.
here is the code so far:
program bissecao
implicit none
integer::cont,int,e,k,intc,t1,t2,t3
doubleprecision::ii,is,pre,prec,erro,somaa,somab,xn
doubleprecision,dimension(:),allocatable::co
t1=0
t2=0
t3=0
! print*,"insira um limite inf da funcao"
read*,ii
!print*,"insira o limite superior da func"
read*,is
! print*,"insira a precisÆo admissivel"
read*,pre
if (erro<=0) then !elimina criterio de parada negativo ou zero
Print*,"erro"
go to 100
end if
!print*,"insira a qtd iteracoes admissiveis"
read*,int
!print*,"insira o grau da f(x)"
read*,e
if (e<=0) then ! elimina expoente negativo
e=(e**2)**(0.5)
end if
allocate(co(e+1))
!print*, "insira os coeficientes na ordem:&
! &c1x^n+...+(cn-1)x^1+cnx^0"
read(*,*)(co(k),k=e+1,1,-1)
somab=2*pre
intc=0
do while (intc<int.and.(somab**2)**0.5>pre.and.((is-ii)**2)**0.5>pre)
somab=0
somaa=0
xn =(ii+is)/2
do k=1,e+1,1
if (ii /=0) then
somaa=ii**(k-1)*co(k)+somaa
else
somaa=co(1)
end if
! print*,"somaa",k,"=",somaa
end do
do k=1,(e+1),1
if (xn/=0) then
somab=xn**(k-1)*co(k)+somab
else
somab=co(1)
end if
!print*,"somab",k,"=",somab
end do
if ((somaa*somab)<0) then
is=xn
else if((somaa*somab)>0)then
ii=xn
else if ((somaa*somab)==0) then
xn=(ii+is)/2
go to 100
end if
intc =intc+1
prec=is-ii
if ((((is-ii)**2)**.5)< pre) then
t3=1
end if
if (((somab**2)**.5)< pre) then
t2=1.
end if
if (intc>=int) then
t1=1
end if
end do
somab=0
xn=(ii+is)/2
do k=1,(e+1),1
if (xn/=0) then
somab=xn**(k-1)*co(k)+somab
else
somab=co(1)
end if
end do
100 write(*,'(A,F20.15,A,F20.15,A,A,F20.15,A,F20.15,A,I2)'),"I:[",ii,",",is,"]","raiz:",xn,"Fraiz:",somab,"Iteracoes:",intc
end program !----------------------------------------------------------------------------
In your program, you are using the "list-directed input" (i.e., read *, or read(*,*))
read *, ii
read *, is
read *, pre
read *, int
read *, e
read *, ( co( k ), k = e+1, 1, -1 )
which means that the program goes to the next line of the data file after each read statement (by neglecting any remaining data in the same line). So, the program works if the data file (say "multi.dat") consists of separate lines (as suggested by OP):
0
1
0.001
5
3
1 0 -9 3
But now you are trying to read an input file containing only a single line (say "single.dat")
0 1 0.001 5 3 1 0 -9 3
In this case, we need to read all the values with a single read statement (if list-directed input is to be used).
A subtle point here is that the range of array co depends on e, which also needs to be read by the same read statement. A workaround might be to just pre-allocate co with a sufficiently large number of elements (say 100) and read the data in a single line, e.g.,
integer :: k
allocate( co( 100 ) )
read *, ii, is, pre, int, e, ( co( k ), k = e+1, 1, -1 )
For completeness, here is a test program where you can choose method = 1 or 2 to read "multi.dat" or "single.dat".
program main
implicit none
integer :: int, e, k, method
double precision :: ii, is, pre
double precision, allocatable :: co(:)
allocate( co( 1000 ) )
method = 1 !! 1:multi-line-data, 2:single-line-data
if ( method == 1 ) then
call system( "cat multi.dat" )
read*, ii
read*, is
read*, pre
read*, int
read*, e
read*, ( co( k ), k = e+1, 1, -1 )
else
call system( "cat single.dat" )
read*, ii, is, pre, int, e, ( co( k ), k = e+1, 1, -1 )
endif
print *, "Input data obtained:"
print *, "ii = ", ii
print *, "is = ", is
print *, "pre = ", pre
print *, "int = ", int
print *, "e = ", e
do k = 1, e+1
print *, "co(", k, ") = ", co( k )
enddo
end program
You can pass the input file from standard input as
./a.out < multi.dat (for method=1)
./a.out < single.dat (for method=2)
Please note that "multi.dat" can also be read directly by using "<".

getting error in reading a data

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>