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

Non-breaking internal restructuring #79

Merged
merged 39 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8ed57d9
Remove sole author credit, bump version
mikeingold Sep 22, 2024
45bdb6f
Bump compat minimums for consistency with Meshes
mikeingold Sep 22, 2024
7a6e73a
Generalize GaussLegendre rules
mikeingold Sep 22, 2024
991ad82
Bump test versions
mikeingold Sep 22, 2024
b29b4c7
Move dim specializations into _integral wrappers
mikeingold Sep 22, 2024
913b58a
Bugfix
mikeingold Sep 22, 2024
beaa60d
Change to product of ntuple of Returns
mikeingold Sep 22, 2024
7936702
Bugfix
mikeingold Sep 22, 2024
bcf5fcd
Make jacobian arg ts generic (vector or tuple)
mikeingold Sep 22, 2024
e5cd20f
Fix copy/paste error
mikeingold Sep 22, 2024
02b4622
Make differential arg ts generic
mikeingold Sep 22, 2024
2695d8c
Remove obsoleted methods
mikeingold Sep 22, 2024
fe6ebab
Allocate and zero ev in one step
mikeingold Sep 22, 2024
26dbdff
Add explicit rtol's where needed
mikeingold Sep 22, 2024
f90217b
Combine methods with optional argument
mikeingold Sep 22, 2024
f12947f
Switch to generalized GaussLegendre method
mikeingold Sep 23, 2024
b8ba553
Split IntegrationAlgorithm into separate file
mikeingold Sep 23, 2024
f3fa161
Split BezierCurve methods into separate file
mikeingold Sep 23, 2024
3b05939
Split Line methods into separate file
mikeingold Sep 23, 2024
010bf1e
Split Tetrahedron methods into separate file
mikeingold Sep 23, 2024
446df3b
Split Triangle methods into separate file
mikeingold Sep 23, 2024
1485849
Split Ray methods into separate file
mikeingold Sep 23, 2024
e6b3ce5
Split CylinderSurface methods into separate file
mikeingold Sep 23, 2024
02ec9f8
Split ConeSurface methods into separate file
mikeingold Sep 23, 2024
c366c66
Split FrustumSurface methods into separate file
mikeingold Sep 23, 2024
18109ef
Split Plane methods into separate file
mikeingold Sep 23, 2024
9bb391c
Move GaussKronrod specializations into single section
mikeingold Sep 23, 2024
7a256da
Consolidate conic methods under new structure
mikeingold Sep 23, 2024
588f8ad
Split Ring and Rope methods into separate files
mikeingold Sep 23, 2024
a50aed7
Fix typo
mikeingold Sep 23, 2024
5aef59d
Remove obsolete files
mikeingold Sep 23, 2024
af9ca21
Point alias functions directly toward worker methods
mikeingold Sep 23, 2024
763f78b
Undo last commit
mikeingold Sep 23, 2024
bb2e3b7
Revert to a minor version bump
mikeingold Sep 23, 2024
eb28edb
Fix docstring typos
mikeingold Sep 23, 2024
99f2a7c
Remove MeshIntegrals from test Project
mikeingold Sep 23, 2024
b4525a6
Add conditional for selecting default integration rule
mikeingold Sep 23, 2024
a150ae7
Update comment
mikeingold Sep 23, 2024
1e997a4
Reduce Meshes lower bound
mikeingold Sep 23, 2024
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
3 changes: 1 addition & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name = "MeshIntegrals"
uuid = "dadec2fd-bbe0-4da4-9dbe-476c782c8e47"
authors = ["Mike Ingold <[email protected]>"]
version = "0.13.4"
version = "0.13.5"

[deps]
CoordRefSystems = "b46f11dc-f210-4604-bfba-323c1ec968cb"
Expand Down
20 changes: 16 additions & 4 deletions src/MeshIntegrals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,23 @@ module MeshIntegrals
include("utils.jl")
export jacobian, derivative, unitdirection

include("integration_algorithms.jl")
export GaussKronrod, GaussLegendre, HAdaptiveCubature

include("integral.jl")
include("integral_aliases.jl")
include("integral_line.jl")
include("integral_surface.jl")
include("integral_volume.jl")
export GaussKronrod, GaussLegendre, HAdaptiveCubature
export integral, lineintegral, surfaceintegral, volumeintegral

# Integration methods specialized for particular geometries
include("specializations/BezierCurve.jl")
include("specializations/ConeSurface.jl")
include("specializations/CylinderSurface.jl")
include("specializations/FrustumSurface.jl")
include("specializations/Line.jl")
include("specializations/Plane.jl")
include("specializations/Ray.jl")
include("specializations/Ring.jl")
include("specializations/Rope.jl")
include("specializations/Tetrahedron.jl")
include("specializations/Triangle.jl")
end
165 changes: 78 additions & 87 deletions src/integral.jl
Original file line number Diff line number Diff line change
@@ -1,48 +1,3 @@
################################################################################
# Integration Algorithms
################################################################################

abstract type IntegrationAlgorithm end

"""
GaussKronrod(kwargs...)

Numerically integrate using the h-adaptive Gauss-Kronrod quadrature rule implemented
by QuadGK.jl. All standard `QuadGK.quadgk` keyword arguments are supported.
"""
struct GaussKronrod <: IntegrationAlgorithm
kwargs
GaussKronrod(; kwargs...) = new(kwargs)
end

