API reference

Documentation for Bramble.jl's public API.


Utilities

Linear algebra backends

Bramble.backendFunction
backend(Wₕ::AbstractSpaceType) -> AbstractBackend

Returns the computational backend associated with the space Wₕ.

source
Bramble.ExecutionPolicyType
ExecutionPolicy

Abstract supertype for backend execution policies.

Directs grid operations and form assembly to execute either sequentially via Serial or across threads via Parallel.

source
Bramble.SerialType
Serial() <: ExecutionPolicy

Sequential execution policy.

Directs grid operations and form assembly to execute via single-threaded loops. This is the default execution policy.

See also: Parallel, ExecutionPolicy.

source
Bramble.ParallelType
Parallel() <: ExecutionPolicy

Multithreaded execution policy.

Directs grid operations and form assembly to execute across CPU threads via static partitioning. Execution is unconditional: no per-call size thresholds are imposed. For workloads dominated by small, frequently repeated calls, use Serial.

See also: Serial, ExecutionPolicy.

source
Bramble.vectorFunction
vector(backend::Backend{VT}, n::Integer) -> VT

Allocate an uninitialized vector of length n using vector type VT configured in backend.

Arguments

  • backend: Target backend instance.
  • n: Number of vector elements.

Throws

  • ErrorException: If neither VT(undef, n) nor VT(n) succeeds.
source
Bramble.matrixFunction
matrix(backend::Backend{<:Any, MT}, n::Integer, m::Integer) -> MT

Allocate a matrix of dimensions n × m using matrix type MT configured in backend.

For dense matrix types, allocates uninitialized storage via MT(undef, n, m). For sparse matrix types (SparseMatrixCSC), allocates an empty sparse matrix via spzeros(T, Ti, n, m).

Arguments

  • backend: Target backend instance.
  • n: Number of rows.
  • m: Number of columns.

Throws

  • ErrorException: If MT cannot be constructed with dimensions (n, m).
source
Bramble.vector_typeFunction
vector_type(backend::Backend{VT}) -> Type{VT}
vector_type(::Type{<:Backend{VT}}) -> Type{VT}

Return the vector type VT configured for backend.

source
Bramble.matrix_typeFunction
matrix_type(backend::Backend{<:Any, MT}) -> Type{MT}
matrix_type(::Type{<:Backend{<:Any, MT}}) -> Type{MT}

Return the matrix type MT configured for backend.

source
Bramble.backend_typesFunction
backend_types(backend::Backend{VT, MT, EP}) -> Tuple{Type, Type{VT}, Type{MT}, Type{Backend{VT, MT, EP}}}
backend_types(::Type{<:Backend{VT, MT, EP}}) -> Tuple{Type, Type{VT}, Type{MT}, Type{Backend{VT, MT, EP}}}

Return a 4-tuple containing (eltype(VT), VT, MT, Backend{VT, MT, EP}).

source
Bramble.backend_eyeFunction
backend_eye(backend::Backend, n::Integer) -> AbstractMatrix

Construct an $n \times n$ identity matrix matching the matrix type configured in backend.

source
Bramble.backend_zerosFunction
backend_zeros(backend::Backend, n::Integer) -> AbstractMatrix

Construct an $n \times n$ zero matrix matching the matrix type configured in backend.

source
Bramble.metal_backendFunction
metal_backend(::Type{T} = Float32; policy::ExecutionPolicy = Serial()) -> Backend

Construct a Metal GPU Backend backed by Metal.jl arrays.

Requires using Metal in the caller environment. Apple Silicon GPUs support Float32 and Float16, but do not support 64-bit floating point arithmetic.

Arguments

  • T: Floating-point element type (Float32 or Float16, default: Float32).

Keywords

  • policy: Execution policy instance (Serial or Parallel, default: Serial()).

Throws

  • ErrorException: If Metal.jl is not loaded.
source

Geometry

Sets and intervals

Bramble.intervalFunction
interval(x::Number, y::Number) -> CartesianProduct{1, T}
interval(X::CartesianProduct{1}) -> CartesianProduct{1, T}

Construct a 1D CartesianProduct representing the closed interval $[x, y]$.

Inputs are converted to floating-point representation with promoted element type T.

Arguments

  • x: Lower endpoint.
  • y: Upper endpoint.

Throws

  • ArgumentError: If x > y.

Examples

using Bramble
I = interval(0.0, 1.0)
first(I) == 0.0 && last(I) == 1.0

# output
true
source
Bramble.pointFunction
point(Ωₕ::AbstractMeshType, idx)

Return the coordinate point at index idx (linear integer, tuple (i, j), or CartesianIndex):

  • For 1D meshes: scalar coordinate $x_i$.
  • For nD meshes: coordinate tuple $(x_{i_1}, \dots, x_{i_D})$.

Direct indexing Ωₕ[idx] delegates to point(Ωₕ, idx).

source
Bramble.boxFunction
box(a::Number, b::Number) -> CartesianProduct{1, T}
box(a::NTuple{D}, b::NTuple{D}) -> CartesianProduct{D, T}

Construct a CartesianProduct from two opposing corner points a and b.

Interval bounds for each dimension i are defined by $[\min(a_i, b_i), \max(a_i, b_i)]$.

source
LinearAlgebra.:×Function
×(X::CartesianProduct{D1}, Y::CartesianProduct{D2}) -> CartesianProduct{D1 + D2}

Compute the Cartesian tensor product of sets X and Y.

The resulting set has embedding dimension D1 + D2 with promoted scalar coordinate type.

source
×(W₁::AbstractSpaceType, W₂::AbstractSpaceType) -> CompositeGridSpace

Construct the Cartesian product space of W₁ and W₂.

Chaining products associatively flattens them into a flat CompositeGridSpace{N}, matching mathematical product space conventions (e.g. W₁ × W₂ × W₃ -> CompositeGridSpace{3}). To explicitly construct hierarchical (nested) composite spaces, call CompositeGridSpace directly (e.g. CompositeGridSpace(Vh, Qh)).

source
Bramble.dimFunction
dim(Wₕ::AbstractSpaceType) -> Int
dim(::Type{<:AbstractSpaceType}) -> Int

Returns the spatial dimension of the mesh associated with the function space Wₕ.

source
Bramble.topo_dimFunction
topo_dim(X::CartesianProduct{D}) -> Int

Return the topological dimension of X, defined as the embedding dimension D minus the number of collapsed dimensions.

source
topo_dim(Ω::Domain) -> Int

Return the topological dimension of Domain Ω.

source
topo_dim(Ωₕ::AbstractMeshType{D}) -> Int

Return the topological dimension of Ωₕ.

The topological dimension counts the number of coordinate axes with more than one point, identifying degenerate or collapsed dimensions (such as manifolds or boundaries embedded in higher-dimensional ambient space).

source
Base.extremaMethod
extrema(X::CartesianProduct, i::Integer) -> Tuple{T, T}
extrema(X::CartesianProduct{1}) -> Tuple{T, T}
extrema(X::CartesianProduct{D}) -> NTuple{D, Tuple{T, T}}

Return component interval endpoint pairs (min, max) for index i or all dimensions.

source
Bramble.projectionFunction
projection(X::CartesianProduct, i::Integer) -> CartesianProduct{1}

Extract the i-th coordinate dimension of X as a 1D CartesianProduct.

source
projection(Ω::Domain, i::Integer) -> CartesianProduct{1}

Extract the i-th coordinate dimension of domain Ω as a 1D CartesianProduct.

source
Bramble.is_collapsedFunction
is_collapsed(a::Number, b::Number) -> Bool
is_collapsed(X::CartesianProduct) -> Bool
is_collapsed(X::CartesianProduct, i::Integer) -> Bool

Check whether an interval endpoint pair, a Cartesian set, or a coordinate dimension i is degenerate (min ≈ max).

For an $n$-dimensional CartesianProduct X, is_collapsed(X) returns true if any coordinate dimension is collapsed (any(X.collapsed)), equivalently when the topological dimension is strictly less than the spatial embedding dimension D. is_collapsed(X, i) queries whether the i-th coordinate axis is degenerate.

Arguments

  • a, b: Scalar interval endpoints.
  • X: Cartesian product set.
  • i: Coordinate dimension index (1 <= i <= D).

Throws

  • BoundsError: If i < 1 or i > D.
source
is_collapsed(Ω::Domain) -> Bool
is_collapsed(Ω::Domain, i::Integer) -> Bool

Return whether the underlying geometric set of domain Ω is collapsed across any dimension, or along coordinate dimension i.

source
is_collapsed(Ωₕ::AbstractMeshType) -> Bool

Whether Ωₕ has no interval to refine or measure a spacing over — a Mesh1D built over a single point. A MeshnD is never collapsed as a whole: each axis is its own Mesh1D and may be collapsed individually, which is handled per axis rather than at this level, so the default here is false.

source
Bramble.point_typeFunction
point_type(X::CartesianProduct{1, T}) -> Type{T}
point_type(X::CartesianProduct{D, T}) -> Type{NTuple{D, T}}
point_type(::Type{<:CartesianProduct{1, T}}) -> Type{T}
point_type(::Type{<:CartesianProduct{D, T}}) -> Type{NTuple{D, T}}

Return the coordinate point representation type for a point in X.

source
point_type(Ω::Domain) -> Type
point_type(::Type{<:Domain{SetType}}) -> Type

Return the coordinate point representation type of Domain Ω.

source
Bramble.boundary_symbolsFunction
boundary_symbols(Ω::Domain) -> Tuple{Vararg{Symbol}}
boundary_symbols(X::CartesianProduct) -> Tuple{Vararg{Symbol}}
boundary_symbols(D::Integer) -> Tuple{Vararg{Symbol}}

Return the canonical coordinate-aligned boundary symbols for dimension D or domain Ω:

  • 1D $[x_1, x_2]$: (:xmin, :xmax)
  • 2D $[x_1, x_2] \times [y_1, y_2]$: (:xmin, :xmax, :ymin, :ymax)
  • 3D $[x_1, x_2] \times [y_1, y_2] \times [z_1, z_2]$: (:xmin, :xmax, :ymin, :ymax, :zmin, :zmax)

Legacy viewpoint symbols (:left, :right, :bottom, :top, :front, :back) remain supported as backward-compatible aliases across the boundary marker interface.

Throws

  • ErrorException: If dimension D > 3.
source
Bramble.setFunction
set(X::CartesianProduct) -> CartesianProduct

Identity accessor returning the geometric set X.

source
set(Ω::Domain) -> CartesianProduct

Return the geometric set defining Domain Ω.

source
set(Ωₕ::AbstractMeshType) -> AbstractSetType

Return the underlying geometric set of the domain over which mesh Ωₕ is defined.

source

Markers and domains

Bramble.markersFunction
markers(space_set::CartesianProduct, pairs::Pair...) -> DomainMarkers
markers(space_set::CartesianProduct, time_set::CartesianProduct{1}, pairs::Pair...) -> DomainMarkers

Construct a DomainMarkers collection from label => identifier pairs.

Arguments

  • space_set: Geometric spatial set.
  • time_set: Optional 1D temporal interval for time-dependent boundary conditions.
  • pairs: Vararg sequence of label => identifier pairs where identifier is a Symbol, NTuple{N, Symbol}, or predicate Function.

Examples

using Bramble
I = interval(0.0, 1.0)
m = markers(I, :left_boundary => :left, :internal => x -> 0.2 < x < 0.8)
length(symbols(m)) == 1 && length(conditions(m)) == 1

# output
true
source
markers(Ω::Domain) -> DomainMarkers

Return the DomainMarkers collection associated with domain Ω.

source
markers(Ωₕ::AbstractMeshType) -> MeshMarkers

Return the MeshMarkers dictionary associated with mesh Ωₕ.

source
Bramble.domainFunction
domain(X::CartesianProduct) -> Domain
domain(X::CartesianProduct, markers::DomainMarkers) -> Domain
domain(X::CartesianProduct, pairs::Pair...) -> Domain
domain(space_set::CartesianProduct, time_set::CartesianProduct{1}, pairs::Pair...) -> Domain

Construct a computational Domain from a CartesianProduct set and optional markers.

When no markers are supplied, defaults to a :boundary marker covering all boundaries of X.

Arguments

  • X: Underlying geometric set.
  • markers: Explicit DomainMarkers container.
  • pairs: Variable sequence of label => identifier pairs.
  • space_set: Spatial bounding set.
  • time_set: 1D temporal interval for time-dependent boundary conditions.

Examples

using Bramble
Ω = domain(interval(0.0, 1.0))
dim(Ω) == 1 && eltype(Ω) === Float64

# output
true
source

Meshes

Mesh types and constructors

Bramble.AbstractMeshTypeType
AbstractMeshType{D}

Abstract supertype for all mesh types in Bramble. The type parameter D represents the spatial dimension of the mesh (1, 2, or 3).

All concrete mesh types must implement the AbstractMeshType interface, including:

  • eltype, dim, topo_dim, indices, backend, markers
  • points, point, half_points, half_point
  • spacing, half_spacing, forward_spacing

Type parameters

  • D: Spatial dimension (1, 2, or 3)

Related types

  • Meshes are created from a Domain using the mesh function.
  • See MeshMarkers for marker management on meshes.

See also: Mesh1D, MeshnD, Domain

source
Bramble.Mesh1DType
Mesh1D{BT, CI, VT, T} <: AbstractMeshType{1}

One-dimensional grid discretizing a 1D CartesianProduct interval.

Stores grid point coordinates pts, underlying geometric interval set, semantic markers markers, Cartesian indices indices, and computational backend backend. Also precomputes and caches cell centers (half_pts), cell measures (half_spacings), and backward spacings (spacings).

Fields

  • set: 1D geometric CartesianProduct interval over which the mesh is defined.
  • markers: MeshMarkers dictionary mapping symbols to BitVector indicators.
  • indices: CartesianIndices{1} of the grid points.
  • backend: Linear algebra Backend for memory management and operations.
  • pts: Coordinate vector storing grid points $x_i$ for $i = 1, \dots, N$.
  • half_pts: Precomputed cell centers (midpoints) $x_{i+1/2}$ for $i = 1, \dots, N+1$.
  • half_spacings: Precomputed cell widths (control volume measures) $h_{i+1/2}$ for $i = 1, \dots, N$.
  • spacings: Precomputed backward grid spacings $h_i = x_i - x_{i-1}$, with $h_1 = x_2 - x_1$.
  • collapsed: Boolean flag indicating whether the interval is degenerate (a single point).

See also: MeshnD, mesh, AbstractMeshType.

source
Bramble.MeshnDType
MeshnD{D, BT, CI, SM, T} <: AbstractMeshType{D}

Structured multi-dimensional tensor-product mesh for spatial dimensions $D \in \{2, 3\}$.

Constructed as a Cartesian product of 1D submeshes (Mesh1D). Coordinate points are evaluated on demand from the tensor-product submeshes.

Type parameters

  • D: Spatial dimension (2 or 3).
  • BT <: Backend: Computational linear algebra backend.
  • CI <: CartesianIndices{D}: Cartesian index space.
  • SM <: Tuple: Tuple of 1D submeshes (Mesh1D).
  • T: Coordinate element type (Float64, Float32, etc.).

Fields

  • set: Multi-dimensional geometric CartesianProduct domain.
  • markers: MeshMarkers dictionary mapping symbols to BitVector indicators.
  • indices: Multi-dimensional CartesianIndices{D} for the grid.
  • backend: Linear algebra Backend.
  • submeshes: Tuple of D Mesh1D objects along each coordinate axis.

