Fix potential problem in Messenger related to MPI window
[hoomd-blue.git] / libhoomd / data_structures / ParticleData.h
blob48efc6c16b9195e1dd033f9573375f47b8c32f65
1 /*
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.
50 // Maintainer: joaander
52 /*! \file ParticleData.h
53 \brief Defines the ParticleData class and associated utilities
56 #ifdef NVCC
57 #error This header cannot be compiled by nvcc
58 #endif
60 #ifdef WIN32
61 #pragma warning( push )
62 #pragma warning( disable : 4103 )
63 #endif
65 #ifndef __PARTICLE_DATA_H__
66 #define __PARTICLE_DATA_H__
68 #include "HOOMDMath.h"
69 #include "GPUArray.h"
70 #include "GPUVector.h"
72 #ifdef ENABLE_CUDA
73 #include "ParticleData.cuh"
74 #endif
76 #include "ExecutionConfiguration.h"
77 #include "BoxDim.h"
79 #include <boost/shared_ptr.hpp>
80 #include <boost/signals2.hpp>
81 #include <boost/function.hpp>
82 #include <boost/utility.hpp>
83 #include <boost/dynamic_bitset.hpp>
85 #ifdef ENABLE_MPI
86 #include "Index1D.h"
87 #endif
89 #include "DomainDecomposition.h"
91 #include <stdlib.h>
92 #include <vector>
93 #include <string>
94 #include <bitset>
96 using namespace std;
98 // windows doesn't understand __restrict__, it is __restrict instead
99 #ifdef WIN32
100 #define __restrict__ __restrict
101 #endif
103 /*! \ingroup hoomd_lib
107 /*! \defgroup data_structs Data structures
108 \brief All classes that are related to the fundamental data
109 structures for storing particles.
111 \details See \ref page_dev_info for more information
114 /*! @}
117 // Forward declaration of Profiler
118 class Profiler;
120 class WallData;
122 // Forward declaration of RigidData
123 class RigidData;
125 // Forward declaration of IntegratorData
126 class IntegratorData;
128 //! List of optional fields that can be enabled in ParticleData
129 struct pdata_flag
131 //! The enum
132 enum Enum
134 isotropic_virial=0, //!< Bit id in PDataFlags for the isotropic virial
135 potential_energy, //!< Bit id in PDataFlags for the potential energy
136 pressure_tensor, //!< Bit id in PDataFlags for the full virial
140 //! flags determines which optional fields in in the particle data arrays are to be computed / are valid
141 typedef std::bitset<32> PDataFlags;
143 //! Defines a simple structure to deal with complex numbers
144 /*! This structure is useful to deal with complex numbers for such situations
145 as Fourier transforms. Note that we do not need any to define any operations and the
146 default constructor is good enough
148 struct CScalar
150 Scalar r; //!< Real part
151 Scalar i; //!< Imaginary part
154 //! Defines a simple moment of inertia structure
155 /*! This moment of interia is stored per particle. Because there are no per-particle body update steps in the
156 design of hoomd, these values are never read or used except at initialization. Thus, a simple descriptive
157 structure is used instead of an advanced and complicated GPUArray strided data array.
159 The member variable components stores the 6 components of an upper-trianglar moment of inertia tensor.
160 The components are, in order, Ixx, Ixy, Ixz, Iyy, Iyz, Izz.
162 They are initialized to 0 and left that way if not specified in an initialization file.
164 struct InertiaTensor
166 InertiaTensor()
168 for (unsigned int i = 0; i < 6; i++)
169 components[i] = Scalar(0.0);
172 //! Set the components of the tensor
173 void set(Scalar c0, Scalar c1, Scalar c2, Scalar c3, Scalar c4, Scalar c5)
175 components[0] = c0;
176 components[1] = c1;
177 components[2] = c2;
178 components[3] = c3;
179 components[4] = c4;
180 components[5] = c5;
183 Scalar components[6]; //!< Stores the components of the inertia tensor
186 //! Sentinel value in \a body to signify that this particle does not belong to a rigid body
187 const unsigned int NO_BODY = 0xffffffff;
189 //! Sentinel value in \a r_tag to signify that this particle is not currently present on the local processor
190 const unsigned int NOT_LOCAL = 0xffffffff;
192 //! Handy structure for passing around per-particle data
193 /*! A snapshot is used for two purposes:
194 * - Initializing the ParticleData
195 * - inside an Analyzer to iterate over the current ParticleData
197 * Initializing the ParticleData is accomplished by first filling the particle data arrays with default values
198 * (such as type, mass, diameter). Then a snapshot of this initial state is taken and pased to the
199 * ParticleDataInitializer, which may modify any of the fields of the snapshot. It then returns it to
200 * ParticleData, which in turn initializes its internal arrays from the snapshot using ParticleData::initializeFromSnapshot().
202 * To support the second scenerio it is necessary that particles can be accessed in global tag order. Therefore,
203 * the data in a snapshot is stored in global tag order.
204 * \ingroup data_structs
206 struct SnapshotParticleData {
207 //! Empty snapshot
208 SnapshotParticleData()
209 : size(0)
213 //! constructor
214 /*! \param N number of particles to allocate memory for
216 SnapshotParticleData(unsigned int N);
218 //! Resize the snapshot
219 /*! \param N number of particles in snapshot
221 void resize(unsigned int N);
223 //! Validate the snapshot
224 /*! \returns true if the number of elements is consistent
226 bool validate() const;
228 //! Replicate this snapshot
229 /*! \param nx Number of times to replicate the system along the x direction
230 * \param ny Number of times to replicate the system along the y direction
231 * \param nz Number of times to replicate the system along the z direction
232 * \param old_box Old box dimensions
233 * \param new_box Dimensions of replicated box
235 void replicate(unsigned int nx, unsigned int ny, unsigned int nz,
236 const BoxDim& old_box, const BoxDim& new_box);
238 std::vector<Scalar3> pos; //!< positions
239 std::vector<Scalar3> vel; //!< velocities
240 std::vector<Scalar3> accel; //!< accelerations
241 std::vector<unsigned int> type; //!< types
242 std::vector<Scalar> mass; //!< masses
243 std::vector<Scalar> charge; //!< charges
244 std::vector<Scalar> diameter; //!< diameters
245 std::vector<int3> image; //!< images
246 std::vector<unsigned int> body; //!< body ids
247 std::vector<Scalar4> orientation; //!< orientations
248 std::vector<InertiaTensor> inertia_tensor; //!< Moments of inertia
250 unsigned int size; //!< number of particles in this snapshot
251 std::vector<std::string> type_mapping; //!< Mapping between particle type ids and names
254 //! Structure to store packed particle data
255 /* pdata_element is used for compact storage of particle data, mainly for communication.
257 struct pdata_element
259 Scalar4 pos; //!< Position
260 Scalar4 vel; //!< Velocity
261 Scalar3 accel; //!< Acceleration
262 Scalar charge; //!< Charge
263 Scalar diameter; //!< Diameter
264 int3 image; //!< Image
265 unsigned int body; //!< Body id
266 Scalar4 orientation; //!< Orientation
267 unsigned int tag; //!< global tag
270 //! Manages all of the data arrays for the particles
271 /*! <h1> General </h1>
272 ParticleData stores and manages particle coordinates, velocities, accelerations, type,
273 and tag information. This data must be available both via the CPU and GPU memories.
274 All copying of data back and forth from the GPU is accomplished transparently by GPUArray.
276 For performance reasons, data is stored as simple arrays. Once a handle to the particle data
277 GPUArrays has been acquired, the coordinates of the particle with
278 <em>index</em> \c i can be accessed with <code>pos_array_handle.data[i].x</code>,
279 <code>pos_array_handle.data[i].y</code>, and <code>pos_array_handle.data[i].z</code>
280 where \c i runs from 0 to <code>getN()</code>.
282 Velocities and other properties can be accessed in a similar manner.
284 \note Position and type are combined into a single Scalar4 quantity. x,y,z specifies the position and w specifies
285 the type. Use __scalar_as_int() / __int_as_scalar() (or __int_as_float() / __float_as_int()) to extract / set
286 this integer that is masquerading as a scalar.
288 \note Velocity and mass are combined into a single Scalar4 quantity. x,y,z specifies the velocity and w specifies
289 the mass.
291 \warning Local particles can and will be rearranged in the arrays throughout a simulation.
292 So, a particle that was once at index 5 may be at index 123 the next time the data
293 is acquired. Individual particles can be tracked through all these changes by their (global) tag.
294 The tag of a particle is stored in the \c m_tag array, and the ith element contains the tag of the particle
295 with index i. Conversely, the the index of a particle with tag \c tag can be read from
296 the element at position \c tag in the a \c m_rtag array.
298 In a parallel simulation, the global tag is unique among all processors.
300 In order to help other classes deal with particles changing indices, any class that
301 changes the order must call notifyParticleSort(). Any class interested in being notified
302 can subscribe to the signal by calling connectParticleSort().
304 Some fields in ParticleData are not computed and assigned by default because they require additional processing
305 time. PDataFlags is a bitset that lists which flags (enumerated in pdata_flag) are enable/disabled. Computes should
306 call getFlags() and compute the requested quantities whenever the corresponding flag is set. Updaters and Analyzers
307 can request flags be computed via their getRequestedPDataFlags() methods. A particular updater or analyzer should
308 return a bitset PDataFlags with only the bits set for the flags that it needs. During a run, System will query
309 the updaters and analyzers that are to be executed on the current step. All of the flag requests are combined
310 with the binary or operation into a single set of flag requests. System::run() then sets the flags by calling
311 setPDataFlags so that the computes produce the requested values during that step.
313 These fields are:
314 - pdata_flag::isotropic_virial - specify that the net_virial should be/is computed (getNetVirial)
315 - pdata_flag::potential_energy - specify that the potential energy .w component stored in the net force array
316 (getNetForce) is valid
317 - pdata_flag::pressure_tensor - specify that the full virial tensor is valid
319 If these flags are not set, these arrays can still be read but their values may be incorrect.
321 If any computation is unable to supply the appropriate values (i.e. rigid body virial can not be computed
322 until the second step of the simulation), then it should remove the flag to signify that the values are not valid.
323 Any analyzer/updater that expects the value to be set should check the flags that are actually set.
325 \note Particles are not checked if their position is actually inside the local box. In fact, when using spatial domain decomposition,
326 particles may temporarily move outside the boundaries.
328 \ingroup data_structs
330 ## Parallel simulations
332 In a parallel simulation, the ParticleData contains he local particles only, and getN() returns the current number of
333 \a local particles. The method getNGlobal() can be used to query the \a global number of particles on all processors.
335 During the simulation particles may enter or leave the box, therefore the number of \a local particles may change.
336 To account for this, the size of the particle data arrays is dynamically updated using amortized doubling of the array sizes. To add particles to
337 the domain, the addParticles() method is called, and the arrays are resized if necessary. Particles are retrieved
338 and removed from the local particle data arrays using removeParticles(). To flag particles for removal, set the
339 communication flag (m_comm_flags) for that particle to a non-zero value.
341 In addition, since many other classes maintain internal arrays holding data for every particle (such as neighbor lists etc.), these
342 arrays need to be resized, too, if the particle number changes. Everytime the particle data arrays are reallocated, a
343 maximum particle number change signal is triggered. Other classes can subscribe to this signal using connectMaxParticleNumberChange().
344 They may use the current maxium size of the particle arrays, which is returned by getMaxN(). This size changes only infrequently
345 (by amortized array resizing). Note that getMaxN() can return a higher number
346 than the actual number of particles.
348 Particle data also stores temporary particles ('ghost atoms'). These are added after the local particle data (i.e. with indices
349 starting at getN()). It keeps track of those particles using the addGhostParticles() and removeAllGhostParticles() methods.
350 The caller is responsible for updating the particle data arrays with the ghost particle information.
352 ## Anisotropic particles
354 Anisotropic particles are handled by storing an orientation quaternion for every particle in the simulation.
355 Similarly, a net torque is computed and stored for each particle. The design decision made is to not
356 duplicate efforts already made to enable composite bodies of anisotropic particles. So the particle orientation
357 is a read only quantity when used by most of HOOMD. To integrate this degree of freedom forward, the particle
358 must be part of a composite body (stored and handled by RigidData) (there can be single-particle bodies,
359 of course) where integration methods like NVERigid will handle updating the degrees of freedom of the composite
360 body and then set the constrained position, velocity, and orientation of the constituent particles.
362 To enable correct initialization of the composite body moment of inertia, each particle is also assigned
363 an individual moment of inertia which is summed up correctly to determine the composite body's total moment of
364 inertia. As such, the initial particle moment of inertias are only ever used during initialization and do not
365 need to be stored in an efficient GPU data structure. Nor does the inertia tensor data need to be resorted,
366 so it will always remain in tag order.
368 Access the orientation quaternion of each particle with the GPUArray gotten from getOrientationArray(), the net
369 torque with getTorqueArray(). Individual inertia tensor values can be accessed with getInertiaTensor() and
370 setInertiaTensor()
372 ## Origin shifting
374 Parallel MC simulations randomly translate all particles by a fixed vector at periodic intervals. This motion
375 is not physical, it is merely the easiest way to shift the origin of the cell list / domain decomposition
376 boundaries. Analysis routines (i.e. MSD) and movies are complicated by the random motion of all particles.
378 ParticleData can track this origin and subtract it from all particles. This subtraction is done when taking a
379 snapshot. Putting the subtraction there naturally puts the correction there for all analysis routines and file I/O
380 while leaving the shifted particles in place for computes, updaters, and integrators. On the restoration from
381 a snapshot, the origin needs to be cleared.
383 Two routines support this: translateOrigin() and resetOrigin(). The position of the origin is tracked by
384 ParticleData internally. translateOrigin() moves it by a given vector. resetOrigin() zeroes it. TODO: This might
385 not be sufficient for simulations where the box size changes. We'll see in testing.
387 class ParticleData : boost::noncopyable
389 public:
390 //! Construct with N particles in the given box
391 ParticleData(unsigned int N,
392 const BoxDim &global_box,
393 unsigned int n_types,
394 boost::shared_ptr<ExecutionConfiguration> exec_conf,
395 boost::shared_ptr<DomainDecomposition> decomposition
396 = boost::shared_ptr<DomainDecomposition>()
399 //! Construct using a ParticleDataSnapshot
400 ParticleData(const SnapshotParticleData& snapshot,
401 const BoxDim& global_box,
402 boost::shared_ptr<ExecutionConfiguration> exec_conf,
403 boost::shared_ptr<DomainDecomposition> decomposition
404 = boost::shared_ptr<DomainDecomposition>()
407 //! Destructor
408 virtual ~ParticleData();
410 //! Get the simulation box
411 const BoxDim& getBox() const;
413 //! Set the global simulation box
414 void setGlobalBox(const BoxDim &box);
416 //! Set the global simulation box Lengths
417 void setGlobalBoxL(const Scalar3 &L)
419 BoxDim box(L);
420 setGlobalBox(box);
423 //! Get the global simulation box
424 const BoxDim& getGlobalBox() const;
426 //! Access the execution configuration
427 boost::shared_ptr<const ExecutionConfiguration> getExecConf() const
429 return m_exec_conf;
432 //! Get the number of particles
433 /*! \return Number of particles in the box
435 inline unsigned int getN() const
437 return m_nparticles;
440 //! Get the currrent maximum number of particles
441 /*\ return Maximum number of particles that can be stored in the particle array
442 * this number has to be larger than getN() + getNGhosts()
444 inline unsigned int getMaxN() const
446 return m_max_nparticles;
449 //! Get current number of ghost particles
450 /*\ return Number of ghost particles
452 inline unsigned int getNGhosts() const
454 return m_nghosts;
457 //! Get the global number of particles in the simulation
458 /*!\ return Global number of particles
460 inline unsigned int getNGlobal() const
462 return m_nglobal;
465 //! Set global number of particles
466 /*! \param nglobal Global number of particles
468 void setNGlobal(unsigned int nglobal);
470 //! Get the number of particle types
471 /*! \return Number of particle types
472 \note Particle types are indexed from 0 to NTypes-1
474 unsigned int getNTypes() const
476 return m_type_mapping.size();
479 //! Get the origin for the particle system
480 /*! \return origin of the system
482 Scalar3 getOrigin()
484 return m_origin;
487 //! Get the origin image for the particle system
488 /*! \return image of the origin of the system
490 int3 getOriginImage()
492 return m_o_image;
495 //! Get the maximum diameter of the particle set
496 /*! \return Maximum Diameter Value
498 Scalar getMaxDiameter() const
500 Scalar maxdiam = 0;
501 ArrayHandle< Scalar > h_diameter(getDiameters(), access_location::host, access_mode::read);
502 for (unsigned int i = 0; i < m_nparticles; i++) if (h_diameter.data[i] > maxdiam) maxdiam = h_diameter.data[i];
503 return maxdiam;
506 //! Return positions and types
507 const GPUArray< Scalar4 >& getPositions() const { return m_pos; }
509 //! Return velocities and masses
510 const GPUArray< Scalar4 >& getVelocities() const { return m_vel; }
512 //! Return accelerations
513 const GPUArray< Scalar3 >& getAccelerations() const { return m_accel; }
515 //! Return charges
516 const GPUArray< Scalar >& getCharges() const { return m_charge; }
518 //! Return diameters
519 const GPUArray< Scalar >& getDiameters() const { return m_diameter; }
521 //! Return images
522 const GPUArray< int3 >& getImages() const { return m_image; }
524 //! Return tags
525 const GPUArray< unsigned int >& getTags() const { return m_tag; }
527 //! Return reverse-lookup tags
528 const GPUArray< unsigned int >& getRTags() const { return m_rtag; }
530 //! Return body ids
531 const GPUArray< unsigned int >& getBodies() const { return m_body; }
534 * Access methods to stand-by arrays for fast swapping in of reordered particle data
536 * \warning An array that is swapped in has to be completely initialized.
537 * In parallel simulations, the ghost data needs to be initalized as well,
538 * or all ghosts need to be removed and re-initialized before and after reordering.
540 * USAGE EXAMPLE:
541 * \code
542 * m_comm->migrateParticles(); // migrate particles and remove all ghosts
544 * ArrayHandle<Scalar4> h_pos_alt(m_pdata->getAltPositions(), access_location::host, access_mode::overwrite)
545 * ArrayHandle<Scalar4> h_pos(m_pdata->getPositions(), access_location::host, access_mode::read);
546 * for (int i=0; i < getN(); ++i)
547 * h_pos_alt.data[i] = h_pos.data[permutation[i]]; // apply some permutation
549 * m_pdata->swapPositions(); // swap in reordered data at no extra cost
550 * notifyParticleSort(); // ensures that ghosts will be restored at next communication step
551 * \endcode
554 //! Return positions and types (alternate array)
555 const GPUArray< Scalar4 >& getAltPositions() const { return m_pos_alt; }
557 //! Swap in positions
558 inline void swapPositions() { m_pos.swap(m_pos_alt); }
560 //! Return velocities and masses (alternate array)
561 const GPUArray< Scalar4 >& getAltVelocities() const { return m_vel_alt; }
563 //! Swap in velocities
564 inline void swapVelocities() { m_vel.swap(m_vel_alt); }
566 //! Return accelerations (alternate array)
567 const GPUArray< Scalar3 >& getAltAccelerations() const { return m_accel_alt; }
569 //! Swap in accelerations
570 inline void swapAccelerations() { m_accel.swap(m_accel_alt); }
572 //! Return charges (alternate array)
573 const GPUArray< Scalar >& getAltCharges() const { return m_charge_alt; }
575 //! Swap in accelerations
576 inline void swapCharges() { m_charge.swap(m_charge_alt); }
578 //! Return diameters (alternate array)
579 const GPUArray< Scalar >& getAltDiameters() const { return m_diameter_alt; }
581 //! Swap in diameters
582 inline void swapDiameters() { m_diameter.swap(m_diameter_alt); }
584 //! Return images (alternate array)
585 const GPUArray< int3 >& getAltImages() const { return m_image_alt; }
587 //! Swap in images
588 inline void swapImages() { m_image.swap(m_image_alt); }
590 //! Return tags (alternate array)
591 const GPUArray< unsigned int >& getAltTags() const { return m_tag_alt; }
593 //! Swap in tags
594 inline void swapTags() { m_tag.swap(m_tag_alt); }
596 //! Return body ids (alternate array)
597 const GPUArray< unsigned int >& getAltBodies() const { return m_body_alt; }
599 //! Swap in bodies
600 inline void swapBodies() { m_body.swap(m_body_alt); }
602 //! Get the net force array (alternate array)
603 const GPUArray< Scalar4 >& getAltNetForce() const { return m_net_force_alt; }
605 //! Swap in net force
606 inline void swapNetForce() { m_net_force.swap(m_net_force_alt); }
608 //! Get the net virial array (alternate array)
609 const GPUArray< Scalar >& getAltNetVirial() const { return m_net_virial_alt; }
611 //! Swap in net virial
612 inline void swapNetVirial() { m_net_virial.swap(m_net_virial_alt); }
614 //! Get the net torque array (alternate array)
615 const GPUArray< Scalar4 >& getAltNetTorqueArray() const { return m_net_torque_alt; }
617 //! Swap in net torque
618 inline void swapNetTorque() { m_net_torque.swap(m_net_torque_alt); }
620 //! Get the orientations (alternate array)
621 const GPUArray< Scalar4 >& getAltOrientationArray() const { return m_orientation_alt; }
623 //! Swap in orientations
624 inline void swapOrientations() { m_orientation.swap(m_orientation_alt); }
626 //! Set the profiler to profile CPU<-->GPU memory copies
627 /*! \param prof Pointer to the profiler to use. Set to NULL to deactivate profiling
629 void setProfiler(boost::shared_ptr<Profiler> prof)
631 m_prof=prof;
634 //! Connects a function to be called every time the particles are rearranged in memory
635 boost::signals2::connection connectParticleSort(const boost::function<void ()> &func);
637 //! Notify listeners that the particles have been rearranged in memory
638 void notifyParticleSort();
640 //! Connects a function to be called every time the box size is changed
641 boost::signals2::connection connectBoxChange(const boost::function<void ()> &func);
643 //! Connects a function to be called every time the maximum particle number changes
644 boost::signals2::connection connectMaxParticleNumberChange(const boost::function< void()> &func);
646 //! Connects a function to be called every time the ghost particles are updated
647 boost::signals2::connection connectGhostParticleNumberChange(const boost::function< void()> &func);
649 #ifdef ENABLE_MPI
650 //! Connects a function to be called every time a single particle migration is requested
651 boost::signals2::connection connectSingleParticleMove(
652 const boost::function<void (unsigned int, unsigned int, unsigned int)> &func);
653 #endif
655 //! Notify listeners that the number of ghost particles has changed
656 void notifyGhostParticleNumberChange();
658 //! Gets the particle type index given a name
659 unsigned int getTypeByName(const std::string &name) const;
661 //! Gets the name of a given particle type index
662 std::string getNameByType(unsigned int type) const;
664 //! Rename a type
665 void setTypeName(unsigned int type, const std::string& name);
667 //! Get the net force array
668 const GPUArray< Scalar4 >& getNetForce() const { return m_net_force; }
670 //! Get the net virial array
671 const GPUArray< Scalar >& getNetVirial() const { return m_net_virial; }
673 //! Get the net torque array
674 const GPUArray< Scalar4 >& getNetTorqueArray() const { return m_net_torque; }
676 //! Get the orientation array
677 const GPUArray< Scalar4 >& getOrientationArray() const { return m_orientation; }
679 #ifdef ENABLE_MPI
680 //! Get the communication flags array
681 const GPUArray< unsigned int >& getCommFlags() const { return m_comm_flags; }
682 #endif
684 #ifdef ENABLE_MPI
685 //! Find the processor that owns a particle
686 unsigned int getOwnerRank(unsigned int tag) const;
687 #endif
689 //! Get the current position of a particle
690 Scalar3 getPosition(unsigned int tag) const;
692 //! Get the current velocity of a particle
693 Scalar3 getVelocity(unsigned int tag) const;
695 //! Get the current acceleration of a particle
696 Scalar3 getAcceleration(unsigned int tag) const;
698 //! Get the current image flags of a particle
699 int3 getImage(unsigned int tag) const;
701 //! Get the current mass of a particle
702 Scalar getMass(unsigned int tag) const;
704 //! Get the current diameter of a particle
705 Scalar getDiameter(unsigned int tag) const;
707 //! Get the current charge of a particle
708 Scalar getCharge(unsigned int tag) const;
710 //! Get the body id of a particle
711 unsigned int getBody(unsigned int tag) const;
713 //! Get the current type of a particle
714 unsigned int getType(unsigned int tag) const;
716 //! Get the current index of a particle with a given global tag
717 inline unsigned int getRTag(unsigned int tag) const
719 assert(tag < m_nglobal);
720 ArrayHandle< unsigned int> h_rtag(m_rtag,access_location::host, access_mode::read);
721 unsigned int idx = h_rtag.data[tag];
722 #ifdef ENABLE_MPI
723 assert(m_decomposition || idx < getN());
724 #endif
725 assert(idx < getN() + getNGhosts() || idx == NOT_LOCAL);
726 return idx;
729 //! Return true if particle is local (= owned by this processor)
730 bool isParticleLocal(unsigned int tag) const
732 assert(tag < m_nglobal);
733 ArrayHandle< unsigned int> h_rtag(m_rtag,access_location::host, access_mode::read);
734 return h_rtag.data[tag] < getN();
737 //! Get the orientation of a particle with a given tag
738 Scalar4 getOrientation(unsigned int tag) const;
740 //! Get the inertia tensor of a particle with a given tag
741 const InertiaTensor& getInertiaTensor(unsigned int tag) const
743 return m_inertia_tensor[tag];
746 //! Get the net force / energy on a given particle
747 Scalar4 getPNetForce(unsigned int tag) const;
749 //! Get the net torque on a given particle
750 Scalar4 getNetTorque(unsigned int tag) const;
752 //! Set the current position of a particle
753 /*! \param move If true, particle is automatically placed into correct domain
755 void setPosition(unsigned int tag, const Scalar3& pos, bool move=true);
757 //! Set the current velocity of a particle
758 void setVelocity(unsigned int tag, const Scalar3& vel);
760 //! Set the current image flags of a particle
761 void setImage(unsigned int tag, const int3& image);
763 //! Set the current charge of a particle
764 void setCharge(unsigned int tag, Scalar charge);
766 //! Set the current mass of a particle
767 void setMass(unsigned int tag, Scalar mass);
769 //! Set the current diameter of a particle
770 void setDiameter(unsigned int tag, Scalar diameter);
772 //! Set the body id of a particle
773 void setBody(unsigned int tag, int body);
775 //! Set the current type of a particle
776 void setType(unsigned int tag, unsigned int typ);
778 //! Set the orientation of a particle with a given tag
779 void setOrientation(unsigned int tag, const Scalar4& orientation);
781 //! Get the inertia tensor of a particle with a given tag
782 void setInertiaTensor(unsigned int tag, const InertiaTensor& tensor)
784 m_inertia_tensor[tag] = tensor;
787 //! Get the particle data flags
788 PDataFlags getFlags() { return m_flags; }
790 //! Set the particle data flags
791 /*! \note Setting the flags does not make the requested quantities immediately available. Only after the next
792 set of compute() calls will the requested values be computed. The System class talks to the various
793 analyzers and updaters to determine the value of the flags for any given time step.
795 void setFlags(const PDataFlags& flags) { m_flags = flags; }
797 //! Set the external contribution to the virial
798 void setExternalVirial(unsigned int i, Scalar v)
800 assert(i<6);
801 m_external_virial[i] = v;
804 //! Get the external contribution to the virial
805 Scalar getExternalVirial(unsigned int i)
807 assert(i<6);
808 return m_external_virial[i];
811 //! Remove the given flag
812 void removeFlag(pdata_flag::Enum flag) { m_flags[flag] = false; }
814 //! Initialize from a snapshot
815 void initializeFromSnapshot(const SnapshotParticleData & snapshot);
817 //! Take a snapshot
818 void takeSnapshot(SnapshotParticleData &snapshot);
820 //! Add ghost particles at the end of the local particle data
821 void addGhostParticles(const unsigned int nghosts);
823 //! Remove all ghost particles from system
824 void removeAllGhostParticles()
826 m_nghosts = 0;
829 #ifdef ENABLE_MPI
830 //! Set domain decomposition information
831 void setDomainDecomposition(boost::shared_ptr<DomainDecomposition> decomposition)
833 assert(decomposition);
834 m_decomposition = decomposition;
835 m_box = m_decomposition->calculateLocalBox(m_global_box);
836 m_boxchange_signal();
839 //! Returns the domain decomin decomposition information
840 boost::shared_ptr<DomainDecomposition> getDomainDecomposition()
842 return m_decomposition;
845 //! Pack particle data into a buffer
846 /*! \param out Buffer into which particle data is packed
847 * \param comm_flags Buffer into which communication flags is packed
849 * Packs all particles for which comm_flag>0 into a buffer
850 * and remove them from the particle data
852 * The output buffers are automatically resized to accomodate the data.
854 * \post The particle data arrays remain compact. Any ghost atoms
855 * are invalidated. (call removeAllGhostAtoms() before or after
856 * this method).
858 void removeParticles(std::vector<pdata_element>& out, std::vector<unsigned int>& comm_flags);
860 //! Remove particles from local domain and add new particle data
861 /*! \param in List of particle data elements to fill the particle data with
863 void addParticles(const std::vector<pdata_element>& in);
865 #ifdef ENABLE_CUDA
866 //! Pack particle data into a buffer (GPU version)
867 /*! \param out Buffer into which particle data is packed
868 * \param comm_flags Buffer into which communication flags is packed
870 * Pack all particles for which comm_flag >0 into a buffer
871 * and remove them from the particle data
873 * The output buffers are automatically resized to accomodate the data.
875 * \post The particle data arrays remain compact. Any ghost atoms
876 * are invalidated. (call removeAllGhostAtoms() before or after
877 * this method).
879 void removeParticlesGPU(GPUVector<pdata_element>& out, GPUVector<unsigned int>& comm_flags);
881 //! Remove particles from local domain and add new particle data (GPU version)
882 /*! \param in List of particle data elements to fill the particle data with
884 void addParticlesGPU(const GPUVector<pdata_element>& in);
885 #endif // ENABLE_CUDA
887 #endif // ENABLE_MPI
889 //! Translate the box origin
890 /*! \param a vector to apply in the translation
892 void translateOrigin(const Scalar3& a)
894 m_origin += a;
895 // wrap the origin back into the box to prevent it from getting too large
896 m_global_box.wrap(m_origin, m_o_image);
899 //! Rest the box origin
900 /*! \post The origin is 0,0,0
902 void resetOrigin()
904 m_origin = make_scalar3(0,0,0);
905 m_o_image = make_int3(0,0,0);
908 private:
909 BoxDim m_box; //!< The simulation box
910 BoxDim m_global_box; //!< Global simulation box
911 boost::shared_ptr<ExecutionConfiguration> m_exec_conf; //!< The execution configuration
912 #ifdef ENABLE_MPI
913 boost::shared_ptr<DomainDecomposition> m_decomposition; //!< Domain decomposition data
914 #endif
916 std::vector<std::string> m_type_mapping; //!< Mapping between particle type indices and names
918 boost::signals2::signal<void ()> m_sort_signal; //!< Signal that is triggered when particles are sorted in memory
919 boost::signals2::signal<void ()> m_boxchange_signal; //!< Signal that is triggered when the box size changes
920 boost::signals2::signal<void ()> m_max_particle_num_signal; //!< Signal that is triggered when the maximum particle number changes
921 boost::signals2::signal<void ()> m_ghost_particle_num_signal; //!< Signal that is triggered when ghost particles are added to or deleted
922 boost::signals2::signal<void ()> m_global_particle_num_signal; //!< Signal that is triggered when the global number of particles changes
924 #ifdef ENABLE_MPI
925 boost::signals2::signal<void (unsigned int, unsigned int, unsigned int)> m_ptl_move_signal; //!< Signal when particle moves between domains
926 #endif
928 unsigned int m_nparticles; //!< number of particles
929 unsigned int m_nghosts; //!< number of ghost particles
930 unsigned int m_max_nparticles; //!< maximum number of particles
931 unsigned int m_nglobal; //!< global number of particles
933 // per-particle data
934 GPUArray<Scalar4> m_pos; //!< particle positions and types
935 GPUArray<Scalar4> m_vel; //!< particle velocities and masses
936 GPUArray<Scalar3> m_accel; //!< particle accelerations
937 GPUArray<Scalar> m_charge; //!< particle charges
938 GPUArray<Scalar> m_diameter; //!< particle diameters
939 GPUArray<int3> m_image; //!< particle images
940 GPUArray<unsigned int> m_tag; //!< particle tags
941 GPUArray<unsigned int> m_rtag; //!< reverse lookup tags
942 GPUArray<unsigned int> m_body; //!< rigid body ids
943 GPUArray< Scalar4 > m_orientation; //!< Orientation quaternion for each particle (ignored if not anisotropic)
944 #ifdef ENABLE_MPI
945 GPUArray<unsigned int> m_comm_flags; //!< Array of communication flags
946 #endif
949 /* Alternate particle data arrays are provided for fast swapping in and out of particle data
950 The size of these arrays is updated in sync with the main particle data arrays.
952 The primary use case is when particle data has to be re-ordered in-place, i.e.
953 a temporary array would otherwise be required. Instead of writing to a temporary
954 array and copying to the main particle data subsequently, the re-ordered particle
955 data can be written to the alternate arrays, which are then swapped in for
956 the real particle data at effectively zero cost.
958 GPUArray<Scalar4> m_pos_alt; //!< particle positions and type (swap-in)
959 GPUArray<Scalar4> m_vel_alt; //!< particle velocities and masses (swap-in)
960 GPUArray<Scalar3> m_accel_alt; //!< particle accelerations (swap-in)
961 GPUArray<Scalar> m_charge_alt; //!< particle charges (swap-in)
962 GPUArray<Scalar> m_diameter_alt; //!< particle diameters (swap-in)
963 GPUArray<int3> m_image_alt; //!< particle images (swap-in)
964 GPUArray<unsigned int> m_tag_alt; //!< particle tags (swap-in)
965 GPUArray<unsigned int> m_body_alt; //!< rigid body ids (swap-in)
966 GPUArray<Scalar4> m_orientation_alt; //!< orientations (swap-in)
967 GPUArray<Scalar4> m_net_force_alt; //!< Net force (swap-in)
968 GPUArray<Scalar> m_net_virial_alt; //!< Net virial (swap-in)
969 GPUArray<Scalar4> m_net_torque_alt; //!< Net torque (swap-in)
971 boost::shared_ptr<Profiler> m_prof; //!< Pointer to the profiler. NULL if there is no profiler.
973 GPUArray< Scalar4 > m_net_force; //!< Net force calculated for each particle
974 GPUArray< Scalar > m_net_virial; //!< Net virial calculated for each particle (2D GPU array of dimensions 6*number of particles)
975 GPUArray< Scalar4 > m_net_torque; //!< Net torque calculated for each particle
976 std::vector< InertiaTensor > m_inertia_tensor; //!< Inertia tensor for each particle
978 Scalar m_external_virial[6]; //!< External potential contribution to the virial
979 const float m_resize_factor; //!< The numerical factor with which the particle data arrays are resized
980 PDataFlags m_flags; //!< Flags identifying which optional fields are valid
982 Scalar3 m_origin; //!< Tracks the position of the origin of the coordinate system
983 int3 m_o_image; //!< Tracks the origin image
985 #ifdef ENABLE_CUDA
986 mgpu::ContextPtr m_mgpu_context; //!< moderngpu context
987 #endif
989 //! Helper function to allocate particle data
990 void allocate(unsigned int N);
992 //! Helper function to allocate alternate particle data
993 void allocateAlternateArrays(unsigned int N);
995 //! Helper function for amortized array resizing
996 void resize(unsigned int new_nparticles);
998 //! Helper function to reallocate particle data
999 void reallocate(unsigned int max_n);
1001 //! Helper function to check that particles of a snapshot are in the box
1002 /*! \return true If and only if all particles are in the simulation box
1003 * \param Snapshot to check
1005 bool inBox(const SnapshotParticleData& snap);
1009 //! Exports the BoxDim class to python
1010 void export_BoxDim();
1011 //! Exports ParticleData to python
1012 void export_ParticleData();
1013 //! Export SnapshotParticleData to python
1014 void export_SnapshotParticleData();
1016 #endif
1018 #ifdef WIN32
1019 #pragma warning( pop )
1020 #endif