Ouro
  • Docs
  • Blog
Join for freeSign in
  • Teams
  • Search
Assets
  • Quests
  • Posts
  • APIs
  • Data
  • Teams
  • Search
Assets
  • Quests
  • Posts
  • APIs
  • Data
22d
120 views

On this page

  • Building a Physically Comparable Magnetic Hysteresis Simulation Framework
    • Introduction
    • Architecture Overview
      • Core Components
    • Simulation Workflow
      • Step 1: Prepare Material Input
      • Step 2: Configure the Simulation
      • Step 3: Execute the Simulation
      • Step 4: Analyze Results
    • Microstructure Capabilities
      • Grain Structure Control
      • Defect Incorporation
    • Physics Implementation
      • Energy Terms
      • Field Direction Control
    • Numerical Methods
      • Micromagnetic Solver (Ubermag/OOMMF)
      • Atomistic Solver (Spirit/UppASD - Phase 1)
    • Configuration System
      • Hierarchical YAML Structure
      • Validation
    • Realistic Experimental Conditions
      • Standard Measurement Protocol
      • Results
      • Engineered Conditions vs. Reality
    • Upcoming Features
      • Phase 1: Atomistic Engine Integration
      • Phase 2: Advanced Microstructure
      • Phase 3: Temperature Effects & Optimization
    • Extensibility
      • Adding New Simulation Engines
      • Custom Microstructure Models
    • Performance Considerations
      • Computational Cost
      • Optimization Strategies
    • Validation and Quality Assurance
      • Physics Sanity Checks
      • Regression Testing
      • Convergence Studies
    • Comparison to Experimental Data
Loading compatible actions...
Loading comments...

Overview of the current work and future enhancements for magnetic hysteresis simulations

Building a Physically Comparable Magnetic Hysteresis Simulation Framework

Introduction

We're working on an end-to-end framework for physically comparable magnetic hysteresis simulations. The framework accepts crystallographic information files (CIF) as input and produces hysteresis loops with quantified key performance indicators (KPIs), while maintaining full provenance tracking. Most importantly, it ensures that simulations run on different engines (micromagnetic and atomistic) use identical material parameters, geometry, microstructure, and protocols—enabling true apples-to-apples comparisons.

This post details the framework's architecture, capabilities, and usage, along with a roadmap for upcoming features including atomistic simulation, advanced microstructure models, and temperature effects.

Architecture Overview

The framework follows a clean ports-and-adapters architecture that separates physics and planning logic from computational engine specifics. This design enables easy extension to new simulation engines while maintaining consistency in material representation and experimental protocols.

Core Components

Material Parameter Pipeline: The framework derives all required material parameters from CIF files and first-principles calculations. Given a CIF file and magneto-crystalline anisotropy energy (MAE) from density functional theory (DFT), the system calculates:

  • Uniaxial anisotropy constant (Ku) from MAE and unit cell volume

  • Saturation magnetization (Ms) from atomic magnetic moments

  • Exchange stiffness (A) for micromagnetics

  • Exchange integrals (J) for atomistic models

  • Recommended discretization cell sizes based on exchange length

This automatic parameter derivation eliminates manual error and ensures consistency across simulation types.

Geometry Builder: The geometry module creates computational domains that match either:

  • Supercell dimensions from crystallographic repeats (atomistic)

  • Specified physical dimensions with appropriate discretization (micromagnetic)

The builder ensures that mesh or lattice discretization respects the exchange length constraint (cell size less than half the exchange length) for numerical stability.

Microstructure Generator: A key innovation is the engine-agnostic microstructure representation. The generator produces:

  • Voronoi tessellation for polycrystalline structures

  • Per-grain orientation distributions (Gaussian axis-angle parameterization)

  • Grain boundary masks with tunable thickness

  • Defect fields (pores, precipitates) with volume fraction control

The microstructure is represented as callable functions that return spatially-varying properties at any point in space. These functions are then mapped to either continuum fields (micromagnetics) or per-site properties (atomistics), ensuring identical microstructure across engines.

Protocol Engine: Standardized field protocols guarantee that different simulation engines experience identical experimental conditions:

  • Hysteresis loops: configurable maximum field and step resolution

  • Field direction control: easy-axis or hard-axis measurements

  • Relaxation criteria: energy minimization or time-integration tolerances

  • Multi-cycle protocols for training effects

