Project Description

This project was created during my PhD project in material science and solid state physics. Provides an object-oriented Mono C# wrapper for VASP computations.

My motivation for creating this library is to avoid the frustrating and error-prone file manipulations needed to use first-principles tools like VASP. Having been doing computer programming almost fulltime for more than two decades, it seemed obvious to implement such a tool when I started my PhD in this field. To use it, just download a zip-file containing the latest revision from Source code above. An installation guide will follow later...

A guide to install all prerequisites: Installation guide

Hope my work may be useful.

Morten Bakkedal, PhD Student, Technical University of Denmark

Why would anyone choose C# for scientific computing?

Actually, it's a very nicely designed language. It supports custom arithmetic operators, properties, and language support for numerical value-types to handled more naturally. It has a mature and well optimized implementation for Linux known as Mono with the development environment MonoDevelop. Finally, C# has a unique feature known as LINQ that allows easy data manipulation and sorting.

See full discussion here: Language for scientific computing


A longer discussion of how to use Atomic Lab to parse VASP output files and do thermodynamic modeling is discussed in the documentation: Thermodynamics


Manipulation of atomic structures

Atomic Lab allows easy manipulation of structures as objects.

// Create an empty fcc structure.
Structure s = Structure.CreateFaceCenteredCubicStructure(3.9);

// Add two atoms to the structure.
s = s.Add(Atom.Fe, 0.0, 0.0, 0.0);
s = s.Add(Atom.C, 0.5, 0.5, 0.5);

// Visualize the structure in VESTA.


Objects are kept immutable by design. This way objects may be passes around in the code knowning that they'll never accidentally be modified. That's why the structure object is reassigned to in each manipulation in the sample above.

Atomic Lab allows quick 3D visualization of atomic structures using the third party tools VESTA or Gnuplot. Here the Show method shows the content of the structure object in VESTA.

Many other operations are provided like repeating or scaling the structure, replacing or moving some of the atoms, space group identification, or finding primitive cells.

More samples: Moving atoms

VASP integration

The purpose of this library is to provide an easy object-oriented wrapper around the first-principles atomic computational package VASP, without the need to do error-prone low-level file manipulations.

In the sample below a structure is created, scaled to multiple lattice constants, VASP is started for each structure and the structure's potential energy is computed. The computed energies are used to fit an equation of state, which is plotted as the last step.

List<VolumeEnergyPoint> points = new List<VolumeEnergyPoint>();

// Create a fcc structure.
Structure s0 = Structure.CreateFaceCenteredCubicStructure(4.04)
    .Add(Atom.Al, 0.0, 0.0, 0.0);

foreach (double a in new double[] { 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04 })
    // Scale structure linearly.
    Structure s = s0.Scale(a);

    // Prepare VASP with options represented as options.
    VaspProblem vasp = new VaspProblem();
    vasp.Structure = s;
    vasp.Convergence.PlaneWaveCutOff = 450.0;
    vasp.Convergence.Precision = VaspPrecision.Accurate;
    vasp.Options.Add(new MethfesselPaxtonSmearing(1, 0.1));
    vasp.Options.Add(new MonkhorstPackMesh(40.0));

    // Run VASP. An object is generated containing relevant output.
    VaspResult result = vasp.Run();

    points.Add(new VolumeEnergyPoint(s.Volume, result.PotentialEnergy));

// Fit an equation of state.
BirchMurnaghan5 bm5 = new BirchMurnaghan5(points);

// Fitted equilibrium lattice constant.
double a0 = Math.Pow(4.0 * bm5.V0, 1.0 / 3.0);
Console.WriteLine("a0 = {0}", a0);

// Plot with the original data points.
Gnuplot.Plot(new DataPlot(points), new FunctionPlot(bm5, 15.1, 18.2, "BM5"));

It's possible to run VASP completely without any file manipulation. The result is returned from VASP and represented as new objects. However, it's often useful to store VASP's output files for debugging, so this is also possible.


Many VASP options are included in the library, with logically linked options being grouped in the same class. Thus MethfesselPaxtonSmearing wraps the VASP options ISMEAR (=1) and SIGMA (=0.1) in the same object and verifies that their values make sense in the context. It also verifies that a GaussianSmearing object isn't added in the same configuration.

The sample above is executed in one step, without the need to do any manipulation of output files. The calculation is performed in serial on the local computer. However, it's easy to set up a parallel cluster computation using the PBS classes.

PBS job manager classes

The library provides an easy-to-use object wrapper for the UNIX job scheduler. Jobs are just instances of user-defined classes and dependencies may be specified by object references.

ATAT wrapper

Atomic Lab also provides an object-oriented wrapper for some of the popular ATAT tools. One such tool computes symmetrically distinct structures of a parent lattice, where some sites may contain one of a selection of atoms, known in Atomic Lab as a placeholder atom. In the sample below the structure contains two fixed sites of Fe atoms and two sites of C, N, or a vacancy. The sample prints the formulas for each structure, but it could easily be passed on to VASP instead. Finally, the usage of LINQ is shown, sorting the structures by total mass.

// Create a fcc structure in one expression; repeated twice in one direction.
Structure l = Structure.CreateFaceCenteredCubicStructure(3.9)
    .Add(Atom.Fe, 0.0, 0.0, 0.0)
    .Add(Atom.Placeholder(Atom.C, Atom.N, Atom.Vacancy), 0.5, 0.5, 0.5)
    .Repeat(2, 1, 1);

