8. Frequently Asked Questions

8.1. What is the difference between the OOMMF and |nmag| approach?

There are several aspects. One important point is the calculation of the demagnetisation field as this is a computationally very expensive step.

`OOMMF`_ is based on discretising space into small cuboids (often called ‘finite differences’). One advantage of this method is that the demag field can be computed very efficiently (via fast Fourier transformation techniques). One disadvantage is that this methods works less well (i.e. less accurately) if the geometry shape does not align with a cartesian grid as the boundary then is represented as a staircase pattern.

|nmag|‘s finite elements discretise space into many small tetrahedra. The corresponding approach towards the computation of the demagnetisation field (which is the same as `Magpar`_‘s method) is based on the Fredkin and Koehler Hybrid Finite Element/Boundary Element method. The advantage of this method (over OOMMF’s approach) is that curved and spherical geometries can be spatially resolved much more accurately. However, this method of calculating the demagnetisation field is less efficient than OOMMF’s approach for thin films. (In particular: memory requirements for the boundary element method grow as the square of the number of surface points.) Note that for simulation of thin films, the hybrid Finite Element/Boundary Element (as used by |nmag| and `Magpar`_) is likely to require a lot of memory (see Memory requirements of boundary element matrix).

There are other points that are related to the fundamentally different discretisation approach used to turn a field theory problem (with a conceptually infinite number of degrees of freedom) into a finite problem: OOMMF assumes the magnetisation in every cell to be constant (with jumps at boundaries), while |Nmag| assumes magnetisation to be continuous and vary linearly within cells (thus slightly violating the constraint of constant magnitude within a cell of non-constant magnetisation).

8.2. ... So, this means the major difference is “cubes” vs. “tetrahedra”?

No. Simplicial mesh discretisation is fundamentally different from finite-difference discretisation. With OOMMF, say, magnetisation degrees of freedom are associated with the centers(!) of the cells, while with nmag, they are associated with corners. This conceptual difference has many implications, e.g. for the question how to conceptually deal with the exchange interaction between different materials.

8.3. Why do you have your own Python interpreter (=nsim)?

In order to provide the ability to run code in a distributed environment (using MPI), we cannot use the standard Python executable. (Technically speaking, a program started under MPI control will receive extra MPI-related command line arguments which upset the standard Python interpreter.) It so happens that – by providing our own Python executable which is called nsim – we have easier access to the low-level library of |nsim| which is written in Objective Caml.

8.4. What is nsim - I thought the package is called |nmag|?

The The |Nsim| library is our general purpose multi-physics simulation environment. The corresponding executable is started through the nsim command. |Nmag| is a collection of scripts that provide micromagnetic functionality on top of nsim. For this reason, nsim is being mentioned a lot in the manual.

8.5. How fast is nmag in comparison to magpar?

Internally, some of the magpar and nmag core components are structurally very similar. In particular, the time integration routine is almost identical up to some philosophical issues such as how to keep the length of the magnetisation vector constant, and whether or not to use a symmetrical exchange matrix and a post-processing step rather than combining these into an asymmetrical matrix, etc. The actual wall clock time used will depend to a large degree on the requested accuracy of the calculations (see example timestepper tolerances).

Given equivalent tolerance parameters, we have found (the single-process version of) nmag to be about as fast as magpar. The computation of an individual velocity dM/dt is very similar in nmag and magpar, and about equally efficient. However, we observe that, depending on the particular problem, subtle differences in the philosophies underlying time integration can lead to noticeable differences in the number of individual steps required to do some particular simulation, which can be up to about 25% of simulation time in either direction.

Setup time is a different issue: nmag derives its flexibility from abstract approaches where magpar uses hard-coded compiled functions. Where magpar uses a hand-coded Jacobian, nmag employs the nsim core to symbolically compute the derivative of the equations of motion. There is a trade-off: the flexibility of being able to introduce another term into the equations of motion without having to manually adjust the code for the Jacobian comes at a price in execution time. Therefore, nmag’s setup time at present is far larger than magpar’s. This can be alleviated to a considerable degree by providing hard-coded “bypass routines” which can be used as alternatives to the symbolically founded methods for special situations that are frequently encountered (such as setting up a Laplace operator matrix). Conceptually, it is easy to add support for this but due to limited manpower, it has not happened yet.

In short: once the setup stage is over, nmag is about as fast as magpar. Magpar’s setup time, however, is much smaller. Magpar is also more efficient in memory usage.

8.6. How do I start a time-consuming nmag run in the background?

While this is a Unix rather than a nmag issue, it comes up sufficiently often to address it here.

