FDM multilayer convolution: Python, ProblemIR, and UI

Last changes: Documentation changelog

What this guide configures

This page is the authoring guide for Fullmag’s FDM multilayer demagnetization path. It shows how to give every named magnet its own Cartesian native grid, request a shared convolution layout, preserve that request in ProblemIR, and inspect the planner/runtime result in the Control Room. The magnetostatic equations and their derivation are owned by FDM multilayer demagnetizing-field convolution; this page owns the Python, ProblemIR, UI, and failure contracts.

Three layouts must not be confused:

  1. a native layer grid carries the layer’s physical magnetization and field samples;

  2. the common convolution grid is FFT scratch used for transfers and pair convolutions, not a physical mesh and not a visualization fallback;

  3. an optional target-only Airbox grid carries only the published H_demag observation outside the magnetic support.

The public authoring vocabulary mirrors FEM: body.mesh(...) configures an object’s native mesh, while study.universe.mesh(...) configures the shared computational domain. For FDM both calls use cell_size=(dx, dy, dz). The common domain is FFT scratch, not an extra magnetic body. Layer separation still comes only from geometry transforms and the resulting native-grid origins.

Authoring-to-grid relations

For layer \(\ell\), Fullmag realizes the cell-center coordinates from the native origin and authored cell size as

(1)\[\mathbf{x}_{\ell,\mathbf{i}} = \mathbf{o}_{\ell} + \left(\mathbf{i}+\tfrac{1}{2}\mathbf{1}\right)\odot\mathbf{h}_{\ell}.\]

With an explicit two-dimensional stack request, the authored in-plane common-grid size fixes the resolved transform-grid cell count to

(2)\[\mathbf{C}=\left(C_x,C_y,1\right) =\left(N_x^{\mathrm{common}},N_y^{\mathrm{common}},1\right).\]

For \(L\) layers the planner records \(L^2\) ordered source-to-destination interactions. Kernel reuse is not determined by a physical separation alone. The reusable implementation key quantizes the signed \(z\) displacement in units of the resolved convolution-cell thickness and also contains the source and destination cell sizes and the common convolution-grid shape:

(3)\[K_{\mathrm{pair}}=L^2, \qquad K_{\mathrm{unique}} =\left|\left\{ \left( \operatorname{round}\!\left(\frac{o_{d,z}-o_{s,z}}{h_{c,z}}\right), Q(\mathbf h_s),Q(\mathbf h_d),\mathbf C \right):d,s\in\{1,\ldots,L\}\right\}\right|, \qquad Q(h)=\operatorname{round}(10^{12}h).\]

These relations define the numerical layout only. They do not replace the demagnetizing-field and energy equations on the physics page.

Symbols and SI units

Symbol

Meaning

SI unit

\(\ell,m\)

destination and source layer indices

\(1\)

\(\mathbf{x}_{\ell,\mathbf{i}}\)

center of native cell \(\mathbf{i}\) in layer \(\ell\)

\(\mathrm{m}\)

\(\mathbf{i}\)

three-dimensional integer cell index

\(1\)

\(\mathbf{o}_{\ell}\)

world-space origin of the native grid for layer \(\ell\)

\(\mathrm{m}\)

\(\mathbf{h}_{\ell}\)

authored native cell-edge lengths of layer \(\ell\)

\(\mathrm{m}\)

\(\mathbf{1}\)

three-component vector of ones

\(1\)

\(\odot\)

component-wise multiplication

\(1\)

\(\mathbf{C}\)

resolved common convolution-grid cell counts

\(1\)

\(C_x,C_y\)

resolved common in-plane cell counts

\(1\)

\(N_x^{\mathrm{common}},N_y^{\mathrm{common}}\)

authored common_cells_xy components

\(1\)

\(L\)

number of magnetic layers

\(1\)

\(o_{d,z},o_{s,z}\)

destination and source native-grid origins along \(z\)

\(\mathrm{m}\)

\(h_{c,z}\)

resolved convolution-cell thickness

\(\mathrm{m}\)

\(Q\)

picometre quantizer used in the reuse key

\(\mathrm{m^{-1}}\)

\(K_{\mathrm{pair}}\)

number of ordered layer pairs

\(1\)

\(K_{\mathrm{unique}}\)

number of distinct reuse keys, not merely distinct physical separations

\(1\)

Assumptions and validity

