So far, we have learned how to run an NVE MD simulation for a periodic system from both programming and application points of view. In such simulations, the total energy (E) should be constant with the propagation of time. This is called the microcanonical ensemble in statistical physics. However, this setup is not really the truth for many practical simulations. It is more likely that the system would interact with the surrounding environment and exchange heat over the boundaries.
In a real scenario, we often want to study the system under a constant temperature condition, instead of constant energy. This method is particularly useful for simulating systems in the canonical ensemble (constant number of particles, volume, and temperature, often denoted as NVT).
To maintain the system at a desired temperature, we couple it to an external heat bath. There are several thermostat techniques for this purpose. In real life, temperature is a measure of how fast the particles are moving on average. But in a computer simulation, you need a way to control this “temperature” to make sure it stays at the desired level throughout the simulation. A thermostat in molecular dynamics is a tool that helps you keep the temperature of your simulated system steady, just like how a thermostat in your house keeps the room temperature stable.
To introduce the thermostat to a MD system, the trick is to modify the integrator. Currently, there exist several flavors of thermostat techniques. Perhaps the easiest way to rescale velocities to force the total kinetic energy to be equal to
The main idea of Anderson thermostat is inspired by the observation of physical collisions between particles in the system and particles in the surrounding environment. After collisions, the particles in the system would change the velocities. These “collisions” ensure that the system exchanges energy with the environment, maintaining thermal equilibrium.
Thus we could periodically pick some particles and randomize the velocities of some particles in the system. These randomizations mimic the effect of an external environment interacting with the particles, ensuring that the system’s temperature remains constant. Hence, we allow two types of MD integration rules in the actual code.
-
Random particle selection and velocity assignment. With a certain probability
$\nu$ , the velocity of each particle is reassigned by sampling from a Maxwell-Boltzmann distribution corresponding to the desired temperature$T$ . - Ordinary update. If the particle’s velocity is not reassigned, it evolves according to the usual equations of motion (e.g., using the Verlet integration method).
In this technique, collision Frequency
The Anderson thermostat is relatively simple to implement, requiring only the addition of random velocity reassignment at each time step. However, it may not reflect the real dynamics. Since velocities are randomly reassigned, the resulting particle trajectories may not correspond to those in a real physical system where energy exchange occurs through physical interactions. This is particularly true for a periodic system without the clear definition of boundary. In addition, one needs to play with the
The algorithm can be described as follows.
- Initialization: Set up initial positions and velocities for the particles, and calculate initial forces.
- Main MD Loop:
- For each time step:
- Update positions using the current velocities and forces.
- Calculate new forces based on updated positions.
- Update velocities using the average of old and new forces.
- Apply the Anderson thermostat by randomly reassigning velocities with a certain probability.
- For each time step:
- Output: Collect and store data for analysis, such as positions, velocities, and energies.
The pseudocode for the Anderson thermostat algorithm is as follows:
import numpy as np
def anderson_thermostat(V, T, nu):
sigma_v = np.sqrt(k_B * T / MASS)
for i in range(num_particles):
if np.random.rand() < nu * TIMESTEP:
V[i] = np.random.normal(0, sigma_v, 3)
return V
# Initialization
T = 300 # in K
R = Initialize_positions()
V = Initialize_velocities()
F = calculate_forces(R)
# Main MD loop
for step in range(num_steps):
# Update R, V, F using Verlet integration
R += V * TIMESTEP + 0.5 * F * TIMESTEP**2 / MASS
F_new = calculate_forces(R)
V += 0.5 * (F + F_new) * TIMESTEP / MASS
F = F_new
# Apply Anderson thermostat to randomly reassign V
V = anderson_thermostat(V, T, nu)
The Langevin thermostat maintains the temperature of a system while also modeling the effects of friction and random forces, similar to those that might be encountered in a viscous fluid. The basic idea is to modify the equations of motion by adding two additional terms to the standard Newtonian dynamics:
-
Frictional Force
$\gamma m_i \mathbf{v}_i$ : the damping effect of the environment, which tends to slow down the particles. -
Random Force
$\mathbf{R}_i(t)$ : the random collisions with particles from the heat bath, which cause the particles to move randomly, maintaining the system’s temperature. These kicks help maintain the temperature of the system by continuously injecting energy into the system.
A typical value of
In MD simulations, the Langevin equation is integrated with the Velocity Verlet algorithm, modified to include the Langevin terms. A simple update rule for the velocity might look like this:
import numpy as np
def langevin_thermostat(V, F, gamma):
# Update R, V, F using Verlet integration
R += V * TIMESTEP + 0.5 * F * TIMESTEP **2 / MASS
# Update velocities with deterministic part
V += 0.5 * F * TIMESTEP / MASS
# Apply friction and random force (stochastic part)
V += -gamma * V * TIMESTEP
sigma = np.sqrt(2 * gamma * kB * T / MASS)
V += np.random.normal(0, sigma, V.shape) * np.sqrt(dt)
# Update forces and velocities
F_new = calculate_forces(positions)
V += 0.5 * (F + F_new) / MASS * TIMESTEP
F = F_new
return R, V, F
# Initialization
T = 300 # in K
R = Initialize_positions()
V = Initialize_velocities()
F = calculate_forces(R)
# Main MD loop
for step in range(num_steps):
R, V, F = langevin_thermostat(R, V, F, L, gamma)
If we want to avoid the use of brute-force velocity reassignment, a gentler approach is to control the temperature by coupling the system to an additional degree of freedom, which acts as a “thermal reservoir” that exchanges energy with the system. Nosé introduced a method where the system’s Hamiltonian is extended by adding an artificial variable that represents the thermal reservoir. This approach ensures that the system’s temperature fluctuates around a desired value, allowing it to correctly sample the canonical ensemble. Then, Hoover reformulated the equations of motion to include a friction term (
In the Nosé-Hoover thermostat, the velocity is updated via the following term
where
Then
where
import numpy as np
# Thermostat variables
Q = 100.0 # Thermal inertia parameter (tune this for stability)
xi = 0.0
# Initialization
R = Initialize_positions()
V = Initialize_velocities()
F = calculate_forces(R)
# Main MD loop
for step in range(num_steps):
# Verlet-like integration
R += V * TIMESTEP + 0.5 * F * TIMESTEP**2 / MASS
F_new = calculate_forces(R)
# Update velocities
V += 0.5 * (F + F_new) * TIMESTEP / MASS
V *= (1 - 0.5 * xi * TIMESTEP) / (1 + 0.5 * xi * TIMESTEP)
# Update the Nosé-Hoover thermostat variable
kE= 0.5 * np.sum(mass * V**2)
xi += dt * (2 * kE / (3 * N * k_B * T) - 1) / Q
Complete the reading in Appendix-W2.
-
Complete the codes in Colab.
-
Modify your code with different
$\nu$ (Anderson),$\gamma$ (Langevin), and$Q$ (Nosé-Hoover) parameters for different thermostats and monitor the progress of kinetic energies. -
Debug the code lec_02_langevin_debug.py.
-
Understand the behaviors of different thermostat techniques as shown in the following figure (obtained from your Colab exercise).