{{define "entry"}}

{{.Name}}{{.Ins}} {{with .Doc}}

{{.}}

{{end}} {{with .Methods}}

methods: {{range .}} {{.}}  {{end}}

{{end}} {{with .Examples}}

examples: {{range .}} [{{.}}] {{end}}

{{end}}

{{end}} {{.Include "head.html"}} {{.Include "header.html"}}

mumax3.10 API

Basics

Advanced Features

Go to mumax3.9c API

Syntax

The mumax3 input syntax is a subset of Go's syntax, somewhat similar to C. It is case-independent however, so msat is the same as Msat or MSAT.

Defining variables

New variables are declared using :=. Variables have a fixed type, inferred from the declaration's right-hand-side. Assigning to existing variables is done using =. E.g.:
i := 7         // defines a new variable i, type automatically detected to be int
print(i)       // now we can use i
i = 5          // assign new value, don't use ':=' (attempt to re-declare)

str := "hello" // defines str, type automatically is string
//str = 1      // would fail, cannot assign int to string

Arithmetic

Most common arithmetic operations are possible. Also Go's math library and some common constants are available. For raise-to-the-power, pow(x,y) should be used.
x := pi*(3+4)/5
x = pow(x, 3)
x++
y := abs(cbrt(cosh(erf(erfc(gamma(J0(Y0(2))))))))

Control structures

Loops are possible as well:
for i:=0; i<10; i++{
	 print(i)
}

Implicit functions

Some of the API features accept a function as argument (e.g.: RunWhile(func()bool), or all input parameters). In that case, and only in this case, the argument is implicitly converted to a function, which is re-evaluated each time it's needed. E.g.:
value := sin(pi*t)  // value is a float64, RHS evaluated only once
Msat = value        // time-independent Msat
versus:
Msat = sin(pi*t)    // RHS converted to function, re-evaluted every time

Methods

Some of the API instances have methods defined on them. You can call methods on an instance by using '.' as in most object oriented programming languages. E.g.: a material parameter such as Msat has the method SetRegion(int, float) to set the value of the material parameter in a certain region:
Msat.SetRegion(1, 800e3) // Set Msat=520e3 in region 1 

Mesh size and geometry

The simulation mesh defines the size of the box around your magnet. It should be set at the beginning of the script. The number of cells should preferably be powers of two, or at least have small prime factors (2,3,5,7). E.g.:
Nx := 128
Ny := 64
Nz := 2
sizeX := 500e-9
sizeY := 250e-9
sizeZ := 10e-9
SetGridSize(Nx, Ny, Nz)
SetCellSize(sizeX/Nx, sizeY/Ny, sizeZ/Nz)

Periodic boundary conditions

Optionally, periodic boundary conditions can be enabled:
SetPBC(5, 0, 0)        // 5 extra images on left and right sides.
SetGridSize(128, 64, 1)
SetCellSize(5e-9, 5e-9, 5e-9)
Setting a nonzero PBC value in a direction enables wrap-around in that direction. The precise value passed determines how many repetitions are seen by the demag field. E.g., in the above example the demag field behaves as if 5 repetitions are present to the left and to the right side. Choosing a large number may cause long initialization time.

Resizing the mesh

The mesh can be changed at any later time in the simulation. This will cause the magnetization to be stretched onto the new mesh if needed, and the geometry and regions to be re-calculated. After resize some cells which had zero magnetization may now fall inside the magnet geometry, they will be initialized to random magnetization.

Setting the geometry

Optionally a magnet Shape other than the full simulation box can be specified. In order to set the geometry, you first need to define a shape.
 geometryShape := cylinder(400e-9, 20e-9).RotX(45*pi/180).Transl(1e-6,0,0)
SetGeom(geometryShape)

{{range .FilterName "setgeom" "setgridsize" "setcellsize" "setpbc" "setmesh"}} {{template "entry" .}} {{end}} {{range .FilterName "edgesmooth"}} {{template "entry" .}} {{end}}

Shapes

A shape is an abstract object which outlines an area in a 3D universe. Shapes are useful for different tasks, e.g.: to define the geometry of a magnet, to define material regions, or to set locally a specific initial magnetization configuration. One can specify primitive shapes, constructed at the origin (box center), and translate/rotate them if needed. All positions are specified in meters and the origin lies in the center of the simulation box. E.g.:
myShape := cylinder(400e-9, 20e-9).RotX(45*pi/180).Transl(1e-6,0,0))
anotherShape := Circle(400e-9).sub(Circle(200e-9))