Well-known techniques to run programs in the background are:

  • Using the “nohup” (no-hangup) command, as in:

    nohup nsim sphere1.py &
  • Using the at-daemon for scheduling of command execution at given times:

    at now
    warning: commands will be executed using /bin/sh
    at> nsim example1.py
    at> <EOT>
    job 2 at Fri Dec 14 12:08:00 2007
  • Manual daemonization by using a parent process which forks & exits, as in:

    perl -e 'exit(0) if fork(); exec "nsim sphere1.py"'

    (But if you know Unix to that degree, you presumably would not have asked in the first place.)

  • One of the most elegant ways to start a process in the background is by using the “screen” utility, which is installed on a number of Unix systems. With “screen”, it becomes possible to start a text terminal session in such a way that one can “detach” from it while keeping the session alive, and even log out and log in again much later and from a different machine, re-attaching the terminal session and continuing work from the point where it was left.

    While it is a good idea to read the documentation, most basic usage of “screen” requires the knowledge of three commands only:

    • With “screen -R”, one can re-attach to a running session, automatically creating a new one if none was created before.
    • Within a “screen” session, Control+a is a prefix keyboard command for controlling “screen”: Pressing Control-a and then Control-d will detach the session.
    • Control-a ? will being up a help screen showing all “screen” keyboard commands.

8.8. How should I cite nmag?

Please cite:

  • Thomas Fischbacher, Matteo Franchin, Giuliano Bordignon, and Hans Fangohr. A Systematic Approach to Multiphysics Extensions of Finite-Element-Based Micromagnetic Simulations: Nmag, in IEEE Transactions on Magnetics, 43, 6, 2896-2898 (2007). (Available online)

8.9. Why can you not use the step as a unique identifier?

There are two reasons. Firstly, |nmag| may be extended in future to support effective energy minimisation in which case the step becomes somewhat meaningless (although it could probably still be used as an identifier if we identify minimisation iterations with steps). Secondly (and more importantly), in |nmag|, the user can modify the magnetisation directly using set_m (either scripted or interactively). This will change the configuration of the system without increasing the step counter of the time integrator. For this reason, we have the unique identifier id.

8.10. How to generate a mesh with more than one region using GMSH?

To assign different material properties to different objects, the mesher needs to assign different region number to different simplices of the mesh. The manual shows how to do this for netgen (see two_cubes.geo) file in example Example: two different magnetic materials).

How does one define different regions using GMSH? User Xu Shu (Wuhan, China) kindly provides this solution:

Within GMSH, one has to firstly “add physical groups” and choose the two detached volumes separately to add them into different groups, then choose “edit” to redefine the number of the two groups, thus you can get two physical objects as you want.

8.11. Can I run more than one simulation in one directory?

If you want to run two (or more) simulations in the same directory, then this is fine as well as long as they have different simulation names.

The simulation name is either the string given to the constructor of the simulation object, or – if no name is defined explicitly – the name of the python file that contains the simulation script (without the .py extension). See File names for data files for a detailed example for this.

Data and log files will all start with the simulation name, followed by some specific appended string and specific file extensions. It is thus safe to run simulations with different names in the same directory.

8.12. Can I save data to an arbitrary directory?

8.12.1. Do you really need to do so?

First, consider whether you really need to save data in a different directory. Remember that you can run many simulation with one single script just using a different simulation name, like:

s1 = Simulation('one')
s2 = Simulation('two')

When you save the data for simulation one you get files like one_dat.h5 and one_dat.ndt, while when dealing with simulation two you get two_dat.h5 and two_dat.nd5. There is no interference between the two simulations (and in particular it is necessary to save thedata in different directories.)

8.12.2. How to save data to a different directory

When you run a simulation script which saves data from a simulation, the files are saved by default in the current working directory. In order to change this and save data into a directory called ./mydir/ you should start your script in the following way:

import nmag
import nsim.features
fts = nsim.features.Features()
fts.set('etc', 'savedir', './mydir/')

Alternatively, you can change the current working directory at the beginning of the file with ordinary Python code:

import os
initial_dir = os.path.abspath(os.path.curdir)

If the directory you want to write to does not exist then (in both the two example) you may have to create it first, with something like:

the_dir = './mydir'
import os
if not os.path.exists(the_dir):

8.13. How to check the convergence of a simulation

How long it takes to run a simulation? This depends very much on what you are simulating and under what conditions (applied field, current, etc). Sometimes, however, your simulation may not be ending as quickly as you expected and you may want to check what is happening. It may be, indeed, that the simulation is not converging, which means that it may actually never end. One thing you can do in such a case is to take a look at the file *_progress.txt, where * stands for the simulation name (given to the Simulation class when creating the simulation oject). For example, if you created your simulation object with a line such as:

s = nmag.Simulation('one')

Then you may be looking for a file with name one_progress.txt. If you used simply s = nmag.Simulation() and your file is named two.py then you should look for a file with name two_progress.txt. This file contains statistics about the time integrator. You’ll first get the current time, step number, etc. Then you’ll get a list of rows each containing four columns, such as:

123 0.456 0.123 None

Column 1 is the step reached, an integer number which always increases. The file shows convergence statistics for the last few steps (it doesn’t contain statistics for all the steps, since this would make it quickly very big). Column 2 contains the current value of max || dM/dt ||. Column 3 contains the stopping value of dM/dt. Convergence is reached when column 2 < column 3 for at least two times. If the simulations is going well, then you should see that column 2 contains numbers which are not oscillating rapidly and are rather decreasing or increasing “smoothly”. This is what typically should happen, even if it can be that your simulation has really a bizarre dynamics which really oscillates in a frenetic way, so one should be careful when analysing the data. The fourth column contains an evaluation of the quality of the convergence according to what we just said. This number should be close to one when the convergence is smooth and close to zero when it is oscillating dramatically.

8.14. What to do in case of convergence problems

If your simulation has really a convergence problem, you can do two things:

  • improve the tolerances ts_abs_err and ts_rel_err (decrease these numbers) by using the method set_params of the Simulation object;
  • use a do=[('next_stage', at('stage_time',SI(x, 's')))] as an argument to the hysteresis method. This way you impose a maximum time x to spend in the computation of a stage (you should make sure this makes sense in your case).

8.15. How to visualise the difference between two fields defined over the same mesh

First save the data into two ASCII VTK files. For example:

nmagpp --vtk=m.vtk --vtkascii --fields=m simulation_name

Note the option "--vtkascii" to force the creation of a ASCII file. Let’s say this command created the two files m-000000.vtk and m-000001.vtk. You can now use the library pyvtk to load the two files, compute the difference and save it back to a third file:

import numpy, pyvtk
a = pyvtk.VtkData("m-000000.vtk")
b = pyvtk.VtkData("m-000001.vtk")
va = a.point_data.data[0].vectors
vb = b.point_data.data[0].vectors
for i in range(len(va)):
    va[i] = list(numpy.array(va[i]) - numpy.array(vb[i]))

Save this text to a file named diff.py and run it as:

python diff.py

You’ll get a third file with name difference.vtk containing the difference of the two fields.

If you are repeating this operation many times, it may become annoying to open again and again the diff.py file to change the names of the input files. You can then modify the script as follows:

import sys, numpy, pyvtk
a = pyvtk.VtkData(sys.argv[1])
b = pyvtk.VtkData(sys.argv[2])
va = a.point_data.data[0].vectors
vb = b.point_data.data[0].vectors
for i in range(len(va)):
    assert a.structure.points[i] == b.structure.points[i]
    va[i] = list(numpy.array(va[i]) - numpy.array(vb[i]))

The name of the files are taken from the command line. You can then compute the difference using:

python diff.py a.vtk b.vtk a_minus_b.vtk

Notice that in the last version of the script we also added the line:

assert a.structure.points[i] == b.structure.points[i]

which does just check that the two files are using the same set of points (i.e. the same mesh).

8.16. How to re-sample data from a saved h5 file

(Available in Nmag-0.2.0)

You can load an h5 file like this

import ocaml
from nmag.h5probe import Fields
handler = Fields("infile.h5")
field = handler.set_field_data("m", "Py", 0)

And probe one of its fields:

position = [0, 1, 2] # In mesh units (typically is nanometres)
value = ocaml.probe_field(field, "m_Py", position)[0][1]

This way you can create two arrays: rs containing an array of points and vs containing the corresponding values. You can then use pyvtk to generate a VTK file from these:

import pyvtk

grid = pyvtk.UnstructuredGrid(rs)
data = pyvtk.PointData(pyvtk.Vectors(vs))
v = pyvtk.VtkData(grid, data)

Here is a full example, which probes the magnetisation in the outer skin of a cylinder, in sections which are not equally spaced. Notice the usage of the function float_set to specify where the sampling should be denser (originally, here is where a domain wall was). The script should be used as nsim probe.py infile.h5 outfile.vtk:

import math
import sys

import pyvtk

import ocaml
from nmag.h5probe import Fields
from nmag import float_set

# First we probe the field in the required points
handler = Fields(sys.argv[1])
field = handler.set_field_data("m", "Py", 0)

xs = float_set([-150.0, -145.0, [], -15.0, -12.5, [], 15.0, 20.0, [], 50.0])
angles = float_set([0, [20], 2*math.pi])
R, R2 = (4.9, 5.1)

rs = []
vs = []
for x in xs:
  for angle in angles:
    r = [x, R*math.cos(angle), R*math.sin(angle)]
    rs.append([x, R2*math.cos(angle), R2*math.sin(angle)])
    vs.append(ocaml.probe_field(field, "m_Py", r)[0][1])

# Now we output the values to a VTK file
grid = pyvtk.UnstructuredGrid(rs)
data = pyvtk.PointData(pyvtk.Vectors(vs))
v = pyvtk.VtkData(grid, data)