Basis Functions

Basis functions define the interpolation between particles and grid nodes. Tesserae stores this local particle-grid relation as basis weights, which contain the basis values and gradients used by transfer macros such as @P2G and @G2P.

Because particles move through the mesh, basis weights are updated before transfers that use the current particle positions. The basis type determines the support nodes of each particle, affecting both the transfer behavior and computational cost.

Tesserae.update!Method
update!(weights, particles, mesh)

Updates each element in weights using particle data and the background mesh. Automatically dispatches to CPU or GPU backend with appropriate parallelization.

This is functionally equivalent to:

for p in eachindex(particles)
    update!(weights[p], LazyRow(particles, p), mesh)
end

where LazyRow is provided in StructArrays.jl.

source

Basis types

Tesserae.BSplineType
BSpline(degree)

B-spline kernel. degree is one of Linear(), Quadratic() or Cubic().

Warning

BSpline(Quadratic()) and BSpline(Cubic()) cannot handle boundaries correctly because the kernel values are merely truncated, which leads to unstable behavior. Therefore, it is recommended to use either SteffenBSpline or KernelCorrection in cases where proper handling of boundaries is necessary.

source
Tesserae.uGIMPType
uGIMP()

A kernel for the unchanged generalized interpolation material point (uGIMP) [GIMP]. uGIMP requires the initial particle length l in the particle property as follows:

ParticleProp = @NamedTuple begin
    < variables... >
    l :: Float64
end
source
Tesserae.CPDIType
CPDI()

A kernel for convected particle domain interpolation (CPDI) [CPDI]. CPDI requires the initial particle length l and the deformation gradient F in the particle property. For example, in two dimensions, the property is likely to be as follows:

ParticleProp = @NamedTuple begin
    < variables... >
    l :: Float64
    F :: Mat{2, 2, Float64, 4}
end
source
Tesserae.WLSType
WLS(kernel)

WLS performs a local weighted least squares fit for the kernel. This results in the same kernel used in moving least squares MPM[MLSMPM]. kernel is one of BSpline and uGIMP.

source
Tesserae.KernelCorrectionType
KernelCorrection(kernel)

KernelCorrection[KC] modifies kernel to achieve stable simulations near boundaries. The corrected kernel satisfies not only the partition of unity, $\sum_i w_{ip} = 1$, but also the linear field reproduction, $\sum_i w_{ip} \bm{x}_i = \bm{x}_p$, near boundaries. In the implementation, this simply applies WLS near boundaries. kernel is one of BSpline and uGIMP. See also SteffenBSpline.

source

Basis weight

Tesserae.BasisWeightType
BasisWeight([T,] basis, mesh)

BasisWeight stores basis function values and their spatial derivatives.

julia> mesh = CartesianMesh(1.0, (0,5), (0,5));

julia> xₚ = Vec(2.2, 3.4); # particle position

julia> bw = BasisWeight(BSpline(Quadratic()), mesh);

julia> update!(bw, xₚ, mesh) # update `bw` at position `xₚ` in `mesh`
BasisWeight:
  Basis: BSpline(Quadratic())
  Basis values: w::Matrix{Float64}, ∇w::Matrix{Vec{2, Float64}}
  Support nodes: CartesianIndices((2:4, 3:5))

julia> sum(bw.w) ≈ 1 # partition of unity
true

julia> nodeindices = supportnodes(bw) # grid indices within a particles' local domain
CartesianIndices((2:4, 3:5))

julia> sum(eachindex(nodeindices)) do ip # linear field reproduction
           i = nodeindices[ip]
           bw.w[ip] * mesh[i]
       end ≈ xₚ
true
source
Tesserae.generate_basis_weightsFunction
generate_basis_weights([T,] ::Basis, mesh, dims...)
generate_basis_weights([T,] ::FEMesh, dims...)

Generate an array of BasisWeights for basis on mesh. For FEMesh, the mesh cell shape is used as the basis.

source
Tesserae.basisFunction
basis(mesh::FEMesh)
basis(mesh::IGAMesh)
basis(weight)

Return the basis associated with a mesh or basis-weight storage.

source
Tesserae.supportnodesFunction
supportnodes(x::Vec, r::Real, mesh::CartesianMesh)

Return CartesianIndices for support nodes around x. r denotes the range for searching area. In 1D, for example, the range a becomes x-r*h ≤ a < x+r*h where h is spacing(mesh).

Examples

julia> mesh = CartesianMesh(1, (0,5))
6-element CartesianMesh{1, Float64, Vector{Float64}, 2}:
 [0.0]
 [1.0]
 [2.0]
 [3.0]
 [4.0]
 [5.0]

julia> supportnodes(Vec(1.5), 1, mesh)
CartesianIndices((2:3,))

julia> supportnodes(Vec(1.5), 3, mesh)
CartesianIndices((1:5,))
source
supportnodes(mesh::FEMesh)
supportnodes(mesh::FEMesh, cell::Int)

Return the sorted node indices used by mesh, or the local support node indices of cell.

source
supportnodes(mesh::IGAMesh)
supportnodes(mesh::IGAMesh, cell::IGACell)

Return the sorted control-point indices used by mesh, or the local support control-point indices of cell.

source
supportnodes(weight[, domain])

Return the nodes in the support of a BasisWeight. When domain is a Grid, SpGrid, or mesh, the returned nodes are checked against that domain.

source