Developer Documentation

Note that these functions could be removed or change in behavior between minor version changes! Use and dispatch on these with care!

Architecture

FerriteViz is structured in three layers, following the ParaView model:

  1. Tessellation (src/tessellation.jl): every reference shape describes its surface triangulation and its wireframe edge segments with a single FerriteViz.ReferenceTessellation — the edges are separate from the triangles because the triangulation contains interior diagonals that are not finite element edges. FEData lays this out per cell with duplicated vertices, so discontinuous (L2) fields render with their inter-element jumps intact, and maps reference coordinates through the cell's geometric interpolation. High-order cells (or high-order fields) get their reference tessellation subdivided first (FerriteViz.subdivide, driven by the Refine filter whose automatic mode FEData applies unless constructed with adaptive=false), so curved geometry and deformation render curved. Since the wireframe's vertices are ordinary tessellation vertices, meshplot inherits warping, clipping and refinement from the pipeline without any special-casing. src/qptessellation.jl adds a second, quadrature rule dependent reference geometry: the Voronoi partition of a reference shape induced by its quadrature points, which AddQuadraturePointData uses to render internal variables piecewise constant.
  2. Data pipeline (src/dataset.jl, src/filters.jl): FEData holds the solution as an Observable plus named point-/cell-data arrays; filters derive new datasets while sharing the source observable, so FerriteViz.update! propagates through the entire pipeline. The coordinates and triangles live in ShaderAbstractions.Buffers shared into a GeometryBasics.Mesh — updates mutate GPU data in place without rebuilding.
  3. Representations (src/representations.jl): thin Makie recipes that take an FEData and the name of the array to color by.

Adding support for a custom cell type

Implement one method. For a 3D reference shape, FerriteViz.facet_based_tessellation usually is all you need — e.g. if pyramids were not already supported, this would make FEData and all representations work for them:

FerriteViz.reference_tessellation(::Type{Ferrite.RefPyramid}) =
    FerriteViz.facet_based_tessellation(Ferrite.RefPyramid)

For 2D shapes, construct the FerriteViz.ReferenceTessellation directly (coordinates in reference space, triangles and wireframe edge segments indexing into them; shared coordinates are fine — per-cell duplication is FEData's job). Edges may be omitted, in which case meshplot draws no wireframe for cells of that shape.

Data layout

Point-data arrays are Matrix{Float64} (nvertices × ncomponents) with tensor components in Tensors.jl linear (column-major) order; scalars have one column. Cell-data arrays are per-cell Vectors of arbitrary element type.

Reference

FerriteViz.ReferenceTessellationType
ReferenceTessellation{refdim,T}

Surface triangulation of a reference shape: coords are vertices in reference space, triangles index into coords. Coordinates may be shared between triangles; the per-cell vertex duplication that makes discontinuous (L2) fields render correctly is applied by FEData, not here.

edges are the wireframe segments drawn by meshplot: polylines along the finite element cell's edges (from Ferrite.reference_edges), also indexing into coords. They are deliberately separate from the triangles — the triangulation contains interior diagonals (e.g. the quadrilateral's center fan) that are not cell edges and must not show up in the wireframe. A tessellation without edges renders no wireframe.

source
FerriteViz.reference_tessellationFunction
reference_tessellation(::Type{<:Ferrite.AbstractRefShape}) -> ReferenceTessellation

The extension point for custom cell types: return the surface triangulation of the reference shape. Implementing this one method makes FEData and all representations work for cells with that reference shape. For 3D shapes, facet_based_tessellation builds a valid tessellation from Ferrite.reference_faces.

source
FerriteViz.facet_based_tessellationFunction
facet_based_tessellation(::Type{<:Ferrite.AbstractRefShape{3}}) -> ReferenceTessellation

Build the surface tessellation of a 3D reference shape from its faces: each face's 2D tessellation (triangle or quadrilateral, chosen by vertex count) is mapped into the element via Ferrite.facet_to_element_transformation. The wireframe edges come from Ferrite.reference_edges, with their own (duplicated) endpoint vertices appended after the face vertices. This is the default building block for reference_tessellation of volumetric shapes.

source
FerriteViz.subdivideFunction
subdivide(tess::ReferenceTessellation, n::Int) -> ReferenceTessellation

Subdivide a tessellation in reference space, n times: every triangle into 4 (orientation preserving) and every edge segment into 2. Midpoints are deduplicated by coordinate, so subdivided triangles share vertices with their neighbours and with edge segments running along the same reference line. New vertices are appended, so indices into the input tessellation stay valid.

This is what resolves curved geometry: the subdivided reference vertices are mapped through the cell's geometric interpolation when the tessellation is instantiated by FEData, so surfaces and wireframe edges of high-order (or nonlinearly deformed) cells bend instead of being drawn as flat facets and straight chords.

source
FerriteViz.QPTessellationType
QPTessellation{refdim}

Voronoi partition of a reference shape induced by a quadrature rule. coords are vertices in reference space, triangles index into them, and vertex_qp[v] is the quadrature point whose region vertex v belongs to.

Vertices are not shared between regions: every region carries its own copy, so assigning each vertex its quadrature point's value renders the region flat.

source
FerriteViz.qp_voronoi_tessellationFunction
qp_voronoi_tessellation(::Type{<:Ferrite.AbstractRefShape}, qr::Ferrite.QuadratureRule) -> QPTessellation

Partition a reference shape into the Voronoi regions of qr's quadrature points and triangulate them. For 3D shapes the partition is intersected with the boundary faces, which is what the surface renderer draws.

source
FerriteViz.num_verticesFunction

Total number of tessellation vertices, i.e. vertices of the rendered triangulation. These are not the vertices of the finite element cells: cells do not share them (they are duplicated per cell, so discontinuities render), and a tessellated cell generally carries more of them than it has corners.

source
FerriteViz.transfer_solutionFunction
transfer_solution(ds::FEData, u::Vector; field_name=:u) -> Matrix{Float64}

Evaluate the field at every tessellation vertex of every visible cell from the owning element's dofs (preserving inter-element discontinuities). Vertices of invisible cells or cells outside the field's subdomain stay NaN.

source
FerriteViz.interpolate_gradient_fieldFunction
interpolate_gradient_field(dh::DofHandler, u::AbstractVector, field_name::Symbol; copy_fields::Vector{Symbol})

Compute the piecewise discontinuous gradient field for field_name. Returns the flux dof handler and the corresponding flux dof values. If the additional keyword argument copy_fields is provided with a non empty Vector{Symbol}, the corresponding fields of dh will be copied into the returned flux dof handler and flux dof value vector.

source
FerriteViz._tensorsjl_gradient_accessorFunction
_tensorsjl_gradient_accessor(v::Tensors.Vec, field_dim_idx::Int, spatial_dim_idx::Int)

This is a helper to access the correct value in Tensors.jl entities, because the gradient index is the outermost one.

source