The planner forms a computational common-scratch envelope from the union of every native XY rectangle. Therefore multilayer bodies may have different XY extents and centers; their native origins, masks, and physical meshes remain separate, and a non-coincident layer is marked push_pull. An explicit common_cells or common_cells_xy must contain that union with a compatible pitch. A runtime lane that cannot consume the resulting insertion/crop or transfer descriptor fails closed. This transfer path is not a claim that Appendix-A irregular Newell supports arbitrary different XY cells: the irregular kernel itself requires common XY cell sizes. Bodies may be separated along \(z\), but they may not overlap there. two_d_stack requires one native Z cell per layer. A multi-cell-Z request fails closed: no public moment-preserving Z reduction exists, so the planner never copies one arbitrary native slice. Select three_d for through-thickness cells. Open boundaries are executable; periodic multilayer axes fail closed. Per-object regions, thermal noise, spin torque, Oersted terms, regional field drives, spatial material fields, and bulk DMI are currently rejected for this path. CPU execution accepts FP64 only. CUDA FP32/FP64 has separate runtime and qualification requirements; representability in Python or ProblemIR is not proof that a requested GPU lane executed.

Python API

Complete parameter reference

Normal scripts use the first three rows below. The legacy FDM* classes remain compatibility adapters and are not canonical authoring syntax.

Python

Type

Default

SI unit

Validation

Meaning

Backend support

ProblemIR

body.mesh(cell_size=...)

Sequence[float] of length 3

required unless a default exists

\(\mathrm{m}\)

Three finite positive values; each object extent must be exactly divisible.

Native Cartesian cell size for that magnetic object.

FDM CPU/GPU subject to planner capability gates.

.fdm.per_magnet[object_name].cell

study.objects.mesh.defaults(cell_size=...)

Sequence[float] of length 3

None

\(\mathrm{m}\)

Three finite positive values.

Default native cell size for objects without an override.

FDM CPU/GPU.

.fdm.default_cell

study.universe.mesh(cell_size=...)

Sequence[float] of length 3

inferred only for compatible grids

\(\mathrm{m}\)

Three finite positive values; must divide the common envelope exactly.

Requested common convolution-grid resolution.

FDM multilayer CPU/GPU subject to lane qualification.

.fdm.demag.common_cell_size

FDMGrid.cell

Sequence[float] of length 3

required

\(\mathrm{m}\) per component

Exactly three finite, strictly positive components.

Native Cartesian cell size for one named magnet.

FDM CPU/GPU multilayer authoring; planner and runtime still capability-gate the resolved lane.

backend_policy.discretization_hints.fdm.per_magnet[magnet_name].cell

FDMDemag.strategy

Literal["auto", "single_grid", "multilayer_convolution"]

"auto"

\(1\)

Must be one of the three literal values.

Requested demagnetization topology; use "multilayer_convolution" to force this path.

FDM CPU/GPU; multi-body single_grid is currently rejected by the planner.

backend_policy.discretization_hints.fdm.demag.strategy

FDMDemag.mode

Literal["auto", "two_d_stack", "three_d"]

"auto"

\(1\)

Must be one of the three literal values.

Requested thin-film stack or full 3-D convolution mode.

FDM CPU/GPU subject to geometry and native-Z constraints.

backend_policy.discretization_hints.fdm.demag.mode

FDMDemag.common_cells

tuple[int, int, int] | None

None

\(1\)

Exactly three positive non-Boolean integers; mutually exclusive with common_cells_xy; invalid with mode="two_d_stack".

Explicit 3-D common convolution-grid cell counts.

FDM CPU/GPU subject to planner memory and runtime capability.

backend_policy.discretization_hints.fdm.demag.common_cells

FDMDemag.common_cells_xy

tuple[int, int] | None

None

\(1\)

Exactly two positive non-Boolean integers; mutually exclusive with common_cells; valid only with mode="auto" or mode="two_d_stack".

Explicit in-plane common-grid counts; planner resolves the Z count to one for a 2-D stack.

FDM CPU/GPU two-dimensional stack path.

backend_policy.discretization_hints.fdm.demag.common_cells_xy

FDMDemag.allow_single_grid_fallback

bool | None

None

\(1\)

Every non-None value raises ValueError.

Removed compatibility input; silent fallback is forbidden.

Unsupported on every lane.

Not serialized

FDMDemag.explain

bool

True

\(1\)

The raw script builder requires a Boolean; the constructor itself does not type-check it.

