Solvers¶
Stokes Flow¶
SNES_Stokes¶
- class underworld3.systems.solvers.SNES_Stokes[source]¶
Bases:
SNES_Stokes_SaddlePtStokes equation solver for incompressible viscous flow.
This class provides functionality for a discrete representation of the Stokes flow equations assuming an incompressibility (or near-incompressibility) constraint.
The momentum equation is:
\[-\nabla \cdot \left[ \boldsymbol{\tau} - p \mathbf{I} \right] = \mathbf{f}\]with the incompressibility constraint:
\[\nabla \cdot \mathbf{u} = 0\]The flux term is a deviatoric stress (\(\boldsymbol{\tau}\)) related to velocity gradients (\(\nabla \mathbf{u}\)) through a viscosity tensor \(\eta\), and a volumetric (pressure) part \(p\):
\[\boldsymbol{\tau} = \frac{\eta}{2}\left( \nabla \mathbf{u} + \nabla \mathbf{u}^T \right)\]The constraint equation gives incompressible flow by default but can be set to any function of the unknown \(\mathbf{u}\) and \(\nabla \cdot \mathbf{u}\).
- Parameters:
mesh (uw.discretisation.Mesh) – The computational mesh.
velocityField (uw.discretisation.MeshVariable, optional) – Pre-existing velocity field. If None, one is created automatically.
pressureField (uw.discretisation.MeshVariable, optional) – Pre-existing pressure field. If None, one is created automatically.
degree (int, optional) – Polynomial degree for velocity interpolation. Default is 2.
p_continuous (bool, optional) – If True (default), pressure is continuous. Set False for discontinuous pressure.
verbose (bool, optional) – Enable verbose output during solving. Default is False.
DuDt (SemiLagrangian_DDt or Lagrangian_DDt, optional) – Material derivative operator for velocity (used in derived classes).
DFDt (SemiLagrangian_DDt or Lagrangian_DDt, optional) – Material derivative operator for flux (used in viscoelastic models).
Notes
Viscosity model: The viscosity tensor \(\boldsymbol{\eta}\) is provided by setting the
constitutive_modelproperty to one of theuw.constitutive_modelsclasses. It may be constant, spatially varying, non-linear, or anisotropic.Augmented Lagrangian: Setting
penaltyto a non-zero value adds \(\lambda \nabla \cdot \mathbf{u}\) to the weak form, improving convergence for incompressible flow (in addition to the constraint equation).Mixed finite elements: The pressure field interpolation order determines the integration order of the mixed method and is typically lower than the velocity field order.
Viscoelastic models: For viscoelastic behaviour, the flux term contains stress history tracked on a particle swarm. See
SNES_VE_Stokes.See also
SNES_VE_StokesViscoelastic Stokes solver with flux history.
SNES_NavierStokesNavier-Stokes solver with inertial terms.
uw.constitutive_modelsAvailable viscosity models.
Examples
>>> import underworld3 as uw >>> mesh = uw.meshing.UnstructuredSimplexBox(minCoords=(0,0), maxCoords=(1,1), cellSize=0.1) >>> stokes = uw.systems.Stokes(mesh, degree=2) >>> stokes.constitutive_model = uw.constitutive_models.ViscousFlowModel() >>> stokes.constitutive_model.Parameters.viscosity = 1.0 >>> stokes.bodyforce = [0, -1] # gravity >>> stokes.solve()
- instances = 0¶
- __init__(mesh, velocityField=None, pressureField=None, degree=2, p_continuous=True, verbose=False, DuDt=None, DFDt=None)[source]¶
- Parameters:
mesh (Mesh)
velocityField (EnhancedMeshVariable | None)
pressureField (EnhancedMeshVariable | None)
degree (int | None)
p_continuous (bool | None)
verbose (bool | None)
DuDt (SemiLagrangian | Lagrangian)
DFDt (SemiLagrangian | Lagrangian)
- set_jacobian_F1_source(F1_source, linesearch='cp')[source]¶
Override the F1 expression used to build the Jacobian blocks.
By default, the Stokes Jacobian’s uu / up G2, G3 blocks are autodiff’d from the residual F1. Some problems benefit from differentiating a different but related expression — e.g. a smooth (softmin) viscosity formula for the Jacobian while the residual F1 keeps a sharp Min, so Newton sees a continuous derivative even when the iterate sits exactly on the yield kink.
Setting
F1_sourcetriggers a JIT recompile (the Jacobian symbols change). PassNoneto revert to autodiff of F1.- Parameters:
F1_source (sympy.Matrix or None) – Alternative expression of the same shape as
F1.sym.linesearch (str or None, default
"cp") – SNES linesearch type to install whenF1_sourceis set. Defaults to"cp"(critical-point) because inexact-Newton steps don’t reliably reduce the residual norm and PETSc’s defaultbt(backtracking) consequently rejects useful steps withDIVERGED_LINE_SEARCH.cpaccepts the predicted step at the optimum of the local linearisation and converges cleanly on the same problems wherebtflails. Set toNoneto leave the linesearch type untouched (e.g. if you’ve already configured one viapetsc_options). Has no effect whenF1_source is None.
- solve(zero_init_guess=True, timestep=None, _force_setup=False, verbose=False, debug=False, debug_name=None, evalf=False, order=None, picard=0, divergence_retries=0)[source]¶
Solve the Stokes system, with optional viscoelastic stress history.
When a constitutive model with stress history is active (DFDt is not None), the solve includes pre/post hooks for advecting stress history, updating BDF coefficients, and projecting the actual stress after the solve.
- Parameters:
zero_init_guess (bool) – If True, use zero initial guess. Otherwise use current field values.
timestep (float, optional) – Advection timestep. Required when stress history is active.
_force_setup (bool) – Force rebuild of pointwise functions.
verbose (bool) – Enable verbose output.
evalf (bool) – Force numerical evaluation during history updates.
order (int, optional) – Override the VE time integration order.
picard (int, default=0) – Number of Picard iterations before switching to Newton. Picard uses a simplified Jacobian and can help convergence for strongly nonlinear problems like VEP at yield onset.
divergence_retries (int, default=0) – If SNES returns a DIVERGED reason after the main solve, re-call the underlying Newton up to this many times with a warm start (
zero_init_guess=False) to try to rescue. Each retry uses the just-computed iterate plus the freshly-advected stress history, which is often enough for VEP at yield onset (Min/softmin kinks) to step off a bad Newton iterate.0preserves legacy behaviour (divergence is terminal). Typical useful value is 1. Only applies in the VE/VEP branch (DFDt is not None).debug (bool)
debug_name (str)
- property tau¶
Deviatoric stress from the most recent solve.
When stress history is active (VEP), returns
psi_star[0]which contains the actual projected stress. Otherwise falls through to the base class lazy projection.
- F0¶
Velocity equation body force term (pointwise).
The \(\mathbf{f}_0\) term represents external body forces acting on the fluid, typically gravity. This is the negative of the
bodyforceparameter.
- F1¶
Velocity equation flux/stress term (pointwise).
The \(\mathbf{F}_1\) tensor represents the stress response of the fluid, combining deviatoric stress \(\boldsymbol{\tau}\), pressure \(p\), and penalty term for weak incompressibility.
- PF0¶
Pressure equation constraint term (continuity).
The \(h_0\) term enforces the incompressibility constraint \(\nabla \cdot \mathbf{u} = 0\). Additional constraints can be added via
add_condition().
- property CM_is_setup¶
Whether the constitutive model is configured for this solver.
- property strainrate¶
Symmetric strain rate tensor from velocity gradients.
The strain rate tensor \(\dot{\varepsilon}\) is computed as:
\[\dot{\varepsilon}_{ij} = \frac{1}{2}\left(\frac{\partial u_i}{\partial x_j} + \frac{\partial u_j}{\partial x_i}\right)\]- Returns:
Symmetric tensor of shape
(dim, dim)wheredimis the mesh dimensionality.- Return type:
sympy.Matrix
See also
strainrate_1dVoigt notation (vector) form.
stress_deviatorDeviatoric stress computed from strain rate.
- property strainrate_1d¶
Strain rate in Voigt notation (vector form).
Converts the symmetric strain rate tensor to Voigt notation for use in constitutive model calculations. In 2D, returns a 3-component vector; in 3D, a 6-component vector.
- Returns:
Strain rate in Voigt notation.
- Return type:
sympy.Matrix
See also
strainrateFull tensor form.
- property strainrate_star_1d¶
Historical strain rate in Voigt notation (for viscoelastic models).
Used in viscoelastic formulations where the stress depends on both current and historical strain rates.
- Returns:
Historical strain rate in Voigt notation.
- Return type:
sympy.Matrix
See also
strainrate_1dCurrent strain rate.
- property stress_deviator¶
Deviatoric stress tensor from the constitutive model.
The deviatoric stress \(\boldsymbol{\tau}\) is the traceless part of the stress tensor, computed by the constitutive model from the strain rate:
\[\boldsymbol{\tau} = \boldsymbol{\eta} : \dot{\boldsymbol{\varepsilon}}\]For a Newtonian fluid: \(\boldsymbol{\tau} = 2\eta\dot{\boldsymbol{\varepsilon}}\)
- Returns:
Deviatoric stress tensor of shape
(dim, dim).- Return type:
sympy.Matrix
See also
stressTotal stress (deviatoric + pressure).
constitutive_modelProvides the viscosity relationship.
- property stress_deviator_1d¶
Deviatoric stress in Voigt notation.
- Returns:
Deviatoric stress in Voigt notation.
- Return type:
sympy.Matrix
See also
stress_deviatorFull tensor form.
- property stress¶
Total Cauchy stress tensor.
The total stress combines the deviatoric stress and pressure:
\[\boldsymbol{\sigma} = \boldsymbol{\tau} - p\mathbf{I}\]where \(\boldsymbol{\tau}\) is the deviatoric stress and \(p\) is the pressure (positive in compression).
- Returns:
Total stress tensor of shape
(dim, dim).- Return type:
sympy.Matrix
See also
stress_deviatorDeviatoric (traceless) part.
- property stress_1d¶
Total stress in Voigt notation.
- Returns:
Total stress in Voigt notation.
- Return type:
sympy.Matrix
See also
stressFull tensor form.
- property div_u¶
Velocity divergence.
For incompressible flow, this should be zero:
\[\nabla \cdot \mathbf{u} = 0\]- Returns:
Scalar divergence expression.
- Return type:
sympy.Expr
Notes
Non-zero divergence indicates compressibility or mass sources/sinks.
- property constraints¶
Constraint equation for the saddle-point system.
By default, this is the incompressibility constraint \(\nabla \cdot \mathbf{u} = 0\). Can be modified for compressible or other constrained formulations.
- Returns:
Constraint expression.
- Return type:
sympy.Expr
- property bodyforce¶
Body force vector (source term).
The volumetric body force \(\mathbf{f}\) appears on the right-hand side of the momentum equation:
\[-\nabla \cdot \boldsymbol{\sigma} = \mathbf{f}\]Common examples include gravity (\(\rho\mathbf{g}\)) or buoyancy forces.
- Returns:
Body force vector expression.
- Return type:
- property saddle_preconditioner¶
Preconditioner for the Schur complement in the saddle-point system.
For the Stokes system, the default preconditioner is \(1/\eta\) (inverse viscosity), which approximates the Schur complement \(\mathbf{S} \approx \mathbf{B}\mathbf{A}^{-1}\mathbf{B}^T\).
- Returns:
Preconditioner expression (typically inverse viscosity).
- Return type:
sympy.Expr
Notes
A good preconditioner significantly improves convergence of the iterative solver. For variable viscosity, use the local viscosity.
- property penalty¶
Augmented Lagrangian penalty parameter.
The penalty \(\lambda\) adds a term to the weak form that penalizes non-zero divergence:
\[\lambda \int (\nabla \cdot \mathbf{u})(\nabla \cdot \mathbf{v}) \, dV\]This improves convergence for incompressible flow without changing the solution (since \(\nabla \cdot \mathbf{u} = 0\) at convergence).
- Returns:
Augmented Lagrangian penalty parameter (typically \(O(1)\)).
- Return type:
Notes
Set to zero for standard Stokes without augmentation. Unlike classical penalty methods that require very large values, the Augmented Lagrangian approach uses modest penalties of \(O(1)\) to improve solver convergence.
References
Glowinski, R., & Le Tallec, P. (1989). Augmented Lagrangian and Operator-Splitting Methods in Nonlinear Mechanics. SIAM. https://doi.org/10.1137/1.9781611970838
- estimate_dt()[source]¶
Calculates an appropriate advective timestep for the Stokes solver.
The Stokes equations are quasi-static (no time derivative ∂v/∂t), so there is no diffusive CFL constraint. The only relevant timescale is the advective one: how long it takes material to cross an element.
This method computes a per-element timestep:
\[\delta t_i = h_i / \|\mathbf{v}_i\|\]where \(h_i\) is the element radius and \(\mathbf{v}_i\) is the velocity at the element centroid, then returns the global minimum. This is more accurate than using global max velocity with global min element size, especially for non-uniform meshes with spatially varying velocity.
- Returns:
Pint Quantity or float: The advective timestep with physical time units if a model with reference scales is available, otherwise nondimensional.
SNES_VE_Stokes¶
Viscoelastic extension of the Stokes solver.
- class underworld3.systems.solvers.SNES_VE_Stokes[source]¶
Bases:
SNES_StokesViscoelastic Stokes solver (backward-compatibility wrapper).
Deprecated since version Use:
uw.systems.Stokesdirectly with aViscoElasticPlasticFlowModelconstitutive model. The Stokes solver now creates stress history infrastructure automatically when the constitutive model is assigned (the lazy-creation pathway also readsstress_history_ddt_kwargsfrom the model — required forintegrator='etd'to allocateforcing_star). VE_Stokes pre-creates the DDt at solver__init__time, before the model exists, so it can’t see those kwargs and is incompatible withintegrator='etd'.Migration: replace:
stokes = uw.systems.VE_Stokes(mesh, velocityField=v, pressureField=p, order=2) stokes.constitutive_model = uw.constitutive_models.ViscoElasticPlasticFlowModel
with:
stokes = uw.systems.Stokes(mesh, velocityField=v, pressureField=p) stokes.constitutive_model = uw.constitutive_models.ViscoElasticPlasticFlowModel( stokes.Unknowns, order=2, )
- Parameters:
mesh (Mesh) – The computational mesh.
order (int, default=2) – BDF time integration order for stress history.
**kwargs – All other arguments are passed to
SNES_Stokes.
- instances = 0¶
- __init__(mesh, velocityField=None, pressureField=None, degree=2, order=2, p_continuous=True, verbose=False, DuDt=None, DFDt=None)[source]¶
- Parameters:
mesh (Mesh)
velocityField (EnhancedMeshVariable | None)
pressureField (EnhancedMeshVariable | None)
degree (int | None)
order (int | None)
p_continuous (bool | None)
verbose (bool | None)
DuDt (SemiLagrangian | Lagrangian)
DFDt (SemiLagrangian | Lagrangian)
- property delta_t¶
Elastic timestep from the constitutive model.
Scalar Equations¶
SNES_Poisson¶
- class underworld3.systems.solvers.SNES_Poisson[source]¶
Bases:
SNES_ScalarPoisson equation solver.
Provides a discrete representation of the Poisson equation:
\[\nabla \cdot \left[ \boldsymbol{\kappa} \nabla u \right] = f\]where \(\mathbf{F} = \boldsymbol{\kappa} \nabla u\) relates the flux to gradients in the unknown \(u\).
- Parameters:
mesh (Mesh) – The computational mesh.
u_Field (MeshVariable, optional) – Pre-existing mesh variable for the solution. If None, one is created.
verbose (bool, optional) – Enable verbose output during solve.
degree (int, optional) – Polynomial degree for the solution field (default: 2).
DuDt (SemiLagrangian_DDt or Lagrangian_DDt, optional) – Time derivative operator for time-dependent problems.
DFDt (SemiLagrangian_DDt or Lagrangian_DDt, optional) – Time derivative operator for the flux.
- __init__(mesh, u_Field=None, verbose=False, degree=2, DuDt=None, DFDt=None)[source]¶
- Parameters:
mesh (Mesh)
u_Field (EnhancedMeshVariable)
DuDt (SemiLagrangian | Lagrangian)
DFDt (SemiLagrangian | Lagrangian)
- F0¶
Source term for the Poisson equation (pointwise).
The \(f_0\) term represents the source/sink in the diffusion equation. Set via the
fproperty (e.g.,poisson.f = heat_source).
- F1¶
Diffusive flux term for the Poisson equation (pointwise).
The \(\mathbf{F}_1\) vector represents the flux \(k \nabla u\) from the constitutive model, where \(k\) is the diffusivity.
- property f¶
Source term for the Poisson equation.
The source term \(f\) appears on the right-hand side:
\[\nabla \cdot (\kappa \nabla u) = f\]- Returns:
Source term expression (scalar, shape
(1, 1)).- Return type:
sympy.Matrix
See also
constitutive_modelProvides the diffusivity \(\kappa\).
- property CM_is_setup¶
Whether the constitutive model is configured for this solver.
SNES_Darcy¶
- class underworld3.systems.solvers.SNES_Darcy[source]¶
Bases:
SNES_ScalarDarcy flow equation solver for groundwater problems.
Provides a discrete representation of the groundwater flow equations:
\[\underbrace{S_s \frac{\partial h}{\partial t}}_{\dot{u}} - \nabla \cdot \underbrace{\left[ \boldsymbol{\kappa} \nabla h - \boldsymbol{s} \right]}_{\mathbf{F}} = \underbrace{W}_{h}\]The flux term \(\mathbf{F}\) relates the effective velocity to pressure gradients:
\[\boldsymbol{v} = \boldsymbol{\kappa} \nabla h - \boldsymbol{s}\]- Parameters:
mesh (Mesh) – The computational mesh.
h_Field (MeshVariable, optional) – Mesh variable for hydraulic head. Created automatically if not provided.
v_Field (MeshVariable, optional) – Mesh variable for Darcy velocity. Created automatically if not provided.
degree (int, default=2) – Polynomial degree for the finite element discretization.
verbose (bool, default=False) – Enable verbose output.
DuDt (optional) – Time derivative operator for the unknown.
DFDt (optional) – Time derivative operator for the flux.
Notes
The unknown is \(h\), the hydraulic head
The permeability tensor \(\kappa\) is set via the
constitutive_modelproperty using one of theuw.constitutive_modelsclasses\(W\) is a pressure source term
\(S_s\) is the specific storage coefficient
The time-dependent term \(\dot{f}\) is not implemented in this version
The solver returns both the primary field and the Darcy flux (mean-flow velocity)
See also
SNES_PoissonRelated diffusion-only solver.
uw.constitutive_models.DarcyFlowModelConstitutive model for Darcy flow.
- F0¶
Source term for the Darcy pressure equation (pointwise).
The \(f_0\) term represents fluid sources/sinks. Set via the
fproperty.
- F1¶
Darcy flux term (pointwise).
The \(\mathbf{F}_1\) vector is the Darcy flux \(K \nabla p\), where \(K\) is the permeability.
- property f¶
Source term for the Darcy equation.
- property darcy_flux¶
Darcy flux velocity computed from pressure gradient.
- property v¶
Projected Darcy velocity field.
- solve(zero_init_guess=True, timestep=None, verbose=False, _force_setup=False, divergence_retries=0)[source]¶
Solve the Darcy flow system.
Computes the pressure field and Darcy flux velocity.
- Parameters:
zero_init_guess (bool, optional) – If True (default), start from zero initial guess. If False, use current field values as initial guess.
timestep (float, optional) – Timestep value for inertial terms (if applicable).
verbose (bool, optional) – If True, print solver progress information.
_force_setup (bool, optional) – Force re-setup of solver even if already configured.
divergence_retries (int, optional) – If SNES reports DIVERGED, retry with warm start up to this many times. 0 preserves legacy behaviour.
Notes
After solving, the pressure field
self.uand velocity fieldself.vcontain the solution.
SNES_AdvectionDiffusion¶
- class underworld3.systems.solvers.SNES_AdvectionDiffusion[source]¶
Bases:
SNES_ScalarAdvection-diffusion equation solver using semi-Lagrangian Crank-Nicolson.
Implements the characteristics-based method described in Spiegelman & Katz (2006):
\[\underbrace{\frac{\partial u}{\partial t} + \left( \mathbf{v} \cdot \nabla \right) u}_{\dot{u}} - \nabla \cdot \underbrace{\left[ \boldsymbol{\kappa} \nabla u \right]}_{\mathbf{F}} = \underbrace{f}_{\mathbf{h}}\]The flux term \(\mathbf{F}\) relates diffusive fluxes to gradients in \(u\). Advective fluxes along the velocity field \(\mathbf{v}\) are handled in the \(\dot{u}\) term.
The time derivative \(\dot{u}\) involves upstream sampling to find \(u^*\), the value of \(u\) at points which later arrive at mesh nodes. This is achieved using a hidden swarm variable advected backwards from nodal points automatically during solve.
- Parameters:
mesh (Mesh) – The computational mesh.
u_Field (MeshVariable) – Mesh variable for the transported scalar.
V_fn (MeshVariable or sympy.Basic) – Velocity field for advection.
order (int, default=1) – Time integration order (1 or 2).
restore_points_func (callable, optional) – Function to restore particles to valid domain.
verbose (bool, default=False) – Enable verbose output.
DuDt (SemiLagrangian_DDt or Lagrangian_DDt, optional) – Time derivative operator for the unknown.
DFDt (SemiLagrangian_DDt or Lagrangian_DDt, optional) – Time derivative operator for the flux.
monotone_mode (str or None, optional) –
Monotonicity limiter for the semi-Lagrangian trace-back. Forwarded to the internally-constructed
SemiLagrangian_DDtinstances forDuDtandDFDt.None(default): pure FE trace-back. Can overshoot at non-nodal upstream points in cells with sharp gradients (e.g. thin boundary layers in deformed cells); legacy behaviour."clamp": clip the FE trace-back result to[nbr_min, nbr_max]of thek = dim + 1nearestpsi_starDOFs. Bit-identical to pure FE in smooth regions; bounds overshoots where the FE interpolant would otherwise leave the local data range."pick": keep the FE result where in-bounds; for out-of-bounds DOFs only, re-evaluate via Shepard’s-method RBF. More conservative than clamp at the catastrophe edge.
When a user supplies a pre-built
DuDt, this kwarg is applied to the internally-constructedDFDtonly — the user’sDuDtalready encodes whatevermonotone_modeit was constructed with.theta (float, default=0.5) –
Adams-Moulton theta for the diffusive flux at order 1. Forwarded to the internally-constructed
SemiLagrangian_DDtinstances (same forwarding rule asmonotone_mode).0.5(default): Crank-Nicolson, A-stable but not L-stable. Second-order accurate. Rings on stiff modes with sharp gradients (negative amplification factor).1.0: Backward Euler, L-stable, monotone for the diffusive flux. First-order accurate. Recommended when SLCN+CN ringing dominates the discretisation error.0.0: Forward Euler — unstable for stiff diffusion; included for completeness.
Notes
The diffusivity \(\kappa\) is set via the
constitutive_modelpropertySources \(f\) can be any sympy expression involving mesh/swarm variables
References
Spiegelman, M., & Katz, R. F. (2006). A semi-Lagrangian Crank-Nicolson algorithm for the numerical solution of advection-diffusion problems. Geochemistry, Geophysics, Geosystems, 7(4). https://doi.org/10.1029/2005GC001073
See also
SNES_DiffusionPure diffusion solver without advection.
SNES_Navier_StokesFull momentum advection-diffusion.
- __init__(mesh, u_Field, V_fn, order=1, restore_points_func=None, verbose=False, DuDt=None, DFDt=None, monotone_mode=None, theta=0.5)[source]¶
- Parameters:
mesh (Mesh)
u_Field (EnhancedMeshVariable)
V_fn (EnhancedMeshVariable | Basic)
order (int)
restore_points_func (Callable)
DuDt (SemiLagrangian | Lagrangian)
DFDt (SemiLagrangian | Lagrangian)
monotone_mode (str | None)
theta (float)
- property F0¶
Pointwise source term including time derivative.
- property F1¶
Pointwise diffusive flux term (Adams-Moulton integration).
- adv_diff_slcn_problem_description()[source]¶
Build residual terms for advection-diffusion FEM assembly.
- property f¶
Source term for the advection-diffusion equation.
The source \(f\) appears on the right-hand side:
\[\frac{\partial u}{\partial t} + \mathbf{V} \cdot \nabla u = \nabla \cdot (\kappa \nabla u) + f\]- Returns:
Source term expression.
- Return type:
sympy.Matrix
- property V_fn¶
Velocity field for advection.
The advection velocity \(\mathbf{V}\) transports the scalar field \(u\). Can be a MeshVariable or symbolic expression.
- Returns:
Velocity vector expression.
- Return type:
sympy.Matrix
- property delta_t¶
Timestep for time integration.
The timestep \(\Delta t\) controls the temporal discretization. For explicit advection, this should satisfy the CFL condition:
\[\Delta t < \frac{h}{|\mathbf{V}|}\]where \(h\) is the element size and \(|\mathbf{V}|\) is the velocity magnitude.
- Returns:
Timestep value.
- Return type:
See also
estimate_dtComputes a stable timestep automatically.
- estimate_dt(direction_aware=False)[source]¶
Estimate an appropriate timestep for the advection-diffusion solver.
This is an implicit solver so the returned \(\delta t\) is the minimum of:
\(\delta t_{\textrm{diff}}\): typical time for diffusion across an element
\(\delta t_{\textrm{adv}}\): typical element-crossing time for a fluid parcel
- Parameters:
direction_aware (bool, default False) – If True, the advective dt uses the per-cell extent along the local velocity direction — h_eff_c = max_i(s_i) - min_i(s_i) where s_i = (x_i - centroid) · v̂ over the cell vertices. This is the distance material actually traverses through the cell per unit |v|, and is always ≥ the isotropic mesh._radii estimate, by 1.5–3× for equant cells (geometric factor) and up to ~10× for cells that the mover has stretched along the flow direction. On adapted meshes the gain is substantial; on uniform meshes it’s the geometric factor only. Off by default to preserve historical behaviour; safe to enable everywhere once validated.
- Returns:
The recommended timestep with physical time units if a model with reference scales is available, otherwise nondimensional.
- Return type:
pint.Quantity or float
- solve(zero_init_guess=True, timestep=None, _force_setup=False, _evalf=False, verbose=False, divergence_retries=0)[source]¶
Generates solution to constructed system.
Params¶
- zero_init_guess:
If True, a zero initial guess will be used for the system solution. Otherwise, the current values of self.u will be used.
- divergence_retries:
If SNES reports DIVERGED, retry with warm start up to this many times. 0 preserves legacy behaviour.
SNES_Diffusion¶
- class underworld3.systems.solvers.SNES_Diffusion[source]¶
Bases:
SNES_ScalarDiffusion equation solver using mesh-based finite elements.
Solves the scalar diffusion equation:
\[\underbrace{\frac{\partial u}{\partial t}}_{\dot{f}} - \nabla \cdot \underbrace{\left[ \boldsymbol{\kappa} \nabla u \right]}_{\mathbf{F}} = \underbrace{f}_{h}\]The flux term \(\mathbf{F}\) relates diffusive fluxes to gradients in the unknown \(u\).
- Parameters:
mesh (Mesh) – The computational mesh.
u_Field (MeshVariable) – Mesh variable for the diffusing scalar.
order (int, default=1) – Time integration order.
theta (float, default=0.0) – Time integration parameter (0=explicit, 0.5=Crank-Nicolson, 1=implicit).
evalf (bool, default=False) – Numerically evaluate symbolic expressions during setup.
verbose (bool, default=False) – Enable verbose output.
DuDt (Eulerian_DDt, SemiLagrangian_DDt, or Lagrangian_DDt, optional) – Time derivative operator for the unknown.
DFDt (Eulerian_DDt, SemiLagrangian_DDt, or Lagrangian_DDt, optional) – Time derivative operator for the flux.
Notes
The diffusivity \(\kappa\) is set via the
constitutive_modelpropertySources \(f\) can be any sympy expression involving mesh/swarm variables
See also
SNES_AdvectionDiffusionAdds advection transport.
SNES_PoissonSteady-state diffusion (no time derivative).
- __init__(mesh, u_Field, order=1, theta=0.0, evalf=False, verbose=False, DuDt=None, DFDt=None)[source]¶
- Parameters:
mesh (Mesh)
u_Field (EnhancedMeshVariable)
order (int)
theta (float)
evalf (bool | None)
DuDt (Eulerian | SemiLagrangian | Lagrangian)
DFDt (Eulerian | SemiLagrangian | Lagrangian)
- property F0¶
Pointwise source term including time derivative.
- property F1¶
Pointwise diffusive flux term.
- property f¶
Source term for the diffusion equation.
- property delta_t¶
Timestep for time integration.
- estimate_dt()[source]¶
Estimate an appropriate timestep for the diffusion solver.
This solver only has a diffusive component, so the returned \(\delta t\) is:
\(\delta t_{\textrm{diff}}\): typical time for diffusion across an element
- Returns:
The diffusive timestep with physical time units if a model with reference scales is available, otherwise nondimensional.
- Return type:
pint.Quantity or float
- solve(zero_init_guess=True, timestep=None, evalf=False, _force_setup=False, verbose=False, divergence_retries=0)[source]¶
Generates solution to constructed system.
Params¶
- zero_init_guess:
If True, a zero initial guess will be used for the system solution. Otherwise, the current values of self.u will be used.
- divergence_retries:
If SNES reports DIVERGED, retry with warm start up to this many times. 0 preserves legacy behaviour.
Projection Solvers¶
SNES_Projection¶
- class underworld3.systems.solvers.SNES_Projection[source]¶
Bases:
SNES_ScalarScalar projection solver for mapping functions to mesh variables.
Solves \(u = \tilde{f}\) where \(\tilde{f}\) is a function that can be evaluated within an element and \(u\) is a mesh variable with associated shape functions.
Typically used to obtain a continuous representation of a function not well-defined at mesh nodes (e.g., derivatives or flux components). More broadly, it is a projection from one basis to another.
Strong form (the screened-Poisson smoother)¶
The projection is implemented by solving
\[u - \nabla \cdot \left( \alpha \nabla u \right) = \tilde{f},\]or equivalently, in the more familiar Helmholtz form
\[u - \alpha \, \nabla^{2} u \;=\; \tilde{f}.\]With \(\alpha = 0\) this is a pure pointwise L2 projection of \(\tilde f\) onto the discrete space of \(u\). With \(\alpha > 0\) it is a screened-Poisson smoother: the equation enforces a balance between fidelity to \(\tilde f\) and curvature of \(u\). The natural length scale that emerges from this balance is
\[L \;=\; \sqrt{\alpha},\]so \(\alpha\) has dimensions of length squared. The free-space Green’s function of the operator decays as \(\exp(-r/L)\) (in 2D it is \(G(r) \propto K_{0}(r/L)/L^{2}\)), so the solution behaves like a Gaussian-like convolution of \(\tilde f\) of width \(L\) — obtained implicitly by one elliptic solve, without ever assembling the kernel. Features in \(\tilde f\) of scale much smaller than \(L\) are attenuated; features much larger than \(L\) pass through essentially unchanged.
Weak form¶
Multiplying by a test function \(v\) and integrating by parts gives the symmetric weak form actually assembled by PETSc:
\[\int_\Omega (u - \tilde f)\, v \; + \; \int_\Omega \alpha \, \nabla u \cdot \nabla v \;=\; 0,\]which is exactly minimising \(\tfrac{1}{2}\!\int (u-\tilde f)^2 + \tfrac{\alpha}{2}\!\int |\nabla u|^2\) — a Tikhonov-regularised L2 projection.
Setting the smoothing length¶
Two equivalent accessors are provided:
smoothing— set the coefficient \(\alpha\) directly (units of length²). Historically used with tiny values (e.g. \(10^{-6}\)) as a numerical regulariser, which corresponds to a sub-grid \(L\) and produces no physical smoothing.smoothing_length— set \(L\) directly (length units, unit-aware viaunderworld3.non_dimensionalise()). This is the recommended path when you actually want the projection to act as a low-pass filter of a chosen physical scale.
See also
SNES_Vector_ProjectionVector field projection.
SNES_Tensor_ProjectionTensor field projection.
- param mesh:
The computational mesh.
- type mesh:
Mesh
- param u_Field:
Target mesh variable for the projection.
- type u_Field:
MeshVariable, optional
- param scalar_Field:
Alternative name for the target field.
- type scalar_Field:
MeshVariable, optional
- param degree:
Polynomial degree for the finite element space.
- type degree:
int, default=2
- param solver_name:
Name for the solver instance.
- type solver_name:
str, optional
- param verbose:
Enable verbose output.
- type verbose:
bool, default=False
- __init__(mesh, u_Field=None, degree=2, verbose=False)[source]¶
- Parameters:
mesh (Mesh)
u_Field (EnhancedMeshVariable)
- F0¶
Projection misfit term (pointwise).
The \(f_0\) term measures the weighted difference between the mesh variable and the target function for L2 projection.
- F1¶
Projection smoothing term (pointwise).
The \(\mathbf{F}_1\) term provides optional regularization via \(\alpha \nabla u\), where \(\alpha\) is the
smoothingparameter.
- uw_function¶
Function to project onto mesh
- property smoothing¶
Smoothing coefficient \(\alpha\) of the screened-Poisson form.
The projection solves \(u - \nabla\!\cdot\!(\alpha\,\nabla u) = \tilde f\), so \(\alpha\) has dimensions of length² and the implied smoothing length is \(L = \sqrt{\alpha}\). The free-space Green’s function decays as \(\exp(-r/L)\), giving the projection the action of a Gaussian-like convolution of width \(L\) — without ever forming the kernel.
See the class docstring for the full derivation.
Two usage patterns¶
Pure L2 projection —
smoothing = 0(or omit). No regularisation;uis the best L2 fit toũ.Genuine length-scale smoother — set
smoothing_lengthto the desired physical length (unit-aware), or equivalentlysmoothing = L**2. The output isũsmoothed at scaleL.
Note
Historical UW3 code occasionally sets
smoothingto a tiny number (e.g.1e-6) as a numerical regulariser against rank deficiency. That value corresponds to \(L \approx 10^{-3}\) in the problem’s ND length units — almost always well below the cell size, so it does no useful smoothing. Use a true sub-grid value only if you need that regularisation; for filtering, usesmoothing_length.
- property smoothing_length¶
Smoothing length scale \(L\) (length units, unit-aware).
L-valued view on
smoothingwith the convention \(L = \sqrt{\alpha}\). Settingsmoothing_length = Lis equivalent to settingsmoothing = L**2, but is the natural physical knob because \(L\) is what the smoother actually filters by.Mathematical meaning¶
The projection then solves the screened-Poisson equation
\[u \;-\; L^{2}\,\nabla^{2} u \;=\; \tilde f,\]whose Green’s function decays as \(\exp(-r/L)\). In practice this acts like a Gaussian convolution of width \(L\):
features in \(\tilde f\) with spatial scale \(\ll L\) are damped (roughly as \(1/(1+k^{2}L^{2})\) for a wavenumber \(k\));
features with scale \(\gg L\) are preserved;
features at \(\sim L\) are attenuated by a factor near
1/2.
Choosing \(L\) smaller than the local mesh size has essentially no effect (the field is already band-limited by the discretisation). A useful default for light de-noising is \(L \approx 1\!-\!2\,h\), where \(h\) is a representative cell size.
Units¶
The setter accepts a plain number (assumed already non-dimensional), a pint
Quantitywith length units, or any unit-aware object understood byunderworld3.non_dimensionalise(). Internally the squared non-dimensional value is stored inself._smoothing(sosmoothingandsmoothing_lengthstay consistent).The getter returns a Pint
Quantitywith length units when a scaling context is configured; otherwise the plain non-dimensional float \(\sqrt{\alpha}\).
- property uw_weighting_function¶
Weighting function applied during projection.
SNES_Vector_Projection¶
- class underworld3.systems.solvers.SNES_Vector_Projection[source]¶
Bases:
SNES_VectorVector projection solver for mapping vector functions to mesh variables.
Solves \(\mathbf{u} = \tilde{\mathbf{f}}\) where \(\tilde{\mathbf{f}}\) is a vector function that can be evaluated within an element and \(\mathbf{u}\) is a vector mesh variable with associated shape functions.
Typically used to obtain a continuous representation of a vector function not well-defined at mesh nodes (e.g., gradient or flux vectors), or as a length-scale-aware smoother of an existing vector field.
Strong form (screened-Poisson, vector-valued)¶
\[\mathbf{u} \;-\; \nabla \cdot \left( \alpha\, \nabla \mathbf{u} \right) \;+\; \lambda \left( \nabla \cdot \mathbf{u} \right) \mathbf{I} \;=\; \tilde{\mathbf{f}} .\]The \(\alpha\)-term is the same screened-Poisson smoother as in
SNES_Projection, applied component-wise: it has the same \(L = \sqrt{\alpha}\) smoothing-length interpretation and the same \(\exp(-r/L)\) Green’s function. The extra \(\lambda\) term is a divergence penalty (seepenalty) — set it nonzero when you want an approximately solenoidal projection of \(\tilde{\mathbf{f}}\).Setting \(\alpha = 0\) (and \(\lambda = 0\)) gives a pure pointwise L2 projection. See
SNES_Projectionfor the full mathematical context; the relationship betweensmoothing(units length²) andsmoothing_length(units length) is the same as for the scalar projection.- param mesh:
The computational mesh.
- type mesh:
Mesh
- param u_Field:
Target vector mesh variable for the projection.
- type u_Field:
MeshVariable, optional
- param degree:
Polynomial degree for the finite element space.
- type degree:
int, default=2
- param verbose:
Enable verbose output.
- type verbose:
bool, default=False
See also
SNES_ProjectionScalar field projection (full mathematical detail).
SNES_Tensor_ProjectionTensor field projection.
- __init__(mesh, u_Field=None, degree=2, verbose=False)[source]¶
- Parameters:
mesh (Mesh)
u_Field (EnhancedMeshVariable)
- F0¶
f_0(u)
- Type:
Vector projection pointwise misfit term
- F1¶
F_1(u)
- Type:
Vector projection pointwise smoothing term
- uw_function¶
Vector function to project onto mesh
- property smoothing¶
Smoothing coefficient \(\alpha\) (units length²).
Coefficient of the \(\nabla\!\cdot\!(\alpha\,\nabla \mathbf u)\) term in the vector screened-Poisson equation (see the class docstring). Acts component-wise; the smoothing length is \(L = \sqrt{\alpha}\) and the Green’s function decays as \(\exp(-r/L)\).
Use
smoothing_lengthfor the L-valued, unit-aware knob. SeeSNES_Projection.smoothingfor the full derivation and usage patterns.
- property smoothing_length¶
Smoothing length \(L\) (length units, unit-aware).
L-valued view on
smoothing, with \(L = \sqrt{\alpha}\). The projection then acts as a component-wise screened-Poisson smoother \(\mathbf u - L^{2}\,\nabla^{2}\mathbf u = \tilde{\mathbf f}\), i.e. a Gaussian-like convolution of width \(L\) applied to each Cartesian component of the input vector field.Choose \(L \gtrsim h\) (a cell size) for noticeable smoothing; \(L < h\) does essentially nothing because the discretisation already band-limits at that scale. See
SNES_Projection.smoothing_lengthfor the full mathematical and units discussion.
- property penalty¶
Divergence penalty \(\lambda\) for (approx.) incompressibility.
Coefficient of the \(\lambda (\nabla\!\cdot\!\mathbf u) \mathbf I\) term in the vector projection. Large positive values bias the projection toward \(\nabla\!\cdot\!\mathbf u = 0\), i.e. a solenoidal approximation of \(\tilde{\mathbf f}\). Has no length interpretation — unlike
smoothingit does not introduce a filter scale.
- property uw_weighting_function¶
Weighting function applied during projection.