Skip to content

Commit f063146

Browse files
authored
Merge pull request #146 from nshaffer/dev-quadrature
First steps toward quadrature
2 parents 7397e96 + 5e8294c commit f063146

8 files changed

+546
-0
lines changed

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ set(fppFiles
77
stdlib_experimental_stats.fypp
88
stdlib_experimental_stats_mean.fypp
99
stdlib_experimental_stats_var.fypp
10+
stdlib_experimental_quadrature.fypp
11+
stdlib_experimental_quadrature_trapz.fypp
1012
)
1113

1214

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#:include "common.fypp"
2+
3+
module stdlib_experimental_quadrature
4+
use stdlib_experimental_kinds, only: sp, dp, qp
5+
6+
implicit none
7+
8+
private
9+
10+
! array integration
11+
public :: trapz
12+
public :: trapz_weights
13+
public :: simps
14+
public :: simps_weights
15+
16+
17+
interface trapz
18+
#:for KIND in REAL_KINDS
19+
pure module function trapz_dx_${KIND}$(y, dx) result(integral)
20+
real(${KIND}$), dimension(:), intent(in) :: y
21+
real(${KIND}$), intent(in) :: dx
22+
real(${KIND}$) :: integral
23+
end function trapz_dx_${KIND}$
24+
#:endfor
25+
#:for KIND in REAL_KINDS
26+
pure module function trapz_x_${KIND}$(y, x) result(integral)
27+
real(${KIND}$), dimension(:), intent(in) :: y
28+
real(${KIND}$), dimension(size(y)), intent(in) :: x
29+
real(${KIND}$) :: integral
30+
end function trapz_x_${KIND}$
31+
#:endfor
32+
end interface trapz
33+
34+
35+
interface trapz_weights
36+
#:for KIND in REAL_KINDS
37+
pure module function trapz_weights_${KIND}$(x) result(w)
38+
real(${KIND}$), dimension(:), intent(in) :: x
39+
real(${KIND}$), dimension(size(x)) :: w
40+
end function trapz_weights_${KIND}$
41+
#:endfor
42+
end interface trapz_weights
43+
44+
45+
interface simps
46+
#:for KIND in REAL_KINDS
47+
pure module function simps_dx_${KIND}$(y, dx, even) result(integral)
48+
real(${KIND}$), dimension(:), intent(in) :: y
49+
real(${KIND}$), intent(in) :: dx
50+
integer, intent(in), optional :: even
51+
real(${KIND}$) :: integral
52+
end function simps_dx_${KIND}$
53+
#:endfor
54+
#:for KIND in REAL_KINDS
55+
pure module function simps_x_${KIND}$(y, x, even) result(integral)
56+
real(${KIND}$), dimension(:), intent(in) :: y
57+
real(${KIND}$), dimension(size(y)), intent(in) :: x
58+
integer, intent(in), optional :: even
59+
real(${KIND}$) :: integral
60+
end function simps_x_${KIND}$
61+
#:endfor
62+
end interface simps
63+
64+
65+
interface simps_weights
66+
#:for KIND in REAL_KINDS
67+
pure module function simps_weights_${KIND}$(x, even) result(w)
68+
real(${KIND}$), dimension(:), intent(in) :: x
69+
real(${KIND}$), dimension(size(x)) :: w
70+
integer, intent(in), optional :: even
71+
end function simps_weights_${KIND}$
72+
#:endfor
73+
end interface simps_weights
74+
75+
end module stdlib_experimental_quadrature

