Enable parallel tests.
[hoomd-blue.git] / python-module / hoomd_script / init.py
blob9683957a5cf537f7345b32c23016a9566fda5de7
1 # -- start license --
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
32 # permission.
34 # Disclaimer
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.
48 # -- end license --
50 # Maintainer: joaander / All Developers are free to add commands for new features
52 from optparse import OptionParser;
54 import hoomd;
56 import math;
57 import sys;
58 import gc;
59 import os;
60 import re;
61 import platform;
63 from hoomd_script import util;
64 from hoomd_script import globals;
65 from hoomd_script import data;
67 ## \package hoomd_script.init
68 # \brief Data initialization commands
70 # Commands in the init package initialize the particle system. Initialization via
71 # any of the commands here must be done before any other command in hoomd_script can
72 # be run.
74 # \sa \ref page_quick_start
76 ## Tests if the system has been initialized
78 # Returns True if a previous init.create* or init.read* command has completed successfully and initialized the system.
79 # Returns False otherwise.
80 def is_initialized():
81 if globals.system is None:
82 return False;
83 else:
84 return True;
86 ## Resets all hoomd_script variables
88 # After calling init.reset() all global variables used in hoomd_script are cleared and all allocated
89 # memory is freed so the simulation can begin anew without needing to launch hoomd again.
91 # \note There is a very important memory management issue that must be kept in mind when using
92 # reset(). If you have saved a variable such as an integrator or a force for changing parameters,
93 # that saved object \b must be deleted before the reset() command is called. If all objects are
94 # not deleted, then a memory leak will result causing repeated runs of even a small simulation
95 # to eventually run the system out of memory. reset() will throw an error if it detects that this
96 # is the case.
98 # \note When using the python data access in hoomd scripts, iterators must also be deleted
99 # \code
100 # for p in sysdef.particles:
101 # # do something
103 # del p
104 # init.reste()
105 # \endcode
107 # \b Example:
108 # \code
109 # init.create_random(N=1000, phi_p = 0.2)
110 # lj = pair.lj(r_cut=3.0)
111 # .... setup and run simulation
112 # del lj
113 # init.reset()
114 # init.create_random(N=2000, phi_p = 0.2)
115 # .... setup and run simulation
116 # \endcode
117 def reset():
118 if not is_initialized():
119 globals.msg.warning("Trying to reset an uninitialized system\n");
120 return;
122 # perform some reference counting magic to verify that the user has cleared all saved variables
123 sysdef = globals.system_definition;
124 globals.clear();
126 gc.collect();
127 count = sysdef.getPDataRefs()
129 # note: the check should be against 2, getrefcount counts the temporary reference
130 # passed to it in the argument
131 expected_count = 6
132 if count != expected_count:
133 globals.msg.warning("Not all saved variables were cleared before calling reset()\n");
134 globals.msg.warning(str(count-expected_count) + " references to the particle data still exist somewhere\n");
135 globals.msg.warning("Going to try and reset anyways, further errors (such as out of memory) may result\n");
137 del sysdef
138 gc.collect();
139 gc.collect();
141 ## Create an empty system
143 # \param N Number of particles to create
144 # \param box a data.boxdim object that defines the simulation box
145 # \param particle_types List of particle type names (must not be zero length)
146 # \param bond_types List of bond type names (may be zero length)
147 # \param angle_types List of angle type names (may be zero length)
148 # \param dihedral_types List of Dihedral type names (may be zero length)
149 # \param improper_types List of improper type names (may be zero length)
151 # \b Examples:
152 # \code
153 # system = init.create_empty(N=1000, box=data.boxdim(L=10)
154 # system = init.create_empty(N=64000, box=data.boxdim(L=1, dimensions=2, volume=1000), particle_types=['A', 'B'])
155 # system = init.create_empty(N=64000, box=data.boxdim(L=20), bond_types=['polymer'], dihedral_types=['dihedralA', 'dihedralB'], improper_types=['improperA', 'improperB', 'improperC'])
156 # \endcode
158 # After init.create_empty returns, the requested number of particles will have been created with
159 # <b> <i> DEFAULT VALUES</i> </b> and further initialization \b MUST be performed. See hoomd_script.data
160 # for full details on how such initialization can be performed.
162 # Specifically, all created particles will be:
163 # - At position 0,0,0
164 # - Have velocity 0,0,0
165 # - In box image 0,0,0
166 # - Have orientation 1,0,0,0
167 # - Have the type `particle_types[0]`
168 # - Have charge 0
169 # - Have a mass of 1.0
171 # The particle, bond, angle, dihedral, and improper types will be created and set to the names specified. Use these
172 # type names later in the job script to refer to particles (i.e. in lj.set_params)
174 # \note The resulting empty system must have its particles fully initialized via python code, \b BEFORE
175 # any other hoomd_script commands are executed. For example, if the pair.lj command were to be
176 # run before the initial particle positions were set, \b all particles would have position 0,0,0 and the memory
177 # initialized by the neighbor list would be so large that the memory allocation would fail.
179 # \sa hoomd_script.data
180 def create_empty(N, box, particle_types=['A'], bond_types=[], angle_types=[], dihedral_types=[], improper_types=[]):
181 util.print_status_line();
183 # check if initialization has already occurred
184 if is_initialized():
185 globals.msg.error("Cannot initialize more than once\n");
186 raise RuntimeError('Error initializing');
188 my_exec_conf = _create_exec_conf();
190 # create the empty system
191 if not isinstance(box, data.boxdim):
192 globals.msg.error('box must be a data.boxdim object');
193 raise TypeError('box must be a data.boxdim object');
195 boxdim = box._getBoxDim();
197 my_domain_decomposition = _create_domain_decomposition(boxdim);
198 if my_domain_decomposition is not None:
199 globals.system_definition = hoomd.SystemDefinition(N,
200 boxdim,
201 len(particle_types),
202 len(bond_types),
203 len(angle_types),
204 len(dihedral_types),
205 len(improper_types),
206 my_exec_conf,
207 my_domain_decomposition);
208 else:
209 globals.system_definition = hoomd.SystemDefinition(N,
210 boxdim,
211 len(particle_types),
212 len(bond_types),
213 len(angle_types),
214 len(dihedral_types),
215 len(improper_types),
216 my_exec_conf)
218 globals.system_definition.setNDimensions(box.dimensions);
220 # transfer names to C++
221 for i,name in enumerate(particle_types):
222 globals.system_definition.getParticleData().setTypeName(i,name);
223 for i,name in enumerate(bond_types):
224 globals.system_definition.getBondData().setTypeName(i,name);
225 for i,name in enumerate(angle_types):
226 globals.system_definition.getAngleData().setTypeName(i,name);
227 for i,name in enumerate(dihedral_types):
228 globals.system_definition.getDihedralData().setTypeName(i,name);
229 for i,name in enumerate(improper_types):
230 globals.system_definition.getImproperData().setTypeName(i,name);
232 # initialize the system
233 globals.system = hoomd.System(globals.system_definition, 0);
235 _perform_common_init_tasks();
236 return data.system_data(globals.system_definition);
238 ## Reads initial system state from an XML file
240 # \param filename File to read
241 # \param time_step (if specified) Time step number to use instead of the one stored in the XML file
242 # \param wrap_coordinates Wrap input coordinates back into the box
244 # \b Examples:
245 # \code
246 # init.read_xml(filename="data.xml")
247 # init.read_xml(filename="directory/data.xml")
248 # init.read_xml(filename="restart.xml", time_step=0)
249 # system = init.read_xml(filename="data.xml")
250 # \endcode
252 # All particles, bonds, etc... are read from the XML file given,
253 # setting the initial condition of the simulation.
254 # After this command completes, the system is initialized allowing
255 # other commands in hoomd_script to be run. For more details
256 # on the file format read by this command, see \ref page_xml_file_format.
258 # All values are read in native units, see \ref page_units for more information.
260 # If \a time_step is specified, its value will be used as the initial time
261 # step of the simulation instead of the one read from the XML file.
263 # If \a wrap_coordinates is set to True, input coordinates will be wrapped
264 # into the box specified inside the XML file. If it is set to False, out-of-box
265 # coordinates will result in an error.
267 # The result of init.read_xml can be saved in a variable and later used to read and/or change particle properties
268 # later in the script. See hoomd_script.data for more information.
270 # \sa dump.xml
271 def read_xml(filename, time_step = None, wrap_coordinates = False):
272 util.print_status_line();
274 # initialize GPU/CPU execution configuration and MPI early
275 my_exec_conf = _create_exec_conf();
277 # check if initialization has already occured
278 if is_initialized():
279 globals.msg.error("Cannot initialize more than once\n");
280 raise RuntimeError("Error creating random polymers");
282 # read in the data
283 initializer = hoomd.HOOMDInitializer(my_exec_conf,filename,wrap_coordinates);
284 snapshot = initializer.getSnapshot()
286 my_domain_decomposition = _create_domain_decomposition(snapshot.global_box);
287 if my_domain_decomposition is not None:
288 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf, my_domain_decomposition);
289 else:
290 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf);
292 # initialize the system
293 if time_step is None:
294 globals.system = hoomd.System(globals.system_definition, initializer.getTimeStep());
295 else:
296 globals.system = hoomd.System(globals.system_definition, time_step);
298 _perform_common_init_tasks();
299 return data.system_data(globals.system_definition);
301 ## Reads initial system state from a binary file
303 # \param filename File to read
304 # \param time_step Override time_step value in the bin file
306 # \b Examples:
307 # \code
308 # init.read_bin(filename="data.bin.gz")
309 # init.read_bin(filename="directory/data.bin")
310 # system = init.read_bin(filename="data.bin.gz")
311 # \endcode
313 # All particles, bonds, etc... are read from the binary file given, setting the initial condition of the simulation.
314 # Binary restart files also include state information needed to continue integrating time forward as if the previous job
315 # had never stopped. For more information see dump.bin.
317 # After this command completes, the system is initialized allowing other commands in hoomd_script to be run.
319 # The presence or lack of a .gz extension determines whether init.read_bin will attempt to decompress the %data
320 # before reading it.
322 # The result of init.read_bin can be saved in a variable and later used to read and/or change particle properties
323 # later in the script. See hoomd_script.data for more information.
325 # \warning init.read_bin is deprecated. It currently maintains all of its old functionality, but there are a number
326 # of new features in HOOMD-blue that it does not support.
327 # * Triclinic boxes
329 # \sa dump.bin
330 def read_bin(filename, time_step = None):
331 util.print_status_line();
332 globals.msg.warning("init.read_bin is deprecated and will be removed in the next release");
334 # initialize GPU/CPU execution configuration and MPI early
335 my_exec_conf = _create_exec_conf();
337 # check if initialization has already occurred
338 if is_initialized():
339 globals.msg.error("Cannot initialize more than once\n");
340 raise RuntimeError('Error initializing');
342 # read in the data
343 initializer = hoomd.HOOMDBinaryInitializer(my_exec_conf,filename);
344 snapshot = initializer.getSnapshot()
346 my_domain_decomposition = _create_domain_decomposition(snapshot.global_box);
347 if my_domain_decomposition is not None:
348 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf, my_domain_decomposition);
349 else:
350 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf);
352 # initialize the system
353 if time_step is None:
354 globals.system = hoomd.System(globals.system_definition, initializer.getTimeStep());
355 else:
356 globals.system = hoomd.System(globals.system_definition, time_step);
358 _perform_common_init_tasks();
359 return data.system_data(globals.system_definition);
361 ## Generates N randomly positioned particles of the same type
363 # \param N Number of particles to create
364 # \param phi_p Packing fraction of particles in the simulation box (unitless)
365 # \param name Name of the particle type to create
366 # \param min_dist Minimum distance particles will be separated by (in distance units)
367 # \param box Simulation box dimensions (data.boxdim object)
368 # \param seed Random seed
370 # Either \a phi_p or \a box must be specified. If \a phi_p is provided, it overrides the value of \a box.
372 # \b Examples:
373 # \code
374 # init.create_random(N=2400, phi_p=0.20)
375 # init.create_random(N=2400, phi_p=0.40, min_dist=0.5)
376 # system = init.create_random(N=2400, box=data.boxdim(L=20))
377 # \endcode
379 # \a N particles are randomly placed in the simulation box.
381 # When phi_p is set, the
382 # dimensions of the created box are such that the packing fraction
383 # of particles in the box is \a phi_p. The number density \e n
384 # is related to the packing fraction by \f$n = 6/\pi \cdot \phi_P\f$
385 # assuming the particles have a radius of 0.5.
386 # All particles are created with the same type, given by \a name.
388 # The result of init.create_random can be saved in a variable and later used to read and/or change particle properties
389 # later in the script. See hoomd_script.data for more information.
391 def create_random(N, phi_p=None, name="A", min_dist=0.7, box=None, seed=1):
392 util.print_status_line();
394 # initialize GPU/CPU execution configuration and MPI early
395 my_exec_conf = _create_exec_conf();
397 # check if initialization has already occured
398 if is_initialized():
399 globals.msg.error("Cannot initialize more than once\n");
400 raise RuntimeError("Error initializing");
402 # abuse the polymer generator to generate single particles
404 if phi_p is not None:
405 # calculate the box size
406 L = math.pow(math.pi/6.0*N / phi_p, 1.0/3.0);
407 box = data.boxdim(L=L);
409 if box is None:
410 raise RuntimeError('box or phi_p must be specified');
412 if not isinstance(box, data.boxdim):
413 globals.msg.error('box must be a data.boxdim object');
414 raise TypeError('box must be a data.boxdim object');
416 # create the generator
417 generator = hoomd.RandomGenerator(my_exec_conf, box._getBoxDim(), seed, box.dimensions);
419 # build type list
420 type_vector = hoomd.std_vector_string();
421 type_vector.append(name);
423 # empty bond lists for single particles
424 bond_ab = hoomd.std_vector_uint();
425 bond_type = hoomd.std_vector_string();
427 # create the generator
428 generator.addGenerator(int(N), hoomd.PolymerParticleGenerator(my_exec_conf, 1.0, type_vector, bond_ab, bond_ab, bond_type, 100, box.dimensions));
430 # set the separation radius
431 generator.setSeparationRadius(name, min_dist/2.0);
433 # generate the particles
434 generator.generate();
436 # initialize snapshot
437 snapshot = generator.getSnapshot()
439 my_domain_decomposition = _create_domain_decomposition(snapshot.global_box);
440 if my_domain_decomposition is not None:
441 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf, my_domain_decomposition);
442 else:
443 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf);
445 # initialize the system
446 globals.system = hoomd.System(globals.system_definition, 0);
448 _perform_common_init_tasks();
449 return data.system_data(globals.system_definition);
451 ## Generates any number of randomly positioned polymers of configurable types
453 # \param box Simulation box dimensions (data.boxdim object)
454 # \param polymers Specification for the different polymers to create (see below)
455 # \param separation Separation radii for different particle types (see below)
456 # \param seed Random seed to use
458 # Any number of polymers can be generated, of the same or different types, as
459 # specified in the argument \a polymers. Parameters for each polymer include
460 # bond length, particle type list, bond list, and count.
462 # The syntax is best shown by example. The below line specifies that 600 block copolymers
463 # A6B7A6 with a %bond length of 1.2 be generated.
464 # \code
465 # polymer1 = dict(bond_len=1.2, type=['A']*6 + ['B']*7 + ['A']*6,
466 # bond="linear", count=600)
467 # \endcode
468 # Here is an example for a second polymer, specifying just 100 polymers made of 5 B beads
469 # bonded in a branched pattern
470 # \code
471 # polymer2 = dict(bond_len=1.2, type=['B']*5,
472 # bond=[(0, 1), (1,2), (1,3), (3,4)] , count=100)
473 # \endcode
474 # The \a polymers argument can be given a list of any number of polymer types specified
475 # as above. \a count randomly generated polymers of each type in the list will be
476 # generated in the system.
478 # In detail:
479 # - \a bond_len defines the %bond length of the generated polymers. This should
480 # not necessarily be set to the equilibrium %bond length! The generator is dumb and doesn't know
481 # that bonded particles can be placed closer together than the separation (see below). Thus
482 # \a bond_len must be at a minimum set at twice the value of the largest separation radius. An
483 # error will be generated if this is not the case.
484 # - \a type is a python list of strings. Each string names a particle type in the order that
485 # they will be created in generating the polymer.
486 # - \a %bond can be specified as "linear" in which case the generator connects all particles together
487 # with bonds to form a linear chain. \a %bond can also be given a list if python tuples (see example
488 # above).
489 # - Each tuple in the form of \c (a,b) specifies that particle \c a of the polymer be bonded to
490 # particle \c b. These bonds are given the default type name of 'polymer' to be used when specifying parameters to
491 # bond forces such as bond.harmonic.
492 # - A tuple with three elements (a,b,type) can be used as above, but with a custom name for the bond. For example,
493 # a simple branched polymer with different bond types on each branch could be defined like so:
494 #\code
495 #bond=[(0,1), (1,2), (2,3,'branchA'), (3,4,'branchA), (2,5,'branchB'), (5,6,'branchB')]
496 #\endcode
498 # \a separation \b must contain one entry for each particle type specified in \a polymers
499 # ('A' and 'B' in the examples above). The value given is the separation radius of each
500 # particle of that type. The generated polymer system will have no two overlapping
501 # particles.
503 # \b Examples:
504 # \code
505 # init.create_random_polymers(box=data.boxdim(L=35),
506 # polymers=[polymer1, polymer2],
507 # separation=dict(A=0.35, B=0.35));
509 # init.create_random_polymers(box=data.boxdim(L=31),
510 # polymers=[polymer1],
511 # separation=dict(A=0.35, B=0.35), seed=52);
513 # # create polymers in an orthorhombic box
514 # init.create_random_polymers(box=data.boxdim(Lx=18,Ly=10,Lz=25),
515 # polymers=[polymer2],
516 # separation=dict(A=0.35, B=0.35), seed=12345);
518 # # create a triclinic box with tilt factors xy=0.1 xz=0.2 yz=0.3
519 # init.create_random_polymers(box=data.boxdim(L=18, xy=0.1, xz=0.2, yz=0.3),
520 # polymeres=[polymer2],
521 # separation=dict(A=0.35, B=0.35));
522 # \endcode
524 # With all other parameters the same, create_random_polymers will always create the
525 # same system if \a seed is the same. Set a different \a seed (any integer) to create
526 # a different random system with the same parameters. Note that different versions
527 # of HOOMD \e may generate different systems even with the same seed due to programming
528 # changes.
530 # \note 1. For relatively dense systems (packing fraction 0.4 and higher) the simple random
531 # generation algorithm may fail to find room for all the particles and print an error message.
532 # There are two methods to solve this. First, you can lower the separation radii allowing particles
533 # to be placed closer together. Then setup integrate.nve with the \a limit option set to a
534 # relatively small value. A few thousand time steps should relax the system so that the simulation can be
535 # continued without the limit or with a different integrator. For extremely troublesome systems,
536 # generate it at a very low density and shrink the box with the command update.box_resize
537 # to the desired final size.
539 # \note 2. The polymer generator always generates polymers as if there were linear chains. If you
540 # provide a non-linear %bond topology, the bonds in the initial configuration will be stretched
541 # significantly. This normally doesn't pose a problem for harmonic bonds (bond.harmonic) as
542 # the system will simply relax over a few time steps, but can cause the system to blow up with FENE
543 # bonds (bond.fene).
545 # \note 3. While the custom %bond list allows you to create ring shaped polymers, testing shows that
546 # such conformations have trouble relaxing and get stuck in tangled configurations. If you need
547 # to generate a configuration of rings, you may need to write your own specialized initial configuration
548 # generator that writes HOOMD XML input files (see \ref page_xml_file_format). HOOMD's built-in polymer generator
549 # attempts to be as general as possible, but unfortunately cannot work in every possible case.
551 # The result of init.create_random_polymers can be saved in a variable and later used to read and/or change particle
552 # properties later in the script. See hoomd_script.data for more information.
554 def create_random_polymers(box, polymers, separation, seed=1):
555 util.print_status_line();
557 # initialize GPU/CPU execution configuration and MPI early
558 my_exec_conf = _create_exec_conf();
560 # check if initialization has already occured
561 if is_initialized():
562 globals.msg.error("Cannot initialize more than once\n");
563 raise RuntimeError("Error creating random polymers");
565 if type(polymers) != type([]) or len(polymers) == 0:
566 globals.msg.error("Polymers specified incorrectly. See the hoomd_script documentation\n");
567 raise RuntimeError("Error creating random polymers");
569 if type(separation) != type(dict()) or len(separation) == 0:
570 globals.msg.error("Polymers specified incorrectly. See the hoomd_script documentation\n");
571 raise RuntimeError("Error creating random polymers");
573 if not isinstance(box, data.boxdim):
574 globals.msg.error('Box must be a data.boxdim object\n');
575 raise TypeError('box must be a data.boxdim object');
577 # create the generator
578 generator = hoomd.RandomGenerator(my_exec_conf,box._getBoxDim(), seed, box.dimensions);
580 # make a list of types used for an eventual check vs the types in separation for completeness
581 types_used = [];
583 # track the minimum bond length
584 min_bond_len = None;
586 # build the polymer generators
587 for poly in polymers:
588 type_list = [];
589 # check that all fields are specified
590 if not 'bond_len' in poly:
591 globals.msg.error('Polymer specification missing bond_len\n');
592 raise RuntimeError("Error creating random polymers");
594 if min_bond_len is None:
595 min_bond_len = poly['bond_len'];
596 else:
597 min_bond_len = min(min_bond_len, poly['bond_len']);
599 if not 'type' in poly:
600 globals.msg.error('Polymer specification missing type\n');
601 raise RuntimeError("Error creating random polymers");
602 if not 'count' in poly:
603 globals.msg.error('Polymer specification missing count\n');
604 raise RuntimeError("Error creating random polymers");
605 if not 'bond' in poly:
606 globals.msg.error('Polymer specification missing bond\n');
607 raise RuntimeError("Error creating random polymers");
609 # build type list
610 type_vector = hoomd.std_vector_string();
611 for t in poly['type']:
612 type_vector.append(t);
613 if not t in types_used:
614 types_used.append(t);
616 # build bond list
617 bond_a = hoomd.std_vector_uint();
618 bond_b = hoomd.std_vector_uint();
619 bond_name = hoomd.std_vector_string();
621 # if the bond setting is 'linear' create a default set of bonds
622 if poly['bond'] == 'linear':
623 for i in range(0,len(poly['type'])-1):
624 bond_a.push_back(i);
625 bond_b.push_back(i+1);
626 bond_name.append('polymer')
627 #if it is a list, parse the user custom bonds
628 elif type(poly['bond']) == type([]):
629 for t in poly['bond']:
630 # a 2-tuple gets the default 'polymer' name for the bond
631 if len(t) == 2:
632 a,b = t;
633 name = 'polymer';
634 # and a 3-tuple specifies the name directly
635 elif len(t) == 3:
636 a,b,name = t;
637 else:
638 globals.msg.error('Custom bond ' + str(t) + ' must have either two or three elements\n');
639 raise RuntimeError("Error creating random polymers");
641 bond_a.push_back(a);
642 bond_b.push_back(b);
643 bond_name.append(name);
644 else:
645 globals.msg.error('Unexpected argument value for polymer bond\n');
646 raise RuntimeError("Error creating random polymers");
648 # create the generator
649 generator.addGenerator(int(poly['count']), hoomd.PolymerParticleGenerator(my_exec_conf, poly['bond_len'], type_vector, bond_a, bond_b, bond_name, 100, box.dimensions));
652 # check that all used types are in the separation list
653 for t in types_used:
654 if not t in separation:
655 globals.msg.error("No separation radius specified for type " + str(t) + "\n");
656 raise RuntimeError("Error creating random polymers");
658 # set the separation radii, checking that it is within the minimum bond length
659 for t,r in separation.items():
660 generator.setSeparationRadius(t, r);
661 if 2*r >= min_bond_len:
662 globals.msg.error("Separation radius " + str(r) + " is too big for the minimum bond length of " + str(min_bond_len) + " specified\n");
663 raise RuntimeError("Error creating random polymers");
665 # generate the particles
666 generator.generate();
668 # copy over data to snapshot
669 snapshot = generator.getSnapshot()
671 my_domain_decomposition = _create_domain_decomposition(snapshot.global_box);
672 if my_domain_decomposition is not None:
673 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf, my_domain_decomposition);
674 else:
675 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf);
677 # initialize the system
678 globals.system = hoomd.System(globals.system_definition, 0);
680 _perform_common_init_tasks();
681 return data.system_data(globals.system_definition);
683 ## Initializes the system from a snapshot
685 # \param snapshot The snapshot to initialize the system from
687 # Snapshots temporarily store system %data. Snapshots contain the complete simulation state in a
688 # single object. They can be used to start or restart a simulation.
690 # Example use cases in which a simulation may be started from a snapshot include user code that generates initial
691 # particle positions.
693 # \note Snapshots do not yet have a python API, so they can only be generated by C++ plugins. A future version of
694 # HOOMD-blue will allow fast access to snapshot data in python.
696 # **Example:**
697 # \code
698 # snapshot = my_system_create_routine(.. parameters ..)
699 # system = init.read_snapshot(snapshot)
700 # \endcode
702 # \sa hoomd_script.data
703 def read_snapshot(snapshot):
704 util.print_status_line();
706 # initialize GPU/CPU execution configuration and MPI early
707 my_exec_conf = _create_exec_conf();
709 # check if initialization has already occured
710 if is_initialized():
711 globals.msg.error("Cannot initialize more than once\n");
712 raise RuntimeError("Error creating random polymers");
714 my_domain_decomposition = _create_domain_decomposition(snapshot.global_box);
716 if my_domain_decomposition is not None:
717 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf, my_domain_decomposition);
718 else:
719 globals.system_definition = hoomd.SystemDefinition(snapshot, my_exec_conf);
721 # initialize the system
722 globals.system = hoomd.System(globals.system_definition, 0);
724 _perform_common_init_tasks();
725 return data.system_data(globals.system_definition);
728 ## Performs common initialization tasks
730 # \internal
731 # Initialization tasks that are performed for every simulation are to
732 # be done here. For example, setting up communication, registering the
733 # SFCPackUpdater, initializing the log writer, etc...
734 def _perform_common_init_tasks():
735 from hoomd_script import update;
736 from hoomd_script import group;
737 from hoomd_script import compute;
739 # create the sorter
740 globals.sorter = update.sort();
742 # create the default compute.thermo on the all group
743 util._disable_status_lines = True;
744 all = group.all();
745 compute._get_unique_thermo(group=all);
746 util._disable_status_lines = False;
748 # set up Communicator, and register it with the System
749 if hoomd.is_MPI_available():
750 cpp_decomposition = globals.system_definition.getParticleData().getDomainDecomposition();
751 if cpp_decomposition is not None:
752 # create the c++ Communicator
753 if not globals.exec_conf.isCUDAEnabled():
754 cpp_communicator = hoomd.Communicator(globals.system_definition, cpp_decomposition)
755 else:
756 cpp_communicator = hoomd.CommunicatorGPU(globals.system_definition, cpp_decomposition)
758 # set Communicator in C++ System
759 globals.system.setCommunicator(cpp_communicator)
762 ## Initializes the execution configuration
764 # \internal
765 def _create_exec_conf():
766 # use a cached execution configuration if available
767 if globals.exec_conf is not None:
768 return globals.exec_conf
770 mpi_available = hoomd.is_MPI_available();
772 # error out on nyx/flux if the auto mode is set
773 if globals.options.mode == 'auto':
774 if (re.match("flux*", platform.node()) is not None) or (re.match("nyx*", platform.node()) is not None):
775 globals.msg.error("--mode=gpu or --mode=cpu must be specified on nyx/flux\n");
776 raise RuntimeError("Error initializing");
777 exec_mode = hoomd.ExecutionConfiguration.executionMode.AUTO;
778 elif globals.options.mode == "cpu":
779 exec_mode = hoomd.ExecutionConfiguration.executionMode.CPU;
780 elif globals.options.mode == "gpu":
781 exec_mode = hoomd.ExecutionConfiguration.executionMode.GPU;
782 else:
783 raise RuntimeError("Invalid mode");
785 # convert None options to defaults
786 if globals.options.gpu is None:
787 gpu_id = -1;
788 else:
789 gpu_id = int(globals.options.gpu);
791 if globals.options.nrank is None:
792 nrank = 0;
793 else:
794 nrank = int(globals.options.nrank);
796 # create the specified configuration
797 exec_conf = hoomd.ExecutionConfiguration(exec_mode, gpu_id, globals.options.min_cpu, globals.options.ignore_display, globals.msg, nrank);
799 # if gpu_error_checking is set, enable it on the GPU
800 if globals.options.gpu_error_checking:
801 exec_conf.setCUDAErrorChecking(True);
803 globals.exec_conf = exec_conf;
805 return exec_conf;
807 ## Create a DomainDecomposition object
808 # \internal
809 def _create_domain_decomposition(box):
810 if not hoomd.is_MPI_available():
811 return None
813 # default values for arguents
814 nx = ny = nz = 0
815 linear = False
817 if globals.options.nx is not None:
818 nx = globals.options.nx
819 if globals.options.ny is not None:
820 ny = globals.options.ny
821 if globals.options.nz is not None:
822 nz = globals.options.nz
823 if globals.options.linear is not None:
824 linear = globals.options.linear
826 if linear is True:
827 # set up linear decomposition
828 nz = globals.exec_conf.getNRanks()
830 # if we are only running on one processor, we use optimized code paths
831 # for single-GPU execution
832 if globals.exec_conf.getNRanks() == 1:
833 return None
835 # initialize domain decomposition
836 return hoomd.DomainDecomposition(globals.exec_conf, box.getL(), nx, ny, nz, not globals.options.onelevel);