Skip to content

Commit 711d5b4

Browse files
mikeingoldgithub-actions[bot]JoshuaLampert
authored
Generalize differential element calculation to n-dims (#101)
* Add CliffordNumbers to deps * Add _clifford utility * Bugfix * Change _clifford to _kvector, avoid an allocation * Explicit namespace * Add _Vec utility * Generalize differential to n-dims * using CliffordNumbers * Explicit namespace, disable _Vec utility * Bugfix * Switch CliffordNumbers from import to using * Remove _Vec utility * Drop stale explicit import * Convert LinearAlgebra to an import * Enable full testing of 4D Box * Analytic integrand/solution for 4D Box * Bugfix * Error when using GK rule >3D * Bugfix * Add explicit rtol for 4D Box * Bump minimum CliffordNumbers (downgrade failing) * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Bump minimum again * Convert all generic errors to specific errors * Apply suggestions from code review Co-authored-by: Joshua Lampert <[email protected]> * Try new method for units handling * Bugfix * Generalize _units to all geometry types * Condense generic GaussKronrod cases above 2D * Apply format suggestion [skip ci] Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update obsoleted comment * Add tests for utils * Change jacobian API to return via ntuple * Apply format suggestions Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Remove _ukvector [skip ci] Co-authored-by: Joshua Lampert <[email protected]> * Organization * Remove tests for _ukvector * Remove @inline * Increase minimum CliffordNumbers version --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joshua Lampert <[email protected]>
1 parent 7111f32 commit 711d5b4

File tree

10 files changed

+84
-39
lines changed

10 files changed

+84
-39
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ uuid = "dadec2fd-bbe0-4da4-9dbe-476c782c8e47"
33
version = "0.14.1"
44

55
[deps]
6+
CliffordNumbers = "3998ac73-6bd4-4031-8035-f167dd3ed523"
67
CoordRefSystems = "b46f11dc-f210-4604-bfba-323c1ec968cb"
78
FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838"
89
HCubature = "19dc6840-f33b-545b-b366-655c7e3ffd49"
@@ -12,6 +13,7 @@ QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
1213
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
1314

1415
[compat]
16+
CliffordNumbers = "0.1.4"
1517
CoordRefSystems = "0.12, 0.13, 0.14, 0.15"
1618
FastGaussQuadrature = "1"
1719
HCubature = "1.5"

src/MeshIntegrals.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
module MeshIntegrals
2+
using CliffordNumbers: CliffordNumbers, VGA,
23
using CoordRefSystems: CoordRefSystems, CRS
3-
using LinearAlgebra: LinearAlgebra, norm, ×,
44

55
import FastGaussQuadrature
66
import HCubature
7+
import LinearAlgebra
78
import Meshes
89
import QuadGK
910
import Unitful

src/differentiation.jl

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ function jacobian(
4545
end
4646
end
4747

48-
return map(n -> ∂ₙr(ts, n), 1:Dim)
48+
return ntuple(n -> ∂ₙr(ts, n), Dim)
4949
end
5050

5151
function jacobian(
@@ -75,7 +75,7 @@ function jacobian(
7575
sigma(i) = B(i, N - 1)(t) .* (P[(i + 1) + 1] - P[(i) + 1])
7676
derivative = N .* sum(sigma, 0:(N - 1))
7777

78-
return [derivative]
78+
return (derivative,)
7979
end
8080

8181
################################################################################
@@ -91,17 +91,16 @@ function for `geometry` at arguments `ts`.
9191
function differential(
9292
geometry::G,
9393
ts::V
94-
) where {G <: Meshes.Geometry, V <: Union{AbstractVector, Tuple}}
94+
) where {M, CRS, G <: Meshes.Geometry{M, CRS}, V <: Union{AbstractVector, Tuple}}
95+
# Calculate the Jacobian, convert Vec -> KVector
9596
J = jacobian(geometry, ts)
97+
J_kvecs = Iterators.map(_kvector, J)
9698

97-
# TODO generalize this with geometric algebra, e.g.: norm(foldl(∧, J))
98-
if length(J) == 1
99-
return norm(J[1])
100-
elseif length(J) == 2
101-
return norm(J[1] × J[2])
102-
elseif length(J) == 3
103-
return abs((J[1] × J[2]) J[3])
104-
else
105-
error("Not implemented yet. Please report this as an Issue on GitHub.")
106-
end
99+
# Extract units from Geometry type
100+
Dim = Meshes.paramdim(geometry)
101+
units = _units(geometry)^Dim
102+
103+
# Return norm of the exterior products
104+
element = foldl(, J_kvecs)
105+
return LinearAlgebra.norm(element) * units
107106
end

src/integral.jl

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ function _integral(
4848
return _integral_gk_1d(f, geometry, rule; kwargs...)
4949
elseif N == 2
5050
return _integral_gk_2d(f, geometry, rule; kwargs...)
51-
elseif N == 3
52-
return _integral_gk_3d(f, geometry, rule; kwargs...)
51+
else
52+
_error_unsupported_combination("geometry with more than two parametric dimensions",
53+
"GaussKronrod")
5354
end
5455
end
5556

@@ -126,13 +127,3 @@ function _integral_gk_2d(
126127
∫₁(v) = QuadGK.quadgk(u -> integrand(u, v), zero(FP), one(FP); rule.kwargs...)[1]
127128
return QuadGK.quadgk(v -> ∫₁(v), zero(FP), one(FP); rule.kwargs...)[1]
128129
end
129-
130-
# Integrating volumes with GaussKronrod not supported by default
131-
function _integral_gk_3d(
132-
f,
133-
geometry,
134-
rule::GaussKronrod;
135-
FP::Type{T} = Float64
136-
) where {T <: AbstractFloat}
137-
error("Integrating this volume type with GaussKronrod not supported.")
138-
end

src/integral_aliases.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ function lineintegral(
2525
if N == 1
2626
return integral(f, geometry, rule; kwargs...)
2727
else
28-
error("Performing a line integral on a geometry with $N parametric dimensions not supported.")
28+
throw(ArgumentError("Performing a line integral on a geometry \
29+
with $N parametric dimensions not supported."))
2930
end
3031
end
3132

@@ -56,7 +57,8 @@ function surfaceintegral(
5657
if N == 2
5758
return integral(f, geometry, rule; kwargs...)
5859
else
59-
error("Performing a surface integral on a geometry with $N parametric dimensions not supported.")
60+
throw(ArgumentError("Performing a surface integral on a geometry \
61+
with $N parametric dimensions not supported."))
6062
end
6163
end
6264

@@ -87,6 +89,7 @@ function volumeintegral(
8789
if N == 3
8890
return integral(f, geometry, rule; kwargs...)
8991
else
90-
error("Performing a volume integral on a geometry with $N parametric dimensions not supported.")
92+
throw(ArgumentError("Performing a volume integral on a geometry \
93+
with $N parametric dimensions not supported."))
9194
end
9295
end

src/specializations/Tetrahedron.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function integral(
1515
rule::GaussLegendre;
1616
FP::Type{T} = Float64
1717
) where {F <: Function, T <: AbstractFloat}
18-
error("Integrating a Tetrahedron with GaussLegendre not supported.")
18+
_error_unsupported_combination("Tetrahedron", "GaussLegendre")
1919
end
2020

2121
function integral(
@@ -40,5 +40,5 @@ function integral(
4040
rule::HAdaptiveCubature;
4141
FP::Type{T} = Float64
4242
) where {F <: Function, T <: AbstractFloat}
43-
error("Integrating a Tetrahedron with HAdaptiveCubature not supported.")
43+
_error_unsupported_combination("Tetrahedron", "HAdaptiveCubature")
4444
end

src/utils.jl

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,23 @@ function _gausslegendre(T, n)
88
return T.(xs), T.(ws)
99
end
1010

11-
# Extract the length units used by the CRS of a Point
12-
_units(pt::Meshes.Point{M, CRS}) where {M, CRS} = first(CoordRefSystems.units(CRS))
11+
# Extract the length units used by the CRS of a Geometry
12+
function _units(g::Meshes.Geometry{M, CRS}) where {M, CRS}
13+
return Unitful.unit(CoordRefSystems.lentype(CRS))
14+
end
15+
16+
# Common error message structure
17+
function _error_unsupported_combination(geometry, rule)
18+
msg = "Integrating a $geometry using a $rule rule not supported."
19+
throw(ArgumentError(msg))
20+
end
21+
22+
################################################################################
23+
# CliffordNumbers Interface
24+
################################################################################
25+
26+
# Meshes.Vec -> ::CliffordNumber.KVector
27+
function _kvector(v::Meshes.Vec{Dim, T}) where {Dim, T}
28+
ucoords = Iterators.map(Unitful.ustrip, v.coords)
29+
return CliffordNumbers.KVector{1, VGA(Dim)}(ucoords...)
30+
end

test/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[deps]
22
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
33
ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7"
4+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
45
Meshes = "eacbb407-ea5a-433e-ab97-5258b1ca43fa"
56
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
67
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
@@ -12,6 +13,7 @@ Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
1213
[compat]
1314
Aqua = "0.7, 0.8"
1415
ExplicitImports = "1.6.0"
16+
LinearAlgebra = "1"
1517
Meshes = "0.50, 0.51"
1618
QuadGK = "2.1.1"
1719
SpecialFunctions = "2"

test/combinations.jl

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,32 @@ end
169169
end
170170

171171
@testitem "Meshes.Box 4D" setup=[Setup] begin
172-
a = zero(Float64)
173-
b = zero(Float64)
174-
box = Box(Point(a, a, a, a), Point(b, b, b, b))
172+
a = π
173+
box = Box(Point(0, 0, 0, 0), Point(a, a, a, a))
175174

176-
f = p -> one(Float64)
175+
function f(p::P) where {P <: Meshes.Point}
176+
x1, x2, x3, x4 = ustrip.(to(p).coords)
177+
σ(x) = sqrt(a^2 - x^2)
178+
(σ(x1) + σ(x2) + σ(x3) + σ(x4)) * u"Ω/m^4"
179+
end
180+
fv(p) = fill(f(p), 3)
177181

178-
# Test for currently-unsupported >3D differentials
179-
@test integral(f, box)1.0u"m^4" broken=true
182+
# Scalar integrand
183+
sol = 4a^3 ** a^2 / 4) * u"Ω"
184+
@test integral(f, box, GaussLegendre(100))sol rtol=1e-6
185+
@test_throws "not supported" integral(f, box, GaussKronrod())
186+
@test integral(f, box, HAdaptiveCubature(rtol = 1e-6))sol rtol=1e-6
187+
188+
# Vector integrand
189+
vsol = fill(sol, 3)
190+
@test integral(fv, box, GaussLegendre(100))vsol rtol=1e-6
191+
@test_throws "not supported" integral(fv, box, GaussKronrod())
192+
@test integral(fv, box, HAdaptiveCubature(rtol = 1e-6))vsol rtol=1e-6
193+
194+
# Integral aliases
195+
@test_throws "not supported" lineintegral(f, box)
196+
@test_throws "not supported" surfaceintegral(f, box)
197+
@test_throws "not supported" volumeintegral(f, box)
180198

181199
# Test jacobian with wrong number of parametric coordinates
182200
@test_throws ArgumentError jacobian(box, zeros(2))

test/utils.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@testitem "Utilities" setup=[Setup] begin
2+
using LinearAlgebra: norm
3+
4+
# _kvector
5+
v = Meshes.Vec(3, 4)
6+
@test norm(MeshIntegrals._kvector(v)) 5.0
7+
8+
# _units
9+
p = Point(1.0u"cm", 2.0u"mm", 3.0u"m")
10+
@test MeshIntegrals._units(p) == u"m"
11+
end

0 commit comments

Comments
 (0)