{{range .FilterReturn "Shape"}} {{template "entry" .}} {{end}}

Material regions

Optionally, up to 256 material regions can be defined. Since each cell is made from one material, it is associated with exactly one region. So regions can not overlap. Each cell is assigned material region 0 by default. It's a good idea to output regions to verify whether each cell is assigned to the intended region. Each region can have its own material parameters, and we can output averages over each region. E.g.:
DefRegion(1, circle(1e-6))
DefRegion(0, circle(1e-6).Inverse()) // redundant
save(regions)
Msat.SetRegion(1, 800e6)
tableAdd(m.Region(1))    // add average m over region 1 to table

{{range .FilterName "DefRegion" "DefRegionCell" "regions"}} {{template "entry" .}} {{end}}

Initial magnetization

The initial magnetization is set by assigning a Config to m, setting it in separate regions, or by loading a file directly.
m = uniform(1, 0, 0)
m.SetRegion(1, vortex(1, 1))
m.LoadFile("config.ovf")
m.SetInShape(circle(50e-9), uniform(0,0,1))

{{range .FilterName "m"}} {{template "entry" .}} {{end}} {{range .FilterReturn "Config"}} {{template "entry" .}} {{end}}

Material parameters

Assigning to a material parameter sets a value in all regions. E.g.:
Msat  = 800e3
AnisU = vector(1, 0, 0)
When regions are defined, they can also be set region-wise:
Msat.SetRegion(0, 800e3)
Msat.SetRegion(1, 540e3)
Material parameters can be functions of time as well. E.g.:
f := 500e6
Ku1 = 500 * sin(2*pi*f*t)

{{range .FilterType "*engine.RegionwiseScalar" "*engine.RegionwiseVector"}} {{template "entry" .}} {{end}}

Excitation

Field or current excitations can be set in the same way as material parameters:
B_ext = vector(0.01, 1e-6*sin(2*pi*f*t), 0)
B_ext.SetRegion(1, vector(0, 0, 0.1))
Additionally, an arbitrary number of time- and space-dependent vector fields of the form g(x,y,z) * f(t) may be added. (E.g., to simulate the field of an antenna or an arbitrary current running through the magnet)
B_ext.Add(LoadFile("antenna.ovf"), sin(2*pi*f*t))
J.Add(LoadFile("current.ovf"), 1)

{{range .FilterType "*engine.Excitation"}} {{template "entry" .}} {{end}}

Spin currents

The effect of spin-polarized currents on the magnetization dynamics can be modelled in different ways. In Mumax3 you can use the Zhang-Li model or the Slonczewski model. For both models, a spin-polarized current field needs to be defined. This is done by setting the current density field J and the polarization Pol.

Zhang-Li model

When using the the Zhang-Li model, it is possible to set the non-adiabaticity through the material parameter xi:
J = vector(1e12, 0, 0)
Pol = 1
xi = 0.1

Slonczewski model

To use the Slonczewski model, you need to define the magnetization configuration of the fixed layer. This fixed layer can be placed above or below the sample. The Slonczewski parameter and the prefactor of the secondary spin transfer torque term of the Slonczewski model can be set through the material parameters Lambda and EpsilonPrime respectively:
DisableZhangLiTorque = true
J = vector(1e12, 0, 0)
Pol = 0.6
FixedLayer = vector(1,0,0)
FixedLayerPosition = FIXEDLAYER_TOP
EpsilonPrime = 0.02
Lambda = 1

{{range .FilterName "epsilonprime" "Lambda" "Pol" "xi" "J" "FreeLayerThickness" "fixedlayer" "fixedlayerposition" "fixedlayer_top" "fixedlayer_bottom" "DisableSlonczewskiTorque" "DisableZhangLiTorque" }} {{template "entry" .}} {{end}}

Magnetic Force Microscopy

Mumax3 has built-in generation of MFM images from a 2D magnetization. The MFM tip lift can be freely chosen. By default the tip magnetization is modeled as a point monopole at the apex. This is sufficient for most situations. Nevertheless, it is also possible to model partially magnetized tips by setting MFMDipole to the magnetized portion of the tip, in meters. E.g., if only the first 20nm of the tip is (vertically) magnetized, set MFMDipole=20e-9.

