FDM multilayer demagnetizing-field convolution

Last changes: Documentation changelog

This page describes the physics, discretization, and public configuration contract for multilayer_convolution. The method computes the demagnetizing field of disconnected magnetic layers or objects on separate FDM grids. It is not a FEM Poisson or BEM model; choosing this strategy changes the numerical realization but does not change the physical definition of the demagnetizing field.

Each magnetic object owns a native FDM grid. The common convolution grid is an FFT supercell used for pair kernels and transfers; it is neither a material mesh nor a FEM universe mesh. Geometry translations determine layer offsets, including the signed \(z\) offsets used by the kernels. A public FDM multilayer script uses named geometry and per-object mesh(cell_size=...) calls; study.universe.mesh(cell_size=...) defines the common computational-grid resolution when it cannot be inferred, and study.demag() enables the physical interaction.

The partial status is intentional. FDM CPU FP64 has local field, energy, reciprocity, and transfer evidence for the stated case classes. CUDA sources and the ABI contract are implemented, but without a fresh, complete device comparison the GPU lane must not be called production-qualified.

1. Physical problem

Consider \(L\) disconnected ferromagnetic objects. Index \(s\) denotes a source layer and \(d\) a destination layer. Each layer has its own regular native_grid, cell size \(\mathbf h_s\), origin \(\mathbf o_s\), active mask, and magnetization field \(\mathbf M_s\). The only permitted pair-offset convention is \(\boldsymbol\delta_{d,s}=\mathbf o_d-\mathbf o_s\).

The field in a destination layer is the sum of its self contribution and all inter-layer contributions. FFT convolution accelerates this sum; it does not replace the magnetostatic tensor with a local approximation. The scratch_grid is a computational tool. Physical position, source-cell size, and destination-cell size remain part of the kernel.

2. Governing equations

2.1. Continuous model and discrete pair sum

The magnetostatic field is defined by

