Skip to content

Commit 8d5f81a

Browse files
Non-breaking internal restructuring (#79)
* Remove sole author credit, bump version * Bump compat minimums for consistency with Meshes * Generalize GaussLegendre rules * Bump test versions * Move dim specializations into _integral wrappers * Bugfix * Change to product of ntuple of Returns * Bugfix * Make jacobian arg ts generic (vector or tuple) * Fix copy/paste error * Make differential arg ts generic * Remove obsoleted methods * Allocate and zero ev in one step * Add explicit rtol's where needed * Combine methods with optional argument * Switch to generalized GaussLegendre method * Split IntegrationAlgorithm into separate file * Split BezierCurve methods into separate file * Split Line methods into separate file * Split Tetrahedron methods into separate file * Split Triangle methods into separate file * Split Ray methods into separate file * Split CylinderSurface methods into separate file * Split ConeSurface methods into separate file * Split FrustumSurface methods into separate file * Split Plane methods into separate file * Move GaussKronrod specializations into single section * Consolidate conic methods under new structure * Split Ring and Rope methods into separate files * Fix typo * Remove obsolete files * Point alias functions directly toward worker methods * Undo last commit * Revert to a minor version bump * Fix docstring typos Co-authored-by: Joshua Lampert <[email protected]> * Remove MeshIntegrals from test Project * Add conditional for selecting default integration rule * Update comment * Reduce Meshes lower bound --------- Co-authored-by: Joshua Lampert <[email protected]>
1 parent 7674006 commit 8d5f81a

20 files changed

+722
-846
lines changed

Diff for: Project.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
name = "MeshIntegrals"
22
uuid = "dadec2fd-bbe0-4da4-9dbe-476c782c8e47"
3-
authors = ["Mike Ingold <[email protected]>"]
4-
version = "0.13.4"
3+
version = "0.13.5"
54

65
[deps]
76
CoordRefSystems = "b46f11dc-f210-4604-bfba-323c1ec968cb"

Diff for: src/MeshIntegrals.jl

+16-4
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,23 @@ module MeshIntegrals
1111
include("utils.jl")
1212
export jacobian, derivative, unitdirection
1313

14+
include("integration_algorithms.jl")
15+
export GaussKronrod, GaussLegendre, HAdaptiveCubature
16+
1417
include("integral.jl")
1518
include("integral_aliases.jl")
16-
include("integral_line.jl")
17-
include("integral_surface.jl")
18-
include("integral_volume.jl")
19-
export GaussKronrod, GaussLegendre, HAdaptiveCubature
2019
export integral, lineintegral, surfaceintegral, volumeintegral
20+
21+
# Integration methods specialized for particular geometries
22+
include("specializations/BezierCurve.jl")
23+
include("specializations/ConeSurface.jl")
24+
include("specializations/CylinderSurface.jl")
25+
include("specializations/FrustumSurface.jl")
26+
include("specializations/Line.jl")
27+
include("specializations/Plane.jl")
28+
include("specializations/Ray.jl")
29+
include("specializations/Ring.jl")
30+
include("specializations/Rope.jl")
31+
include("specializations/Tetrahedron.jl")
32+
include("specializations/Triangle.jl")
2133
end

Diff for: src/integral.jl

+78-87
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,3 @@
1-
################################################################################
2-
# Integration Algorithms
3-
################################################################################
4-
5-
abstract type IntegrationAlgorithm end
6-
7-
"""
8-
GaussKronrod(kwargs...)
9-
10-
Numerically integrate using the h-adaptive Gauss-Kronrod quadrature rule implemented
11-
by QuadGK.jl. All standard `QuadGK.quadgk` keyword arguments are supported.
12-
"""
13-
struct GaussKronrod <: IntegrationAlgorithm
14-
kwargs
15-
GaussKronrod(; kwargs...) = new(kwargs)
16-
end
17-
18-
"""
19-
GaussLegendre(n)
20-
21-
Numerically integrate using an `n`'th-order Gauss-Legendre quadrature rule. nodes
22-
and weights are efficiently calculated using FastGaussQuadrature.jl.
23-
24-
So long as the integrand function can be well-approximated by a polynomial of
25-
order `2n-1`, this method should yield results with 16-digit accuracy in `O(n)`
26-
time. If the function is know to have some periodic content, then `n` should
27-
(at a minimum) be greater than the expected number of periods over the geometry,
28-
e.g. `length(geometry)/lambda`.
29-
"""
30-
struct GaussLegendre <: IntegrationAlgorithm
31-
n::Int64
32-
end
33-
34-
"""
35-
GaussKronrod(kwargs...)
36-
37-
Numerically integrate areas and surfaces using the h-adaptive cubature rule
38-
implemented by HCubature.jl. All standard `HCubature.hcubature` keyword
39-
arguments are supported.
40-
"""
41-
struct HAdaptiveCubature <: IntegrationAlgorithm
42-
kwargs
43-
HAdaptiveCubature(; kwargs...) = new(kwargs)
44-
end
45-
461
################################################################################
472
# Master Integral Function
483
################################################################################
@@ -68,57 +23,38 @@ contrast, increasing `FP` to e.g. `BigFloat` will typically increase precision
6823
"""
6924
function integral end
7025

71-
# If only f and geometry are specified, default to HAdaptiveCubature
26+
# If only f and geometry are specified, select default algorithm
7227
function integral(
7328
f::F,
7429
geometry::G
7530
) where {F<:Function, G<:Meshes.Geometry}
76-
_integral(f, geometry, HAdaptiveCubature())
77-
end
78-
79-
# If algorithm is HAdaptiveCubature, use the generalized n-dim solution
80-
function integral(
81-
f::F,
82-
geometry::G,
83-
settings::HAdaptiveCubature
84-
) where {F<:Function, G<:Meshes.Geometry}
85-
_integral(f, geometry, settings)
31+
N = Meshes.paramdim(geometry)
32+
rule = (N == 1) ? GaussKronrod() : HAdaptiveCubature()
33+
_integral(f, geometry, rule)
8634
end
8735

88-
# If algorithm is HAdaptiveCubature, and FP specified, use the generalized n-dim solution
36+
# with algorithm and T specified
8937
function integral(
9038
f::F,
9139
geometry::G,
92-
settings::HAdaptiveCubature,
93-
FP::Type{T}
94-
) where {F<:Function, G<:Meshes.Geometry, T<:AbstractFloat}
40+
settings::I,
41+
FP::Type{T} = Float64
42+
) where {F<:Function, G<:Meshes.Geometry, I<:IntegrationAlgorithm, T<:AbstractFloat}
9543
_integral(f, geometry, settings, FP)
9644
end
9745

98-
# If algorithm is not HAdaptiveCubature, specialize on number of dimensions
99-
function integral(
100-
f::F,
101-
geometry::G,
102-
settings::I
103-
) where {F<:Function, G<:Meshes.Geometry, I<:IntegrationAlgorithm}
104-
# Run the appropriate integral type
105-
Dim = Meshes.paramdim(geometry)
106-
if Dim == 1
107-
return _integral_1d(f, geometry, settings)
108-
elseif Dim == 2
109-
return _integral_2d(f, geometry, settings)
110-
elseif Dim == 3
111-
return _integral_3d(f, geometry, settings)
112-
end
113-
end
11446

115-
# If algorithm is not HAdaptiveCubature, and FP specified, specialize on number of dimensions
116-
function integral(
117-
f::F,
118-
geometry::G,
119-
settings::I,
120-
FP::Type{T}
121-
) where {F<:Function, G<:Meshes.Geometry, I<:IntegrationAlgorithm, T<:AbstractFloat}
47+
################################################################################
48+
# Generalized (n-Dimensional) Worker Methods
49+
################################################################################
50+
51+
# GaussKronrod
52+
function _integral(
53+
f,
54+
geometry,
55+
settings::GaussKronrod,
56+
FP::Type{T} = Float64
57+
) where {T<:AbstractFloat}
12258
# Run the appropriate integral type
12359
Dim = Meshes.paramdim(geometry)
12460
if Dim == 1
@@ -130,12 +66,32 @@ function integral(
13066
end
13167
end
13268

69+
# GaussLegendre
70+
function _integral(
71+
f,
72+
geometry,
73+
settings::GaussLegendre,
74+
FP::Type{T} = Float64
75+
) where {T<:AbstractFloat}
76+
N = Meshes.paramdim(geometry)
77+
78+
# Get Gauss-Legendre nodes and weights for a region [-1,1]^N
79+
xs, ws = _gausslegendre(FP, settings.n)
80+
weights = Iterators.product(ntuple(Returns(ws), N)...)
81+
nodes = Iterators.product(ntuple(Returns(xs), N)...)
13382

134-
################################################################################
135-
# Generalized (n-Dimensional) Worker Methods
136-
################################################################################
83+
# Domain transformation: x [-1,1] ↦ t [0,1]
84+
t(x) = FP(1//2) * x + FP(1//2)
13785

138-
# General solution for HAdaptiveCubature methods
86+
function integrand((weights, nodes))
87+
ts = t.(nodes)
88+
prod(weights) * f(geometry(ts...)) * differential(geometry, ts)
89+
end
90+
91+
return FP(1//(2^N)) .* sum(integrand, zip(weights, nodes))
92+
end
93+
94+
# HAdaptiveCubature
13995
function _integral(
14096
f,
14197
geometry,
@@ -158,3 +114,38 @@ function _integral(
158114
# Reapply units
159115
return value .* integrandunits
160116
end
117+
118+
################################################################################
119+
# Specialized GaussKronrod Methods
120+
################################################################################
121+
122+
function _integral_1d(
123+
f,
124+
geometry,
125+
settings::GaussKronrod,
126+
FP::Type{T} = Float64
127+
) where {T<:AbstractFloat}
128+
integrand(t) = f(geometry(t)) * differential(geometry, [t])
129+
return QuadGK.quadgk(integrand, FP(0), FP(1); settings.kwargs...)[1]
130+
end
131+
132+
function _integral_2d(
133+
f,
134+
geometry2d,
135+
settings::GaussKronrod,
136+
FP::Type{T} = Float64
137+
) where {T<:AbstractFloat}
138+
integrand(u,v) = f(geometry2d(u,v)) * differential(geometry2d, [u,v])
139+
∫₁(v) = QuadGK.quadgk(u -> integrand(u,v), FP(0), FP(1); settings.kwargs...)[1]
140+
return QuadGK.quadgk(v -> ∫₁(v), FP(0), FP(1); settings.kwargs...)[1]
141+
end
142+
143+
# Integrating volumes with GaussKronrod not supported by default
144+
function _integral_3d(
145+
f,
146+
geometry,
147+
settings::GaussKronrod,
148+
FP::Type{T} = Float64
149+
) where {T<:AbstractFloat}
150+
error("Integrating this volume type with GaussKronrod not supported.")
151+
end

0 commit comments

Comments
 (0)