Data Extraction: Automated analysis extracts standard magnetic performance metrics:

  • Coercivity (Hc): zero-crossing detection with interpolation

  • Remanence ratio (Mr/Ms): magnetization at zero field

  • Energy product (BHmax): maximum in second quadrant

  • Loop area: integrated hysteresis loss

Provenance Tracking: Every simulation logs complete metadata to MLflow:

  • Input configurations (YAML serialization)

  • Material parameters and their derivation

  • Microstructure random seeds

  • Engine versions and computational environment

  • Output artifacts (CSV data, plots, analysis)

This enables full reproducibility and comparison across simulation campaigns.

Simulation Workflow

Step 1: Prepare Material Input

Start with a CIF file containing the crystal structure of your magnetic material. Provide the MAE per unit cell from DFT calculations or literature... or from a certain MAE model that may or may not be coming soon. For example, Fe₂B with tetragonal structure:

plaintext
Unit cell: a = 5.109 Å, c = 4.249 Å
MAE: 60 meV/cell (c-axis anisotropy)
Saturation moment: ~2.3 μB per iron atom

The framework automatically extracts the unit cell volume (108.46 ų) and c-axis orientation vector from the CIF file.

Step 2: Configure the Simulation

Create a YAML configuration file specifying:

yaml
engine: "ubermag"

material:
  cif_path: "material.cif"
  Ms: 1.2e6                      # A/m (from experiment or DFT)
  MAE_meV_per_cell: 60.0         # meV (from DFT)
  A: 8.0e-12                     # J/m (micromagnetic exchange)
  alpha: 0.05                    # Gilbert damping
  T: 0.0                         # Temperature (K)
  easy_axis_from: "c_axis"       # Use CIF c-axis

domain:
  target_dims_nm: [100, 100, 100]  # Physical size
  bc: "free"                       # Boundary conditions
  shape: "box"
  cell_size_factor: 2.5            # Discretization: lexch/2.5

microstructure:
  type: "voronoi"                  # Grain structure
  grains: 12
  seed: 42
  misorientation:
    distribution: "gaussian_axis_angle"
    mean_deg: 0.0
    std_deg: 20.0                  # Texture strength
  boundaries:
    thickness_nm: 2.0
    A_scale: 0.6                   # Exchange weakening
    Ku_scale: 0.8                  # Anisotropy reduction

protocol:
  H_max_MA_per_m: 5.0              # Maximum field (MA/m)
  steps_per_leg: 31                # Field steps
  field_direction: [0, 0, 1]       # Along easy axis
  relax_mode: "energy_min"
  tol: 1.0e-6

logging:
  mlflow:
    tracking_uri: "file:./mlruns"
    experiment: "MaterialStudy"
  output_dir: "./artifacts/run_001"

Step 3: Execute the Simulation

Run the simulation from the command line:

bash
python -m src.cli.run_experiment \
    --config configs/my_material.yaml \
    --engine ubermag

The framework will:

  1. Parse the CIF and derive Ku = 88.6 MJ/m³

  2. Calculate exchange length: 2.97 nm

  3. Create a mesh with 1.19 nm cells (84×84×84 cells for 100 nm cube)

  4. Generate 12 Voronoi grains with 20° misorientation

  5. Map grain orientations to spatially-varying anisotropy fields

  6. Apply weakened exchange at grain boundaries

  7. Run 153 field steps from +5 to -5 to +5 MA/m

  8. Extract and log KPIs

Step 4: Analyze Results

The simulation produces:

  • hysteresis_loop.csv: H and M data points

  • hysteresis_loop.png: Plotted M-H curve

  • kpis.json: Extracted performance metrics

  • metadata.json: Mesh and computational details

Access via MLflow UI for comparison across runs:

bash
mlflow ui --backend-store-uri ./mlruns

Microstructure Capabilities

Grain Structure Control

The Voronoi tessellation generates realistic polycrystalline microstructures:

Grain Count: Control the number of grains to study size effects. Fewer grains (1-5) model single-domain or oligocrystalline samples. Many grains (50-100) represent bulk polycrystals.

Texture Control: The misorientation standard deviation controls crystallographic texture:

  • std_deg: 0 → Perfect single crystal

  • std_deg: 10-20 → Strong texture (aligned grains), typical of sintered magnets

  • std_deg: 30-45 → Moderate texture

  • std_deg: 90 → Random texture (isotropic)

This parameter critically affects coercivity. Aligned textures (10-20°) produce soft behavior with low Hc, while random textures (90°) enable high Hc when sufficient field is applied.

Grain Boundary Engineering:

Adjust exchange coupling and anisotropy at boundaries:

yaml
boundaries:
  thickness_nm: 2.0      # Physical width
  A_scale: 0.6           # 40% reduction in exchange
  Ku_scale: 0.8          # 20% reduction in anisotropy

This models boundary phases, segregation, or amorphization that disrupts magnetic coupling between grains.

Defect Incorporation

Pores (Voids):

yaml
defects:
  pores:
    volume_fraction: 0.02    # 2% porosity
    size_nm: [3, 8]          # Size distribution

Pores act as nucleation sites for magnetic reversal, typically reducing coercivity.

Precipitates (Second Phases):

yaml
defects:
  precipitates:
    volume_fraction: 0.03
    phase: "hard"             # or "soft"
    Ku_scale: 1.5             # 50% higher anisotropy
    A_scale: 2.0              # Enhanced exchange

Hard precipitates pin domain walls and increase coercivity. Soft precipitates can create exchange-spring behavior in nanocomposites.

Physics Implementation

Energy Terms

Exchange Energy: For micromagnetics, the framework uses continuum exchange with stiffness A:

E_exchange = A∫(∇m)2dVA ∫ (∇m)² dVA∫(∇m)2dV

For atomistics (future Phase 1), discrete Heisenberg exchange:

E_exchange = −ΣJijSi⋅Sj-Σ J_ij S_i · S_j−ΣJi​jSi​⋅Sj​

The mapping A ↔ J is handled consistently: for simple cubic lattices with coordination z and lattice constant a:

A≈(zJS2)/aA ≈ (z J S²) / aA≈(zJS2)/a

Uniaxial Anisotropy: Spatially-varying easy axis and strength:

E_anis = ∫Ku(r)[1−(m(r)⋅u(r))2]dV∫ Ku(r) [1 - (m(r) · u(r))²] dV∫Ku(r)[1−(m(r)⋅u(r))2]dV

The framework automatically maps per-grain orientations to smooth field functions for micromagnetics or discrete per-site values for atomistics.

Demagnetization: Full magnetostatic self-interaction via FFT-accelerated Newell method (micromagnetics). For atomistic models, this is handled via dipolar coupling or shape anisotropy approximation.

Zeeman Energy: External field interaction with configurable direction:

E_zeeman = −μ0∫H⋅MdV-μ₀ ∫ H · M dV−μ0​∫H⋅MdV

Field Direction Control

A critical feature for realistic measurements:

Easy-Axis Loops:

yaml
field_direction: [0, 0, 1]  # Parallel to easy axis

Measures intrinsic coercivity. High fields required to reverse well-aligned grains.

Hard-Axis Loops:

yaml
field_direction: [1, 0, 0]  # Perpendicular to easy axis

Measures anisotropy field. Linear response with small magnetization projection.

Arbitrary Directions:

yaml
field_direction: [0.707, 0, 0.707]  # 45° to easy axis

Studies angular dependence and Stoner-Wohlfarth behavior.

The projected magnetization along the field direction is reported, matching experimental measurement geometry.

Numerical Methods

Micromagnetic Solver (Ubermag/OOMMF)

The framework interfaces with the Object Oriented MicroMagnetic Framework (OOMMF) via the Ubermag Python API.

Discretization: Finite difference method on a regular rectangular mesh. Cell size automatically set to half the exchange length for stability:

cell_size = √(2A/μ0Ms2)/2.5√(2A / μ₀Ms²) / 2.5√(2A/μ0​Ms2)/2.5

Relaxation: Energy minimization via conjugate gradient method:

python
driver = MinDriver()
driver.drive(system, tol=1e-6, max_steps=3000)

Each field step relaxes the magnetization to the local energy minimum before recording M.

Performance: A 100×100×100 nm cube (84³ cells) requires approximately:

  • 5-10 seconds per field step in stable regions

  • 30-60 seconds near switching events

  • Total: 15-30 minutes for a full loop (31 steps per leg)

