FDM Cartesian grids

Last changes: Documentation changelog

FDM represents magnetization on cell-centred Cartesian grids. A body can inherit the study default cell size or own a native grid. Multi-body demagnetization can additionally use a common convolution grid selected by the planner; that grid does not replace the native body grids.

Implementation status

Single-grid FDM is available on CPU and on capability-gated GPU routes. Public multi-body execution uses multilayer_convolution; requesting single_grid for more than one magnetic body fails closed. Backend eligibility is established by planning, not by the authored strategy name alone.

Physical problem

Let a magnetic region occupy a bounded subset of a rectangular Cartesian universe. Fullmag stores one magnetization vector per active FDM cell. The rectangular allocation also contains inactive cells outside the magnetic support. Geometry voxelization determines the active/material mask and, when boundary correction is requested and supported, a magnetic volume fraction.

The cell spacing controls geometry occupancy, local finite-difference operators, FFT demagnetization kernels, allocation size, and the shortest represented wavelength. It must resolve the smallest relevant geometric and magnetic length scales. A one-cell film thickness is a thickness-averaged model and cannot resolve a nonuniform thickness mode.

Governing grid equations

For cell-boundary origin \(\mathbf x_0\), native spacings \((h_x,h_y,h_z)\), and zero-based indices,

(1)\[\mathbf x_{ijk}=\mathbf x_0+ \left(\left(i+\tfrac12\right)h_x, \left(j+\tfrac12\right)h_y, \left(k+\tfrac12\right)h_z\right).\]

The rectangular allocation has cell volume and count

(2)\[V_{\mathrm{cell}}=h_xh_yh_z, \qquad N=N_xN_yN_z.\]

With a binary active/material mask, the following is the documentary volume identity derived from the resolved mask and spacing:

(3)\[V_{m,h}=V_{\mathrm{cell}} \sum_{i=0}^{N_x-1}\sum_{j=0}^{N_y-1}\sum_{k=0}^{N_z-1}\chi_{ijk}.\]

If a supported boundary-correction route supplies cell fractions, the corresponding documentary volume identity is

(4)\[V_{m,h}=V_{\mathrm{cell}} \sum_{i=0}^{N_x-1}\sum_{j=0}^{N_y-1}\sum_{k=0}^{N_z-1}\phi_{ijk}.\]

The native grid of magnetic body \(r\) is the implementation tuple

(5)\[\mathcal G_r=\left(\mathbf x_{0,r},(N_{x,r},N_{y,r},N_{z,r}), (h_{x,r},h_{y,r},h_{z,r}),\chi^{(r)}\right).\]

For multilayer convolution, source and target identities must remain distinct. For every source layer \(s\), the CPU runtime pushes magnetization to that layer’s common transform layout and performs one forward FFT. For every ordered pair \((r,s)\), a destination/source binding selects the pair tensor from the kernel catalog and accumulates into target \(r\). Finally, each target is negated, inverse transformed, cropped, and pulled to its native grid:

(6)\[\widehat{\mathbf M}_{c,s} =\mathcal F_c\!\left[\mathcal P_s\mathbf M_s\right], \qquad \widehat{\mathbf H}_{c,r} =-\sum_s\widehat{\mathbf N}_{rs}\widehat{\mathbf M}_{c,s}, \qquad \mathbf H_r =\mathcal R_r\mathcal F_c^{-1}\!\left[\widehat{\mathbf H}_{c,r}\right].\]

Local interaction pages own exact field stencils and boundary equations. On an interior uniform axis,

(7)\[\left.\frac{\partial u}{\partial x}\right|_i =\frac{u_{i+1}-u_{i-1}}{2h_x}+\mathcal O(h_x^2),\]
(8)\[\left.\frac{\partial^2u}{\partial x^2}\right|_i =\frac{u_{i+1}-2u_i+u_{i-1}}{h_x^2}+\mathcal O(h_x^2).\]

Here \(\widehat{\mathbf N}_{rs}\) is selected by the ordered binding with dst_layer = r and src_layer = s. Catalog deduplication may let several ordered bindings reuse one stored tensor, but it does not merge source magnetizations or target accumulators. For \(L\) layers, one refresh performs \(L\) forward FFTs, \(L^2\) ordered-pair accumulations, and \(L\) inverse FFTs when all pairs are present.

The first-derivative formula is realized for interior active neighbours by multilayer_dmi_field_kernel; missing/inactive neighbours are clamped to the centre and DMI boundary corrections are applied separately. The second-derivative formula is the uniform-material fast path of exchange_field_fp64_kernel; its general path uses per-neighbour exchange coefficients, active masks, and periodic wrap or clamped Neumann neighbours. The displayed formulas therefore do not define cut-cell, interface, or boundary treatment.

Symbols and SI units

ID

Symbol

Meaning

SI unit

x

\(\mathbf x_{ijk}\)

cell centre

\(\mathrm{m}\)

x0

\(\mathbf x_0\)

cell-boundary origin

\(\mathrm{m}\)

h

\(h_x,h_y,h_z\)

native cell spacings

\(\mathrm{m}\)

Vcell

\(V_{\mathrm{cell}}\)

cell volume

\(\mathrm{m^3}\)

Vmh

\(V_{m,h}\)

discrete magnetic volume

\(\mathrm{m^3}\)

Nxyz

\(N_x,N_y,N_z\)

cell counts

\(1\)

N

\(N\)

total rectangular allocation

\(1\)

chi

\(\chi_{ijk}\)

binary active/material mask

\(1\)

phi

\(\phi_{ijk}\)

magnetic volume fraction

\(1\)

Gr

\(\mathcal G_r\)

native grid owned by magnet r

\(1\)

Mc

\(\widehat{\mathbf M}_{c,s}\)

source-layer magnetization spectrum on the common transform grid

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

Mr

\(\mathbf M_s\)

magnetization on native source grid s

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

Hc

\(\widehat{\mathbf H}_{c,r}\)

accumulated target-layer field spectrum on the common transform grid

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

Hr

\(\mathbf H_r\)

field restricted to native target grid r

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

P

\(\mathcal P_s\)

source push and insertion into its common transform layout

implementation-dependent

R

\(\mathcal R_r\)

target crop and pull to its native grid

implementation-dependent

F

\(\mathcal F_c\)

common-layout discrete Fourier transform

\(1\)

Nrs

\(\widehat{\mathbf N}_{rs}\)

FFT-domain demag tensor for ordered target/source pair \((r,s)\)

\(1\)

r

\(r\)

target-layer index

\(1\)

s

\(s\)

source-layer index

\(1\)

u

\(u\)

generic grid scalar component

quantity-dependent

Assumptions and validity

  • Spacings are finite, strictly positive SI lengths; grids are axis-aligned and Cartesian.

  • Cell counts are positive integers resolved from geometry, spacing, and planner policy.

  • Geometry smaller than a cell can disappear or change occupancy under a sub-cell translation.

  • A demag kernel is tied to grid shape, spacing, boundary policy, and precision.

  • common_cells, common_cells_xy, and common_cell_size are alternative common-grid requests, not native-grid cell sizes.

  • Grid refinement establishes adequacy for the reported observable.

  • The centre and volume equations are grid definitions. resolved_fdm_cell_centers implements the centre coordinates; FdmPlanIR carries the resolved shape, spacing, masks, and origin from which the volume identities are derived. FDMGrid itself validates spacing only.

  • compute_boundary_geometry realizes \(\phi_{ijk}\) by fixed \(4^3\) SDF sub-sampling per cell for the boundary-correction geometry route; the volume sum is a documented derived quantity, not a claim that every backend computes a standalone V_mh scalar.

Python API

Complete canonical example

The ordinary public route is mesh-owned. This example uses a default native spacing, one body override, and a common convolution spacing required by unequal native grids.

# %% Imports and study
import fullmag as fm

nm = 1.0e-9
study = fm.study("fdm_grid_reference")
study.engine("fdm")
study.device("cpu", precision="double")
study.mode("strict")
study.objects.mesh.defaults(cell_size=(2 * nm, 2 * nm, 2 * nm))
study.universe.mesh(cell_size=(1 * nm, 1 * nm, 1 * nm))

# %% Magnetic bodies and native grids
bottom = study.geometry(
    fm.Box(size=(80 * nm, 40 * nm, 2 * nm)).translate((0.0, 0.0, -2 * nm)),
    name="bottom",
)
top = study.geometry(
    fm.Box(size=(80 * nm, 40 * nm, 2 * nm)).translate((0.0, 0.0, 2 * nm)),
    name="top",
)
top.mesh(cell_size=(4 * nm, 4 * nm, 2 * nm))

# %% Materials and initial state
for body in (bottom, top):
    body.Ms = 800.0e3
    body.Aex = 13.0e-12
    body.alpha = 0.02
    body.m = fm.texture.uniform(1.0, 0.0, 0.0)

# %% Physics and stage
study.exchange()
study.demag()
study.stages.add_relax(
    stage_id="equilibrium",
    algorithm="llg_overdamped",
    dt=1.0e-13,
    tolA=1.0e-4,
    max_steps=5_000,
)

study.fdm(...) and fm.fdm(...) remain callable for explicit FDM/FDMDemag policy, but emit DeprecationWarning for ordinary grid authoring. Prefer body.mesh(cell_size=...), study.objects.mesh.defaults(cell_size=...), study.universe.mesh(cell_size=...), and study.demag(). The advanced policy route remains necessary for explicit common counts, FFT backend, or boundary floor/distance fields that have no canonical mesh call.

Exhaustive grid and demag parameter contract

Python field

Type

Default

SI unit

Validation

Meaning

Backend support

Python-to-ProblemIR mapping

FDMGrid.cell

tuple[float,float,float]

required

\(\mathrm{m}\)

exactly three finite positive values

per-magnet native spacing

FDM CPU; GPU capability-gated

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

FDM.cell

Sequence[float] | None

None

\(\mathrm{m}\)

legacy input is exclusive with default_cell; three finite positive values when set

legacy constructor input and read-only alias of default_cell

FDM CPU/GPU compatibility surface

both .fdm.cell and .fdm.default_cell

FDM.default_cell

tuple[float,float,float] | None

None

\(\mathrm{m}\)

exactly three finite positive values; default_cell or per_magnet is required

default native spacing

FDM CPU/GPU

both .fdm.default_cell and compatibility .fdm.cell

FDM.per_magnet

dict[str,FDMGrid] | None

None

\(1\)

nonblank string keys and FDMGrid values; default_cell or per_magnet is required

object-owned native grids

FDM CPU; multi-body GPU capability-gated

.fdm.per_magnet

FDM.demag

FDMDemag | None

None

\(1\)

expected FDMDemag when set; FDM has no explicit runtime isinstance check

nested demag authoring policy

FDM

.fdm.demag, omitted for None

FDM.boundary_correction

str | None

None

\(1\)

none, volume, or full

requested boundary correction

interaction/device gated; multilayer accepts None or none

.fdm.boundary_correction, omitted for None

FDM.boundary_phi_floor

float | None

None

\(1\)

strictly in (0,1)

requested minimum boundary volume fraction

boundary-correction gated; current multilayer unsupported

.fdm.boundary_phi_floor, omitted for None

FDM.boundary_delta_min

float | None

None

\(\mathrm{m}\)

Direct FDM rejects only values < 0: NaN and +Inf pass; Scene/script requires a finite number; FdmHintsIR does not revalidate; the single-grid planner forwards the value

requested minimum geometric distance

boundary-correction gated; current multilayer unsupported

.fdm.boundary_delta_min, omitted for None

FDM.projection_policy

str | None

None

\(1\)

None or unit_sphere

projected-RK state constraint request

FDM time-integrator policy

.fdm.projection_policy, omitted for None

FDMDemag.strategy

str

auto

\(1\)

auto, single_grid, or multilayer_convolution

nonlocal grid strategy

FDM; multi-body single_grid unsupported

.fdm.demag.strategy

FDMDemag.mode

str

auto

\(1\)

auto, two_d_stack, or three_d

common-grid dimensionality

FDM multilayer

.fdm.demag.mode

FDMDemag.common_cells

tuple[int,int,int] | None

None

\(1\)

positive triple; auto or three_d; exclusive with other common-grid forms

