Skip to content

Commit 96fa3a2

Browse files
committed
doc updates
1 parent d80787a commit 96fa3a2

File tree

1 file changed

+104
-50
lines changed

1 file changed

+104
-50
lines changed

docs/src/ParticleSystem.md

Lines changed: 104 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ The `ParticleSystem` interface facilitates the use of `CellListMap` for the majo
1717

1818
## The mapped function
1919

20-
The function to be mapped for every pair of particles within the cutoff follows the same interface as the standard interface. It must be of the form
20+
The purpose of CellListMap is to compute a pairwise-dependent function for all pairs of particles that are closer to
21+
each other than a defined cutoff. This pairwise function must be implemented by the user and adhere to the following
22+
interface:
23+
2124
```julia
2225
function f(x, y, i, j, d2, output)
2326
# update output variable
@@ -26,6 +29,34 @@ end
2629
```
2730
where `x` and `y` are the positions of the particles, already wrapped relative to each other according to the periodic boundary conditions (a minimum-image set of positions), `i` and `j` are the indexes of the particles in the arrays of coordinates, `d2` is the squared distance between the particles, and `output` is the variable to be computed.
2831

32+
!!! info
33+
#### Details of the mapped function interface
34+
35+
The input parameters `x`, `y`, `i`, `j`, and `d2` must not be modified by the user. They are the
36+
the input data that the user may use to update the `output` variable.
37+
38+
| Input Parameter | Type | Meaning |
39+
|:----------------:|:-------:|:-----------|
40+
| `x` | `SVector` | The coordinates of particle `i` of the pair. |
41+
| `y` | `SVector` | The coordinates of particle `j` of the pair (minimum-image relative to `x`). |
42+
| `i` | `Int` | Index of first particle in the original array of coordinates. |
43+
| `j` | `Int` | Index of second particle in the original array of coordinates. |
44+
| `d2` | `<:Real` | Squared distance between the particles. |
45+
| `output` | user defined | the value to be updated |
46+
47+
**Notes:** `x` and `y` may be 2D or 3D vectors, depending on the dimension of the system. The type of
48+
the coordinates of `x`, `y`, and of `d2` are dependent on the input arrays and cutoff, and can be `Float64`,
49+
`Float32`, unitful quantities, etc.
50+
51+
| Return value | Type | Meaning |
52+
|:----------------:|:-------:|:-----------|
53+
| `output` | user defined | the updated value of output. |
54+
55+
The `output` variable **must** be returned by the function, being it mutable or immutable.
56+
57+
58+
### Basic examples
59+
2960
For example, computing the energy, as the sum of the inverse of the distance between particles, can be done with a function like:
3061
```julia
3162
function energy(d2,u)
@@ -35,9 +66,14 @@ end
3566
```
3667
and the additional parameters required by the interface can be eliminated by the use of an anonymous function, directly on the call to the `map_pairwise` function:
3768
```julia
38-
u = map_pairwise((x,y,i,j,d2,u) -> energy(d2,u), system)
69+
u = map_pairwise(
70+
(x,y,i,j,d2,u) -> energy(d2,u),
71+
system
72+
)
3973
```
40-
(what `system` is will be explained in the examples below).
74+
(what `system` is will be explained in the examples below). Note that the `energy` function does not use the `x`, `y`, `i`, and `j` input parameters, such
75+
that the anonymous function managing the interface could also be written as `(_, _, _, _, d2, u) -> energy(d2, u)`, making explicit the dummy character of
76+
these variables in the example.
4177

4278
Alternatively, the function might require additional parameters, such as the masses of the particles. In this case, we can use a closure to provide such data:
4379
```julia
@@ -49,7 +85,8 @@ const masses = # ... some masses
4985
u = map_pairwise((x,y,i,j,d2,u) -> energy(d2,u,masses), system)
5086
```
5187

52-
## Potential energy example
88+
Here we reinforce the fact that the `energy` functions defined above compute the contribution to the energy of the interaction of *a single* pair
89+
of particles. This function will be called for every pair of particles within the cutoff, automatically, in the `map_pairwise` call.
5390

5491
!!! note
5592
The `output` of the `CellListMap` computation may be of any kind. Most commonly, it is an energy, a set of forces, or other data type that can be represented either as a number, an array of numbers, or an array of vectors (`SVectors` in particular), such as an arrays of forces.
@@ -58,43 +95,57 @@ u = map_pairwise((x,y,i,j,d2,u) -> energy(d2,u,masses), system)
5895

5996
For these types of `output` data the usage does not require the implementation of any data-type dependent function.
6097

61-
For example, let us build a system of random particles in a cubic box, and compute an "energy", which in this case is simply the sum of `1/d` over all pair of particles, within a cutoff.
98+
## The ParticleSystem constructor
99+
100+
## Potential energy example
101+
102+
For example, here we read the coordinates of Argon atoms from a PDB file. The coordinates are given as
103+
vector of `SVector`s. We then compute an "energy", which in this case is simply the sum of `1/d` over all pair of particles, within a cutoff.
62104

63105
The `ParticleSystem` constructor receives the properties of the system and sets up automatically the most commonly used data structures necessary.
64106

65107
```julia-repl
66-
julia> using CellListMap, StaticArrays
108+
julia> using CellListMap, PDBTools
109+
110+
julia> argon_coordinates = coor(readPDB(CellListMap.argon_pdb_file))
67111
68112
julia> system = ParticleSystem(
69-
xpositions = rand(SVector{3,Float64},1000),
70-
unitcell=[1.0,1.0,1.0],
71-
cutoff = 0.1,
113+
xpositions=argon_coordinates,
114+
unitcell=[21.0,21.0,21.0],
115+
cutoff = 8.0,
72116
output = 0.0,
73117
output_name = :energy
74118
);
75119
```
76120

77-
Now, directly, let us compute a putative energy of the particles, assuming a simple formula which depends on the inverse of the distance between pairs:
121+
!!! note
122+
- Systems can be 2 or 3-dimensional.
123+
- The `unitcell` parameter may be:
124+
- a vector, in which case the system periodic boundaries are Orthorhombic, this is faster.
125+
- a matrix, in which case the system periodic boundaries are Triclinic (general).
126+
- `nothing` (by default), in which case no periodic boundary conditions will be used.
127+
- `Unitful` quantities can be provided, given appropriate types for all input parameters.
128+
129+
Now, let us compute the energy of the particles, assuming a simple formula which depends on the inverse of the distance between pairs:
78130

79131
```julia-repl
80-
julia> map_pairwise!((x,y,i,j,d2,energy) -> energy += 1 / sqrt(d2), system)
81-
30679.386366872823
132+
julia> function energy(x, y, i, j, d2, energy)
133+
energy += 1 / sqrt(d2)
134+
return energy
135+
end
136+
137+
julia> map_pairwise!(energy, system)
138+
207.37593043370865
82139
```
140+
Note that the first four parameters of `energy` are not used here but are needed to adhere to the interface. The function
141+
input could be written as `(_, _, _, _, d2, energy)` to make that explicit.
83142

84143
The `system.energy` field accesses the resulting value of the computation:
85144
```julia-repl
86145
julia> system.energy
87-
30679.386366872823
146+
207.37593043370865
88147
```
89-
because the `output_name` field was provided. If it is not provided, you can access the output value from the `system.output` field.
90-
91-
!!! note
92-
- Systems can be 2 or 3-dimensional.
93-
- The `unitcell` parameter may be:
94-
- a vector, in which case the system periodic boundaries are Orthorhombic, this is faster.
95-
- a matrix, in which case the system periodic boundaries are Triclinic (general).
96-
- `nothing` (by default), in which case no periodic boundary conditions will be used.
97-
- `Unitful` quantities can be provided, given appropriate types for all input parameters.
148+
because the `output_name` field was provided. If it is not provided, you can access the output value from the `system.energy` field.
98149

99150
## Computing forces
100151

@@ -115,13 +166,15 @@ Importantly, the function *must* return the `forces` array to follow the API.
115166
Now, let us setup the system with the new type of output variable, which will be now an array of forces with the same type as the positions:
116167

117168
```julia-repl
118-
julia> positions = rand(SVector{3,Float64},1000);
169+
julia> using CellListMap, PDBTools
170+
171+
julia> argon_coordinates = coor(readPDB(CellListMap.argon_pdb_file))
119172
120173
julia> system = ParticleSystem(
121-
xpositions = positions,
122-
unitcell=[1,1,1],
123-
cutoff = 0.1,
124-
output = similar(positions),
174+
xpositions=argon_coordinates,
175+
unitcell=[21.0, 21.0, 21.0],
176+
cutoff = 8.0,
177+
output = similar(argon_coordinates),
125178
output_name = :forces
126179
);
127180
```
@@ -139,11 +192,12 @@ julia> system.forces
139192
A call to `map_pairwise!` with the appropriate function definition will update the forces:
140193
```julia-repl
141194
julia> map_pairwise!((x,y,i,j,d2,forces) -> update_forces!(x,y,i,j,d2,forces), system)
142-
1000-element Vector{SVector{3, Float64}}:
143-
[-151.19529230407284, 159.33819000196905, -261.3055111242796]
144-
[-173.02442398784672, -178.782819965489, 4.570607952876692]
195+
100-element Vector{SVector{3, Float64}}:
196+
[0.026493833307357332, 0.18454277989323772, -0.012253902366284965]
197+
[0.07782602581235695, 0.2791082233740261, 0.21926615329195248]
145198
146-
[-722.5400961501635, 182.65287417718935, 380.0394926753039]
199+
[0.11307234751448932, 0.006353545239676281, -0.05955687310348302]
200+
[-0.03101200918307673, 0.03543655648545697, 0.031849121630976335]
147201
```
148202

