There are implemented routines for integration of functions by simple Trapezoid and Simpson rules via two routines trapz and simps. The use of both routines is very similar. For instance:
If we have data sampled to a grid of ordered values, we can integrate them by using trapezoid or simpson quadrature similarly as with functions. In order to use them we have only to call trapz or simps
program ex_trapz
USE numfor, only: dp, zero, m_pi, str, trapz, linspace
The use of Simpson routine is similar, and need only to replace trapz() by simps()
Adaptive Simpson method
In addition to The simple, fixed points, Simpson quadrature routines there are implemented Globally Adaptive Simpson routines for finite and infinite integration domains.
Routine iads follows a scheme in which the integration interval is bisected, and the Simpson integration result for the sum of the subintervals is compared with the result for the parent interval. For each subdivision, only three additional function evaluations are needed. This routine is regarded as a good choice when moderate precision ( ) is required.
print "(A)", 'integrate( \log(x) \sqrt(x), 1.e-12, pi) = '//str(integ1)//" (Error="//str(err)//") with N = "//str(abs(n))
! integrate( \log(x) \sqrt(x), 1.e-12, pi) = 1.7746775593141 (Error=1.3697319985965e-05) with N = 89
contains
function fquad451(x) result(y)
implicit none
real(dp) :: y
real(dp), intent(IN) :: x
y = sqrt(x) * log(x)
end function fquad451
end program ex_iads
Routine iadsi is available for semi-infinite integration domains.
For instance, for the function
we see that the main contribution comes from the region below . Then, we can use that information as argument brkpts, as shown in the following example
program ex_iadsi
USE numfor, only: dp, zero, m_pi, str, iadsi, nf_inf, qags
print "(A)", 'integrate(log(1+x)/(1 + 100*x^2), 0, inf) = '//str(integ1)//" (Error="//str(err)//") with N = "//str(abs(n))
! integrate(log(1+x)/(1 + 100*x^2), 0, inf) = 0.0335216255386 (Error=1.259162853146e-12) with N = 165
contains
function f(x) result(y)
implicit none
real(dp) :: y
real(dp), intent(IN) :: x
y = log(1 + x) / (1 + 100 * x**2)
end function f
end program ex_iadsi
Integration using the Tanh-sinh scheme
Routine qnthsh is an implementation of the Tanh-sinh quadrature method. As explained in Wikipedia, the tanh-sinh or Double exponential quadrature is a method for numerical integration introduced by Hidetosi Takahasi and Masatake Mori in 1974. It is based in the change of variables
For a given step size h, the integral is approximated by the sum
with the abscissas
and the weights
The Tanh-Sinh method is quite insensitive to endpoint behavior. Should singularities or infinite derivatives exist at one or both endpoints of the (−1, +1) interval, these are mapped to the (−∞,+∞) endpoints of the transformed interval, forcing the endpoint singularities and infinite derivatives to vanish. This results in a great enhancement of the accuracy of the numerical integration procedure, which is typically performed by the Trapezoidal Rule. In most cases, the transformed integrand displays a rapid roll-off (decay), enabling the numerical integrator to quickly achieve convergence.
Examples of use
The most simple example of using the routine is given by
1program ex_qthsh1
2USE numfor, only: dp, zero, m_pi, str, center, qnthsh
3
4 real(dp) :: err
5integer :: N
6
7 real(dp) :: Integ1
8intrinsic dsin
9 print "(A)", center(" Integrate sin(x) between 0 and pi ", 70, '-')
18 print "(A)", '\int \sin(x) dx = '//str(integ1)//" (Error="//str(err)//") with N = "//str(n)
19! that prints:
20!---------- Get estimation of error and number of evaluations ---------
21! \int \sin(x) dx = 2 (Error=4.8361314952672e-12) with N = 65
22end program ex_qthsh1
Here in the call in line 10 is the simplest possible and only uses the required arguments.
Quadpack routines
The code implemented here has been slightly adapted from the original Quadpack routines (by Piessens, de Doncker-Kapenga, Ueberhuber and Kahaner). It has been ported to Modern Fortran by following several sources: Gnu Scientific Library, J. Burkardt's page, and SciFortran. Moreover, the routines have been tweaked to work with both real and complex functions.
There are routines for adaptive and non-adaptive integration of general functions, with specific routines for some particular difficult cases. These include integration over infinite and semi-infinite ranges, singular integrals, including potential and logarithmic singularities, computation of Cauchy principal values and oscillatory integrals.
The algorithms in Quadpack use a naming convention based on the following letters:
Symbol
Explanation
Q
quadrature routine
N
non-adaptive integrator
A
adaptive integrator
G
general integrand (user-defined)
W
weight function with integrand
S
singularities can be more readily integrated
P
points of special difficulty can be supplied
I
infinite range of integration
O
oscillatory weight function, cos or sin
F
Fourier integral
C
Cauchy principal value
The algorithms are built on pairs of quadrature rules, a higher order rule and a lower order rule. The higher order rule is used to compute the best approximation to an integral over a small range. The difference between the results of the higher order rule and the lower order rule gives an estimate of the error in the approximation.
All subroutines present a similar interface. They accept several optional input and output arguments but, in their simpler form, all integrators without weight functions may be called as
call integrator(f, a, b, IntVal)
where f is a real or complex function f(x,[args]) as described in Integrable functions, IntVal is the value returned with an approximation to the integral of f over the (possibly infinite) interval (a,b).
There are available the following integration routines:
Subroutine QNG for non-adaptive integration
The subroutine qng is a simple non-adaptive automatic integrator, based on a sequence of rules with increasing degree of algebraic precision (Patterson, 1968). It applies the Gauss-Kronrod 10-point, 21-point, 43-point and 87-point integration rules in succession until an estimate of the integral is achieved within the desired absolute and relative error limits. Each successive approximation reuses the previous function evaluations.
Examples of use
1program ex_qng
2USE numfor, only: dp, zero, m_pi, str, center, qng
3implicit none
4
5 real(dp) :: err
6integer :: N
7 real(dp) :: w
8
9 real(dp) :: Integ1
10complex(dp) :: Integ2
11intrinsic dsin
12 print "(A)", center(" Integrate sin(x) between 0 and pi ", 70, '-')
28 print "(A)", '\int \cos(w \sin(x)) dx = '//str(integ2)//" (Error="//str(err)//") with N = "//str(n)
29! that prints:
30!-------------------- Integrate a complex function --------------------
31! \int \cos(w \sin(x)) dx = (0.062787400402-0.2226721656122j) (Error=2.8652541230259) with N = 87
32
33contains
35function fquad451(x) result(y)
36implicit none
37 real(dp) :: y
38 real(dp), intent(IN) :: x
39 y = sqrt(x) * log(x)
40end function fquad451
41
43function fquad452wc(x, w) result(y)
44implicit none
45complex(dp) :: y
46 real(dp), intent(IN) :: x
47 real(dp), dimension(:), intent(IN) :: w
48 y = cmplx(cos(w(1) * sin(x)), sin(w(1) * sin(x)), kind=dp)
49end function fquad452wc
50
51end program ex_qng
Subroutine QAG for simple adaptive integration
The subroutine qag uses a global adaptive scheme in which the interval is divided and at each step the integral is calculated for each subinterval, and the one with the larger error is bisected. This scheme is recusively applied and the most difficult points are calculated in finer grids.
Examples of use
1program ex_qag
2USE numfor, only: dp, zero, m_pi, str, center, qag
3implicit none
4
5 real(dp) :: err
6integer :: N
7 real(dp) :: w
8
9 real(dp) :: Integ1
10complex(dp) :: Integ2
11 real(dp), parameter :: epsrel = 1.e-3_8
12
13intrinsic dsin
14 print "(A)", center(" Integrate sin(x) between 0 and pi ", 70, '-')
34 print "(A)", '\int \cos(w \sin(x)) dx = '//str(integ2)//" (Error="//str(err)//") with N = "//str(n)
35! that prints:
36!-------------------- Integrate a complex function --------------------
37! \int \cos(w \sin(x)) dx = (0.062787390876-0.2226721893626j) (Error=1.7375840100087e-08) with N = 427
38
39contains
41function fquad451(x) result(y)
42implicit none
43 real(dp) :: y
44 real(dp), intent(IN) :: x
45 y = sqrt(x) * log(x)
46end function fquad451
47
49function fquad452wc(x, w) result(y)
50implicit none
51complex(dp) :: y
52 real(dp), intent(IN) :: x
53 real(dp), dimension(:), intent(IN) :: w
54 y = cmplx(cos(w(1) * sin(x)), sin(w(1) * sin(x)), kind=dp)
55end function fquad452wc
56
57end program ex_qag
Subroutine QAGS for general integration with singularities
Subroutine qags is a global adaptive algorithm with bisection of the integration interval and a Wynn-epsilon algorithm to extrapolate and speed-up the convergence of the integral. This routine is able to integrate functions with singularities of many types.
The limits of integration may be finite or infinite. By default it uses a Gauss-Kronrod rule of 21 points for finite limits, and a 15-points rule for infinite limits. The rule may be given to the routine as an argument.
The integration over the infinite intervals are is performed by means of mappings to the semi-open interval .
27 print "(A)", ∞'integrate( \log(x)/(1 + w x^2), 0, +) = '//str(integ1)//" (Error="//str(err)//") with N = "//str(n)
28! integrate( \log(x)/(1 + w x^2), 0, +∞) = -0.3616892188416 (Error=2.170181735946e-07) with N = 399
29contains
30
32function fquad453(x) result(y)
33implicit none
34 real(dp) :: y
35 real(dp), intent(IN) :: x
36 y = log(x) / sqrt(x)
37end function fquad453
38
40function fquad455w(x, w) result(y)
41implicit none
42 real(dp) :: y
43 real(dp), intent(IN) :: x
44 real(dp), dimension(:), intent(IN) :: w
45 y = log(x) / (1 + w(1) * x**2)
46end function fquad455w
47end program ex_qags
Subroutine QAGP integration with known singular points
Subroutine qagp uses the same strategy than qags to integrate a function that presents singularities in the interior of the integration domain. The user has to supply an array with the points where difficulties arise.
16 print "(A)", 'integrate(cos(pi x /2 ) / sqrt(x), x, 0, inf ) = '//str(integ1)//" (Error="//str(err)//") with N = "//str(n)
17! integrate(cos(pi x /2 ) / sqrt(x), x, 0, inf ) = 0.9999969531148 (Error=0.0005923419178) with N = 380
18contains
20function fquad457(x) result(y)
21implicit none
22 real(dp) :: y
23 real(dp), intent(IN) :: x
24 y = 0._8
25IF (x > 0) y = 1.0_8 / sqrt(x)
26end function fquad457
27
28end program ex_qawf
Subroutine QAWS for integration of singular functions
Subroutine qaws computes the integral of a function f multiplied by a weight function with an algebraic-logarithmic singularity chosen according to the flag flgw,
flgw
Weight function
1
2
3
4
The points are the limits of the integration domain.
14 print "(A)", 'integrate(1/(x(5 x^3 + 6), -1, 5)) = '//str(integ1)//" (Error="//str(err)//") with N = "//str(n)
15! integrate(1/(x(5 x^3 + 6), -1, 5)) = -0.0899440069584 (Error=1.1852922354142e-06) with N = 215
16contains
17
19function fquad459(x) result(y)
20implicit none
21 real(dp) :: y
22 real(dp), intent(IN) :: x
23 y = 1 / (5 * x**3 + 6)
24end function fquad459
25
26end program ex_qaws
Use of the extra parameter info
Most adaptive routines allow for an optional input/output argument info. It is mainly used to pass information on details of the calculations. This argument is a variable of the type d_qp_extra for integration of real functions, and of the type c_qp_extra for integration of complex functions.
Following Piessend et al we illustrate one of its use considering the integral
As we can see, the general integrator qags is able to integrate this singular function but needs several function evaluations, with an important error in the vicinity of . We can use this additional information and replace the routine qags by qagp. It only need to change line number XX to: