Molecular Dynamics¶
Set up environment (optional)¶
These steps are required for Google Colab, but may work on other systems too:
[ ]:
# import locale
# locale.getpreferredencoding = lambda: "UTF-8"
# !python3 -m pip install janus-core[all]
[ ]:
from ase.build import bulk
from ase.visualize import view
from ase.io import read
from data_tutorials.data import get_data
import matplotlib.pyplot as plt
import numpy as np
from janus_core.calculations.md import NVE, NVT
from janus_core.helpers.stats import Stats
from janus_core.processing import post_process
Use data_tutorials
to get the data required for this tutorial:
[ ]:
get_data(
url="https://raw.githubusercontent.com/stfc/janus-tutorials/main/data/",
filename=["precomputed_NaCl-traj.xyz"],
folder="data",
)
Cooling¶
Build NaCl structure and attach the MACE calculator:
[ ]:
NaCl = bulk("NaCl", "rocksalt", a=5.63, cubic=True)
NaCl = NaCl * (2, 2, 2)
[ ]:
view(NaCl, viewer="x3d")
Prepare a simulation, cooling the structure from 300K to 200K in stepx of 20K, with 5fs at each temperature:
[ ]:
cooling = NVT(
struct=NaCl.copy(),
arch="mace_mp",
device="cpu",
model_path="small",
calc_kwargs={"default_dtype": "float64"},
temp_start=300.0,
temp_end=200.0,
temp_step=20,
temp_time=5,
stats_every=2,
)
Run cooling:
[ ]:
cooling.run()
The final structures at each temperature are saved in Cl32Na32-nvt-T300.0-final.xyz
, Cl32Na32-nvt-T280.0-final.xyz
, …, Cl32Na32-nvt-T200.0-final.xyz
.
The statiscs from the simulation are also saved every 20 steps in Cl32Na32-nvt-T300.0-T200.0-stats.dat
. This can then be analysed using the Stats
module:
[ ]:
data = Stats("Cl32Na32-nvt-T300.0-T200.0-stats.dat")
[ ]:
print(data)
[ ]:
plt.plot(data[0], data[5], label="Actual")
plt.plot(data[0], data[16], label="Target")
plt.legend()
plt.xlabel("Steps")
plt.ylabel("Temperature / K")
plt.show()
Heating, followed by MD¶
This will prepare an NVT MD simulation, initially increasing the temperature from 0K to 300K in 20K steps, with 1fs at each temperature, before a further 10 steps (10fs) at 300K.
The final structure at each temperature will be saved, e.g. Cl32Na32-nvt-T0-final.xyz
, Cl32Na32-nvt-T0-final.xyz
, …, Cl32Na32-nvt-T300-final.xyz.
[ ]:
heating = NVT(
struct=NaCl.copy(),
arch="mace_mp",
device="cpu",
model_path="small",
calc_kwargs={"default_dtype": "float64"},
temp_start=0, # Start of temperature ramp
temp_end=300.0, # End of temperature ramp
temp_step=20, # Temperature ramp increments
temp_time=1, # Time at each temperature in ramp
temp=300, # MD temperature
steps=10, # MD steps at 300K
)
[ ]:
heating.run()
The same structure can then be used to run an additional NVE MD similation for 50 steps (50fs), with post-processing performed to compute the RDF by setting post_process_kwargs = {"rdf_compute": True}
, with the results saved to Cl32Na32-nve-rdf.dat
:
[ ]:
md = NVE(
struct=heating.struct,
temp=300,
stats_every=5,
steps=50,
post_process_kwargs={"rdf_compute": True, "rdf_rmax": 5, "rdf_bins": 200},
)
[ ]:
md.run()
[ ]:
rdf = np.loadtxt("Cl32Na32-nve-T300-rdf.dat")
bins, counts = zip(*rdf)
[ ]:
plt.plot(bins, counts)
plt.ylabel("RDF")
plt.xlabel("Distance / Å")
plt.show()
The same post-processing can also be performed separately after completing the simulation:
[ ]:
data = read("data/precomputed_NaCl-traj.xyz", index=":")
[ ]:
rdf = post_process.compute_rdf(data, rmax=5.0, nbins=200)
[ ]:
plt.plot(rdf[0], rdf[1])
plt.ylabel("RDF")
plt.xlabel("Distance / Å")
plt.show()