Examples

# Create a 2D mesh with 20×30 grid points
X = domain(interval(0, 1) × interval(0, 2))
Ωₕ = mesh(X, (20, 30), (true, false))

# Access submeshes
x_mesh = Ωₕ(1)  # 1D mesh along x-axis
y_mesh = Ωₕ(2)  # 1D mesh along y-axis

# Query a specific point coordinate
point(Ωₕ, (10, 15))  # returns (x₁₀, y₁₅)

See also: Mesh1D, submeshes, mesh.

source
Bramble.MeshMarkersType
const MeshMarkers = Dict{Symbol, BitVector}

Dictionary mapping semantic marker symbols to boolean indicator vectors across mesh points.

For each label, a BitVector indicates whether the corresponding mesh point satisfies the marker.

source
Bramble.meshFunction
mesh(Wₕ::AbstractSpaceType) -> AbstractMeshType

Returns the underlying mesh object associated with the function space Wₕ.

source
Bramble.submeshesFunction
submeshes(Ω::Domain, npts, unif, backend) -> NTuple{D, Mesh1D}

Create the component 1D submeshes for a tensor-product grid.

Generates a tuple of D independent Mesh1D objects corresponding to each coordinate axis of Ω.

Arguments

  • Ω: Multi-dimensional continuous Domain.
  • npts: Number of points along each dimension.
  • unif: Flags indicating whether each axis is uniformly partitioned.
  • backend: Computational linear algebra Backend.
source

Points and spacings

Bramble.npointsFunction
npoints(Ωₕ::AbstractMeshType) -> Int
npoints(Ωₕ::AbstractMeshType, ::Type{Tuple}) -> NTuple{D, Int}

Return the total number of points in Ωₕ. When passing Tuple as the second argument, returns a tuple with the number of points along each dimension.

source
Bramble.pointsFunction
points(Ωₕ::AbstractMeshType) -> Union{Vector, NTuple}

Return the coordinates of the mesh points:

  • For 1D meshes (Mesh1D): returns a coordinate vector Vector{T} of length $N_x$.
  • For nD meshes (MeshnD): returns an NTuple{D, Vector{T}} containing the 1D coordinate vectors along each axis.

See also: point.

source
Bramble.half_pointsFunction
half_points(Ωₕ::AbstractMeshType)

Return the precomputed cell centers (half-points) for each coordinate axis:

\[x_{i+1/2} = \frac{x_i + x_{i+1}}{2}, \quad i = 1, \dots, N-1.\]

source
Bramble.half_pointFunction
half_point(Ωₕ::AbstractMeshType, idx)

Return the cell center (half-point) coordinate corresponding to index idx.

source
Bramble.spacingFunction
spacing(Ωₕ::AbstractMeshType, idx)
spacing(Ωₕ::AbstractMeshType, idx, dim::Int)

Return the backward spacing $h_i = x_i - x_{i-1}$ at index idx (for $i=1$, returns $x_2 - x_1$). For nD meshes, returns a tuple of backward spacings along each axis; passing dim queries only that axis directly, without building and discarding the other D - 1 components.

source
Bramble.forward_spacingFunction
forward_spacing(Ωₕ::AbstractMeshType, idx)
forward_spacing(Ωₕ::AbstractMeshType, idx, dim::Int)

Return the forward spacing $h_{i+1} = x_{i+1} - x_i$ at index idx (for $i=N$, returns $x_N - x_{N-1}$). For nD meshes, returns a tuple of forward spacings along each axis; passing dim queries only that axis directly, without building and discarding the other D - 1 components.

source
Bramble.half_spacingFunction
half_spacing(Ωₕ::AbstractMeshType, idx)

Return the cell width (half-spacing) at index idx.

source
Bramble.spacingsFunction
spacings(Ωₕ::Mesh1D) -> AbstractVector

Return the cached vector of backward spacings, where spacings(Ωₕ)[i] is spacing(Ωₕ, i). Recomputed by set_points! whenever the grid points change.

source
spacings(Ωₕ::MeshnD{D}) -> NTuple{D, AbstractVector}

Return the per-axis backward spacings as an NTuple{D} of vectors, where spacings(Ωₕ)[d][i] is spacing(Ωₕ(d), i).

See also: half_spacings, cell_measures.

source
Bramble.half_spacingsFunction
half_spacings(Ωₕ::AbstractMeshType)

Return the cell widths (half-spacings) along each axis:

\[h_{i+1/2} = \frac{h_i + h_{i+1}}{2}.\]

source
Bramble.hₘₐₓFunction
hₘₐₓ(Ωₕ::AbstractMeshType) -> Real

Return the maximum diagonal stepsize across all cells in the mesh:

\[h_{\max} = \max_{\mathbf{i}} \| (h_{1, i_1}, \dots, h_{D, i_D}) \|_2.\]

source
Bramble.hₘᵢₙFunction
hₘᵢₙ(Ωₕ::AbstractMeshType) -> Real

Return the diagonal of the smallest cell in the mesh, the counterpart of hₘₐₓ:

  • In 1D: $\min_i (x_i - x_{i-1})$.
  • In nD:

\[h_{\min} = \min_{\mathbf{i}} \| (h_{1, i_1}, \dots, h_{D, i_D}) \|_2.\]

This is a diagonal rather than an edge length, so that hₘₐₓ and hₘᵢₙ measure the same kind of quantity. For the smallest extent along one coordinate, query that submesh directly: hₘᵢₙ(Ωₕ(i)).

source
Bramble.stepsizeFunction
stepsize(Ωₕ::AbstractMeshType) -> Union{Real, NTuple{D, Real}}
stepsize(Ωₕ::AbstractMeshType, d::Integer) -> Real

Return the constant stepsize for a uniform mesh:

  • In 1D: returns scalar $h = x_2 - x_1$.
  • In nD: returns a tuple $(h_1, \dots, h_D)$ of stepsizes along each coordinate axis.
  • When d is specified: returns the stepsize along dimension d.

Throws an ArgumentError if the mesh is not uniform.

See also: is_uniform, spacing.

source
Bramble.locate_cellFunction
locate_cell(Ωₕ::AbstractMeshType{1}, x::Real) -> Int
locate_cell(Ωₕ::AbstractMeshType{D}, x) -> CartesianIndex{D}

Locate the cell containing continuous coordinate x:

  • For 1D meshes: returns integer index i \in 1:N-1 such that $x_i \le x \le x_{i+1}$ (clamped to the domain boundaries).
  • For nD meshes: returns a CartesianIndex{D} locating the bounding cell along each dimension.

Examples

Ωₕ = mesh(domain(interval(0.0, 1.0)), 11)  # h = 0.1
locate_cell(Ωₕ, 0.35)  # returns 4 (interval [0.3, 0.4])
source
Bramble.normal_vectorFunction
normal_vector(Ωₕ::AbstractMeshType{D}, symbol::Symbol) -> NTuple{D, Float64}
normal_vector(::Val{D}, symbol::Symbol) -> NTuple{D, Float64}

Return the outward unit normal vector (as an NTuple{D, Float64}) associated with a standard boundary facet label (:xmin, :xmax, :ymin, :ymax, :zmin, :zmax) or legacy viewpoint alias (:left, :right, :bottom, :top, :front, :back).

Conventions

  • 1D:
    • :xmin, :left $\to (-1.0)$
    • :xmax, :right $\to (+1.0)$
  • 2D:
    • :xmin, :left $\to (-1.0, 0.0)$
    • :xmax, :right $\to (+1.0, 0.0)$
    • :ymin, :bottom $\to (0.0, -1.0)$
    • :ymax, :top $\to (0.0, +1.0)$
  • 3D:
    • :xmin, :back $\to (-1.0, 0.0, 0.0)$
    • :xmax, :front $\to (+1.0, 0.0, 0.0)$
    • :ymin, :left $\to (0.0, -1.0, 0.0)$
    • :ymax, :right $\to (0.0, +1.0, 0.0)$
    • :zmin, :bottom $\to (0.0, 0.0, -1.0)$
    • :zmax, :top $\to (0.0, 0.0, +1.0)$

See also: boundary_symbols.

source
Bramble.cell_measureFunction
cell_measure(Ωₕ::AbstractMeshType, idx) -> Real

Return the control volume (length, area, or volume) of the cell centered at index idx:

\[\operatorname{meas}(\square_{\mathbf{i}}) = \prod_{d=1}^D h_{d, i_d+1/2}.\]

source
Bramble.cell_measuresFunction
cell_measures(Ωₕ::MeshnD{D}) -> NTuple{D, AbstractVector}

Return the per-axis cell widths as an NTuple{D} of vectors. The measure of an individual cell is the product of its per-axis widths; see cell_measure.

source
Bramble.is_uniformFunction
is_uniform(Ωₕ::AbstractMeshType; tol = 1e-10) -> Bool

Check whether the mesh has uniform spacing (within numerical tolerance tol).

source

Mesh indexing and boundaries

Bramble.indicesFunction
indices(Ωₕ::AbstractMeshType) -> CartesianIndices

Return the CartesianIndices associated with the points of mesh Ωₕ.

source
Bramble.boundary_indicesFunction
boundary_indices(idxs::CartesianIndices{D}) -> NTuple{2D, CartesianIndices{D}}
boundary_indices(Ωₕ::AbstractMeshType{D}) -> NTuple{2D, CartesianIndices{D}}

Return all boundary facets of a CartesianIndices domain or mesh Ωₕ as a tuple of CartesianIndices.

source
Bramble.interior_indicesFunction
interior_indices(indices::CartesianIndices{D}) -> CartesianIndices{D}
interior_indices(Ωₕ::AbstractMeshType{D}) -> CartesianIndices{D}

Compute the CartesianIndices representing the interior of a domain or mesh, excluding all boundary points. Dimensions with a length of one or less remain unchanged.

source
Bramble.is_boundary_indexFunction
is_boundary_index(idxs::CartesianIndices{D}, idx) -> Bool
is_boundary_index(Ωₕ::AbstractMeshType, idx) -> Bool

Determine whether index idx lies on the boundary of idxs or mesh Ωₕ.

source
Bramble.index_in_markerFunction
index_in_marker(Ωₕ::AbstractMeshType, label::Symbol) -> BitVector

Return the BitVector indicator associated with marker label in mesh Ωₕ.

If label is not directly found in the mesh markers, its coordinate-aligned or viewpoint boundary alias (e.g. :xmin:left in 2D, :xmin:back in 3D) is consulted if available.

source

Mesh adaptation and mutation

Bramble.iterative_refinement!Function
iterative_refinement!(Ωₕ::AbstractMeshType, [domain_markers::DomainMarkers]) -> AbstractMeshType

Refine the mesh Ωₕ in-place by halving each existing cell (inserting new points at midpoints). If domain markers are supplied, they are re-evaluated onto the refined grid points.

Without domain_markers, any custom marker Ωₕ carries beyond :boundary/:interior has no domain here to re-derive it from, so this throws an ArgumentError rather than silently dropping it. Pass domain_markers (the same ones the mesh was built with, or equivalent) to keep them.

source
Bramble.change_points!Function
change_points!(Ωₕ::AbstractMeshType, [domain_markers::DomainMarkers], pts) -> AbstractMeshType

Update the coordinates of mesh Ωₕ in-place using new point coordinates in pts, recalculating all cached half-points and cell spacings.

source

Grid spaces

Function spaces

Bramble.ScalarGridSpaceType
ScalarGridSpace(mesh::MType, weights::SpaceWeights{D, VT})
ScalarGridSpace{D, T, VT, MType}(mesh::MType, weights::SpaceWeights{D, VT})

Represents a function space for scalar fields defined on a mesh.

A ScalarGridSpace pairs the mesh with the precomputed weight vectors (SpaceWeights) its discrete inner products need.

Fields

  • mesh::MType: the underlying mesh of the grid space.
  • weights::SpaceWeights{D, VT}: precomputed inner product weight vectors.

Discrete inner products

The weights object stores vectors for different discrete $L^2$ inner products on the space of grid functions. They are defined as follows:

- :innerₕ: The standard discrete $L^2$ inner product, weighted by the cell measure $|\square_k|$.

  • 1D case:

\[(u_h, v_h)_h = \sum_{i=1}^{N_x} |\square_{i}| u_h(x_i) v_h(x_i)\]

  • 2D case:

\[(u_h, v_h)_h = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y} |\square_{i,j}| u_h(x_i,y_j) v_h(x_i,y_j)\]

  • 3D case:

\[(u_h, v_h)_h = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y}\sum_{l=1}^{N_z} |\square_{i,j,l}| u_h(x_i,y_j,z_l) v_h(x_i,y_j,z_l)\]

Here, $|\cdot|$ denotes the measure of the set (length, area, or volume). See cell_measure for details.

- :inner₊, :inner₊ₓ, :inner₊ᵧ, :inner₊₂: Modified discrete $L^2$ inner products, weighted by a mix of forward/backward spacings ($h_k$) and cell widths ($h_{k+1/2}$).

  • 1D case (:inner₊):

\[(u_h, v_h)_+ = \sum_{i=1}^{N_x} h_{i} u_h(x_i) v_h(x_i)\]

  • 2D case (:inner₊ₓ, :inner₊ᵧ):

\[(u_h, v_h)_{+x} = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y} h_{x,i} h_{y,j+1/2} u_h(x_i,y_j) v_h(x_i,y_j)\]

\[(u_h, v_h)_{+y} = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y} h_{x,i+1/2} h_{y,j} u_h(x_i,y_j) v_h(x_i,y_j)\]

  • 3D case (:inner₊ₓ, :inner₊ᵧ, :inner₊₂):

\[(u_h, v_h)_{+x} = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y}\sum_{l=1}^{N_z} h_{x,i} h_{y,j+1/2} h_{z,l+1/2} u_h(x_i,y_j,z_l) v_h(x_i,y_j,z_l)\]

\[(u_h, v_h)_{+y} = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y}\sum_{l=1}^{N_z} h_{x,i+1/2} h_{y,j} h_{z,l+1/2} u_h(x_i,y_j,z_l) v_h(x_i,y_j,z_l)\]

\[(u_h, v_h)_{+z} = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y}\sum_{l=1}^{N_z} h_{x,i+1/2} h_{y,j+1/2} h_{z,l} u_h(x_i,y_j,z_l) v_h(x_i,y_j,z_l)\]

source
Bramble.CompositeGridSpaceType
CompositeGridSpace(spaces::Tuple)
CompositeGridSpace{N}(spaces::Spaces) where {N, Spaces <: Tuple}
CompositeGridSpace{N, Spaces}(spaces::Spaces) where {N, Spaces <: Tuple}

A CompositeGridSpace represents a grid space formed by composing N individual sub-spaces. It is immutable and stack-allocatable, wrapping a tuple of spaces.

Fields

  • spaces::Spaces: the tuple of constituent sub-spaces.
source
Bramble.gridspaceFunction
gridspace(Ωₕ::AbstractMeshType{D}) -> ScalarGridSpace{D}

Constructs a ScalarGridSpace defined on the mesh Ωₕ, precomputing the inner product weights listed in ScalarGridSpace.

Scratch memory is supplied explicitly by callers through in-place mutating operators (such as D₋ₓ!(vₕ, uₕ)), avoiding hidden internal vector buffers.