Requests a human-readable plan explanation; it is not physical intent.

Python/UI authoring helper only.

Not serialized

FDM.cell

Sequence[float] | None

None

\(\mathrm{m}\) per component

Legacy alias; cannot be supplied together with default_cell; when present, exactly three finite positive components.

Backward-compatible default Cartesian cell size.

FDM CPU/GPU; prefer default_cell.

Both backend_policy.discretization_hints.fdm.cell and .default_cell

FDM.default_cell

Sequence[float] | None

None

\(\mathrm{m}\) per component

Exactly three finite positive components when supplied; either this or a non-empty per_magnet mapping is required.

Default grid for magnets without an explicit native-grid override and basis for an inferred common grid.

FDM CPU/GPU.

Both backend_policy.discretization_hints.fdm.cell and .default_cell

FDM.per_magnet

dict[str, FDMGrid] | None

None

\(1\)

Keys are non-empty strings and values are FDMGrid; without default_cell, every authored magnet must have a matching key.

Native grid overrides keyed by canonical magnet name.

FDM multilayer paths.

backend_policy.discretization_hints.fdm.per_magnet

FDM.demag

FDMDemag | None

None

\(1\)

FDM.__init__ has no explicit type check; a valid FDMDemag is required during lowering.

Attaches requested demagnetization topology and common-grid policy.

FDM CPU/GPU.

backend_policy.discretization_hints.fdm.demag

FDM.boundary_correction

Literal["none", "volume", "full"] | None

None

\(1\)

When supplied, must be "none", "volume", or "full".

Selects binary, T0 volume-fraction, or T1 full sub-cell boundary policy.

Lane and precision dependent; this page does not qualify all combinations.

backend_policy.discretization_hints.fdm.boundary_correction

FDM.boundary_phi_floor

float | None

None

\(1\)

Strictly \(0<\varphi_{\mathrm{floor}}<1\) when supplied.

Lower volume-fraction bound used by boundary-correction stability logic.

Boundary-correction lanes only.

backend_policy.discretization_hints.fdm.boundary_phi_floor

FDM.boundary_delta_min

float | None

None

\(\mathrm{m}\)

Values less than zero raise ValueError; the Python constructor currently performs no separate finiteness check.

Lower intersection-distance bound used by the T1 stencil.

Boundary-correction lanes only.

backend_policy.discretization_hints.fdm.boundary_delta_min

Complete stage-first example

This small three-layer stack is directly copyable. It explicitly enables demagnetization, requests the CPU FP64 reference lane, saves H_demag, and ends in a fixed-step stage.

# %% Imports and study execution intent
import fullmag as fm

nm = 1.0e-9
study = fm.study("fdm_multilayer_python_guide")
study.engine("fdm")
study.device("cpu", precision="double")
study.mode("strict")
study.interactive(False)

# %% Native cell size
native_cell = (4.0 * nm, 4.0 * nm, 3.0 * nm)

# %% Universe and three non-overlapping, XY-aligned layers
study.universe(
    mode="manual",
    size=(40.0 * nm, 20.0 * nm, 30.0 * nm),
    center=(0.0, 0.0, 9.0 * nm),
    padding=(0.0, 0.0, 0.0),
)

layer_size = (32.0 * nm, 16.0 * nm, 3.0 * nm)
bottom = study.geometry(fm.Box(size=layer_size), name="layer_bottom")
middle = study.geometry(
    fm.Box(size=layer_size).translate((0.0, 0.0, 9.0 * nm)),
    name="layer_middle",
)
top = study.geometry(
    fm.Box(size=layer_size).translate((0.0, 0.0, 18.0 * nm)),
    name="layer_top",
)
for layer in (bottom, middle, top):
    layer.mesh(cell_size=native_cell)
study.universe.mesh(cell_size=native_cell)

# %% Material state and interactions
for layer in (bottom, middle, top):
    layer.Ms = 800.0e3
    layer.Aex = 13.0e-12
    layer.alpha = 0.02
    layer.m = fm.init.UniformMagnetization((1.0, 0.0, 0.0))

study.exchange(enabled=True)
study.demag(enabled=True)
study.b_ext(-24.6e-3, 4.3e-3, 0.0)

# %% Output and stage
study.save("H_demag", every=1.0e-13)
study.solver(integrator="rk4", fix_dt=1.0e-14, gamma=2.211e5)
study.tableautosave(
    1.0e-13,
    quantities=["step", "t", "mx", "my", "mz", "e_demag", "e_total"],
)
study.stages.add_run(until=1.0e-13, stage_id="multilayer_run")

