I am trying to use PPVAL function from the IMSL library, to evaluate a piecewise polynomial, similar to MATLAB's ppval function.
Sadly, I could not understand well the documentation on how to properly use the function.
I tried to evaluate a simple polynomial.
The polynomials p(x) = 1 and p(x) = x were ok. What I don't understand is when I try to get higher degree polynomials.
The program below tries to evaluate the polynomial p(x)=x^4:
program main
include 'LINK_FNL_SHARED.h'
USE PPVAL_INT
implicit none
double precision :: x(11), y(11)
double precision :: BREAK(2),PPCOEF(5,1)
integer :: ii
break = [0.0d0,10.0d0] ! breakpoints in increasing order
PPCOEF(:,1) = [0.0d0,0.0d0,0.0d0,0.0d0,1.0d0] ! polynomial coefficients
x = dble([0,1,2,3,4,5,6,7,8,9,10])
do ii=1,11
y(ii) = PPVAL(x(ii),break,PPCOEF)
end do
print *, 'x = ', x
print *, 'y = ', y
pause
end program main
But the function returns the polynomial p(x) = x^4/4!.
For degrees 2,3 and 5, the return is always, p(x) = x^2/2!, p(x)=x^3/3!, p(x)=x^5/5!. Why does this factor appear in the ppval function? Why can't I just supply the polynomial coefficients and evaluate it?
Is there another simpler function to evaluate polynomials in Fortran, like MATLAB polyval?
I understand Monte carlo simulation is for estimating area by plotting random points and calculating the ration between the points outside the curve and inside the curve.
I have well calculated the value of pi assuming radius of curve to be unity.
Here is the code
program pi
implicit none
integer :: count, n, i
real :: r, x, y
count = 0
n=500
CALL RANDOM_SEED
DO i = 1, n
CALL RANDOM_NUMBER(x)
CALL RANDOM_NUMBER(y)
IF (x*x + y*Y <1.0) count = count + 1
END DO
r = 4 * REAL(count)/n
print *, r
end program pi
But to find integration , Textbook says to apply same idea. But I'm lost on How to write a code if I want to find the integration of
f(x)=sqrt(1+x**2) over a = 1 and b = 5
Before when radius was one, I did assume point falling inside by condition x*2+y**2 but How can I solve above one?
Any help is extremely helpful
I will write the code first and then explain:
Program integral
implicit none
real f
integer, parameter:: a=1, b=5, Nmc=10000000 !a the lower bound, b the upper bound, Nmc the size of the sampling (the higher, the more accurate the result)
real:: x, SUM=0
do i=1,Nmc !Starting MC sampling
call RANDOM_NUMBER(x) !generating random number x in range [0,1]
x=a+x*(b-a) !converting x to be in range [a,b]
SUM=SUM+f(x) !summing all values of f(x). EDIT: SUM is also an instrinsic function in Fortran so don't call your variable this, I named it so, to illustrate its purpose
enddo
print*, (b-a)*(SUM/Nmc) !final result of your integral
end program integral
function f(x) !defining your function
implicit none
real, intent(in):: x
real:: f
f=sqrt(1+x**2)
end function f
So what's happening:
The integral can be written as
. where:
(this g(x) is a uniform probability distribution of the variable x in [a,b]). And we can write the integral as:
where .
So, finally, we get that the integral should be:
So, all you have to do is generate a random number in the range [a,b] and then calcualte the value of your function for this x. Then do this lots of times (Nmc times), and calculate the sum. Then just divide with Nmc, to find the average and then multiply with (b-a). And this is what the code does.
There's lots of stuff on the internet for this. here's one example that visualizes it pretty nice
EDIT: Second way, that is the same as the Pi method:
Nin=0 !Number of points inside the function (under the curve)
do i=1,Nmc
call random_number(x)
call random_number(y)
x=a+x*(b-a)
y=f_min+y(f_max-f_min)
if (f(x)<y) Nin=Nin+1
enddo
print*, (f_max-f_min)*(b-a)*(real(Nin)/Nmc)
All of this, you could then enclose it in an outer do loop summing the (f_max-f_min)(b-a)(real(Nin)/Nmc) and in the end printing its average.
For this example, what you do is essentially creating an enclosing box from a to b (x dimension) and from f_min to f_max (y dimension) and then doing a sampling of points inside this area and counting the points that are in the function (Nin).Obviously you will have to know the minimum (f_min) and maximum (f_max) value of your function in the range [a,b]. Alternatively you could use arbitrarily low/high values for your f_min f_max but then you will be wasting a lot of points and your error will be bigger.
Today I started coding equations and algebraic expressions using Fortran (I'm using gfortran in Debian(Parrot-home OS) and Geany).
The problem is, I code on the same way(or equal) to the mode I see on internet, and I get only a wrong root to x' and x''.
program equacao2grau
real delta, a, b, c, x, x2
complex sqrt
print*, "This program calc 2º equations"
print*, "Give the values 'A', 'B'e 'C'"
read*, a !Getting values
read*, b ! for
read*, c !resolution
if (a /= 0) then !if 'a' be different of 0
delta = b**2 - 4*a !do delta
end if
print*, delta = b**2 - 4*a*c
if (a .EQ. 0) then
stop
end if
if (delta .EQ. 0) then
print*, "The value is", (-b / 2*a)
stop
end if
if (delta .GT. 0) then
print*, "The roots are", -b + sqrt(delta) / 2*a
print*, "e", -b - sqrt(delta) / 2*a
stop
end if
end
I know, it is incomplete, but I'm demotivated with don't find any correct result.
Things I researched:
https://www.cenapad.unicamp.br/servicos/treinamentos/apostilas/apostila_fortran90.pdf
http://ftp.demec.ufpr.br/disciplinas/TM111/Arquivos_Infomatica/Fortran/fortran.html#_Toc467428016
http://www.oc.nps.edu/~bird/oc3030_online/fortran/if/logicalif.html
http://wwwp.fc.unesp.br/~lavarda/fc1/apo/fort_04.htm
You are missing brackets in the expressions.
-b + sqrt(delta) / 2*a
Should be:
(-b + sqrt(delta)) / (2*a)
And same for the other roots.
Edit
Also, as pointed by #albert, you omitted c in the formula of delta.
Moreover, as said by #IanBush, the declaration of complex sqrt must be removed.
And always use implicit none.
I want to solve a set of equations using 5th order Runge-Kutta method with adaptive stepsize method. I have found a useful code written by Taner Akgun. Here is the code:
c
c Adaptive Size Method for 5th Order Runge-Kutta Method
c (Based on Numerical Recipes.)
c
c Taner Akgun
c June, 2002
c
c Read on for various definitions.
c (For more information consult the book.)
c
program main
implicit none
integer nvar,nok,nbad
double precision x,y,dydx
double precision ystart,x1,x2,eps,h1,hmin
c Number of derivatives to be integrated:
c (In general, we can specify a set of equations.)
parameter(nvar=1)
external derivs,rkqs
open(1,file='test')
c Integration boundaries and initial values:
x1 = 0d0
x2 = 2d0
ystart = 1d0
c Stepsize definitions:
c (h1 - initial guess; hmin - minimum stepsize)
h1 = 1d-1
hmin = 1d-9
c write(1,*)'(Initial) Stepsize:',h1
c Allowable error for the adaptive size method:
eps = 1d-9
c Calculations:
c Adaptive Size Method:
y = ystart
call odeint(y,nvar,x1,x2,eps,h1,hmin,nok,nbad,derivs,rkqs)
stop
end
c
c Subroutine for the differential equation to be integrated.
c Calculates derivative dydx at point x for a function y.
c
subroutine derivs(x,y,dydx)
implicit none
double precision x,y,dydx
dydx = dexp(x)
return
end
c
c Subroutine for the Adaptive Size Method.
c See Numerical Recipes for further information.
c
subroutine odeint(ystart,nvar,x1,x2,eps,h1,hmin,nok,nbad,derivs,
* rkqs)
implicit none
integer nbad,nok,nvar,KMAXX,MAXSTP,NMAX
double precision eps,h1,hmin,x1,x2,ystart(nvar),TINY
external derivs,rkqs
parameter(MAXSTP=10000,NMAX=50,KMAXX=200,TINY=1.e-30)
integer i,kmax,kount,nstp
double precision dxsav,h,hdid,hnext,x,xsav,dydx(NMAX)
double precision xp(KMAXX),y(NMAX),yp(NMAX,KMAXX),yscal(NMAX)
common /path/ kmax,kount,dxsav,xp,yp
x=x1
h=sign(h1,x2-x1)
nok=0
nbad=0
kount=0
do 11 i=1,nvar
y(i)=ystart(i)
11 continue
if (kmax.gt.0) xsav=x-2.d0*dxsav
do 16 nstp=1,MAXSTP
call derivs(x,y,dydx)
do 12 i=1,nvar
yscal(i)=dabs(y(i))+dabs(h*dydx(i))+TINY
12 continue
if(kmax.gt.0)then
if(abs(x-xsav).gt.dabs(dxsav))then
if(kount.lt.kmax-1)then
kount=kount+1
xp(kount)=x
do 13 i=1,nvar
yp(i,kount)=y(i)
13 continue
xsav=x
endif
endif
endif
if((x+h-x2)*(x+h-x1).gt.0.d0) h=x2-x
call rkqs(y,dydx,nvar,x,h,eps,yscal,hdid,hnext,derivs)
if(hdid.eq.h)then
nok=nok+1
else
nbad=nbad+1
endif
if((x-x2)*(x2-x1).ge.0.d0)then
do 14 i=1,nvar
ystart(i)=y(i)
14 continue
if(kmax.ne.0)then
kount=kount+1
xp(kount)=x
do 15 i=1,nvar
yp(i,kount)=y(i)
15 continue
endif
return
endif
if(abs(hnext).lt.hmin) pause
* 'stepsize smaller than minimum in odeint'
h=hnext
16 continue
pause 'too many steps in odeint'
return
end
c
c Subroutine for the Adaptive Size Method.
c See Numerical Recipes for further information.
c Uses 'derivs' and 'rkck'.
c
subroutine rkqs(y,dydx,n,x,htry,eps,yscal,hdid,hnext,derivs)
implicit none
integer n,NMAX
double precision eps,hdid,hnext,htry,x,dydx(n),y(n),yscal(n)
external derivs
parameter(NMAX=50)
integer i
double precision errmax,h,htemp,xnew,yerr(NMAX),ytemp(NMAX)
double precision SAFETY,PGROW,PSHRNK,ERRCON
parameter(SAFETY=0.9,PGROW=-.2,PSHRNK=-.25,ERRCON=1.89e-4)
h=htry
1 call rkck(y,dydx,n,x,h,ytemp,yerr,derivs)
errmax=0d0
do 11 i=1,n
errmax=max(errmax,dabs(yerr(i)/yscal(i)))
11 continue
errmax=errmax/eps
if(errmax.gt.1d0)then
htemp=SAFETY*h*(errmax**PSHRNK)
h=sign(max(dabs(htemp),0.1d0*dabs(h)),h)
xnew=x+h
if(xnew.eq.x)pause 'stepsize underflow in rkqs'
goto 1
else
if(errmax.gt.ERRCON)then
hnext=SAFETY*h*(errmax**PGROW)
else
hnext=5d0*h
endif
hdid=h
x=x+h
do 12 i=1,n
y(i)=ytemp(i)
12 continue
return
endif
end
c
c Subroutine for the Adaptive Size Method.
c See Numerical Recipes for further information.
c
subroutine rkck(y,dydx,n,x,h,yout,yerr,derivs)
implicit none
integer n,NMAX
double precision h,x,dydx(n),y(n),yerr(n),yout(n)
external derivs
parameter(NMAX=50)
integer i
double precision ak2(NMAX),ak3(NMAX),ak4(NMAX)
double precision ak5(NMAX),ak6(NMAX),ytemp(NMAX)
double precision A2,A3,A4,A5,A6
double precision B21,B31,B32,B41,B42,B43,B51,B52,B53,
* B54,B61,B62,B63,B64,B65
double precision C1,C3,C4,C6,DC1,DC3,DC4,DC5,DC6
parameter(A2=.2,A3=.3,A4=.6,A5=1.,A6=.875,B21=.2,B31=3./40.,
* B32=9./40.,B41=.3,B42=-.9,B43=1.2,B51=-11./54.,B52=2.5,
* B53=-70./27.,B54=35./27.,B61=1631./55296.,B62=175./512.,
* B63=575./13824.,B64=44275./110592.,B65=253./4096.,C1=37./378.,
* C3=250./621.,C4=125./594.,C6=512./1771.,DC1=C1-2825./27648.,
* DC3=C3-18575./48384.,DC4=C4-13525./55296.,DC5=-277./14336.,
* DC6=C6-.25)
do 11 i=1,n
ytemp(i)=y(i)+B21*h*dydx(i)
11 continue
call derivs(x+A2*h,ytemp,ak2)
do 12 i=1,n
ytemp(i)=y(i)+h*(B31*dydx(i)+B32*ak2(i))
12 continue
call derivs(x+A3*h,ytemp,ak3)
do 13 i=1,n
ytemp(i)=y(i)+h*(B41*dydx(i)+B42*ak2(i)+B43*ak3(i))
13 continue
call derivs(x+A4*h,ytemp,ak4)
do 14 i=1,n
ytemp(i)=y(i)+h*(B51*dydx(i)+B52*ak2(i)+B53*ak3(i)+B54*ak4(i))
14 continue
call derivs(x+A5*h,ytemp,ak5)
do 15 i=1,n
ytemp(i)=y(i)+h*(B61*dydx(i)+B62*ak2(i)+B63*ak3(i)+B64*ak4(i)+
* B65*ak5(i))
15 continue
call derivs(x+A6*h,ytemp,ak6)
do 16 i=1,n
yout(i)=y(i)+h*(C1*dydx(i)+C3*ak3(i)+C4*ak4(i)+C6*ak6(i))
16 continue
do 17 i=1,n
yerr(i)=h*(DC1*dydx(i)+DC3*ak3(i)+DC4*ak4(i)+DC5*ak5(i)+DC6*
* ak6(i))
17 continue
return
end
Unfortunately, I'm not familiar with Fortran at all. I'm going to solve the following set of equations using this code.
dy/dx=-x
dy/dx=-1
Inside the code, it says the nvar variable is the number of equations and in this code, it is set to 1. If I want to change it to other than 1, how should I change the code?
Also, I want to save all the x's and y's values in the output file. How could I do it?
Firstly to try to answer your first question. Without repeating the large code block from your original question I suspect you will need to do the following:
Replace
parameter(nvar=1)
with
parameter(nvar=2)
and replace the existing derivs routine with something like
subroutine derivs(x,y,dydx)
implicit none
double precision x
double precision, dimension(:) y,dydx
dydx(1) = -x
dydx(2) = -1
return
end
You will also need to change the declaration of ystart, y and dydx in main to be double precision, dimension(2) :: ystart, y, dydx and then ensure these are set properly. This may be sufficient to give you the correct answer.
For your second question, one way to get the intermediate x and y values is rather than integrate from the start right to the end, instead integrate in steps. For example something like
do i=1,nstep
call odeint(y,nvar,x1,x2,eps,h1,hmin,nok,nbad,derivs,rkqs)
print*,"At x=",x2," y= ",y
!Update start and end points
x1=x2
x2=x1+stepSize
enddo
However, if your goal is not to learn fortran (as you've suggested in a comment) but just to solve these equations you may want to look to the odeint module from scipy in python which provides all of this functionality.
I have never done programming in my life and this is my very first code for a uni assignment, I get no errors in the compiling stage but myh program does not run saying that I have the error in the title, guess the problem is when I call the subroutine. Can anyone help me? It is my first code and it is really frustrating. Thank you.
!NUMERICAL COMPUTATION OF INCOMPRESSIBLE COUETTE FLOW USING FINITE DIFFERENCE METHOD
!IMPLICIT APPROACH
!MODEL EQUATION
!PARTIAL(U)/PARTIAL(T)=1/RE*(PARTIAL(U) SQUARE/PARTIAL(Y) SQUARE)
!DEFINE VARIABLES
IMPLICIT NONE
!VELOCITY U AT TIME T, VELOCITY UNEW AT TIME T+1, TIME T
!MAXIMUM 1000 POINTS
REAL V(1000)
REAL VNEW(1000)
REAL T
!GRID SPACING DY, GRID POINTS N+1
REAL DY
INTEGER N
!TIME STEP
REAL DT
!FLOW REYNOLDS NUMBER IN THE MODEL EQUATION
REAL ALPHA
!TOTAL SIMULATION TIME - LOOP NUMBER
INTEGER REP, I, J
!COEFFICIENTS IN LINEAR EQUATION MATRIX, SOURCE TERM K, DIAGONAL B, NON-DIAGONAL A
REAL S(1000), B, A
!INITIALIZATION OF DATA
DATA ALPHA/5000.0/
DATA N/100/
DATA REP/3000/
!CALCULATION OF GRID SPACING
DY=1.0/N
!CALCULATION OF TIME STEP DELTA T, CAN BE LARGER THAN THAT IN AN EXPLICIT METHOD
DT=0.5*RE*DY*DY
DT=ALPHA*DY*DY
!INITIAL CONDITIONS OF VELOCITY PROFILE
!BOTTOM AND INNER POINTS
DO I=1,N
V(I)=0.0
ENDDO
!POINT AT MOVING PLATE
V(N+1)=1.0
!BOUNDARY CONDITIONS AT LOWER AND UPPER POINTS ON PLATE
V(1)=0.0
V(N+1)=1.0
!CALCULATION OF DIAGONAL B AND NON-DIAGONAL A IN LINEAR EQUATION MATRIX
B=1.0+DT/DY/DY/ALPHA
A=-(DT)/2.0/DY/DY/ALPHA
!INITIAL COMPUTATION TIME
T=0.0
!ENTER MAIN LOOP TO MARCH IN TIME DIRECTION
DO I=1,REP
!SIMULATION TIME INCREASE BY DELTA T EACH STEP
T=T+DT
!USE IMPLICIT METHOD TO UPDATE GRID POINT VALUES FOR ALL INTERNAL GRIDS ONLY
!TWO BOUNDARY GRID POINTS VALUES ARE CONSTANT WITHIN THE WHOLE SIMULATION
!CALCULATION OF SOURCE TERM IN LINEAR EQUATION
DO J=2,N
S(J)=(1.0-DT/DY/DY/ALPHA)*V(J)+DT/2.0/DY/DY/ALPHA*V(J+1)+V(J-1)
ENDDO
!INCLUDE BOUNDARY CONDITIONS FOR TWO POINTS NEAR BOUDNARY
S(2)=S(2)-A*V(1)
S(N)=S(N)-A*V(N+1)
!USE SOURCE TERM K, DIAGONAL B, NON-DIAGONAL A, ORDER OF MATRIX N, TO SOLVE LINEAR EQUATION TO GET UPDATED VELOCITY
!CHECK ON INTERNET HOW TO SOLVE THIS BECUASE THIS COMPILER
!DOES NOT SOLVE IT, SOLVE LINEAR EQUATIONS BY A LINEAR SOLVER, FIND AND DOWNLOAD THE MATH LIBRARY FOR THIS COMPILER
CALL SR1(A,B,N,S,VNEW)
!REPLACE OLD VELOCITY VALUES WITH NEW VALUES.
!SINCE UNEW IS FROM UNEW(1), UNEW(2)......., UNEW(N-1), WE SHOULD RE-ARRANGE NUMBERS AS FOLLOWS
DO J=1,N-1
V(J+1)=VNEW(J)
ENDDO
!RETURN TO MAIN LOOP HERE
ENDDO
PRINT*,'HERE'
!OUTPUT VELOCITY PROFILES AT THE END OF COMPUTATION
!CREATE OUPUT FILE NAME
OPEN(15,FILE='PLEASEWORK')
!WRITE GRID POINTS AND VELOCITY VALUES
DO I=1,N+1
WRITE(15,10) V(I),(I-1)*DY
10 FORMAT(2F12.3)
ENDDO
CLOSE(15)
!DISPLAY INFORMATION ON SCREEN
!WRITE(*,*) 'THE OUTPUT VELOCITY IS AFTER', ITER, ' TIME STEPS'
!TERMINATION OF COMPUTER PROGRAM
STOP
END
!!!!!!!!
!!!!!!!!!!!!
!!!!!!!!!
SUBROUTINE SR1(A,B,N,S,VNEW)
REAL DIAGM(N), DIAGU(N), DIAGL(N)
REAL SS(N)
DO J=1,N-1
SS(J)=S(J+1)
ENDDO
DO I=1,N
DIAGM(i)=B
!Sets main diagonal as B for every value of i
IF (I==0) then
DIAGU(I)=A
DIAGL(I)=0
! No lower diagonal coefficient when i = 0
ELSE IF (I==N) THEN
DIAGU(I)=0
! No upper diagonal coefficient when i = Num
DIAGL(I)=A
ELSE
DIAGU(I)=A
! For all other points there is an upper diagonal coefficient
DIAGL(I)=A
! For all other points there is a lower diagonal coefficient
ENDIF
ENDDO
!CALL STANDARD FORTRAN MATH LIBRARY TO SOLVE LINEAR EQUATION AND GET SOLUTION VECTOR X(N-1)
CALL SR2 (DIAGL,DIAGM,DIAGU,SS,VNEW,N-2)
!RETURN TO MAIN PROGRAM AND X(N-1) IS FEEDED INTO UNEW(N-1)
RETURN
END SUBROUTINE
!!!!!!!!!!!!!!!
!!!!!!!!!!!
!!!!!!!!!!!
SUBROUTINE SR2 (A,B,C,D,Z,N)
!a - sub-diagonal (means it is the diagonal below the main diagonal)
!b - the main diagonal
!c - sup-diagonal (means it is the diagonal above the main diagonal)
!K - right part
!UNEW - the answer
!E - number of equations
INTEGER N
REAL A(N), B(N), C(N), D(N)
REAL CP(N), DP(N), Z(N)
REAL M
INTEGER I
DATA M/1/
!initialize c-prime and d-prime
CP(1) = C(1)/B(1)
DP(1) = D(1)/B(1)
!solve for vectors c-prime and d-prime
DO I=2,N
M=b(i)-CP(I-1)*(A(I))
CP(I)=C(I)/M
DP(I)=(D(I)-DP(I-1)*A(I))/M
ENDDO
!initialize UNEW
Z(N)=DP(N)
!solve for x from the vectors c-prime and d-prime
DO I=N-1, 1, -1
Z(I)=DP(I)-CP(I)*Z(I+1)
ENDDO
END SUBROUTINE
As george says in a comment, the problem is with the subroutine SR1. So that this isn't just a CW-stealing-a-comment answer I'll also expand a bit.
The way things are structured SR1 is a different scope from the main program. The IMPLICIT NONE in the main program doesn't apply to the subroutine, so A, B, N, S and VNEW are all implicitly typed. Apart from N,which is an integer, they are (scalar) reals.
The reference to S(J+1), as george says, means that S is not only a scalar real, but also a function. Remember that SR1 is a different scope and no information is passed from the caller to the callee about types, shapes, etc.. Further, that the dummy argument in SR1 called A happens to be same name as the actual argument in the call doesn't mean that the callee "knows" things. Your call to SR2 with the VNEW is also a problem for the same reason.
The question is tagged as "fortran77" so there isn't too much you can do to ensure there is a lot of checking going on, but there may well be compiler options and as you can use IMPLICIT NONE (not Fortran 77) that would detect your problems.
But, the question is also tagged "fortran" and "fortran95" so I'll point out that there are far better ways to detect the issues, using more modern features. Look at interfaces, modules and internal procedures.