Skip to content
8 changes: 5 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ version = "1.1.0"
[deps]
EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extras?

LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
NearestNeighbors = "b8a86587-4115-5ab1-83bc-aa920d37bbce"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
Expand All @@ -28,14 +29,15 @@ FerriteSparseMatrixCSR = "SparseMatricesCSR"
[compat]
BlockArrays = "0.16, 1"
EnumX = "1"
HCubature = "1.7.0"
ForwardDiff = "0.10, 1"
HCubature = "1.7.0"
Interpolations = "0.16.1"
Metis = "1.3"
SparseMatricesCSR = "0.6"
NearestNeighbors = "0.4"
OrderedCollections = "1"
Preferences = "1"
Reexport = "1"
SparseMatricesCSR = "0.6"
StaticArrays = "1"
Tensors = "1.14"
WriteVTK = "1.13"
Expand All @@ -47,13 +49,13 @@ Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
FerriteGmsh = "4f95f4f8-b27c-4ae5-9a39-ea55e634e36b"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
Gmsh = "705231aa-382f-11e9-3f0c-b7cb4346fdeb"
HCubature = "19dc6840-f33b-545b-b366-655c7e3ffd49"
IterativeSolvers = "42fd0dbc-a981-5370-80f2-aaf504508153"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
Metis = "2679e427-3c69-5b7f-982b-ece356f1e94b"
NBInclude = "0db19996-df87-5ea3-a455-e3a50d440464"
OhMyThreads = "67456a42-1dca-4109-a031-0a68de7e3ad5"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
HCubature = "19dc6840-f33b-545b-b366-655c7e3ffd49"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
SparseMatricesCSR = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1"
Expand Down
12 changes: 12 additions & 0 deletions src/PointEvalHandler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,20 @@ function check_isoparametric_boundaries(::Type{RefSimplex{dim}}, x_local::Vec{di
return all(x -> x > -tol, x_local) && sum(x_local) - 1 < tol
end

function check_isoparametric_boundaries(::Type{RefPrism}, x_local::Vec{dim, T}, tol) where {dim, T}
# Positive and below the plane 1 - ξx - ξy
return all(x -> x > -tol, x_local) && x_local[1] + x_local[2] - 1 < tol
end

function check_isoparametric_boundaries(::Type{RefPyramid}, x_local::Vec{dim, T}, tol) where {dim, T}
# Positive and below the planes 1 - ξy - ξz and 1 - ξx - ξz
return all(x -> x > -tol, x_local) && x_local[1] + x_local[3] - 1 < tol && x_local[2] + x_local[3] - 1 < tol
end

cellcenter(::Type{<:RefHypercube{dim}}, _::Type{T}) where {dim, T} = zero(Vec{dim, T})
cellcenter(::Type{<:RefSimplex{dim}}, _::Type{T}) where {dim, T} = Vec{dim, T}((ntuple(d -> 1 / 3, dim)))
cellcenter(::Type{RefPrism}, _::Type{T}) where {T} = Vec{3, T}((1 / 3, 1 / 3, 0.5))
cellcenter(::Type{RefPyramid}, _::Type{T}) where {T} = Vec{3, T}((0.4, 0.4, 0.2))

_solve_helper(A::Tensor{2, dim}, b::Vec{dim}) where {dim} = inv(A) ⋅ b
_solve_helper(A::SMatrix{idim, odim}, b::Vec{idim, T}) where {odim, idim, T} = Vec{odim, T}(pinv(A) * b)
Expand Down
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ using OrderedCollections
using WriteVTK
import Metis
using HCubature: hcubature, hquadrature
using Interpolations

include("test_utils.jl")

Expand Down
2 changes: 1 addition & 1 deletion test/test_cellvalues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
end

# Check if the non-linear mapping is correct
# Only do this for one interpolation becuase it relise on AD on "iterative function"
# Only do this for one interpolation because it relies on AD on "iterative function"
if scalar_interpol === Lagrange{RefQuadrilateral, 2}()
coords_nl = [x + rand(x) * 0.01 for x in coords] # add some displacement to nodes
reinit!(cv, coords_nl)
Expand Down
2 changes: 1 addition & 1 deletion test/test_facevalues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
end

# Check if the non-linear mapping is correct
# Only do this for one interpolation becuase it relise on AD on "iterative function"
# Only do this for one interpolation because it relies on AD on "iterative function"
if scalar_interpol === Lagrange{RefQuadrilateral, 2}()
coords_nl = [x + rand(x) * 0.01 for x in coords] # add some displacement to nodes
reinit!(fv, coords_nl, facet)
Expand Down
57 changes: 40 additions & 17 deletions test/test_l2_projection.jl
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
# Tests a L2-projection of integration point values (to nodal values),
# determined from the function y = 1 + x[1]^2 + (2x[2])^2
function test_projection(order, refshape)
element = refshape == RefQuadrilateral ? Quadrilateral : Triangle
grid = generate_grid(element, (1, 1), Vec((0.0, 0.0)), Vec((1.0, 1.0)))

function test_projection(order, elementtype)
refshape = getrefshape(elementtype)
dim = Ferrite.getrefdim(refshape)
grid = single_element_grid(elementtype)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you change this to a single element grid? Previously we had triangles/tetrahedrons filled a square/cube.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, I didn't notice it.

ip = Lagrange{refshape, order}()
ip_geom = Lagrange{refshape, 1}()
qr = Ferrite._mass_qr(ip)
cv = CellValues(qr, ip, ip_geom)

# Create node values for the cell
f(x) = 1 + x[1]^2 + (2x[2])^2
# Nodal approximations for this simple grid when using linear interpolation
f_approx(i) = refshape == RefQuadrilateral ?
[0.1666666666666664, 1.166666666666667, 5.166666666666667, 4.166666666666666][i] :
[0.444444444444465, 1.0277777777778005, 4.027777777777753, 5.444444444444435][i]

# analytical values
function analytical(f)
qp_values = []
Expand All @@ -34,10 +30,31 @@ function test_projection(order, refshape)
point_vars = project(proj, qp_values, qr)
qp_values_matrix = reduce(hcat, qp_values)
point_vars_2 = project(proj, qp_values_matrix, qr)

if order == 1
# A linear approximation can not recover a quadratic solution,
# so projected values will be different from the analytical ones
ae = [f_approx(i) for i in 1:4]
qp_1D_coord = Float64[]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a small comment what you are trying to do here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to calculate the first order approximation values using linear extrapolation from the quadrature points instead of using precomputed hardcoded values. But since we use more than one element this won't work so I'll compute the values for other cell types and add them instead.

cellcoords = []
for cell in CellIterator(grid)
reinit!(cv, cell)
append!(cellcoords, getcoordinates(cell))
r = [spatial_coordinate(cv, qp, getcoordinates(cell)) for qp in 1:getnquadpoints(cv)]
for i in 1:dim
append!(qp_1D_coord, getindex.(r, i))
end
end
# TODO: clean this
qp_1D_coord .= round.(qp_1D_coord; digits = 12)
sort!(unique!(qp_1D_coord))
unique!(cellcoords)
if dim == 2
f_res = [f((x_1, x_2)) for x_1 in qp_1D_coord, x_2 in qp_1D_coord]
elseif dim == 3
f_res = [f((x_1, x_2, x_3)) for x_1 in qp_1D_coord, x_2 in qp_1D_coord, x_3 in qp_1D_coord]
end
interp_linear = linear_interpolation(ntuple(_ -> qp_1D_coord, dim), f_res; extrapolation_bc = Interpolations.Line())
ae = [interp_linear(coords...) for coords in cellcoords]
elseif order == 2
# For a quadratic approximation the analytical solution is recovered
ae = zeros(length(point_vars))
Expand All @@ -50,7 +67,7 @@ function test_projection(order, refshape)
qp_values = analytical(f_vector)
point_vars = project(proj, qp_values, qr)
if order == 1
ae = [Vec{1, Float64}((f_approx(j),)) for j in 1:4]
ae = [Vec{1, Float64}((interp_linear(coords...),)) for coords in cellcoords]
elseif order == 2
ae = zeros(length(point_vars))
apply_analytical!(ae, proj.dh, :_, x -> f_vector(x)[1])
Expand All @@ -65,7 +82,7 @@ function test_projection(order, refshape)
point_vars = project(proj, qp_values, qr)
point_vars_2 = project(proj, qp_values_matrix, qr)
if order == 1
ae = [Tensor{2, 2, Float64}((f_approx(i), 2 * f_approx(i), 3 * f_approx(i), 4 * f_approx(i))) for i in 1:4]
ae = [Tensor{2, 2, Float64}((interp_linear(coords...), 2 * interp_linear(coords...), 3 * interp_linear(coords...), 4 * interp_linear(coords...))) for coords in cellcoords]
elseif order == 2
ae = zeros(4, length(point_vars))
for i in 1:4
Expand All @@ -82,7 +99,7 @@ function test_projection(order, refshape)
point_vars = project(proj, qp_values, qr)
point_vars_2 = project(proj, qp_values_matrix, qr)
if order == 1
ae = [SymmetricTensor{2, 2, Float64}((f_approx(i), 2 * f_approx(i), 3 * f_approx(i))) for i in 1:4]
ae = [SymmetricTensor{2, 2, Float64}((interp_linear(coords...), 2 * interp_linear(coords...), 3 * interp_linear(coords...))) for coords in cellcoords]
elseif order == 2
ae = zeros(3, length(point_vars))
for i in 1:3
Expand All @@ -98,7 +115,8 @@ function test_projection(order, refshape)
else
bad_order = 1
end
@test_throws LinearAlgebra.PosDefException L2Projector(ip, grid; qr_lhs = QuadratureRule{refshape}(bad_order))
# This is broken with single elements it seems like
# @test_throws LinearAlgebra.PosDefException L2Projector(ip, grid; qr_lhs = QuadratureRule{refshape}(bad_order))
return
end

Expand Down Expand Up @@ -494,10 +512,15 @@ function test_l2proj_errorpaths()
end

@testset "Test L2-Projection" begin
test_projection(1, RefQuadrilateral)
test_projection(1, RefTriangle)
test_projection(2, RefQuadrilateral)
test_projection(2, RefTriangle)
for ref_shape in (
Quadrilateral,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are not refshapes

Hexahedron,
Tetrahedron,
# Pyramid,
# Wedge
), degree in 1:2
test_projection(degree, ref_shape)
end
test_projection_subset_of_mixedgrid()
test_add_projection_grid()
test_projection_mixedgrid()
Expand Down
6 changes: 6 additions & 0 deletions test/test_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,9 @@ function grid_with_inserted_quad(grid::Grid{2, Triangle}, nrs::NTuple{2, Int}; u
end
# TODO: Update sets (not needed for current usage)
end

function single_element_grid(::Type{CellType}) where {RefShape, CellType <: Ferrite.AbstractCell{RefShape}}
nodes = Node.(Ferrite.reference_coordinates(Lagrange{RefShape, 1}()))
cells = [CellType(ntuple(i -> i, length(nodes)))]
return Grid(cells, nodes)
end
Loading