Geometry and meshes
One-dimensional cell-centered finite-volume meshes. See the User Guide's meshes chapter.
Pyrolysis.Geometry.create_uniform_mesh — Function
create_uniform_mesh(L::Real, n_cells::Int, ::Val{NC};
T_initial::Real=300.0,
ξ_initial=nothing,
cross_section_area::Real=1.0) -> Mesh1D{NC}Create a uniform 1D mesh.
Arguments
L: Domain length (thickness) [m]n_cells: Number of cellsVal{NC}: Number of components as a type parameter (useVal(NC))T_initial=300.0: Initial temperature [K]ξ_initial=nothing: Initial concentrations (NTuple or scalar)cross_section_area=1.0: Cross-sectional area [m²]
Returns
A Mesh1D{NC} with uniform cell spacing.
Convention
- z = 0 is the BOTTOM surface (substrate, boundary_id = 2)
- z = L is the TOP surface (exposed surface, boundary_id = 1)
- Cell 1 is at z ≈ 0 (bottom), Cell N is at z ≈ L (top)
- Heat enters from the top (z = L), material shrinks toward bottom
Example
mesh = create_uniform_mesh(0.01, 100, Val(2)) # 1 cm, 100 cells, 2 componentsPyrolysis.Geometry.create_stretched_mesh — Function
create_stretched_mesh(L::Real, n_cells::Int, ::Val{NC}, stretch::Real;
T_initial::Real=300.0,
ξ_initial=nothing,
cross_section_area::Real=1.0,
stretch_from::Symbol=:top) -> Mesh1D{NC}Create a geometrically stretched 1D mesh with the finest cells at the boundary named by stretch_from and cell sizes growing geometrically (ratio stretch) away from it.
Arguments
L: Domain length [m]n_cells: Number of cellsVal{NC}: Number of components as a type parameter (useVal(NC))stretch: Geometric size ratio between adjacent cells (must be ≥ 1; 1 = uniform). Each cell isstretchtimes thicker than its neighbor on the refined side.T_initial=300.0: Initial temperature [K]ξ_initial=nothing: Initial concentrationscross_section_area=1.0: Cross-sectional area [m²]stretch_from=:top: Which boundary gets the finest cells —:top(exposed surface at z = L, the default) or:bottom(substrate at z = 0)
Returns
A Mesh1D{NC} with geometric stretching.
Example
# Fine mesh near top surface (z=L), coarser toward bottom (z=0)
mesh = create_stretched_mesh(0.01, 50, Val(2), 1.1; stretch_from=:top)Pyrolysis.Geometry.MeshTopology — Type
MeshTopology — immutable connectivity.
A MeshTopology{D, NC} carries everything that does not change once the mesh is built: nodes, cells, faces, boundary tags, and dimensional metadata. Mutable per-step state (current node positions, cell volumes, face areas, mesh velocities) lives in MeshGeometry inside the Workspace.
This split is the structural prerequisite for the unified variant surface and the Jacobian backends (geometry derivatives need a clean distinction between "what changes" and "what doesn't").
Type Parameters
D: Spatial dimension (1 today; 2/3 are the design target)NC: Number of components (carried for compile-time dispatch by consumers)
Fields
nodes::Vector{NodeT}: Node objects (Node1D for D=1)cells::Vector{CellT}: Cell objectsfaces::Vector{FaceT}: Face objectsboundary_tags::Dict{Symbol,Vector{Int}}: tag => face IDs (e.g.:top,:bottom)n_active_cells::Int: Active (leaf) cell count for AMR
Pyrolysis.Geometry.MeshGeometry — Type
MeshGeometry — mutable per-step geometry.
A MeshGeometry{D} carries the geometric quantities that change as the mesh moves (ALE) or is regenerated (AMR): node positions, cell volumes, face areas and (for D ≥ 2) face normals. The cross-sectional area A(t) for the 1D specialization lives here as a scalar.
Geometry instances live inside the Workspace so the immutable MeshTopology does not have to be rebuilt every time z or V changes.
Type Parameters
D: Spatial dimension (1 today; 2/3 are the design target)
Fields (1D specialization layout)
node_positions::Vector{Float64}: currentzper nodenode_positions_ref::Vector{Float64}: reference (initial)zper nodecell_centers::Vector{Float64}: cell center positionscell_volumes::Vector{Float64}: cell volumesface_positions::Vector{Float64}: face positionsface_areas::Vector{Float64}: face cross-sectional areasnode_velocities::Vector{Float64}: ALE mesh velocitiesmesh_time::Base.RefValue{Float64}: timestamp of the geometry snapshotcross_section_area::Base.RefValue{Float64}: currentA(t)(scalar in 1D)cross_section_area_initial::Float64: calibration referenceA_0
For D ≥ 2, node_positions and face_normals become Vector{SVector{D,Float64}} and cross_section_area* becomes a per-face scalar.