149203
## Computing both energy and forces
@@ -164,7 +218,7 @@ must be defined. It can be followed for the computation of other general propert
164218
than for the arrays.
165219

166220
```julia
167-
using CellListMap, StaticArrays
221+
using CellListMap, StaticArrays, PDBTools
168222
```
169223

170224
The computation of energies and forces in a single call is an interesting example for the definition of a custom `output` type and the required interface functions.
@@ -181,14 +235,14 @@ the default corresponding functions, for our new output type:
181235

182236
The copy method creates a new instance of the `EnergyAndForces` type, with copied data:
183237
```julia
184-
import CellListMap: copy_output
185-
copy_output(x::EnergyAndForces) = EnergyAndForces(copy(x.energy), copy(x.forces))
238+
function CellListMap.copy_output(x::EnergyAndForces)
239+
return EnergyAndForces(copy(x.energy), copy(x.forces))
240+
end
186241
```
187242

188243
The reset method will zero both the energy and all forces:
189244
```julia
190-
import CellListMap: reset_output!
191-
function reset_output!(output::EnergyAndForces)
245+
function CellListMap.reset_output!(output::EnergyAndForces)
192246
output.energy = 0.0
193247
for i in eachindex(output.forces)
194248
output.forces[i] = SVector(0.0, 0.0, 0.0)
@@ -197,12 +251,11 @@ function reset_output!(output::EnergyAndForces)
197251
end
198252
```
199253

200-
The reduction function defines what it means to combine two output variables obtained on
254+
The reducer function defines what it means to combine two output variables obtained on
201255
independent threads. In this case, we sum the energies and forces. Different reduction functions
202256
might be necessary for other custom types (for example if computing minimum distances).
203257
```julia
204-
import CellListMap: reducer
205-
function reducer(x::EnergyAndForces, y::EnergyAndForces)
258+
function CellListMap.reducer(x::EnergyAndForces, y::EnergyAndForces)
206259
e_tot = x.energy + y.energy
207260
x.forces .+= y.forces
208261
return EnergyAndForces(e_tot, x.forces)
@@ -231,14 +284,14 @@ end
231284

232285
To finally define the system and compute the properties:
233286

234-
```julia-repl
235-
positions = rand(SVector{3,Float64},1000);
287+
```julia
288+
argon_coordinates = coor(readPDB(CellListMap.argon_pdb_file))
236289

237290
system = ParticleSystem(
238-
xpositions = positions,
239-
unitcell=[1.0,1.0,1.0],
240-
cutoff = 0.1,
241-
output = EnergyAndForces(0.0, similar(positions)),
291+
xpositions = argon_coordinates,
292+
unitcell = [21.0, 21.0, 21.0],
293+
cutoff = 8.0,
294+
output = EnergyAndForces(0.0, similar(argon_coordinates)),
242295
output_name = :energy_and_forces
243296
);
244297

@@ -248,14 +301,15 @@ map_pairwise((x,y,i,j,d2,output) -> energy_and_forces!(x,y,i,j,d2,output), syste
248301
The output can be seen with the aliases of the `system.output` variable:
249302
```julia-repl
250303
julia> system.energy_and_forces.energy
251-
31696.94766439311
304+
207.37593043370862
252305
253306
julia> system.energy_and_forces.forces
254-
1000-element Vector{SVector{3, Float64}}:
255-
[-338.1909601911842, 7.7663690656924445, 202.25889647151405]
256-
[33.67299655756128, 282.7581453168999, -79.09639223837306]
307+
100-element Vector{SVector{3, Float64}}:
308+
[0.02649383330735732, 0.18454277989323772, -0.012253902366284958]
309+
[0.07782602581235692, 0.27910822337402613, 0.21926615329195248]
257310
258-
[38.83014327604529, -204.45236278342745, 249.307871211616]
311+
[0.11307234751448932, 0.006353545239676281, -0.05955687310348303]
312+
[-0.031012009183076745, 0.03543655648545698, 0.03184912163097636]
259313
```
260314

261315
## Updating coordinates, unit cell, and cutoff

0 commit comments

Comments
 (0)