2 # Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
3 # (HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
4 # the University of Michigan All rights reserved.
6 # HOOMD-blue may contain modifications ("Contributions") provided, and to which
7 # copyright is held, by various Contributors who have granted The Regents of the
8 # University of Michigan the right to modify and/or distribute such Contributions.
10 # You may redistribute, use, and create derivate works of HOOMD-blue, in source
11 # and binary forms, provided you abide by the following conditions:
13 # * Redistributions of source code must retain the above copyright notice, this
14 # list of conditions, and the following disclaimer both in the code and
15 # prominently in any materials provided with the distribution.
17 # * Redistributions in binary form must reproduce the above copyright notice, this
18 # list of conditions, and the following disclaimer in the documentation and/or
19 # other materials provided with the distribution.
21 # * All publications and presentations based on HOOMD-blue, including any reports
22 # or published results obtained, in whole or in part, with HOOMD-blue, will
23 # acknowledge its use according to the terms posted at the time of submission on:
24 # http://codeblue.umich.edu/hoomd-blue/citations.html
26 # * Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
27 # http://codeblue.umich.edu/hoomd-blue/
29 # * Apart from the above required attributions, neither the name of the copyright
30 # holder nor the names of HOOMD-blue's contributors may be used to endorse or
31 # promote products derived from this software without specific prior written
36 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
37 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
39 # WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.
41 # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42 # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
43 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
46 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 # Maintainer: joaander / All Developers are free to add commands for new features
53 from hoomd_script
import globals;
54 from hoomd_script
import compute
;
55 from hoomd_script
import util
;
56 from hoomd_script
import variant
;
58 from hoomd_script
import init
;
60 ## \package hoomd_script.update
61 # \brief Commands that modify the system state in some way
63 # When an updater is specified, it acts on the particle system each time step to change
64 # it in some way. See the documentation of specific updaters to find out what they do.
67 # \brief Base class for updaters
69 # An updater in hoomd_script reflects an Updater in c++. It is responsible
70 # for all high-level management that happens behind the scenes for hoomd_script
71 # writers. 1) The instance of the c++ updater itself is tracked and added to the
72 # System 2) methods are provided for disabling the updater and changing the
73 # period which the system calls it
76 # \brief Constructs the updater
78 # Initializes the cpp_updater to None.
79 # Assigns a name to the updater in updater_name;
81 # check if initialization has occurred
82 if not init
.is_initialized():
83 globals.msg
.error("Cannot create updater before initialization\n");
84 raise RuntimeError('Error creating updater');
86 self
.cpp_updater
= None;
88 # increment the id counter
92 self
.updater_name
= "updater%d" % (id);
97 # \brief Helper function to setup updater period
99 # \param period An integer or callable function period
101 # If an integer is specified, then that is set as the period for the analyzer.
102 # If a callable is passed in as a period, then a default period of 1000 is set
103 # to the integer period and the variable period is enabled
105 def setupUpdater(self
, period
):
106 if type(period
) == type(1.0):
107 period
= int(period
);
109 if type(period
) == type(1):
110 globals.system
.addUpdater(self
.cpp_updater
, self
.updater_name
, period
);
111 elif type(period
) == type(lambda n
: n
*2):
112 globals.system
.addUpdater(self
.cpp_updater
, self
.updater_name
, 1000);
113 globals.system
.setUpdaterPeriodVariable(self
.updater_name
, period
);
115 globals.msg
.error("I don't know what to do with a period of type " + str(type(period
)) + "expecting an int or a function\n");
116 raise RuntimeError('Error creating updater');
120 # \brief True if the updater is enabled
124 # \brief Stores the C++ side Updater managed by this class
128 # \brief The Updater's name as it is assigned to the System
132 # \brief Saved period retrieved when an updater is disabled: used to set the period when re-enabled
135 # \brief Checks that proper initialization has completed
136 def check_initialization(self
):
137 # check that we have been initialized properly
138 if self
.cpp_updater
is None:
139 globals.msg
.error('Bug in hoomd_script: cpp_updater not set, please report\n');
140 raise RuntimeError();
142 ## Disables the updater
149 # Executing the disable command will remove the updater from the system.
150 # Any run() command executed after disabling an updater will not use that
151 # updater during the simulation. A disabled updater can be re-enabled
154 # To use this command, you must have saved the updater in a variable, as
155 # shown in this example:
157 # updater = update.some_updater()
158 # # ... later in the script
162 util
.print_status_line();
163 self
.check_initialization();
165 # check if we are already disabled
167 globals.msg
.warning("Ignoring command to disable an updater that is already disabled");
170 self
.prev_period
= globals.system
.getUpdaterPeriod(self
.updater_name
);
171 globals.system
.removeUpdater(self
.updater_name
);
172 self
.enabled
= False;
174 ## Enables the updater
181 # See disable() for a detailed description.
183 util
.print_status_line();
184 self
.check_initialization();
186 # check if we are already disabled
188 globals.msg
.warning("Ignoring command to enable an updater that is already enabled");
191 globals.system
.addUpdater(self
.cpp_updater
, self
.updater_name
, self
.prev_period
);
194 ## Changes the period between updater executions
196 # \param period New period to set
200 # updater.set_period(100);
201 # updater.set_period(1);
204 # While the simulation is \ref run() "running", the action of each updater
205 # is executed every \a period time steps.
207 # To use this command, you must have saved the updater in a variable, as
208 # shown in this example:
210 # updater = update.some_updater()
211 # # ... later in the script
212 # updater.set_period(10)
214 def set_period(self
, period
):
215 util
.print_status_line();
217 if type(period
) == type(1.0):
218 period
= int(period
);
220 if type(period
) == type(1):
222 globals.system
.setUpdaterPeriod(self
.updater_name
, period
);
224 self
.prev_period
= period
;
225 elif type(period
) == type(lambda n
: n
*2):
226 globals.msg
.warning("A period cannot be changed to a variable one");
228 globals.msg
.warning("I don't know what to do with a period of type " + str(type(period
)) + " expecting an int or a function");
230 # **************************************************************************
232 ## Sorts particles in memory to improve cache coherency
234 # Every \a period time steps, particles are reordered in memory based on
235 # a Hilbert curve. This operation is very efficient, and the reordered particles
236 # significantly improve performance of all other algorithmic steps in HOOMD.
238 # The reordering is accomplished by placing particles in spatial bins. A Hilbert curve is generated that traverses
239 # these bins and particles are reordered in memory in the same order in which
240 # they fall on the curve. The grid dimension used over the course of the simulation is held constant, and the default
241 # is chosen to be as fine as possible without utilizing too much memory. The dimension can be changed with set_params(),
242 # just be aware that the value chosen will be rounded up to the next power of 2 and that the amount of memory usage for
243 # 3D simulations grows very quickly:
244 # - \a grid=128 uses 8 MB
245 # - \a grid=256 uses 64 MB
246 # - \a grid=512 uses 512 MB
247 # - \a grid=1024 uses 4096 MB
249 # 2D simulations do not use any additional memory and default to \a grid=4096
251 # Because all simulations benefit from this process, a sorter is created by
252 # default. If you have reason to disable it or modify parameters, you
253 # can use the built-in variable \c sorter to do so after initialization. The
254 # following code example disables the sorter. The init.create_random command
255 # is just an example; sorter can be modified after any command that initializes
258 # init.create_random(N=1000, phi_p=0.2)
261 class sort(_updater
):
262 ## Initialize the sorter
264 # Users should not initialize the sorter directly. One in created for you
265 # when any initialization command from init is run.
266 # The created sorter can be accessed via the built-in variable \c sorter.
268 # By default, the sorter is created with a \a grid of 256 (4096 in 2D) and
269 # an update period of 300 time steps (100 if running on the CPU).
270 # The period can be changed with set_period() and the grid width can be
271 # changed with set_params()
273 # initialize base class
274 _updater
.__init
__(self
);
276 # create the c++ mirror class
277 if not globals.exec_conf
.isCUDAEnabled():
278 self
.cpp_updater
= hoomd
.SFCPackUpdater(globals.system_definition
);
280 self
.cpp_updater
= hoomd
.SFCPackUpdaterGPU(globals.system_definition
);
282 default_period
= 300;
283 # change default period to 100 on the CPU
284 if not globals.exec_conf
.isCUDAEnabled():
285 default_period
= 100;
287 self
.setupUpdater(default_period
);
289 ## Change sorter parameters
291 # \param grid New grid dimension (if set)
295 # sorter.set_params(grid=128)
297 def set_params(self
, grid
=None):
298 util
.print_status_line();
299 self
.check_initialization();
302 self
.cpp_updater
.setGrid(grid
);
305 ## Rescales particle velocities
307 # Every \a period time steps, particle velocities are rescaled by equal factors
308 # so that they are consistent with a given temperature in the equipartition theorem
309 # \f$\langle 1/2 m v^2 \rangle = k_B T \f$.
311 # update.rescale_temp is best coupled with the \ref integrate.nve "NVE" integrator.
313 class rescale_temp(_updater
):
314 ## Initialize the rescaler
316 # \param T Temperature set point (in energy units)
317 # \param period Velocities will be rescaled every \a period time steps
319 # \a T can be a variant type, allowing for temperature ramps in simulation runs.
323 # update.rescale_temp(T=1.2)
324 # rescaler = update.rescale_temp(T=0.5)
325 # update.rescale_temp(period=100, T=1.03)
326 # update.rescale_temp(period=100, T=variant.linear_interp([(0, 4.0), (1e6, 1.0)]))
329 # \a period can be a function: see \ref variable_period_docs for details
330 def __init__(self
, T
, period
=1):
331 util
.print_status_line();
333 # initialize base class
334 _updater
.__init
__(self
);
336 # setup the variant inputs
337 T
= variant
._setup
_variant
_input
(T
);
339 # create the compute thermo
340 thermo
= compute
._get
_unique
_thermo
(group
=globals.group_all
);
342 # create the c++ mirror class
343 self
.cpp_updater
= hoomd
.TempRescaleUpdater(globals.system_definition
, thermo
.cpp_compute
, T
.cpp_variant
);
344 self
.setupUpdater(period
);
346 ## Change rescale_temp parameters
348 # \param T New temperature set point (in energy units)
350 # To change the parameters of an existing updater, you must have saved it when it was specified.
352 # rescaler = update.rescale_temp(T=0.5)
357 # rescaler.set_params(T=2.0)
359 def set_params(self
, T
=None):
360 util
.print_status_line();
361 self
.check_initialization();
364 T
= variant
._setup
_variant
_input
(T
);
365 self
.cpp_updater
.setT(T
.cpp_variant
);
367 ## Zeroes system momentum
369 # Every \a period time steps, particle velocities are modified such that the total linear
370 # momentum of the system is set to zero.
372 # update.zero_momentum is intended to be used when the \ref integrate.nve "NVE" integrator has the
373 # \a limit option specified, where Newton's third law is broken and systems could gain momentum.
374 # Of course, it can be used in any script.
377 class zero_momentum(_updater
):
378 ## Initialize the momentum zeroer
380 # \param period Momentum will be zeroed every \a period time steps
384 # update.zero_momentum()
385 # zeroer= update.zero_momentum(period=10)
388 # \a period can be a function: see \ref variable_period_docs for details
389 def __init__(self
, period
=1):
390 util
.print_status_line();
392 # initialize base class
393 _updater
.__init
__(self
);
395 # create the c++ mirror class
396 self
.cpp_updater
= hoomd
.ZeroMomentumUpdater(globals.system_definition
);
397 self
.setupUpdater(period
);
399 ## Enforces 2D simulation
401 # Every time step, particle velocities and accelerations are modified so that their z components are 0: forcing
402 # 2D simulations when other calculations may cause particles to drift out of the plane.
404 # Using enforce2d is only allowed when the system is specified as having only 2 dimensions. This specification can
405 # be made in the xml file read by init.read_xml() or set dynamically via the particle data access routines. Setting
406 # the number of dimensions to 2 also changes the degrees of freedom calculation for temperature calculations and forces
407 # the neighbor list to only find 2D neighbors. Doing so requires that a small, but non-zero, value be set for the z
408 # dimension of the simulation box.
411 class enforce2d(_updater
):
412 ## Initialize the 2D enforcement
420 util
.print_status_line();
423 # initialize base class
424 _updater
.__init
__(self
);
426 # create the c++ mirror class
427 if not globals.exec_conf
.isCUDAEnabled():
428 self
.cpp_updater
= hoomd
.Enforce2DUpdater(globals.system_definition
);
430 self
.cpp_updater
= hoomd
.Enforce2DUpdaterGPU(globals.system_definition
);
431 self
.setupUpdater(period
);
433 ## Rescales the system box size
435 # Every \a period time steps, the system box dimensions is updated to values given by
436 # the user (in a variant). As an option, the particles can either be left in place
437 # as the box is changed or their positions can be scaled with the box.
440 class box_resize(_updater
):
441 ## Initialize box size resize updater
443 # \param L (if set) box length in the x,y, and z directions as a function of time (in distance units)
444 # \param Lx (if set) box length in the x direction as a function of time (in distance units)
445 # \param Ly (if set) box length in the y direction as a function of time (in distance units)
446 # \param Lz (if set) box length in the z direction as a function of time (in distance units)
447 # \param xy (if set) X-Y tilt factor as a function of time (dimensionless)
448 # \param xz (if set) X-Z tilt factor as a function of time (dimensionless)
449 # \param yz (if set) Y-Z tilt factor as a function of time (dimensionless)
450 # \param period The box size will be updated every \a period time steps
452 # \a L, Lx, \a Ly, \a Lz, \a xy, \a xz, \a yz can either be set to a constant number or a variant may be provided.
453 # if any of the box parameters are not specified, they are set to maintain the same value in the current box.
455 # Use \a L as a shorthand to specify Lx, Ly, and Lz to the same value.
457 # By default, particle positions are rescaled with the box. To change this behavior,
460 # If, under rescaling, tilt factors get too large, the simulation may slow down due to too many ghost atoms
461 # being communicated. update.box.resize does NOT reset the box to orthorhombic shape if this occurs (and does not
462 # move the next periodic image into the primary cell).
466 # update.box_resize(L = variant.linear_interp([(0, 20), (1e6, 50)]))
467 # box_resize = update.box_resize(L = variant.linear_interp([(0, 20), (1e6, 50)]), period = 10)
468 # update.box_resize(Lx = variant.linear_interp([(0, 20), (1e6, 50)]),
469 # Ly = variant.linear_interp([(0, 20), (1e6, 60)]),
470 # Lz = variant.linear_interp([(0, 10), (1e6, 80)]))
471 # update.box_resize(Lx = variant.linear_interp([(0, 20), (1e6, 50)]), Ly = 10, Lz = 10)
473 # # Shear the box in the xy plane using Lees-Edwards boundary conditions
474 # update.box_resize(xy = variant.linear_interp([(0,0), (1e6, 1)]))
477 # \a period can be a function: see \ref variable_period_docs for details
479 # If \a period is set to None, then the given box lengths are applied immediately and periodic updates
482 def __init__(self
, Lx
= None, Ly
= None, Lz
= None, xy
= None, xz
= None, yz
= None, period
= 1, L
= None):
483 util
.print_status_line();
485 # initialize base class
486 _updater
.__init
__(self
);
493 if Lx
is None and Ly
is None and Lz
is None and xy
is None and xz
is None and yz
is None:
494 globals.msg
.warning("update.box_resize: Ignoring request to setup updater without parameters\n")
498 box
= globals.system_definition
.getParticleData().getGlobalBox();
508 xy
= box
.getTiltFactorXY();
510 xz
= box
.getTiltFactorXZ();
512 yz
= box
.getTiltFactorYZ();
514 Lx
= variant
._setup
_variant
_input
(Lx
);
515 Ly
= variant
._setup
_variant
_input
(Ly
);
516 Lz
= variant
._setup
_variant
_input
(Lz
);
518 xy
= variant
._setup
_variant
_input
(xy
);
519 xz
= variant
._setup
_variant
_input
(xz
);
520 yz
= variant
._setup
_variant
_input
(yz
);
522 # create the c++ mirror class
523 self
.cpp_updater
= hoomd
.BoxResizeUpdater(globals.system_definition
, Lx
.cpp_variant
, Ly
.cpp_variant
, Lz
.cpp_variant
,
524 xy
.cpp_variant
, xz
.cpp_variant
, yz
.cpp_variant
);
526 self
.cpp_updater
.update(globals.system
.getCurrentTimeStep());
528 self
.setupUpdater(period
);
530 ## Change box_resize parameters
532 # \param scale_particles Set to True to scale particles with the box. Set to False
533 # to have particles remain in place when the box is scaled.
535 # To change the parameters of an existing updater, you must have saved it when it was specified.
537 # box_resize = update.box_resize(Lx = variant.linear_interp([(0, 20), (1e6, 50)]), period = 10)
542 # box_resize.set_params(scale_particles = False)
543 # box_resize.set_params(scale_particles = True)
545 def set_params(self
, scale_particles
=None):
546 util
.print_status_line();
547 self
.check_initialization();
549 if scale_particles
is not None:
550 self
.cpp_updater
.setParams(scale_particles
);
552 # Global current id counter to assign updaters unique names