Skip to content

Commit 49c06f3

Browse files
committed
add a blog post
1 parent e67a991 commit 49c06f3

2 files changed

Lines changed: 152 additions & 0 deletions

File tree

pages/blog/coding/cvr_example.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
+++
2+
cover = false
3+
+++
4+
5+
# Canonical Velocity Rescaling Thermostat
6+
7+
This thermostat is the most widely used thermostat for molecular dynamics (MD)
8+
simulations. The [manuscript](https://pubs.aip.org/aip/jcp/article-abstract/126/1/014101/186581/Canonical-sampling-through-velocity-rescaling?redirectedFrom=fulltext) it was
9+
published in is one of the highest cited papers related to MD simulations.
10+
Due to the massive success of this thermostat there is a wide array of resources
11+
explaining the thermostat and the math behind it in simple terms. However, none
12+
of these resources show how to implement the thermostat in a programming language.
13+
Making the source code of MD packages the only option, but they are often very
14+
difficult to follow. Since I've implemented this thermostat in Julia for my
15+
MD package ([YASS](https://github.com/Cavenfish/YetAnotherSimulationSuite.jl)),
16+
I wanted to put out a short explanation of implementing it.
17+
18+
## Brief Math Explanation
19+
20+
The temperature of a system is related to the total kineteic energy of a system
21+
by,
22+
23+
$
24+
K = \frac{1}{2} k_B N_f T
25+
$
26+
27+
where $K$ is the kinetic energy, $k_B$ is Boltzmann constant, $N_f$ is the
28+
degrees of freedom, and $T$ is the temperature. A velocity rescaling thermostat
29+
takes advantage of this experssion by scaling the velocities to increase or
30+
decrease the temperature of the system. Typically through a scaling factor
31+
($\alpha$),
32+
33+
$
34+
\alpha = \sqrt{\frac{K_\text{target}}{K\text{current}}}
35+
$
36+
37+
where $K_\text{target}$ is the target kinetic energy, and $K\text{current}$ is
38+
the kinetic energy of the current timeframe of the simulation. The CVR thermostat
39+
enforces a canonical sampling for $K_\text{target}$ to ensure proper
40+
thermodynamic proporties in the simulation. The explicit derivation of this
41+
can be found in the original manuscript, or even other online resources. For
42+
the sake of just learning to implement the thermostat only these two concepts
43+
are necessary.
44+
45+
## Coding it Up
46+
47+
We first need a function that calculates the temperature of our system from
48+
the kinetic energy. We can calculate this by taking $\sum_i m_i v_i^2 = k_B N_f T$,
49+
where the $\frac{1}{2}$ is dropped from both sides.
50+
51+
```julia
52+
function getTemp(v::AbstractVector, m::AbstractVector, kB::Float64)
53+
# Leave out the 1/2 to get 2Ekin for T calc
54+
N = length(m)
55+
Nf = 3N - 3
56+
v2 = [i'i for i in v]
57+
Ekin = sum(m .* v2)
58+
59+
Ekin / (kB * Nf)
60+
end
61+
```
62+
63+
The next thing we need is a function for sampling from a normal and gamma
64+
distributions. You could implement this from scratch but its better to use the
65+
implementations in [Distributions.jl](https://juliastats.org/Distributions.jl/stable/)
66+
since they are well tested and highly performant. These two functions are
67+
`Normal` and `Gamma` in the code blocks below.
68+
69+
The CVR thermostat needs to have non-zero velocities to scale (or else you still
70+
have zero after scaling), so if your system has all zero velocities (or $T=0$)
71+
then you skip apply the thermostat and let the system gain some amount of kinetic
72+
energy due to the potential. This means adding a conditional return in your CVR
73+
function to avoid wasteful computations. In this example I use a short circuit
74+
expression (which I love but some hate), so I'll quickly explain them. These
75+
expressions take advantage of the and/or logic by using the `&&` and `||`
76+
operators to write compact if-then statements.
77+
78+
```julia
79+
# This shows a typical if statment within a for loop
80+
for i = 1:100
81+
if i % 10 == 0
82+
println(i)
83+
end
84+
end
85+
86+
# This does the same thing but using a short circuit expression
87+
for i = 1:100
88+
i % 10 == 0 && println(i)
89+
end
90+
91+
# Again, the same thing but using ||
92+
for i = 1:100
93+
i % 10 != 0 || println(i)
94+
end
95+
```
96+
97+
Getting back to the CVR thermostat, once we have a non-zero kinetic energy
98+
we can rescale the velocities to try to reach our desired temperature.
99+
100+
```julia
101+
function CVR!(
102+
v::AbstractVector, m::AbstractVector,
103+
kB::Float64, tau::Float64, Ttar::Float64
104+
)
105+
N = length(m)
106+
Tsim = getTemp(v, m, kB)
107+
108+
Tsim == 0.0 && return
109+
110+
Nf = 3N - 3
111+
n = Normal(0.0,1.0)
112+
R1 = rand(n)
113+
114+
R2 = if (Nf-1)%2 == 0
115+
alpha = (Nf - 1)/2
116+
G = Gamma(alpha, 1)
117+
118+
2 .* rand(G)
119+
else
120+
alpha = (Nf - 2)/2
121+
G = Gamma(alpha, 1)
122+
123+
2 .* rand(G) .+ (rand(n) .^2)
124+
end
125+
126+
tau > 0.1 ? c1 = exp(-1/tau) : c1 = 0.0
127+
128+
K = 0.5 * Nf * kB * Tsim
129+
sigma = 0.5 * Nf * kB * Ttar
130+
131+
Knew = @. (
132+
K + (1-c1) * (sigma * (R2 + R1^2) / Nf - K) +
133+
2 * R1 * sqrt(K * sigma / Nf * (1-c1) * c1)
134+
)
135+
alpha2 = @. sqrt(Knew / K)
136+
137+
@. v *= alpha2
138+
end
139+
```

pages/blog/index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
+++
2+
cover = false
3+
name = "Blog"
4+
+++
5+
6+
My blog is mostly a collection of random tutorials/guides on how to do things
7+
(mostly coding based). I will also occasionally write some product reviews.
8+
9+
\post{
10+
"Canonical Velocity Rescaling Thermostat",
11+
"A short guide on implementing the CVR thermostat in Julia.",
12+
"/pages/blog/coding/cvr_example.md"
13+
}

0 commit comments

Comments
 (0)