Problem interface¶
spec.build() turns a recipe into a LoweredProblem, which ds.pdesolve
and the inference verbs take. The problem interface
overview builds one problem
three ways.
Building¶
to_equation_set() freezes a recipe into an EquationSet and lower
compiles it.
diff_soup.problem.lower
¶
lower(eqset: Any, *, layout: Optional[Layout] = None, precision: Optional[Precision] = None, **options: Any) -> Any
Compile an EquationSet into a problem, or a Study into a lowered study.
Equation sets equal in structure, values, layout and precision share one lowered problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
eqset
|
Any
|
An |
required |
layout
|
Optional[Layout]
|
Device placement, a |
None
|
precision
|
Optional[Precision]
|
|
None
|
**options
|
Any
|
Keywords for a study, such as |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
A |
Raises:
| Type | Description |
|---|---|
LoweringError
|
If |
TypeError
|
If |
diff_soup.problem.EquationSet
¶
Frozen description of a problem, its components, globals, constraints, observations, controls, couplings and families.
spec.to_equation_set() builds one, and lower
compiles it. a | b concatenates two sets, and with_(...) returns a copy
with nodes added, removed or replaced.
Attributes:
| Name | Type | Description |
|---|---|---|
components |
tuple[Component, ...]
|
Components, each a domain with its fields, equations and boundary conditions, at least one. |
globals |
tuple[GlobalVariable, ...]
|
Global unknowns. |
constraints |
tuple[Constraint, ...]
|
Constraint records that close the globals. |
observations |
tuple[Observation, ...]
|
Declared observations. |
controls |
tuple[Control, ...]
|
Declared controls. |
couplings |
tuple
|
Couplings that move values between components. |
families |
tuple
|
Families of identical members. |
scales |
Scales
|
|
residual_scale |
Mapping
|
Divisor of each field's residual rows, keyed by |
quad_fields |
'frozenset[str]'
|
Names of the fields that |
diff_soup.problem.LoweredProblem
¶
Solve-ready problem compiled from a recipe or an equation set.
spec.build() and lower return one, and
pdesolve and the inference verbs take it.
It is a pytree whose floating-point leaves are the declared values.
Attributes:
| Name | Type | Description |
|---|---|---|
layout |
Layout
|
|
precision |
Precision
|
|
quad_fields |
'frozenset[str]'
|
Names of the fields that |
observables
property
¶
observables: tuple[Observable, ...]
One record per declared observation, with its name, kind, shape, dtype, owner and reads.
layout
class-attribute
instance-attribute
¶
layout: Layout = eqx.field(static=True, default_factory=Layout)
precision
class-attribute
instance-attribute
¶
precision: Precision = eqx.field(static=True, default_factory=Precision)
observe
¶
observe(u: Array, t: Array, lam_internal: Optional[Array] = None, *, names: Optional[Sequence[str]] = None) -> dict[str, Any]
Evaluate the declared observations at an internal state and time, in dimensional units.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
u
|
Array
|
State vector in internal units. |
required |
t
|
Array
|
Internal time. |
required |
lam_internal
|
Optional[Array]
|
Global unknowns in internal units, or |
None
|
names
|
Optional[Sequence[str]]
|
Observation names to evaluate, or |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Mapping from observation name to its value, empty when nothing is declared. |
controls
¶
controls(t: Array) -> dict[str, Any]
Evaluate every declared control at an internal time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
t
|
Array
|
Internal time, multiplied by the time scale before each control function is called. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Mapping from control name to its dimensional value, empty when no control is declared. |
default_theta
¶
default_theta()
Return the pytree a solve takes as theta, holding every floating-point array of the problem.
That is the declared parameters and functions, the mass diagonal, the
initial multipliers and the family member parameters. theta[D] reads
a declared parameter and theta.replace(D, value) sets it.
assemble_state
¶
assemble_state(values: dict[str, Any], *, default: float = 0.0) -> jax.Array
Assemble the flat initial state from per-field values.
Fields missing from values take default, not their declared init, and a
callable value raises TypeError. ProblemSpec.assemble_state evaluates
declared initial conditions and coordinate callables.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
dict[str, Any]
|
Mapping from field name to a scalar or an array of the field's shape, with family fields keyed |
required |
default
|
float
|
Value of every field left out. |
0.0
|
Returns:
| Type | Description |
|---|---|
Array
|
The state vector, component fields in layout order, then family members. |
initial_u
¶
initial_u(y0: Array) -> jax.Array
Convert a dimensional state to internal units, (y0 - offset) / scale per field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y0
|
Array
|
Full state vector in dimensional units. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
The state vector in internal units. |
state_size
¶
state_size() -> int
Return the length of the state vector, which excludes the global unknowns.
global_layout
¶
global_layout() -> tuple[dict, ...]
Describe where each global unknown sits in the global block.
Returns:
| Type | Description |
|---|---|
tuple[dict, ...]
|
One dict per global with its |
Problem types¶
diff_soup.problem.MassProblem
¶
Mass-matrix problem M(t, y) @ ydot = f(t, y), one of the two problem types the solvers integrate.
The sizes of mass, rhs_sparsity and structure must agree. An algebraic
variable's column of the mass must be empty.
Attributes:
| Name | Type | Description |
|---|---|---|
rhs |
Callable
|
Function |
mass |
MassOperator
|
|
structure |
DAEStructure
|
|
rhs_sparsity |
Union[SparseTopology, str]
|
|
linearization |
Optional[ResidualLinearization]
|
Optional |
precision |
Precision
|
|
diff_soup.problem.ImplicitProblem
¶
Fully implicit problem F(t, y, ydot) = 0, one of the two problem types the solvers integrate.
Use it when the residual is nonlinear in ydot. An algebraic variable's
column of the declared dF/dydot support must be empty.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
residual
|
Callable
|
Function |
required |
structure
|
DAEStructure
|
|
required |
linearization
|
ResidualLinearization
|
|
required |
precision
|
Optional[Precision]
|
|
None
|
diff_soup.problem.DAEStructure
¶
Which unknowns of a problem are differential and which are algebraic, plus named index ranges.
Properties differential_indices, algebraic_indices and n_differential
read the mask, and partition(name) returns a range by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
differential_vars
|
Nonempty 1-D boolean mask, true for each differential unknown. |
required | |
partitions
|
tuple
|
Triples |
()
|
diff_soup.problem.ResidualSparsity
¶
Supports of the two residual Jacobians, dF/dy and dF/dydot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dy
|
|
required | |
dydot
|
|
required |
diff_soup.problem.ResidualLinearization
¶
Jacobian supports of a residual, with optional callbacks for their values.
A callback left None is replaced by automatic differentiation over the
declared support.
Attributes:
| Name | Type | Description |
|---|---|---|
sparsity |
ResidualSparsity
|
|
dy_values |
Optional[Callable]
|
Function |
dydot_values |
Optional[Callable]
|
Function |
combined_values |
Optional[Callable]
|
Function |
max_fy_reuse_steps |
Optional[int]
|
Most steps a solver may reuse one |
diff_soup.problem.Dependencies
¶
Which solve-time inputs a set of coefficients varies with.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time
|
bool
|
Whether the coefficients depend on |
required |
state
|
bool
|
Whether they depend on the state |
required |
parameters
|
bool
|
Whether they depend on |
required |
control
|
bool
|
Whether they depend on the control values. |
required |
Structure diagnostics¶
diff_soup.problem.topology_report
¶
topology_report(problem, *, top_k: int = 5) -> TopologyReport
Summarize the Jacobian sparsity pattern a problem presents to the solvers.
A problem without a sparse pattern reports a dense one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
A |
required | |
top_k
|
int
|
Number of widest rows to report. |
5
|
Returns:
| Type | Description |
|---|---|
TopologyReport
|
diff_soup.problem.TopologyReport
¶
Summary of a problem's Jacobian sparsity pattern, returned by topology_report.
Attributes:
| Name | Type | Description |
|---|---|---|
n |
int
|
Number of unknowns. |
nnz |
int
|
Number of structural nonzeros. |
max_row_degree |
int
|
Largest number of nonzeros in one row. |
mean_row_degree |
float
|
Mean number of nonzeros per row. |
color_count |
Optional[int]
|
Colors needed to compute the Jacobian by automatic differentiation, or |
widest_rows |
tuple
|
|
per_variable_nnz |
dict
|
Nonzeros per field or global name, empty when the rows carry no names. |
diff_soup.problem.RowOwner
¶
One row of a Jacobian pattern, with its nonzero count and owning variable.
Attributes:
| Name | Type | Description |
|---|---|---|
row |
int
|
Row index. |
degree |
int
|
Number of nonzeros in the row. |
variable |
Optional[str]
|
Name of the field or global the row belongs to, or |
Families and couplings
These matter only when you build an EquationSet by hand or write a
custom transfer.
diff_soup.problem.Family
¶
Record of a population of count identical members on one member domain.
spec.family(...) builds one. Names within a family must be unique, and
every graph must have the family's member count.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Family name, non-empty. |
required |
count
|
int
|
Number of members. |
required |
domain
|
Member domain shared by every member. |
required | |
member_variables
|
tuple
|
Member field variables. |
()
|
member_equations
|
tuple
|
Member equations. |
()
|
member_bcs
|
tuple
|
Member flux boundary conditions. |
()
|
member_couplings
|
tuple
|
Couplings owned by the family, left empty by the Recipe API. |
()
|
scale
|
State scale of each member field, keyed by field name. |
None
|
|
residual_scale
|
Residual divisor of each member field, keyed by field name. |
None
|
|
operator_factory
|
object
|
Operator-bank class or top-level named function of the domain, or |
None
|
member_params
|
Mapping[str, 'jax.Array'] | None
|
Per-member parameter arrays, keyed by name. |
None
|
graphs
|
tuple
|
|
()
|
graph_exchanges
|
tuple
|
|
()
|
stencil_radius
|
int | None
|
Jacobian reach of a member kernel in cells per axis, or |
None
|
diff_soup.problem.FamilyGraph
¶
Edge list connecting members of one family, with a weight per edge.
family.graph(...) builds one. Undirected edges are stored with the lower
member index first, and self-loops and duplicate edges raise ValueError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Graph name, unique within the family. |
required |
member_count
|
int
|
Number of members, the family's |
required |
edges
|
Any
|
Integer array of shape |
required |
directed
|
bool
|
Whether each edge has a direction, given explicitly. |
required |
weights
|
Any
|
A float scalar, a float array of length |
required |
diff_soup.problem.FamilyGraphExchange
¶
Pairwise exchange term along the edges of a family graph.
family.graph_exchange(...) builds one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Exchange name, unique within the family. |
required |
graph
|
str
|
Name of the |
required |
writes
|
str
|
Member field whose rows receive the exchange. |
required |
reads
|
tuple[str, ...]
|
Member fields |
required |
weight_reads
|
tuple[str, ...]
|
Member fields a weight function reads. |
required |
fn
|
Any
|
Callable |
required |
diff_soup.problem.TransferOp
¶
Base class of the operators that move a field's values into another component.
Pass one as spec.couple(..., via=op). A subclass implements apply and
sparsity, and overrides alias_size(n_source=..., n_target=...) when the
coupled value is not the size of the target component.
apply
¶
apply(source: Array, target_size: int) -> Array
Map a source vector to a target vector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Array
|
Values of the coupled field. |
required |
target_size
|
int
|
Length of the returned vector. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
The transferred values, of length |
sparsity
¶
sparsity(source_size: int, target_size: int) -> tuple[np.ndarray, np.ndarray]
Return the nonzero pattern of the Jacobian d(target)/d(source).
A dense transfer lists every pair of target row and source column.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_size
|
int
|
Length of the source vector. |
required |
target_size
|
int
|
Length of the target vector. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ndarray]
|
Integer arrays |
diff_soup.problem.NodalExtractOp
¶
Transfer that reads entry i of the coupled value from source row source_indices[i].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_indices
|
Source rows, one per entry of the coupled value. |
required |
diff_soup.problem.NodalInjectOp
¶
Transfer that writes source entry k into target row target_indices[k] and zero elsewhere.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target_indices
|
Target rows, one per source entry. |
required |
diff_soup.problem.VarRef
dataclass
¶
Address of a variable by its owner's name and its own.
Attributes:
| Name | Type | Description |
|---|---|---|
component_name |
str
|
Name of the component or family that owns the variable. |
variable_name |
str
|
Name of the variable. |
family |
bool
|
Whether the owner is a family. |
diff_soup.problem.Scales
dataclass
¶
Scales of an equation set, relating internal values to dimensional ones.
A dimensional value is offset + scale * internal. spec.build() fills one
from the inline and central scales of a recipe.
Attributes:
| Name | Type | Description |
|---|---|---|
state_ref |
Mapping[tuple[str, str], float]
|
State scale per |
state_offset |
Mapping[tuple[str, str], float]
|
State offset per |
time_ref |
float
|
Time scale, finite and nonzero. |
integrand_ref |
Mapping[str, float]
|
Target divisor per constraint name, finite and nonzero. |