{{range .FilterPrefix "MFM"}} {{template "entry" .}} {{end}}

Output quantities

The quantities listed below can be output. Also, derived quantities can be produced: the quantity restricted to a certain region or a single component. E.g.:
m           // magnetization quantity
m.Comp(0)   // x-component
m.Region(1) // magnetization in region 1 (0 elsewhere)

{{range .FilterType "engine.ScalarField" "engine.VectorField" "*engine.geom" "*engine.thermField" "*engine.ScalarValue" "*engine.VectorValue"}} {{template "entry" .}} {{end}}

Slicing and dicing output

To save storage space, it's possible to save only the part of the output we're interested in. This works on all output quantities (not only m)
save(m)                         // save full magnetization
save(m.Comp(0))                 // save only x-component
save(CropLayer(m, 13))          // save only layer 13
save(CropLayer(m.Comp(0), 13))  // save only x-component of layer 13
Or even:
mx   := m.Comp(0)
mx13 := CropLayer(mx, 13) 
save(mx13)
tableAdd(mx13)

{{range .FilterName "Crop" "CropX" "CropY" "CropZ" "CropLayer" "CropRegion"}} {{template "entry" .}} {{end}}

Scheduling output

All input and output quantities (as described above) can be saved in a space-dependent way (".ovf" file), or as spatial averages (table output). The data table ("table.txt") contains by default the time and average magnetization. More columns can be added with TableAdd().
save(B_ext)

tableadd(B_ext)
tablesave()
Optionally, the output/averaging can be done over a single region:
save(m.Region(1))
TableAdd(m.Region(1)) 
User-defined variables can be added to the table with TableAddVar().
myField := 0.42
TableAddVar(myField, "B_extra", "T")
myField = ...

{{range .FilterName "dump" "tableadd" "tableaddvar" "tablesave" "tableautosave" "save" "saveas" "autosave" "snapshot" "snapshotas" "snapshotformat" "autosnapshot" "filenameformat" "outputformat" "ovf1_text" "ovf1_binary" "ovf2_text" "ovf2_binary" "TablePrint" "FPrintln" "Sprint" "Sprintf" "Print" "Flush"}} {{template "entry" .}} {{end}}

Running

Run(time) runs the simulation for a given time in seconds, using sensible error settings.
Run(1e-9)
More fine-grained control is provided by RunWhile(condition), which runs as long as an arbitrary condition is met. E.g.:
mx := m.comp(0)
RunWhile(mx.average() < 0)   // search for switching field during reversal
Optionally, the solver accuracy may be fine-tuned. E.g.:
MaxDt = 1e-12
MinDt = 1e-15
MaxErr = 1e-6
Optionally, a different solver may be chosen (at any point) with SetSolver(int). Currently available solver types:
  • 6: RK56 (Fehlberg) solver. This is the highest order solver available, but which is typically not faster than the RK45 solver.
  • 5: RK45 (Dormand-Prince) solver (the default). An accurate solver, very fast for magnetization dynamics at the cost of some memory usage.
  • 4: Classical 4th-order Runge-Kutta method. Intended for simulations where a fixed, relatively large time step is desired.
  • 3: RK23 (Bogacki-Shampine) solver. A robust and reasonably fast solver with low memory requirements. Typically outperforms RK45 when relaxing the magnetization with little dynamics, so it used internally by Relax().
  • 2: Adaptive Heun solver. Robust and uses very little memory but takes smaller time steps than the higher-order solvers. Also suited when a fixed, relatively small time step is desired.
  • 1: Euler solver (requires FixDt = ..., ignores other settings). Only useful in exceptional situations or for debugging.
E.g.:
SetSolver(2) // Heun
FixDt = 1e-15

Relax

Relax() tries to evolve the magnetization as closely as possible to the minimum energy state. This function assumes all excitations have been turned off (temperature, electrical current, time-dependent magnetic fields). During relax precession is disabled and the time t does not increase. There is no need to set high damping.

In general it is difficult to be sure the minimum energy state has been truly reached. Hence, relax may occasionally return after the energy has reached a local minimum, a saddle point, or a rather flat valley in the energy landscape.

