@@ -15,9 +15,9 @@ Initialize the simulation
15
15
:align: right
16
16
:class: only-light
17
17
18
- Here, the *InitializeSimulation * class is created . This class is used to
19
- prepare the simulation box and populate the box randomly with atoms.
20
- Let us improve the previously created *InitializeSimulation * class:
18
+ Here, the *InitializeSimulation * class is completed . This class is used to
19
+ prepare the simulation box and populate it randomly with atoms. Improve the
20
+ previously created *InitializeSimulation * class as follows :
21
21
22
22
.. label :: start_InitializeSimulation_class
23
23
@@ -43,30 +43,20 @@ Let us improve the previously created *InitializeSimulation* class:
43
43
44
44
Several parameters are provided to the *InitializeSimulation * class:
45
45
46
- - The first parameter is the box dimensions, which is a list with a length
47
- corresponding to the dimension of the system. Each element of the list
48
- corresponds to a dimension of the box in Ångström in the x, y, and z
49
- directions, respectively.
50
- - Optionally, a seed can be provided as an integer. If the seed is given
51
- by the user, the random number generator will always produce the same
52
- displacements.
46
+ - The box dimensions, which is a list with 3 elements. Each element of
47
+ the list corresponds to a dimension of the box in Ångström in the :math: `x`,
48
+ :math: `y`, and :math: `z`` directions, respectively.
49
+ - The cutoff :math: `r_\text {c}` for the potential interaction.
53
50
- Optionally, initial positions for the atoms can be provided as an array
54
51
of length corresponding to the number of atoms. If *initial_positions *
55
- is left equal to *None *, positions will be randomly assigned to the
56
- atoms (see below).
57
- - A cut off value with a default of 10 Ångströms is defined.
58
- - The *neighbor * parameter determines the interval between recalculations of
59
- the neighbor lists. By default, a value of 1 is used, meaning that neighbor
60
- list will be reconstructed every steps. In certain cases, the number will be
61
- increased to recude the computation time.
62
-
63
- ..
64
- - Optionally, a thermo period and a dumping_period can be provided to # TOFIX to be added later
65
- control the outputs from the simulation (it will be implemented # TOFIX to be added later
66
- in :ref:`chapter5-label`). # TOFIX to be added later
67
-
68
- Finally, the *dimensions * of the system are calculated as the length of
69
- *box_dimensions *.
52
+ is set to *None *, positions will be randomly assigned to the atoms (see
53
+ below).
54
+ - The *neighbor * parameter determines the interval between recalculations
55
+ of the neighbor lists. By default, a value of 1 is used, meaning that the
56
+ neighbor list will be reconstructed every step. In certain cases, this
57
+ number may be increased to reduce computation time.
58
+
59
+ Note that the simulation step is initialized to 0.
70
60
71
61
Nondimensionalize units
72
62
-----------------------
@@ -89,8 +79,8 @@ parameters, here the *box_dimensions*, the *cut_off*, as well as the *initial_po
89
79
Define the box
90
80
--------------
91
81
92
- Let us define the simulation box using the values from *box_dimensions *. Add the following
93
- method to the *InitializeSimulation * class:
82
+ Let us define the simulation box using the values from *box_dimensions *. Add the
83
+ following method to the *InitializeSimulation * class:
94
84
95
85
.. label :: start_InitializeSimulation_class
96
86
@@ -99,10 +89,8 @@ method to the *InitializeSimulation* class:
99
89
def define_box (self ):
100
90
""" Define the simulation box. Only 3D boxes are supported."""
101
91
box_boundaries = np.zeros((3 , 2 ))
102
- dim = 0
103
- for L in self .box_dimensions:
92
+ for dim, L in enumerate (self .box_dimensions):
104
93
box_boundaries[dim] = - L/ 2 , L/ 2
105
- dim += 1
106
94
self .box_boundaries = box_boundaries
107
95
box_size = np.diff(self .box_boundaries).reshape(3 )
108
96
box_geometry = np.array([90 , 90 , 90 ])
@@ -113,12 +101,16 @@ method to the *InitializeSimulation* class:
113
101
The *box_boundaries * are calculated from the *box_dimensions *. They
114
102
represent the lowest and highest coordinates in all directions. By symmetry,
115
103
the box is centered at 0 along all axes. A *box_size * is also defined,
116
- following the MDAnalysis conventions: Lx, Ly, Lz, 90, 90, 90, where the
117
- last three numbers are angles in degrees. Values different from *90 * for
118
- the angles would define a triclinic (non-orthogonal) box, which is not
119
- currently supported by the existing code.
104
+ following the MDAnalysis |mdanalysis_box |: Lx, Ly, Lz, 90, 90, 90, where
105
+ the last three numbers are angles in degrees :cite: `michaud2011mdanalysis `.
106
+ Values different from *90 * for the angles would define a triclinic (non-orthogonal)
107
+ box, which is not currently supported by the existing code.
108
+
109
+ .. |mdanalysis_box | raw :: html
110
+
111
+ <a href="https://docs.mdanalysis.org/stable/documentation_pages/transformations/boxdimensions.html" target="_blank">conventions</a>
120
112
121
- Let us call the *define_box * method from the *__init__ * class :
113
+ Let us call *define_box() * from the *__init__() * method :
122
114
123
115
.. label :: start_InitializeSimulation_class
124
116
@@ -132,40 +124,41 @@ Let us call the *define_box* method from the *__init__* class:
132
124
133
125
.. label :: end_InitializeSimulation_class
134
126
135
- Populate the box
127
+ Populate the Box
136
128
----------------
137
129
138
130
Here, the atoms are placed within the simulation box. If initial
139
131
positions were not provided (i.e., *initial_positions = None *), atoms
140
- are placed randomly within the box. If *initial_positions * was provided
141
- as an array, the provided positions are used instead. Note that, in this
132
+ are placed randomly within the box. If *initial_positions * is provided
133
+ as an array, the provided positions are used instead. Note that in this
142
134
case, the array must be of size 'number of atoms' times 'number of dimensions'.
143
135
144
136
.. label :: start_InitializeSimulation_class
145
137
146
138
.. code-block :: python
147
139
148
140
def populate_box (self ):
141
+ Nat = np.sum(self .number_atoms) # total number of atoms
149
142
if self .initial_positions is None :
150
- atoms_positions = np.zeros((np.sum( self .number_atoms) , 3 ))
143
+ atoms_positions = np.zeros((Nat , 3 ))
151
144
for dim in np.arange(3 ):
152
145
diff_box = np.diff(self .box_boundaries[dim])
153
- random_pos = np.random.random(np.sum( self .number_atoms) )
146
+ random_pos = np.random.random(Nat )
154
147
atoms_positions[:, dim] = random_pos* diff_box- diff_box/ 2
155
148
self .atoms_positions = atoms_positions
156
149
else :
157
150
self .atoms_positions = self .initial_positions
158
151
159
152
.. label :: end_InitializeSimulation_class
160
153
161
- In case *initial_positions is None *, and array is first created. Then, random
162
- positions that are constrained within the box boundaries are defined using the
163
- random function of NumPy. Note that, here, the newly added atoms are added
164
- randomly within the box, without taking care of avoiding overlaps with
165
- existing atoms. Overlaps will be dealt with using energy minimization,
166
- see :ref: `chapter4-label `.
154
+ In case *initial_positions * is None, an array is first created. Then,
155
+ random positions constrained within the box boundaries are defined using
156
+ the random function from NumPy. Note that newly added atoms are placed
157
+ randomly within the box, without considering overlaps with existing
158
+ atoms. Overlaps will be addressed using energy minimization (see
159
+ the :ref: `chapter4-label ` chapter) .
167
160
168
- Let us call the *populate_box * method from the *__init__ * class :
161
+ Let us call *populate_box * from the *__init__ * method :
169
162
170
163
.. label :: start_InitializeSimulation_class
171
164
@@ -178,7 +171,7 @@ Let us call the *populate_box* method from the *__init__* class:
178
171
179
172
.. label :: end_InitializeSimulation_class
180
173
181
- Build neighbor lists
174
+ Build Neighbor Lists
182
175
--------------------
183
176
184
177
In molecular simulations, it is common practice to identify neighboring atoms
@@ -210,12 +203,16 @@ atom, ensuring that only relevant interactions are considered in the
210
203
calculations. These lists will be recalculated at intervals specified by
211
204
the *neighbor * input parameter.
212
205
213
- Update cross coefficients
206
+ For efficiency, the *contact_matrix * function from MDAnalysis is
207
+ used :cite: `michaud2011mdanalysis `. The *contact_matrix * function returns
208
+ information about atoms located at a distance less than the cutoff from one another.
209
+
210
+ Update Cross Coefficients
214
211
-------------------------
215
212
216
- At the same time as the neighbor lists are getting build up , let us also
217
- pre-calculate the cross coefficients. This will make the force calculation
218
- more practical (see below).
213
+ As the neighbor lists are being built , let us also pre-calculate the cross
214
+ coefficients. This will make the force calculation more efficient (see
215
+ below).
219
216
220
217
.. label :: start_Utilities_class
221
218
@@ -250,7 +247,7 @@ Here, the values of the cross coefficients between atom of type 1 and 2,
250
247
\sigma _{12 } = (\sigma _{11 }+\sigma _{22 })/2 \\
251
248
\epsilon _{12 } = (\epsilon _{11 }+\epsilon _{22 })/2
252
249
253
- Finally, import the following library in the *Utilities.py * file:
250
+ Finally, import the following libraries in the *Utilities.py * file:
254
251
255
252
.. label :: start_Utilities_class
256
253
@@ -261,8 +258,8 @@ Finally, import the following library in the *Utilities.py* file:
261
258
262
259
.. label :: end_Utilities_class
263
260
264
- Let us call the *update_neighbor_lists * and *update_cross_coefficients *
265
- methods from the *__init__ * class :
261
+ Let us call *update_neighbor_lists * and *update_cross_coefficients *
262
+ from the *__init__ * method :
266
263
267
264
.. label :: start_InitializeSimulation_class
268
265
@@ -276,12 +273,11 @@ methods from the *__init__* class:
276
273
277
274
.. label :: end_InitializeSimulation_class
278
275
279
- Test the code
276
+ Test the Code
280
277
-------------
281
278
282
- Let us test the *InitializeSimulation * class to make sure that it does what
283
- is expected, i.e. that it does create atoms that are located within the box
284
- boundaries along all 3 dimensions of space:
279
+ Let us test the *InitializeSimulation * class to ensure that it behaves as
280
+ expected, i.e., that it creates atoms located within the box boundaries:
285
281
286
282
.. label :: start_test_3a_class
287
283
@@ -333,3 +329,6 @@ boundaries along all 3 dimensions of space:
333
329
pytest.main([" -s" , __file__ ])
334
330
335
331
.. label :: end_test_3a_class
332
+
333
+ The value of the cutoff, chosen as :math: `2.5 \sigma _{11 }`, is relatively
334
+ common for Lennard-Jones fluids and will often be the default choice for us.
0 commit comments