The planner selects two_d_stack only when every native layer has exactly one Z cell and no explicit 3-D common resolution is requested. Supplying study.universe.mesh(cell_size=...) requests a full 3-D common grid, so the resolved mode is three_d. This is deliberate: the three components specify the physical resolution of the FFT supercell, while each layer keeps its own native grid and world-space Z origin.

Optional CPU FP64 target-only Airbox observation

The current target-only carrier is an explicit post-run observation contract, not part of FDMDemag and not a CUDA promise. Add this before the stage when a CPU FP64 run must publish H_demag on a separate Airbox grid:

# %% Complete study with a target-only Airbox observation
import fullmag as fm

nm = 1.0e-9
study = fm.study("fdm_multilayer_airbox_guide")
study.engine("fdm")
study.device("cpu", precision="double")
study.mode("strict")
study.universe(mode="manual", size=(40.0 * nm, 20.0 * nm, 30.0 * nm), center=(0.0, 0.0, 4.5 * nm))
bottom = study.geometry(fm.Box(size=(32.0 * nm, 16.0 * nm, 3.0 * nm)), name="bottom")
top = study.geometry(
    fm.Box(size=(32.0 * nm, 16.0 * nm, 3.0 * nm)).translate((0.0, 0.0, 9.0 * nm)),
    name="top",
)
for layer in (bottom, top):
    layer.mesh(cell_size=(4.0 * nm, 4.0 * nm, 3.0 * nm))
study.universe.mesh(cell_size=(4.0 * nm, 4.0 * nm, 3.0 * nm))
for layer in (bottom, top):
    layer.Ms = 800.0e3
    layer.Aex = 13.0e-12
    layer.alpha = 0.02
    layer.m = fm.init.UniformMagnetization((1.0, 0.0, 0.0))
study.exchange(enabled=True)
study.demag(enabled=True)
study.save("H_demag", every=1.0e-13)
study.runtime_metadata(
    "airbox_observation",
    {
        "cells": (10, 6, 12),
        "spacing_m": (4.0 * nm, 4.0 * nm, 3.0 * nm),
        "origin_m": (-20.0 * nm, -12.0 * nm, -15.0 * nm),
        "padding_cells_above_below": (4, 6),
        "target_only": True,
        "scope_kind": "airbox",
        "published_quantities": ("H_demag",),
        "unavailable_quantities": {
            "H_eff": "fdm_multilayer_airbox_h_eff_unavailable.v1",
        },
    },
)
study.solver(integrator="rk4", fix_dt=1.0e-14, gamma=2.211e5)
study.stages.add_run(until=1.0e-13, stage_id="airbox_run")

The Airbox metadata is validated fail-closed: target_only must be true, scope_kind must be "airbox", the only published quantity must be H_demag, and H_eff must carry the exact unavailable-reason identifier shown above. The current materializer ignores this request on a non-CPU-reference execution engine and rejects non-FP64 provenance.

Canonical ProblemIR

The public mesh-authoring calls produce backend_policy.discretization_hints.fdm. The following JSON is the canonical ProblemIR wrapper produced by the first example’s FDM objects; explain is absent by design because it is an authoring/display preference. The surrounding backend_policy path is part of the canonical contract, not an illustrative shorthand:

{
  "backend_policy": {
    "requested_backend": "fdm",
    "execution_precision": "double",
    "discretization_hints": {
      "fdm": {
        "cell": [4e-09, 4e-09, 3e-09],
        "default_cell": [4e-09, 4e-09, 3e-09],
        "per_magnet": {
          "layer_bottom": {"cell": [4e-09, 4e-09, 3e-09]},
          "layer_middle": {"cell": [4e-09, 4e-09, 3e-09]},
          "layer_top": {"cell": [4e-09, 4e-09, 3e-09]}
        },
        "demag": {
          "strategy": "multilayer_convolution",
          "mode": "two_d_stack",
          "common_cells_xy": [8, 4]
        }
      }
    }
  }
}

