Skip to content

Commit f0cc586

Browse files
Documentation 1
* magnetic interactions * rdf * energy * general structure * custom potential * potentials and thermostats * plotting and drawing * corrections
1 parent c4ef1c7 commit f0cc586

File tree

1 file changed

+354
-1
lines changed

1 file changed

+354
-1
lines changed

README.md

Lines changed: 354 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,358 @@
44
[![Build status](https://ci.appveyor.com/api/projects/status/1ofg9ianvcciq26v?svg=true)](https://ci.appveyor.com/project/Mikhail-Vaganov/nbodysimulator-jl)
55

66
This project is under development at the moment. The implementation of potential calculations is fairly experimental and has not been extensively verified yet.
7+
You can test simulation of different systems now but be aware of possible changes in future.
78

8-
You can test simulation of different systems now but be aware of possible changes in future.
9+
## Add Package
10+
11+
In order to start simulating systems of N interacting bodies, it is necessary to add `NBodySimulator` package to Julia and then begin to use it:
12+
13+
```julia
14+
]add NBodySimulator
15+
using NBodySimulator
16+
```
17+
18+
If you cannot wait to start codding, try to run some scripts from `examples` folder. The number of particles `N` and the final timestep of simulations `t2` are the two parameters which will determine the time of script execution.
19+
20+
## Basic Components
21+
There are three basic components required for any simulation of systems of N-bodies: `bodies`, `system` and `simulation`.
22+
23+
**Bodies** or **Particles** are the objects which will interact with each other and for wich the equations of Newton's 2nd law are solved during the simulation process. Three parametes of a body are necessary, they are initial location, initial velocity and mass. `MassBody` structure represents such particles:
24+
25+
```julia
26+
using StaticArrays
27+
r = SVector(.0,.0,.0)
28+
v = SVector(.1,.2,.5)
29+
mass = 1.25
30+
body = MassBody(r,v,mass)
31+
```
32+
For the sake of simulation speed it is advised to use static arrays from the corresponding package.
33+
34+
A **System** covers bodies and necessary parameters for correct simulation of interaction between particles. For example, to create an entity for a system of gravitationally interacting particles, one needs to use `GravitationalSystem` constructor:
35+
36+
```julia
37+
const G = 6.67e-11 # m^3/kg/s^2
38+
system = GravitationalSystem(bodies, G)
39+
```
40+
41+
**Simulation** is an entity determining parameters of the experiment: time span of simulation, global physical constants, borders of the simulation cell, external magnetic or electric fields, etc. The required arguments for `NBodySImulation` constructor are the system to be tested and the time span of simulation.
42+
43+
```julia
44+
tspan = (.0, 10.0)
45+
simulation = NBodySimulation(system, tspan)
46+
```
47+
48+
There are different types of bodies but they are just containers of particle parameters. The interaction and acceleration of particles are defined by the potentials or force fields.
49+
50+
## Generating bodies
51+
The package exports quite a useful function for placing simular particles in the nodes of a cubic cell with their velocities distributed in accordance with the Maxwell–Boltzmann law:
52+
53+
```julia
54+
N = 100 # number of bodies/particles
55+
m = 1.0 # mass of each of them
56+
v = 10.0 # mean velocity
57+
L = 21.0 # size of the cell side
58+
59+
bodies = generate_bodies_in_cell_nodes(N, m, v, L)
60+
```
61+
62+
Molecules for the SPC/Fw water model can be imported from a PDB file:
63+
```julia
64+
molecules = load_water_molecules_from_pdb("path_to_pdb_file.pdb")
65+
```
66+
67+
## Potentials
68+
The potentials or force field determines the interaction of particles ant, therefore, their acceleration.
69+
70+
There are several structures for basic physical interactions:
71+
72+
```julia
73+
g_parameters = GravitationalParameters(G)
74+
m_parameters = MagnetostaticParameters(μ_4π)
75+
el_potential = ElectrostaticParameters(k, cutoff_radius)
76+
jl_parameters = LennardJonesParameters(ϵ, σ, cutoff_radius)
77+
spc_water_paramters = SPCFwParameters(rOH, ∠HOH, k_bond, k_angle)
78+
```
79+
80+
The Lennard-Jones potential is used in molecular dynamics simulations for approximating interactions between neutral atoms or molecules. The SPC/Fw water model is used in water simulations. The meaning of arguments for `SPCFwParameters` constructor will be clarified further in this documentation.
81+
82+
`PotentialNBodySystem` structure represents systems with a custom set of potentials. In other words, the user determines the ways in which the particles are allowed to interact. One can pass the bodies and parameters of interaction potentials into that system. In case the potential parameters are not set, during the simulation particles will move at constant velocities without acceleration.
83+
84+
```julia
85+
system = PotentialNBodySystem(bodies, Dict(:gravitational => g_parameters, electrostatic: => el_potential))
86+
```
87+
88+
### Custom Potential
89+
There exists an [example](http://docs.juliadiffeq.org/latest/models/physical.html) of simulation of an N-body system at absolutely custom potential.
90+
91+
Here is shown how to create custom acceleration functions using tools of NBodySimulator.
92+
93+
First of all it is necessary to create a structure for parameters for the custom potential.
94+
95+
```julia
96+
struct CustomPotentialParameters <: PotentialParameters
97+
a::AbstractFloat
98+
end
99+
```
100+
101+
Next, the acceleration function for the potential is required. The custom potential defined here creates a force acting on all the particles proportionate to their masses. The first argument of the function determines the potential for which the acceleration should be calculated in this method.
102+
103+
```julia
104+
import NBodySimulator.get_accelerating_function
105+
function get_accelerating_function(p::CustomPotentialParameters, simulation::NBodySimulation)
106+
ms = get_masses(simulation.system)
107+
(dv, u, v, t, i) -> begin custom_accel = SVector(0.0, 0.0, p.a); dv .= custom_accel*ms[i] end
108+
end
109+
```
110+
111+
After the parameters and acceleration function are created, one can instantiate a system of particles interacting with a set of potentials which includes the just created custom potential:
112+
113+
```julia
114+
parameters = CustomPotentialParameters(-9.8)
115+
system = PotentialNBodySystem(bodies, Dict(:custom_potential_params => parameters))
116+
```
117+
118+
### Gravitational Interaction
119+
Using NBodySimulator it is possible to simulate gravitational interaction of celestial bodies.
120+
In fact, any structure for bodies can be used for simulation of gravitational interaction since all those structures are required to have mass as one of their parameters:
121+
122+
```julia
123+
body1 = MassBody(SVector(0.0, 1.0, 0.0), SVector( 5.775e-6, 0.0, 0.0), 2.0)
124+
body2 = MassBody(SVector(0.0,-1.0, 0.0), SVector(-5.775e-6, 0.0, 0.0), 2.0)
125+
```
126+
127+
Solving gravitational problem one needs to specify the gravitational constant G.
128+
```julia
129+
G = 6.673e-11
130+
```
131+
132+
Now we have enough parameters to create a GravitationalSystem object:
133+
134+
```julia
135+
system = GravitationalSystem([body1,body2], G)
136+
```
137+
138+
Usually we solve an N-body problem for a certain period of time:
139+
140+
```julia
141+
tspan = (0.0, 1111150.0)
142+
```
143+
144+
The created objects determines the simulation we want to run:
145+
146+
```julia
147+
simulation = NBodySimulation(system, tspan)
148+
sim_result = run_simulation(simulation)
149+
```
150+
151+
And, finally, we can animate our solution showing two equal bodies rotating on the same orbit:
152+
```julia
153+
using Plots
154+
animate(sim_result, "path_to_animated_particles.gif")
155+
```
156+
157+
<img src="https://user-images.githubusercontent.com/16945627/39958539-d2cf779c-561d-11e8-96a8-ffc3a595be8b.gif" alt="Here should appear a gif of rotating bodies" width="350"/>
158+
159+
### Electrostatic Interaction
160+
Interaction between charged particles obeys Coulomb's law. The movement of such bodies can be simulated using `ChargedParticle` and `ChargedParticles` structures.
161+
162+
The following example shows how to model two oppositely charged particles. If one body is more massive that another, it will be possible to observe rotation of the light body around the heavy one without ajusting their positions in space. The constructor for `ChargedParticles` system requires bodies and Coulomb's constant `k` to be passed as arguments.
163+
164+
```julia
165+
r = 100.0 # m
166+
q1 = 1e-3 # C
167+
q2 = -1e-3 # C
168+
m1 = 100.0 # kg
169+
m2 = 0.1 # kg
170+
v2 = sqrt(abs(k * q1 * q2 / m2 / r)) # m/s - using the centrifugal acceleration
171+
t = 2 * pi * r / v2 # s - for one rotation
172+
p1 = ChargedParticle(SVector(0.0, 0.0, 0.0), SVector(0.0, 0, 0.0), m1, q1)
173+
p2 = ChargedParticle(SVector(100.0, 0.0, 0.0), SVector(0.0, v2, 0.0), m2, q2)
174+
system = ChargedParticles([p1, p2], k)
175+
simulation = NBodySimulation(system, (0.0, t))
176+
sim_result = run_simulation(simulation)
177+
```
178+
179+
### Magnetic Interaction
180+
An N-body system consisting of `MagneticParticle`s can be used for simulation of interacting magnetic dipoles, though such dipoles cannot rotate in space. Such a model can represent single domain particles interacting under the influence of a strong external magnetic field.
181+
182+
In order to create a magnetic particle one specifies its location in space, velocity and the vector of its magnetic moment. The following code shows how we can construct an iron particle:
183+
184+
```julia
185+
iron_dencity = 7800 # kg/m^3
186+
magnetization_saturation = 1.2e6 # A/m
187+
188+
mass = 5e-6 # kg
189+
r = SVector(-0.005,0.0,0.0) # m
190+
v = SVector(0.0,0.0,0.0) # m/s
191+
magnetic_moment = SVector(0.0, 0.0, magnetization_saturation * mass / iron_dencity) # A*m^2
192+
193+
p1 = MagneticParticle(r, v, mass, magnetic_moment)
194+
```
195+
196+
For the second particle we will use a shorter form:
197+
198+
```julia
199+
p2 = MagneticParticle(SVector(0.005, 0.0, 0.0), SVector(0.0, 0.0, 0.0), 5e-6, SVector(0.0,0.0,0.00077))
200+
```
201+
202+
To calculate magnetic interactions properly one should also specify the value for the constant μ<sub>0</sub>/4π or its substitute. Having created parameters for the magnetostatic potential, one can now instantiate a system of particles which should interact magnetically. For that purpose we use `PotentialNBodySystem` and pass particles and potential parameters as arguments.
203+
204+
```julia
205+
parameters = MagnetostaticParameters(μ_4π)
206+
system = PotentialNBodySystem([p1, p2], Dict(:magnetic => parameters))
207+
simulation = NBodySimulation(system, (t1, t2))
208+
sim_result = run_simulation(simulation, VelocityVerlet(), dt=τ)
209+
```
210+
211+
## Molecular Dynamics (MD)
212+
NBodySimulator allows one to conduct molecular dynamic simulations for the Lennard-Jones liquids, SPC/Fw model of water and other molecular systems thanks to implementations of basic interaction potentials between atoms and molecules:
213+
214+
- Lennard-Jones
215+
- electrostatic and magnetostatic
216+
- harmonic bonds
217+
- harmonic valence angle generated by pairs of bonds
218+
219+
The comprehensive examples of liquid argon and water simulations can be found in `examples` folder.
220+
Here only the basic principles of the molecular dynamics simulations using NBodySimulator are presented using liquid argon as a classical MD system for beginners.
221+
222+
First of all one needs to define paramters of the simultaion:
223+
224+
```julia
225+
T = 120.0 # °K
226+
T0 = 90.0 # °K
227+
kb = 8.3144598e-3 # kJ/(K*mol)
228+
ϵ = T * kb
229+
σ = 0.34 # nm
230+
ρ = 1374/1.6747# Da/nm^3
231+
m = 39.95# Da
232+
N = 216
233+
L = (m*N/ρ)^(1/3)#10.229σ
234+
R = 0.5*L
235+
v_dev = sqrt(kb * T / m)
236+
bodies = generate_bodies_in_cell_nodes(N, m, v_dev, L)
237+
238+
τ = 0.5e-3 # ps or 1e-12 s
239+
t1 = 0.0
240+
t2 = 2000τ
241+
```
242+
243+
Liquid argon consists of neutral molecules so the Lennard-Jones potential runs their interaction:
244+
245+
```julia
246+
parameters = LennardJonesParameters(ϵ, σ, R)
247+
lj_system = PotentialNBodySystem(bodies, Dict(:lennard_jones => parameters));
248+
```
249+
250+
Then, a thermostat and boundary conditions should be selected and instantiated:
251+
252+
```julia
253+
thermostat = NoseHooverThermostat(T0, 200τ)
254+
pbc = CubicPeriodicBoundaryConditions(L)
255+
simulation = NBodySimulation(lj_system, (t1, t2), pbc, thermostat, kb);
256+
result = run_simulation(simulation, VelocityVerlet(), dt=τ)
257+
```
258+
It is recommended to use `CubicPeriodicBoundaryConditions` since cubic boxes are among the most popular boundary conditions in MD. There are different variants of the `NBodySimulation` constructor for MD:
259+
260+
```julia
261+
simulation = NBodySimulation(lj_system, (t1, t2));
262+
simulation = NBodySimulation(lj_system, (t1, t2), pbc);
263+
simulation = NBodySimulation(lj_system, (t1, t2), pbc, thermostat);
264+
simulation = NBodySimulation(lj_system, (t1, t2), pbc, thermostat, kb);
265+
```
266+
267+
The default boundary conditions are `InfiniteBox` withouth any limits, default thermostat is `NullThermostat` which does no thermostating and default Boltzmann constant `kb` equals its value in SI, i.e. 1.38e-23 J/K.
268+
269+
## Thermostats
270+
Usually during simulation of a system is required to be at a particular temperature. NBodySimulator contains several thermostas for that purpose. Here the thermostating of liquid argon is presented, for thermostating of water one can refer to [this post](https://mikhail-vaganov.github.io/gsoc-2018-blog/2018/08/06/thermostating.html)
271+
272+
### [Andersen Thermostat](http://www.sklogwiki.org/SklogWiki/index.php/Andersen_thermostat)
273+
```julia
274+
τ = 0.5e-3 # timestep of integration and simulation
275+
T0 = 90
276+
ν = 0.05/τ
277+
thermostat = AndersenThermostat(90, ν)
278+
```
279+
![andersen thermostating](https://user-images.githubusercontent.com/16945627/44002487-cd99653a-9e5c-11e8-8481-78945a930d94.png)
280+
281+
### [Berendsen Thermostat](http://www2.mpip-mainz.mpg.de/~andrienk/journal_club/thermostats.pdf)
282+
```julia
283+
τB = 2000τ
284+
thermostat = BerendsenThermostat(90, τB)
285+
```
286+
![berendsen thermostating](https://user-images.githubusercontent.com/16945627/44002495-f07e164a-9e5c-11e8-8db7-16c09a7631cd.png)
287+
288+
### [Nosé–Hoover Thermostat](http://www.sklogwiki.org/SklogWiki/index.php/Nos%C3%A9-Hoover_thermostat)
289+
```julia
290+
τNH = 200τ
291+
thermostat = NoseHooverThermostat(T0, 200τ)
292+
```
293+
![nose-hoover thermostating](https://user-images.githubusercontent.com/16945627/44002501-ffc1aea0-9e5c-11e8-857b-9e3c83197336.png)
294+
295+
### Langevin Thermostat
296+
```julia
297+
γ = 10.0
298+
thermostat = LangevinThermostat(90, γ)
299+
```
300+
![langevin thermostating](https://user-images.githubusercontent.com/16945627/44002505-0683c6b0-9e5d-11e8-8647-5b15b98eb0fa.png)
301+
302+
## Analyzing the Result of Simulation
303+
Once the simulation is completed, one can analyze the result and obtain some useful characteristics of the system.
304+
305+
Function `run_simulation` returns a structure containig the initial parameters of simulation and the solution of differential equation (DE) required for description of the corresponding system of particles. There are different functions which help to intepret solution of DEs into physical quantities.
306+
307+
One of the main charachterestics of a system during molecular dynamics simulations is its thermodynamic temperature. The value of the temperature at a particular time `t` can be obtained via calling this function:
308+
309+
```julia
310+
T = temperature(result, t)
311+
```
312+
313+
### [Radial distribution functions](https://en.wikipedia.org/wiki/Radial_distribution_function)
314+
The RDF is another popular and essential characteristic of molecules or similar systems of particles. It shows the reciprocal location of particles averaged by the time of simulation.
315+
316+
```julia
317+
(rs, grf) = @time rdf(result)
318+
```
319+
320+
The dependence of `grf` on `rs` shows radial distribution of particles at different distances from an average particle in a system.
321+
Here the radial distribution function for the classic system of liquid argon is presented:
322+
![rdf for liquid argon](https://user-images.githubusercontent.com/16945627/43990348-843b164c-9d74-11e8-8d9e-daaff142c0b7.png)
323+
324+
325+
### Mean Squared Displacement (MSD)
326+
The MSD characteristic can be used to estimate the shift of particles from their initial positions.
327+
```julia
328+
(ts, dr2) = @time msd(result)
329+
```
330+
For a standrad liquid argon system the displacement grows with time:
331+
![rdf for liquid argon](https://user-images.githubusercontent.com/16945627/43990362-9a67c0aa-9d74-11e8-9512-08840294d411.png)
332+
333+
### Energy Functions
334+
335+
Energy is a higlhy important physical characteristic of a system. The module provides four functions to obtain it, though the `total_energy` function just sums potential and kinetic energy:
336+
337+
```julia
338+
e_init = initial_energy(simualtion)
339+
e_kin = kinetic_energy(result, t)
340+
e_pot = potential_energy(result, t)
341+
e_tot = total_energy(result, t)
342+
```
343+
344+
## Ploting Images
345+
Using tools of NBodySimulator one can export results of simulation into a [Protein Database File](https://en.wikipedia.org/wiki/Protein_Data_Bank_(file_format)). [VMD](http://www.ks.uiuc.edu/Research/vmd/) is a well-known tool for visualizing molecular dynamics, which can read data from PDB files.
346+
347+
```julia
348+
save_to_pdb(result, "path_to_a_new_pdb_file.pdb" )
349+
```
350+
351+
In future it will be possible to export results via FileIO interface and its `save` function.
352+
353+
Using Plots.jl one can draw positions of particles at any time of simulation or create an animation of moving particles, molecules of water:
354+
355+
```julia
356+
using Plots
357+
plot(result)
358+
animate(result, "path_to_file.gif")
359+
```
360+
361+
Makie.jl also has a recipe for plotting results of N-body simulations. The [example](http://makie.juliaplots.org/stable/examples-meshscatter.html#Type-recipe-for-molecule-simulation-1) is presenten in the documentation.

0 commit comments

Comments
 (0)