LAMMPS#
In this example, we show how to run simulations with the popular molecular dynamics program
LAMMPS through aiida-shell. A complete script can be
downloaded here. Below we will go through the script step-by-step, followed by some tips
for basic analysis of the results.
Warning
This example purely serves to illustrate how to use aiida-shell.
There is no guarantee that LAMMPS is used correctly or in the most efficient way.
The most basic LAMMPS invocation looks as follows:
lmp -in input.file
The lmp executable is called passing the input.file file as an input using the -in command line option:
For the purposes of this example, we will take the input script for one of the official benchmarks. The complete input script can be downloaded here. We start our example script with some imports and by defining the input script:
#!/usr/bin/env runaiida
"""Simulation of Lennard-Jones fluid using LAMMPS."""
from aiida import orm
from aiida_shell import launch_shell_job
script = """
# 3d Lennard-Jones melt
variable x index 1
variable y index 1
variable z index 1
variable xx equal 20*$x
variable yy equal 20*$y
variable zz equal 20*$z
units lj
atom_style atomic
lattice fcc 0.8442
region box block 0 ${xx} 0 ${yy} 0 ${zz}
create_box 1 box
create_atoms 1 box
mass 1 1.0
velocity all create 1.44 87287 loop geom
pair_style lj/cut 2.5
pair_coeff 1 1 1.0 1.0 2.5
neighbor 0.3 bin
neigh_modify delay 0 every 20 check no
fix 1 all nve
run 100
"""
The next step is to call the lmp for this input script. To do so, we use the launch_shell_job function of
aiida-shell:
lmp executable for the example script through aiida-shell.#results, node = launch_shell_job(
'lmp',
arguments='-in {script}',
nodes={
'script': orm.SinglefileData.from_string(script),
},
)
The first argument is the command that should be executed, which is lmp in this example. The arguments argument
takes any command line options that should be passed. As shown in the introduction, this should be -in input.file.
The difference here is that the script we want to run is not a file on disk, but defined in memory assigned to the
script variable. Therefore, the input script filename in the arguments is replaced by the {script} placeholder.
The actual script is then added to the nodes dictionary, where the content of the script is wrapped in AiiDA’s
SinglefileData node class. This allows the script to be stored in the provenance graph. When launch_shell_job is
called, it will ensure that the content of the script is copied to a file inside the working directory where lmp is
invoked and the {script} placeholder is replaced with the filename.
The launch_shell_job function returns a tuple of two elements once the command has completed:
results: A dictionary of the outputs produced by the commandnode: The node that represents the execution of the command in AiiDA’s provenance graph
These outputs can be used to inspect the results of the executed command:
print(f'Calculation terminated: {node.process_state}')
print('Outputs:')
for key, node in results.items():
print(f'{key}: {node.__class__.__name__}<{node.pk}>')
The output should look something like the following:
Calculation terminated: ProcessState.FINISHED
Outputs:
stderr: SinglefileData<100>
stdout: SinglefileData<101>
The numbers between the <> brackets are the pks of the output nodes. In this case, there are just two SinglefileData
nodes that contain the output that was written to the stdout and stderr file descriptors. Their content can be
retrieved by loading the node through its pk using AiiDA’s load_node function, and then calling the get_content
method:
from aiida.orm import load_node
node = load_node(101)
print(node.get_content())
This should print the output written by LAMMPS which looks something like the following:
LAMMPS (20 Nov 2019)
Lattice spacing in x,y,z = 1.6796 1.6796 1.6796
Created orthogonal box = (0 0 0) to (33.5919 33.5919 33.5919)
1 by 1 by 1 MPI processor grid
Created 32000 atoms
create_atoms CPU = 0.00462803 secs
Neighbor list info ...
update every 20 steps, delay 0 steps, check no
max neighbors/atom: 2000, page size: 100000
master list distance cutoff = 2.8
ghost atom cutoff = 2.8
binsize = 1.4, bins = 24 24 24
1 neighbor lists, perpetual/occasional/extra = 1 0 0
(1) pair lj/cut, perpetual
attributes: half, newton on
pair build: half/bin/atomonly/newton
stencil: half/bin/3d/newton
bin: standard
Setting up Verlet run ...
Unit style : lj
Current step : 0
Time step : 0.005
Per MPI rank memory allocation (min/avg/max) = 13.82 | 13.82 | 13.82 Mbytes
Step Temp E_pair E_mol TotEng Press
0 1.44 -6.7733681 0 -4.6134356 -5.0197073
100 0.7574531 -5.7585055 0 -4.6223613 0.20726105
Loop time of 2.32985 on 1 procs for 100 steps with 32000 atoms
Performance: 18541.947 tau/day, 42.921 timesteps/s
100.0% CPU use with 1 MPI tasks x no OpenMP threads
MPI task timing breakdown:
Section | min time | avg time | max time |%varavg| %total
---------------------------------------------------------------
Pair | 1.9495 | 1.9495 | 1.9495 | 0.0 | 83.67
Neigh | 0.30639 | 0.30639 | 0.30639 | 0.0 | 13.15
Comm | 0.026903 | 0.026903 | 0.026903 | 0.0 | 1.15
Output | 0.0001828 | 0.0001828 | 0.0001828 | 0.0 | 0.01
Modify | 0.040458 | 0.040458 | 0.040458 | 0.0 | 1.74
Other | | 0.006424 | | | 0.28
Nlocal: 32000 ave 32000 max 32000 min
Histogram: 1 0 0 0 0 0 0 0 0 0
Nghost: 19657 ave 19657 max 19657 min
Histogram: 1 0 0 0 0 0 0 0 0 0
Neighs: 1.20283e+06 ave 1.20283e+06 max 1.20283e+06 min
Histogram: 1 0 0 0 0 0 0 0 0 0
Total # of neighbors = 1202833
Ave neighs/atom = 37.5885
Neighbor list builds = 5
Dangerous builds not checked
Total wall time: 0:00:02