explicit 3D common-grid dimensions

FDM multilayer

.fdm.demag.common_cells, omitted for None

FDMDemag.common_cells_xy

tuple[int,int] | None

None

\(1\)

positive pair; auto or two_d_stack; exclusive with other common-grid forms

explicit in-plane dimensions

FDM multilayer

.fdm.demag.common_cells_xy, omitted for None

FDMDemag.common_cell_size

tuple[float,float,float] | None

None

\(\mathrm{m}\)

Python: positive finite triple and exclusive with counts; ProblemIR also rejects explicit two_d_stack

requested common spacing

FDM multilayer

.fdm.demag.common_cell_size, omitted for None

FDMDemag.fft_backend

str

auto

\(1\)

auto, rustfft, fftw, mkl, or cufft

requested FFT realization

demag/device gated; no silent fallback

.fdm.demag.fft_backend

FDMDemag.explain

bool

True

\(1\)

direct construction does not type-check; Scene/script overrides require Boolean

human-readable plan explanation request

authoring and Scene/script round-trip only

not serialized into ProblemIR

FDMDemag.allow_single_grid_fallback

bool | None

None

\(1\)

every non-None value is rejected as a removed option

compatibility-only rejected input

unsupported

no ProblemIR mapping; rejected before lowering

body.mesh(cell_size=...)

Sequence[float] | None

None

\(\mathrm{m}\)

exactly three finite positive values; exclusive with FEM mesh controls

canonical per-body native spacing

FDM CPU; GPU capability-gated

.fdm.per_magnet.<canonical-name>.cell

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

Sequence[float] | None

None

\(\mathrm{m}\)

exactly three finite positive values; exclusive with FEM mesh controls

canonical default native spacing

FDM CPU/GPU

both .fdm.default_cell and compatibility .fdm.cell

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

Sequence[float] | None

None

\(\mathrm{m}\)

exactly three finite positive values; exclusive with FEM universe controls

canonical common convolution spacing

FDM multilayer

creates .fdm.demag with auto strategy/mode/fft_backend and .common_cell_size

The canonical paths do not merely alias one another. body.mesh records a named override; study.objects.mesh.defaults records the inherited default; and study.universe.mesh constructs an FDMDemag(common_cell_size=...) request. During Problem construction, every magnetic body must have an override or default, and unequal effective native spacings require the universe common spacing. The FDM constructor’s legacy cell= input and cell property both resolve to default_cell.

ProblemIR contract

Authored intent is stored at backend_policy.discretization_hints.fdm:

{
  "cell": [2e-9, 2e-9, 2e-9],
  "default_cell": [2e-9, 2e-9, 2e-9],
  "per_magnet": {"top": {"cell": [4e-9, 4e-9, 2e-9]}},
  "demag": {
    "strategy": "auto",
    "mode": "auto",
    "fft_backend": "auto",
    "common_cell_size": [1e-9, 1e-9, 1e-9]
  }
}

cell is a compatibility mirror of default_cell; Python emits both when a default exists. Optional fields are omitted when unset. projection_policy is emitted when requested. FDMDemag.explain is deliberately absent, while allow_single_grid_fallback cannot reach lowering because every non-None value is rejected. Canonical body.mesh lowers by canonical magnet name to per_magnet.<name>.cell; study.objects.mesh.defaults lowers to both default/compatibility cell fields; study.universe.mesh creates a demag object with strategy="auto", mode="auto", fft_backend="auto", and the authored common_cell_size.

ProblemIR records requested intent, not execution. Single-grid planning resolves FdmPlanIR. Multilayer planning resolves FdmMultilayerPlanIR with common counts, per-layer native grid, spacing, origin, masks, convolution descriptors, transfer kind, grid certificate, and planner_summary. The summary preserves requested_strategy/requested_mode separately from selected_strategy/resolved_mode.

Round-trip and failure semantics

Requested intent

Python to_ir() preserves known grid and demag values. auto remains authored intent until planning. Scene/script export additionally retains FDMDemag.explain.

Resolved execution