source
gridspace(Ωₕ::AbstractMeshType, ::Val{N}) where N -> CompositeGridSpace{N}
gridspace(Ωₕ::AbstractMeshType, N::Int) -> CompositeGridSpace{N}

Constructs a vector function space with N components on mesh Ωₕ. The underlying scalar space and its weights are computed once and shared across components.

N == 1 yields the ScalarGridSpace itself rather than a one-component composite, for both spellings. The element interface is uniform either way: uₕ(1) and components(uₕ) work on a scalar element.

The Val form is always type stable. The Int form is stable wherever N is a literal or otherwise constant-foldable, and returns a small Union when N is only known at run time; prefer Val on hot paths.

source
Bramble.vector_gridspaceFunction
vector_gridspace(Ωₕ::AbstractMeshType, [N = dim(Ωₕ)]) -> CompositeGridSpace

Convenience constructor for a vector grid space on mesh Ωₕ. If N is omitted, it defaults to the spatial dimension of the mesh (dim(Ωₕ)).

source

Space properties and degrees of freedom

Bramble.ndofsFunction
ndofs(Wₕ::AbstractSpaceType) -> Int
ndofs(Wₕ::AbstractSpaceType, ::Type{Tuple}) -> NTuple{N, Int}

Returns the total number of degrees of freedom (DOFs) in the function space Wₕ.

The `Tuple` form means something different for a composite space

On a ScalarGridSpace, ndofs(Wₕ, Tuple) is the grid's shape — one entry per spatial dimension (Nₓ, Nᵧ, ...). On a CompositeGridSpace, it is instead one entry per component, each that component's own (scalar) DOF count — unrelated to spatial dimension, and not a shape a prod should be taken over. Code that does not know in advance which kind of space it was given should reach for one of the two unambiguous forms instead: npoints(mesh(Wₕ), Tuple) for the grid shape, or map(ndofs, spaces(Wₕ)) for the per-component counts. Mixing them up is not hypothetical: src/space/operators/difference.jl's _grid_dims avoids ndofs(Wₕ, Tuple) for exactly this reason, after a 3-component 4×6 space addressed 13824 slots into 72 and segfaulted under an @inbounds engine.

source
Bramble.weightsFunction
weights(Wₕ::ScalarGridSpace) -> SpaceWeights
weights(Wₕ::ScalarGridSpace, ::Innerh) -> AbstractVector
weights(Wₕ::ScalarGridSpace, ::Innerplus) -> NTuple{D, AbstractVector}
weights(Wₕ::ScalarGridSpace, ::InnerProductType, i::Int) -> AbstractVector

Returns the precomputed weight vectors for discrete inner products.

The weights are diagonal matrices (stored as vectors) used in computing discrete $L^2$ inner products. They represent cell measures or staggered grid spacings.

Methods

  1. weights(Wₕ) - Returns the full SpaceWeights struct
  2. weights(Wₕ, Innerh()) - Returns weights for standard $L^2$ inner product (cell volumes)
  3. weights(Wₕ, Innerplus()) - Returns tuple of weights for modified inner products (all directions)
  4. weights(Wₕ, Innerplus(), i) - Returns weights for modified inner product in direction i
  5. weights(Wₕ, Innerh(), i) - Same as weights(Wₕ, Innerh()); the cell measures do not depend on a direction, so i is accepted and ignored for interface symmetry

Examples

Wₕ = gridspace(Ωₕ)

# Get all weights
w = weights(Wₕ)  # Returns SpaceWeights{D, VT}

# Get standard L² weights
w_h = weights(Wₕ, Innerh())  # Vector of cell volumes

# Get modified inner product weights for x-direction
w_plus_x = weights(Wₕ, Innerplus(), 1)  # Vector for x-direction

# Use in inner product
result = dot(uₕ.data, w_h, vₕ.data)  # Weighted inner product

Defined for a ScalarGridSpace only, the same rule normₕ/norm₊ follow: a composite grid space's leaves can have different meshes and therefore different weights, so there is no single vector that could correctly answer for the whole composite. A CompositeGridSpace raises a MethodError; take a scalar component of it with components first.

See also: SpaceWeights, Innerh, Innerplus, innerₕ

source
Bramble.spacesFunction
spaces(Wₕ::AbstractSpaceType) -> Tuple

Returns the constituent subspace(s) of Wₕ as a tuple.

source
Bramble.spaceFunction
space(Wₕ::AbstractSpaceType) -> AbstractSpaceType

Returns the function space Wₕ itself.

source
space(uₕ::VectorElement) -> AbstractSpaceType

Returns the grid space associated with VectorElement uₕ.

source
space(sd::Semidiscretization)

Return the test space the semidiscretisation was built on.

source
Bramble.ncomponentsFunction
ncomponents(Wₕ::AbstractSpaceType) -> Int
ncomponents(::Type{<:AbstractSpaceType}) -> Int

Returns the number of field components of the function space (e.g. 1 for scalar, D for vector).

source

Vector elements and grid functions

Bramble.VectorElementType
VectorElement(data::VT, space::S)
VectorElement{S, T, VT}(data::VT, space::S)

Represents a grid function (a vector) that belongs to a specific function space.

This is a wrapper that bundles the raw numerical data (the vector data) with its parent space. The space provides the essential context, such as the underlying mesh and associated operators. By subtyping AbstractVector, a VectorElement can be used just like a regular Julia vector in most operations.

Fields

  • data::VT: the raw vector data containing the degrees of freedom.
  • space::S: the parent function space to which this vector belongs.
source
Bramble.elementFunction
element(Wₕ::AbstractSpaceType) -> VectorElement
element(Wₕ::AbstractSpaceType, α::Number) -> VectorElement

Returns a VectorElement for grid space Wₕ with uninitialized components. If α is provided, the components are initialized to α.

source
element(Wₕ::AbstractSpaceType, ::Type{T}) -> VectorElement

Returns a VectorElement for grid space Wₕ holding coefficients of type T, with uninitialized components.

The coefficients of a grid function and the coordinates of the mesh under it are two different things, and this is where they part company. element(Wₕ) takes its type from the backend, which is the mesh's own; this takes whatever is asked for, and the container follows through similar, so a Vector backend gives a Vector{T} and a device array gives a device array of T.

The case this exists for is automatic differentiation: a ForwardDiff.Dual grid function over an ordinary Float64 mesh, so that the geometry is not differentiated along with the field. See Rₕ, which uses it to give back an element of whatever type the restricted function returns.

source
element(Wₕ::AbstractSpaceType, v::AbstractVector) -> VectorElement

Returns a VectorElement for a grid space Wₕ with the same coefficients as v.

source
Base.parentMethod
parent(uₕ::VectorElement) -> AbstractVector

Returns the coefficient vector containing the degrees of freedom of VectorElement uₕ.

source
Base.reshapeMethod
reshape(uₕ::VectorElement)

Reshapes the flat coefficient vector of uₕ into a multidimensional array that matches the logical layout of the grid points.

  • For a scalar space, this returns a D-dimensional array.
  • For an N-component vector space, it returns an N-tuple of arrays, one for each component.

This zero-argument form is specific to VectorElement and does not conflict with reshape(A, dims); it does shadow Base.reshape(A) = reshape(A, ())'s 0-dimensional result for this type specifically, in favor of the shape a grid function actually has. Replaces the former to_matrix outright (gpena/Bramble.jl#73).

source
Bramble.componentsFunction
components(uₕ::VectorElement) -> Tuple

Returns an NTuple of VectorElement views, one per leaf of uₕ's space, depth-first — the same leaf a matching-index uₕ(i) returns, regardless of nesting.

source
components(op::Union{TrialFunction, TestFunction}) -> Tuple
components(op::LazyOp, N::Integer) -> Tuple
components(op::LazyOp, space::AbstractSpaceType) -> Tuple

Returns an NTuple of components of the symbolic trial or test function, suitable for tuple destructuring: (u, v) = components(p).

source
Bramble.component_rangeFunction
component_range(Wₕ::CompositeGridSpace, i::Int) -> UnitRange{Int}

Returns the degree-of-freedom index range for the i-th leaf of composite space Wₕ, numbered depth-first (see leaf_spaces_offsets) — the same numbering uₕ(i) and dirichlet_components use, so it agrees with them regardless of how deeply Wₕ nests.

source
Bramble.component_rangesFunction
component_ranges(Wₕ::CompositeGridSpace) -> NTuple{N, UnitRange{Int}}

N is the number of scalar leaves underneath Wₕ, counting through any nesting.

Returns the degree-of-freedom ranges for every leaf of Wₕ, depth-first — see component_range.

source
Base.:*Method
f::Function * uₕ::VectorElement -> VectorElement
uₕ::VectorElement * f::Function -> VectorElement

Project the continuous function f onto uₕ's own space and scale uₕ pointwise by it (gpena/Bramble.jl#197): Rₕ(space(uₕ), f) .* uₕ.

A plain Function has no meaning as a grid function on its own – a form built from innerₕ(f, v) restricts it first through source_function/form's own lowering, but f * uₕ outside a form (or a continuous spatial condition multiplying a grid function, (x -> x[1] < 1) * uₕ) had no operator to reach that with:

julia> (x -> x[1] < 1) * uₕ
ERROR: MethodError: no method matching *(::Function, ::VectorElement)

now restricts f to space(uₕ) and multiplies elementwise, so the result is an ordinary VectorElement, usable anywhere one is – including as a SourceFunction-lowered term inside another form.

source

Restriction and averaging operators

Bramble.RₕFunction
Rₕ(Wₕ::AbstractSpaceType, f; markers = ()) -> VectorElement

Standard nodal restriction operator. Evaluates f at the grid points of mesh(Wₕ) and returns the result as a VectorElement.

Arguments

  • Wₕ::AbstractSpaceType: grid space on which to restrict f.
  • f: function of one grid point. It receives a scalar on a 1D mesh and an NTuple{D} on a D-dimensional one, never an SVector.

Keywords

  • markers::NTuple{N,Symbol}: restrict evaluation to the named marked regions, leaving every other entry zero.

Examples

Rₕ(Wₕ, x -> sin(x))                # 1D: x is a Float64
Rₕ(Wₕ, x -> sin(x[1]) * x[2])      # 2D: x is a Tuple{Float64,Float64}

# Vector-valued spaces:
Rₕ(Vₕ, (f₁, f₂))                   # one function per component
Rₕ(Vₕ, x -> (f₁(x), f₂(x)))        # one function returning all components

Prefer x -> (f₁(x), f₂(x)) when components share computation, as it evaluates once per grid point on a space whose components share one mesh, whereas (f₁, f₂) always evaluates each component function separately. On a heterogeneous composite — components built over different meshes — the single-function form gives up that advantage, since there is no grid point shared by every component to evaluate it at only once.

See also: Rₕ!, avgₕ.

source
Bramble.Rₕ!Function
Rₕ!(uₕ::VectorElement, f; markers = ()) -> VectorElement

In-place version of the restriction operator Rₕ. Evaluates f at the grid points and writes the result into uₕ. Returns uₕ.

Arguments

  • uₕ::VectorElement: pre-allocated element to write into.
  • f: function of one grid point. It receives a scalar on a 1D mesh and an NTuple{D} on a D-dimensional one, never an SVector.

Keywords

  • markers::NTuple{N,Symbol}: restrict evaluation to the named marked regions, leaving every other entry zero. Several markers act as a union.

Examples

Rₕ!(uₕ, x -> sin(x))                  # 1D: x is a Float64
Rₕ!(uₕ, x -> sin(x[1]) * cos(x[2]))   # 2D: x is a Tuple{Float64,Float64}

# only the points carrying the :left marker; the rest stay zero
Rₕ!(uₕ, x -> 1.0; markers = (:left,))

For an N-component element either shape of f works and both give the same result; the single vector-valued function is evaluated once per grid point when every component shares the same mesh, whereas the tuple always evaluates each component function separately. On a heterogeneous composite — components built over different meshes — the single-function form is instead re-evaluated once per component, since there is no grid point shared by every component to evaluate it at only once:

Rₕ!(uₕ, (f₁, f₂))                     # one function per component
Rₕ!(uₕ, x -> (f₁(x), f₂(x)))          # one function returning all components

See also: Rₕ, avgₕ!, element

source
Bramble.avgₕFunction
avgₕ(Wₕ::AbstractSpaceType, f; quad_points = AVG_QUAD_POINTS, markers = ()) -> VectorElement

Returns a VectorElement with the average of function f with respect to the cell_measure of mesh(Wₕ) around each grid point.

Each cell average is a tensor-product Gauss-Legendre rule with quad_points points per direction, exact for polynomials of degree 2 * quad_points - 1.

Arguments

  • Wₕ::AbstractSpaceType: grid space on which to average f.
  • f: function of one grid point. Receives coordinates as a scalar on 1D meshes or an NTuple{D} on D-dimensional meshes, never an SVector.

Keywords

  • quad_points::Union{Integer, Val}: points per direction, per cell. Defaults to Val(AVG_QUAD_POINTS).
  • markers::NTuple{N, Symbol}: restrict evaluation to the named marked regions, leaving every other entry zero.

Examples

avgₕ(Wₕ, x -> sin(x))
avgₕ(Wₕ, x -> sin(x[1]) * x[2]; quad_points = Val(4))

See also: avgₕ!, Rₕ.

source
Bramble.avgₕ!Function
avgₕ!(uₕ::VectorElement, f; quad_points = AVG_QUAD_POINTS, markers = ()) -> VectorElement

In-place version of the averaging operator avgₕ. Returns uₕ.

Evaluates the tensor-product Gauss-Legendre cell average of f and writes the result into uₕ.

Arguments

  • uₕ::VectorElement: pre-allocated element to write into.
  • f: function of one grid point. Receives coordinates as a scalar on 1D meshes or an NTuple{D} on D-dimensional meshes.

Keywords

  • quad_points::Union{Integer, Val}: points per direction, per cell. Defaults to Val(AVG_QUAD_POINTS). Using a Val allows compile-time specialization of the quadrature nodes and weights without boxing.
  • markers::NTuple{N, Symbol}: restrict evaluation to the named marked regions, leaving every other entry zero.

See also: avgₕ, Rₕ!.

source

Interpolation between grid spaces

Moving a grid function from one mesh to another — the piecewise (multi)linear interpolant, named after Rₕ/Rₕ!'s own Xₕ/Xₕ! convention. One name, πₕ, with methods that dispatch tells apart by what they are given rather than by different names:

  • πₕ(Wₕ, uₕ) and πₕ!(dest, src) — the numeric operator, interpolating a grid function's values onto another space's mesh. interpolate_at is the single-point building block both are written in terms of, and interpolation_matrix is the same interpolant as a sparse matrix rather than applied pointwise.
  • πₕ(uₕ) — the symbolic source, wrapping a grid function's interpolant as an AST leaf, composable with D₋ₓ/M₋ₓ/... inside innerₕ. For the known side of a linear form.

See the operators tutorial for the numeric side and the pattern this exists for: a heterogeneous composite space whose leaves live on different meshes.

Bramble.interpolate_atFunction
interpolate_at(uₕ::VectorElement, x)

The piecewise (multi)linear interpolant of uₕ at the physical point x, using uₕ's own mesh.

Locates the cell of mesh(space(uₕ)) containing x (locate_cell) and blends the $2^D$ grid values at that cell's corners, weighted by x's relative position within it (the standard bilinear/trilinear construction), exact for any affine function of the coordinates and correct on a non-uniform mesh, since it reads the mesh's own point coordinates rather than assuming a fixed step. locate_cell clamps which cell a point outside the mesh is read against to the boundary cell, but the relative position x is weighted by is not itself clamped, so a point outside the mesh is a linear extrapolation along that boundary cell's own slope, not a constant hold of the boundary value.

