neml2.pyzag#
Adapter exposing a NEML2 nonlinear system to the pyzag time-integration library.
NEML2PyzagModel wraps a NEML2 ModelNonlinearSystem as a
pyzag.nonlinear.NonlinearFunctionOperatorFactory – assembling the per-chunk
residual and bidiagonal Jacobian from NEML2’s equation-systems layer and mirroring
the model’s HIT parameters as torch.nn.Parameter s for gradient-based
calibration. The backing block-operator implementations live in
neml2.pyzag.operators.
- class neml2.pyzag.NEML2BlockJacobian(diag_am, sub_am, layout, _reversed=False)[source]#
Bases:
BlockJacobianPer-chunk bidiagonal Jacobian wrapping neml2
AssembledMatrixdiag/sub.- Parameters:
diag_am (AssembledMatrix)
sub_am (AssembledMatrix)
_reversed (bool)
- adjoint_system(inverse_operator)[source]#
Build the transposed, time-reversed bidiagonal operator for the adjoint sweep.
Uses the transposed diagonal/subdiagonal blocks in reverse time order. Must be called on the Jacobian returned by
as_adjoint_walk().
- as_adjoint_walk()[source]#
Return a view of this Jacobian marked for the reverse-time adjoint walk.
- Return type:
- couple_prev_chunk(a_first)[source]#
Propagate the adjoint across the chunk boundary via the subdiagonal coupling.
Applies the transpose of this chunk’s boundary subdiagonal block to the first adjoint variable
a_first, giving the contribution into the previous chunk’s terminal adjoint.- Parameters:
a_first (BlockVector)
- Return type:
- forward_system(inverse_operator)[source]#
Build the forward bidiagonal chunk operator solved during the state sweep.
inverse_operatoris the factorization pyzag requests. Must be called on a forward-walk Jacobian, not one fromas_adjoint_walk().
- class neml2.pyzag.NEML2BlockVector(raw_tensors, layout, intmd_dims=None)[source]#
Bases:
BlockVectorBlock vector held as per-group torch tensors with neml2 layout metadata.
Per-group torch tensors plus explicit
intmd_dimsmirror the dense backend pattern and let__setitem__/clonework in place. A neml2AssembledVectoris materialized only at the neml2 boundary (viato_av()), where the linear solvers and matmul consume it.- Parameters:
raw_tensors (list[torch.Tensor])
layout (AxisLayout)
- property block_size: int#
Total per-block degrees of freedom summed across all groups (incl. intmd dims).
- classmethod cat(vectors, dim=0)[source]#
Concatenate matching-layout block vectors group-by-group along
dim.- Parameters:
- Return type:
- flatten()[source]#
Concatenate all groups into one
(batch, nblk * dofs)tensor.Each group is transposed to put the batch axis first, then flattened and concatenated along the feature axis – the flat form pyzag’s PCR path expects.
- Return type:
- flip(dim)[source]#
Reverse every group along
dim(used to walk time backward in the adjoint).- Parameters:
dim (int)
- Return type:
- classmethod from_av(av)[source]#
Construct from a neml2
AssembledVector.- Parameters:
av (AssembledVector)
- Return type:
- scale_batches(factor)[source]#
Scale each plain-batch entry by the matching entry of
factor.- Parameters:
factor (Tensor)
- Return type:
- where(mask, other)[source]#
Batchwise select: keep
selfwheremaskis true, elseother.- Parameters:
mask (Tensor)
other (BlockVector)
- Return type:
- class neml2.pyzag.NEML2PyzagModel(sys, *args, exclude_parameters=None, include_parameters=None, **kwargs)[source]#
Bases:
Module,NonlinearFunctionOperatorFactoryAdapt a NEML2
ModelNonlinearSystemto pyzag’s time-integration library.Implements pyzag’s
NonlinearFunctionOperatorFactoryABC. The public name staysNEML2PyzagModelfor user-facing continuity even though the base protocol is now the factory (pyzag 2.0) rather than the oldNonlinearRecursiveFunction.- Parameters:
sys (ModelNonlinearSystem) – the native NEML2 nonlinear system to wrap.
- Keyword Arguments:
Construction yields a
py-eagermodel. To accelerate the residual with in-processtorch.compile(py-jit), opt in explicitly after construction withneml2.compile()– e.g.neml2.compile(model).- assemble_forces(forces_dict, dynamic_dim=2)[source]#
Build a flat forces tensor from a per-variable forces dict.
Derived fresh from the pristine force baselines (see
assemble_state()); idempotent and order-independent.
- assemble_state(ic_dict, dynamic_dim=1)[source]#
Build a flat initial-state tensor from a per-variable IC dict.
The runtime state / old-state / residual layouts are derived fresh from the pristine baselines captured in
_setup_maps(), so this is idempotent and independent of priorassemble_state()/assemble_forces()calls.
- evaluate_raw(x_full, forces)[source]#
Return
(r, NEML2BlockJacobian)for one chunk’s state and forces.pyzag passes the driving forces as a list (one tensor per
*forcesargument topyzag.nonlinear.solve(), each chunk-sliced). They are concatenated along the feature axis into the single flat forces tensor the system consumes, in the order given – which must match the force (given-variable) layout, exactly asassemble_forces()produces it.
- make_operator(prev_solution, forces, inverse_operator)[source]#
Build the pyzag chunk operator for one solve window.
- Parameters:
- Returns:
A
pyzag.nonlinear.ChunkOpbound to this factory.- Return type:
ChunkOp
- property wrapper#
The
NEML2Wrapperfor the current state layout.
- class neml2.pyzag.NEML2SolvableBlockOperator(am)[source]#
Bases:
SolvableBlockOperatorBlock operator backed by a neml2
AssembledMatrix.- Parameters:
am (AssembledMatrix)
- classmethod factored(am)[source]#
Construct the operator and eagerly cache its factorization.
For a single-group diagonal this factors all block-axis entries at once (one batched
lu_factor); the cache is carried through__getitem__()so a Thomas sweep reuses it per block vialu_solveinstead of re-factoring. Multi-group (Schur) diagonals are not cached here – they delegate toSchurComplementper solve.- Parameters:
am (AssembledMatrix)
- Return type:
- matvec(x)[source]#
Grain-diagonal matrix-vector product
self @ x.Delegates to
per_instance_matvec()(a BLOCK output stays per-site; only a DENSE output consuming a BLOCK input aggregates the site axis). Raw tensors appear only at the finalNEML2BlockVectorhand-off.- Parameters:
x (BlockVector)
- Return type:
- pad_front(n=1)[source]#
Return a copy with
nzero blocks prepended along the dynamic axis.Used to align a subdiagonal operator with the diagonal so block
kof the padded result is the coupling into stepk.- Parameters:
n (int)
- Return type:
- pcr_finalize(state)[source]#
Finish the PCR sweep, returning the reduced
(operator, rhs)pair.- Parameters:
state (PCRState)
- pcr_init(B, v)[source]#
Seed a parallel-cyclic-reduction sweep (single-group dense only).
Delegates to pyzag’s dense backend. Raises
NotImplementedErrorfor multi-group / BLOCK layouts – use the Thomas factorization for those.- Parameters:
B (BlockOperator)
v (BlockVector)
- Return type:
PCRState
- pcr_reduce_level(state, level)[source]#
Advance the PCR sweep by one stride-doubling level (single-group dense).
- Parameters:
state (PCRState)
level (int)
- solve(rhs)[source]#
Solve
self @ x = rhsfor the diagonal block.Single-group layouts use the cached batched LU; a two-group BLOCK+DENSE split delegates to
SchurComplementwith aCachingLUprimary solver. Three or more groups are unsupported.- Parameters:
rhs (BlockVector)
- Return type:
- class neml2.pyzag.NEML2Wrapper(layout)[source]#
Bases:
objectConvert between pyzag flat torch tensors and neml2-backed block objects.
- Parameters:
layout (AxisLayout)
- unwrap_vector(bv)[source]#
NEML2BlockVector-> flat torch(..., nflat).- Parameters:
bv (BlockVector)
- Return type:
- wrap_jacobian(diag, sub)[source]#
Wrap diag / sub
AssembledMatrixblocks into anNEML2BlockJacobian.- Parameters:
diag (AssembledMatrix)
sub (AssembledMatrix)
- Return type:
- wrap_vector(raw)[source]#
Flat torch
(..., nflat)->NEML2BlockVector.- Parameters:
raw (Tensor)
- Return type:
- neml2.pyzag.change_lag_order(var, new_order)[source]#
Re-tag a variable name to a different lag order. Inverse of
lag_order().