"""
GaussLegendre(n)

Numerically integrate using an `n`'th-order Gauss-Legendre quadrature rule. nodes
and weights are efficiently calculated using FastGaussQuadrature.jl.

So long as the integrand function can be well-approximated by a polynomial of
order `2n-1`, this method should yield results with 16-digit accuracy in `O(n)`
time. If the function is know to have some periodic content, then `n` should
(at a minimum) be greater than the expected number of periods over the geometry,
e.g. `length(geometry)/lambda`.
"""
struct GaussLegendre <: IntegrationAlgorithm
n::Int64
end

"""
GaussKronrod(kwargs...)

Numerically integrate areas and surfaces using the h-adaptive cubature rule
implemented by HCubature.jl. All standard `HCubature.hcubature` keyword
arguments are supported.
"""
struct HAdaptiveCubature <: IntegrationAlgorithm
kwargs
HAdaptiveCubature(; kwargs...) = new(kwargs)
end

################################################################################
# Master Integral Function
################################################################################
Expand All @@ -68,57 +23,38 @@
"""
function integral end

# If only f and geometry are specified, default to HAdaptiveCubature
# If only f and geometry are specified, select default algorithm
function integral(
f::F,
geometry::G
) where {F<:Function, G<:Meshes.Geometry}
_integral(f, geometry, HAdaptiveCubature())
end

# If algorithm is HAdaptiveCubature, use the generalized n-dim solution
function integral(
f::F,
geometry::G,
settings::HAdaptiveCubature
) where {F<:Function, G<:Meshes.Geometry}
_integral(f, geometry, settings)
N = Meshes.paramdim(geometry)
rule = (N == 1) ? GaussKronrod() : HAdaptiveCubature()
JoshuaLampert marked this conversation as resolved.
Show resolved Hide resolved
_integral(f, geometry, rule)

Check warning on line 33 in src/integral.jl

View check run for this annotation

Codecov / codecov/patch

src/integral.jl#L31-L33

Added lines #L31 - L33 were not covered by tests
end

# If algorithm is HAdaptiveCubature, and FP specified, use the generalized n-dim solution
# with algorithm and T specified
function integral(
f::F,
geometry::G,
settings::HAdaptiveCubature,
FP::Type{T}
) where {F<:Function, G<:Meshes.Geometry, T<:AbstractFloat}
settings::I,
JoshuaLampert marked this conversation as resolved.
Show resolved Hide resolved
FP::Type{T} = Float64
) where {F<:Function, G<:Meshes.Geometry, I<:IntegrationAlgorithm, T<:AbstractFloat}
_integral(f, geometry, settings, FP)
end

# If algorithm is not HAdaptiveCubature, specialize on number of dimensions
function integral(
f::F,
geometry::G,
settings::I
) where {F<:Function, G<:Meshes.Geometry, I<:IntegrationAlgorithm}
# Run the appropriate integral type
Dim = Meshes.paramdim(geometry)
if Dim == 1
return _integral_1d(f, geometry, settings)
elseif Dim == 2
return _integral_2d(f, geometry, settings)
elseif Dim == 3
return _integral_3d(f, geometry, settings)
end
end

# If algorithm is not HAdaptiveCubature, and FP specified, specialize on number of dimensions
function integral(
f::F,
geometry::G,
settings::I,
FP::Type{T}
) where {F<:Function, G<:Meshes.Geometry, I<:IntegrationAlgorithm, T<:AbstractFloat}
################################################################################
# Generalized (n-Dimensional) Worker Methods
################################################################################

# GaussKronrod
function _integral(
f,
geometry,
settings::GaussKronrod,
FP::Type{T} = Float64
) where {T<:AbstractFloat}
# Run the appropriate integral type
Dim = Meshes.paramdim(geometry)
if Dim == 1
Expand All @@ -130,12 +66,32 @@
end
end

# GaussLegendre
function _integral(
f,
geometry,
settings::GaussLegendre,
FP::Type{T} = Float64
) where {T<:AbstractFloat}
N = Meshes.paramdim(geometry)

# Get Gauss-Legendre nodes and weights for a region [-1,1]^N
xs, ws = _gausslegendre(FP, settings.n)
weights = Iterators.product(ntuple(Returns(ws), N)...)
nodes = Iterators.product(ntuple(Returns(xs), N)...)

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

# General solution for HAdaptiveCubature methods
function integrand((weights, nodes))
ts = t.(nodes)
prod(weights) * f(geometry(ts...)) * differential(geometry, ts)
end

return FP(1//(2^N)) .* sum(integrand, zip(weights, nodes))
end

# HAdaptiveCubature
function _integral(
f,
geometry,
Expand All @@ -158,3 +114,38 @@
# Reapply units
return value .* integrandunits
end

################################################################################
# Specialized GaussKronrod Methods
################################################################################

function _integral_1d(
f,
geometry,
settings::GaussKronrod,
FP::Type{T} = Float64
) where {T<:AbstractFloat}
integrand(t) = f(geometry(t)) * differential(geometry, [t])
return QuadGK.quadgk(integrand, FP(0), FP(1); settings.kwargs...)[1]
end

function _integral_2d(
f,
geometry2d,
settings::GaussKronrod,
FP::Type{T} = Float64
) where {T<:AbstractFloat}
integrand(u,v) = f(geometry2d(u,v)) * differential(geometry2d, [u,v])
∫₁(v) = QuadGK.quadgk(u -> integrand(u,v), FP(0), FP(1); settings.kwargs...)[1]
return QuadGK.quadgk(v -> ∫₁(v), FP(0), FP(1); settings.kwargs...)[1]
end

# Integrating volumes with GaussKronrod not supported by default
function _integral_3d(
f,
geometry,
settings::GaussKronrod,
FP::Type{T} = Float64
) where {T<:AbstractFloat}
error("Integrating this volume type with GaussKronrod not supported.")
end
Loading
Loading