Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quadrature: spec tweaks & Simpson's rule #209

Merged
merged 20 commits into from
Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 36 additions & 14 deletions doc/specs/stdlib_experimental_quadrature.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,26 +76,26 @@ program demo_trapz_weights
real :: x(5) = [0., 1., 2., 3., 4.]
real :: y(5) = x**2
real :: w(5)
w = trapz_weight(x)
print *, dot_product(w, y)
w = trapz_weights(x)
print *, sum(w*y)
! 22.0
end program demo_trapz_weights

```

## `simps` - integrate sampled values using Simpson's rule (to be implemented)
## `simps` - integrate sampled values using Simpson's rule

### Description

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`.

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.
Simpson's ordinary ("1/3") rule is used for odd-length arrays. For even-length arrays, Simpson's 3/8 rule is also utilized in a way that depends on the value of `even`. If `even` is negative (positive), the 3/8 rule is used at the beginning (end) of the array. If `even` is zero or not present, the result is as if the 3/8 rule were first used at the beginning of the array, then at the end of the array, and these two results were averaged.

### Syntax

`result = simps(y, x [, even])`
`result = [[stdlib_experimental_quadrature(module):simps(interface)]](y, x [, even])`

`result = simps(y, dx [, even])`
`result = [[stdlib_experimental_quadrature(module):simps(interface)]](y, dx [, even])`

### Arguments

Expand All @@ -105,37 +105,48 @@ Simpson's rule is defined for odd-length arrays only. For even-length arrays, an

`dx`: Shall be a scalar of type `real` having the same kind as `y`.

`even`: (Optional) Shall be a scalar integer of default kind. Its default value is `1`.
`even`: (Optional) Shall be a default-kind `integer`.

### Return value

The result is a scalar of type `real` having the same kind as `y`.

