Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions src/differentiation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function jacobian(
geometry::G,
ts::Union{AbstractVector{T}, Tuple{T, Vararg{T}}}
) where {G <: Geometry, T <: AbstractFloat}
return jacobian(geometry, ts, _default_method(G))
return jacobian(geometry, ts, _default_diff_method(G))
end

function jacobian(
Expand Down Expand Up @@ -107,7 +107,7 @@ possible and finite difference approximations otherwise.
function differential(
geometry::G,
ts::Union{AbstractVector{T}, Tuple{T, Vararg{T}}},
diff_method::DifferentiationMethod = _default_method(G)
diff_method::DifferentiationMethod = _default_diff_method(G)
) where {G <: Geometry, T <: AbstractFloat}
J = Iterators.map(_KVector, jacobian(geometry, ts, diff_method))
return LinearAlgebra.norm(foldl(∧, J))
Expand Down
22 changes: 13 additions & 9 deletions src/integral.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function _integral(
geometry,
rule::GaussKronrod;
FP::Type{T} = Float64,
diff_method::DM = _default_method(geometry)
diff_method::DM = _default_diff_method(geometry)
) where {DM <: DifferentiationMethod, T <: AbstractFloat}
# Implementation depends on number of parametric dimensions over which to integrate
N = Meshes.paramdim(geometry)
Expand Down Expand Up @@ -70,24 +70,28 @@ function _integral(
geometry,
rule::GaussLegendre;
FP::Type{T} = Float64,
diff_method::DM = _default_method(geometry)
diff_method::DM = _default_diff_method(geometry)
) where {DM <: DifferentiationMethod, T <: AbstractFloat}
N = Meshes.paramdim(geometry)

# Get Gauss-Legendre nodes and weights for a region [-1,1]^N
xs, ws = _gausslegendre(FP, rule.n)
weights = Iterators.product(ntuple(Returns(ws), N)...)
nodes = Iterators.product(ntuple(Returns(xs), N)...)
# Get Gauss-Legendre nodes and weights of type FP for a region [-1,1]ᴺ
xs, ws = FastGaussQuadrature.gausslegendre(rule.n)
xsFP = Iterators.map(FP, xs)
wsFP = Iterators.map(FP, ws)
weight_grid = Iterators.product(ntuple(Returns(wsFP), N)...)
node_grid = Iterators.product(ntuple(Returns(xsFP), N)...)

# Domain transformation: x [-1,1] ↦ t [0,1]
t(x) = (1 // 2) * x + (1 // 2)

function integrand((weights, nodes))
ts = t.(nodes)
# Transforms nodes/xs, store in an NTuple
ts = ntuple(i -> t(nodes[i]), length(nodes))
# Integrand function
prod(weights) * f(geometry(ts...)) * differential(geometry, ts, diff_method)
end

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

# HAdaptiveCubature
Expand All @@ -96,7 +100,7 @@ function _integral(
geometry,
rule::HAdaptiveCubature;
FP::Type{T} = Float64,
diff_method::DM = _default_method(geometry)
diff_method::DM = _default_diff_method(geometry)
) where {DM <: DifferentiationMethod, T <: AbstractFloat}
N = Meshes.paramdim(geometry)

Expand Down
50 changes: 31 additions & 19 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,62 @@
# Misc. Internal Tools
################################################################################

# Calculate Gauss-Legendre nodes/weights and convert to type T
function _gausslegendre(T, n)
xs, ws = FastGaussQuadrature.gausslegendre(n)
return T.(xs), T.(ws)
end

# Common error message structure
function _error_unsupported_combination(geometry, rule)
msg = "Integrating a $geometry using a $rule rule not supported."
throw(ArgumentError(msg))
end

# Return an NTuple{N, T} of zeros; same interface as Base.zeros() but faster
_zeros(T::DataType, N::Int64) = ntuple(_ -> zero(T), N)
_zeros(N::Int) = _zeros(Float64, N)

# Return an NTuple{N, T} of ones; same interface as Base.ones() but faster
_ones(T::DataType, N::Int64) = ntuple(_ -> one(T), N)
_ones(N::Int) = _ones(Float64, N)

################################################################################
# DifferentiationMethod
################################################################################

# Return the default DifferentiationMethod instance for a particular geometry type
function _default_method(
function _default_diff_method(
g::Type{G}
) where {G <: Geometry}
return FiniteDifference()
end

# Return the default DifferentiationMethod instance for a particular geometry instance
_default_method(g::G) where {G <: Geometry} = _default_method(G)
_default_diff_method(g::G) where {G <: Geometry} = _default_diff_method(G)

################################################################################
# CliffordNumbers and Units
# Numerical Tools
################################################################################

# Meshes.Vec -> Unitful.Quantity{CliffordNumber.KVector}
"""
_KVector(v::Meshes.Vec) -> Unitful.Quantity{CliffordNumbers.KVector}

Convert a `Vec` to a Unitful KVector.
"""
function _KVector(v::Meshes.Vec{Dim, T}) where {Dim, T}
ucoords = Iterators.map(Unitful.ustrip, v.coords)
return CliffordNumbers.KVector{1, VGA(Dim)}(ucoords...) * _units(v)
end

# Extract the length units used by the CRS of a Geometry
"""
_units(geometry)

Return the Unitful.jl units associated with a particular `geometry`.
"""
_units(::Geometry{M, CRS}) where {M, CRS} = Unitful.unit(CoordRefSystems.lentype(CRS))
_units(::Meshes.Vec{Dim, T}) where {Dim, T} = Unitful.unit(T)

"""
_zeros(T = Float64, N)

Return an `NTuple{N, T}` filled with zeros. This method avoids allocating an array, which
happens when using `Base.zeros`.
"""
_zeros(T::DataType, N::Int64) = ntuple(_ -> zero(T), N)
_zeros(N::Int) = _zeros(Float64, N)

"""
_ones(T = Float64, N)

Return an `NTuple{N, T}` filled with ones. This method avoids allocating an array, which
happens when using `Base.ones`.
"""
_ones(T::DataType, N::Int64) = ntuple(_ -> one(T), N)
_ones(N::Int) = _ones(Float64, N)
4 changes: 1 addition & 3 deletions test/combinations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ end
end

@testitem "Meshes.BezierCurve" setup=[Setup] begin
curve = BezierCurve(
[Point(t * u"m", sin(t) * u"m", 0.0u"m") for t in range(-pi, pi, length = 361)]
)
curve = BezierCurve([Point(t, sin(t), 0) for t in range(-pi, pi, length = 361)])

function f(p::P) where {P <: Meshes.Point}
ux = ustrip(p.coords.x)
Expand Down
11 changes: 4 additions & 7 deletions test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,12 @@
end

@testitem "DifferentiationMethod" setup=[Setup] begin
using MeshIntegrals: _default_method
using MeshIntegrals: _default_diff_method

# Test geometries
# _default_diff_method
sphere = Sphere(Point(0, 0, 0), 1.0)
triangle = Triangle(Point(0, 0, 0), Point(0, 1, 0), Point(1, 0, 0))

# _default_method
@test _default_method(Meshes.Sphere) isa FiniteDifference
@test _default_method(sphere) isa FiniteDifference
@test _default_diff_method(Meshes.Sphere) isa FiniteDifference
@test _default_diff_method(sphere) isa FiniteDifference

# FiniteDifference
@test FiniteDifference().ε ≈ 1e-6
Expand Down
Loading