(1)\[\mathbf H(\mathbf r) =-\int_{\Omega_m}\mathcal N(\mathbf r-\mathbf r') \mathbf M(\mathbf r')\,\mathrm dV'.\]

The implemented FDM contract is a directed source-to-destination pair sum corresponding to equation (3) of Lepadatu (2019):

(2)\[\mathbf H_{d,l} =-\sum_{s=1}^{L}\sum_{\mathbf r_{s,j}\in V_s} \mathsf N\!\left( \mathbf r_{d,l}-\mathbf r_{s,j},\mathbf h_d,\mathbf h_s \right)\mathbf M(\mathbf r_{s,j}).\]

The tensor \(\mathsf N\) has six independent components: \(N_{xx}\), \(N_{yy}\), \(N_{zz}\), \(N_{xy}\), \(N_{xz}\), and \(N_{yz}\). The minus sign belongs to the field definition. Tensor-vector multiplication in the FFT domain accumulates the product without that sign, and the field stage applies the negation exactly once.

2.2. Reciprocity and energy

For different cell volumes, reciprocity is volume-weighted:

(3)\[V_d\,\mathsf N_{d\leftarrow s}(\mathbf q) =V_s\,\mathsf N_{s\leftarrow d}^{\mathsf T}(-\mathbf q).\]

Simple equality of the two directions is valid only when \(V_d=V_s\). The demagnetization energy over active cells in all layers is

(4)\[E_{\mathrm d} =-\frac{\mu_0}{2}\sum_{d=1}^{L} \sum_{c\in\mathcal A_d}V_{d,c}\, \mathbf M_{d,c}\mathbin\cdot\mathbf H_{d,c}.\]

The factor \(1/2\) removes double counting of pair energy. The field, active mask, volumes, and precision used by the energy reduction must match the field path.

2.3. FFT convolution

Each source layer is transformed once, each ordered pair accumulates a six-component tensor product, and each destination receives one inverse transform:

(5)\[\widehat{\mathbf H}_d(\mathbf k) =-\sum_{s=1}^{L} \widehat{\mathsf N}_{d\leftarrow s}(\mathbf k) \widehat{\mathbf M}_s(\mathbf k), \qquad \mathbf H_d=\mathcal F^{-1}\!\left[\widehat{\mathbf H}_d\right].\]

One complete operator refresh for \(L\) layers therefore has \(L\) forward transforms, \(L\) inverse transforms, and \(L^2\) pair accumulations. These counters describe the demagnetization operator, not automatically the residency of the complete time integrator.

2.4. Transfer between native_grid and scratch_grid

When native and scratch grids differ, magnetization is transferred by operator \(P\):

(6)\[\mathbf M(\mathbf r')=\sum_{i\in\mathcal P}w_i\mathbf M(\mathbf r_i).\]

The weights from equations (4)-(5) of Lepadatu are

(7)\[w_i=\frac{\widetilde d_i\delta_i}{\widetilde d_T}, \qquad \widetilde d_T=\sum_{i\in\mathcal P}\widetilde d_i\delta_i, \qquad \widetilde d_i= \frac{\lvert\mathbf h'+\mathbf h\rvert}{2} -\lvert\mathbf r'-\mathbf r_i\rvert.\]

Returning the field to a native grid must use the volume-adjoint \(P^*\):

(8)\[\left\langle P\mathbf M,\mathbf H_c\right\rangle_{V_c} =\left\langle\mathbf M,P^*\mathbf H_c\right\rangle_{V_n}.\]

This identity is the work and energy conservation condition. Pointwise field interpolation alone is not sufficient evidence of a correct transfer.

2.5. Irregular Newell tensor for unequal Z thickness

For common \(h_x,h_y\) and different \(h_{s,z},h_{d,z}\), Appendix A of the publication defines

(9)\[N_{xx}(\mathbf s)= \mathcal L[f;\mathbf h_s,\mathbf h_d](\mathbf s), \qquad N_{xy}(\mathbf s)= \mathcal L[g;\mathbf h_s,\mathbf h_d](\mathbf s).\]
(10)\[\begin{split}\begin{aligned} \mathcal L[w;\mathbf h_s,\mathbf h_d](\mathbf s) =\frac{1}{\tau} \sum_{\epsilon_1,\epsilon_2=-1}^{1} (-1)^{|\epsilon_1|+|\epsilon_2|} \bigl[&-w(x+\epsilon_1h_x,y+\epsilon_2h_y,z-h_{s,z})\\ &-w(x+\epsilon_1h_x,y+\epsilon_2h_y,z+h_{d,z})\\ &+w(x+\epsilon_1h_x,y+\epsilon_2h_y,z)\\ &+w(x+\epsilon_1h_x,y+\epsilon_2h_y,z-\Delta)\bigr]. \end{aligned}\end{split}\]
(11)\[\begin{split}\begin{aligned} R^2&=x^2+y^2+z^2, &\tau&=\pi h_xh_yh_{d,z}, &\Delta&=h_{s,z}-h_{d,z},\\ f(x,y,z)&=\frac{(2x^2-y^2-z^2)R}{6} +\frac{y(z^2-x^2)}{4} \ln\!\left(1+\frac{2y(y+R)}{x^2+z^2}\right)\\ &\quad+\frac{z(y^2-x^2)}{4} \ln\!\left(1+\frac{2z(z+R)}{x^2+y^2}\right) -xyz\arctan\!\frac{yz}{xR}. \end{aligned}\end{split}\]
(12)\[\begin{split}\begin{aligned} g(x,y,z)&=-\frac{xyR}{3} -\frac{z^3}{6}\arctan\!\frac{xy}{zR} -\frac{zy^2}{2}\arctan\!\frac{xz}{yR} -\frac{zx^2}{2}\arctan\!\frac{yz}{xR}\\ &\quad+\frac{y(3z^2-y^2)}{12} \ln\!\left(1+\frac{2x(x+R)}{y^2+z^2}\right) +\frac{x(3z^2-x^2)}{12} \ln\!\left(1+\frac{2y(y+R)}{x^2+z^2}\right)\\ &\quad+\frac{xyz}{2} \ln\!\left(1+\frac{2z(z+R)}{x^2+y^2}\right). \end{aligned}\end{split}\]

The remaining components follow by axis permutations consistent with Newell-tensor symmetry. Appendix A covers unequal Z thickness with a common XY cell size; it does not justify arbitrary XY offsets or arbitrary, different XY grids.

3. Symbols and SI units

Symbol

Meaning

SI unit

\(L\)

number of magnetic layers

\(1\)

\(d,s\)

destination and source layer indices

\(1\)

\(l,j,c,i\)

cell, component, or transfer-point indices

\(1\)

\(\Omega_m\)

magnetic part of the domain

\(\mathrm{m^3}\)

\(V_s\)

source domain or source-cell volume, according to the sum context

\(\mathrm{m^3}\)

\(V_d\)

destination-cell volume

\(\mathrm{m^3}\)

\(V_{d,c}\)

volume of active cell \(c\) in destination layer \(d\)

\(\mathrm{m^3}\)

\(V_c\)

convolution-cell volume

\(\mathrm{m^3}\)

\(V_n\)

native-cell volume

\(\mathrm{m^3}\)

\(\mathbf r,\mathbf r'\)

observation and source positions in the continuous model

\(\mathrm m\)

\(\mathbf r_{d,l}\)

destination-cell center

\(\mathrm m\)

\(\mathbf r_{s,j}\)

source-cell center

\(\mathrm m\)

\(\mathbf r_i\)

input-cell center for transfer

\(\mathrm m\)

\(\mathbf o_d,\mathbf o_s\)

destination and source grid origins

\(\mathrm m\)

\(\boldsymbol\delta_{d,s}\)

offset \(\mathbf o_d-\mathbf o_s\)

\(\mathrm m\)

\(\mathbf q\)

spatial kernel lag

\(\mathrm m\)

\(\mathbf s=(x,y,z)\)

spatial argument of the Appendix A operator

\(\mathrm m\)

\(x,y,z\)

coordinates of the kernel argument

\(\mathrm m\)

\(R\)

distance \(\sqrt{x^2+y^2+z^2}\)

\(\mathrm m\)

\(\mathbf h_s,\mathbf h_d\)

source and destination cell sizes

\(\mathrm m\)

\(\mathbf h,\mathbf h'\)

input and scratch transfer-cell sizes

\(\mathrm m\)

\(h_x,h_y\)

common cell sizes along X and Y

\(\mathrm m\)

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

source and destination cell thicknesses

\(\mathrm m\)

\(\Delta\)

difference \(h_{s,z}-h_{d,z}\)

\(\mathrm m\)

\(\tau\)

normalization \(\pi h_xh_yh_{d,z}\)

\(\mathrm{m^3}\)

\(\mathbf M,\mathbf M_s,\mathbf M_{d,c}\)

magnetization

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

\(\mathbf H,\mathbf H_d,\mathbf H_{d,c},\mathbf H_c\)

magnetostatic or demagnetizing field

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

\(\widehat{\mathbf M}_s\)

discrete transform of source magnetization

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

\(\widehat{\mathbf H}_d\)

discrete transform of the destination field

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

\(\mathcal N\)

continuous magnetostatic kernel

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

\(\mathsf N,\mathsf N_{d\leftarrow s}\)

discrete cell-pair demagnetizing tensor

\(1\)

\(\widehat{\mathsf N}_{d\leftarrow s}\)

discrete transform of the pair tensor

\(1\)

\(N_{xx},N_{yy},N_{zz},N_{xy},N_{xz},N_{yz}\)

six independent tensor components

\(1\)

\(\mathcal F,\mathcal F^{-1}\)

discrete Fourier transform and inverse

\(1\)

\(\mathbf k\)

discrete-transform index or wave vector

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

\(P,P^*\)

native-to-scratch transfer and volume adjoint

\(1\)

\(\mathcal P\)

set of cells participating in transfer

\(1\)

\(w_i\)

normalized transfer weight

\(1\)

\(\delta_i\)

cell-overlap indicator

\(1\)

\(\widetilde d_i,\widetilde d_T\)

weighted distance and its sum

\(\mathrm m\)

\(\mathcal A_d\)

active-cell set of layer \(d\)

\(1\)

\(E_{\mathrm d}\)

demagnetization energy

\(\mathrm J\)

\(\mu_0\)

vacuum permeability

\(\mathrm{N\,A^{-2}}\)

\(\mathcal L\)

irregular Newell corner operator

\(1\)

\(f,g,w\)

Appendix A basis functions

\(\mathrm{m^3}\)

\(\epsilon_1,\epsilon_2\)

corner-sum indices

\(1\)

4. Assumptions, kernel classes, and validity limits

The current public planner accepts disconnected objects with different XY extents and/or centers by forming the union of their native XY bounds as a computational common-scratch envelope. Native origins, cell sizes, masks, and material objects remain independent; layers that do not coincide with that envelope use explicit push_pull transfer. An explicitly requested common_cells or common_cells_xy must contain the union and have a compatible resolved pitch; a lane that cannot consume the resulting insertion/crop or transfer descriptor fails closed. This is not the same as evaluating the irregular Newell formula on arbitrary different XY cells: that formula is only the unequal-Z/common-XY kernel, while lateral differences are handled by the transfer path. Layers may be separated by arbitrary non-overlapping Z gaps, but overlapping bodies and periodic axes fail closed until the corresponding pair, transfer, and exchange-seam classes are qualified.

two_d_stack is intended for thin layers with one native Z cell. A layer with multiple Z cells is rejected: there is no public moment-preserving Z average today, and the planner does not copy an arbitrary slice. Select three_d instead. common_cells_xy=(N_x,N_y) resolves a scratch grid \((N_x,N_y,1)\); common_cells=(N_x,N_y,N_z) selects a full 3-D grid. two_d_stack is a Fullmag mode, not a spelling for BORIS 2dmulticonvolution=1 or =2: those BORIS modes remain distinct, unsupported semantics. If both common_cells fields are absent, Fullmag applies planner-auto common-scratch selection and records the resolved layout in the plan/provenance; the authored ProblemIR contains no common_cells* fields. This absence is not an alias for BORIS ncommonstatus=false, whose largest-mesh default is a different policy.

The symmetry classes in Lepadatu Table I determine the legal spectral representation:

Class

Geometry

Spectral representation and storage

Fullmag status

2D-self

one Z cell, no shift

real diagonal and XY components, reduced

locally verified CPU FP64; no production qualification

3D-self

common cell size

real, reduced

small L=3 local oracle; no independent managed receipt

2D-zShift

common XY, pure Z shift

real diagonal/XY, imaginary XZ/YZ, reduced

locally verified CPU FP64 for both Z signs

3D-zShift

common cell, pure Z shift

complex, reduced

small local oracle; no complete production matrix

2D-full

geometry without shift-only parity

complex, full

not an executable qualified lane

3D-full

general 3-D geometry

complex, full

not an executable qualified lane

Zero padding must provide at least \(n_{\mathrm{src}}+n_{\mathrm{dst}}-1\) samples on each axis for a linear convolution. The transform descriptor separates physical grids from fft_shape, insertion offsets, lag-zero position, and destination crop. The inverse transform applies \(1/(F_xF_yF_z)\) exactly once.

5. Python API

5.1. Complete parameter table

The canonical interface separates the physical interaction from its numerical realization. Mesh calls carry geometric resolution, study.demag() enables the interaction, and the planner selects the qualified numerical realization. The FDM* rows document migration adapters only.

Python parameter

Type

Default

SI unit

Validation

Meaning

Backend support

ProblemIR

body.mesh(cell_size=...)

Sequence[float]

required unless a default exists

\(\mathrm m\)

Exactly three finite positive values; object extents must divide exactly.

Native Cartesian cell size of one magnetic object.

FDM CPU/GPU authoring; runtime lane gated.

backend_policy.discretization_hints.fdm.per_magnet.<object>.cell

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

Sequence[float]

None

\(\mathrm m\)

Exactly three finite positive values.

Default native cell size for objects without overrides.

FDM CPU/GPU authoring.

backend_policy.discretization_hints.fdm.default_cell

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

Sequence[float]

required for unequal native grids

\(\mathrm m\)

Exactly three finite positive values; common extents must divide exactly.

Requested non-physical common convolution-grid resolution.

FDM multilayer CPU/GPU authoring; runtime lane gated.

backend_policy.discretization_hints.fdm.demag.common_cell_size

FDMGrid.cell

Sequence[float]

required

\(\mathrm m\)

Exactly three finite, positive values.

Native cell size of one named magnet.

FDM CPU/GPU authoring; execution remains lane-gated.

backend_policy.discretization_hints.fdm.per_magnet.<name>.cell

FDM.cell

Sequence[float] | None

None

\(\mathrm m\)

Exactly three positive values; cannot be supplied with default_cell.

Backward-compatible alias for the default cell size.

FDM CPU/GPU authoring.

backend_policy.discretization_hints.fdm.cell and normalized default_cell

FDM.default_cell

Sequence[float] | None

None

\(\mathrm m\)

Exactly three positive values; required when the per-magnet map is incomplete.

Default native cell size.

FDM CPU/GPU authoring.

backend_policy.discretization_hints.fdm.default_cell

FDM.per_magnet

dict[str,FDMGrid] | None

None

\(1\)

Keys are non-empty names; values must be FDMGrid.

Native-grid overrides for named magnets.

FDM multilayer CPU/GPU authoring.

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.

Demagnetizing-field realization policy.

FDM CPU/GPU authoring.

backend_policy.discretization_hints.fdm.demag

FDMDemag.strategy

Literal[str]

auto

\(1\)

auto, single_grid, or multilayer_convolution.

Requested strategy; an explicit multilayer request cannot silently fall back to single grid.

FDM CPU/GPU authoring; runtime qualified per lane.

backend_policy.discretization_hints.fdm.demag.strategy

FDMDemag.mode

Literal[str]

auto

\(1\)

auto, two_d_stack, or three_d.

Requested mode; auto is resolved by the planner after layer geometry is known.

FDM CPU/GPU authoring.

backend_policy.discretization_hints.fdm.demag.mode

FDMDemag.common_cells

tuple[int,int,int] | None

None

\(1\)

Three positive integers; mutually exclusive with common_cells_xy and two_d_stack.

Explicit full 3-D scratch-grid size.

FDM CPU/GPU authoring.

backend_policy.discretization_hints.fdm.demag.common_cells

FDMDemag.common_cells_xy

tuple[int,int] | None

None

\(1\)

Two positive integers; mutually exclusive with common_cells and three_d.

Explicit in-plane scratch-grid size for a 2-D stack.

FDM CPU/GPU authoring.

backend_policy.discretization_hints.fdm.demag.common_cells_xy

FDMDemag.explain

bool

True

\(1\)

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

Requests a readable plan explanation; it is not physical data and is not serialized by to_ir().

FDM authoring helper.

not serialized

FDMDemag.allow_single_grid_fallback

bool | None

None

\(1\)

Any value other than None raises ValueError.

Removed compatibility switch; forbids silent fallback.

Unsupported combinations are rejected.

not serialized

boundary_correction, boundary_phi_floor, and boundary_delta_min belong to the general FDM partial-cell policy. They are not multilayer-convolution parameters and are not presented as FFT, padding, or transfer-accuracy controls. The current multilayer plan does not carry or reject non-neutral values and therefore does not fail closed, which is an open round-trip defect. Until their per-layer meaning is defined and validated, these inputs must not be used with multilayer convolution.

The current qualification boundary is stricter than source availability: CPU FP64 has scoped, local evidence. The declared push_pull operator is locally validated for different extents and \(V_{native}\ne V_{scratch}\); the missing proof is a direct continuum/native-cell oracle for \(h_{source,z}\ne h_{destination,z}\). CUDA-assisted execution for heterogeneous two_d_stack cases does not yet use the same descriptor pair operator as CPU, and no CUDA lane is runtime-verified or production-qualified.

5.2. Common XY versus full 3-D mode

two_d_stack is a thin-layer optimization. It is legal only when every magnetic object has one native cell through its thickness. The solver retains each layer’s world-space Z origin, but the common transform has one Z plane. It is therefore unsuitable when magnetization may vary through the thickness.

three_d retains multiple common cells along Z. The planner selects it whenever any native layer has more than one Z cell or when the author supplies all three components of study.universe.mesh(cell_size=...). This does not merge the magnets: native magnetization and field samples remain on each object’s mesh, while the common 3-D supercell is temporary FFT storage.

study.mode("strict") is an execution policy, not an accuracy preset. It forbids rounding a cell count, resizing geometry, silently changing the requested cell sizes, or falling back to an unqualified transfer/backend. A planned and qualified push_pull transfer is part of the selected method, so using it does not violate strict mode.

5.3. Heterogeneous native grids with a 3-D supercell

This example is the regression case exercised by the Python, planner, round-trip, and CPU reference tests. The lower magnet uses 2 nm x 2 nm x 10 nm cells, the upper magnet uses 5 nm x 5 nm x 10 nm cells, and the common convolution domain uses 2 nm x 2 nm x 2.5 nm cells.

import fullmag as fm

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

bottom = study.geometry(
    fm.Box(size=(100 * nm, 50 * nm, 10 * nm)),
    name="layer_bottom",
)
top = study.geometry(
    fm.Box(size=(100 * nm, 50 * nm, 10 * nm)).translate((0, 0, 20 * nm)),
    name="layer_top",
)

bottom.mesh(cell_size=(2 * nm, 2 * nm, 10 * nm))
top.mesh(cell_size=(5 * nm, 5 * nm, 10 * nm))
study.universe.mesh(cell_size=(2 * nm, 2 * nm, 2.5 * nm))

for layer in (bottom, top):
    layer.Ms = 800e3
    layer.Aex = 13e-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.stages.add_run(until=1e-13, stage_id="heterogeneous_run")

The common XY extent is 100 nm x 50 nm, so exact division gives 50 x 25 common cells. The common scratch thickness is the maximum native layer thickness, 10 nm, not the complete 30 nm world-space span between the bottom of the first layer and the top of the second. Layer separation is encoded in pair-kernel offsets. Therefore 10 nm / 2.5 nm = 4 and the resolved common transform shape is 50 x 25 x 4.

The lower native shape is 50 x 25 x 1; the upper native shape is 20 x 10 x 1. Because a 5 nm cell is not an integer multiple of a 2 nm common cell in XY, direct copying would be wrong. The planner selects push_pull: volume-overlap weights push magnetization to the common grid and the volume-adjoint pull maps the computed field back to each native grid. The CPU test checks that this real transfer executes, produces finite demagnetization energy, and preserves 29 native cells across the two reduced test layers.

5.4. Complete multilayer authoring example

The example is stage-first and uses SI units. Loading it verifies authoring and lowering; merely placing a stage in the script is not evidence that a native solver ran.

# %% Imports and study
import fullmag as fm

study = fm.study("fdm_multilayer_two_d_stack_example")
study.engine("fdm")
study.device("cpu", precision="double")
study.mode("strict")
study.interactive(False)

# %% Native cell size
cell = (4e-9, 4e-9, 3e-9)

# %% Domain, geometry, and material
study.universe(
    mode="manual",
    size=(40e-9, 24e-9, 30e-9),
    center=(0.0, 0.0, 4.5e-9),
    padding=(0.0, 0.0, 0.0),
)
bottom = study.geometry(
    fm.Box(size=(32e-9, 16e-9, 3e-9), name="layer_bottom_geom"),
    name="layer_bottom",
)
top = study.geometry(
    fm.Box(size=(32e-9, 16e-9, 3e-9), name="layer_top_geom").translate(
        (0.0, 0.0, 9e-9)
    ),
    name="layer_top",
)
bottom.mesh(cell_size=cell)
top.mesh(cell_size=cell)
study.universe.mesh(cell_size=cell)
for layer in (bottom, top):
    layer.Ms = 8e5
    layer.Aex = 13e-12
    layer.alpha = 0.02
    layer.m = fm.init.UniformMagnetization((1.0, 0.1, 0.0))

# %% Interactions, observables, and stage
study.exchange(enabled=True)
study.demag(enabled=True)
study.b_ext(-24.6e-3, 4.3e-3, 0.0)
study.save("H_demag", every=1e-12)
study.solver(fix_dt=1e-14, gamma=2.211e5)
study.tableautosave(
    1e-13,
    quantities=["step", "t", "mx", "my", "mz", "e_demag", "e_total"],
)
study.stages.add_run(until=1e-12, stage_id="multilayer_run")

5.5. When to use three_d

Set mode="three_d" and common_cells=(N_x,N_y,N_z) when at least one layer has multiple native Z cells or when through-thickness texture matters. Do not set common_cells_xy at the same time. For the simplest identity transfer, choose a common grid equal to every native grid. Different grids activate push_pull and require a separate transfer-error assessment.

5.6. Real test scenarios and interpretation

The cases below are copyable counterparts of the fixtures in tests/standard_problems/mumag/sp4/fdm/multilayer_convolution/. They are SP4-derived scenarios, not the canonical µMAG Standard Problem 4.

L=3, three_d, transfer identity

This case has three layers of size 31.25 nm × 15.625 nm × 6 nm, native cell (3.90625 nm, 3.90625 nm, 3 nm), and common grid (8, 4, 2). Every layer has the same grid, so the planner can use identity; Z translations remain part of the physical pair offset.

# %% L=3 identity fixture (corresponds to scenario_l3_identity_3d_small.py)
import fullmag as fm

CELL = (3.90625e-9, 3.90625e-9, 3e-9)
SIZE = (31.25e-9, 15.625e-9, 6e-9)
study = fm.study("fdm_multilayer_l3_identity_3d_small")
study.engine("fdm")
study.device("cpu", precision="double")
study.mode("strict")
study.universe(mode="manual", size=(40e-9, 20e-9, 36e-9),
               center=(0.0, 0.0, 12e-9), padding=(0.0, 0.0, 0.0))
for name, z in (("layer_bottom", 0.0), ("layer_middle", 12e-9),
                ("layer_top", 24e-9)):
    shape = fm.Box(size=SIZE).translate((0.0, 0.0, z))
    layer = study.geometry(shape, name=name)
    layer.mesh(cell_size=CELL)
    layer.Ms = 8e5
    layer.Aex = 1.3e-11
    layer.alpha = 0.02
    layer.m = fm.init.UniformMagnetization((0.9950371902099893,
                                             0.09950371902099893, 0.0))
study.universe.mesh(cell_size=CELL)
study.exchange(enabled=True)
study.demag(enabled=True)
study.stages.add_run(until=1e-14, stage_id="l3_identity_three_d_small")

The test test_l3_identity_three_d_scenario_preserves_common_identity_grid checks the exact lowered strategy, mode, common_cells, and three per_magnet entries. It does not measure fields; it is authoring and ProblemIR evidence.

L=2, unequal thickness through three_d

scenario_unequal_small.py uses a lower layer of height 3 nm, an upper layer of 6 nm, the same native cell, and common_cells=(16, 8, 2). The native Z counts are 1 and 2, respectively. This is the correct public way to encode through-thickness texture: do not force two_d_stack or pretend that a Z average was performed.

# %% Unequal-Z fixture (corresponds to scenario_unequal_small.py)
import fullmag as fm

cell = (3.90625e-9, 3.90625e-9, 3e-9)
study = fm.study("fdm_multilayer_unequal_z_small")
study.engine("fdm")
study.device("cpu", precision="double")
study.mode("strict")
study.universe(mode="manual", size=(64e-9, 32e-9, 24e-9),
               center=(0.0, 0.0, 7.5e-9), padding=(0.0, 0.0, 0.0))
bottom = study.geometry(
    fm.Box(size=(31.25e-9, 15.625e-9, 3e-9)), name="layer_bottom"
)
top_shape = fm.Box(size=(31.25e-9, 15.625e-9, 6e-9)).translate(
    (0.0, 0.0, 12e-9)
)
top = study.geometry(top_shape, name="layer_top")
bottom.mesh(cell_size=cell)
top.mesh(cell_size=cell)
study.universe.mesh(cell_size=cell)
for layer in (bottom, top):
    layer.Ms = 8e5
    layer.Aex = 1.3e-11
    layer.alpha = 0.02
    layer.m = fm.init.UniformMagnetization((0.9950371902099893,
                                             0.09950371902099893, 0.0))
study.exchange(enabled=True)
study.demag(enabled=True)
study.stages.add_run(until=1e-14, stage_id="l2_unequal_small")

Supercell and push_pull

In scenario_l3_heterogeneous_small.py, the layers have native Z counts 1/2/1 but share a working grid (16, 8, 2). This requires explicit native → scratch → native transfer; it does not create one ferromagnetic mesh covering all layers. The multilayer_engine tests also check that a regular stack of nine ordered pairs materializes five unique kernels and that an irregular stack does not perform forbidden reuse.

The small descriptor test uses simpler numbers: source [3,2,1], target [5,4,1], hence linear extent [7,5,1]; crop and insertion offset are stored separately. CommonTransformLayout has physical_mesh=false. A field in this scratch grid is not an observable material field and must not be rendered as a layer.

Test

Result on current master

Interpretation

descriptors.rs — layout and linear extent

19/19

supercell, mask, crop, padding, and reuse contract; no field proof

irregular_shifted_kernel.rs

7/7

GL8 for unequal \(h_z\), separate parity for \(+z/-z\) offsets, inverse FFT, reciprocity, and unequal-XY fail-closed behavior

shifted_newell_oracle.rs

7/7

independent cubature, parity, and bounded far-field

fullmag-engine multilayer

16/16 (one benchmark ignored)

CPU catalog/workspace and transfer contracts

fullmag-plan multilayer

25/25

planner mode, identity/push-pull, PBC, and unsupported interactions

fullmag-fdm-demag transfer unit tests

4/4 (filter volume_weighted_transfer)

Z moment, masked adjointness, reused buffers, and fail-closed PBC

Python fixture tests

21/21

stage-first authoring, lowering, and fail-closed API; no field parity

These results are contract tests and local oracles. They do not promote CUDA to runtime-verified: the current CUDA-assisted heterogeneous path does not use the same descriptor pair operator as CPU, and the complete step remains host-authoritative. For unequal native-cell thicknesses, an independent continuum/native-cell oracle for composed transfer is still missing.

6. ProblemIR, planner, and provenance

FDMGrid.to_ir() normalizes a cell tuple to an SI list. FDMDemag.to_ir() writes only the requested strategy, requested mode, and optional common layout. explain does not change physics and does not enter ProblemIR.

The following fragment is the actual serialized shape for an \(L=3\) scenario with mode="three_d":

{
  "backend_policy": {
    "discretization_hints": {
      "fdm": {
        "cell": [3.90625e-09, 3.90625e-09, 3e-09],
        "default_cell": [3.90625e-09, 3.90625e-09, 3e-09],
        "per_magnet": {
          "layer_bottom": {"cell": [3.90625e-09, 3.90625e-09, 3e-09]},
          "layer_middle": {"cell": [3.90625e-09, 3.90625e-09, 3e-09]},
          "layer_top": {"cell": [3.90625e-09, 3.90625e-09, 3e-09]}
        },
        "demag": {
          "strategy": "multilayer_convolution",
          "mode": "three_d",
          "common_cells": [16, 8, 2]
        }
      }
    }
  }
}

The planner creates one FdmLayerPlanIR per object and one FdmMultilayerPlanIR for the realization. Each layer contains stable layer_id, object_id, native grid, origin, mask, scratch grid, and transfer_kind. planner_summary preserves requested_strategy, selected_strategy, requested_mode, resolved_mode, eligibility, and estimates of kernel count and memory.

6.1. UI authoring → generated Python → ProblemIR

The Control Room does not invent a second FDM model. The authoring chain is explicit:

Stage

Canonical implementation

Mapping

UI draft

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

Inspector fields study.fdm.default_cell, study.fdm.per_magnet, study.fdm.demag, and the separate study.demag_enabled become one scene merge patch.

Generated Python

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

The patch is rendered as per-object mesh(cell_size=...), optional study.universe.mesh(cell_size=...), and an independent study.demag(enabled=True) call.

Per-magnet identity

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

The geometry name is the lookup key; it is not a mesh or a generated alias.

Python lowering

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

FDMGrid.cell, default cell, per-magnet grids, and demag policy lower under backend_policy.discretization_hints.fdm.

Resolution

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

The planner resolves mode, origins, common transform layout, transfer kind, pair keys, and eligibility without overwriting authored intent.

common_transform_layout is an API resource describing FFT scratch. It is not a physical mesh, material body, FEM universe mesh, or field fallback. The public API route is GET /v2/sessions/current/data/domain/fdm-multilayer-layout; unavailable layouts return an explicit reason. The Explorer omits layout-specific nodes when available=false rather than synthesizing a mesh. Native layer fields use layer/object scopes; the target-only Airbox uses airbox; no field request projects a common transform layout.

For every layer declaring active_mask_present, the native occupancy is a revisioned FMBM v1 binary resource at GET /v2/sessions/current/data/domain/fdm-multilayer-layers/{layer_id}/active-mask. Its header binds native shape, layout revision, grid fingerprint, and packed-mask hash. The client decoder and resource hook reject an absent declaration or any identity mismatch, so a declared native grid never fabricates a physical active-cell mask.

7. Round-trip and failure semantics

requested intent is the authored contract: strategy, mode, per-magnet cells, common layout, device, and precision. resolved execution is the planner/runtime decision: actual mode, grids, transfers, padding, FFT backend, device, and operator counters. UI export preserves requested intent through public mesh-authoring calls plus study.demag(); it does not export multilayer as a FEM realization.

validation errors are returned for invalid enums, non-positive sizes, simultaneous common_cells and common_cells_xy, mode/layout mismatches, missing per-magnet cells, overlapping layers, an explicit common grid that cannot contain the union of native XY rectangles, unsupported transfer/boundary combinations, and periodicity. unsupported combinations must be rejected; the planner cannot silently change strategy, device, precision, boundary conditions, or remove an interaction.

Runtime artifacts must separate requested/resolved demag realization, transfer telemetry, and CUDA stage telemetry. CUDA L/L/L² counters prove the shape of one device demag refresh, not that the complete integrator was device-resident.

8. Backend realizations

Solver

Device

Status

What is implemented

What the status does not prove

FDM

CPU

reference-executable, not production-qualified

FP64, FFT, six-component pairs, identity and push/pull, field and energy; local 2-D/3-D oracles and scoped Airbox convergence.

Does not automatically qualify full-complex, PBC, or every size and offset.

FDM

GPU

implemented, runtime-unqualified

ABI v2, D-07 plan, cuFFT workspace, and stage telemetry counters exist in source.

Build and ABI contract do not replace fresh executed-device field/energy parity; FP32 has separate thresholds.

FEM

CPU

not-applicable

None: this method is Newell/FFT Cartesian convolution on FDM grids.

It does not describe Poisson on an Airbox or FEM-BEM.

FEM

GPU

not-applicable

None for the same physical/numerical reason; FEM GPU has separate magnetostatic realizations.

multilayer_convolution cannot be selected as a FEM realization.

8.1. FDM CPU

CPU FP64 is the reference execution lane. MultilayerDemagRuntime clears each destination spectrum, sums all sources, performs the inverse FFT, and pulls the field back to the native grid. The 2-D lane uses the exact Newell corner sum. General 3-D has an explicitly bounded asymptotic branch for distant pairs; the oracle scope must therefore be reported with every result.

8.2. FDM CUDA

The native v2 plan stores layer and pair descriptors, creates a compute stream, and prepares cuFFT workspace. An identity common grid may use device-side D-07; a heterogeneous path may retain host-authoritative orchestration. Provenance must report that distinction instead of calling the whole run device-resident.

9. Enable and control the method in the UI

  1. Open the Study module in the unified workspace and select the study’s global Explorer node to open its Inspector.

  2. Set Engine to FDM, Requested device to CPU, CUDA, or Auto, Requested precision to Double or Single, and keep Mode=Strict when fallback is forbidden.

  3. Enable Demag enabled. In FDM demag, select FDM multilayer convolution.

  4. Enter dx, dy, dz in metres under FDM default cell. Under FDM per-magnet grids, enter JSON keyed by exact magnet names, for example {"layer_bottom":{"cell":[4e-9,4e-9,3e-9]}}.

  5. For thin, one-cell layers select FDM demag mode = 2-D stack and enter Nx, Ny under Common convolution cells XY. Leave Common convolution cells empty.

  6. For full 3-D select 3-D and enter Nx, Ny, Nz under Common convolution cells. Leave the XY field empty. Positive integers are required.

  7. Enable Explain FDM demag plan to retain a readable planner explanation, then apply the draft; the UI validator rejects contradictory parameter pairs.

After materialization, Explorer shows each native layer target as fdm-native-layer:<layer-id>. If a target-only Airbox is published, it appears as a separate target. Select a layer or Airbox and request quantity H_demag; Airbox H_eff is explicitly unavailable and must not be synthesized by the UI.

The viewport supports layer solids, bounds, wireframe, points, and field vectors. A full Airbox wireframe also includes an interior bounds/volume overlay. A visible image is not by itself correctness evidence: qualification requires a fresh compute_fields, runtime-origin data, working WebGL, and a non-zero drawing buffer.

9.1. Stable implementation mapping

Responsibility

Path

Symbol

Lane

Python grid

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

class FDMGrid

Public authoring

Python demag policy

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

class FDMDemag

Public authoring

Python FDM wrapper

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

class FDM

Public authoring

ProblemIR validation

crates/fullmag-ir/src/mesh_hints.rs

FdmDemagHintsIR::validate

Authored and resolved FDM IR

Planner

crates/fullmag-plan/src/fdm.rs

plan_fdm_multilayer

FDM planner

CPU runtime

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

execute_reference_fdm_multilayer

FDM CPU FP64

CPU observation and energy

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

observe_multilayer

FDM CPU FP64

Push transfer

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

push_m_with_boundary_policy

FDM CPU transfer

Pull transfer

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

pull_h_with_boundary_policy

FDM CPU transfer

Newell diagonal primitive

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

newell_f

Kernel preparation

Newell cross primitive

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

newell_g

Kernel preparation

Shifted Newell builder

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

compute_newell_kernels_shifted

Shifted pair kernel

CUDA v2 plan creation

backends/fdm/api/c_api.cpp

fullmag_fdm_backend_create_v2

FDM CUDA

CUDA FFT workspace

backends/fdm/gpu/cuda/runtime/context.cu

context_prepare_multilayer_fft_workspace_v2

FDM CUDA

UI round-trip model

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

createStudyGlobalDraft

Control Room authoring

UI native-layer adapter

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

adaptFdmDomainMeta

Explorer/viewport

UI Airbox adapter

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

adaptFdmDomainPresentation

Explorer/viewport

10. Validation and current evidence status

Statuses are disjoint: implemented means code is present, executable means the contract can run, runtime-verified means a fresh execution, physically-validated means an independent oracle, and production-qualified means a complete evidence matrix. A lower status does not inherit a higher one.

Scope

Evidence

Status

CPU 2D-self FP64

Complete L=1 field, energy, reciprocity, cubature, and self-trace

locally physically-validated; not production-qualified

CPU 2D-zShift FP64

Complete L=2 field for both Z signs, energy, and weighted reciprocity

locally physically-validated; not production-qualified

CPU 3D identity FP64

Small L=3 field, energy, reciprocity, self-trace, and cubature

locally physically-validated; no independent managed receipt

CPU push/pull FP64

Transfer moment/adjoint unit contracts plus local equal-thickness field/energy cases

locally physically-validated in the stated scope; no unequal-native-cell continuum oracle

CPU target-only Airbox

160×40×18 versus 160×40×24 convergence at common centers

locally runtime-verified and physically-validated for this mesh pair

CUDA FP64

ABI v2 contract, plan creation, and static tests

implemented/executable contract; no fresh device parity

CUDA FP32

Source and runtime path

not runtime-verified and not physically-validated

UI/viewport

Round-trip, adapter, Explorer/Inspector, and render-model tests

contract-verified; no fresh post-integration browser/WebGL proof

The remaining independent qualification gate is full field coverage across all six tensor components and lag signs, energy, weighted reciprocity, and the composed unequal-native-cell transfer. The transfer unit tests cover moment and adjoint contracts, but comparing two paths that share the same kernel builder is not independent physical evidence.

11. Limitations

  • PBC, general XY offsets, and full-complex 2-D/3-D classes are not production-qualified.

  • The CPU descriptor path now has a kernel catalog and reusable FFT workspace; this closes an implementation gap, not the qualification gap for every BORIS kernel family or for CUDA.

  • two_d_stack cannot represent through-thickness texture without an explicit moment-preserving transfer; multi-cell Z fails closed.

  • Different XY cells require a transfer grid or rejection; Appendix A does not legalize an arbitrary XY difference.

  • CPU FP64 is the execution reference but does not replace independent analysis or cubature.

  • A CUDA build, cuFFT presence, and a valid ABI are not field/energy parity evidence on a concrete GPU.

  • Target-only Airbox publishes H_demag. H_eff outside magnetic support has a versioned unavailable reason and is not synthesized.

  • SP4-derived scenarios provide traceability and do not change the canonical µMAG Standard Problem 4 definition.

11.1. BORIS comparison and gap matrix

BORIS is a traceability reference, not a Fullmag oracle. The comparison below records the observable contract differences against the clean-room manifest docs/physics/multilayer_convolution/boris-reference-manifest.v1.json and its behavior-only transcription in docs/physics/multilayer_convolution/boris-behavioral-spec.v1.md. The original external snapshot is intentionally ignored by Git; the manifest hashes identify it without making unavailable source files part of the published source index.

Contract axis

BORIS snapshot (path and symbol, line anchor)

Fullmag public contract

Qualification or gap

Multilayer versus supermesh choice

external_solvers/BORIS/Boris/SDemag.h, multilayer/supermesh comments (L59-L61); SDemag::Set_Multilayered_Convolution in SDemag_MConv.cpp (L1195-L1202)

FDMDemag.strategy="multilayer_convolution" is an explicit requested strategy. There is no hidden conversion to a single-grid supermesh and no public single-grid fallback for a multi-body request.

Fullmag preserves requested intent and fails closed when the requested path is not eligible; BORIS’s supermesh option is not a semantic alias.

Per-layer Rect_collection and scratch rectangles

SDemag::set_Rect_collection in external_solvers/BORIS/Boris/SDemag.cpp (L98-L179) and SDemag::get_convolution_rect (L194-L204); Initialize_MConv_Demag in SDemag_MConv.cpp (L128-L166)

FdmLayerPlanIR keeps native grid/origin/mask and a separate convolution layout. API FdmCommonTransformLayoutResource is FFT scratch only; is_physical_mesh=false and provenance are explicit.

common_transform_layout is computational CommonTransformLayout, not a physical mesh, material body, or FEM/universe mesh, and it cannot be used as a field fallback.

n_common versus physical grid

BORIS SDemag::set_default_n_common (L56-L96) and Set_n_common (L206-L227) choose common convolution counts; n_common.z=1 forces the 2-D option.

FDMDemag.common_cells and common_cells_xy are explicit scratch-grid hints lowered under backend_policy.discretization_hints.fdm.demag; they never create a physical layer.

A matching integer tuple does not imply matching semantics: Fullmag native grids and physical origins remain per magnet.

Common-cell pitch and normalization

BORIS derives h_common = convolution_rect / n_common and uses the maximum cell size when normalizing transfer dimensions.

Fullmag keeps common-cell size, native-cell size, and transform layout as separate resolved descriptor fields; a mismatch becomes explicit transfer or rejection.

Equal counts do not prove equal cell volumes or transfer accuracy; each cell-size class needs its own field/energy evidence.

2dmulticonvolution=0/1/2

external_solvers/BORIS/Boris/SDemag.h force-mode comments (L81-L91) define 0=no 2-D, 1=take every mesh as 2-D, and 2=layer each mesh along Z.

Fullmag mode="two_d_stack" is not BORIS 2dmulticonvolution=1 or =2; it is a separate Fullmag mode requiring one native Z cell per layer. A multi-cell-Z request has no public moment-preserving reduction and fails closed with a validation error.

No Fullmag claim maps either BORIS option to two_d_stack; use mode="three_d" for native through-thickness cells.

Arbitrary XY extents, centers, and XYZ offsets

BORIS SDemag::set_Rect_collection enlarges/alines rectangles and supports different XY extents/starts (L98-L179); shifted kernels operate on the resulting rectangles.

Planner materializes the union of native XY bounds as one computational scratch envelope and marks layers that need push_pull; native origins remain physical. An explicit common grid must contain that union.

Authoring/planner support is present, but the complete transfer, insertion/crop, energy, and CUDA matrix is not production-qualified. Do not draw the union scratch envelope as a material mesh.

Arbitrary Z gaps

BORIS pair kernels carry signed shifts through SDemag_MConv.cpp::UpdateField_MConv_Demag (L197-L337) and shifted tensor functions.

Non-overlapping layers may have arbitrary Z gaps. The planner quantizes the signed origin difference by resolved convolution-cell thickness for a reuse key; overlapping Z intervals are rejected.

Gap support is planner/runtime scoped and still requires pair-kernel and energy evidence for each claimed geometry class.

Unequal source/destination thickness

BORIS DemagTFunc::CalcDiagTens2D_Shifted_Irregular in DemagTFunc_Irregular.cpp (L5-L119) explicitly supports unequal Z thickness while requiring common XY.

Fullmag’s irregular Newell contract is documented for common XY cells and unequal \(h_{s,z},h_{d,z}\); the checked pair builder preserves both cell sizes in the oriented kernel.

Pair/oracle tests and a focused CPU unequal-thickness test pass; this does not qualify arbitrary XY transfer, reduced-storage families, or CUDA.

Weighted transfer

BORIS SDemag_Demag::Initialize_Mesh_Transfer and weighted transfer branch (L63-L87, L282-L295) use mesh-transfer weights.

Fullmag exposes push_m_with_boundary_policy and its volume-adjoint pull_h_with_boundary_policy; transfer_kind="push_pull" is explicit in FdmLayerPlanIR.

Transfer correctness requires moment, energy, and adjointness evidence; point interpolation is not enough.

Full pair-oriented kernels

BORIS DemagKernelCollection::KernelMultiplication_2D and KernelMultiplication_3D in DemagKernelCollection_Mult.cpp (L635-L735) multiply all ordered inputs; UpdateField_MConv_Demag performs forward/pair/inverse stages.

Fullmag plans all \(L^2\) ordered source→destination pairs and six tensor components. Pair orientation includes source/destination cell sizes, signed Z shift, common shape, masks, and transfer.

A scalar separation-only kernel is not the Fullmag contract; each orientation must have field/energy and reciprocity evidence.

Spectral storage and representation

BORIS DemagKernelCollection::KerType in external_solvers/BORIS/Boris/DemagKernelCollection.h (L35-L62) stores real/complex kernels, shift flags, source/destination cell sizes, and FFT dimensions.

Fullmag TensorDemagKernel in crates/fullmag-fdm-demag/src/types.rs stores six components on the padded FFT shape; CellPairTensor::components fixes the xx,yy,zz,xy,xz,yz order.

Real/reduced versus complex/full storage is a kernel-class decision; source presence does not qualify every representation or precision.

Kernel catalog and reuse

BORIS catalog declarations in DemagKernelCollection.h (L108-L131) cover 2-D/3-D self, Z-shifted, X-shifted, and complex-full families; KernelAlreadyComputed (L130-L131) checks reuse.

Fullmag KernelReuseKey::from_pair_with_layout plus the CPU kernel_catalog/pair_bindings runtime deduplicate one tensor per full key and reuse one FFT/workspace allocation across refreshes; telemetry reports hit/miss, pair/FFT counts, and cold/warm bytes.

CPU descriptor-path reuse is implemented and fail-closed, but it does not qualify all BORIS kernel families, reduced/full representations, CUDA, or device residency.

FFT work decomposition

BORIS SDemag::UpdateField_MConv_Demag in SDemag_MConv.cpp (L197-L337) performs forward transforms, pair kernel multiplication, and inverse transforms.

Fullmag’s documented operator shape is \(L\) forward transforms, \(L^2\) pair accumulation, and \(L\) inverse transforms; CUDA telemetry is scoped to one demag refresh.

Counters do not prove full time-integrator device residency or production parity.

Zero padding and crop

BORIS Initialize_MConv_Demag sets convolution dimensions and scratch spaces in SDemag_MConv.cpp (L128-L166).

Fullmag records fft_shape, insertion offsets, lag-zero, crop, and inverse normalization in the resolved transform descriptor; linear convolution needs at least \(n_{src}+n_{dst}-1\) samples per axis.

Static shape descriptions do not qualify numerical padding for every geometry or precision.

CPU/CUDA realization

BORIS has SDemagCUDA::Initialize_MConv_Demag and SDemagCUDA::UpdateField_MConv_Demag in SDemagCUDA_MConv.cpp (L14-L277).

Fullmag has a CPU FP64 reference and a CUDA v2 plan/workspace contract. GPU status remains partial until fresh managed executed-device field/energy parity and residency telemetry are recorded.

BORIS CUDA source presence is not a Fullmag qualification receipt, and Fullmag source/build/ABI presence is not device proof.

PBC images

BORIS demag_pbc_images and Set_PBC apply the same image counts to every participating mesh in either supermesh or multilayer convolution.

Fullmag’s multilayer boundary mode is open; PBC is rejected by the planner and cannot silently fall back to another strategy.

PBC remains an explicit gap requiring Python/ProblemIR fields, image kernels, energy/provenance rules, and separate CPU/CUDA qualification.

Empty cells, masks, and energy

BORIS tracks non_empty_cells and total_nonempty_volume, excludes mesh regions as configured, and normalizes multilayer energy over participating volume.

Fullmag keeps native active masks, uses volume-weighted demag energy, and publishes target-only Airbox H_demag while keeping solver masking separate from visualization fields.

Mask, volume, energy, and Airbox claims require separate runtime artifacts; source tests do not close the full matrix.

Antiferromagnetic and atomistic meshes

BORIS tracks antiferromagnetic participation and forces transfer for atomistic meshes.

Fullmag’s public multilayer contract is for named ferromagnetic FDM objects; AFM and atomistic mesh semantics are not silently mapped into it.

This is an explicit scope gap requiring a separate material, mask, transfer, energy, and qualification contract.

Reconfiguration and invalidation

BORIS rebuilds per-mesh demag modules when mesh geometry, n_common, force mode, or PBC changes.

Fullmag resolves a new plan from topology fingerprints and invalidates the CPU catalog/workspace when descriptor geometry changes.

An end-to-end session replan and post-replan parity receipt is still missing; a fingerprint alone is not a runtime qualification.

Airbox target-only observation

BORIS multilayer/supermesh descriptions do not define Fullmag’s target-only Airbox resource.

Fullmag FdmMultilayerAirboxRenderDomain is a target-only grid for H_demag; it is deliberately unrelated to the FFT/common-transform grid. Airbox H_eff is unavailable with a versioned reason.

Airbox extent and wireframe are UI geometry evidence only; field qualification needs fresh runtime data and WebGL checks.

UI, Explorer, and viewport semantics

BORIS source has no Fullmag resource-first browser contract.

GET /v2/sessions/current/data/domain/fdm-multilayer-layout publishes availability and reason; Explorer omits unavailable layout nodes; viewport adapters expose native-layer targets and target-only Airbox, never the common scratch grid.

UI tests and source mappings are contract evidence, not fresh interactive qualification.

Production qualification boundary

BORIS source and the clean-room manifest provide traceability only.

Fullmag must report implemented, executable, runtime-verified, physically-validated, and production-qualified separately for CPU, CUDA, UI, and each requested display mode.

Neither static source comparison nor a visual screenshot alone closes the production gate.

12. Scientific bibliography

  1. S. Lepadatu, “Efficient computation of demagnetizing fields for magnetic multilayers using multilayered convolution,” Journal of Applied Physics 126, 103903 (2019), doi:10.1063/1.5116754.

  2. A. J. Newell, W. Williams, and D. J. Dunlop, “A generalization of the demagnetizing tensor for nonuniform magnetization,” Journal of Geophysical Research: Solid Earth 98, 9551–9555 (1993), doi:10.1029/93JE01171.

  3. A. Aharoni, “Demagnetizing factors for rectangular ferromagnetic prisms,” Journal of Applied Physics 83, 3432–3434 (1998), doi:10.1063/1.367113.

BORIS clean-room boundary

BORIS is used only as external traceability material for kernel categories and convolution organization. The canonical boundary is recorded in docs/physics/multilayer_convolution/boris-reference-manifest.v1.json. BORIS code is not copied into Fullmag, is not a numerical oracle, and is not qualification evidence. The equations on this page come from Lepadatu and Newell and map to independently maintained Fullmag code.

13. Source-code index

Claim

Path

Symbol

Responsibility

Lane

Tests/evidence

Evidence status

Immutable link

Python grid

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

class FDMGrid

Validates and lowers one magnet’s cell.

Public API

packages/fullmag-py/tests/test_fdm_multilayer_contract.py

executable authoring

master@762ca086b

Python demag policy

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

class FDMDemag

Validates requested strategy, mode, and common layout.

Public API

packages/fullmag-py/tests/test_fdm_multilayer_contract.py

executable authoring

master@762ca086b

Python FDM wrapper

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

class FDM

Lowers complete FDM hints.

Public API

packages/fullmag-py/tests/test_fdm_ui_roundtrip.py

round-trip contract

master@762ca086b

ProblemIR topology identity

crates/fullmag-ir/src/mesh_hints.rs

fdm_multilayer_topology_tokens

Binds resolved mode and layer geometry to topology certificate.

IR

crates/fullmag-ir/src/mesh_hints.rs tests

executable contract

master@762ca086b

ProblemIR validation

crates/fullmag-ir/src/mesh_hints.rs

FdmDemagHintsIR::validate

Rejects illegal authored configuration.

IR

crates/fullmag-ir/src/mesh_hints.rs tests

executable contract

master@762ca086b

Planner

crates/fullmag-plan/src/fdm.rs

plan_fdm_multilayer

Resolves mode, layers, grid certificate, and transfer.

Planner

crates/fullmag-plan/src/tests.rs multilayer tests

executable contract

master@762ca086b

CPU runtime

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

execute_reference_fdm_multilayer

Runs CPU reference; runtime performs FFT, pairs, and field pull.

FDM CPU FP64

multilayer engine tests and independent oracles

local/source-unbound runtime evidence

master@762ca086b

CPU observation and energy

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

observe_multilayer

Publishes CPU field, energy, and provenance.

FDM CPU FP64

SP4-derived runtime artifacts

local/source-unbound runtime evidence

master@762ca086b

Push transfer

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

push_m_with_boundary_policy

Transfers magnetization to the scratch grid.

FDM CPU transfer

volume_weighted_transfer_preserves_2d_moment_through_z_average

locally physically-validated for the stated moment contract; no unequal-native-cell-thickness continuum oracle

master@762ca086b

Pull transfer

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

pull_h_with_boundary_policy

Returns field to the native grid.

FDM CPU transfer

volume_weighted_transfer_is_adjoint_with_active_mask

locally physically-validated for the stated volume-adjoint and mask contract; no unequal-native-cell-thickness continuum oracle

master@762ca086b

Newell diagonal primitive

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

newell_f

Evaluates Newell tensor function \(f\).

Kernel preparation

Newell reference tests

code/test evidence

master@762ca086b

Newell cross primitive

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

newell_g

Evaluates Newell tensor function \(g\).

Kernel preparation

Newell reference tests

code/test evidence

master@762ca086b

Shifted Newell builder

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

compute_newell_kernels_shifted

Builds an oriented shifted tensor.

FDM CPU kernel

shifted/cubature tests

locally physically-validated

master@762ca086b

CUDA v2 plan creation

backends/fdm/api/c_api.cpp

fullmag_fdm_backend_create_v2

Validates, uploads, and prepares D-07 plan.

FDM CUDA

managed ABI/contract tests

executable contract, no device parity

master@762ca086b

CUDA FFT workspace

backends/fdm/gpu/cuda/runtime/context.cu

context_prepare_multilayer_fft_workspace_v2

Prepares batched cuFFT workspace.

FDM CUDA

managed contract tests

executable contract, no device parity

master@762ca086b

UI round-trip model

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

createStudyGlobalDraft

Reads scene FDM values into the Inspector draft.

Control Room

StudyGlobalAuthoringModel.test.ts

contract-verified

master@762ca086b

UI native-layer adapter

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

adaptFdmMultilayerNativeLayerDomains

Adapts independent physical native-layer carriers and rejects malformed mask declarations.

Explorer/viewport

viewport adapter tests

contract-verified

master@762ca086b

UI Airbox adapter

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

adaptFdmMultilayerAirboxDomain

Adapts the validated target-only Airbox without treating the common FFT grid as geometry.

Explorer/viewport

viewport adapter tests

contract-verified, no fresh browser proof

master@762ca086b

BORIS common-grid policy

external_solvers/BORIS/Boris/SDemag.cpp

SDemag::Set_n_common

Reference behavior for explicit shared convolution counts.

BORIS reference

clean-room behavioral reference; SHA-256 manifest

traceability only

External reference snapshot

BORIS ordered kernel reuse

external_solvers/BORIS/Boris/DemagKernelCollection_Calc.cpp

DemagKernelCollection::KernelAlreadyComputed

Observed reference key lookup over oriented shift and source/destination cell size.

BORIS reference

clean-room behavioral reference; SHA-256 manifest

traceability only

External reference snapshot

BORIS pair accumulation

external_solvers/BORIS/Boris/DemagKernelCollection_Mult.cpp

DemagKernelCollection::KernelMultiplication_2D

Observed reference ordered pair multiplication.

BORIS reference

clean-room behavioral reference; SHA-256 manifest

traceability only

External reference snapshot

BORIS irregular-thickness tensor

external_solvers/BORIS/Boris/DemagTFunc_Irregular.cpp

DemagTFunc::CalcDiagTens2D_Shifted_Irregular

Observed unequal-thickness tensor construction.

BORIS reference

clean-room behavioral reference; SHA-256 manifest

traceability only

External reference snapshot

BORIS multilayer phases

external_solvers/BORIS/Boris/SDemag_MConv.cpp

SDemag::UpdateField_MConv_Demag

Observed forward, pair, and inverse staging.

BORIS reference

clean-room behavioral reference; SHA-256 manifest

traceability only

External reference snapshot

Fullmag kernel reuse

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

KernelReuseKey::from_layers_with_layout

Builds the independent reuse key from the full transform and layer descriptors.

FDM CPU/GPU

descriptor unit tests

executable contract

master@762ca086b

Fullmag common-transform schema

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

fdm_multilayer_layout_resource

Builds the resource containing the computational common-transform schema, not a physical mesh.

Control Room API

API schema tests

contract-verified

master@762ca086b

Fullmag layer correlation

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

correlate_multilayer_layers

Binds artifact and execution-plan layers one-to-one and rejects identity disagreement.

Control Room API

v2 route tests

contract-verified

master@762ca086b

Fullmag layout route

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

get_fdm_multilayer_layout

Publishes layout availability and an explicit unavailable reason.

Control Room API

v2 route tests

contract-verified

master@762ca086b

Fullmag FMBM mask route

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

get_fdm_multilayer_layer_active_mask

Publishes a revisioned FMBM v1 active-mask payload with bound layout and grid identities.

Control Room API

v2 route tests

contract-verified

master@762ca086b

Fullmag FMBM payload builder

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

pack_native_active_mask

Packs the native active mask carried by the FMBM payload.

Control Room API

v2 route tests

contract-verified

master@762ca086b

Fullmag FMBM codec

apps/control-room/src/kernel/api/codecs/fdmMultilayerActiveMaskCodec.ts

decodeFdmMultilayerActiveMask

Validates FMBM magic, version, shape, cell count, and payload length.

Control Room API

codec tests

contract-verified

master@762ca086b

Fullmag FMBM identity contract

apps/control-room/src/kernel/api/codecs/fdmMultilayerActiveMaskCodec.ts

validateFdmMultilayerActiveMaskContract

Rejects mismatched layout revision, grid identity, hash, and active-cell counts.

Control Room API

codec tests

contract-verified

master@762ca086b

Fullmag FMBM resource hook

apps/control-room/src/kernel/resources/geometryLifecycleResources.ts

useFdmMultilayerLayerActiveMasksResource

Fetches only declared masks and marks incompatible payloads unusable.

Control Room API

resource-hook tests

contract-verified

master@762ca086b

Fullmag Explorer omission

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

buildModelTree

Omits unavailable layout nodes and keeps native-layer targets separate.

Explorer

Explorer tests

contract-verified

master@762ca086b

Fullmag native-layer domains

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

adaptFdmMultilayerNativeLayerDomains

Adapts physical native-layer carriers only.

Viewport

viewport adapter tests

contract-verified

master@762ca086b

Fullmag target-only Airbox domain

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

adaptFdmMultilayerAirboxDomain

Adapts target-only Airbox and validates field availability.

Viewport

viewport adapter tests

contract-verified, no fresh browser proof

master@762ca086b

Control Room crosswalk

Use Model Explorer -> Objects -> <object> -> Physics when PhysicsInteractionPanel exposes the interaction. Status: partial. frontend support is not implemented applies to physical parameters without a matching control. See {doc}/frontend/capability-register; do not infer UI support from backend or Python availability.

Python/API crosswalk

The linked Python API page is authoritative for exact functions, arguments, units, and failure semantics. If this page is a foundation or category overview, runnable Python is ot applicable here and must be taken from the terminal API page.

Bibliography and source scope

Use the scientific bibliography and source-code index on the linked terminal page. This block adds no new equation or unverified implementation claim.

Source-code index

  • Public Python and lowering sources are linked by the applicable terminal API page. Runtime realization is in the relevant backends/fdm or backends/fem lane; frontend ownership is apps/control-room/src/modules/inspector/panels/PhysicsInteractionPanel.tsx where a live control exists.