If the size of `y` is zero or one, the result is zero.

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`.
If the size of `y` is two, the result is the same as if `trapz` had been called instead.

### Example

TBD
```fortran
program demo_simps
use stdlib_experimental_quadrature, only: simps
implicit none
real :: x(5) = [0., 1., 2., 3., 4.]
real :: y(5) = 3.*x**2
print *, simps(y, x)
! 64.0
print *, simps(y, 0.5)
! 32.0
end program demo_simps
```

## `simps_weights` - Simpson's rule weights for given abscissas (to be implemented)
## `simps_weights` - Simpson's rule weights for given abscissas

### Description

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.

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.
Simpson's ordinary ("1/3") rule is used for odd-length arrays. For even-length arrays, Simpson's 3/8 rule is also utilized in a way that depends on the value of `even`. If `even` is negative (positive), the 3/8 rule is used at the beginning (end) of the array and the 1/3 rule used elsewhere. If `even` is zero or not present, the result is as if the 3/8 rule were first used at the beginning of the array, then at the end of the array, and then these two results were averaged.

### Syntax

`result = simps_weights(x [, even])`
`result = [[stdlib_experimental_quadrature(module):simps_weights(interface)]](x [, even])`

### Arguments

`x`: Shall be a rank-one array of type `real`.

`even`: (Optional) Shall be a scalar integer of default kind. Its default value is `1`.
`even`: (Optional) Shall be a default-kind `integer`.

### Return value

Expand All @@ -147,4 +158,15 @@ If the size of `x` is two, then the result is the same as if `trapz_weights` had

### Example

TBD
```fortran
program demo_simps_weights
use stdlib_experimental_quadrature, only: simps_weights
implicit none
real :: x(5) = [0., 1., 2., 3., 4.]
real :: y(5) = 3.*x**2
real :: w(5)
w = simps_weights(x)
print *, sum(w*y)
! 64.0
end program demo_simps_weights
```
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(fppFiles
stdlib_experimental_stats_var.fypp
stdlib_experimental_quadrature.fypp
stdlib_experimental_quadrature_trapz.fypp
stdlib_experimental_quadrature_simps.fypp
)


Expand Down
88 changes: 53 additions & 35 deletions src/stdlib_experimental_quadrature.fypp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#:include "common.fypp"

module stdlib_experimental_quadrature
!! ([Specification](../page/specs/stdlib_experimental_quadrature.html#description))
use stdlib_experimental_kinds, only: sp, dp, qp
Expand All @@ -18,63 +17,82 @@ module stdlib_experimental_quadrature
interface trapz
!! Integrates sampled values using trapezoidal rule
!! ([Specification](../page/specs/stdlib_experimental_quadrature.html#description))
#:for KIND in REAL_KINDS
pure module function trapz_dx_${KIND}$(y, dx) result(integral)
real(${KIND}$), dimension(:), intent(in) :: y
real(${KIND}$), intent(in) :: dx
real(${KIND}$) :: integral
end function trapz_dx_${KIND}$
#:for k1, t1 in REAL_KINDS_TYPES
pure module function trapz_dx_${k1}$(y, dx) result(integral)
${t1}$, dimension(:), intent(in) :: y
${t1}$, intent(in) :: dx
${t1}$ :: integral
end function trapz_dx_${k1}$
#:endfor
#:for KIND in REAL_KINDS
pure module function trapz_x_${KIND}$(y, x) result(integral)
real(${KIND}$), dimension(:), intent(in) :: y
real(${KIND}$), dimension(size(y)), intent(in) :: x
real(${KIND}$) :: integral
end function trapz_x_${KIND}$
#:for k1, t1 in REAL_KINDS_TYPES
module function trapz_x_${k1}$(y, x) result(integral)
${t1}$, dimension(:), intent(in) :: y
${t1}$, dimension(:), intent(in) :: x
${t1}$ :: integral
end function trapz_x_${k1}$
#:endfor
end interface trapz


interface trapz_weights
!! Integrates sampled values using trapezoidal rule weights for given abscissas
!! ([Specification](../page/specs/stdlib_experimental_quadrature.html#description_1))
#:for KIND in REAL_KINDS
pure module function trapz_weights_${KIND}$(x) result(w)
real(${KIND}$), dimension(:), intent(in) :: x
real(${KIND}$), dimension(size(x)) :: w
end function trapz_weights_${KIND}$
#:for k1, t1 in REAL_KINDS_TYPES
pure module function trapz_weights_${k1}$(x) result(w)
${t1}$, dimension(:), intent(in) :: x
${t1}$, dimension(size(x)) :: w
end function trapz_weights_${k1}$
#:endfor
end interface trapz_weights


interface simps
#:for KIND in REAL_KINDS
pure module function simps_dx_${KIND}$(y, dx, even) result(integral)
real(${KIND}$), dimension(:), intent(in) :: y
real(${KIND}$), intent(in) :: dx
!! Integrates sampled values using Simpson's rule
!! ([Specification](../page/specs/stdlib_experimental_quadrature.html#description_3))
! "recursive" is an implementation detail
#:for k1, t1 in REAL_KINDS_TYPES
pure recursive module function simps_dx_${k1}$(y, dx, even) result(integral)
${t1}$, dimension(:), intent(in) :: y
${t1}$, intent(in) :: dx
integer, intent(in), optional :: even
real(${KIND}$) :: integral
end function simps_dx_${KIND}$
${t1}$ :: integral
end function simps_dx_${k1}$
#:endfor
#:for KIND in REAL_KINDS
pure module function simps_x_${KIND}$(y, x, even) result(integral)
real(${KIND}$), dimension(:), intent(in) :: y
real(${KIND}$), dimension(size(y)), intent(in) :: x
#:for k1, t1 in REAL_KINDS_TYPES
recursive module function simps_x_${k1}$(y, x, even) result(integral)
${t1}$, dimension(:), intent(in) :: y
${t1}$, dimension(:), intent(in) :: x
integer, intent(in), optional :: even
real(${KIND}$) :: integral
end function simps_x_${KIND}$
${t1}$ :: integral
end function simps_x_${k1}$
#:endfor
end interface simps


interface simps_weights
#:for KIND in REAL_KINDS
pure module function simps_weights_${KIND}$(x, even) result(w)
real(${KIND}$), dimension(:), intent(in) :: x
real(${KIND}$), dimension(size(x)) :: w
!! Integrates sampled values using trapezoidal rule weights for given abscissas
!! ([Specification](../page/specs/stdlib_experimental_quadrature.html#description_3))
#:for k1, t1 in REAL_KINDS_TYPES
pure recursive module function simps_weights_${k1}$(x, even) result(w)
${t1}$, dimension(:), intent(in) :: x
integer, intent(in), optional :: even
end function simps_weights_${KIND}$
${t1}$, dimension(size(x)) :: w
end function simps_weights_${k1}$
#:endfor
end interface simps_weights


! Interface for a simple f(x)-style integrand function.
! Could become fancier as we learn about the performance
! ramifications of different ways to do callbacks.
abstract interface
#:for k1, t1 in REAL_KINDS_TYPES
pure function integrand_${k1}$(x) result(f)
import :: ${k1}$
${t1}$, intent(in) :: x
${t1}$ :: f
end function integrand_${k1}$
#:endfor
end interface

end module stdlib_experimental_quadrature
Loading