Shared base module

Zmag_bins.Zmag_dynamic_stereo_base is the shared core for dynamic demag and nodemag solvers.

Architecture

Zmag_dynamic_stereo_solvers.create_stereo_solver(model=...)
     │
     ├── demag  → Z_sim_dynamic_stereo_demag  ──┐
     └── nodemag → Z_sim_dynamic_stereo_nodemag ─┤ subclass
                                                 ▼
                           Z_sim_dynamic_stereo_base
                           (time loop, atlas, BDF/CFL, gates, writers)

solve_problem code map

The acceptance labels (A)–(F) in Solver algorithms map to private methods on the base class. One inner-loop attempt runs _run_accept_attempt; failures call _handle_step_rejection; successes call _finalize_accepted_step.

Gate

Method

Role

_run_nonlinear_solve

Nonlinear solve / outer split → trial state

_validate_algebraic_solve

SNES/KSP and outer-split validity

_refresh_attempt_energies

Atlas radius guard + energy snapshot

_apply_residual_gate

Residual backtrack, merit, soft accept

_apply_thermodynamic_gate

Thermodynamic inequality; optional E1 backtrack

_apply_closure_gate

Atlas closure and jump gate

Module-level helpers (below) are called from init_dynamic on each subclass. Drivers normally interact with the concrete solver or factory wrapper, not these functions directly.

Checkpoint files

Required on restart:

  • <checkpoint_base>_qA.npz, <checkpoint_base>_qB.npz

Optional BDF history:

  • _qA_prev.npz, _qA_prev_prev.npz, _qB_prev.npz, _qB_prev_prev.npz

Base class (selected API)

class Zmag_bins.Zmag_dynamic_stereo_base.Z_sim_dynamic_stereo_base[source]

Bases: object

Shared Landau–Lifshitz–Gilbert time integrator on a two-chart stereographic atlas.

Instantiate via Z_sim_dynamic_stereo_demag or Z_sim_dynamic_stereo_nodemag.

Physical model

Chart coordinates \(q_A\) (pole \(+1\)) and \(q_B\) (pole \(-1\)) represent magnetization on \(S^2\). DG0 masks chiA/chiB/chiAB and weights wA/wB blend contributions cell-wise. The blended Cartesian direction used in diagnostics is reconstructed from both charts.

Time stepping

solve_problem() runs a retry loop per step: update continuation ramps, call subclass solve_weak_form(), apply residual / thermodynamic / atlas gates, then adapt \(\Delta t^\ast\) on acceptance.

Code map (this class)

Methods are grouped in the source file by section banners. Within solve_problem(), the private pipeline is:

  • Setup — _init_solve_problem_runtime, _open_timestep, _run_timestep_preamble

  • One attempt — _run_accept_attempt (gates A–F below)

  • On failure — _handle_step_rejection (rollback, dt cut, SNES mode)

  • On success — _finalize_accepted_step (history, CFL, I/O, stop test)

Gates A–F (labels match Solver algorithms):

Gate

Method

Role

A

_run_nonlinear_solve

BDF step + outer split → trial q

B

_validate_algebraic_solve

SNES/KSP + outer-split convergence

C

_refresh_attempt_energies

Atlas radius guard + energy snapshot

D

_apply_residual_gate

D1 backtrack, D2 merit, D3 soft accept

E

_apply_thermodynamic_gate

Dissipation inequality; E1 backtrack

F

_apply_closure_gate

Inactive-chart closure + jump check

Supporting blocks (other section banners in source):

  • Mesh / I/O — check_and_save_mesh_partition, load_mesh_partition, XDMF writers

  • Atlas — _atlas_update_masks_from_qA … _apply_post_accept_atlas_closure

  • State blend / rollback — _set_state_from_backup_trial_blend, _rollback_to_step_backup

  • Dual-chart init — _initialize_and_smooth_q_from_m, _cart_to_stereo_dual_numpy, _bootstrap_chart_state_for_time_loop, restore_checkpoint_atlas_state

  • Backtracking searches — _residual_backtracking_search, _thermo_backtracking_search

  • Thermo assembly — _evaluate_thermodynamic_residual (with gate E)

  • Timestep control — _update_timestep_cfl, _compute_temporal_error_norm

Subclasses implement init_dynamic, solve_weak_form, compute_energy, and model-specific I/O hooks. Shared initialization, checkpoint restore, physical-energy evaluation, per-step backup/rollback, and destroy_dynamic live on this base class.

check_and_save_mesh_partition(comm, dmain, c_tags, f_tags, results_dir)[source]

Validate MPI mesh partition balance and export domain.xdmf.

Fails if any rank owns zero cells. Rank 0 prints load-balance statistics.

Parameters:
  • comm (mpi4py.MPI.Comm) – Mesh communicator.

  • dmain (dolfinx.mesh.Mesh) – Distributed mesh.

  • c_tags (dolfinx.cpp.mesh.MeshTags_int32) – Cell and facet tags.

  • f_tags (dolfinx.cpp.mesh.MeshTags_int32) – Cell and facet tags.

  • results_dir (str) – Output directory for domain.xdmf.

load_mesh_partition(comm, results_dir)[source]

Reload mesh and meshtags written by check_and_save_mesh_partition().

Parameters:
  • comm (mpi4py.MPI.Comm)

  • results_dir (str) – Directory containing domain.xdmf.

Returns:

(domain, cell_tags, facet_tags).

Return type:

tuple

set_mesh(mesh: dolfinx.mesh.Mesh, cell_tags: dolfinx.cpp.mesh.MeshTags_int32, facet_tags: dolfinx.cpp.mesh.MeshTags_int32, surface_tag: int)[source]

Attach mesh, tags, and build FEM spaces for the mixed formulation.

Calls _init_after_mesh to allocate V_q, V_phi (demag only), mixed V_mixed, atlas DG0 fields, measures, and mesh-size field.

Parameters:
  • mesh (dolfinx.mesh.Mesh)

  • cell_tags (dolfinx.cpp.mesh.MeshTags_int32)

  • facet_tags (dolfinx.cpp.mesh.MeshTags_int32)

  • surface_tag (int) – Facet tag for the exterior magnetostatic boundary (demag).

set_materials(materials: list[dict])[source]

Interpolate piecewise-constant material data onto FEM coefficient fields.

Parameters:

materials (list[dict]) – One dict per cell tag with keys tag, Ms, Aex, K, Q1, K2K1_ratio, and optional anisotropy_axis.

set_external_field(field_input)[source]

Set the non-dimensional Zeeman field h_zee.

Requires "zeeman" in energy_terms.

Parameters:

field_input (dict or array-like) – Constant 3-vector or Biot–Savart coil parameter dictionary.

Raises:
  • TypeError – If the input type is unsupported.

  • AssertionError – If Zeeman is not an active energy term.

P_mu_gamma(q)[source]

Stereographic exchange metric \(P_\mu = \mathrm{diag}(\sigma^2,\sigma^2)\).

Parameters:

q (ufl.core.expr.Expr) – Chart coordinates.

Returns:

  • ufl.Matrix

  • 2×2 metric with \(\sigma^2=(2/(1+r^2))^2\).

Q_mu(q, grad_q)[source]

Nonlinear exchange coupling \(Q_\mu(q,\nabla q)\) in the stereographic weak form.

Parameters:
  • q

  • grad_q

  • gradient. (UFL chart value and)

Returns:

  • ufl.Vector

  • Length-2 UFL vector contracted with test functions in exchange terms.

update_demag_ramp_factor()[source]

Update demag ramp factor with transition marker on completion.

update_zeeman_ramp_factor()[source]

Update Zeeman ramp factor with transition marker on completion.

stereo_to_cart_chart(q, sign)[source]

Map stereographic chart coordinates to a unit Cartesian magnetization.

Uses the pole and tangent basis from args_init_sim. Chart B uses sign=-1.

Parameters:
  • q (ufl.core.expr.Expr) – Chart coordinates \((u,v)\).

  • sign (float) – +1 (chart A) or -1 (chart B).

Returns:

  • ufl.Vector

  • \(\mathbf{m}(q,\mathrm{sign})\) on the unit sphere.

L_mu_gamma_chart(q, sign)[source]

Chart-specific L matrix with fixed orientation sign.

A_mu_i_chart(q, sign)[source]

Chart-specific Jacobian dm/dq with fixed sign.

check_q_magnitude(silent=False)[source]

Report the global maximum effective chart radius.

Computes \(\min(r_A,r_B)\) per node with \(r=|q|\), then MPI-reduces the maximum. Used as an atlas stability diagnostic.

Parameters:

silent (bool, optional) – Suppress rank-0 printing when True.

Returns:

  • float

  • Global maximum of the per-node minimum chart radius.

solve_problem()[source]

Advance the simulation from step_start to step_end.

High-level loop (each integer step):

  1. Preamble — update demag/Zeeman ramps; optional continuation transition (shrink dt, force BDF1, suspend thermo briefly); solve_magnetostatics.

  2. Retry loop — repeat until the step is accepted or retry limits fire.

  3. Post-accept — advance t by full dt, update BDF history, CFL controller, I/O, checkpoints; test physical steady-state stop.

One acceptance attempt is _run_accept_attempt(), which runs gates in order: (A) _run_nonlinear_solve(), (B) _validate_algebraic_solve(), (C) _refresh_attempt_energies(), (D) _apply_residual_gate(), (E) _apply_thermodynamic_gate(), (F) _apply_closure_gate(). See the table in _run_accept_attempt() for substages and side helpers.

Backtracking (both kinds) damps state along \(q^n + \lambda(q^{\mathrm{trial}}-q^n)\) at full dt without re-solving; see _set_state_from_backup_trial_blend(). Residual backtracking failure restores the SNES trial and falls through to merit/soft gates (D2/D3); only thermodynamic backtracking failure raises RuntimeError, rolls back via _rollback_to_step_backup(), and may cut dt (unless same-dt recovery applies).

Rejected steps shrink dt (thermo-aware or halving), may escalate outer-split cap or switch SNES globalization, and may fall back BDF2→BDF1.

See also

Solver algorithms, solve_weak_form(), _update_timestep_cfl()

Notes

All ranks participate in atlas and gate MPI reductions.

effective_field(target=None)[source]

Assemble the atlas-weighted effective field \(\mathbf{H}_{\mathrm{eff}}\).

Exchange and anisotropy contributions are blended with wA/wB from both charts; demagnetizing and Zeeman terms use the solver’s shared field state.

write_energies(filename: str)[source]

Write a tab-separated energy log on rank 0.

Rows follow self.energies (time, \(\Delta t^\ast\), active terms, total).

Parameters:

filename (str) – Output path for the energy table.

set_init_q_from_external_field(std_u, std_v, smoothing_len, smoothing_iters, material_aware=False, zeeman_bias=0.3)[source]

Initialize charts from the Zeeman field direction plus Gaussian noise.

Requires set_external_field and the zeeman energy term. The field direction is preserved at every node, including near the projection pole P: chart B is used when m·P > 0, chart A when m·P < 0 (see Initializing the atlas).

Parameters:
  • std_u (float) – Noise standard deviations on the active chart coordinates per node.

  • std_v (float) – Noise standard deviations on the active chart coordinates per node.

  • smoothing_len (float, int) – Helmholtz smoothing controls after projection.

  • smoothing_iters (float, int) – Helmholtz smoothing controls after projection.

  • material_aware (optional) – Reserved API parameters (currently unused).

  • zeeman_bias (optional) – Reserved API parameters (currently unused).

set_init_q_from_angles(theta0_target, theta1_target, std_u, std_v, smoothing_len, smoothing_iters)[source]

Initialize uniform magnetization from spherical angles (theta0, theta1) plus noise.

Uses dual-chart projection; noise is applied on the active chart per node.

Parameters:
  • theta0_target (float) – Spherical angles defining the target direction.

  • theta1_target (float) – Spherical angles defining the target direction.

  • std_u – Noise and smoothing parameters.

  • std_v – Noise and smoothing parameters.

  • smoothing_len – Noise and smoothing parameters.

  • smoothing_iters – Noise and smoothing parameters.

set_init_q_from_theta_function(eval_theta_init, smoothing_len, smoothing_iters)[source]

Initialize from a spatially varying angle field eval_theta_init(x).

Cartesian directions are built from (theta0, theta1) and projected onto both charts (pole-aware routing).

Parameters:
  • eval_theta_init (callable) – Returns (theta0, theta1) arrays for node coordinates x of shape (3, N).

  • smoothing_len (float, int) – Post-projection smoothing.

  • smoothing_iters (float, int) – Post-projection smoothing.

set_init_q_from_m_function(eval_m_init, smoothing_len, smoothing_iters)[source]

Initialize by projecting eval_m_init(x) onto both atlas charts.

Accepts any magnetization field, including m = ±P and directions close to the projection pole. Vectors are normalized per node inside _initialize_and_smooth_q_from_m(); degenerate inputs default to -P (chart-A origin). At exact poles the well-conditioned chart is stored at q = 0 and the singular chart at |q| = R_cap.

Parameters:
  • eval_m_init (callable) – Returns (mx, my, mz) arrays for node coordinates x of shape (3, N).

  • smoothing_len (float, int) – Post-projection smoothing.

  • smoothing_iters (float, int) – Post-projection smoothing.

restore_checkpoint_atlas_state(filename: str) → None[source]

Restore atlas chart fields, BDF history, and optional demag potential.

Delegates to the module-level restore_checkpoint_atlas_state() loader, which also rehydrates DG0 atlas weights and sets restart flags.

Parameters:

filename (str) – Checkpoint stem (_qA.npz / _qB.npz siblings required).

destroy_dynamic()[source]

Release SNES/KSP objects and close XDMF time-series writers.

Safe to call at the end of a simulation segment or before process exit.

Module-level functions and constants

Shared core for stereographic dynamic micromagnetics.

This module factors all model-independent logic used by the demag and nodemag dynamic solvers. The Landau–Lifshitz–Gilbert (LLG) equation is discretized in stereographic chart coordinates \((q_A,q_B)\) with a two-chart atlas so that \(|\mathbf{m}|=1\) is intrinsic to the parametrization.

Module-level API

Class Z_sim_dynamic_stereo_base

Hosts Z_sim_dynamic_stereo_base.solve_problem(), atlas masks and weights, BDF time differencing, adaptive timestep control (CFL cap, embedded BDF error estimate, thermodynamic caps), acceptance gates, continuation ramps, and shared field writers.

The per-timestep acceptance pipeline is orchestrated by Z_sim_dynamic_stereo_base.solve_problem() and factored into private helpers (see class docstring Code map). Algorithm details and gate labels (A)–(F) are in Solver algorithms.

Gate → method (quick reference)

Label

Method

_run_nonlinear_solve()

_validate_algebraic_solve()

_refresh_attempt_energies()

_apply_residual_gate()

_apply_thermodynamic_gate()

_apply_closure_gate()

One attempt runs _run_accept_attempt(); rejections call _handle_step_rejection(); accepted steps call _finalize_accepted_step().

Subclasses supply mixed FEM spaces, SNES residuals, and magnetostatics coupling.

Zmag_bins.Zmag_dynamic_stereo_base.parent_dof_map_from_collapse(collapse_map: Any) → numpy.ndarray[source]

Flatten a DOLFINx collapse() parent DOF map to a 1-D int32 array.

DOLFINx 0.9 returned a flat sequence of parent DOF indices. DOLFINx 0.10+ returns a list of arrays (one per collapsed block). Indexing the raw list with map[:n_owned] is wrong for the latter and yields invalid fieldsplit index sets (PETSc SEGV in the LU factor).

Zmag_bins.Zmag_dynamic_stereo_base.validate_spin_vector(vec: Any, name: str) → numpy.ndarray[source]

Return a length-SPIN_DIM finite vector or raise ValueError.

Zmag_bins.Zmag_dynamic_stereo_base.init_stereographic_chart_basis(args_init_sim: dict[str, Any]) → tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray][source]

Build orthonormal stereographic projection pole and tangent basis in R^3.

Parameters:

args_init_sim (dict) – May contain projection_pole (length-3, nonzero).

Returns:

(pole, e1, e2) unit vectors.

Return type:

tuple[np.ndarray, np.ndarray, np.ndarray]

Zmag_bins.Zmag_dynamic_stereo_base.merge_convergence_settings(args_init_dyn: dict[str, Any]) → dict[str, float | int][source]

Merge user convergence_settings with DEFAULT_CONVERGENCE_SETTINGS.

Parameters:

args_init_dyn (dict) – Dynamic configuration dictionary.

Returns:

  • dict

  • Merged settings (physical_tol_mdot_rms, physical_tol_edot, steady_steps, …).

Raises:

ValueError – If convergence_settings is present but not a dict.

Zmag_bins.Zmag_dynamic_stereo_base.apply_cfl_settings(solver: Any, args_init_dyn: dict[str, Any]) → None[source]

Attach adaptive timestep attributes on a solver instance.

Merges args_init_dyn['cfl_settings'] with DEFAULT_CFL_SETTINGS for use in Z_sim_dynamic_stereo_base._update_timestep_cfl().

Parameters:
  • solver (Z_sim_dynamic_stereo_base) – Solver during init_dynamic setup.

  • args_init_dyn (dict) – Must contain a cfl_settings sub-dictionary.

Raises:

ValueError – If cfl_settings is missing or not a dict.

Zmag_bins.Zmag_dynamic_stereo_base.convergence_tolerances(convergence_settings: dict[str, Any]) → tuple[float, float, int][source]

Extract steady-state stopping thresholds.

Parameters:

convergence_settings (dict) – Merged convergence dictionary.

Returns:

  • tuple[float, float, int]

  • (physical_tol_mdot_rms, physical_tol_edot, steady_steps).

Zmag_bins.Zmag_dynamic_stereo_base.save_checkpoint_atlas_state(solver: Any, base: str) → None[source]

Write stereographic atlas state and BDF history to npz files.

Writes base_qA.npz, base_qB.npz, optional BDF history files, and atlas metadata.

Zmag_bins.Zmag_dynamic_stereo_base.save_checkpoint_time_state(solver: Any, base: str) → None[source]

Write time-integration/controller state to base + '_time_state.npz'.

The dynamic checkpoint test expects the solver to be able to continue the same adaptive/BDF/thermo controllers after restoring a checkpoint. The atlas state alone is insufficient because gate budgets (EMAs) and BDF coefficients depend on solver history.

Zmag_bins.Zmag_dynamic_stereo_base.restore_checkpoint_time_state(solver: Any, filename: str) → None[source]

Restore time/controller state from *_time_state.npz if present.

Safe to call even when the file is missing (older checkpoints).

Zmag_bins.Zmag_dynamic_stereo_base.restore_checkpoint_atlas_state(solver: Any, filename: str) → None[source]

Restore atlas chart fields and BDF history in-place on solver.

Loads qA, qB, both BDF histories, and atlas metadata directly into the solver’s live fields. Sets solver._atlas_checkpoint_restored so Z_sim_dynamic_stereo_base._bootstrap_chart_state_for_time_loop() preserves the restored history instead of cold-start regeneration.

Parameters:
  • solver (Z_sim_dynamic_stereo_base) – Solver with allocated chart spaces.

  • filename (str) – Checkpoint stem; _qA.npz and _qB.npz must exist.

Raises:

FileNotFoundError – If required npz files are missing.

Notes

Missing BDF history files fall back to repeating the loaded current chart state. Sets _qB_ready and _dual_charts_initialized so magnetization outputs and cold-start guards treat the restored charts as authoritative. DG0 atlas weights are rebuilt immediately via _rehydrate_atlas_state_from_restored_q(). Demag phi (when present) is restored as a warm start only; after remesh the live BEM generally differs, so demag solvers re-equilibrate phi from the restored magnetization in init_dynamic before seeding the thermo gate.

Zmag_bins.Zmag_dynamic_stereo_base.checkpoint_atlas_field_norms(solver: Any, filename: str) → dict[str, float][source]

Return owned L2 norms of atlas checkpoint fields without mutating solver state.