Unstructured Finite Volume#
- class pybamm.FiniteVolumeUnstructured(options=None)[source]#
Cell-centered finite volume method on unstructured meshes.
Supports triangles and quadrilaterals (2D), tetrahedra and hexahedra (3D). Operators:
Laplacian – Two-Point Flux Approximation (TPFA) with an implicit non-orthogonal correction: the face normal is split as \(\hat n = \alpha \hat e + \mathbf{k}\) along the unit centroid-to-centroid direction \(\hat e\), so the normal derivative is \(\alpha (u_j - u_i)/d + \mathbf{k}\cdot\nabla u_f\) with the cross term taken from the Green-Gauss gradient. On orthogonal meshes \(\mathbf{k} = 0\) and this is plain TPFA.
Gradient – Green-Gauss cell-centroid reconstruction
Divergence – face-flux summation (adjoint of gradient)
Boundary conditions – ghost-cell (Dirichlet) / direct injection (Neumann)
Neumann boundary values on the named axis sides (
"left"/"right","front"/"back","bottom"/"top") are coordinate-direction derivatives (\(\partial u/\partial x\), etc.), matchingpybamm.FiniteVolume; e.g.u = xtakes value+1on both"left"and"right". Values on any other face tag (Gmsh region names,"iface_*") are outward-normal derivatives \(\partial u/\partial n\).- Parameters:
options (dict, optional) – Passed through to
pybamm.SpatialMethod. Additionally"non-orthogonal correction"selects the decomposition of the face normal:"over-relaxed"(default, \(\alpha = 1/\cos \theta\), favouring diagonal dominance) or"minimum"(\(\alpha = \cos\theta\), the smallest cross term). Both are exact on linear fields.
Extends:
pybamm.spatial_methods.spatial_method.SpatialMethod- boundary_integral(child, discretised_child, region)[source]#
Integral of the owner-cell values of
childover the boundary faces ofregion("entire"= all exterior faces).
- boundary_value_or_flux(symbol, discretised_child, bcs=None)[source]#
Owner-cell values on a boundary side (zeroth-order boundary value); corner sides return the single closest boundary cell.
- definite_integral_matrix(child, vector_type='row', integration_dimension='primary')[source]#
Cell-volume weights of the primary domain as a
pybamm.Matrix, one block per auxiliary-domain repeat.- Parameters:
child (pybamm.Symbol) – The symbol being integrated.
vector_type (str, optional) –
"row"(default) or"column".integration_dimension (str, optional) – Only
"primary"is supported: cells have no secondary structure to integrate over.
- Raises:
NotImplementedError – For a non-primary
integration_dimension.
- delta_function(symbol, discretised_symbol)[source]#
Implements the delta function on the approriate side for a spatial method.
- Parameters:
symbol (
pybamm.Symbol) – The symbol to which is being integrateddiscretised_symbol (
pybamm.Symbol) – The discretised symbol of the correct size
- div_D_grad(div_symbol, grad_child, disc_D, disc_u, boundary_conditions)[source]#
Discretise
div(D * grad(u))as a single TPFA operation.Fully symbolic — works for both constant and state-dependent scalar
D. Internal-face fluxes use the distance-weighted harmonic mean ofD(resistances in series, aspybamm.FiniteVolumedoes for coefficients of a gradient, so material interfaces carry the exact two-cell flux) and the two-point normal derivative plus its non-orthogonal cross term (see_tpfa_matrix()).Dmust be strictly positive.This method is only reached when the expression is written as
div(D * grad(u))(a single product, matched syntactically during discretisation); other flux forms go through the genericgradient()/divergence()operators, which cannot apply boundary conditions conservatively and raise instead.
- divergence(symbol, discretised_symbol, boundary_conditions)[source]#
Face-flux divergence of a cell-centred vector field.
Boundary faces use zeroth-order flux extrapolation, so fluxes built from BC-carrying gradients are rejected (see the raise below).
- gradient(symbol, discretised_symbol, boundary_conditions)[source]#
Least-squares cell-centroid gradient, returned as a
pybamm.VectorFieldwith one component per dimension.Exact on linear fields for any cell shape: every face contributes one directional-derivative equation — towards the neighbour centroid (internal faces), towards the face centroid holding the prescribed value (Dirichlet), or the normal derivative itself (Neumann). Boundary faces without a condition contribute nothing.
- gradient_squared(symbol, discretised_symbol, boundary_conditions)[source]#
Pointwise
|grad u|^2viagradient().
- indefinite_integral(child, discretised_child, direction)[source]#
Implements the indefinite integral for a spatial method.
- Parameters:
child (
pybamm.Symbol) – The symbol to which is being integrateddiscretised_child (
pybamm.Symbol) – The discretised symbol of the correct sizedirection (str) – The direction of integration
- Returns:
Contains the result of acting the discretised indefinite integral on the child discretised_symbol
- Return type:
class: pybamm.Array
- integral(child, discretised_child, integration_dimension, integration_variable=None)[source]#
Volume integral over the primary domain (cell-volume weights).
- internal_neumann_condition(left_symbol_disc, right_symbol_disc, left_mesh, right_mesh, left_bcs=None, right_bcs=None)[source]#
Normal gradient across the interface between two submeshes, one value per interface face (outward from
left_mesh).On unstructured meshes this is the two-point difference plus the non-orthogonal cross term (see
_tpfa_matrix()), whose face gradient is fitted on both sides with the interface faces as cross-mesh rows.left_bcs/right_bcsare the external boundary conditions of each side, used by that fit.
- laplacian(symbol, discretised_symbol, boundary_conditions)[source]#
Laplacian
Matrix @ discretised_symbol + bc_rhs: the two-point flux plus the non-orthogonal cross term, which is built from the BC-aware Green-Gauss gradient so it stays fully implicit.
- process_binary_operators(bin_op, left, right, disc_left, disc_right)[source]#
Apply a binary operator componentwise when either operand is a
pybamm.VectorField, lifting scalars to N components.
- set_internal_bcs_for_concat(disc, var, children, outer_bcs)[source]#
Build internal BC dict for each
Concatenationchild by walking its mesh’sinterface_datagraph instead of assuming consecutive 1D-stack pairs.Returns
Nonewhen noiface_<other>face buckets exist in any child mesh — that means there’s no graph-discovered topology, so the caller should fall through to the legacy 1D-stack pairwise routine.- For each child
T_aon submeshmesh_a(graph case): Pass through any user-supplied
outer_bcswhose tag matches an external boundary tag present inmesh_a.boundary_faces.For each interface
mesh_a ↔ mesh_b(one entry per neighbor inmesh_a.interface_data), setiface_<b>to the discretised internal Neumann gradient betweenT_aand the matching childT_b.
- For each child