Minimize

Minimize() is like Relax, but uses the conjugate gradient method to find the energy minimum. It is usually much faster than Relax, but is a bit less robust against divergence. E.g., a random starting configuration can be Relaxed, but may fail with Minimize. Minimize is very well suited for hysteresis calculations, where we are never far away from the ground state.


{{range .FilterName "run" "steps" "runwhile" "relax" "minimize"}} {{template "entry" .}} {{end}} {{range .FilterName "t" "dt" "MinDt" "MaxDt" "FixDt" "HeadRoom" "MaxErr" "step" "NEval" "peakErr" "lastErr" "minimizerstop" "minimizersamples" "relaxtorquethreshold"}} {{template "entry" .}} {{end}} {{range .FilterName "SetSolver"}} {{template "entry" . }} {{end}}

Moving simulation window

Mumax3 can automatically shift the magnetization so that the simulation "window" stays centered on a region of interest. Shifting is done to keep a freely chosen magnetization component nearly zero. E.g.
ext_centerwall(0)
ext_rmSurfaceCharge(0, -1, 1)
TableAdd(TotalShift)
will try to keep mx (component 0, counting from 0) close to zero. If desired, one can override which "new" magnetization is inserted from the sides by setting ShiftMagL and ShiftMagR, though the default behaviour is usually OK.
{{range .FilterName "ext_centerwall" "ext_rmSurfaceCharge" "shift" "shiftgeom" "shiftm" "shiftregions" "shiftmagl" "shiftmagr" "shiftmagd" "shiftmagu" "totalshift"}} {{template "entry" .}} {{end}}

Extensions

Extensions are extra functionalities that are not officially supported. They are aimed at rather specific problems and may not work as expected for your particular situation. Their API and functionality may change in future releases.
{{range .FilterPrefix "ext_"}} {{template "entry" .}} {{end}}

Custom quantities

Using existing quantities, it is possible to define new custom quantities. E.g.: instead of using the pre-defined ext_topologicalchargedensity quantity, it is possible to define this quantity yourselves inside an input script:
cs := 1e-9
setcellsize(cs,cs,cs)
setgridsize(64,64,1)

// Use central finite differences to approximate the spatial derivatives of m
mL := Shifted(m,-1,0,0) // shift left
mR := Shifted(m,1,0,0)  // shift right
mD := Shifted(m,0,-1,0) // shift up
mU := Shifted(m,0,1,0)  // shift down
dmdx := Mul( Const(1/(2*cs)), Madd(mR,mL,1,-1) )
dmdy := Mul( Const(1/(2*cs)), Madd(mU,mD,1,-1) ) 

// Define the topological charge density
chargeDensity := Mul( Const(1/(4*pi)), Dot(m, Cross(dmdx,dmdy)))

// Save the topological charge density of a skyrmion
m = neelskyrmion(1,-1)
saveas(chargeDensity, "chargeDensity.ovf")

{{range .FilterName "Add" "Const" "ConstVector" "Cross" "Div" "Dot" "MAdd" "Masked" "Mul" "MulMV" "Shifted"}} {{template "entry" .}} {{end}}

Custom effective field terms

It is possible to define additional effective field terms by promoting a custom quantity to an effective field term. The corresponding energy density term can also be added by promoting a custom quantity. E.g.: instead of using the existing anistropy field in mumax3, you could define the uniaxial anisotropy field (and the corresponding energy density) yourselves:

Ms := 1100e3
K  := 0.5e6
u  := ConstVector(1, 0, 0)
anisField := Mul( Const(2*K/Ms)  , Mul( Dot(u, m), u))
anisEdens := Mul( Const(-0.5*Ms) , Dot( anisField, m))

AddFieldTerm(anisField) // promote anisField to an effective field term
AddEdensTerm(anisEdens) // promote anisEdens to an energy density term

tableAdd(E_custom)  // Add a column with the energy related to the custom field

{{range .FilterName "AddFieldTerm" "AddEdensTerm" "RemoveCustomFields" "B_custom" "E_custom" "Edens_custom" }} {{template "entry" .}} {{end}}

Misc

Other available functions.
{{range .FilterLeftovers}} {{template "entry" .}} {{end}}
{{range .All }} {{template "entry" .}} {{end}}