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
Related
I built a speed, distance, and time calculator. I thought that it would be cool if you could go back to the main menu and calculate time after your original calculation (as an example). How would I do this by using modules? Here are the modules I have created:
module menu
real :: s ! speed
real :: d ! distance
real :: t ! time
real :: gg ! this is how I am going to switch between distance, time, and speed
print *, 'Press 1 for speed, 2 for distance, and 3 for time'
read*, gg
end menu
module speed
print *, 'Input distance in metres'
read *, d
print *, 'Input time in seconds'
read *, t
s = d / t
print *, 'Speed is ', s
end speed
module stay or leave
print *, 'Press 4 to go back to menu, or press 5 to exit the console'
read *, gg
end stay or leave
module distance
print *, 'Input speed in metres per second'
read *, s
print *, 'Input time in seconds'
read *, t
d = s * t
print*, 'Distance is ', d
end distance
module time
print *, 'Input distance in metres'
read *, d
print *, 'Input speed in metres per second'
read *, s
t = d / s
print*, 'Time is ', s
end time
You are using module as a subroutine. A module is a collection of related subroutines, user types and other related data. There is no need to use modules in this example (at least not in the way it is shown above).
But if you had to use modules I have included an example below. The module definition contains the following subroutines
time_from_distance_and_speed()
distance_from_speed_and_time()
speed_from_time_and_distance()
and three common variables t, d, s used in the calculations. Although in general it not recommended re-using the same variables in different routines, this is done here for illustrative purposes to show how "global" variables can be defined in the module level.
Module
Here the module contains the variable definitions which are common to the procedures it contains. It also defines the three calculation processes.
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
Program
Here the main program uses the module defined above and calls the appropriate method depending on the user input.
program bike
use kinematics
integer :: gg
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, anything else will repeat'
read *, gg
if(gg== 5) then
exit
end if
end do
end program
I want to call a subroutine in the main program and also want to get the output of that subroutine in the main program but when I write the output in the subroutine its different than when I write it in the main program someone can tell me where I am wrong? while writing yy in subroutine and in main program gives different values.
subroutine zlamda(lamdaroot)
INTEGER N,NBMAX
REAL X1,X2
PARAMETER(N=100,NBMAX=20,X1=0.0,X2=3.141592/2.)
INTEGER i,nb
REAL zbrent,root,tol,xb1(NBMAX),xb2(NBMAX)
EXTERNAL zbrak,bess
REAL bess,lamdaroot,lamda
COMMON /flamda/ eL,z
nb=NBMAX
call zbrak(bess,X1,X2,N,xb1,xb2,nb)
do 200 i=1,nb
tol=(1.0e-6)*(xb1(i)+xb2(i))/2.0
lamdaroot=zbrent(bess,xb1(i),xb2(i),tol)
yy=lamdaroot
write(*,*)yy,'=lamdaroot=yy'
200 continue
return
END
FUNCTION bess(lamda)
REAL bss,lamda,zz,x
bess=0.5*sin(lamda)*sqrt(1.+3.*sin(lamda)**2)+(0.5/sqrt(3.))
+ *log(abs(sqrt(3.)*sin(lamda)+sqrt(1.+3.*sin(lamda)**2)))
+ -abs(zz)/4685.0
return
END
SUBROUTINE zbrak(fx,x1,x2,n,xb1,xb2,nb)
INTEGER n,nb
REAL x1,x2,xb1(nb),xb2(nb),fx
EXTERNAL fx
INTEGER i,nbb
REAL dx,fc,fp,x
nbb=0
x=x1
dx=(x2-x1)/n
fp=fx(x)
do 11 i=1,n
x=x+dx
fc=fx(x)
if(fc*fp.le.0.) then
nbb=nbb+1
xb1(nbb)=x-dx
xb2(nbb)=x
if(nbb.eq.nb)goto 1
endif
fp=fc
11 continue
1 continue
nb=nbb
return
END
FUNCTION zbrent(func,x1,x2,tol)
INTEGER ITMAX
REAL zbrent,tol,x1,x2,func,EPS
EXTERNAL func
PARAMETER (ITMAX=100,EPS=3.e-8)
INTEGER iter
REAL a,b,c,d,e,fa,fb,fc,p,q,r,s,tol1,xm
a=x1
b=x2
fa=func(a)
fb=func(b)
if((fa.gt.0..and.fb.gt.0.).or.(fa.lt.0..and.fb.lt.0.))pause
*'root must be bracketed for zbrent'
c=b
fc=fb
do 11 iter=1,ITMAX
if((fb.gt.0..and.fc.gt.0.).or.(fb.lt.0..and.fc.lt.0.))then
c=a
fc=fa
d=b-a
e=d
endif
if(abs(fc).lt.abs(fb)) then
a=b
b=c
c=a
fa=fb
fb=fc
fc=fa
endif
tol1=2.*EPS*abs(b)+0.5*tol
xm=.5*(c-b)
if(abs(xm).le.tol1 .or. fb.eq.0.)then
zbrent=b
return
endif
if(abs(e).ge.tol1 .and. abs(fa).gt.abs(fb)) then
s=fb/fa
if(a.eq.c) then
p=2.*xm*s
q=1.-s
else
q=fa/fc
r=fb/fc
p=s*(2.*xm*q*(q-r)-(b-a)*(r-1.))
q=(q-1.)*(r-1.)*(s-1.)
endif
if(p.gt.0.) q=-q
p=abs(p)
if(2.*p .lt. min(3.*xm*q-abs(tol1*q),abs(e*q))) then
e=d
d=p/q
else
d=xm
e=d
endif
else
d=xm
e=d
endif
a=b
fa=fb
if(abs(d) .gt. tol1) then
b=b+d
else
b=b+sign(tol1,xm)
endif
fb=func(b)
11 continue
pause 'zbrent exceeding maximum iterations'
zbrent=b
return
END
and main program is
program main
implicit none
real yy,lamdaroot
call zlamda(lamdaroot)
write(*,*)yy
stop
endprogram main
I am writing a Fortran90 subroutine, but the language does not matter for the purpose of this question. Feel free to provide answers in psuedocode if it's more convenient.
I have a number statements (or groups of statements) to execute based on an input parameter. Let the input variable be x and let's call the statements A, B, C,..., N. These statements do not share enough common properties to be combined, and should therefore be executed separately.
The conditions are:
if ( x .eq. 1 ) then
! execute A
endif
if ( x .eq. 2 ) then
! execute A
! execute B
if ( x .eq. 3 ) then
! execute A
! execute B
! execute C
endif
.
.
.
and so on...
(Note that all the ! execute statements are all mathematical calculations and variable assignments. Nothing is printed, no functions are called, etc...)
My attempt to simplify the code turned it into:
if ( x .ge. 1 ) then
! execute A
endif
if ( x .ge. 2 ) then
! execute B
endif
if ( x .ge. 3 ) then
! execute C
endif
.
.
.
This is still too much coding to do for a large value of x. I know that I have to code all the execute statements (and I have already done so), but I am hoping that there is still a faster way to only run the number that the user specifies without having to type over a hundred if statements. Any thoughts on that?
Oh what a shame that computed go to is frowned upon. No self-respecting Fortran programmer in C21 would write something like
...
read(*,*) x
go to (3,2,1) x
1 call C()
2 call B()
3 call A()
Of course, this executes the calls in the reverse order to that specified in the question, but the question also hints that the order doesn't matter.
I'll close this by reminding readers that this is definitely nasty old FORTRAN. Let us not speak of this again
Not exactly an ideal solution since F90 doesn't have function pointers. Could do it in F03 with function pointers but since you have specified F90
subroutine selector(howmany)
integer, intent(in):: howmany
integer:: ii
do ii = 1, howmany
select case(ii)
case (1)
! execute A
case (2)
! execute B
case (3)
! execute C
case default
continue
end select
end do
end subroutine selector
...
call selector(3)
Unlike C, fortran doesn't have a dropthrough
You could use one-line versions of if:
if ( x .ge. 1 ) call ... ! execute A
if ( x .ge. 2 ) call ... ! execute B
...
Or, if processed within a subroutine or function, you could use return:
call ... ! execute A
if ( x .lt. 2 ) return
call ... ! execute B
if ( x .lt. 3 ) return
...
It's also possible to do this in one line per statement:
call ... ; if ( x .lt. 2 ) return ! execute A
call ... ; if ( x .lt. 3 ) return ! execute B
I don't think it will get less than that, even when using function pointers you would have to point them to the corresponding function/subroutine (which also amounts to one line per function)...
What about a recursive subroutine? Something like this:
recursive subroutine select(x)
integer,intent(in) :: x
select case(x)
case(1)
!execute A
case(2)
!execute B
case(3)
!execute C
end select
if(x > 0) call select(x-1)
end subroutine select
Again, this goes backwards, but a forward version shouldn't be too hard. And there's always the stack overflow possibility if you have a lot of these. This is essentially getting rid of the explicit loop in the accepted answer.
I might do something like this:
i=howmany
do while(i.gt.0)
< a code >
i=i-1;if(i.eq.0)exit
< b code >
i=i-1;if(i.eq.0)exit
<c code>
i=i-1;if(i.eq.0)exit
<d code>
exit
enddo
or equivalently use a subroutine with return.
Note this is logically equivalent to where you started, but the conditional line is the same so a lazy typist can quickly do ctrl-y ctrl-y ctrl-y
Another advantage of this is, should you need to edit the lines you can insert/delete a line anywhere without manually reindexing.
I would appreciate some help on this. The point of the program is to take a lower bound, an upper bound, and the number of steps, and then input them into the respective chosen equation to create a matrix that is the length of the steps, that contains the values for for the equation that was chosen. I'm getting an unclassifiable statement at:
array(i)=function1(x)
array(i)=function2(x)
array(i)=function3(x)
I feel like it has something to do with how I declared my function, but I cannot figure out a fix to it. Any help would be appreciated.
PROGRAM stuff1
IMPLICIT NONE
!variables
INTEGER::i,step
REAL::lower,upper,function1,function2,function3,x,q,w,e
CHARACTER(20)::option
REAL,ALLOCATABLE::array(:)
!formats
101 FORMAT(A) !single text element only
102 FORMAT() ! <description>
!-------Variable Definitions-------!
!
!
!
!----------------------------------!
!x= .1(upper-lower)
!<Begin Coding Here>
WRITE(*,101)"Hello User, please select a function to evaluate:"
WRITE(*,101)
WRITE(*,101)"A) f(x)=x^2+2x+4"
WRITE(*,101)"B) f(x)=|x+4|"
WRITE(*,101)"C) f(x)=sin(x)+42"
WRITE(*,101)"Enter A,B,or C"
DO
READ(*,101)option
IF ((option.EQ."A") .OR. (option.EQ."a")) THEN
ELSE IF((option.EQ.'B') .OR. (option.EQ.'b'))THEN
ELSE IF((option.EQ.'c') .OR. (option.EQ.'c'))THEN
ELSE
WRITE(*,*)"Please enter A,B,or C"
CYCLE
END IF
EXIT
END DO
WRITE(*,101)"please enter an lower bound:"
READ(*,*)lower
WRITE(*,101)
WRITE(*,101)"please enter an upper bound:"
READ(*,*)upper
WRITE(*,101)
WRITE(*,101)"please enter a step size"
READ(*,*)step
function1=((x**2)+(2*x)+4)
function2=(abs(x+4))
function3=(sin(x)+42)
ALLOCATE(array(step))
x=lower
DO i=1,step
IF ((option.EQ."A") .OR. (option.EQ."a")) THEN
array(i)=function1(x)
ELSE IF((option.EQ.'B') .OR. (option.EQ.'b'))THEN
array(i)=function2(x)
ELSE IF((option.EQ.'c') .OR. (option.EQ.'c'))THEN
array(i)=function3(x)
END IF
x=x+(upper-lower)/step
END DO
DO i=1,step
WRITE(*,'(4F6.2)')array(i)
END DO
END PROGRAM
These lines
function1=((x**2)+(2*x)+4)
function2=(abs(x+4))
function3=(sin(x)+42)
appear to be three statement functions. This is an obsolescent feature which you should not use, instead you should define functions along the lines
real function one(x)
real, intent(in) :: x
one = x**2 + 2*x + 4
end function one
If you must program like it's 1979 then the correct form for a statement function would be
function1(x)=((x**2)+(2*x)+4)
You have omitted the dummy argument in the definitions, it's no surprise to me that the compiler gets angry and issues that error.
That's not how to define a function in Fortran!
After the END PROGRAM, define your functions like:
real function function1(x)
real,intent(in) :: x
function1=((x**2)+(2*x)+4)
end function
real function function2(x)
real,intent(in) :: x
function2=(abs(x+4))
end function
real function function3(x)
real,intent(in) :: x
function3=(sin(x)+42)
end function
Or, even better, put them into a module!
How do I use a variable in the command executed in a system subroutine call? For example, if I want to create multiple directories like test_1_1, test_1_2, and so on till test_3_3 then what should my code be?
I am trying the following code but can't seem to figure out what to write in #### part.
integer :: i,j
do i = 1,3
do j = 1,3
CALL system('mkdir folder ####')
enddo
enddo
character (len=8) :: test_name
do i=1, 3
do j=1, 3
write (test_name, '( "test_", I1, "_", I1 )' ) i, j
call system ( "mkdir " // test_name )
end do
end do
The format in my example will work as long as the numbers are single digits. If you want larger values you could use I2.2 (for up to two digits, with leading zero, if single digits), or I0, for whatever number of digits are needed.