src/stdlib_experimental_quadrature.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Numerical integration
2+
3+
## Implemented
4+
5+
* `trapz`
6+
* `trapz_weights`
7+
8+
## `trapz` - integrate sampled values using trapezoidal rule
9+
10+
Returns the trapezoidal rule integral of an array `y` representing discrete samples of a function. The integral is computed assuming either equidistant abscissas with spacing `dx` or arbitary abscissas `x`.
11+
12+
### Syntax
13+
14+
`result = trapz(y, x)`
15+
16+
`result = trapz(y, dx)`
17+
18+
### Arguments
19+
20+
`y`: Shall be a rank-one array of type `real`.
21+
22+
`x`: Shall be a rank-one array of type `real` having the same kind and size as `y`.
23+
24+
`dx`: Shall be a scalar of type `real` having the same kind as `y`.
25+
26+
### Return value
27+
28+
The result is a scalar of type `real` having the same kind as `y`.
29+
30+
If the size of `y` is zero or one, the result is zero.
31+
32+
### Example
33+
34+
```fortran
35+
program demo_trapz
36+
use stdlib_experimental_quadrature, only: trapz
37+
implicit none
38+
real :: x(5) = [0., 1., 2., 3., 4.]
39+
real :: y(5) = x**2
40+
print *, trapz(y, x)
41+
! 22.0
42+
print *, trapz(y, 0.5)
43+
! 11.0
44+
end program
45+
```
46+
47+
## `trapz_weights` - trapezoidal rule weights for given abscissas
48+
49+
Given an array of abscissas `x`, computes the array of weights `w` such that if `y` represented function values tabulated at `x`, then `sum(w*y)` produces a trapezoidal rule approximation to the integral.
50+
51+
### Syntax
52+
53+
`result = trapz_weights(x)`
54+
55+
### Arguments
56+
57+
`x`: Shall be a rank-one array of type `real`.
58+
59+
### Return value
60+
61+
The result is a `real` array with the same size and kind as `x`.
62+
63+
If the size of `x` is one, then the sole element of the result is zero.
64+
65+
### Example
66+
67+
```fortran
68+
program demo_trapz_weights
69+
use stdlib_experimental_quadrature, only: trapz_weights
70+
implicit none
71+
real :: x(5) = [0., 1., 2., 3., 4.]
72+
real :: y(5) = x**2
73+
real :: w(5)
74+
w = trapz_weight(x)
75+
print *, dot_product(w, y)
76+
! 22.0
77+
end program
78+
79+
```
80+
81+
# `simps` - integrate sampled values using Simpson's rule
82+
83+
Returns the Simpson's rule integral of an array `y` representing discrete samples of a function. The integral is computed assuming either equidistant abscissas with spacing `dx` or arbitary abscissas `x`.
84+
85+
Simpson's rule is defined for odd-length arrays only. For even-length arrays, an optional argument `even` may be used to specify at which index to replace Simpson's rule with Simpson's 3/8 rule. The 3/8 rule will be used for the array section `y(even:even+4)` and the ordinary Simpon's rule will be used elsewhere.
86+
87+
### Syntax
88+
89+
`result = simps(y, x [, even])`
90+
91+
`result = simps(y, dx [, even])`
92+
93+
### Arguments
94+
95+
`y`: Shall be a rank-one array of type `real`.
96+
97+
`x`: Shall be a rank-one array of type `real` having the same kind and size as `y`.
98+
99+
`dx`: Shall be a scalar of type `real` having the same kind as `y`.
100+
101+
`even`: (Optional) Shall be a scalar integer of default kind. Its default value is `1`.
102+
103+
### Return value
104+
105+
The result is a scalar of type `real` having the same kind as `y`.
106+
107+
If the size of `y` is zero or one, the result is zero.
108+
109+
If the size of `y` is two, the result is the same as if `trapz` had been called instead, regardless of the value of `even`.
110+
111+
### Example
112+
113+
TBD
114+
115+
# `simps_weights` - Simpson's rule weights for given abscissas
116+
117+
Given an array of abscissas `x`, computes the array of weights `w` such that if `y` represented function values tabulated at `x`, then `sum(w*y)` produces a Simpson's rule approximation to the integral.
118+
119+
Simpson's rule is defined for odd-length arrays only. For even-length arrays, an optional argument `even` may be used to specify at which index to replace Simpson's rule with Simpson's 3/8 rule. The 3/8 rule will be used for the array section `x(even:even+4)` and the ordinary Simpon's rule will be used elsewhere.
120+
121+
### Syntax
122+
123+
`result = simps_weights(x [, even])`
124+
125+
### Arguments
126+
127+
`x`: Shall be a rank-one array of type `real`.
128+
129+
`even`: (Optional) Shall be a scalar integer of default kind. Its default value is `1`.
130+
131+
### Return value
132+
133+
The result is a `real` array with the same size and kind as `x`.
134+
135+
If the size of `x` is one, then the sole element of the result is zero.
136+
137+
If the size of `x` is two, then the result is the same as if `trapz_weights` had been called instead.
138+
139+
### Example
140+
141+
TBD
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#:include "common.fypp"
2+
3+
submodule (stdlib_experimental_quadrature) stdlib_experimental_quadrature_trapz
4+
5+
implicit none
6+
7+
contains
8+
9+
#:for KIND in REAL_KINDS
10+
11+
pure module function trapz_dx_${KIND}$(y, dx) result(integral)
12+
real(${KIND}$), dimension(:), intent(in) :: y
13+
real(${KIND}$), intent(in) :: dx
14+
real(${KIND}$) :: integral
15+
16+
integer :: n
17+
18+
n = size(y)
19+
20+
select case (n)
21+
case (0:1)
22+
integral = 0.0_${KIND}$
23+
case (2)
24+
integral = 0.5_${KIND}$*dx*(y(1) + y(2))
25+
case default
26+
integral = dx*(sum(y(2:n-1)) + 0.5_${KIND}$*(y(1) + y(n)))
27+
end select
28+
end function trapz_dx_${KIND}$
29+
30+
#:endfor
31+
#:for KIND in REAL_KINDS
32+
33+
pure module function trapz_x_${KIND}$(y, x) result(integral)
34+
real(${KIND}$), dimension(:), intent(in) :: y
35+
real(${KIND}$), dimension(size(y)), intent(in) :: x
36+
real(${KIND}$) :: integral
37+
38+
integer :: i
39+
integer :: n
40+
41+
n = size(y)
42+
43+
select case (n)
44+
case (0:1)
45+
integral = 0.0_${KIND}$
46+
case (2)
47+
integral = 0.5_${KIND}$*(x(2) - x(1))*(y(1) + y(2))
48+
case default
49+
integral = 0.0_${KIND}$
50+
do i = 2, n
51+
integral = integral + (x(i) - x(i-1))*(y(i) + y(i-1))
52+
end do
53+
integral = 0.5_${KIND}$*integral
54+
end select
55+
end function trapz_x_${KIND}$
56+
57+
#:endfor
58+
#:for KIND in REAL_KINDS
59+
60+
pure module function trapz_weights_${KIND}$(x) result(w)
61+
real(${KIND}$), dimension(:), intent(in) :: x
62+
real(${KIND}$), dimension(size(x)) :: w
63+
64+
integer :: i
65+
integer :: n
66+
67+
n = size(x)
68+
69+
select case (n)
70+
case (0)
71+
! no action needed
72+
case (1)
73+
w(1) = 0.0_${KIND}$
74+
case (2)
75+
w = 0.5_${KIND}$*(x(2) - x(1))
76+
case default
77+
w(1) = 0.5_${KIND}$*(x(2) - x(1))
78+
w(n) = 0.5_${KIND}$*(x(n) - x(n-1))
79+
do i = 2, size(x)-1
80+
w(i) = 0.5_${KIND}$*(x(i+1) - x(i-1))
81+
end do
82+
end select
83+
end function trapz_weights_${KIND}$
84+
85+
#:endfor
86+
end submodule stdlib_experimental_quadrature_trapz

src/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_subdirectory(io)
1111
add_subdirectory(optval)
1212
add_subdirectory(stats)
1313
add_subdirectory(system)
14+
add_subdirectory(quadrature)
1415

1516
ADDTEST(always_skip)
1617
set_tests_properties(always_skip PROPERTIES SKIP_RETURN_CODE 77)

src/tests/quadrature/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ADDTEST(trapz)
2+

src/tests/quadrature/Makefile.manual

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
PROGS_SRC = test_trapz.f90
2+
3+
include ../Makefile.manual.test.mk

0 commit comments

Comments
 (0)