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

Reference interpolation and integration #3

Merged
merged 5 commits into from
Oct 4, 2023
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
26 changes: 0 additions & 26 deletions src/Geometry/Geometry.jl

This file was deleted.

16 changes: 15 additions & 1 deletion src/Inti.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,22 @@ const PROJECT_ROOT = pkgdir(Inti)

using StaticArrays

# helper functions
include("utils.jl")
include("Geometry/Geometry.jl")

# basic interpolation and integration
include("reference_shapes.jl")
include("reference_interpolation.jl")
include("quad_rules_tables.jl")
include("reference_integration.jl")

# # geometry and meshes
# include("domain.jl")
# include("mesh.jl")

# # integral operators
# include("integral_potentials.jl")
# include("integral_operators.jl")


end
58 changes: 58 additions & 0 deletions src/quad_rules_tables.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#=
Tabulated Gaussian quadrature rules from GMSH.
Obtained from `https://gitlab.onelab.info/gmsh/gmsh/-/blob/gmsh_4_7_0/Numeric/GaussQuadratureTri.cpp`
and `https://gitlab.onelab.info/gmsh/gmsh/-/blob/gmsh_4_7_0/Numeric/GaussQuadratureTet.cpp`.
=#

include("quad_rules_tables_tetrahedron.jl")
include("quad_rules_tables_triangle.jl")

##
# Dictionaries that contains the quadrature rules
# for various `ReferenceShape`. The dictionary
# key represents the number of quadrature nodes.

const TRIANGLE_GAUSS_QRULES = Dict(1 => TRIANGLE_G1N1,
3 => TRIANGLE_G2N3,
4 => TRIANGLE_G3N4,
6 => TRIANGLE_G4N6,
7 => TRIANGLE_G5N7,
12 => TRIANGLE_G6N12,
13 => TRIANGLE_G7N13,
16 => TRIANGLE_G8N16,
19 => TRIANGLE_G9N19,
25 => TRIANGLE_G10N25,
33 => TRIANGLE_G12N33)

# map a desired quadrature order to the number of nodes
const TRIANGLE_GAUSS_ORDER_TO_NPTS = Dict(1 => 1,
2 => 3,
3 => 4,
4 => 6,
5 => 7,
6 => 12,
7 => 13,
8 => 16,
9 => 19,
10 => 25,
12 => 33)
const TRIANGLE_GAUSS_NPTS_TO_ORDER = Dict((v, k) for (k, v) in TRIANGLE_GAUSS_ORDER_TO_NPTS)

const TETAHEDRON_GAUSS_QRULES = Dict(1 => TETAHEDRON_G1N1,
4 => TETAHEDRON_G2N4,
5 => TETAHEDRON_G3N5,
11 => TETAHEDRON_G4N11,
14 => TETAHEDRON_G5N14,
24 => TETAHEDRON_G6N24,
31 => TETAHEDRON_G7N31,
43 => TETAHEDRON_G8N43)

# map a desired quadrature order to the number of nodes
const TETRAHEDRON_GAUSS_ORDER_TO_NPTS = Dict(1 => 1, 2 => 4, 3 => 5, 4 => 11, 5 => 14,
6 => 24, 7 => 31, 8 => 43)
const TETRAHEDRON_GAUSS_NPTS_TO_ORDER = Dict((v, k)
for (k, v) in TETRAHEDRON_GAUSS_ORDER_TO_NPTS)

##
const GAUSS_QRULES = Dict(ReferenceTriangle => TRIANGLE_GAUSS_QRULES,
ReferenceTetrahedron => TETAHEDRON_GAUSS_QRULES)
326 changes: 326 additions & 0 deletions src/quad_rules_tables_tetrahedron.jl

Large diffs are not rendered by default.

215 changes: 215 additions & 0 deletions src/quad_rules_tables_triangle.jl

Large diffs are not rendered by default.

232 changes: 232 additions & 0 deletions src/reference_integration.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
"""
abstract type ReferenceQuadrature{D}

A quadrature rule for integrating a function over the domain `D <: ReferenceShape`.

Calling `x,w = q()` returns the nodes `x`, given as `SVector`s, and weights `w`,
for performing integration over `domain(q)`.
"""
abstract type ReferenceQuadrature{D} end

"""
domain(q::ReferenceQuadrature)

The domain of integratino for quadrature rule `q`.
"""
domain(q::ReferenceQuadrature{D}) where {D} = D()

"""
qcoords(q)

Return the coordinate of the quadrature nodes associated with `q`.
"""
qcoords(q::ReferenceQuadrature) = q()[1]

Check warning on line 23 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L23

Added line #L23 was not covered by tests

"""
qweights(q)

Return the quadrature weights associated with `q`.
"""
qweights(q::ReferenceQuadrature) = q()[2]

Check warning on line 30 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L30

Added line #L30 was not covered by tests

function (q::ReferenceQuadrature)()
return interface_method(q)

Check warning on line 33 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L32-L33

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

Base.length(q::ReferenceQuadrature) = length(qweights(q))

Check warning on line 36 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L36

Added line #L36 was not covered by tests

"""
integrate(f,q::ReferenceQuadrature)
integrate(f,x,w)

Integrate the function `f` using the quadrature rule `q`. This is simply
`sum(f.(x) .* w)`, where `x` and `w` are the quadrature nodes and weights,
respectively.

The function `f` should take an `SVector` as input.
"""
function integrate(f, q::ReferenceQuadrature)
x, w = q()
if domain(q) == ReferenceLine()
return integrate(x -> f(x[1]), x, w)
else
return integrate(f, x, w)
end
end

function integrate(f, x, w)
sum(zip(x, w)) do (x, w)
return f(x) * prod(w)
end
end

## Define some one-dimensional quadrature rules
"""
struct Fejer{N}

`N`-point Fejer's first quadrature rule for integrating a function over `[0,1]`.
Exactly integrates all polynomials of degree `≤ N-1`.

```jldoctest
using Inti

q = Inti.Fejer(;order=10)

Inti.integrate(cos,q) ≈ sin(1) - sin(0)

# output

true
```

"""
struct Fejer{N} <: ReferenceQuadrature{ReferenceLine} end

Fejer(n::Int) = Fejer{n}()

Fejer(; order::Int) = Fejer(order + 1)

# N point fejer quadrature integrates all polynomials up to degree N-1
"""
order(q::ReferenceQuadrature)

A quadrature of order `p` integrates all polynomials of degree `≤ p`.
"""
order(::Fejer{N}) where {N} = N - 1

Check warning on line 95 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L95

Added line #L95 was not covered by tests

@generated function (q::Fejer{N})() where {N}
theta = [(2j - 1) * π / (2 * N) for j in 1:N]
x = -cos.(theta)
w = zero(x)
for j in 1:N
tmp = 0.0
for l in 1:floor(N / 2)
tmp += 1 / (4 * l^2 - 1) * cos(2 * l * theta[j])
end
w[j] = 2 / N * (1 - 2 * tmp)
end
xs = svector(i -> SVector(0.5 * (x[i] + 1)), N)
ws = svector(i -> w[i] / 2, N)
return xs, ws
end

"""
struct Gauss{D,N} <: ReferenceQuadrature{D}

Tabulated `N`-point symmetric Gauss quadrature rule for integration over `D`.
"""
struct Gauss{D,N} <: ReferenceQuadrature{D}
# gauss quadrature should be constructed using the order, and not the number
# of nodes. This ensures you don't instantiate quadratures which are not
# tabulated.
function Gauss(; domain, order)
domain == :triangle && (domain = ReferenceTriangle())
domain == :tetrehedron && (domain = ReferenceTetrahedron())
if domain isa ReferenceTriangle
msg = "quadrature of order $order not available for ReferenceTriangle"
haskey(TRIANGLE_GAUSS_ORDER_TO_NPTS, order) || error(msg)
n = TRIANGLE_GAUSS_ORDER_TO_NPTS[order]
elseif domain isa ReferenceTetrahedron
msg = "quadrature of order $order not available for ReferenceTetrahedron"
haskey(TETRAHEDRON_GAUSS_ORDER_TO_NPTS, order) || error(msg)
n = TETRAHEDRON_GAUSS_ORDER_TO_NPTS[order]
else
error("Tabulated Gauss quadratures only available for `ReferenceTriangle` or `ReferenceTetrahedron`")