The planner selects grid counts, origins, transfers, precision policy, and the certificate. plan_fdm_fft only validates FFT-request compatibility and stores requested_backend; concrete FFT resolved_backend and executed_backend values belong to runtime receipts. Runtime consumes the resolved plan. common_cell_size remains recorded as requested_common_cell_size while resolved common_cells and layer descriptors are authoritative.

Validation errors

Validation is layered and the boundaries are intentional:

  • Direct Python FDMGrid/FDM construction validates vector shape/positivity, the legacy cell/default_cell conflict, per-magnet names and values, projection token, boundary fields, and the requirement for a default or per-magnet grid. FDM.demag is type-annotated but FDM does not perform an explicit isinstance check.

  • Direct FDMDemag construction validates strategy, mode, FFT token, positive integer counts, positive common_cell_size, count conflicts, and count/mode combinations. It does not runtime-check that explain is Boolean. It also permits common_cell_size with explicit mode="two_d_stack", so successful Python construction is not proof of valid ProblemIR.

  • Scene/script override parsing additionally requires fdm.demag.explain to be Boolean and validates input container/number shapes before constructing the Python policy.

  • ProblemIR deserialization denies unknown demag fields and FdmDemagHintsIR.validate rechecks strategy, mode, FFT backend, positivity, and mutual exclusion. It additionally rejects common_cell_size with explicit mode="two_d_stack".

  • Canonical mesh calls validate a finite positive three-vector and reject mixing cell_size with FEM mesh controls. Problem construction rejects missing body spacing and unequal native spacings without study.universe.mesh(cell_size=...).

  • Planning rejects nonrepresentable/capability-ineligible intent before runtime allocation. The checked CPU multilayer runtime then verifies descriptor counts, field/mask lengths, scratch grids, identity-transfer extents, and ordered pair/catalog indices.

Unsupported combinations

  • Multi-body single_grid is rejected; use multilayer_convolution or strategy="auto".

  • Unequal native spacing requires study.universe.mesh(cell_size=...) in canonical authoring.

  • Current multilayer planning rejects boundary correction other than None/none and rejects boundary_phi_floor or boundary_delta_min.

  • ProblemIR rejects common_cell_size combined with explicit mode="two_d_stack" even though direct FDMDemag construction currently permits that pair.

  • A non-auto FFT backend requires active demag and successful capability planning.

  • allow_single_grid_fallback has been removed and is rejected rather than ignored.

Discrete realization

Each body grid owns origin, shape, spacing, active mask, region mask, and material data. Allocation size is \(N_xN_yN_z\) even when only a subset is magnetic. Supported boundary correction can replace binary occupancy by fractional volume and corrected local operators.

compute_newell_kernels constructs a cell-geometry-dependent Newell tensor and FftWorkspace owns single-grid spectra/cache state. CPU multilayer execution is owned by MultilayerDemagRuntime::compute_demag_fields_checked. Its persistent workspace stores separate m_fft[s] and h_fft[r] arrays. build_kernel_catalog_incrementally consumes KernelCatalogSpec::pair_bindings, materializes each unique tensor at most once, and retains every ordered src_layer/dst_layer binding. Runtime performs a forward transform per source, calls accumulate_tensor_convolution for every binding into the selected target accumulator, then negates, inverse-transforms, crops, and pulls each target field. VolumeWeightedTransfer or identity transfer realizes \(\mathcal P_s\) and \(\mathcal R_r\); these symbols do not promise arbitrary interpolation.

Implementation mapping

Layer

Stable owner

Contract

Python schemas

packages/fullmag-py/src/fullmag/model/discretization.py — class FDMGrid, class FDM, class FDMDemag

signatures, validation, to_ir()

Native-grid authoring

packages/fullmag-py/src/fullmag/world.py — class GeometryMeshHandle, class StudyObjectsMeshDefaultsHandle

body/default spacing

Common-grid authoring

packages/fullmag-py/src/fullmag/world.py — class StudyUniverseHandle

universe spacing

Script/Scene round-trip

packages/fullmag-py/src/fullmag/runtime/script_builder.py — def _fdm_from_overrides, def _export_fdm

parsing and export

ProblemIR

crates/fullmag-ir/src/mesh_hints.rs — pub struct FdmHintsIR, pub struct FdmDemagHintsIR