The physical interaction remains a separate global Demag energy term. study.demag(enabled=True) controls whether that term is enabled; the mesh calls are a distinct FDM discretization policy which selects how that enabled term is realized. They are not normalized by one shared Python resolver. The planner lowers the authored FDM subtree to BackendPlanIR::FdmMultilayer, whose resolved payload contains:

  • mode, common_cells, and a topology-bound grid_certificate;

  • one FdmLayerPlanIR per named magnet with layer_id, object_id, native grid, native origin, active mask, convolution layout, and transfer_kind (identity or push_pull);

  • planner_summary.requested_strategy, selected_strategy, requested_mode, resolved_mode, eligibility, pair/unique-kernel counts, memory estimate, and warnings;

  • resolved precision, integrator, fixed timestep, enabled interactions, periodicity, and output plan.

This resolved plan is runtime input and provenance. It is not written back over the authored Python request.

Python-to-ProblemIR mapping

Python object

Canonical destination

Normalization

FDMGrid(cell=h)

backend_policy.discretization_hints.fdm.per_magnet[name].cell

sequence becomes a three-element JSON array

FDM(cell=h)

.fdm.cell and .fdm.default_cell

legacy alias is duplicated for compatibility

FDM(default_cell=h)

.fdm.cell and .fdm.default_cell

canonical default also populates the legacy mirror

FDM(per_magnet=...)

.fdm.per_magnet

mapping keys remain canonical magnet names

FDM(demag=policy)

.fdm.demag

nested FDMDemag.to_ir() output

FDMDemag(strategy=...)

.fdm.demag.strategy

requested value is preserved, including "auto"

FDMDemag(mode=...)

.fdm.demag.mode

requested value is preserved; planner owns resolved_mode

FDMDemag(common_cells=...)

.fdm.demag.common_cells

tuple becomes a three-element integer array

FDMDemag(common_cells_xy=...)

.fdm.demag.common_cells_xy

tuple becomes a two-element integer array

FDMDemag(explain=...)

not serialized

retained only by authoring/UI round-trip

FDM(boundary_correction=...)

.fdm.boundary_correction

literal is preserved

FDM(boundary_phi_floor=...)

.fdm.boundary_phi_floor

scalar is preserved

FDM(boundary_delta_min=...)

.fdm.boundary_delta_min

SI metres are preserved

UI → generated Python → ProblemIR

The authoring path is one chain, including the per-magnet identity:

Layer

Source symbol

Contract

Control Room draft

apps/control-room/src/modules/inspector/panels/StudyGlobalAuthoringModel.ts::buildStudyGlobalMergePatch

Global fields (study.fdm.default_cell, study.fdm.per_magnet, study.fdm.demag, and study.demag_enabled) are written to one canonical scene merge patch.

Generated script

packages/fullmag-py/src/fullmag/runtime/script_builder.py::render_loaded_problem_as_script

The scene patch renders independent study.demag(enabled=True), per-object mesh calls, and the optional common-universe mesh call.

Per-magnet lookup

study.geometry(..., name="layer_bottom") and per_magnet["layer_bottom"]

The geometry name is the canonical key. It is not a generated mesh alias and it must not be silently renamed.

Python lowering

packages/fullmag-py/src/fullmag/model/discretization.py::FDM.to_ir

Native cells and demag policy lower under backend_policy.discretization_hints.fdm.

Planner resolution

crates/fullmag-plan/src/fdm.rs::plan_fdm_multilayer

Geometry, mode, common transform, transfer, pair keys, and eligibility become resolved execution; authored values remain requested intent.

CommonTransformLayout is computational scratch, not a physical mesh. The resource schema (crates/fullmag-api/src/schemas/domain.rs::FdmCommonTransformLayoutResource) reports is_physical_mesh=false and provenance. The resource-first route is GET /v2/sessions/current/data/domain/fdm-multilayer-layout; an unavailable layout has an explicit reason and is not synthesized by Explorer. Native-layer fields use layer/object scopes. The target-only Airbox uses airbox scope and publishes H_demag only; no request projects a field from the common transform layout.

Round-trip, requested intent, and failure semantics

Requested intent is the Python/UI strategy, mode, native cell sizes, optional common-grid counts, precision, device, and execution mode. auto remains auto in authored ProblemIR. Resolved execution is recorded separately in the execution plan and artifacts: actual mode, common-grid shape, native origins and masks, transfer kinds, grid fingerprints, pair-kernel counts, selected runtime engine, precision, FFT backend, and runtime/device identity.

