Setting up a micromagnetic problem
A micromagnetic problem is defined by a single problem object that is filled
with parameters and then handed to the Fortran solver. The Matlab and the
Python interfaces expose the same set of parameters, but they use slightly
different names; the naming used by Fortran is dictated by the subroutine
getProblemFieldnames in MagTenseMicroMagIO.f90.
The authoritative lists of parameters are
Matlab: DefaultMicroMagProblem.m
Python: micromag.py
and a side-by-side listing is given in Micromagnetic parameter reference.
Matlab problem setup
In Matlab a problem is created with DefaultMicroMagProblem(nx,ny,nz), which
returns an object with all parameters set to sensible defaults for a uniform
grid with nx*ny*nz cells. Parameters are then overwritten, and a number of
set... helper methods map human-readable names onto the integer flags that
Fortran expects. Finally the object is converted to a plain struct and passed
to the MEX-file:
addpath('MagTense/matlab/MEX_files');
addpath('MagTense/matlab/util');
mu0 = 4*pi*1e-7;
resolution = [36,9,1];
problem = DefaultMicroMagProblem( resolution(1), resolution(2), resolution(3) );
problem.grid_L = [500e-9,125e-9,3e-9]; % m
% Solver and hardware options
problem = problem.setMicroMagSolver( 'Dynamic' );
problem = problem.setUseCuda( true );
problem = problem.setUseCVODE( false );
problem.nThreads = int32(8);
% Material parameters
problem.A0 = 1.3e-11; % J/m
problem.Ms = 8e5*ones(prod(resolution),1); % A/m
problem.K0 = zeros(prod(resolution),1); % J/m^3
problem.alpha = 4.42e3; % m/(A s)
problem.gamma = 2.21e5; % m/(A s)
% Initial state, normalised internally if it is not already
problem.m0(:,1) = 1/sqrt(3);
problem.m0(:,2) = 1/sqrt(3);
problem.m0(:,3) = 1/sqrt(3);
% Output times and the applied field as a function of time
problem = problem.setTime( linspace(0,1e-9,200) );
HystDir = 1/mu0*[-24.6,4.3,0]/1000;
problem = problem.setHext( @(t) (t>-1)'.*HystDir, linspace(0,1e-9,2000) );
% Solve
solution = struct();
solution = problem.MagTenseLandauLifshitzSolver_mex( struct(problem), solution );
The struct(problem) call performs a final consistency check before the data
is handed to Fortran: scalar values of Ms, A0, K0, K1 and
K2 are expanded to one value per cell, and m0 is normalised if it is
not of unit length (a warning is issued). It also prints an estimate of the
memory needed by the demagnetization tensor.
problem.MagTenseLandauLifshitzSolver_mex is a function handle that
setUseCuda sets, pointing either at MagTenseLandauLifshitzSolver_mex or
at MagTenseLandauLifshitzSolverNoCUDA_mex.
Note
The constructor sets useCuda to 0 but does not populate that function
handle, so setUseCuda has to be called at least once - with false
for a CPU run - before the solver can be invoked through
problem.MagTenseLandauLifshitzSolver_mex. Alternatively, call the
MEX-file directly by name.
Python problem setup
In Python the problem is a MicromagProblem object. Most parameters are
constructor arguments, the remaining ones are plain attributes that can be
assigned after construction. The applied field is passed as a callable to the
run method rather than being stored on the problem:
import numpy as np
from magtense.micromag import MicromagProblem
mu0 = 4 * np.pi * 1e-7
res = (36, 9, 1)
problem = MicromagProblem(
res=res,
grid_L=[500e-9, 125e-9, 3e-9],
grid_type="uniform",
solver="dynamic",
m0=1 / np.sqrt(3),
A0=1.3e-11,
Ms=8e5,
K0=0.0,
alpha=4.42e3,
gamma=2.21e5,
cuda=False,
cvode=False,
)
h_ext = np.array([-24.6, 4.3, 0]) / 1000 / mu0
def h_ext_fct(t):
# Constant in time; must return an (nt_h_ext, 3) array
return np.outer(np.ones_like(t), h_ext)
t_out, M_out, pts, H_exc, H_ext, H_dem, H_ani, *_ = problem.run_simulation(
t_end=1e-9, nt=200, fct_h_ext=h_ext_fct, nt_h_ext=2000
)
m0 accepts a scalar (all components set to that value), an (ntot,3)
array, or None, in which case a random unit vector is drawn for every cell.
As in Matlab, m0 is normalised on assignment and a warning is issued if it
was not already of unit length.
The three run methods are
run_simulation(t_end, nt, fct_h_ext, nt_h_ext)- a single solve, used for both the dynamic and the explicit solver;run_hysteresis(H_ext)- a predefined sequence of applied fields, see Hysteresis simulations;run_hysteresis_adaptive(...)- a field sweep where the solver picks the field steps itself, see Adaptive hysteresis.
Units and conventions
Quantity |
Unit |
Comment |
|---|---|---|
Lengths, grid size |
m |
|
Saturation magnetization \(M_s\) |
A/m |
divide a value in tesla by \(\mu_0\) |
Applied and effective fields |
A/m |
|
Exchange constant \(A_0\) |
J/m |
often written \(A_\mathrm{ex}\) |
Anisotropy constants \(K_0, K_1, K_2\) |
J/m3 |
|
Damping \(\alpha\), precession \(\gamma\) |
m/(A s) |
Landau-Lifshitz form, see The equation that is solved |
Time |
s |
|
Temperature |
K |
The returned magnetization M is the reduced magnetization
\(\mathbf{m}\), i.e. it is normalised to unit length and must be multiplied
by \(M_s\) to obtain A/m.