wire schema and validation

Planner

crates/fullmag-plan/src/fdm.rs — pub(crate) fn plan_fdm_multilayer

requested/resolved grids and policy

Resolved cell centres

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

evaluates centre coordinates from origin, indices, and spacing

Fractional boundary geometry

crates/fullmag-plan/src/boundary_geometry.rs — compute_boundary_geometry

computes \(\phi\) using \(4^3\) SDF sub-samples and boundary metadata

Resolved single-grid schema

crates/fullmag-ir/src/plan.rs — FdmPlanIR

owns shape, spacing, origin, masks, and certificate behind documentary volume identities

Resolved multilayer schema

crates/fullmag-ir/src/mesh_hints.rs — FdmMultilayerPlanIR

owns per-layer native/common grid and transfer descriptors

Pair-kernel catalog

crates/fullmag-engine/src/multilayer.rs — build_kernel_catalog_incrementally; crates/fullmag-fdm-demag/src/descriptors.rs — KernelCatalogSpec

binds every ordered source/target pair to a reusable tensor

CPU multilayer demag

crates/fullmag-engine/src/multilayer.rs — compute_demag_fields_checked

separate source FFT, pair accumulation, target inverse/pull

CUDA first derivative

backends/fdm/gpu/cuda/interactions/multilayer_dmi.cu — multilayer_dmi_field_kernel

centred interior derivatives plus DMI boundary handling

CUDA second derivative

backends/fdm/gpu/cuda/interactions/exchange_fp64.cu — exchange_field_fp64_kernel

uniform Laplacian and region/PBC/active-mask paths

Demag tensor

crates/fullmag-fdm-demag/src/newell.rs — pub fn compute_newell_kernels

Newell kernels

CPU FFT

crates/fullmag-engine/src/fdm/cpu/fft.rs — pub struct FftWorkspace

spectra and cache

Validation and convergence

Source tests cover canonical lowering, common-grid conflicts, FFT request preservation, Python/Scene/script/ProblemIR round-trip, and fail-closed IR validation. CPU runtime tests additionally check three forward FFTs, nine ordered-pair accumulations, and three inverse FFTs for three layers, plus equality of the catalog result with a sum of separate pair runs. These tests do not prove a study is grid converged. Use at least three grid levels with geometry, materials, solver tolerances, initial state, and output sampling fixed. Report cell sizes, resolved shapes, active-cell counts, backend/device/precision, grid fingerprint, and convergence of the scientific observable.

Limitations

  • Cartesian voxelization is stair-stepped without supported boundary correction.

  • A common grid can increase memory; explicit counts remain subject to budget checks.

  • Canonical authoring exposes spacing, not explicit native counts or origins.

  • The centred-difference equations do not specify interface, cut-cell, or periodic stencils.

  • Source-backed capability does not replace a runtime receipt for the selected lane.

Scientific bibliography

  • C. Abert, “Micromagnetics and spintronics: models and numerical methods,” European Physical Journal B 92, 120 (2019), doi:10.1140/epjb/e2019-90599-6.

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

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

  • W. F. Brown Jr., Micromagnetics, Interscience Publishers, New York (1963).

Runtime ownership and validation boundaries

Shifted source/target pair tensor

build_kernel_catalog_incrementally invokes the builder supplied by its caller and deduplicates the returned tensors; it is not the owner of shifted-pair geometry or Newell mathematics. In the active CPU reference path, build_multilayer_demag_runtime derives independent source and destination cell sizes and the destination-minus-source XYZ offset for each ordered pair, then calls compute_shifted_kernel_pair. That checked alias delegates to try_compute_shifted_kernel_pair, whose mathematical owner is try_compute_newell_kernels_shifted_pair; the latter evaluates the real-space six-component tensor for the independent source/target cells and offset before fft_newell_to_kernel transforms it. This is the implementation evidence for the ordered N_rs pair kernel. The equal-cell compute_newell_kernels branch alone is not evidence for unequal or shifted pairs.

FFT request versus runtime execution

plan_fdm_fft checks the authoring request against planner-visible compatibility constraints and creates FdmFftPlanIR with only requested_backend. FdmFftPlanIR has no FFT resolved_backend or executed_backend; the CommonPlanMeta.resolved_backend field describes the overall execution backend and must not be interpreted as an FFT realization.