Atomistic Solver (Spirit/UppASD - Phase 1)

Future implementation will use Landau-Lifshitz-Gilbert (LLG) integration:

dS/dt=−γ(S×Heff)−(α/∣S∣)(S×dS/dt)dS/dt = -γ(S × H_eff) - (α/|S|)(S × dS/dt)dS/dt=−γ(S×He​ff)−(α/∣S∣)(S×dS/dt)

where effective field includes exchange, anisotropy, dipolar, and Zeeman contributions. Relaxation via damping to steady state at each field step.

Configuration System

Hierarchical YAML Structure

The configuration system supports:

Base Configurations:

yaml
# configs/base.yaml
material:
  alpha: 0.05
  T: 0.0
domain:
  bc: "free"
  shape: "box"

Material Libraries:

yaml
# configs/materials/fe2b.yaml
Ms: 1.2e6
MAE_meV_per_cell: 60.0
A: 8.0e-12

Experiment Compositions:

yaml
# configs/experiments/texture_study.yaml
includes:
  - ../base.yaml
  - ../materials/fe2b.yaml
microstructure:
  misorientation:
    std_deg: 20.0

Validation

Pydantic-based schema validation ensures:

  • Required fields present

  • Correct types and units

  • Physical constraints (e.g., Ms > 0, Ku ≥ 0)

  • Mutually exclusive options handled

Invalid configurations are caught immediately with informative error messages.

Realistic Experimental Conditions

To demonstrate the framework's predictive capability, we compare engineered versus realistic simulations of Fe₂B.

Standard Measurement Protocol

The realistic_experimental.yaml configuration represents what would be measured in a vibrating sample magnetometer (VSM) or superconducting quantum interference device (SQUID):

yaml
material:
  cif_path: "fe2b.cif"
  Ms: 1.2e6                      # From literature
  MAE_meV_per_cell: 60.0         # From DFT
  A: 8.0e-12
  alpha: 0.05
  T: 0.0                         # Baseline at 0 K

domain:
  target_dims_nm: [100, 100, 100]  # Representative volume

microstructure:
  type: "voronoi"
  grains: 12
  misorientation:
    std_deg: 20.0                # Realistic sintered texture

protocol:
  H_max_MA_per_m: 5.0            # 6.3 Tesla superconducting magnet
  field_direction: [0, 0, 1]     # Standard easy-axis measurement

Results

Key Performance Indicators:

  • Coercivity (Hc): 0.0 MA/m

  • Remanence ratio (Mr/Ms): 0.957

  • Magnetization range: 1.144 to 1.152 MA/m (always positive)

Interpretation:

The simulation correctly predicts soft magnetic behavior for Fe₂B under realistic processing conditions:

  1. No Coercivity: The 20° texture means most grains are aligned with the applied field direction. The 5 MA/m maximum field is insufficient to reverse these well-aligned grains against their 73 MA/m anisotropy field (Hk = Ku/Ms).

  2. High Remanence: Mr/Ms = 0.96 indicates strong alignment. When field is removed, magnetization remains close to saturation because grains are textured along the measurement direction.

  3. Reversible Rotation: Magnetization undergoes small reversible rotation as field varies but never switches sign. This is characteristic of aligned magnetic materials below their switching threshold.

Physical Validity:

This matches experimental observations of sintered Fe₂B-based materials, which typically show:

  • Low coercivity: 0.1-2 MA/m (depending on processing)

  • High remanence in textured samples

  • Soft magnetic characteristics at practical field strengths

The framework accurately captures that coercivity requires either:

  1. Random grain orientation (opposing easy axes)

  2. Applied fields exceeding the anisotropy field

  3. Thermal activation over energy barriers (T > 0)

  4. Defects providing nucleation sites

None of these conditions are met in the realistic configuration, hence Hc = 0.

Engineered Conditions vs. Reality

For comparison, an engineered configuration with 90° random texture and 150 MA/m field produces:

  • Coercivity: 54.3 MA/m

  • Remanence ratio: 0.65

  • Full magnetization reversal: -1.15 to +1.15 MA/m

This represents the theoretical maximum performance achievable with:

  • Perfect random texture (impossible to fabricate)

  • Extreme applied fields (10× practical limits)

  • Ideal single-phase crystals (no defects)

