From 97ce9d30aaf5f0b174df9ffb0f83f4453bc3df6f Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Thu, 30 Jan 2020 00:11:37 -0700 Subject: [PATCH 01/10] initial commit -- trapz --- src/CMakeLists.txt | 2 + src/stdlib_experimental_quadrature.fypp | 37 +++ src/stdlib_experimental_quadrature_trapz.fypp | 87 +++++++ src/tests/CMakeLists.txt | 1 + src/tests/quadrature/CMakeLists.txt | 2 + src/tests/quadrature/Makefile.manual | 3 + src/tests/quadrature/test_trapz.f90 | 236 ++++++++++++++++++ 7 files changed, 368 insertions(+) create mode 100644 src/stdlib_experimental_quadrature.fypp create mode 100644 src/stdlib_experimental_quadrature_trapz.fypp create mode 100644 src/tests/quadrature/CMakeLists.txt create mode 100644 src/tests/quadrature/Makefile.manual create mode 100644 src/tests/quadrature/test_trapz.f90 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90bd8e1ed..480e2737a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ set(fppFiles stdlib_experimental_io.fypp stdlib_experimental_stats.fypp stdlib_experimental_stats_mean.fypp + stdlib_experimental_quadrature.fypp + stdlib_experimental_quadrature_trapz.fypp ) diff --git a/src/stdlib_experimental_quadrature.fypp b/src/stdlib_experimental_quadrature.fypp new file mode 100644 index 000000000..e049eaab9 --- /dev/null +++ b/src/stdlib_experimental_quadrature.fypp @@ -0,0 +1,37 @@ +#:include "common.fypp" + +module stdlib_experimental_quadrature + use stdlib_experimental_kinds, only: sp, dp, qp + + implicit none + + private + public :: trapz, trapz_weights + + interface trapz + #: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}$ + #: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}$ + #:endfor + end interface trapz + + interface trapz_weights + #: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}$ + #:endfor + end interface trapz_weights + +end module stdlib_experimental_quadrature diff --git a/src/stdlib_experimental_quadrature_trapz.fypp b/src/stdlib_experimental_quadrature_trapz.fypp new file mode 100644 index 000000000..8bdb91cbe --- /dev/null +++ b/src/stdlib_experimental_quadrature_trapz.fypp @@ -0,0 +1,87 @@ +#:include "common.fypp" + +submodule (stdlib_experimental_quadrature) stdlib_experimental_quadrature_trapz + use stdlib_experimental_kinds, only: sp, dp, qp + + implicit none + +contains + + #: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 + + integer :: n + + n = size(y) + + select case (n) + case (0:1) + integral = 0.0_${KIND}$ + case (2) + integral = 0.5_${KIND}$*dx*(y(1) + y(2)) + case default + integral = dx*(sum(y(2:n-1)) + 0.5_${KIND}$*(y(1) + y(n))) + end select + end function trapz_dx_${KIND}$ + + #: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 + + integer :: i + integer :: n + + n = size(y) + + select case (n) + case (0:1) + integral = 0.0_${KIND}$ + case (2) + integral = 0.5_${KIND}$*(x(2) - x(1))*(y(1) + y(2)) + case default + integral = 0.0_${KIND}$ + do i = 2, n + integral = integral + (x(i) - x(i-1))*(y(i) + y(i-1)) + end do + integral = 0.5_${KIND}$*integral + end select + end function trapz_x_${KIND}$ + + #:endfor + #: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 + + integer :: i + integer :: n + + n = size(x) + + select case (n) + case (0) + ! no action needed + case (1) + w(1) = 0.0_${KIND}$ + case (2) + w = 0.5_${KIND}$*(x(2) - x(1)) + case default + w(1) = 0.5_${KIND}$*(x(2) - x(1)) + w(n) = 0.5_${KIND}$*(x(n) - x(n-1)) + do i = 2, size(x)-1 + w(i) = 0.5_${KIND}$*(x(i+1) - x(i-1)) + end do + end select + end function trapz_weights_${KIND}$ + +#:endfor +end submodule stdlib_experimental_quadrature_trapz diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index df5bd0a09..f3b7d434c 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(io) add_subdirectory(optval) add_subdirectory(stats) add_subdirectory(system) +add_subdirectory(quadrature) ADDTEST(always_skip) set_tests_properties(always_skip PROPERTIES SKIP_RETURN_CODE 77) diff --git a/src/tests/quadrature/CMakeLists.txt b/src/tests/quadrature/CMakeLists.txt new file mode 100644 index 000000000..08f1ce4c6 --- /dev/null +++ b/src/tests/quadrature/CMakeLists.txt @@ -0,0 +1,2 @@ +ADDTEST(trapz) + diff --git a/src/tests/quadrature/Makefile.manual b/src/tests/quadrature/Makefile.manual new file mode 100644 index 000000000..83061a7bf --- /dev/null +++ b/src/tests/quadrature/Makefile.manual @@ -0,0 +1,3 @@ +PROGS_SRC = test_trapz.f90 + +include ../Makefile.manual.test.mk diff --git a/src/tests/quadrature/test_trapz.f90 b/src/tests/quadrature/test_trapz.f90 new file mode 100644 index 000000000..b275643e8 --- /dev/null +++ b/src/tests/quadrature/test_trapz.f90 @@ -0,0 +1,236 @@ +program test_trapz + use stdlib_experimental_kinds, only: sp, dp, qp + use stdlib_experimental_error, only: assert + use stdlib_experimental_quadrature, only: trapz, trapz_weights + + implicit none + + call test_trapz_sp + call test_trapz_dp + call test_trapz_qp + + call test_trapz_weights_sp + call test_trapz_weights_dp + call test_trapz_weights_qp + + call test_trapz_zero_sp + call test_trapz_zero_dp + call test_trapz_zero_qp + +contains + + subroutine test_trapz_sp + integer, parameter :: n = 17 + real(sp), dimension(n) :: y + real(sp), dimension(n) :: x + real(sp) :: val + real(sp) :: ans + integer :: i + + print *, "test_trapz_sp" + + y = [(real(i-1, sp), i = 1, n)] + + val = trapz(y, 1.0_sp) + ans = 128.0_sp + call assert(val == ans) + + val = trapz(y, 0.5_sp) + ans = 64.0_sp + call assert(val == ans) + + x = [((i-1)*4.0_sp/real(n-1, sp), i = 1, n)] + val = trapz(y, x) + ans = 32.0_sp + call assert(val == ans) + + x = y**2 + val = trapz(y, x) + ans = 2728.0_sp + call assert(val == ans) + end subroutine test_trapz_sp + + subroutine test_trapz_dp + integer, parameter :: n = 17 + real(dp), dimension(n) :: y + real(dp), dimension(n) :: x + real(dp) :: val + real(dp) :: ans + integer :: i + + print *, "test_trapz_dp" + + y = [(real(i-1, dp), i = 1, n)] + + val = trapz(y, 1.0_dp) + ans = 128.0_dp + call assert(val == ans) + + val = trapz(y, 0.5_dp) + ans = 64.0_dp + call assert(val == ans) + + x = [((i-1)*4.0_dp/real(n-1, dp), i = 1, n)] + val = trapz(y, x) + ans = 32.0_dp + call assert(val == ans) + + x = y**2 + val = trapz(y, x) + ans = 2728.0_sp + call assert(val == ans) + end subroutine test_trapz_dp + + + subroutine test_trapz_qp + integer, parameter :: n = 17 + real(qp), dimension(n) :: y + real(qp), dimension(n) :: x + real(qp) :: val + real(qp) :: ans + integer :: i + + print *, "test_trapz_qp" + + y = [(real(i-1, qp), i = 1, n)] + + val = trapz(y, 1.0_qp) + ans = 128.0_qp + call assert(val == ans) + + val = trapz(y, 0.5_qp) + ans = 64.0_qp + call assert(val == ans) + + x = [((i-1)*4.0_qp/real(n-1, qp), i = 1, n)] + val = trapz(y, x) + ans = 32.0_qp + call assert(val == ans) + + x = y**2 + val = trapz(y, x) + ans = 2728.0_qp + call assert(val == ans) + end subroutine test_trapz_qp + + + subroutine test_trapz_weights_sp + integer, parameter :: n = 17 + real(sp), dimension(n) :: y + real(sp), dimension(n) :: x + real(sp), dimension(n) :: w + integer :: i + real(sp) :: val + real(sp) :: ans + + print *, "test_trapz_weights_sp" + + y = [(real(i-1, sp), i = 1, n)] + + x = y + w = trapz_weights(x) + val = dot_product(w, y) + ans = trapz(y, x) + call assert(val == ans) + + x = y**2 + w = trapz_weights(x) + val = dot_product(w, y) + ans = trapz(y, x) + call assert(val == ans) + + end subroutine test_trapz_weights_sp + + + subroutine test_trapz_weights_dp + integer, parameter :: n = 17 + real(dp), dimension(n) :: y + real(dp), dimension(n) :: x + real(dp), dimension(n) :: w + integer :: i + real(dp) :: val + real(dp) :: ans + + print *, "test_trapz_weights_dp" + + y = [(real(i-1, dp), i = 1, n)] + + x = y + w = trapz_weights(x) + val = dot_product(w, y) + ans = trapz(y, x) + call assert(val == ans) + + x = y**2 + w = trapz_weights(x) + val = dot_product(w, y) + ans = trapz(y, x) + call assert(val == ans) + + end subroutine test_trapz_weights_dp + + + subroutine test_trapz_weights_qp + integer, parameter :: n = 17 + real(qp), dimension(n) :: y + real(qp), dimension(n) :: x + real(qp), dimension(n) :: w + integer :: i + real(qp) :: val + real(qp) :: ans + + print *, "test_trapz_weights_qp" + + y = [(real(i-1, qp), i = 1, n)] + + x = y + w = trapz_weights(x) + val = dot_product(w, y) + ans = trapz(y, x) + call assert(val == ans) + + x = y**2 + w = trapz_weights(x) + val = dot_product(w, y) + ans = trapz(y, x) + call assert(val == ans) + + end subroutine test_trapz_weights_qp + + + subroutine test_trapz_zero_sp + real(sp), dimension(0) :: a + + print *, "test_trapz_zero_sp" + + call assert(trapz(a, 1.0_sp) == 0.0_sp) + call assert(trapz([1.0_sp], 1.0_sp) == 0.0_sp) + call assert(trapz(a, a) == 0.0_sp) + call assert(trapz([1.0_sp], [1.0_sp]) == 0.0_sp) + end subroutine test_trapz_zero_sp + + + subroutine test_trapz_zero_dp + real(dp), dimension(0) :: a + + print *, "test_trapz_zero_dp" + + call assert(trapz(a, 1.0_dp) == 0.0_dp) + call assert(trapz([1.0_dp], 1.0_dp) == 0.0_dp) + call assert(trapz(a, a) == 0.0_dp) + call assert(trapz([1.0_dp], [1.0_dp]) == 0.0_dp) + end subroutine test_trapz_zero_dp + + + subroutine test_trapz_zero_qp + real(qp), dimension(0) :: a + + print *, "test_trapz_zero_qp" + + call assert(trapz(a, 1.0_qp) == 0.0_qp) + call assert(trapz([1.0_qp], 1.0_qp) == 0.0_qp) + call assert(trapz(a, a) == 0.0_qp) + call assert(trapz([1.0_qp], [1.0_qp]) == 0.0_qp) + end subroutine test_trapz_zero_qp + +end program test_trapz From 77a31aebb97e7dec5b5ca4a9e3cf088f37bfe037 Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Thu, 30 Jan 2020 00:18:28 -0700 Subject: [PATCH 02/10] bugfix? redundant use stmt --- src/stdlib_experimental_quadrature_trapz.fypp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stdlib_experimental_quadrature_trapz.fypp b/src/stdlib_experimental_quadrature_trapz.fypp index 8bdb91cbe..0ea66fe5e 100644 --- a/src/stdlib_experimental_quadrature_trapz.fypp +++ b/src/stdlib_experimental_quadrature_trapz.fypp @@ -1,7 +1,6 @@ #:include "common.fypp" submodule (stdlib_experimental_quadrature) stdlib_experimental_quadrature_trapz - use stdlib_experimental_kinds, only: sp, dp, qp implicit none From 52386a6a95ecf3edc2dc9c9a6c1b62aaa64a6bcc Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Sun, 2 Feb 2020 08:26:56 -0700 Subject: [PATCH 03/10] Add simpson's rule API (not implemented) --- src/stdlib_experimental_quadrature.fypp | 40 ++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/stdlib_experimental_quadrature.fypp b/src/stdlib_experimental_quadrature.fypp index e049eaab9..ecb15840f 100644 --- a/src/stdlib_experimental_quadrature.fypp +++ b/src/stdlib_experimental_quadrature.fypp @@ -6,7 +6,13 @@ module stdlib_experimental_quadrature implicit none private - public :: trapz, trapz_weights + + ! array integration + public :: trapz + public :: trapz_weights + public :: simps + public :: simps_weights + interface trapz #:for KIND in REAL_KINDS @@ -25,6 +31,7 @@ module stdlib_experimental_quadrature #:endfor end interface trapz + interface trapz_weights #:for KIND in REAL_KINDS pure module function trapz_weights_${KIND}$(x) result(w) @@ -34,4 +41,35 @@ module stdlib_experimental_quadrature #: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 + integer, intent(in), optional :: even + real(${KIND}$) :: integral + end function simps_dx_${KIND}$ + #: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 + integer, intent(in), optional :: even + real(${KIND}$) :: integral + end function simps_x_${KIND}$ + #: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 + integer, intent(in), optional :: even + end function simps_weights_${KIND}$ + #:endfor + end interface simps_weights + end module stdlib_experimental_quadrature From b1fb2651ea1b04586baa0ee927ceb2c8fc04080a Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Wed, 5 Feb 2020 06:08:02 -0700 Subject: [PATCH 04/10] Add initial spec for trapz and trapz_weights --- src/stdlib_experimental_quadrature.md | 79 +++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/stdlib_experimental_quadrature.md diff --git a/src/stdlib_experimental_quadrature.md b/src/stdlib_experimental_quadrature.md new file mode 100644 index 000000000..4627f2cb9 --- /dev/null +++ b/src/stdlib_experimental_quadrature.md @@ -0,0 +1,79 @@ +# Numerical integration + +## Implemented + +* `trapz` +* `trapz_weights` + +## `trapz` - integrate sampled values using trapezoidal rule + +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`. + +### Syntax + +`result = trapz(y, x)` + +`result = trapz(y, dx)` + +### Arguments + +`y`: Shall be a rank-one array of type `real`. + +`x`: Shall be a rank-one array of type `real` having the same kind and size as `y`. + +`dx`: Shall be a scalar of type `real` having the same kind as `y`. + +### 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. + +### Example + +```fortran +program demo_trapz + use stdlib_experimental_quadrature, only: trapz + implicit none + real :: x(5) = [0., 1., 2., 3., 4.] + real :: y(5) = x**2 + print *, trapz(y, x) +! 22.0 + print *, trapz(y, 0.5) +! 11.0 +end program +``` + +## `trapz_weights` - compute trapezoidal rule weights for given abscissas + +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. + +### Syntax + +`result = trapz_weights(x)` + +### Arguments + +`x`: Shall be an array of type `real`. + +### Return value + +The result is a `real` array with the same size and kind as `x`. + +If the size of `x` is one, then the only element of the result is zero. + +### Example + +```fortran +program demo_trapz_weights + use stdlib_experimental_quadrature, only: trapz_weights + implicit none + 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) +! 22.0 +end program + +``` From 0b385e745b192d87b08146e49a8f44ad7e8f0794 Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Wed, 5 Feb 2020 06:34:10 -0700 Subject: [PATCH 05/10] Add spec for simps --- src/stdlib_experimental_quadrature.md | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/stdlib_experimental_quadrature.md b/src/stdlib_experimental_quadrature.md index 4627f2cb9..fb4e3e6b8 100644 --- a/src/stdlib_experimental_quadrature.md +++ b/src/stdlib_experimental_quadrature.md @@ -77,3 +77,39 @@ program demo_trapz_weights end program ``` + +# `simps` - integrate sampled values using Simpson's rule + +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 `u(even:even+4)` and the ordinary Simpon's rule will be used elsewhere. + +### Syntax + +`result = simps(y, x [, even])` + +`result = simps(y, dx [, even])` + +### Arguments + +`y`: Shall be a rank-one array of type `real`. + +`x`: Shall be a rank-one array of type `real` having the same kind and size as `y`. + +`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`. + +### 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 even, the result + +### Example + +TBD From 770671d74413baae48bc830cc40a2872b7b7291c Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Thu, 6 Feb 2020 06:33:54 -0700 Subject: [PATCH 06/10] typos --- src/stdlib_experimental_quadrature.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/stdlib_experimental_quadrature.md b/src/stdlib_experimental_quadrature.md index fb4e3e6b8..fc505d5f7 100644 --- a/src/stdlib_experimental_quadrature.md +++ b/src/stdlib_experimental_quadrature.md @@ -82,7 +82,7 @@ end program 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 `u(even:even+4)` and the ordinary Simpon's rule will be used elsewhere. +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. ### Syntax @@ -108,8 +108,6 @@ 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 even, the result - ### Example TBD From 8b6dcb7462f313f0f72844bc07e9d19440ddada2 Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Thu, 6 Feb 2020 06:42:23 -0700 Subject: [PATCH 07/10] minor wording changes --- src/stdlib_experimental_quadrature.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stdlib_experimental_quadrature.md b/src/stdlib_experimental_quadrature.md index fc505d5f7..31f9b445f 100644 --- a/src/stdlib_experimental_quadrature.md +++ b/src/stdlib_experimental_quadrature.md @@ -44,7 +44,7 @@ program demo_trapz end program ``` -## `trapz_weights` - compute trapezoidal rule weights for given abscissas +## `trapz_weights` - trapezoidal rule weights for given abscissas 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. @@ -54,13 +54,13 @@ Given an array of abscissas `x`, computes the array of weights `w` such that if ### Arguments -`x`: Shall be an array of type `real`. +`x`: Shall be a rank-one array of type `real`. ### Return value The result is a `real` array with the same size and kind as `x`. -If the size of `x` is one, then the only element of the result is zero. +If the size of `x` is one, then the sole element of the result is zero. ### Example From f7d732dc0315c17c86ba9494767bae32c1c521c4 Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Thu, 6 Feb 2020 06:42:31 -0700 Subject: [PATCH 08/10] add spec for simps_weights --- src/stdlib_experimental_quadrature.md | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/stdlib_experimental_quadrature.md b/src/stdlib_experimental_quadrature.md index 31f9b445f..c62638f64 100644 --- a/src/stdlib_experimental_quadrature.md +++ b/src/stdlib_experimental_quadrature.md @@ -111,3 +111,31 @@ If the size of `y` is two, the result is the same as if `trapz` had been called ### Example TBD + +# `simps_weights` - Simpson's rule weights for given abscissas + +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. + +### Syntax + +`result = simps_weights(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`. + +### Return value + +The result is a `real` array with the same size and kind as `x`. + +If the size of `x` is one, then the sole element of the result is zero. + +If the size of `x` is two, then the result is the same as if `trapz_weights` had been called instead. + +### Example + +TBD From d1c91ecc56f244176d0fe386eb71dd6bdfdbae92 Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Fri, 7 Feb 2020 06:35:52 -0700 Subject: [PATCH 09/10] replace f.p. equality checks with tolerance checks --- src/tests/quadrature/test_trapz.f90 | 84 ++++++++++++++--------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/tests/quadrature/test_trapz.f90 b/src/tests/quadrature/test_trapz.f90 index b275643e8..7450878e0 100644 --- a/src/tests/quadrature/test_trapz.f90 +++ b/src/tests/quadrature/test_trapz.f90 @@ -12,7 +12,7 @@ program test_trapz call test_trapz_weights_sp call test_trapz_weights_dp call test_trapz_weights_qp - + call test_trapz_zero_sp call test_trapz_zero_dp call test_trapz_zero_qp @@ -28,26 +28,26 @@ subroutine test_trapz_sp integer :: i print *, "test_trapz_sp" - + y = [(real(i-1, sp), i = 1, n)] val = trapz(y, 1.0_sp) ans = 128.0_sp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) val = trapz(y, 0.5_sp) ans = 64.0_sp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = [((i-1)*4.0_sp/real(n-1, sp), i = 1, n)] val = trapz(y, x) ans = 32.0_sp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = y**2 val = trapz(y, x) ans = 2728.0_sp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) end subroutine test_trapz_sp subroutine test_trapz_dp @@ -59,26 +59,26 @@ subroutine test_trapz_dp integer :: i print *, "test_trapz_dp" - + y = [(real(i-1, dp), i = 1, n)] val = trapz(y, 1.0_dp) ans = 128.0_dp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) val = trapz(y, 0.5_dp) ans = 64.0_dp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = [((i-1)*4.0_dp/real(n-1, dp), i = 1, n)] val = trapz(y, x) ans = 32.0_dp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = y**2 val = trapz(y, x) ans = 2728.0_sp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) end subroutine test_trapz_dp @@ -91,26 +91,26 @@ subroutine test_trapz_qp integer :: i print *, "test_trapz_qp" - + y = [(real(i-1, qp), i = 1, n)] val = trapz(y, 1.0_qp) ans = 128.0_qp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) val = trapz(y, 0.5_qp) ans = 64.0_qp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = [((i-1)*4.0_qp/real(n-1, qp), i = 1, n)] val = trapz(y, x) ans = 32.0_qp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = y**2 val = trapz(y, x) ans = 2728.0_qp - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) end subroutine test_trapz_qp @@ -124,20 +124,20 @@ subroutine test_trapz_weights_sp real(sp) :: ans print *, "test_trapz_weights_sp" - + y = [(real(i-1, sp), i = 1, n)] x = y w = trapz_weights(x) val = dot_product(w, y) ans = trapz(y, x) - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = y**2 w = trapz_weights(x) val = dot_product(w, y) ans = trapz(y, x) - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) end subroutine test_trapz_weights_sp @@ -152,24 +152,24 @@ subroutine test_trapz_weights_dp real(dp) :: ans print *, "test_trapz_weights_dp" - + y = [(real(i-1, dp), i = 1, n)] x = y w = trapz_weights(x) val = dot_product(w, y) ans = trapz(y, x) - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = y**2 w = trapz_weights(x) val = dot_product(w, y) ans = trapz(y, x) - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) end subroutine test_trapz_weights_dp - + subroutine test_trapz_weights_qp integer, parameter :: n = 17 real(qp), dimension(n) :: y @@ -180,20 +180,20 @@ subroutine test_trapz_weights_qp real(qp) :: ans print *, "test_trapz_weights_qp" - + y = [(real(i-1, qp), i = 1, n)] x = y w = trapz_weights(x) val = dot_product(w, y) ans = trapz(y, x) - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) x = y**2 w = trapz_weights(x) val = dot_product(w, y) ans = trapz(y, x) - call assert(val == ans) + call assert(abs(val - ans) < epsilon(ans)) end subroutine test_trapz_weights_qp @@ -202,11 +202,11 @@ subroutine test_trapz_zero_sp real(sp), dimension(0) :: a print *, "test_trapz_zero_sp" - - call assert(trapz(a, 1.0_sp) == 0.0_sp) - call assert(trapz([1.0_sp], 1.0_sp) == 0.0_sp) - call assert(trapz(a, a) == 0.0_sp) - call assert(trapz([1.0_sp], [1.0_sp]) == 0.0_sp) + + call assert(abs(trapz(a, 1.0_sp)) < epsilon(0.0_sp)) + call assert(abs(trapz([1.0_sp], 1.0_sp)) < epsilon(0.0_sp)) + call assert(abs(trapz(a, a)) < epsilon(0.0_sp)) + call assert(abs(trapz([1.0_sp], [1.0_sp])) < epsilon(0.0_sp)) end subroutine test_trapz_zero_sp @@ -214,11 +214,11 @@ subroutine test_trapz_zero_dp real(dp), dimension(0) :: a print *, "test_trapz_zero_dp" - - call assert(trapz(a, 1.0_dp) == 0.0_dp) - call assert(trapz([1.0_dp], 1.0_dp) == 0.0_dp) - call assert(trapz(a, a) == 0.0_dp) - call assert(trapz([1.0_dp], [1.0_dp]) == 0.0_dp) + + call assert(trapz(a, 1.0_dp)) < epsilon(0.0_dp)) + call assert(abs(trapz([1.0_dp], 1.0_dp)) < epsilon(0.0_dp)) + call assert(abs(trapz(a, a)) < epsilon(0.0_dp)) + call assert(abs(trapz([1.0_dp], [1.0_dp])) < epsilon(0.0_dp)) end subroutine test_trapz_zero_dp @@ -226,11 +226,11 @@ subroutine test_trapz_zero_qp real(qp), dimension(0) :: a print *, "test_trapz_zero_qp" - - call assert(trapz(a, 1.0_qp) == 0.0_qp) - call assert(trapz([1.0_qp], 1.0_qp) == 0.0_qp) - call assert(trapz(a, a) == 0.0_qp) - call assert(trapz([1.0_qp], [1.0_qp]) == 0.0_qp) + + call assert(trapz(a, 1.0_qp) < epsilon(0.0_qp)) + call assert(trapz([1.0_qp], 1.0_qp) < epsilon(0.0_qp)) + call assert(trapz(a, a) < epsilon(0.0_qp)) + call assert(trapz([1.0_qp], [1.0_qp]) < epsilon(0.0_qp)) end subroutine test_trapz_zero_qp - + end program test_trapz From ccaf5485d1f07d5958a957083a6193a596aeb9bd Mon Sep 17 00:00:00 2001 From: Nathaniel Shaffer <nrshaffer@protonmail.com> Date: Fri, 7 Feb 2020 06:41:31 -0700 Subject: [PATCH 10/10] fix compile error --- src/tests/quadrature/test_trapz.f90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tests/quadrature/test_trapz.f90 b/src/tests/quadrature/test_trapz.f90 index 7450878e0..1265e4b6b 100644 --- a/src/tests/quadrature/test_trapz.f90 +++ b/src/tests/quadrature/test_trapz.f90 @@ -215,7 +215,7 @@ subroutine test_trapz_zero_dp print *, "test_trapz_zero_dp" - call assert(trapz(a, 1.0_dp)) < epsilon(0.0_dp)) + call assert(abs(trapz(a, 1.0_dp)) < epsilon(0.0_dp)) call assert(abs(trapz([1.0_dp], 1.0_dp)) < epsilon(0.0_dp)) call assert(abs(trapz(a, a)) < epsilon(0.0_dp)) call assert(abs(trapz([1.0_dp], [1.0_dp])) < epsilon(0.0_dp)) @@ -227,10 +227,10 @@ subroutine test_trapz_zero_qp print *, "test_trapz_zero_qp" - call assert(trapz(a, 1.0_qp) < epsilon(0.0_qp)) - call assert(trapz([1.0_qp], 1.0_qp) < epsilon(0.0_qp)) - call assert(trapz(a, a) < epsilon(0.0_qp)) - call assert(trapz([1.0_qp], [1.0_qp]) < epsilon(0.0_qp)) + call assert(abs(trapz(a, 1.0_qp)) < epsilon(0.0_qp)) + call assert(abs(trapz([1.0_qp], 1.0_qp)) < epsilon(0.0_qp)) + call assert(abs(trapz(a, a)) < epsilon(0.0_qp)) + call assert(abs(trapz([1.0_qp], [1.0_qp])) < epsilon(0.0_qp)) end subroutine test_trapz_zero_qp end program test_trapz