At execution time, resolve_cpu_fft_execution_for_demag maps auto or rustfft to RustFFT and writes all three FFT receipt fields. The CUDA multilayer runtime writes the same receipt contract in device_resident_multilayer_provenance for cuFFT and in assisted_multilayer_provenance for host RustFFT assistance. FdmFftExecutionProvenance is the artifact schema carrying requested_backend, resolved_backend, and executed_backend. Therefore a concrete FFT implementation is resolved and recorded only by the runtime that actually executes it.

Exact boundary_delta_min acceptance boundary

Entry/stage

Exact behavior

What reaches the next stage

Direct Python FDM(...)

If non-None, the constructor checks only boundary_delta_min < 0.0. Negative finite values and -Inf are rejected; NaN and +Inf pass because the comparison is false.

The accepted value is emitted unchanged by FDM.to_ir().

Scene/script overrides

_fdm_number first converts the value with float(...) and then requires math.isfinite. It rejects NaN, +Inf, and -Inf; a finite negative value reaches FDM(...) and is rejected there.

Only None or a finite nonnegative value survives this route.

IR (FdmHintsIR)

The field is Option<f64> and FdmHintsIR has no equivalent finite/nonnegative validator. This statement concerns typed IR validation; a particular JSON parser can impose its own syntax restrictions before IR construction.

No IR-layer normalization or range check is applied.

Single-grid planner

plan_fdm copies FdmHintsIR.boundary_delta_min directly into FdmPlanIR.boundary_delta_min.

The planner preserves the supplied value; it does not resolve or validate it.

Multilayer planner

Any specified boundary_delta_min is rejected because the current multilayer plan cannot represent boundary-correction controls.

No multilayer runtime plan is produced for that request.

Source-code index

Repository path

Stable symbol

Responsibility

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

class FDMGrid

native-grid spacing validation and serialization

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

class FDM

complete FDM hint policy and lowering

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

class FDMDemag

demag policy and direct-constructor validation

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

class GeometryMeshHandle

canonical per-body cell size

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

class StudyObjectsMeshDefaultsHandle

canonical default cell size

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

class StudyUniverseHandle

canonical common convolution spacing

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

_export_fdm

Scene/script round-trip state

crates/fullmag-ir/src/mesh_hints.rs

FdmHintsIR

ProblemIR FDM hints

crates/fullmag-ir/src/mesh_hints.rs

FdmDemagHintsIR

ProblemIR demag validation

crates/fullmag-plan/src/fdm.rs

plan_fdm_multilayer

multilayer plan resolution

crates/fullmag-plan/src/fdm.rs

resolved_fdm_cell_centers

implemented cell-centre coordinates

crates/fullmag-ir/src/plan.rs

FdmPlanIR

resolved single-grid shape, spacing, origin, and masks

crates/fullmag-ir/src/mesh_hints.rs

FdmMultilayerPlanIR

resolved per-layer and common-grid descriptors

crates/fullmag-plan/src/boundary_geometry.rs

compute_boundary_geometry

fractional boundary geometry

crates/fullmag-engine/src/multilayer.rs

build_kernel_catalog_incrementally

unique tensors and ordered pair bindings

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

KernelCatalogSpec

canonical ordered pair catalog specification

crates/fullmag-engine/src/multilayer.rs

compute_demag_fields_checked

CPU source FFT, pair accumulation, target inverse/pull

backends/fdm/gpu/cuda/interactions/multilayer_dmi.cu

multilayer_dmi_field_kernel

implemented centred first derivatives

backends/fdm/gpu/cuda/interactions/exchange_fp64.cu

exchange_field_fp64_kernel

implemented centred second derivatives

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

compute_newell_kernels

cell-dependent Newell tensor

crates/fullmag-engine/src/fdm/cpu/fft.rs

FftWorkspace

single-grid CPU spectra/cache

packages/fullmag-py/tests/test_fdm_multilayer_contract.py

test_mesh_cell_size_lowers_per_object_and_common_domain

canonical lowering test

