Skip to content

vlc1/StencilCore.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StencilCore.jl

Build Status Dev

The shared type vocabulary at the root of a three-package stack for variable-coefficient Cartesian stencils and the symbolic algebra that builds them. StencilCore owns the types; it has no assembly and depends only on StaticArrays.jl.

StencilCore         stencil types: AccessStyle, AbstractStencil, AbstractPointwise,
  │                                ArrayOrTermLike, StaticShift, LinearStencil,
  │                                StarStencil, Stencil, as_linear / as_star
  │                  scalar CAS:   AbstractScalar{T}, Var, Constant, Null, Unity,
  │                                Scalar, @var, @addmethod,
  │                                simplify, materialize, differentiate
  ├── StencilAssembly      CSC assembly  (build / assemble / update!)
  └── StencilCalculus      term-level CAS (simplify, differentiate, materialize) + bridge

What it provides

  • AccessStyle trait (ColumnAccess / RowAccess) and the AbstractStencil{T} / NeighborhoodStencil{T, S<:AccessStyle} hierarchy — T is the coefficient eltype (the linear-map space, mirroring Unity{T} in scalar-land), accessed via Base.eltype(::AbstractStencil). The two abstract children of AbstractStencil are AbstractPointwise{T} (diagonal stencils, no offsets) and NeighborhoodStencil{T, S} (offset-bearing, carries an AccessStyle).
  • AbstractTerm{T} — a dimension-/size-less array-like with element type T — and ArrayOrTermLike{T} = Union{AbstractArray{T}, AbstractTerm{T}}, the coefficient type of every stencil (a stencil is assemblable with a concrete array coefficient, symbolic with a term coefficient).
  • StaticPair{D,O} / StaticShift — type-level lattice offsets with a +/-/* algebra, the zero shift ô, and basis shifts ê₁ … ê₉.
  • LinearStencil (contiguous offsets along one axis), the interlaced StarStencil (whole star per cell, explicit diagonal), and the general Stencil (arbitrary reverse-lex offset list).
  • as_linear / as_star — narrow a general Stencil to an assemblable type by a shift-pattern match and a verbatim coefficient copy.
  • AbstractScalar{T} — the cell-level scalar algebra. Concrete leaves Var, Constant, Null, Unity plus the interior Scalar node, with operator overloads, a structural simplify, materialize, and a Jacobian-aware differentiate (including the SVector → SMatrix self-derivative case). The @var macro declares a named Var; @addmethod installs a typed Julia method from a scalar expression.

Install

The three packages are unregistered and resolve each other through relative [sources] paths, so clone them side by side:

git clone …/StencilCore
git clone …/StencilAssembly
git clone …/StencilCalculus

Then ]dev /path/to/StencilCore (or add the others, whose [sources] point at ../StencilCore).

Example

using StencilCore, StaticArrays
# A 1-D forward difference stencil (offsets 0,1; one SVector of coeffs per cell).
st = LinearStencil{1}(SUnitRange(0, 1), fill(SVector(-1.0, 1.0), 5))

# Type-level offsets read like lattice vectors:
3ê₁ + ê₂                      # StaticShift{Tuple{StaticPair{1,3}, StaticPair{2,1}}}

# The scalar CAS, on its own:
@var τ Float64
differentiate(2τ + τ * τ, τ)                  # 2 + 2τ  (simplified)
differentiate(Constant(2.0), τ)               # Null{Float64}() — no dependence

# Vector-valued symbols: the Jacobian lands in the matching square SMatrix.
@var x SVector{2, Float64}
differentiate(2x, x)          # Scalar tree, eltype SMatrix{2,2,Float64,4}

# Turn a scalar expression into a callable Julia method:
@var y Int
@addmethod myfun (τ ^ y) (y, τ)  # function myfun(y::Int, τ::Float64); τ ^ y; end
myfun(2, 3.0)                  # 9.0

# ...or widen the emitted signature with a NamedTuple of type overrides
# (the tree stays concretely typed; only the method signature widens):
@addmethod myfun (τ ^ y) (y = Integer, τ = AbstractFloat)
myfun(big(2), 3.0f0)           # accepts any Integer / AbstractFloat

See AGENTS.md for the canonical design decisions.

Design: why type-based dispatch?

StencilCore encodes expression structure in the type system rather than runtime tags. The full AST of a scalar expression lives in type parameters:

Scalar{typeof(+), Tuple{Var{,Float64}, Constant{Float64}}, Float64}

This pays dividends throughout the stack:

  • materialize / differentiate are type-stable. Return types are computed at compile time from type parameters; @code_warntype shows a concrete Body::T, never Any.
  • simplify is type-stable. A @generated rewriter resolves Null/Unity identities, double-negation, and constant fold entirely from types — no runtime value inspection.
  • Zero-overhead narrowing. as_linear / as_star match the offset pattern at compile time; the coefficient is reused verbatim with no runtime loop.
  • Materialized values are plain Julia arrays, with no symbolic wrapper to strip before calling BLAS or StaticArrays kernels.

The trade-off vs. Symbolics.jl: Symbolics uses a uniform Num type (type erasure) for generality; StencilCore uses concrete per-shape types (type explosion) for compiler transparency. For the bounded, shape-homogeneous expression vocabulary of stencil coefficients the explosion is acceptable and the transparency matters. See the Design rationale page in the docs for the full analysis and comparison table.

About

Type vocabulary for variable-coefficient Cartesian-mesh stencils

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages