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

Use a new _ParametricGeometry for specializations #131

Closed
wants to merge 97 commits into from
Closed
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
cd4b29b
Rename nil to o (zero-alike)
mikeingold Nov 10, 2024
928ad43
Implement a custom geometry subtype for parametrics
mikeingold Nov 10, 2024
7109af5
Enable tests
mikeingold Nov 10, 2024
95a8bed
Include new file
mikeingold Nov 10, 2024
7147060
Bugfix
mikeingold Nov 10, 2024
180a0d0
Fix errant comma
mikeingold Nov 10, 2024
39e4948
Explicit import
mikeingold Nov 10, 2024
2a28ccd
Rename
mikeingold Nov 10, 2024
c975a0f
Rename
mikeingold Nov 10, 2024
218b391
Remove type params
mikeingold Nov 10, 2024
69d84c4
Test changed default diff_method
mikeingold Nov 10, 2024
db6f6a6
Fix use of ts arg in constructor
mikeingold Nov 10, 2024
d080d4a
Test whether prevfloat prevents out-of-bounds barycentric
mikeingold Nov 10, 2024
9a4de27
Test more prevfloat
mikeingold Nov 10, 2024
b4f45c1
Tweak to only use prevfloat when > 0
mikeingold Nov 10, 2024
c1881cf
Try a more aggressive prevfloat
mikeingold Nov 10, 2024
0ccd36f
Refactor - issue was ts in [0,1]
mikeingold Nov 10, 2024
953c6b7
Update naming
mikeingold Nov 10, 2024
d7d470e
Update constructor for new method signature
mikeingold Nov 10, 2024
5c75967
Test constraint on t1
mikeingold Nov 10, 2024
f9c6c6b
Tweak constraints and add arg range asserts
mikeingold Nov 10, 2024
c635ff5
Re-organize new functions
mikeingold Nov 10, 2024
1c8035d
Add top-level docstring for _parametric
mikeingold Nov 10, 2024
7ca59b3
Try obsoleting old Tetrahedron methods
mikeingold Nov 10, 2024
d0d25bb
Update tests for Tetrahedron
mikeingold Nov 10, 2024
2a2dc9a
Update naming
mikeingold Nov 10, 2024
b0b8f0c
Update support matrix
mikeingold Nov 10, 2024
eec4dcf
Fix issues with tests
mikeingold Nov 10, 2024
f32d79d
Remove obsolete code, update header
mikeingold Nov 10, 2024
281e615
Update Triangle to use _ParametricGeometry
mikeingold Nov 11, 2024
97488b4
Remove obsolete code
mikeingold Nov 11, 2024
cac0969
Fix typo
mikeingold Nov 11, 2024
15e6894
Test new version of Line methods
mikeingold Nov 11, 2024
045e760
Fix number of dims
mikeingold Nov 11, 2024
bbec7fa
Fix explicit namespace
mikeingold Nov 11, 2024
e9b4904
Fix typo
mikeingold Nov 11, 2024
2f118c8
Remove obsolete code
mikeingold Nov 11, 2024
aa6a3e0
Test new version of Ray methods
mikeingold Nov 11, 2024
fad580d
Remove obsolete code
mikeingold Nov 11, 2024
0ba43b8
Test new version of Plane methods
mikeingold Nov 11, 2024
26a7802
Update header, fix function signature
mikeingold Nov 11, 2024
97808ed
Remove unneeded arg
mikeingold Nov 11, 2024
d79fed6
Add a TODO note in docs
mikeingold Nov 11, 2024
fadd7a7
Update tests
mikeingold Nov 11, 2024
6ae40fc
Remove obsolete code
mikeingold Nov 11, 2024
294ab48
Test new version of BezierCurve methods
mikeingold Nov 11, 2024
d92d543
Remove obsolete code, update jacobian signature
mikeingold Nov 11, 2024
bf4a5fe
Test removal of _guarantee_analytical
mikeingold Nov 11, 2024
1067043
Remove obsolete _guarantee_analytical
mikeingold Nov 11, 2024
762b4bb
Test new parametrics that don't require constrain
mikeingold Nov 11, 2024
98732f1
Remove obsolete code
mikeingold Nov 11, 2024
c1d96ec
Remove obsolete reference
mikeingold Nov 11, 2024
ef9e678
Apply suggestions from code review
mikeingold Nov 11, 2024
33ed924
Remove extended tag from Tetrahedron tests
mikeingold Nov 11, 2024
fbd83b3
Add tests
mikeingold Nov 11, 2024
1795a1b
Try parameterizing paramdim
mikeingold Nov 11, 2024
b9d71ee
Try consolidated parametric method definition
mikeingold Nov 11, 2024
3a6f9d6
Add alt float tests for _ParametricGeometry
mikeingold Nov 11, 2024
b40b9b8
Renaming and improved docstring
mikeingold Nov 11, 2024
6a0d06a
Add new _zeros utility
mikeingold Nov 11, 2024
2356db1
Add explicit return statements
mikeingold Nov 11, 2024
5d56f00
Add one-arg _zeros method
mikeingold Nov 11, 2024
2bd0231
Use new _zeros method
mikeingold Nov 11, 2024
78fd313
Refactor due to unbound params issue
mikeingold Nov 11, 2024
4466204
Bugfix typo
mikeingold Nov 11, 2024
6e8f041
Remove _ParametricGeometry from alt FP tests
mikeingold Nov 11, 2024
9b1262e
Add type stability test for Triangle
mikeingold Nov 11, 2024
21c4fe5
Switch rule
mikeingold Nov 11, 2024
55c3021
Apply suggestions from code review
mikeingold Nov 11, 2024
4a90773
Update docstrings
mikeingold Nov 11, 2024
66920dc
Apply suggestions from code review
mikeingold Nov 12, 2024
e64232e
Add _ones function and update usages
mikeingold Nov 12, 2024
838e65e
Finish writing docstring
mikeingold Nov 12, 2024
c3a36d2
Add Specializations branch to benchmarks
mikeingold Nov 12, 2024
86d0b03
Change integrand function
mikeingold Nov 12, 2024
817caa5
Add missing comma and tweak formatting
mikeingold Nov 12, 2024
055c445
Use Unitful integrand for Triangle and Tetrahedron
mikeingold Nov 12, 2024
e4ddf78
Temp disable Tetrahedron benchmark, cleanup TODO note
mikeingold Nov 12, 2024
91ed795
Formatting
mikeingold Nov 12, 2024
c81f00b
More formatting
mikeingold Nov 12, 2024
d305ae5
Add tests
mikeingold Nov 13, 2024
d90bf23
Test simplified parametric function wrapper
mikeingold Nov 13, 2024
0af032e
Explicit import of non-exports
mikeingold Nov 13, 2024
7ffb14c
Fix typo
mikeingold Nov 13, 2024
3603d90
Remove obsoleted code
mikeingold Nov 13, 2024
7cff3e1
Parameterize source geometry types
mikeingold Nov 13, 2024
07364a1
Add missing arg
mikeingold Nov 13, 2024
e8174b4
Test storage of source geometry in _ParametricGeometry
mikeingold Nov 13, 2024
59bb9c1
Remove comma
mikeingold Nov 13, 2024
0f87431
Merge branch 'tetrahedron' of github.com:JuliaGeometry/MeshIntegrals.…
mikeingold Nov 13, 2024
8c90f3f
Revert test and deprecate analytical jacobian for BezierCurve
mikeingold Nov 13, 2024
0dd012e
Fix typo
mikeingold Nov 13, 2024
ee5044d
Add more specialization benchmarks, change rule
mikeingold Nov 16, 2024
54b3549
Fix typo
mikeingold Nov 16, 2024
bf23c4d
Add Unitful
mikeingold Nov 16, 2024
3e8c6f7
Add Unitful to benchmark Project
mikeingold Nov 16, 2024
bf24d08
Define other rules, disable Tetrahedron benchmark
mikeingold Nov 16, 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: 3 additions & 0 deletions docs/src/specializations.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ There are several notable exceptions to how Meshes.jl defines [parametric functi

## Triangle

!!! note
This derivation is now obsolete.

For a specified `Meshes.Triangle` surface with area $A$, let $u$ and $v$ be Barycentric coordinates that span the surface.
```math
\int_\triangle f(\bar{r}) \, \text{d}A
Expand Down
2 changes: 1 addition & 1 deletion docs/src/supportmatrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Cubature integration rules are recommended (and the default).
| `SimpleMesh` | [🎗️](https://github.com/JuliaGeometry/MeshIntegrals.jl/issues/27) | [🎗️](https://github.com/JuliaGeometry/MeshIntegrals.jl/issues/27) | [🎗️](https://github.com/JuliaGeometry/MeshIntegrals.jl/issues/27) |
| `Sphere` in `𝔼{2}` | ✅ | ✅ | ✅ |
| `Sphere` in `𝔼{3}` | ✅ | ✅ | ✅ |
| `Tetrahedron` in `𝔼{3}` | [🎗️](https://github.com/JuliaGeometry/MeshIntegrals.jl/issues/40) | | [🎗️](https://github.com/JuliaGeometry/MeshIntegrals.jl/issues/40) |
| `Tetrahedron` in `𝔼{3}` | | 🛑 | |
| `Triangle` | ✅ | ✅ | ✅ |
| `Torus` | ✅ | ✅ | ✅ |
| `Wedge` | [🎗️](https://github.com/JuliaGeometry/MeshIntegrals.jl/issues/28) | [🎗️](https://github.com/JuliaGeometry/MeshIntegrals.jl/issues/28) | [🎗️](https://github.com/JuliaGeometry/MeshIntegrals.jl/issues/28) |
1 change: 1 addition & 0 deletions src/MeshIntegrals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ include("integral_aliases.jl")
export lineintegral, surfaceintegral, volumeintegral

# Integration methods specialized for particular geometries
include("specializations/_ParametricGeometry.jl")
include("specializations/BezierCurve.jl")
include("specializations/ConeSurface.jl")
include("specializations/CylinderSurface.jl")
Expand Down
67 changes: 15 additions & 52 deletions src/specializations/BezierCurve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,60 +32,23 @@ calculating Jacobians that are used to calculate differential elements
steep performance cost, especially for curves with a large number of control points.
"""
function integral(
f::F,
f::Function,
mikeingold marked this conversation as resolved.
Show resolved Hide resolved
curve::Meshes.BezierCurve,
rule::GaussLegendre;
diff_method::DM = _default_method(curve),
FP::Type{T} = Float64,
alg::Meshes.BezierEvalMethod = Meshes.Horner()
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
# Compute Gauss-Legendre nodes/weights for x in interval [-1,1]
xs, ws = _gausslegendre(FP, rule.n)

# Change of variables: x [-1,1] ↦ t [0,1]
t(x) = FP(1 // 2) * x + FP(1 // 2)
point(x) = curve(t(x), alg)
integrand(x) = f(point(x)) * differential(curve, (t(x),), diff_method)

# Integrate f along curve and apply domain-correction for [-1,1] ↦ [0, length]
return FP(1 // 2) * sum(w .* integrand(x) for (w, x) in zip(ws, xs))
end

function integral(
f::F,
curve::Meshes.BezierCurve,
rule::GaussKronrod;
diff_method::DM = _default_method(curve),
FP::Type{T} = Float64,
alg::Meshes.BezierEvalMethod = Meshes.Horner()
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
point(t) = curve(t, alg)
integrand(t) = f(point(t)) * differential(curve, (t,), diff_method)
return QuadGK.quadgk(integrand, zero(FP), one(FP); rule.kwargs...)[1]
rule::IntegrationRule;
alg::Meshes.BezierEvalMethod = Meshes.Horner(),
kwargs...
)
paramfunction(t) = _parametric(curve, t; alg = alg)
param_curve = _ParametricGeometry(paramfunction, 1)
return _integral(f, param_curve, rule; kwargs...)
mikeingold marked this conversation as resolved.
Show resolved Hide resolved
end

function integral(
f::F,
curve::Meshes.BezierCurve,
rule::HAdaptiveCubature;
diff_method::DM = _default_method(curve),
FP::Type{T} = Float64,
alg::Meshes.BezierEvalMethod = Meshes.Horner()
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
point(t) = curve(t, alg)
integrand(ts) = f(point(only(ts))) * differential(curve, ts, diff_method)

# HCubature doesn't support functions that output Unitful Quantity types
# Establish the units that are output by f
testpoint_parametriccoord = zeros(FP, 1)
integrandunits = Unitful.unit.(integrand(testpoint_parametriccoord))
# Create a wrapper that returns only the value component in those units
uintegrand(ts) = Unitful.ustrip.(integrandunits, integrand(ts))
# Integrate only the unitless values
value = HCubature.hcubature(uintegrand, zeros(FP, 1), ones(FP, 1); rule.kwargs...)[1]
################################################################################
# Parametric
################################################################################

# Reapply units
return value .* integrandunits
function _parametric(curve::Meshes.BezierCurve, t; alg::Meshes.BezierEvalMethod)
return curve(t, alg)
end

################################################################################
Expand All @@ -94,9 +57,9 @@ end

function jacobian(
bz::Meshes.BezierCurve,
ts::V,
ts::Union{AbstractVector{T}, Tuple{T, Vararg{T}}},
diff_method::Analytical
) where {V <: Union{AbstractVector, Tuple}}
) where {T <: AbstractFloat}
t = only(ts)
# Parameter t restricted to domain [0,1] by definition
if t < 0 || t > 1
Expand Down
87 changes: 13 additions & 74 deletions src/specializations/Line.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,83 +8,22 @@
################################################################################

function integral(
f::F,
f::Function,
line::Meshes.Line,
rule::GaussLegendre;
diff_method::DM = Analytical(),
FP::Type{T} = Float64
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
_guarantee_analytical(Meshes.Line, diff_method)

# Compute Gauss-Legendre nodes/weights for x in interval [-1,1]
xs, ws = _gausslegendre(FP, rule.n)

# Normalize the Line s.t. line(t) is distance t from origin point
line = Meshes.Line(line.a, line.a + Meshes.unormalize(line.b - line.a))

# Domain transformation: x ∈ [-1,1] ↦ t ∈ (-∞,∞)
t(x) = x / (1 - x^2)
t′(x) = (1 + x^2) / (1 - x^2)^2

# Integrate f along the Line
differential(line, x) = t′(x) * _units(line(0))
integrand(x) = f(line(t(x))) * differential(line, x)
return sum(w .* integrand(x) for (w, x) in zip(ws, xs))
end

function integral(
f::F,
line::Meshes.Line,
rule::GaussKronrod;
diff_method::DM = Analytical(),
FP::Type{T} = Float64
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
_guarantee_analytical(Meshes.Line, diff_method)

# Normalize the Line s.t. line(t) is distance t from origin point
line = Meshes.Line(line.a, line.a + Meshes.unormalize(line.b - line.a))

# Integrate f along the Line
domainunits = _units(line(0))
integrand(t) = f(line(t)) * domainunits
return QuadGK.quadgk(integrand, FP(-Inf), FP(Inf); rule.kwargs...)[1]
end

function integral(
f::F,
line::Meshes.Line,
rule::HAdaptiveCubature;
diff_method::DM = Analytical(),
FP::Type{T} = Float64
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
_guarantee_analytical(Meshes.Line, diff_method)

# Normalize the Line s.t. line(t) is distance t from origin point
line = Meshes.Line(line.a, line.a + Meshes.unormalize(line.b - line.a))

# Domain transformation: x ∈ [-1,1] ↦ t ∈ (-∞,∞)
t(x) = x / (1 - x^2)
t′(x) = (1 + x^2) / (1 - x^2)^2

# Integrate f along the Line
differential(line, x) = t′(x) * _units(line(0))
integrand(x::AbstractVector) = f(line(t(x[1]))) * differential(line, x[1])

# HCubature doesn't support functions that output Unitful Quantity types
# Establish the units that are output by f
testpoint_parametriccoord = FP[0.5]
integrandunits = Unitful.unit.(integrand(testpoint_parametriccoord))
# Create a wrapper that returns only the value component in those units
uintegrand(uv) = Unitful.ustrip.(integrandunits, integrand(uv))
# Integrate only the unitless values
value = HCubature.hcubature(uintegrand, (-one(FP),), (one(FP),); rule.kwargs...)[1]

# Reapply units
return value .* integrandunits
rule::IntegrationRule;
kwargs...
)
paramfunction(t) = _parametric(line, t)
param_line = _ParametricGeometry(paramfunction, 1)
return _integral(f, param_line, rule; kwargs...)
end

################################################################################
# jacobian
# Parametric
################################################################################

_has_analytical(::Type{T}) where {T <: Meshes.Line} = true
function _parametric(line::Meshes.Line, t)
f1(t) = t / (1 - t^2)
f2(t) = 2t - 1
return line((f1 ∘ f2)(t))
end
116 changes: 21 additions & 95 deletions src/specializations/Plane.jl
Original file line number Diff line number Diff line change
@@ -1,104 +1,30 @@
################################################################################
# Specialized Methods for Plane
############################################################################################
# Specialized Methods for Plane
#
# Why Specialized?
# The Plane geometry is a special case, representing a planar surface with
# infinite extent along two basis vectors. This requires a pair of domain
# transformations mapping from the typical parametric region [0,1]² to an
# infinite one (-∞,∞)².
################################################################################
# The Plane geometry is a special case, representing a planar surface with infinite extent
# along two basis vectors. This requires a pair of domain transformations mapping from the
# typical parametric region [0,1]² to an infinite one (-∞,∞)².
############################################################################################

function integral(
f::F,
f::Function,
plane::Meshes.Plane,
rule::GaussLegendre;
diff_method::DM = Analytical(),
FP::Type{T} = Float64
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
_guarantee_analytical(Meshes.Plane, diff_method)

# Get Gauss-Legendre nodes and weights for a 2D region [-1,1]²
xs, ws = _gausslegendre(FP, rule.n)
wws = Iterators.product(ws, ws)
xxs = Iterators.product(xs, xs)

# Normalize the Plane's orthogonal vectors
uu = Meshes.unormalize(plane.u)
uv = Meshes.unormalize(plane.v)
uplane = Meshes.Plane(plane.p, uu, uv)

# Domain transformation: x ∈ [-1,1] ↦ t ∈ (-∞,∞)
t(x) = x / (1 - x^2)
t′(x) = (1 + x^2) / (1 - x^2)^2

# Integrate f over the Plane
domainunits = _units(uplane(0, 0))
function integrand(((wi, wj), (xi, xj)))
wi * wj * f(uplane(t(xi), t(xj))) * t′(xi) * t′(xj) * domainunits^2
end
return sum(integrand, zip(wws, xxs))
end

function integral(
f::F,
plane::Meshes.Plane,
rule::GaussKronrod;
diff_method::DM = Analytical(),
FP::Type{T} = Float64
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
_guarantee_analytical(Meshes.Plane, diff_method)

# Normalize the Plane's orthogonal vectors
uu = Meshes.unormalize(plane.u)
uv = Meshes.unormalize(plane.v)
uplane = Meshes.Plane(plane.p, uu, uv)

# Integrate f over the Plane
domainunits = _units(uplane(0, 0))^2
integrand(u, v) = f(uplane(u, v)) * domainunits
inner∫(v) = QuadGK.quadgk(u -> integrand(u, v), FP(-Inf), FP(Inf); rule.kwargs...)[1]
return QuadGK.quadgk(inner∫, FP(-Inf), FP(Inf); rule.kwargs...)[1]
rule::IntegrationRule;
kwargs...
)
paramfunction(t1, t2) = _parametric(plane, t1, t2)
param_plane = _ParametricGeometry(paramfunction, 2)
return _integral(f, param_plane, rule; kwargs...)
end

function integral(
f::F,
plane::Meshes.Plane,
rule::HAdaptiveCubature;
diff_method::DM = Analytical(),
FP::Type{T} = Float64
) where {F <: Function, DM <: DifferentiationMethod, T <: AbstractFloat}
_guarantee_analytical(Meshes.Plane, diff_method)

# Normalize the Plane's orthogonal vectors
uu = Meshes.unormalize(plane.u)
uv = Meshes.unormalize(plane.v)
uplane = Meshes.Plane(plane.p, uu, uv)

# Domain transformation: x ∈ [-1,1] ↦ t ∈ (-∞,∞)
t(x) = x / (1 - x^2)
t′(x) = (1 + x^2) / (1 - x^2)^2
############################################################################################
# Parametric
############################################################################################

# Integrate f over the Plane
domainunits = _units(uplane(0, 0))
function integrand(x::AbstractVector)
f(uplane(t(x[1]), t(x[2]))) * t′(x[1]) * t′(x[2]) * domainunits^2
end

# HCubature doesn't support functions that output Unitful Quantity types
# Establish the units that are output by f
testpoint_parametriccoord = zeros(FP, 2)
integrandunits = Unitful.unit.(integrand(testpoint_parametriccoord))
# Create a wrapper that returns only the value component in those units
uintegrand(uv) = Unitful.ustrip.(integrandunits, integrand(uv))
# Integrate only the unitless values
value = HCubature.hcubature(uintegrand, -ones(FP, 2), ones(FP, 2); rule.kwargs...)[1]

# Reapply units
return value .* integrandunits
function _parametric(plane::Meshes.Plane, t1, t2)
f1(t) = t / (1 - t^2)
f2(t) = 2t - 1
f = f1 ∘ f2
return plane(f(t1), f(t2))
end

################################################################################
# jacobian
################################################################################

_has_analytical(::Type{T}) where {T <: Meshes.Plane} = true
Loading
Loading