Check warning on line 134 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L134

Added line #L134 was not covered by tests
end
return new{typeof(domain),n}()
end
end

function order(q::Gauss{ReferenceTriangle,N}) where {N}
return TRIANGLE_GAUSS_NPTS_TO_ORDER[N]

Check warning on line 141 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L140-L141

Added lines #L140 - L141 were not covered by tests
end

function order(q::Gauss{ReferenceTetrahedron,N}) where {N}
return TETRAHEDRON_GAUSS_NPTS_TO_ORDER[N]

Check warning on line 145 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L144-L145

Added lines #L144 - L145 were not covered by tests
end

@generated function (q::Gauss{D,N})() where {D,N}
x, w = _get_gauss_qcoords_and_qweights(D, N)
return :($x, $w)
end

"""
_get_gauss_and_qweights(R::Type{<:ReferenceShape{D}}, N) where D

Returns the `N`-point symmetric gaussian qnodes and qweights `(x, w)` for integration over `R`.
"""
function _get_gauss_qcoords_and_qweights(R::Type{<:ReferenceShape}, N)
D = ambient_dimension(R())
if !haskey(GAUSS_QRULES, R) || !haskey(GAUSS_QRULES[R], N)
error("quadrature rule not found")

Check warning on line 161 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L161

Added line #L161 was not covered by tests
end
qrule = GAUSS_QRULES[R][N]
@assert length(qrule) == N
# qnodes
qnodestype = SVector{N,SVector{D,Float64}}
x = qnodestype([q[1] for q in qrule])
# qweights
qweightstype = SVector{N,Float64}
w = qweightstype([q[2] for q in qrule])
return x, w
end

"""
TensorProductQuadrature{N,Q}

A tensor-product of one-dimension quadrature rules. Integrates over `[0,1]^N`.

# Examples
```julia
qx = Fejer(10)
qy = TrapezoidalOpen(15)
q = TensorProductQuadrature(qx,qy)
```
"""
struct TensorProductQuadrature{N,Q} <: ReferenceQuadrature{ReferenceHyperCube{N}}
quads1d::Q
end

function TensorProductQuadrature(q...)
N = length(q)
Q = typeof(q)
return TensorProductQuadrature{N,Q}(q)
end

function (q::TensorProductQuadrature{N})() where {N}
nodes1d = ntuple(N) do i
x1d, _ = q.quads1d[i]()
return map(x -> x[1], x1d) # convert the `SVector{1,T}` to just `T`
end
weights1d = map(q -> q()[2], q.quads1d)
nodes_iter = (SVector(x) for x in Iterators.product(nodes1d...))
weights_iter = (prod(w) for w in Iterators.product(weights1d...))
return nodes_iter, weights_iter
end

"""
qrule_for_reference_shape(ref,order)

Given a `ref`erence shape and a desired quadrature `order`, return
an appropiate quadrature rule.
"""
function qrule_for_reference_shape(ref, order)
if ref === ReferenceLine() || ref === :line
return Fejer(; order)

Check warning on line 215 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L213-L215

Added lines #L213 - L215 were not covered by tests
# return Fejer(; order)
elseif ref === ReferenceSquare() || ref === :square
qx = qrule_for_reference_shape(ReferenceLine(), order)
qy = qx
return TensorProductQuadrature(qx, qy)
elseif ref === ReferenceCube() || ref === :cube
qx = qrule_for_reference_shape(ReferenceLine(), order)
qy = qz = qx
return TensorProductQuadrature(qx, qy, qz)
elseif ref isa ReferenceTriangle || ref === :triangle
return Gauss(; domain=ref, order=order)
tanderson92 marked this conversation as resolved.
Show resolved Hide resolved
elseif ref isa ReferenceTetrahedron || ref === :tetrahedron
return Gauss(; domain=ref, order=order)

Check warning on line 228 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L217-L228

Added lines #L217 - L228 were not covered by tests
else
error("no appropriate quadrature rule found.")

Check warning on line 230 in src/reference_integration.jl

View check run for this annotation

Codecov / codecov/patch

src/reference_integration.jl#L230

Added line #L230 was not covered by tests
end
end
Loading
Loading