Python constructor validation errors reject malformed vectors, non-positive sizes, Boolean cell counts, incompatible common-grid fields, invalid modes/strategies, empty magnet names, wrong grid objects, and the removed fallback switch. Rust deserialization repeats the demag-policy checks for non-Python producers. Planner validation errors reject geometry and capability violations before allocation. Unsupported combinations fail without silently changing multilayer to single-grid, CUDA to CPU, or three_d to two_d_stack.

The Control Room’s global Demag toggle is exported as study.demag(...); the FDM policy is exported independently through the public mesh-authoring calls. A saved explain checkbox may round-trip through authoring state and generated Python even though it does not enter physical ProblemIR.

Backend support and qualification

Solver

Device

Authoring/IR

Runtime state

Qualification boundary

FDM

CPU

documented

FP64 reference multilayer execution and optional post-run target-only Airbox materialization

Local numerical artifacts exist; production qualification still requires the repository’s managed gates for the claimed matrix.

FDM

GPU

documented

CUDA multilayer paths and telemetry contracts exist

Source, compilation, and ABI tests are not executed-device parity. Do not claim production GPU support without a fresh managed CUDA receipt, device identity, field/energy parity, and residency telemetry.

FEM

CPU

not applicable

FEM demagnetization uses scalar-potential/BEM families, not FDM multilayer convolution

Select a documented FEM demag realization instead.

FEM

GPU

not applicable

FEM demagnetization uses MFEM/hypre/libCEED realizations, not FDM multilayer convolution

Select a documented FEM GPU demag realization instead.

Control Room workflow

Enable and configure the method

  1. Set the study lane to Backend: FDM. In the Physics ribbon choose Global Physics → Demagnetization and enable the interaction.

  2. Select the study in Explorer and use its Inspector global settings. Set FDM demag to FDM multilayer convolution.

  3. Enter FDM default cell as dx, dy, dz in metres. In FDM per-magnet grids, enter a JSON object keyed by canonical magnet names, for example {"free":{"cell":[2e-9,2e-9,1e-9]}}.

  4. Set FDM demag mode to 2-D stack or 3-D. For 2-D enter Nx, Ny in Common convolution cells XY. For 3-D enter Nx, Ny, Nz in Common convolution cells. The two fields are mutually exclusive.

  5. Optionally enable Explain FDM demag plan and configure boundary correction. Press Save globals only after the Inspector has no validation errors.

The global Demagnetization control enables the physical Demag term. The study’s FDM demag strategy is a separate discretization-policy request; the current code does not normalize the two fields through one resolver. The policy is meaningful only for an FDM lane, and capability-disabled ribbon actions remain disabled with an explanation.

BORIS comparison and implementation gap

The detailed English BORIS/Fullmag matrix is canonical on FDM multilayer demagnetizing-field convolution under BORIS comparison and gap matrix. It is linked here because Python authoring must not imply BORIS compatibility. The matrix covers:

Axis

Fullmag authoring consequence

BORIS multilayer versus supermesh

strategy="multilayer_convolution" is explicit; Fullmag does not silently turn a multi-body request into a supermesh or single-grid fallback.

BORIS Rect_collection/scratch and n_common

common_cells and common_cells_xy describe FFT scratch only; native grids, origins, and masks remain per magnet.

BORIS common-cell pitch

Fullmag keeps native cell size, resolved common-cell size, and transform layout separate; equal common counts do not imply equal cell volumes.

BORIS arbitrary XY rectangles and XYZ offsets

Fullmag planner forms a union scratch envelope for different native XY extents/centers and marks the affected layers push_pull; an explicit common grid must contain that union. Complete transfer/runtime/CUDA qualification is still open.

BORIS 2dmulticonvolution=0/1/2

Fullmag mode="two_d_stack" is not =1 or =2; it requires one native Z cell and rejects multi-cell Z because no public moment-preserving reduction exists.

Pair kernels, unequal thickness, weighted transfer

Fullmag keeps oriented source/destination cell sizes, signed offsets, six components, and explicit push_pull transfer; each scope needs field/energy/reciprocity evidence.

Catalog/reuse, spectral storage, FFT, padding, CPU/CUDA

Fullmag records six-component tensor storage, exact transform/crop reuse keys, and a CPU catalog/workspace that reuses unique kernels across refreshes; \(L\) forward/\(L^2\) pair/\(L\) inverse work and separate CPU/CUDA qualification gates remain explicit. Source presence is not device proof.

BORIS PBC and reconfiguration

BORIS applies shared PBC images and rebuilds modules after mesh/count/mode changes; Fullmag currently accepts only open boundaries and replans from topology fingerprints.