crates/fullmag-ir/tests/ir_tests.rs

fdm_demag_hints_round_trip_preserves_known_wire_values

IR round-trip test

Round-2 ownership additions

Contract

Runtime owner

Evidence boundary

Ordered shifted-pair call site

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

Derives source/destination cells and XYZ offset, then calls the pair builder.

Checked shifted-pair kernel

crates/fullmag-fdm-demag/src/shifted_kernel.rs::compute_shifted_kernel_pair

Public checked alias used by the runner.

Shifted-pair Newell mathematics

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

Computes the unequal/shifted six-component real-space tensor.

FFT request planning

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

Validates compatibility and stores only the request.

FFT request IR

crates/fullmag-ir/src/plan.rs::FdmFftPlanIR

Contains only requested_backend.

CPU FFT resolution/execution

crates/fullmag-runner/src/fdm/cpu/reference/fft_backend.rs::resolve_cpu_fft_execution_for_demag

Resolves RustFFT and fills the runtime receipt.

CUDA device-resident FFT receipt

crates/fullmag-runner/src/fdm/gpu/cuda/multilayer.rs::device_resident_multilayer_provenance

Records cuFFT as resolved and executed.

CUDA-assisted FFT receipt

crates/fullmag-runner/src/fdm/gpu/cuda/multilayer.rs::assisted_multilayer_provenance

Records assisted RustFFT as resolved and executed.

FFT receipt schema

crates/fullmag-runner/src/types.rs::FdmFftExecutionProvenance

Owns requested, resolved, and executed FFT fields.

Scene finite-number guard

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

Rejects all nonfinite scene/script values.

Single-grid forwarding

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

Copies boundary_delta_min without an equivalent check.

Scope and purpose

This page defines the public contract for Cartesian FDM grid construction. It is an authoring and implementation reference: the Python example, the serialized ProblemIR description, the implementation mapping, and the adjacent source map are the source-backed contract. A capability marked partial or not evaluated is not presented as a production guarantee.

Scientific and numerical model

The mesh or grid is a discrete approximation of the continuous domain. For a Cartesian partition, each spacing satisfies Delta_i = L_i / N_i; for a geometry-dependent FEM mesh, the requested local target is bounded by the active bulk, interface, boundary, and topology constraints. In compact form, h_target(x) = min(h_bulk(x), h_interface(x), h_boundary(x)). Length quantities use SI metres (m); counts, orders, and topology labels are dimensionless.

The equations and assumptions in the earlier physical-problem and governing-equations sections state the model-specific specialization. This section does not introduce a conversion from FEM to FDM, a hidden topology conversion, or a silent CPU fallback.

Parameters

The exact callable and argument names are the ones shown in the ## Python API section above. For this page the parameter family is cell_size, grid dimensions, origin, and periodicity. Use the documented defaults, validation rules, and ProblemIR lowering exactly as shown; do not replace a canonical argument with an unlisted alias. Numerical lengths must be supplied in metres, and invalid positive-length, count, order, periodicity, or topology constraints must fail closed rather than being silently repaired.

Control Room workflow

In Control Room, select the engine and mesh workflow, enter the same values as the Python authoring example, inspect the planned mesh or grid report, and only then submit the run. The UI is a projection of the public contract: a missing control is not evidence that the backend accepts the option, and a visible control is not evidence that a production lane is enabled. When the page or capability register marks a field partial or not evaluated, keep the workflow explicitly bounded to the implemented path.

Diagnostics and failure semantics

A valid request must preserve the declared geometry, units, element or cell topology, and backend lane. Reject non-finite or non-positive lengths, invalid counts and orders, incompatible periodic or shared-boundary data, and unsupported topology combinations at the owning validation layer. Reports should retain requested and resolved values, source identity, and any capability gate. No diagnostic may hide a failed mesh realization by substituting another discretization.

Where this is implemented

The existing implementation-mapping and source-code-index sections identify the exact public authoring, ProblemIR, planner, realization, and runtime owners for this topic. The adjacent .source-map.json file is the machine-readable source of truth for those paths, symbols, responsibilities, backend matrix, and reviewed revision. Claims in this page must be updated together with that map when an owner moves.