The framework correctly distinguishes between theoretical limits and practical performance.

Upcoming Features

Phase 1: Atomistic Engine Integration

Spirit/UppASD Implementation:

Extend the framework to atomistic spin dynamics for direct comparison with micromagnetics:

python
class SpiritEngine(MagSimEngine):
    def setup(self, mat, geom, payload):
        # Build spin lattice from CIF supercell
        # Assign exchange integrals J_ij from A
        # Map microstructure to per-site anisotropy
        # Configure LLG integrator
        
    def relax_at_field(self, H_Am):
        # Time-integrate LLG to steady state
        # Project spin moments along field
        # Return average magnetization

Key Capabilities:

  • Discrete spin representation (S_i on each atom)

  • Heisenberg exchange with neighbor shells

  • Per-site anisotropy from grain orientations

  • Comparison to continuum micromagnetics

Use Cases:

  • Validate micromagnetic approximation (when does it break?)

  • Study small systems (<10 nm) where continuum fails

  • Model site-specific defects (vacancies, dopants)

  • Capture atomistic details at interfaces

What we want to show: Side-by-side Ubermag vs. Spirit comparison showing coercivity agreement within 20% for representative test cases.

Phase 2: Advanced Microstructure

Extended Grain Structures:

Beyond Voronoi tessellation, implement:

  1. Lamellar Structures: Alternating layers for L10-type ordered alloys (FePt, CoPt)

    yaml
    microstructure:
      type: "lamellar"
      layer_thickness_nm: 5.0
      orientation: [0, 0, 1]
    
  2. Columnar Grains: Thin film growth structures with elongated grains

    yaml
    microstructure:
      type: "columnar"
      aspect_ratio: 10.0
      growth_direction: [0, 0, 1]
    
  3. Twinned Domains: Crystallographic twins with specific angle relationships

    yaml
    microstructure:
      type: "twinned"
      twin_type: "cubic_90deg"
    
  4. Grain Size Distributions: Log-normal or bimodal size distributions

    yaml
    microstructure:
      grain_size_distribution:
        type: "lognormal"
        median_nm: 50.0
        sigma: 0.5
    

Realistic Defects:

Implement defect models that reduce coercivity:

  1. Vacancies: Point defects reducing local magnetic moment

    python
    def add_vacancies(sites, concentration=0.01):
        # Remove random sites
        # Or reduce local Ms by 50%
    
  2. Dislocations: Line defects creating easy nucleation zones

    python
    def add_dislocations(sites, density_m2=1e14):
        # Create dislocation cores with Ku_scale=0.3
    
  3. Stacking Faults: Planar defects interrupting crystal order

  4. Impurity Segregation: Non-magnetic atoms at grain boundaries

Multi-Phase Nanocomposites:

Model exchange-spring magnets with hard-soft phase mixing:

yaml
microstructure:
  type: "composite"
  phases:
    hard:
      fraction: 0.7
      Ku_base: 100e6  # MJ/m³
      grain_size_nm: 20
    soft:
      fraction: 0.3
      Ku_base: 1e6
      A_scale: 2.0    # Enhanced exchange
      grain_size_nm: 5
  interface_coupling: "exchange_spring"

Deliverable: Working hard-soft nanocomposite showing enhanced energy product (BHmax) from exchange-spring mechanism.

Phase 3: Temperature Effects & Optimization

Temperature-Dependent Properties:

Implement thermal scaling of magnetic parameters:

python
def apply_temperature_scaling(params, T_K, Tc_K=1000):
    """
    Scale properties with reduced magnetization m(T)
    following mean-field approximation
    """
    m = (1 - (T_K/Tc_K)**2)**0.5 if T_K < Tc_K else 0.0
    
    return {
        'Ms': params['Ms'] * m,
        'Ku': params['Ku'] * m**2,
        'A': params['A'] * m
    }

Temperature-dependent simulations enable:

  • Thermal stability studies (energy barrier height)

  • Curie temperature determination

  • Temperature coefficients of Hc and Mr

  • Thermal demagnetization protocols

Stochastic Thermal Activation:

Add Langevin noise to LLG equation for thermal fluctuations:

dS/dt=−γ(S×Heff)−α(S×dS/dt)dS/dt = -γ(S × H_eff) - α(S × dS/dt)dS/dt=−γ(S×He​ff)−α(S×dS/dt) + thermal_noise(TK,dt)(T_K, dt)(TK​,dt)

This captures:

  • Thermally-assisted reversal over energy barriers

  • Viscous damping and loss mechanisms

  • Time-dependent switching probabilities

Parameter Sweep Framework:

Automated optimization studies:

python
def parameter_sweep(base_config, sweep_grid):
    """
    Example sweep_grid:
    {
        'material.MAE_meV_per_cell': [40, 60, 80, 100],
        'microstructure.misorientation.std_deg': [10, 20, 30, 45, 60],
        'domain.target_dims_nm[0]': [50, 100, 200]
    }
    """
    results = []
    for params in grid_iterator(sweep_grid):
        config = apply_parameters(base_config, params)
        result = run_simulation(config)
        results.append({
            'params': params,
            'Hc': result.kpis['Hc_avg_Am'],
            'Mr_Ms': result.kpis['Mr_Ms_ratio'],
            'BHmax': result.kpis['BHmax_J_m3']
        })
    
    return results

Visualization:

Generate contour plots showing:

  • Hc vs. texture vs. anisotropy

  • Energy product vs. grain size vs. composition

  • Optimal parameter regions highlighted

Dynamic Hysteresis:

Frequency-dependent measurements:

yaml
protocol:
  mode: "dynamic"
  frequency_Hz: [0.01, 0.1, 1, 10, 100]
  H_amplitude_MA_per_m: 5.0

Studies:

  • AC loss mechanisms

  • Frequency-dependent coercivity

  • Minor loop behavior

  • First-order reversal curves (FORC)

What we want to show: Automated optimization framework producing contour maps of performance metrics across multi-dimensional parameter spaces.

Extensibility

Adding New Simulation Engines

The framework's engine-agnostic design enables straightforward integration of new solvers. Implement the MagSimEngine protocol:

python
class CustomEngine:
    def setup(self, mat: MaterialParams, 
              geom: GeometrySpec, 
              payload: Dict[str, Any]) -> None:
        """
        Initialize solver with material, geometry, and microstructure
        
        Args:
            mat: MaterialParams with Ms, Ku, A, alpha, etc.
            geom: GeometrySpec with dimensions and discretization
            payload: Microstructure fields or per-site data
        """
        # Setup custom solver
        
    def relax_at_field(self, H_Am: float) -> Dict[str, Any]:
        """
        Relax system at applied field and return magnetization
        
        Args:
            H_Am: Applied field magnitude (A/m) along field_direction
            
        Returns:
            {'H_Am': H_Am, 'M_Am': M_projected, ...}
        """
        # Run relaxation
        # Project magnetization along field_direction
        return results
        
    def finalize(self) -> SimulationResult:
        """Return complete H and M arrays"""
        return SimulationResult(H_Am=self.H_list, M_Am=self.M_list)

Register the new engine:

python
# src/cli/run_experiment.py
def run_custom_experiment(config):
    engine = CustomEngine()
    engine.setup(mat_params, geom_spec, payload)
    # ... standard experiment loop

The microstructure payload automatically adapts to the engine's needs via the assignment layer.

Custom Microstructure Models

Extend the microstructure generator:

python
class CustomMicrostructure:
    def generate(self, dims_m):
        """
        Return functions mapping position to properties
        
        Returns:
            {
                'easy_axis': lambda pos: unit_vector,
                'scale_Ku': lambda pos: scale_factor,
                'scale_A': lambda pos: scale_factor,
                'scale_Ms': lambda pos: scale_factor,
                'grain_label': lambda pos: int,
                'is_boundary': lambda pos: bool,
                'is_pore': lambda pos: bool
            }
        """
        # Custom microstructure logic
        return field_functions

Register in the factory:

python
# src/core/microstructure.py
MICROSTRUCTURE_TYPES = {
    'voronoi': VoronoiMicrostructure,
    'lamellar': LamellarMicrostructure,
    'custom': CustomMicrostructure
}

Performance Considerations

Computational Cost

Typical simulation times on a workstation (8-core, 32 GB RAM):