BORIS AFM/atomistic participation

Fullmag’s public contract is named ferromagnetic FDM objects only; antiferromagnetic and atomistic transfer semantics remain a separate scope gap.

Airbox and UI

Target-only Airbox is not the common transform grid; Explorer/viewport expose only scoped native-layer or Airbox resources and fail closed when unavailable.

Inspect the realized meshes

When the versioned multilayer-layout resource is available, its current Explorer integration may expose the following diagnostics under Mesh:

  • Common Convolution Grid can show shape, cell size, origin, FFT shape, and provenance. Its Inspector identifies it as diagnostic FFT scratch, not a physical mesh.

  • Native Layers can contain one node per named magnet. Where published, layer diagnostics expose the realized carrier, active/inactive counts, identity/push_pull, layout fingerprint, and revisions.

  • The current Explorer omits layout-specific nodes when their layout resource has available=false; it does not synthesize a common/native grid or a single-grid fallback. A caller must inspect the resource’s reason or degraded payload rather than infer a mesh from missing nodes.

Inspect and display target-only Airbox H_demag

When a validated runtime carrier exists and the Airbox target resource is published, Explorer may add Multilayer H_demag target. Its available Inspector data can include target cells, origin, cell size, sample/value counts, carrier fingerprint, layout/observation revisions, source-grid fingerprints, and runtime identity. A missing resource is not a UI failure and does not authorize a synthetic target; where published, H_demag is available and H_eff retains its unavailable reason.

The viewport requests quantity_id=H_demag with scope_kind=airbox and scope_id=airbox. It accepts only FMVP v3 data with the target carrier fingerprint, matching domain generation, exact grid shape, three components, complete explicit cell indices, and exact sample/value counts. Mismatched data is discarded; it is never replaced with the common FFT scratch field.

Use the Visualization controls to enable the target, bounds, wireframe, points, vectors, or shader as available. Airbox bounds/wireframe prove the target extent; points/vectors prove field samples. A valid source contract or React test is not visual qualification. Fresh qualification requires a post-integration compute_fields, visible canvas, gl.isContextLost() == false, non-zero drawing buffer, verified field requests/responses, and separate screenshots for each claimed display mode.

Runtime resource boundary

The layout resource may publish availability from the resolved plan and/or an artifact and may report missing parts through reason and degraded payloads. This availability contract is separate from the target-only Airbox carrier. Native-layer and Airbox field vectors remain scoped binary data-plane resources. The strong fail-closed contract applies to the target-only Airbox: invalid target metadata, a mismatched fingerprint, an unsupported quantity, or non-CPU-FP64 provenance must not produce a substitute carrier.

Validation checklist

Before treating a configuration as executable, verify:

  • every per_magnet name matches an authored magnet;

  • the planner’s common scratch envelope contains every native XY rectangle; layers do not overlap along Z;

  • two_d_stack layers each have one native Z cell;

  • the common-grid field matches the mode and is within the planner memory budget;

  • Demag is enabled and requested/resolved strategies are visible in provenance;

  • every native layer has the expected fingerprint, mask, transfer kind, and sample coverage;

  • any Airbox carrier reports CPU FP64 runtime origin, target_only=true, H_demag only, and matching field/layout fingerprints;

  • GPU claims include a fresh managed device execution receipt; UI claims include a fresh WebGL receipt as described above.

Limitations

The public constructors describe more combinations than are production-qualified. The common grid is not a mesh authoring surface. The target-only Airbox is currently CPU FP64 post-processing, not a hot-loop field carrier, and publishes no H_eff. Its runtime-metadata request is deliberately strict and is not a general arbitrary-observation-grid API. Periodic multilayer execution and the capability-gated physics listed under assumptions remain unavailable. Fresh browser/WebGL evidence for every Airbox display mode and fresh managed CUDA parity are separate release gates.

Scientific bibliography

The physical derivation and primary literature are collected on FDM multilayer demagnetizing-field convolution. This guide uses the repository implementation and tests as the source of truth for public API, ProblemIR, planner, runtime-resource, and UI behavior.

Source-code index

Claim

Path

Stable symbol

Responsibility

Lane and evidence

Native cell constructor and lowering

packages/fullmag-py/src/fullmag/model/discretization.py

class FDMGrid

validates one layer’s cell size and serializes it

Python/IR tests

Demag policy and removed fallback