// Iterate through symmetrically distinct combinations.
foreach (Structure s in l.FillPlaceholders())
    // Print chemical formula.

// A more advanced sample using LINQ. Structures are sorted by total mass and vacancies are removed.
IEnumerable<string> formulas = l.FillPlaceholders()
    .OrderByDescending(structure => structure.Sites.Sum(site => site.Atom.Mass))
    .Select(structure => structure.RemoveVacancies().Formula);

// Result: N2Fe2, NCFe2, C2Fe2, NFe2, CFe2, Fe2
Console.WriteLine(string.Join(", ", formulas));

Thermal properties

Atomic Lab supplies algorithms to compute thermal properties of harmonic phonons and electronic excitations; all of this without getting hands dirty in low-level file manipulations. The images below show some of the capabilities of the library. The first is a useful illustration of atomic perturbations in the frozen phonon model for certain symmetry directions. The small cell to the left is the Wigner-Seitz cell. The second image shows the result of the quasi-harmonic model that allows computation of lattice expansion. The equilibrium volume of the structure at a given temperature is where the free energy is minimal. The surface plot shows the free energy surface as a function of temperature and volume. The red curve is the minimum energy and hence the equilibrium volume.



Plots are created using an object-oriented Gnuplot wrapper. All 3D plots are rotatable in real-time using the mouse.

More code samples will follow...

Supporting tools

The library contains a large set of supporting tools for efficient matrix algebra, plotting, statistics, complex arithmetics, etc.

Linear algebra

The immutable classes Matrix and Vector in the Atomic.Libraries.Mathematics namespace provides a way to represent and perform calculations on matrices.

Gnuplot wrapper

An object oriented Gnuplot wrapper in available in the Atomic.Libraries.Plotting namespace, allowing interactive plots on the screen as well as publication quality plots for papers produced from essentially the same code.

Random number generators

A collection of high-quality pseudo-random generators are available the Atomic.Libraries.Mathematics.RandomNumbers namespace. MersenneTwister is an efficient implementation of the Mersenne Twister. PolarBoxMullerGenerator can be used to generate normally distributed random numbers from any underlying random generator.


Numerically stable single pass classes for computing means, variances, correlations, root-mean-squares, etc. are provided in the Atomic.Libraries.Mathematics.Statistics namespace trough the classes MeanStatistics, VarianceStatistics, CovarianceStatistics, and RootMeanSquareStatistics.

Complex numbers

Provided by the Complex struct in the Atomic.Libraries.Mathematics namespace. May be used in conjunction with the GNU Scientific Library.

GNU Scientific Library wrapper

See the Gsl wrapper class in the Atomic.Libraries.Mathematics namespace.

Numerical optimization

An easy to use representation of non-linear optimization with non-linear constraints using IPOPT through the class IpoptOptimizer in the namespace Atomic.Libraries.Mathematics.Optimization.Ipopt.

Numerical optimization

When doing scientific computing it's important to have access to numerical optimization. Atomic Lab provides a copy of my other open source project FuncLib. Here mathematical functions may be specified represented by objects, so exact derivatives may be computed automatically. FuncLib provides a wrapper for the most powerful open source non-linear optimizer available IPOPT. This optimizer supports non-linear optimizer with multiple non-linear constraints. It's even able to find a solution when the starting point doesn't satisfy the constaints. Both the objective function and the constraints are specified using function objects as in this sample.

// Variables.
Variable x1 = new Variable();
Variable x2 = new Variable();
Variable x3 = new Variable();
Variable x4 = new Variable();

// Objective function and non-linear constraints.
Function f = x1 * x4 * (x1 + x2 + x3) + x3;
Function g1 = x1 * x2 * x3 * x4;
Function g2 = Function.Sqr(x1) + Function.Sqr(x2) + Function.Sqr(x3) + Function.Sqr(x4);

// Prepare the optimizer with variables bounds and non-linear equality and inequality constraints.
IpoptOptimizer o = new IpoptOptimizer();
o.Variables.Add(x1, x2, x3, x4);
o.ObjectiveFunction = f;
o.Constraints.Add(g1 >= 25.0);
o.Constraints.Add(g2 == 40.0);
o.Constraints.Add(x1 => 1.0, x1 <= 5.0);
o.Constraints.Add(x2 => 1.0, x2 <= 5.0);
o.Constraints.Add(x3 => 1.0, x3 <= 5.0);
o.Constraints.Add(x4 => 1.0, x4 <= 5.0);

// Run optimization starting from (x1, x2, x3, x4) = (1, 5, 5, 1). Not required to satisfy the constraints.
IOptimizerResult or = o.Run(x1 | 1.0, x2 | 5.0, x3 | 5.0, x4 | 1.0);

Console.WriteLine("f(x1, x2, x3, x4) = " + or.OptimalValue);
Console.WriteLine("g1(x1, x2, x3, x4) = " + g1.Value(or.OptimalPoint));
Console.WriteLine("g2(x1, x2, x3, x4) = " + g2.Value(or.OptimalPoint));
Console.WriteLine("x1 = " + or.OptimalPoint[x1]);
Console.WriteLine("x2 = " + or.OptimalPoint[x2]);
Console.WriteLine("x3 = " + or.OptimalPoint[x3]);
Console.WriteLine("x4 = " + or.OptimalPoint[x4]);

Last edited Jul 3, 2014 at 2:17 PM by bakkedal, version 21