This is the building block both πₕ!/πₕ (below, the numeric operator) and the one-argument, symbolic πₕ use: x -> interpolate_at(uₕ, x) is itself a valid source function, usable anywhere one is accepted, including directly as Rₕ's own argument: πₕ(Wₕ, src) is Rₕ applied to this one function, not a separate mechanism. Rₕ(Wₕ, f) restricts an arbitrary continuous f; when f happens to be another grid function's own interpolant, restricting it is interpolating it, which is why πₕ generalises Rₕ for the case the source is discrete rather than a closed-form function.

source
Bramble.πₕ!Function
πₕ!(dest::VectorElement, src::VectorElement) -> VectorElement

Fills dest with the piecewise (multi)linear interpolant of src, sampled at dest's own mesh points, providing the in-place numeric interpolation operator named after the Rₕ!/ avgₕ! convention.

interpolate_at(src, ·) is a genuine function of a physical point (evaluable anywhere, not only at src's own grid points), so this is equivalent to Rₕ!(dest, x -> interpolate_at(src, x)). dest and src may be built over entirely different meshes. Rₕ! handles evaluating the interpolant at each of dest's grid points, following dest's backend execution_policy.

Every call here re-locates, via locate_cell, which cell of src's mesh each of dest's points falls in. Interpolating repeatedly between the same two meshes (a time loop transferring a coefficient between two composite leaves, say) should build that once instead: see the interpolation_matrix-based method below, following the same "build the pattern once" shape allocate_system_matrix/assemble! already use.

source
πₕ!(dest::VectorElement, P::SparseMatrixCSC, src::VectorElement) -> VectorElement

Fills dest via a precomputed interpolation_matrix P instead of re-locating each destination point's cell: parent(dest) .= P * parent(src), computed in place via mul! (zero allocations, once P and dest already exist).

P must be interpolation_matrix(space(dest), space(src)) (or an equal-shape matrix built the same way) – a mismatched size throws the usual DimensionMismatch from mul!. Repeated interpolation between the same two meshes should build P once and reuse it here every subsequent call, exactly as allocate_system_matrix/assemble! split the sparsity pattern (expensive, built once) from refilling values (cheap, every step):

P = interpolation_matrix(space(dest), space(src))
for step in 1:nsteps
    Rₕ!(src, coefficient_at(step))
    πₕ!(dest, P, src)   # no locate_cell search, zero allocations
end
source
Bramble.πₕFunction
πₕ(Wₕ::ScalarGridSpace, src::VectorElement) -> VectorElement

Evaluates Rₕ(Wₕ, x -> interpolate_at(src, x)); see πₕ!. Distinguished by multiple dispatch from the one-argument symbolic wrapper πₕ(uₕ) in form/operators/interpolation.jl. The element type is promoted from Wₕ's and src's own, so interpolating a Dual-valued src yields a Dual-valued result on an undifferentiated Wₕ.

source
πₕ(uₕ::VectorElement) -> LazyOp

The interpolant of uₕ, as a symbolic source term; usable anywhere a source is, including inside another operator: innerₕ(D₋ₓ(πₕ(uₕ)), D₋ₓ(v)) differentiates the interpolated field the same way D₋ₓ differentiates any other source, innerₕ(M₋ₓ(πₕ(uₕ)), v) averages it, and so on. This enables a coupled form to evaluate a leaf's grid function on a different leaf's mesh.

Built as source_function(x -> interpolate_at(uₕ, x), Val(D)): a SourceFunction's own local_stencil evaluates its function at the current point of whichever mesh is being walked, so uₕ can originate from another leaf without special handling; the interpolation occurs once per point inside interpolate_at, where ordinary source function calls occur.

source
Bramble.interpolation_matrixFunction
interpolation_matrix(Wdest::ScalarGridSpace, Wsrc::ScalarGridSpace) -> SparseMatrixCSC

The piecewise (multi)linear interpolant of πₕ/interpolate_at as a sparse matrix P rather than applied pointwise: P * parent(src) ≈ parent(πₕ(Wdest, src)) for any src::VectorElement over Wsrc. P is ndofs(Wdest) × ndofs(Wsrc), generally rectangular (since Wdest and Wsrc are built over different meshes), with at most $2^D$ nonzero entries per row: the corner weights of the source cell locate_cell places that destination point in.

Unlike D₋ₓ(Wₕ) and the other operator matrices, this is always a SparseMatrixCSC, regardless of either space's own backend matrix_type. Those matrices are built from shift (a fixed diagonal offset generalized via Kronecker products), but which source cell a destination point falls in has no such regular structure across two independent meshes: it is genuinely sparse and irregular, assembled directly from locate_cell rather than composed from a handful of shifts. Converting the result to another matrix type, where that is meaningful, is left to the caller.

source

Difference, jump and average operators

The finite difference, the jump and the average, per coordinate and over every coordinate at once. See the operators tutorial.

The unscaled differences (diff₋ₓ and its siblings) are the plain, undivided differences these are built from. They are reached as Bramble.diff₋ₓ rather than brought into scope by using Bramble: they have no form-layer node, so they cannot appear inside a bilinear form, and in a form the undivided forward difference is spelled jumpₓ, which says which of the two is meant.

Bramble.diff₋ₓFunction
diff₋ₓ(arg)

The backward unscaled difference along the x direction, $u_{i} - u_{i-1}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for backward_difference(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.diff₋ₓ!Function
diff₋ₓ!(vₕ, uₕ)

The backward unscaled difference of uₕ along the x direction, $u_{i} - u_{i-1}$, written into vₕ.

The in-place form of diff₋ₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(diff₋ₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_difference!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.diff₋ᵧFunction
diff₋ᵧ(arg)

The backward unscaled difference along the y direction, $u_{i} - u_{i-1}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for backward_difference(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.diff₋ᵧ!Function
diff₋ᵧ!(vₕ, uₕ)

The backward unscaled difference of uₕ along the y direction, $u_{i} - u_{i-1}$, written into vₕ.

The in-place form of diff₋ᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(diff₋ᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_difference!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.diff₋₂Function
diff₋₂(arg)

The backward unscaled difference along the z direction, $u_{i} - u_{i-1}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for backward_difference(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.diff₋₂!Function
diff₋₂!(vₕ, uₕ)

The backward unscaled difference of uₕ along the z direction, $u_{i} - u_{i-1}$, written into vₕ.

The in-place form of diff₋₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(diff₋₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_difference!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.diff₋ₕFunction
diff₋ₕ(arg)

The backward unscaled difference of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, diff₋ₕ(uₕ) is (backward_difference(uₕ, Val(1)), backward_difference(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for backward_difference.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source
Bramble.diff₊ₓFunction
diff₊ₓ(arg)

The forward unscaled difference along the x direction, $u_{i+1} - u_i$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for forward_difference(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.diff₊ₓ!Function
diff₊ₓ!(vₕ, uₕ)

The forward unscaled difference of uₕ along the x direction, $u_{i+1} - u_i$, written into vₕ.

The in-place form of diff₊ₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(diff₊ₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_difference!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.diff₊ᵧFunction
diff₊ᵧ(arg)

The forward unscaled difference along the y direction, $u_{i+1} - u_i$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for forward_difference(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.diff₊ᵧ!Function
diff₊ᵧ!(vₕ, uₕ)

The forward unscaled difference of uₕ along the y direction, $u_{i+1} - u_i$, written into vₕ.

The in-place form of diff₊ᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(diff₊ᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_difference!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.diff₊₂Function
diff₊₂(arg)

The forward unscaled difference along the z direction, $u_{i+1} - u_i$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for forward_difference(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.diff₊₂!Function
diff₊₂!(vₕ, uₕ)

The forward unscaled difference of uₕ along the z direction, $u_{i+1} - u_i$, written into vₕ.

The in-place form of diff₊₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(diff₊₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_difference!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.diff₊ₕFunction
diff₊ₕ(arg)

The forward unscaled difference of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, diff₊ₕ(uₕ) is (forward_difference(uₕ, Val(1)), forward_difference(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for forward_difference.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source
Bramble.D₋ₓFunction
D₋ₓ(arg)

The backward finite difference along the x direction, $\frac{u_{i} - u_{i-1}}{h_i}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for backward_finite_difference(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
D₋ₓ(op::LazyOp{D}) where D
D₊ₓ(op::LazyOp{D}) where D
D₋ᵧ(op::LazyOp{D}) where D
D₊ᵧ(op::LazyOp{D}) where D
D₋₂(op::LazyOp{D}) where D
D₊₂(op::LazyOp{D}) where D

Symbolic finite difference operators in specified coordinate directions (x, y, z).

source
Bramble.D₋ₓ!Function
D₋ₓ!(vₕ, uₕ)

The backward finite difference of uₕ along the x direction, $\frac{u_{i} - u_{i-1}}{h_i}$, written into vₕ.

The in-place form of D₋ₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(D₋ₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_finite_difference!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.D₋ᵧFunction
D₋ᵧ(arg)

The backward finite difference along the y direction, $\frac{u_{i} - u_{i-1}}{h_i}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for backward_finite_difference(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.D₋ᵧ!Function
D₋ᵧ!(vₕ, uₕ)

The backward finite difference of uₕ along the y direction, $\frac{u_{i} - u_{i-1}}{h_i}$, written into vₕ.

The in-place form of D₋ᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(D₋ᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_finite_difference!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.D₋₂Function
D₋₂(arg)

The backward finite difference along the z direction, $\frac{u_{i} - u_{i-1}}{h_i}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for backward_finite_difference(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.D₋₂!Function
D₋₂!(vₕ, uₕ)

The backward finite difference of uₕ along the z direction, $\frac{u_{i} - u_{i-1}}{h_i}$, written into vₕ.

The in-place form of D₋₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(D₋₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_finite_difference!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.∇₋ₕFunction
∇₋ₕ(arg)

The backward finite difference of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, ∇₋ₕ(uₕ) is (backward_finite_difference(uₕ, Val(1)), backward_finite_difference(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for backward_finite_difference.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source
∇₋ₕ(op::LazyOp{D}) where D

Symbolic backward gradient operator.

source
∇₋ₕ(ops::Tuple)

Applies the backward gradient component-wise to a tuple of scalar symbolic functions (e.g. the velocity components (u1, u2) of a composite space). Returns a tuple of gradient tuples, one per component.

source
Bramble.D₊ₓFunction
D₊ₓ(arg)

The forward finite difference along the x direction, $\frac{u_{i+1} - u_i}{h_i}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for forward_finite_difference(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.D₊ₓ!Function
D₊ₓ!(vₕ, uₕ)

The forward finite difference of uₕ along the x direction, $\frac{u_{i+1} - u_i}{h_i}$, written into vₕ.

The in-place form of D₊ₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(D₊ₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_finite_difference!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.D₊ᵧFunction
D₊ᵧ(arg)

The forward finite difference along the y direction, $\frac{u_{i+1} - u_i}{h_i}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for forward_finite_difference(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.D₊ᵧ!Function
D₊ᵧ!(vₕ, uₕ)

The forward finite difference of uₕ along the y direction, $\frac{u_{i+1} - u_i}{h_i}$, written into vₕ.

The in-place form of D₊ᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(D₊ᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_finite_difference!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.D₊₂Function
D₊₂(arg)

The forward finite difference along the z direction, $\frac{u_{i+1} - u_i}{h_i}$. The unscaled difference is not divided by the grid spacing; the finite difference is.

Alias for forward_finite_difference(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.D₊₂!Function
D₊₂!(vₕ, uₕ)

The forward finite difference of uₕ along the z direction, $\frac{u_{i+1} - u_i}{h_i}$, written into vₕ.

The in-place form of D₊₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(D₊₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_finite_difference!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.∇₊ₕFunction
∇₊ₕ(arg)

The forward finite difference of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, ∇₊ₕ(uₕ) is (forward_finite_difference(uₕ, Val(1)), forward_finite_difference(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for forward_finite_difference.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source
∇₊ₕ(op::LazyOp{D}) where D

Symbolic forward gradient operator.

source
∇₊ₕ(ops::Tuple)

Applies the forward gradient component-wise to a tuple of scalar symbolic functions, as ∇₋ₕ does. Returns a tuple of gradient tuples, one per component.

source

The forward difference over the averaged spacing, which is the one that satisfies the discrete summation-by-parts identity $(\textrm{Dstar}_{+x} u_h, v_h)_h = -(u_h, D_{-x} v_h)_{+x}$ for grid functions vₕ vanishing on the boundary.

Bramble.Dstar₊ₓFunction
Dstar₊ₓ(arg)

The forward difference of uₕ along the x direction over the averaged spacing, $\frac{u_{i+1} - u_i}{(h_i + h_{i+1})/2}$.

Alias for forward_star_difference(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. The last point along x is truncated to zero.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Dstar₊ₓ(op::LazyOp{D}) where D
Dstar₊ᵧ(op::LazyOp{D}) where D
Dstar₊₂(op::LazyOp{D}) where D

Symbolic starred forward differences in the coordinate directions.

source
Bramble.Dstar₊ₓ!Function
Dstar₊ₓ!(vₕ, uₕ)

The forward difference of uₕ along the x direction over the averaged spacing, $\frac{u_{i+1} - u_i}{(h_i + h_{i+1})/2}$, written into vₕ.

The in-place form of Dstar₊ₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dstar₊ₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_star_difference!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.Dstar₊ᵧFunction
Dstar₊ᵧ(arg)

The forward difference of uₕ along the y direction over the averaged spacing, $\frac{u_{i+1} - u_i}{(h_i + h_{i+1})/2}$.

Alias for forward_star_difference(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. The last point along y is truncated to zero.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.Dstar₊ᵧ!Function
Dstar₊ᵧ!(vₕ, uₕ)

The forward difference of uₕ along the y direction over the averaged spacing, $\frac{u_{i+1} - u_i}{(h_i + h_{i+1})/2}$, written into vₕ.

The in-place form of Dstar₊ᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dstar₊ᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_star_difference!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.Dstar₊₂Function
Dstar₊₂(arg)

The forward difference of uₕ along the z direction over the averaged spacing, $\frac{u_{i+1} - u_i}{(h_i + h_{i+1})/2}$.

Alias for forward_star_difference(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. The last point along z is truncated to zero.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.Dstar₊₂!Function
Dstar₊₂!(vₕ, uₕ)

The forward difference of uₕ along the z direction over the averaged spacing, $\frac{u_{i+1} - u_i}{(h_i + h_{i+1})/2}$, written into vₕ.

The in-place form of Dstar₊₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dstar₊₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_star_difference!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.Dstar₊ₕFunction
Dstar₊ₕ(arg)

The starred forward difference of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, Dstar₊ₕ(uₕ) is (forward_star_difference(uₕ, Val(1)), forward_star_difference(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for forward_star_difference.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source

The centered difference, over the span its stencil covers. It reproduces the derivative of an affine function exactly on any grid, and is skew-symmetric in innerₕ for grid functions vanishing on the boundary.

Bramble.DcₓFunction
Dcₓ(arg)

The centered difference of uₕ along the x direction, $\frac{u_{i+1} - u_{i-1}}{h_i + h_{i+1}}$.

Alias for centered_difference(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. The first and last points along x are truncated to zero, so the mesh needs at least three points along x and an ArgumentError is thrown when it has fewer.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Dcₓ(op::LazyOp{D}) where D
Dcᵧ(op::LazyOp{D}) where D
Dc₂(op::LazyOp{D}) where D

Symbolic centered differences in the coordinate directions.

source
Bramble.Dcₓ!Function
Dcₓ!(vₕ, uₕ)

The centered difference of uₕ along the x direction, $\frac{u_{i+1} - u_{i-1}}{h_i + h_{i+1}}$, written into vₕ.

The in-place form of Dcₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dcₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for centered_difference!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.DcᵧFunction
Dcᵧ(arg)

The centered difference of uₕ along the y direction, $\frac{u_{i+1} - u_{i-1}}{h_i + h_{i+1}}$.

Alias for centered_difference(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. The first and last points along y are truncated to zero, so the mesh needs at least three points along y and an ArgumentError is thrown when it has fewer.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.Dcᵧ!Function
Dcᵧ!(vₕ, uₕ)

The centered difference of uₕ along the y direction, $\frac{u_{i+1} - u_{i-1}}{h_i + h_{i+1}}$, written into vₕ.

The in-place form of Dcᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dcᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for centered_difference!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.Dc₂Function
Dc₂(arg)

The centered difference of uₕ along the z direction, $\frac{u_{i+1} - u_{i-1}}{h_i + h_{i+1}}$.

Alias for centered_difference(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. The first and last points along z are truncated to zero, so the mesh needs at least three points along z and an ArgumentError is thrown when it has fewer.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.Dc₂!Function
Dc₂!(vₕ, uₕ)

The centered difference of uₕ along the z direction, $\frac{u_{i+1} - u_{i-1}}{h_i + h_{i+1}}$, written into vₕ.

The in-place form of Dc₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dc₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for centered_difference!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.DcₕFunction
Dcₕ(arg)

The centered difference of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, Dcₕ(uₕ) is (centered_difference(uₕ, Val(1)), centered_difference(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for centered_difference.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source
Dcₕ(op::LazyOp{D}) where D
Dstar₊ₕ(op::LazyOp{D}) where D
∇ₕ(op::LazyOp{D}) where D

The vector forms: every direction at once, as a D-tuple of nodes. In one dimension there is only one direction, so the node itself is returned rather than a one-element tuple, as ∇₋ₕ and ∇₊ₕ already do.

source

The cross-weighted centered difference, the same two one-sided differences weighted by the opposite spacings. It reproduces the derivative of a quadratic exactly on any grid, and so is second order on a non-uniform one where Dcₓ is first.

Bramble.DₕₓFunction
Dₕₓ(arg)

The cross-weighted centered difference of uₕ along the x direction, the backward differences at $x_{i+1}$ and $x_i$ weighted by $h_i$ and $h_{i+1}$.

Alias for cross_weighted_difference(arg, Val(1)). Second order on a non-uniform grid, where Dcₓ is first. arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. Unlike Dcₓ, the first and last points along x are not truncated: with no neighbour on the far side, each collapses to the one-sided difference the near side still gives, D₊ₓ at the first point and D₋ₓ at the last. The mesh still needs at least three points along x, and an ArgumentError is thrown when it has fewer.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Dₕₓ(op::LazyOp{D}) where D
Dₕᵧ(op::LazyOp{D}) where D
Dₕ₂(op::LazyOp{D}) where D

Symbolic cross-weighted centered differences in the coordinate directions.

source
Bramble.Dₕₓ!Function
Dₕₓ!(vₕ, uₕ)

The cross-weighted centered difference of uₕ along the x direction, the backward differences at $x_{i+1}$ and $x_i$ weighted by $h_i$ and $h_{i+1}$, written into vₕ.

The in-place form of Dₕₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dₕₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for cross_weighted_difference!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.DₕᵧFunction
Dₕᵧ(arg)

The cross-weighted centered difference of uₕ along the y direction, the backward differences at $x_{i+1}$ and $x_i$ weighted by $h_i$ and $h_{i+1}$.

Alias for cross_weighted_difference(arg, Val(2)). Second order on a non-uniform grid, where Dcᵧ is first. arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. Unlike Dcᵧ, the first and last points along y are not truncated: with no neighbour on the far side, each collapses to the one-sided difference the near side still gives, D₊ᵧ at the first point and D₋ᵧ at the last. The mesh still needs at least three points along y, and an ArgumentError is thrown when it has fewer.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.Dₕᵧ!Function
Dₕᵧ!(vₕ, uₕ)

The cross-weighted centered difference of uₕ along the y direction, the backward differences at $x_{i+1}$ and $x_i$ weighted by $h_i$ and $h_{i+1}$, written into vₕ.

The in-place form of Dₕᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dₕᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for cross_weighted_difference!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.Dₕ₂Function
Dₕ₂(arg)

The cross-weighted centered difference of uₕ along the z direction, the backward differences at $x_{i+1}$ and $x_i$ weighted by $h_i$ and $h_{i+1}$.

Alias for cross_weighted_difference(arg, Val(3)). Second order on a non-uniform grid, where Dc₂ is first. arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement. Unlike Dc₂, the first and last points along z are not truncated: with no neighbour on the far side, each collapses to the one-sided difference the near side still gives, D₊₂ at the first point and D₋₂ at the last. The mesh still needs at least three points along z, and an ArgumentError is thrown when it has fewer.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.Dₕ₂!Function
Dₕ₂!(vₕ, uₕ)

The cross-weighted centered difference of uₕ along the z direction, the backward differences at $x_{i+1}$ and $x_i$ weighted by $h_i$ and $h_{i+1}$, written into vₕ.

The in-place form of Dₕ₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(Dₕ₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for cross_weighted_difference!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.∇ₕFunction
∇ₕ(arg)

The cross-weighted centered difference of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, ∇ₕ(uₕ) is (cross_weighted_difference(uₕ, Val(1)), cross_weighted_difference(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for cross_weighted_difference. The centered counterpart of ∇₋ₕ and ∇₊ₕ, built from Dₕₓ rather than from the one-sided differences.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source

Jumps across an interface, $\llbracket u \rrbracket = u_{i+1} - u_i$. There is one of these rather than a forward and a backward pair: a jump belongs to the interface between two cells, not to a direction of travel across it.

Bramble.jumpₓFunction
jumpₓ(arg)

The jump across the interfaces along the x direction, $\\llbracket u \\rrbracket = u_{i+1} - u_i$.

Alias for jump(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

The last point along x has no forward neighbour and is treated as though it were zero, as in diff₊ₓ.

source
jumpₓ(op::LazyOp{D}) -> JumpNode
jumpᵧ(op::LazyOp{D}) -> JumpNode
jump₂(op::LazyOp{D}) -> JumpNode

Symbolic jumps across the interfaces along coordinate directions $x$, $y$, and $z$.

source
Bramble.jumpₓ!Function
jumpₓ!(vₕ, uₕ)

The in-place form of jumpₓ: writes the jump into vₕ and returns it, allocating nothing. vₕ and uₕ must belong to the same space and must not be the same object.

source
Bramble.jumpᵧFunction
jumpᵧ(arg)

The jump across the interfaces along the y direction, $\\llbracket u \\rrbracket = u_{i+1} - u_i$.

Alias for jump(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

The last point along y has no forward neighbour and is treated as though it were zero, as in diff₊ᵧ.

source
Bramble.jumpᵧ!Function
jumpᵧ!(vₕ, uₕ)

The in-place form of jumpᵧ: writes the jump into vₕ and returns it, allocating nothing. vₕ and uₕ must belong to the same space and must not be the same object.

source
Bramble.jump₂Function
jump₂(arg)

The jump across the interfaces along the z direction, $\\llbracket u \\rrbracket = u_{i+1} - u_i$.

Alias for jump(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

The last point along z has no forward neighbour and is treated as though it were zero, as in diff₊₂.

source
Bramble.jump₂!Function
jump₂!(vₕ, uₕ)

The in-place form of jump₂: writes the jump into vₕ and returns it, allocating nothing. vₕ and uₕ must belong to the same space and must not be the same object.

source
Bramble.jumpₕFunction
jumpₕ(arg)

The jump of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, jumpₕ(uₕ) is (jump(uₕ, Val(1)), jump(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for jump.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source
jumpₕ(op::LazyOp{D})

Symbolic jumps across every coordinate direction simultaneously. Returns a JumpNode in 1D, or a NTuple{D, JumpNode} in higher dimensions.

source

Averages of a point with its neighbour.

Bramble.M₋ₓFunction
M₋ₓ(arg)

The backward average along the x direction, $\frac{u_{i-1} + u_{i}}{2}$.

Alias for backward_average(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
M₋ₓ(op::LazyOp{D}) where D
M₊ₓ(op::LazyOp{D}) where D
M₋ᵧ(op::LazyOp{D}) where D
M₊ᵧ(op::LazyOp{D}) where D
M₋₂(op::LazyOp{D}) where D
M₊₂(op::LazyOp{D}) where D

Symbolic averaging operators in specified coordinate directions (x, y, z).

source
Bramble.M₋ₓ!Function
M₋ₓ!(vₕ, uₕ)

The backward average of uₕ along the x direction, $\frac{u_{i-1} + u_{i}}{2}$, written into vₕ.

The in-place form of M₋ₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(M₋ₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_average!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.M₋ᵧFunction
M₋ᵧ(arg)

The backward average along the y direction, $\frac{u_{i-1} + u_{i}}{2}$.

Alias for backward_average(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.M₋ᵧ!Function
M₋ᵧ!(vₕ, uₕ)

The backward average of uₕ along the y direction, $\frac{u_{i-1} + u_{i}}{2}$, written into vₕ.

The in-place form of M₋ᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(M₋ᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_average!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.M₋₂Function
M₋₂(arg)

The backward average along the z direction, $\frac{u_{i-1} + u_{i}}{2}$.

Alias for backward_average(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.M₋₂!Function
M₋₂!(vₕ, uₕ)

The backward average of uₕ along the z direction, $\frac{u_{i-1} + u_{i}}{2}$, written into vₕ.

The in-place form of M₋₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(M₋₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for backward_average!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.M₋ₕFunction
M₋ₕ(arg)

The backward average of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, M₋ₕ(uₕ) is (backward_average(uₕ, Val(1)), backward_average(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for backward_average.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source
M₋ₕ(op::LazyOp{D}) where D

Symbolic backward spatial averaging operator tuple.

source
Bramble.M₊ₓFunction
M₊ₓ(arg)

The forward average along the x direction, $\frac{u_{i} + u_{i+1}}{2}$.

Alias for forward_average(arg, Val(1)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.M₊ₓ!Function
M₊ₓ!(vₕ, uₕ)

The forward average of uₕ along the x direction, $\frac{u_{i} + u_{i+1}}{2}$, written into vₕ.

The in-place form of M₊ₓ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(M₊ₓ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_average!(vₕ, uₕ, Val(1)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.M₊ᵧFunction
M₊ᵧ(arg)

The forward average along the y direction, $\frac{u_{i} + u_{i+1}}{2}$.

Alias for forward_average(arg, Val(2)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.M₊ᵧ!Function
M₊ᵧ!(vₕ, uₕ)

The forward average of uₕ along the y direction, $\frac{u_{i} + u_{i+1}}{2}$, written into vₕ.

The in-place form of M₊ᵧ: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(M₊ᵧ!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_average!(vₕ, uₕ, Val(2)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.M₊₂Function
M₊₂(arg)

The forward average along the z direction, $\frac{u_{i} + u_{i+1}}{2}$.

Alias for forward_average(arg, Val(3)). arg is a mesh, a grid space or a VectorElement: the first two give the operator as a sparse matrix, the third applies it and returns a VectorElement.

Accepts a grid function of a scalar or of a composite grid space. On a composite one the operator is applied to each component in turn, and the result is the composite grid function whose components are those results.

source
Bramble.M₊₂!Function
M₊₂!(vₕ, uₕ)

The forward average of uₕ along the z direction, $\frac{u_{i} + u_{i+1}}{2}$, written into vₕ.

The in-place form of M₊₂: it allocates nothing, where the allocating form allocates its result. Returns vₕ, so it composes: normₕ(M₊₂!(vₕ, uₕ)).

vₕ and uₕ must be grid functions of the same space, and must not be the same object, as every stencil reads neighbours of the target coordinate; aliasing them would read values that have already been overwritten.

Alias for forward_average!(vₕ, uₕ, Val(3)). Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter.

source
Bramble.M₊ₕFunction
M₊ₕ(arg)

The forward average of arg along every coordinate, as a tuple with one entry per spatial dimension. On a one-dimensional mesh it returns that single entry rather than a one-tuple.

For a 2D space, M₊ₕ(uₕ) is (forward_average(uₕ, Val(1)), forward_average(uₕ, Val(2))). arg is a mesh, a grid space or a VectorElement, as for forward_average.

Accepts a grid function of a scalar or of a composite grid space, componentwise on the latter: each entry of the tuple is then itself a composite grid function.

source
M₊ₕ(op::LazyOp{D}) where D

Symbolic forward spatial averaging operator tuple.

source

Inner products and norms

Bramble.innerₕFunction
innerₕ(uₕ::VectorElement, vₕ::VectorElement; markers = ()) -> Real

Returns the discrete $L^2$ inner product of the grid functions uₕ and vₕ, weighting each point by its cell measure.

  • 1D case

\[(\textrm{u}_h, \textrm{v}_h)_h \vcentcolon = \sum_{i=1}^N |\square_{i}| \textrm{u}_h(x_i) \textrm{v}_h(x_i)\]

  • 2D case

\[(\textrm{u}_h, \textrm{v}_h)_h \vcentcolon = \sum_{i=1}^{N_x} \sum_{j=1}^{N_y} |\square_{i,j}| \textrm{u}_h(x_i,y_j) \textrm{v}_h(x_i,y_j)\]

  • 3D case

\[(\textrm{u}_h, \textrm{v}_h)_h \vcentcolon = \sum_{i=1}^{N_x} \sum_{j=1}^{N_y} \sum_{l=1}^{N_z} |\square_{i,j,l}| \textrm{u}_h(x_i,y_j) \textrm{v}_h(x_i,y_j)\]

On a CompositeGridSpace it is the inner product of the product space, the sum of the component-wise products:

\[(\textrm{u}_h, \textrm{v}_h)_h = \sum_{c=1}^{N_c} (\textrm{u}_h^{(c)}, \textrm{v}_h^{(c)})_h\]

which is the only meaning it can have, so there is nothing ambiguous about accepting one. The two grid functions must have the same number of components.

markers restricts the sum to the union of the labelled regions' points (a masked sum of the same cell measures, not a surface integral; see the note above _combined_mask).

source
innerₕ(left::LazyOp{D}, right::LazyOp{D}; markers = ()) -> LazyOp{D}

Constructs a symbolic $L^2$ inner product between left and right: a LinearProduct (source × test) if left is source-only (_is_source_only: a source, or a source wrapped in differences/averages/shifts/jumps/restrictions/scales, never a trial function), or a BilinearProduct (trial × test) otherwise.

This applies specifically when left is a LazyOp: a bare Function/Number/VectorElement is unconditionally a source, so those overloads build a LinearProduct directly. When left arrives already wrapped (πₕ(uₕ) or D₋ₓ(πₕ(uₕ))), this check ensures the correct linear AST node is constructed.

markers restricts the assembled term to the union of the labelled regions: a mask on which grid points it contributes to at all.

source
Bramble.inner₊Function
inner₊(uₕ::VectorElement, vₕ::VectorElement) -> Real
inner₊(uₕ::VectorElement, vₕ::VectorElement, ::Type{Tuple}) -> Tuple
inner₊(uₕ::NTuple{D, VectorElement}, vₕ::NTuple{D, VectorElement}) -> Real

Returns the discrete modified $L^2$ inner product of the grid functions uₕ and vₕ.

If the Tuple argument is given, it returns a D-tuple of all $\textrm{inner}_{x_i,+}$ applied to its input arguments, where D is the topological dimension of the mesh associated with the elements.

If NTuples of VectorElement are passed as input arguments, it returns the sum of all inner products $(\textrm{u}_h[i],\textrm{v}_h[i])_{+x_i}$.

For VectorElements, the definition is given by

  • 1D case

\[(\textrm{u}_h, \textrm{v}_h)_+ \vcentcolon = \sum_{i=1}^{N_x} h_{i} \textrm{u}_h(x_i) \textrm{v}_h(x_i)\]

  • 2D case

\[(\textrm{u}_h, \textrm{v}_h)_+ \vcentcolon = (\textrm{u}_h, \textrm{v}_h)_{+x} + (\textrm{u}_h, \textrm{v}_h)_{+y}\]

  • 3D case

\[(\textrm{u}_h, \textrm{v}_h)_+ \vcentcolon = (\textrm{u}_h, \textrm{v}_h)_{+x} + (\textrm{u}_h, \textrm{v}_h)_{+y} + (\textrm{u}_h, \textrm{v}_h)_{+z}.\]

See the definitions of inner₊ₓ, inner₊ᵧ, and inner₊₂ for more details.

Defined for grid functions of a ScalarGridSpace only, and for tuples whose entries are such grid functions. A grid function of a composite grid space raises a MethodError; take a scalar component of it with components first, which is itself a scalar grid function and is accepted.

source
inner₊(left::LazyOp{1}, right::LazyOp{1}; markers = ())
inner₊(left::NTuple{D,LazyOp{D}}, right::NTuple{D,LazyOp{D}}; markers = ()) where D

Constructs a symbolic modified $L^2_+$ inner product between left and right.

markers restricts the sum as it does for innerₕ.

source
inner₊(left::BackwardDifference{D,Dim}, right::BackwardDifference{D,Dim}) -> LazyOp{D}

inner₊ of two backward differences taken along the same direction, which is the weight the product carries: InnerPlus{Dim}.

In one dimension there is only one direction, so inner₊(left, right) already answers. Above one dimension a bare inner₊ of two operators names no direction, and the weights are directional: the direction is read off the nodes. This is what makes inner₊(D₋ₓ(u), D₋ₓ(v)) mean what it reads as.

Backward differences only, as everywhere inner₊ meets a difference: the weights are those of the summation-by-parts identity, which pairs them with a backward difference.

Constructs a LinearProduct (source × test) if left is source-only (_is_source_only), or a BilinearProduct otherwise, matching innerₕ.

markers restricts the sum as it does for innerₕ.

source
inner₊(left::LazyOp{D}, right::LazyOp{D}) -> LazyOp{D}

Symbolic inner₊ of two operators neither of which names a direction.

In one dimension there is only one direction to name, so this is the product, with weight InnerPlus{1}. Above one dimension the weights are directional and nothing here supplies the direction, so it throws an ArgumentError.

markers restricts the sum as it does for innerₕ.

source
inner₊(left::LazyOp{D}, right::BackwardDifference{D,Dim}) -> LazyOp{D}
inner₊(left::BackwardDifference{D,Dim}, right::LazyOp{D}) -> LazyOp{D}

inner₊ where one side is a backward difference and the other is not: the difference names the direction, so the product carries InnerPlus{Dim}.

This is what inner₊(u, D₋ₓ(v)) means: the common form, and the one the coupled pressure-velocity terms are written in, inner₊(p, D₋ₓ(v[1])) with p a symbolic scalar field. It is not restricted to indexed leaves: a plain TrialFunction reads the direction off the difference just as an IndexedTrialFunction does.

Backward differences only, as everywhere inner₊ meets a difference.

A LinearProduct if left is source-only (_is_source_only), a BilinearProduct otherwise, matching innerₕ.

markers restricts the sum as it does for innerₕ.

source
inner₊(left::BackwardDifference{D,Dim1}, right::BackwardDifference{D,Dim2}) where {D,Dim1,Dim2}

Rejects inner₊ of two backward differences taken along different directions.

Each side names a direction and they disagree, so there is no one weight the product carries. This also has to be written out rather than left to dispatch: with a difference on either side, the two single-sided methods above tie, and the pair would be an ambiguity rather than an error the caller can read.

source
inner₊(left::NTuple{N,<:Tuple}, right::NTuple{N,<:Tuple}) where N

Vector-field inner₊: sums per-component inner products. Used when left and right are tuples of gradient tuples, e.g. inner₊(∇₋ₕ(u), ∇₋ₕ(v)) where u = (u1, u2) is a velocity tuple. Each element pair (left[k], right[k]) is a D-tuple of LazyOp (a gradient), which dispatches to the existing inner₊(::NTuple{D,LazyOp}, ::NTuple{D,LazyOp}).

This overload is intentionally restricted to NTuple{N,<:Tuple} so it does not interfere with inner₊(NTuple{D,VectorElement}, NTuple{D,VectorElement}) handled by the @generated method in inner_product.jl. That restriction is what separates this file's symbolic family from that file's numeric one; it is asserted in test/form/inner_products.jl, testset "Symbolic and numeric families stay apart".

markers restricts the whole sum, not each component separately, as it does for innerₕ.

source
Bramble.inner₊ₓFunction
inner₊ₓ(uₕ::VectorElement, vₕ::VectorElement; markers = ()) -> Real

Returns the discrete modified $L^2$ inner product of the grid functions uₕ and vₕ associated with the first variable.

For VectorElements, it is defined as

  • 1D case

\[(\textrm{u}_h, \textrm{v}_h)_+ \vcentcolon = \sum_{i=1}^{N_x} h_{i} \textrm{u}_h(x_i) \textrm{v}_h(x_i)\]

  • 2D case

\[(\textrm{u}_h, \textrm{v}_h)_{+x} \vcentcolon = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y} h_{x,i} h_{y,j+1/2} \textrm{u}_h(x_i,y_j) \textrm{v}_h(x_i,y_j)\]

  • 3D case

\[(\textrm{u}_h, \textrm{v}_h)_{+x} \vcentcolon = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y}\sum_{l=1}^{N_z} h_{x,i} h_{y,j+1/2} h_{z,l+1/2} \textrm{u}_h(x_i,y_j,z_l) \textrm{v}_h(x_i,y_j,z_l).\]

Defined for grid functions of a ScalarGridSpace only. A grid function of a composite grid space is rejected at dispatch; take a scalar component of it with components first, which is itself a scalar grid function and is accepted.

markers restricts the sum as it does for innerₕ (a masked sum, not a surface integral).

source
inner₊ₓ(left::LazyOp{D}, right::LazyOp{D}) where D
inner₊ᵧ(left::LazyOp{D}, right::LazyOp{D}) where D
inner₊₂(left::LazyOp{D}, right::LazyOp{D}) where D

Constructs directional modified $L^2_+$ inner products in x, y, and z directions.

A LinearProduct if left is source-only (_is_source_only), a BilinearProduct otherwise, exactly as innerₕ decides.

markers restricts the sum as it does for innerₕ.

source
Bramble.inner₊ᵧFunction
inner₊ᵧ(uₕ::VectorElement, vₕ::VectorElement; markers = ()) -> Real

Returns the discrete modified $L^2$ inner product of the grid functions uₕ and vₕ associated with the second variable, the $y$ direction.

For VectorElements, it is defined as

  • 2D case

\[(\textrm{u}_h, \textrm{v}_h)_{+y} \vcentcolon = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y} h_{x,i} h_{y,j+1/2} \textrm{u}_h(x_i,y_j) \textrm{v}_h(x_i,y_j)\]

  • 3D case

\[(\textrm{u}_h, \textrm{v}_h)_{+y} \vcentcolon = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y}\sum_{l=1}^{N_z} h_{x,i+1/2} h_{y,j} h_{z,l+1/2} \textrm{u}_h(x_i,y_j,z_l) \textrm{v}_h(x_i,y_j,z_l).\]

Defined for grid functions of a ScalarGridSpace only. A grid function of a composite grid space is rejected at dispatch; take a scalar component of it with components first, which is itself a scalar grid function and is accepted.

markers restricts the sum as it does for innerₕ (a masked sum, not a surface integral).

source
Bramble.inner₊₂Function
inner₊₂(uₕ::VectorElement, vₕ::VectorElement; markers = ()) -> Real

Returns the discrete modified $L^2$ inner product of the grid functions uₕ and vₕ associated with the z variable

\[(\textrm{u}_h, \textrm{v}_h)_{+z} \vcentcolon = \sum_{i=1}^{N_x}\sum_{j=1}^{N_y}\sum_{l=1}^{N_z} h_{x,i+1/2} h_{y,j+1/2} h_{z,l} \textrm{u}_h(x_i,y_j,z_l) \textrm{v}_h(x_i,y_j,z_l).\]

Defined for grid functions of a ScalarGridSpace only. A grid function of a composite grid space is rejected at dispatch; take a scalar component of it with components first, which is itself a scalar grid function and is accepted.

markers restricts the sum as it does for innerₕ (a masked sum, not a surface integral).

source
Bramble.normₕFunction
normₕ(uₕ::VectorElement) -> Real

Returns the discrete $L^2$ norm of the grid function uₕ, defined as

\[\Vert \textrm{u}_h \Vert_h \vcentcolon = \sqrt{(\textrm{u}_h, \textrm{u}_h)_h}\]

On a CompositeGridSpace it is the norm of the product space, which follows from the inner product there: the square root of the sum of the components' squared norms.

source
Bramble.norm₁ₕFunction
norm₁ₕ(uₕ::VectorElement) -> Real

Returns the discrete version of the standard $H^1$ norm of VectorElement uₕ.

\[\Vert \textrm{u}_h \Vert_{1h} \vcentcolon = \sqrt{ \Vert \textrm{u}_h \Vert_h^2 + \Vert \nabla_h \textrm{u}_h \Vert_h^2 }\]

Built from the squared quantities directly: taking normₕ and snorm₁ₕ and squaring them back up would compute two square roots only to undo them.

Defined for grid functions of a ScalarGridSpace only. A grid function of a composite grid space is rejected at dispatch; take a scalar component of it with components first, which is itself a scalar grid function and is accepted.

source
Bramble.snorm₁ₕFunction
snorm₁ₕ(uₕ::VectorElement) -> Real

Returns the discrete $H^1$ seminorm of the grid function uₕ,

\[|\textrm{u}_h|_{1h} \vcentcolon = \Vert \nabla_h \textrm{u}_h \Vert_+\]

so that snorm₁ₕ(uₕ) == norm₊(∇₋ₕ(uₕ)) in one, two and three dimensions. The argument is the grid function itself; the backward gradient is taken internally, and without materialising it, so this allocates nothing.

See also: norm₁ₕ, norm₊, ∇₋ₕ.

Defined for grid functions of a ScalarGridSpace only. A grid function of a composite grid space is rejected at dispatch; take a scalar component of it with components first, which is itself a scalar grid function and is accepted.

source
Bramble.norm₊Function
norm₊(uₕ::VectorElement) -> Real
norm₊(uₕ::NTuple{D, VectorElement}) -> Real

Returns the discrete modified $L^2$ norm of the grid function uₕ. It also accepts an NTuple of VectorElements.

For VectorElements uₕ, it is defined as

\[\Vert \textrm{u}_h \Vert_+ = \sqrt{(\textrm{u}_h,\textrm{u}_h)_+}.\]

and for NTuples of VectorElements it returns

\[\Vert \textrm{u}_h \Vert_+ \vcentcolon = \sqrt{ \sum_{i=1}^D(\textrm{u}_h[i],\textrm{u}_h[i])_{+,x_i}}.\]

Defined for grid functions of a ScalarGridSpace only, and for tuples whose entries are such grid functions. A grid function of a composite grid space raises a MethodError; take a scalar component of it with components first, which is itself a scalar grid function and is accepted.

source

Forms

Linear and bilinear forms, their assembly, and the boundary conditions applied to an assembled system. See the forms tutorial.

Building a form

Bramble.formFunction
form(Wₕ, f) -> LinearForm

Construct a LinearForm over the test space Wₕ using the linear expression f.

Construction resolves the AST once and runs simplify_ast over it – factoring common scalings, combining like terms, and eliding zero-scaled ones – before it is stored. Grid partitioning for parallel assembly is determined from the resolved AST during assembly (see _colour_strides).

Every SourceFunction reachable from the simplified AST – a source term built directly from a plain function, f(x), rather than a VectorElement or a Ref – is then sampled once against its own leaf's space and lowered to a SourceVector (gpena/Bramble.jl#197): a brand-new closure passed as a source used to force a full recompilation of the assembly pipeline (~11ms measured) on every distinct closure, since Julia gives it its own type; assembling against the fixed SourceVector shape instead means that cost is paid once, here, not on every later assemble!/assemble call. This changes what a raw closure that captures mutable state does: it is evaluated once, now, not re-evaluated on later assemblies. VectorElement and Ref coefficients are unaffected – see the note on _lower_sources in form/common.jl for why, and for the documented alternative (update_coefficients!) a source meant to keep varying should use instead.

Examples

# 1D linear form: l(v) = (f, v)
l = form(Wₕ, v -> innerₕ(fₕ, v))
source
form(Wₕ, Vₕ, f) -> BilinearForm

Construct a BilinearForm over the trial space Wₕ and the test space Vₕ from the bilinear expression f (a function of trial and test arguments (u, v)). The AST is resolved once and run through simplify_ast – factoring common scalings, combining like terms, and eliding zero-scaled ones – before it is stored.

Examples

# a(u, v) = (∇₋ₕu, ∇₋ₕv)₊
a = form(Wₕ, Wₕ, (u, v) -> inner₊ₓ(D₋ₓ(u), D₋ₓ(v)))

# a coupled system, one term per block
a = form(Vₕ, Vₕ, (u, v) -> inner₊ₓ(D₋ₓ(u(1)), D₋ₓ(v(1))) + innerₕ(u(2), v(1)))
source

Assembling

assemble allocates its result; the mutating forms refill one that already exists, which is what a time loop wants. allocate_system_matrix builds a matrix's sparsity pattern once so that assemble! can refill it without allocating.

Bramble.assembleFunction
assemble(form::LinearForm; dirichlet = nothing, dirichlet_components = nothing) -> AbstractVector

Assemble the system vector of the LinearForm, applying the boundary values dirichlet carries on the regions it names. dirichlet accepts a label => f Pair, a Tuple of such Pairs, or constraints from dirichlet_constraints – a bare label or Tuple of labels has no values to write and raises an error (see _normalize_dirichlet for every accepted form). dirichlet_components restricts which leaf components of a composite test space they bind to (see dirichlet_bc!).

Runs serially or across threads following test_space(form)'s backend execution_policy: Serial (the default) or Parallel. assemble_parallel! always threads regardless of the backend policy.

source
assemble(form::BilinearForm; dirichlet = nothing, dirichlet_components = nothing) -> SparseMatrixCSC

Allocate a matrix with the form's sparsity pattern and assemble into it.

Call this once, then assemble into what it returns. Building the sparsity pattern is the larger part of the work (at 250,000 degrees of freedom it is 9,700 us and 52 MB against 1,500 us and zero allocations to refill the matrix), and the pattern does not change between assemblies. A time loop or Newton iteration benefits from preallocating the pattern once:

A = assemble(a)                        # once: pattern, allocation and initial fill
for step in 1:nsteps
    Rₕ!(cₕ, coefficient_at(step))      # modified in-place
    assemble!(A, a)                    # or assemble_parallel!(A, a)
end

Runs serially or across threads following form.trial_space's backend execution_policy: Serial by default. Optional dirichlet applies boundary conditions to the matrix – a label Symbol, a Tuple of labels, a label => f Pair (values ignored on the matrix side), or constraints from dirichlet_constraints; see _normalize_dirichlet for every accepted form. dirichlet_components restricts which leaf components of a composite trial space they bind to (see dirichlet_bc!).

source
assemble(a::BilinearForm, l::LinearForm; dirichlet = nothing, dirichlet_components = nothing, symmetrize::Bool = false) -> (A, F)

Assemble both the matrix and the vector in one call, applying the same dirichlet constraints to each – the common case of building a system to solve A \ F against. a and l should share the same test space; boundary values are read from dirichlet once rather than once per form.

symmetrize = true additionally restores symmetry in A after dirichlet_bc! (which only clears rows, not the columns) and updates F to match, via symmetrize!. Requires dirichlet to name at least one label – there is nothing to symmetrize against otherwise.

A, F = assemble(a, l; dirichlet = :boundary => sol, symmetrize = true)
u = A \ F

is the one-call equivalent of assembling a and l separately and calling symmetrize! by hand.

source
Bramble.assemble!Function
assemble!(b::AbstractVector, form::LinearForm; dirichlet = nothing,
          dirichlet_components = nothing) -> AbstractVector

Refill b with the assembled form and return it with zero allocations (0 bytes).

assemble! uses the pre-resolved form.ast stored directly inside the form.

Live coefficients

  • Grid functions: the stored AST retains references to source VectorElement storage. Mutating values in-place (Rₕ!(uₕ, ...) or parent(uₕ) .= ...) between steps automatically updates the assembled vector without needing to rebuild the form.
  • Dynamic scalars: plain numbers work directly for constant scalars. To update a scalar dynamically across loop iterations, wrap it in a Ref(val) (e.g. α = Ref(1.0); l = form(Wₕ, v -> α * innerₕ(uₕ, v))). Mutating α[] = new_val evaluates live during assembly with 0 allocations.

Arguments

  • b: Vector to refill, with length ndofs(test_space(form)).
  • form: Linear form to assemble.

Keywords

  • dirichlet: Boundary values to impose after assembly, and the labels to impose them on, together – a label => f Pair, a Tuple of such Pairs, or constraints from dirichlet_constraints (default: nothing; see _normalize_dirichlet for every accepted form).
  • dirichlet_components: Restricts which leaf components of a composite test_space(form) the labels bind to (see dirichlet_bc!; default: nothing, targeting all leaves).

Runs serially or across threads following test_space(form)'s backend execution_policy: Serial or Parallel. assemble_parallel! forces threaded execution regardless of backend policy.

See also assemble, assemble_parallel!, and evaluate!.

source
assemble!(A::SparseMatrixCSC, form::BilinearForm; dirichlet = nothing, dirichlet_components = nothing) -> SparseMatrixCSC

Assemble the BilinearForm into the preallocated sparse matrix A, allocating nothing (0 bytes).

Runs serially or across threads following form.trial_space's backend execution_policy: Serial (the default) or Parallel. assemble_parallel! is a separate, lower-level entry point that always threads, ignoring the backend's policy.

assemble! uses the pre-resolved form.ast stored directly inside the form.

Live coefficients

  • Grid functions: the stored AST retains references to source VectorElement storage. Mutating values in-place (Rₕ!(cₕ, ...) or parent(cₕ) .= ...) between steps automatically updates the matrix entries with 0 allocations.
  • Dynamic scalars: plain numbers work directly for constant scalars. To update a scalar dynamically across loop iterations, wrap it in a Ref(val) (e.g. β = Ref(1.0); a = form(Wₕ, Wₕ, (u, v) -> innerₕ(β * D₋ₓ(u), D₋ₓ(v)))). Mutating β[] = new_val evaluates live during assembly with 0 allocations.
source
Bramble.assemble_parallel!Function
assemble_parallel!(b::AbstractVector, form::LinearForm) -> AbstractVector

Refill b with the assembled form across threads and return it, regardless of test_space(form)'s backend execution policy. Unlike assemble!, does not apply Dirichlet conditions.

source
assemble_parallel!(A::SparseMatrixCSC, form::BilinearForm) -> SparseMatrixCSC

Refill A with the assembled form across threads and return it, regardless of form.trial_space's backend policy. A must already carry the correct sparsity pattern from allocate_system_matrix or a previous assemble. Unlike assemble!, does not apply dirichlet_labels.

Colouring on the test side ensures thread safety when updating stored matrix values concurrently.

source
Bramble.allocate_system_matrixFunction
allocate_system_matrix(form::BilinearForm, ast = resolve_form_ast(form)) -> SparseMatrixCSC

Build the sparse matrix a BilinearForm assembles into: the appropriate size, correct sparsity pattern, and stored zeros throughout.

The pattern follows from the stencil rather than coefficient values, remaining invariant while the mesh and expression structure are unchanged. Preallocating the matrix once outside loops allows zero-allocation in-place assembly:

A = allocate_system_matrix(a)
for step in 1:nsteps
    assemble!(A, a)          # refills values in-place with zero allocations
end

Only the structure is preallocated here; all stored entries are zero until assemble! fills them.

See also assemble and assemble!.

source
Bramble.evaluate!Function
evaluate!(scratch::AbstractVector, form::LinearForm, vₕ::VectorElement) -> Number

Evaluate form at vₕ, assembling into scratch rather than into a newly allocated vector, and return the resulting contracted scalar value.

Useful when both the assembled vector and the scalar value are needed (such as a Newton step requiring the residual vector and its norm). scratch is overwritten and contains the right-hand side upon return.

For the scalar value alone, form(vₕ) fuses the contraction into the assembly sweep in a single pass.

Examples

l = form(Wₕ, v -> innerₕ(fₕ, v))
scratch = zeros(ndofs(Wₕ))
for step in 1:nsteps
    Rₕ!(fₕ, source_at(step))          # modified in-place
    value = evaluate!(scratch, l, uₕ)
end
source

Jacobian sparsity

For a Newton residual built from a BilinearForm with a live nonlinear coefficient (see the nonlinear Poisson example), jacobian_pattern reads the Jacobian's sparsity pattern directly off the form's AST, without AD tracing. ast_sparsity_detector wraps it as an ADTypes.AbstractSparsityDetector, ready to hand AutoSparse directly (requires ADTypes.jl).

Bramble.jacobian_patternFunction
jacobian_pattern(a::BilinearForm, coefficient_dependencies::Function...) -> SparseMatrixCSC{Bool}

Sparsity pattern of the Jacobian of a Newton residual A(u) * u - F, where a is the BilinearForm that assembles A(u) (e.g. diffusion_matrix in the nonlinear Poisson example) and each function in coefficient_dependencies names, symbolically, the stencil operator one of a's live coefficients was itself computed from – written the same way a form term names an operator, as a function of the trial placeholder. If a's diffusion coefficient was built as αvals = α.(M₋ₕ(uₕ)), pass U -> M₋ₕ(U).

Derived entirely from a's AST and each dependency's own stencil reach – no AD tracing, no coefficient values needed. A safe superset of the exact pattern (a pointwise nonlinear α can never narrow the reach its argument already has), suitable for ADTypes.KnownJacobianSparsityDetector:

a = form(Wₕ, Wₕ, (U, V) -> inner₊(αvals * ∇₋ₕ(U), ∇₋ₕ(V)))   # αvals = α.(M₋ₕ(uₕ))
pattern = jacobian_pattern(a, U -> M₋ₕ(U))
sparse_ad = AutoSparse(AutoForwardDiff();
    sparsity_detector = KnownJacobianSparsityDetector(pattern),
    coloring_algorithm = GreedyColoringAlgorithm())

Composite trial/test spaces

A dependency may also name a different leaf, the same way a form term does – U -> U(2) for a coefficient that is component 2's own value (no stencil op, as in the coupled reaction-diffusion example's v_c), or U -> M₋ₕ(U(2)) for one built from a stencil op applied to that other component. nothing named (U -> M₋ₕ(U), no (k)) means the coefficient depends on this block's own trial leaf, exactly like the non-composite case above. Every dependency still applies to every block the walk visits, whichever leaf it names – a safe superset stays safe however many blocks end up seeing an entry they did not strictly need.

# a = form(Vₕ, Vₕ, (p, q) -> inner₊(∇₋ₕ(p(1)), ∇₋ₕ(q(1))) + innerₕ(v_c * p(1), q(1)) +
#                            inner₊(∇₋ₕ(p(2)), ∇₋ₕ(q(2))) - innerₕ(u_c * p(2), q(2)))
pattern = jacobian_pattern(a, U -> U(2), U -> U(1))   # block (1,1) reads U(2), (2,2) reads U(1)
source
Bramble.ast_sparsity_detectorFunction
ast_sparsity_detector(a::BilinearForm, coefficient_dependencies::Function...)

An ADTypes.AbstractSparsityDetector that supplies jacobian_pattern(a, coefficient_dependencies...) directly as a Newton residual's Jacobian sparsity, in place of one detected by tracing:

sparse_ad = AutoSparse(AutoForwardDiff();
    sparsity_detector = ast_sparsity_detector(a, U -> M₋ₕ(U)),
    coloring_algorithm = GreedyColoringAlgorithm())

Requires ADTypes.jl; call using ADTypes before calling this function.

source

Time-dependent problems and the SciML stack

semidiscretize applies the method of lines to a spatial BilinearForm and a source LinearForm, producing the system M uₕ' = F(t) - A uₕ as a callable with the (du, u, p, t) signature a time stepper expects. Dirichlet conditions become algebraic rows of a singular mass matrix, so the result is an index-1 differential-algebraic system needing only the boundary data g, never its time derivative (see the heat equation example).

Nothing in this group needs a weak dependency except the last three, which name their results the way SciMLBase does: ode_function and ode_problem hand the semidiscretisation to OrdinaryDiffEq, and linear_problem hands a steady system to LinearSolve with its factorisations and preconditioners. All three require SciMLBase.jl.

Bramble.semidiscretizeFunction
semidiscretize(a::BilinearForm, l::LinearForm; kwargs...) -> Semidiscretization

Semidiscretise M u_h' = F(t) - A u_h from the spatial form a and the source l, both posed on the same test space.

Write a as the steady problem is written: assemble(a) is A, so the steady state of the returned system solves A u_h = F.

Keywords

  • mass: BilinearForm defining M (default: innerₕ(u, v), the discrete inner product, which is diagonal).
  • dirichlet: constrained labels and, where they carry values, the values – every form assemble accepts, including time-dependent constraints from dirichlet_constraints(Ωₕ, I, :label => (x, t) -> ...) (default: nothing).
  • dirichlet_components: leaf components of a composite space the labels bind to (default: nothing, all leaves).
  • state: VectorElement the current u is copied into before each assembly, for forms whose coefficients read it (default: nothing).
  • update_coefficients!: called with the current t before each assembly, for coefficients that vary in time – t -> Rₕ!(fₕ, x -> f(x, t)) for a time-dependent source, or t -> (α[] = t) for a scalar Ref (default: nothing).
  • reassemble: refill A at every step, for an operator whose coefficients change with t or u (default: false).

Time dependence of the Dirichlet values is detected by arity, exactly as dirichlet_constraints validates it: conditions accepting (x, t) are evaluated at each step, conditions accepting (x) are not.

Examples

Ωₕ = mesh(domain(interval(0.0, 1.0)), 101)
Wₕ = gridspace(Ωₕ)
I = interval(0.0, 1.0)

fₕ = Rₕ(Wₕ, x -> 1.0)
a = form(Wₕ, Wₕ, (u, v) -> inner₊(∇₋ₕ(u), ∇₋ₕ(v)))
l = form(Wₕ, v -> innerₕ(fₕ, v))
bcs = dirichlet_constraints(Ωₕ, I, :boundary => (x, t) -> 0.0)

sd = semidiscretize(a, l; dirichlet = bcs)

See also ode_function, ode_problem, jacobian!.

source
Bramble.SemidiscretizationType
Semidiscretization{...}

Method-of-lines semidiscretisation of M u_h' = F(t) - A u_h, callable with the (du, u, p, t) signature a time stepper expects.

Built by semidiscretize; read back with mass_matrix and operator_matrix.

Fields

  • operator: spatial BilinearForm, assembled into A.
  • source: source LinearForm, assembled into F(t) at each step.
  • space: the test space both forms share.
  • operator_matrix: A, with eₖ rows on the constrained degrees of freedom.
  • mass_matrix: M, with zero rows on the constrained degrees of freedom.
  • source_vector: the reusable F buffer, refilled in place.
  • constraints: how the source's boundary values are reached – one of NoConstraints, LabelsOnly, StaticConstraints or TimeDependentConstraints.
  • labels: constrained boundary labels.
  • components: leaf components the labels bind to, or nothing for all.
  • state: VectorElement receiving u before assembly, or nothing.
  • update_coefficients: callable invoked with t before assembly, or nothing.
  • reassemble: Val(true) to refill A at every step.
source
Bramble.mass_matrixFunction
mass_matrix(sd::Semidiscretization) -> SparseMatrixCSC

Return the constant mass matrix M, whose constrained rows are zero.

source
Bramble.operator_matrixFunction
operator_matrix(sd::Semidiscretization) -> SparseMatrixCSC

Return the assembled spatial operator A, whose constrained rows are eₖ.

source
Bramble.jacobian!Function
jacobian!(J, sd::Semidiscretization, u, p, t) -> J

Fill J with ∂/∂u (F(t) - A u) = -A and return it.

Exact whenever the operator's coefficients do not read u – that is, whenever sd was built without state. With a state the operator also varies with u, the term -(∂A/∂u) u is missing, and this is a Picard linearisation rather than a Jacobian: pass jacobian = nothing to ode_function and let the solver build it by sparse automatic differentiation instead, seeded from jacobian_pattern.

See also jacobian_prototype.

source
Bramble.jacobian_prototypeFunction
jacobian_prototype(sd::Semidiscretization) -> SparseMatrixCSC

Return a matrix carrying the sparsity of ∂/∂u (F(t) - A u), for a solver to use as its Jacobian cache.

This is the pattern of the assembled operator, Dirichlet rows included, which is what the system's Jacobian has – jacobian_pattern answers the different question of what a Newton residual's Jacobian looks like when the form's coefficients depend on the solution.

See also jacobian!.

source
Bramble.ode_functionFunction
ode_function(sd::Semidiscretization; kwargs...) -> ODEFunction
ode_function(a::BilinearForm, l::LinearForm; kwargs...) -> ODEFunction

Wrap a semidiscretisation as an ODEFunction carrying its mass matrix, Jacobian and sparsity, ready for OrdinaryDiffEq.

The two-form method builds the Semidiscretization first, forwarding every keyword to semidiscretize.

Keywords

  • jacobian: jacobian! (the default) to hand the solver the exact -A, or nothing to let it build one by automatic differentiation from jac_prototype.
  • jac_prototype: sparsity for the solver's Jacobian cache (default: jacobian_prototype(sd)).

The resulting system is a differential-algebraic one whenever any Dirichlet label is constrained, since those rows of the mass matrix are zero. Solve it with a method that admits a singular mass matrix – FBDF, QNDF, Rodas5P, RadauIIA5 – not an explicit one.

Rosenbrock methods and `update_coefficients!`

A Rosenbrock method (Rodas5P, Rosenbrock23) also needs ∂f/∂t, which it builds by differentiating through t. That works when the only time dependence is the Dirichlet data, since those values reach the assembled vector as its element type. An update_coefficients! hook writing into a Float64 VectorElement – the usual t -> Rₕ!(fₕ, x -> f(x, t)) – cannot take a ForwardDiff.Dual time, and the solve fails on the first step with a time-gradient error. Either pass Rodas5P(autodiff = AutoFiniteDiff()), or use a BDF method, which needs no ∂f/∂t at all. FBDF and QNDF are unaffected either way.

Requires SciMLBase.jl; call using SciMLBase (or any package that loads it, such as OrdinaryDiffEq) before calling this function.

See also ode_problem, linear_problem.

source
Bramble.ode_problemFunction
ode_problem(sd::Semidiscretization, u₀, I::CartesianProduct{1}; kwargs...) -> ODEProblem
ode_problem(a::BilinearForm, l::LinearForm, u₀, I; kwargs...) -> ODEProblem

Build the ODEProblem stepping sd over the time domain I, from the initial condition u₀ – a VectorElement or a plain vector. I may equally be a (t₀, t₁) tuple.

u₀ is copied, never mutated, and the copy is made consistent with the Dirichlet rows at t₀ (see dirichlet_bc!).

Keywords are those of ode_function; the two-form method also forwards to semidiscretize.

Requires SciMLBase.jl.

Examples

sd = semidiscretize(a, l; dirichlet = bcs)
prob = ode_problem(sd, Rₕ(Wₕ, x -> sinpi(x[1])), interval(0.0, 1.0))
sol = solve(prob, FBDF())

See also ode_function, semidiscretize.

source
Bramble.linear_problemFunction
linear_problem(a::BilinearForm, l::LinearForm; kwargs...) -> LinearProblem

Assemble a and l into the LinearProblem that LinearSolve.solve takes, so the steady system reaches the factorisations, iterative solvers and preconditioners in that stack without being assembled by hand first.

Keywords

  • dirichlet, dirichlet_components: as assemble takes them.
  • symmetrize: restore symmetry after imposing the conditions (default: false; see symmetrize!).

Requires SciMLBase.jl, which defines LinearProblem; LinearSolve itself is needed only to solve the result.

Examples

using LinearSolve, IncompleteLU

prob = linear_problem(a, l; dirichlet = bcs)
sol = solve(prob, KrylovJL_GMRES())

See also assemble, ode_problem.

source

Caching a coefficient-dependent assembly by element type

A Newton residual generic over T (Float64 on a plain call, ForwardDiff.Dual while an AD backend's sparse Jacobian sweep is probing it) cannot preallocate one matrix the way a Picard loop can. type_cached_assemble! gives the sparsity pattern a place to live per element type it is ever reached at instead, so only the very first call at a given type pays for it.

Bramble.type_cached_assemble!Function
type_cached_assemble!(build, cache::AbstractDict, uₕ::VectorElement;
    dirichlet = nothing, dirichlet_components = nothing) -> SparseMatrixCSC

Assembles a coefficient-dependent BilinearForm into a matrix whose sparsity pattern is built once per distinct element type uₕ is ever passed at, rather than on every call – the fix diffusion_matrix-style Newton residuals in the nonlinear worked examples name and deliberately defer, since assemble/allocate_system_matrix rebuild the whole matrix, pattern included, every time otherwise.

build(uₕ) is called once for each element type uₕ is ever seen at, and must return (a, refill!): the BilinearForm to assemble, built around whatever live coefficient buffer(s) it needs (see the forms tutorial), and a one-argument function refill!(uₕ) updating those buffers from the current uₕ – called on every invocation, cache hit or miss, so a later call at an already-seen type still sees the new guess rather than the one build first saw.

build itself should be a named function defined once, not a closure literal written inside whatever function calls type_cached_assemble! — the same reason the Picard loop in poisson_nonlinear.jl builds its own form once, outside the loop, rather than on every iteration: a do ... end block re-literalized on every call allocates a new closure each time, which is exactly the cost this function exists to avoid paying more than once.

function build_diffusion(uₕ)
    Mu = element(Wₕ, eltype(uₕ))     # scratch for M₋ₓ!'s own output
    αvals = element(Wₕ, eltype(uₕ))
    a = form(Wₕ, Wₕ, (U, V) -> inner₊(αvals * ∇₋ₕ(U), ∇₋ₕ(V)))
    refill!(uₕ) = begin
        M₋ₓ!(Mu, uₕ)          # in place: `M₋ₓ(uₕ)` alone would allocate a fresh result
        αvals .= α.(Mu)
    end
    return a, refill!
end

cache = Dict()
diffusion_matrix(uₕ) = type_cached_assemble!(
    build_diffusion, cache, uₕ; dirichlet = :boundary)

refill! reaches for M₋ₓ! rather than the non-mutating M₋ₓ/M₋ₕ deliberately: the latter allocates a fresh result every call (the same similar-based cost every allocating stencil operator has), which would silently reintroduce an O(n) allocation this function's whole point is to stop paying repeatedly. M₋ₓ! alone covers the 1D case above; a D-dimensional coefficient needs one scratch buffer and one M₋ₓ!/M₋ᵧ!/M₋₂! call per direction, the same way poisson_nonlinear.jl's own nonlinear_series builds a D-dimensional coefficient tuple.

cache is shared across an entire Newton (or Picard) loop, one Dict per residual: the first call at a given type pays build's own cost plus allocate_system_matrix's; every later call at that same type pays only assemble!'s refill plus a small, fixed dictionary/dynamic-dispatch overhead fetching the cached entry back out (a few KB, independent of ndofs) – not the O(ndofs) pattern rebuild a cache miss (or no cache at all) pays every time.

Not thread-safe: cache is a plain, unlocked Dict, sized for the one-cache-per-residual usage above. A form assembled from more than one task needs a lock or a per-task cache, the same as any other shared mutable Dict.

source

Dirichlet conditions

Bramble.dirichlet_constraintsFunction
dirichlet_constraints(input, [I::CartesianProduct{1}], pairs::Pair...) -> DomainMarkers

Create Dirichlet boundary constraints.

Each pair is of the form :label => func, where :label identifies the boundary region and func defines the Dirichlet values. If the optional time domain I is provided, func must be a time-dependent function func(x, t); this is checked by arity, since nothing about func itself can be evaluated at construction time.

input can be a CartesianProduct, a Domain, an AbstractMeshType, a ScalarGridSpace, or a CompositeGridSpace from which the mesh is extracted. The :label must match a label in the mesh definition.

source
dirichlet_constraints(X::CartesianProduct, f::Function) -> DomainMarkers

Create a single Dirichlet boundary constraint with function f under the :boundary label.

source
Bramble.dirichlet_bc!Function
dirichlet_bc!(A::AbstractMatrix, Ωₕ::AbstractMeshType, labels::Symbol...) -> AbstractMatrix

Apply Dirichlet boundary conditions to matrix A based on marked regions in the mesh Ωₕ.

For each index i associated with the given Dirichlet labels, this function:

  1. Sets all elements in the i-th row of A to zero.
  2. Sets the diagonal element A[i, i] to one.
source
dirichlet_bc!(A::AbstractMatrix, space::CompositeGridSpace, labels::Symbol...; components = nothing) -> AbstractMatrix

Apply Dirichlet boundary conditions to matrix A on the regions named by labels, restricted to the leaf components specified in components (1-based positions in leaf_spaces_offsets(space), following the depth-first ordering used by u(1)/u(2) addressing). components = nothing (the default) applies to every leaf component.

This allows coupled systems to constrain selected fields while leaving others unconstrained (for example, prescribing velocity while leaving pressure free in a Stokes problem):

Wₕ = vector_gridspace(Ωₕ, Val(2))   # 1: velocity, 2: pressure
dirichlet_bc!(A, Wₕ, :left, :right; components = 1)   # velocity only

Successive calls with different labels/components pairs compose cleanly.

source
dirichlet_bc!(v::AbstractVector, Ωₕ::AbstractMeshType, bcs::ConstraintMarkers, labels::Symbol...) -> AbstractVector

Write Dirichlet values into v at the points marked by labels.

bcs may be unevaluated constraints or time-evaluated constraints (see ConstraintMarkers). Only the marked entries are modified, with complexity proportional to the boundary cardinality.

source
dirichlet_bc!(u::AbstractVector, sd::Semidiscretization, t::Number) -> u

Write sd's Dirichlet values at time t into u and return it.

An index-1 differential-algebraic system needs its initial condition to satisfy the algebraic rows already: a u disagreeing with g(x, 0) on the boundary is inconsistent, and a stiff solver either rejects it or absorbs it into the first step. ode_problem applies this to a copy of the initial condition it is handed.

source
Bramble.symmetrize!Function
symmetrize!(A::AbstractMatrix, F::AbstractVector, Wₕ::CompositeGridSpace, labels::Symbol...; components = nothing)

Symmetrize a coupled linear system leaf space by leaf space.

The counterpart of the composite dirichlet_bc!: each leaf's marker mask is read at that leaf's offset into the global system without allocating full-system masks. leaf_spaces_offsets returns a tuple, enabling loop unrolling and type stability.

Takes the same components keyword as composite dirichlet_bc!, restricting which leaf components labels binds to (1-based positions in leaf_spaces_offsets(Wₕ)). components = nothing (the default) applies to every leaf.

source

Structural properties

Whether a BilinearForm is symmetric, or symmetric positive semi-definite, by construction — a cheap, symbolic check on its expression, answered before any matrix is assembled.

LinearAlgebra.issymmetricMethod
issymmetric(a::BilinearForm) -> Bool

Whether a is symmetric by construction: innerₕ(L(u), L(v)), or a sum or scaling of such terms, with the same L written once and applied to both the trial and test argument.

Purely structural: this walks a's expression and never assembles a matrix. It is also conservative: a term that happens to produce a symmetric matrix through some other route answers false, the same as one that is not symmetric at all.

This describes the unconstrained operator. dirichlet_bc! zeros a row without touching its column, so a matrix assembled with dirichlet is not symmetric even when issymmetric(a) is true, until symmetrize! restores it. true here is a claim about a's expression, not about whatever matrix a particular call to assemble produced.

Examples

a = form(Wₕ, Wₕ, (u, v) -> inner₊ₓ(D₋ₓ(u), D₋ₓ(v)))
issymmetric(a)  # true: the same D₋ₓ on both sides

b = form(Wₕ, Wₕ, (u, v) -> inner₊(u, D₋ₓ(v)))
issymmetric(b)  # false: different operators either side

issymmetric(Matrix(assemble(a)))                                # true
issymmetric(Matrix(assemble(a; dirichlet = :boundary)))   # false: rows zeroed, columns not
source
LinearAlgebra.isposdefMethod
isposdef(a::BilinearForm) -> Bool

Whether a is symmetric positive semi-definite by the same LᵀWL construction issymmetric checks: true only when, in addition, every scaling along the way is by a positive number, which is what keeps that positivity from being flipped or collapsed.

Purely structural, like issymmetric, and for the same reason conservative: this does not prove positive-definite (which also needs L to have trivial kernel), only that the assembled matrix is symmetric positive semi-definite, enough to make cholesky worth attempting first rather than a general factorization.

Describes the unconstrained operator, exactly as issymmetric does: a matrix assembled with dirichlet needs symmetrize! after dirichlet_bc! before either symmetry or positive-definiteness holds of it, isposdef(a) being true notwithstanding.

source

Exporters

Writing a mesh and its grid functions to a file a viewer can open. See the VTK export tutorial and the PGFPlots export tutorial.

Bramble.export_vtkFunction
export_vtk(filename::AbstractString, Ωₕ::AbstractMeshType, fields::Pair...) -> Vector{String}
export_vtk(filename::AbstractString, uₕ::VectorElement, name::AbstractString = "u") -> Vector{String}

Write Ωₕ, and any number of named fields over it, to a VTK rectilinear grid file (.vtr).

Each entry in fields is name => data, where data is a VectorElement over a grid space on Ωₕ (scalar or composite) or a plain array already shaped like the grid. The second method is a shorthand for a single field, named "u" unless told otherwise.

A 1D mesh gets a degenerate second axis rather than being refused: VTK has no dedicated 1D grid type, but a rectilinear grid one point deep in y opens and renders correctly.

Requires WriteVTK.jl; call using WriteVTK before calling this.

Examples

using Bramble, WriteVTK

Ωₕ = mesh(domain(interval(0.0, 1.0) × interval(0.0, 1.0)), (20, 20), (true, true))
Wₕ = gridspace(Ωₕ)
uₕ = Rₕ(Wₕ, x -> sin(x[1]) * x[2])

export_vtk("solution", Ωₕ, "u" => uₕ)   # writes solution.vtr
export_vtk("solution", uₕ)              # the same field, named "u"
source
Bramble.export_pgfplotsFunction
export_pgfplots(filename::AbstractString, Ωₕ::AbstractMeshType{1}, fields::Pair...) -> String
export_pgfplots(filename::AbstractString, Ωₕ::AbstractMeshType{2}, field::Pair) -> String
export_pgfplots(filename::AbstractString, uₕ::VectorElement, name::AbstractString = "u") -> String

Write grid data to a plain-text table, laid out the way pgfplots reads it directly: no external package needed, since the format is just whitespace-separated numbers.

On a 1D mesh, any number of named fields become columns: x name₁ name₂ ..., one row per grid point, readable with \addplot table {file.dat} or \addplot table[y=name] {file.dat} to pick one column by name. A composite VectorElement expands into one column per component, named name_1, name_2, and so on.

On a 2D mesh, exactly one field is written as x y z triples (pgfplots' surf/mesh format has no way to encode more than one value per point) with a blank line after each run of constant x. That blank line is what tells \addplot3[surf] table {file.dat} where one row of the grid ends and the next begins; without it the same numbers plot as a shredded zigzag instead of a surface. A composite element is refused with a message saying so, rather than silently writing one of its components.

data in a field pair can be a VectorElement, or a plain array already shaped like the grid (a vector in 1D, a vector or a (nx, ny) matrix in 2D).

A 3D mesh is refused: \addplot3[surf] plots a height field over a 2D domain, not a true 3D volume, so a 3D mesh has no faithful representation in this format. See export_vtk.

Examples

using Bramble

Ωₕ = mesh(domain(interval(0.0, 1.0)), 33, true)
Wₕ = gridspace(Ωₕ)
uₕ = Rₕ(Wₕ, sin)
export_pgfplots("curve", Ωₕ, "u" => uₕ)   # writes curve.dat

Ω2 = mesh(domain(interval(0.0, 1.0) × interval(0.0, 1.0)), (20, 20), (true, true))
W2 = gridspace(Ω2)
v2 = Rₕ(W2, x -> sin(x[1]) * x[2])
export_pgfplots("surface", Ω2, "u" => v2)   # writes surface.dat, for \addplot3[surf]
source