packages/fullmag-py/src/fullmag/model/discretization.py

class FDMDemag

strategy, mode, common grid, validation, lowering

Python/IR tests

Global physical Demag term

packages/fullmag-py/src/fullmag/model/energy.py

class Demag

physical energy-term configuration, separate from FDM policy

Python authoring tests

Study authoring split

packages/fullmag-py/src/fullmag/world.py

class StudyBuilder (fdm, demag)

independently accepts the global interaction and FDM discretization policy

Python authoring tests

Complete FDM hint container

packages/fullmag-py/src/fullmag/model/discretization.py

class FDM

default/native grids and boundary policy

Python/UI round-trip tests

Generated stage-first Python

packages/fullmag-py/src/fullmag/runtime/script_builder.py

render_loaded_problem_as_script

emits independent study.demag(...), per-object mesh, and common-universe mesh calls from canonical state

script-builder tests

Kernel reuse identity

crates/fullmag-fdm-demag/src/descriptors.rs

from_pair_with_layout

builds KernelReuseKey from oriented shifts, source/destination cell sizes, exact transform shape, padding, and crop

unit tests

Per-magnet local validation

packages/fullmag-py/src/fullmag/model/discretization.py

FDM.__init__

rejects empty names and non-FDMGrid values; matching names to authored geometry is planner validation

Python/planner tests

Resolved multilayer plan

crates/fullmag-plan/src/fdm.rs

plan_fdm_multilayer

geometry eligibility, mode/grid resolution, transfer, certificate, provenance

planner tests

Topology-bound identity

crates/fullmag-ir/src/mesh_hints.rs

fdm_multilayer_topology_tokens

hashes mode, layer/object identity, native layout, mask, convolution layout, and transfer

IR migration/validation tests

Optional Airbox carrier

crates/fullmag-runner/src/fdm/cpu/multilayer_reference.rs

execute_reference_fdm_multilayer

CPU FP64 multilayer runner; optional target-only H_demag is a scoped post-run extension

runner unit tests and local numerical evidence

UI scene lowering and validation

apps/control-room/src/modules/inspector/panels/StudyGlobalAuthoringModel.ts

buildStudyGlobalMergePatch

maps Inspector fields to the canonical scene merge patch

frontend model tests

Explorer node omission boundary

apps/control-room/src/modules/explorer/builders/buildModelTree.ts

buildModelTree

the committed tree has no fabricated multilayer layout node when no available layout is supplied

Explorer tests

Layer/common/Airbox Inspector

apps/control-room/src/modules/inspector/panels/StudyGlobalAuthoringModel.ts

createStudyGlobalDraft

reads committed study values into the Inspector draft; detailed layout facts are scoped extensions

Inspector tests

Dedicated target-only Airbox Inspector

apps/control-room/src/modules/viewport-3d/viewport3dDomainAdapter.ts

adaptFdmDomainPresentation

adapts the committed FDM presentation carrier; target capability and provenance remain scoped

Inspector tests

Versioned layout resource

crates/fullmag-api/src/router_v2/handlers/data/domain.rs

fdm_grid_descriptor

provides the committed FDM domain metadata base for native/common/Airbox exposure

API v2 tests

Native layer viewport domains

apps/control-room/src/modules/viewport-3d/viewport3dDomainAdapter.ts

adaptFdmDomainMeta

creates the committed FDM render carrier used for separate native-layer targets

viewport adapter tests

Scoped Airbox field request

apps/control-room/src/modules/viewport-3d/viewport3dDomainAdapter.ts

adaptFdmDomainPresentation

adapts the committed FDM presentation carrier used for target-scoped H_demag

viewport field tests

Multilayer layout resource

crates/fullmag-api/src/router_v2/handlers/data/domain.rs

fdm_multilayer_layout_resource

publishes availability, explicit reason, native layers, and computational common-transform metadata

API v2 tests

Native multilayer viewport domains

apps/control-room/src/modules/viewport-3d/viewport3dDomainAdapter.ts

adaptFdmMultilayerNativeLayerDomains

adapts physical native-layer carriers and never projects the common scratch grid

viewport adapter tests

Target-only multilayer Airbox domain

apps/control-room/src/modules/viewport-3d/viewport3dDomainAdapter.ts

adaptFdmMultilayerAirboxDomain

validates target-only metadata, H_demag availability, and unavailable H_eff

viewport field tests; no fresh browser proof