Micromagnetics (Ubermag/OOMMF):

  • 50×50×50 nm (42³ cells): 5 min for 31-step loop

  • 100×100×100 nm (84³ cells): 20 min for 31-step loop

  • 200×200×200 nm (168³ cells): 2 hours for 31-step loop

Scales approximately as N_cells^1.3 due to FFT-based demagnetization.

Atomistics (future):

  • 10×10×10 nm (10⁴ spins): 30 min estimated

  • 20×20×20 nm (10⁵ spins): 5 hours estimated

Scales approximately as N_spins × N_neighbors × N_steps.

Optimization Strategies

Adaptive Stepping: Use fine steps near coercivity, coarse steps in saturated regions:

python
def adaptive_field_schedule(H_max, Hc_estimate):
    # Dense sampling near ±Hc
    # Sparse sampling far from reversal

Warm Starting: Initialize each field step from the previous magnetization state rather than random or saturated. Reduces convergence iterations.

Parallel Execution: Parameter sweeps are embarrassingly parallel:

python
from multiprocessing import Pool

with Pool(8) as p:
    results = p.map(run_simulation, config_list)

Reduced Symmetry: For single-grain or highly symmetric cases, simulate only a representative volume element.

Validation and Quality Assurance

Physics Sanity Checks

Automated validation ensures physical consistency:

  1. Energy Conservation: Check that relaxed state is at local energy minimum

  2. Coercivity Bounds: Verify Hc ≤ Hk (anisotropy field) Verify Hc ≤ H_max (can't measure higher than applied field)

  3. Magnetization Magnitude: Check |M| ≤ Ms at all times

  4. Remanence Bounds: Verify 0 ≤ Mr/Ms ≤ 1

  5. Loop Closure: Final state should match initial state (within tolerance)

Regression Testing

Golden test suite runs on every code change:

python
def test_fe2b_single_grain():
    """Baseline test with known expected values"""
    config = load_config('tests/golden/fe2b_single.yaml')
    result = run_simulation(config)
    
    assert abs(result.kpis['Hc_avg_Am'] - 0.0) < 1e3  # Hc near zero
    assert abs(result.kpis['Mr_Ms_ratio'] - 1.0) < 0.01  # Near saturation

Convergence Studies

Verify mesh independence:

python
def test_mesh_convergence():
    """Test Hc convergence with refinement"""
    cell_sizes = [5.0, 2.5, 1.25, 0.625]  # nm
    Hc_values = [run_simulation(cell_size).kpis['Hc'] 
                 for cell_size in cell_sizes]
    
    # Hc should converge (relative change < 5%)
    assert (Hc_values[-1] - Hc_values[-2]) / Hc_values[-2] < 0.05

Comparison to Experimental Data

The framework facilitates direct comparison with measurements:

Import VSM/SQUID Data:

python
def import_vsm_data(filename):
    """Load experimental M-H curve"""
    H_exp, M_exp = load_vsm(filename)
    
    # Convert units if needed (Oe → A/m, emu/g → A/m)
    H_exp_Am = H_exp * 1e3 / (4*pi)  # Oe to A/m
    
    return H_exp_Am, M_exp

Overlay Simulation and Experiment:

python
def compare_to_experiment(sim_result, exp_data):
    """Generate comparison plot"""
    fig, ax = plt.subplots()
    ax.plot(sim_result.H_Am, sim_result.M_Am, 
            label='Simulation', linewidth=2)
    ax.plot(exp_data.H_Am, exp_data.M_Am, 
            label='Experiment', linestyle='--', linewidth=2)
    ax.set_xlabel('Applied Field (MA/m)')
    ax.set_ylabel('Magnetization (MA/m)')
    ax.legend()
    return fig

Parameter Fitting:

Optimize simulation parameters to match experimental loop:

python
from scipy.optimize import minimize

def objective(params):
    """Minimize difference between sim and exp"""
    config.material.Ms = params[0]
    config.material.MAE_meV_per_cell = params[1]
    config.microstructure.misorientation.std_deg = params[2]
    
    sim_result = run_simulation(config)
    
    error = np.sum((sim_result.M_Am - exp_M_Am)**2)
    return error

# Find best-fit parameters
result = minimize(objective, x0=[1.2e6, 60.0, 20.0])

This entire build will continue to evolve... more to come as always.