Hello Sodium Chloride

In this example, we will simulate a Sodium Chloride crystal using molecular dynamics to propagate the position throughout time. Sodium Chloride adds a challenge in simulations because each atom carries a charge. These charges interact with a Coulomb potential which goes to zero as \(1 / r\). The problem is that the cutoff scheme used for pair potentials in most molecular simulations can not be used for anything that goes to zero slower than \(1 / r^3\). So we need to use alternative methods to compute the potential for the interactions between pairs of charges.

For this simulation, you will need the following files:

  • the initial configuration nacl.xyz`
  • the input file nacl.toml

You can download both files here.

Again, you can run the simulation which should complete in a minute with lumol nacl.toml. This will perform a molecular dynamics simulation of a NaCl crystal using electrostatic interactions between atomic charges.

The input file commented

We start with the input version again:

[input]
version = 1

Then we load the system from the nacl.xyz file and define the unit cell.

[[systems]]
file = "nacl.xyz"
cell = 22.5608

Next, we define our potential. This section is way bigger than the one for our previous Lennard-Jones example:

[systems.potentials.global]
cutoff = "8 A"

[systems.potentials.charges]
Na = 1.0
Cl = -1.0

[systems.potentials.pairs]
Na-Na = {type = "lj", sigma = "2.497 A", epsilon = "0.07826 kcal/mol"}
Cl-Cl = {type = "lj", sigma = "4.612 A", epsilon = "0.02502 kcal/mol"}
Na-Cl = {type = "lj", sigma = "3.5545 A", epsilon = "0.04425 kcal/mol"}

[systems.potentials.coulomb]
wolf = {cutoff = "8 A"}

Let’s break it down. First, we define some global values for the interactions: setting systems.potentials.global.cutoff will use the given cutoff for all pair interactions in the system. We set the charges of atoms in the systems.potentials.charges section.

[systems.potentials.global]
cutoff = "8 A"

[systems.potentials.charges]
Na = 1.0
Cl = -1.0

Then, we need to define the pair interactions for all possible pair combinations in the system, i.e. (Na, Na), (Cl, Cl), and (Na, Cl).

[systems.potentials.pairs]
Na-Na = {type = "lj", sigma = "2.497 A", epsilon = "0.07826 kcal/mol"}
Cl-Cl = {type = "lj", sigma = "4.612 A", epsilon = "0.02502 kcal/mol"}
Na-Cl = {type = "lj", sigma = "3.5545 A", epsilon = "0.04425 kcal/mol"}

Because our system contains charges, we need to use an electrostatic potential solver. Here we are going for the Wolf solver, with a cutoff of 8 A. Note that if we’d chose a cutoff different from the global one defined above, we would overwrite the global one for the coulombic interactions.

[systems.potentials.coulomb]
wolf = {cutoff = "8 A"}

We can now define the simulation and the outputs for this simulation. We are using a molecular dynamics simulation of the NaCl crystal with a timestep of 1 fs for integration (this will produce a NVE ensemble).

[[simulations]]
nsteps = 5000
outputs = [
    {type = "Trajectory", file = "trajectory.xyz", frequency = 10}
]

[simulations.propagator]
type = "MolecularDynamics"
timestep = "1 fs"

As before, run the simulation via

lumol nacl.toml

Until now, the force field we used for the system was defined in the same input file (in the system.potential section) as rest of the simulation settings. It can sometimes be interesting to separate the force field from the rest of the input, in particular when using the same force-field for multiple simulations. In the next example, we will do exactly this.