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: ndtrung
52 /*! \file RigidData.cc
53 \brief Defines RigidData and related classes.
57 #pragma warning( push )
58 #pragma warning( disable : 4103 4244 )
63 #include <boost/python.hpp>
65 using namespace boost::python
;
67 #include "RigidData.h"
68 #include "QuaternionMath.h"
70 using namespace boost
;
73 // Maximum number of iterations for Jacobi rotations
75 // Maximum value macro
76 #define MAX(A,B) ((A) > (B)) ? (A) : (B)
78 /*! \param particle_data ParticleData this use in initializing this RigidData
80 \pre \a particle_data has been completeley initialized with all arrays filled out
81 \post All data members in RigidData are completely initialized from the given info in \a particle_data
83 RigidData::RigidData(boost::shared_ptr
<ParticleData
> particle_data
)
84 : m_pdata(particle_data
), m_n_bodies(0), m_ndof(0)
86 // leave arrays initialized to NULL. There are currently 0 bodies and their
87 // initialization is delayed because we cannot reasonably determine when that initialization
90 // connect the sort signal
91 m_sort_connection
= m_pdata
->connectParticleSort(bind(&RigidData::recalcIndices
, this));
93 // save the execution configuration
94 m_exec_conf
= m_pdata
->getExecConf();
97 RigidData::~RigidData()
99 m_sort_connection
.disconnect();
103 /*! \pre m_body_size has been filled with values
104 \pre m_particle_tags has been filled with values
105 \pre m_particle_indices has been allocated
106 \post m_particle_indices is updated to match the current sorting of the particle data
108 void RigidData::recalcIndices()
115 assert(!m_particle_tags
.isNull());
116 assert(!m_particle_indices
.isNull());
117 // assert(m_n_bodies <= m_particle_tags.getPitch());
118 // assert(m_n_bodies <= m_particle_indices.getPitch());
119 // printf("m_n_bodies = %d; particle tags pitch = %d\n", m_n_bodies, m_particle_tags.getPitch());
121 assert(m_n_bodies
== m_body_size
.getNumElements());
123 // get the particle data
124 ArrayHandle
< unsigned int > h_rtag(m_pdata
->getRTags(), access_location::host
, access_mode::read
);
126 // get all the rigid data we need
127 ArrayHandle
<unsigned int> tags(m_particle_tags
, access_location::host
, access_mode::read
);
128 unsigned int tags_pitch
= m_particle_tags
.getPitch();
130 ArrayHandle
<unsigned int> indices(m_particle_indices
, access_location::host
, access_mode::readwrite
);
131 unsigned int indices_pitch
= m_particle_indices
.getPitch();
132 ArrayHandle
<unsigned int> rigid_particle_indices(m_rigid_particle_indices
, access_location::host
, access_mode::readwrite
);
135 ArrayHandle
<unsigned int> body_size(m_body_size
, access_location::host
, access_mode::read
);
136 ArrayHandle
<unsigned int> h_particle_offset(m_particle_offset
, access_location::host
, access_mode::readwrite
);
139 unsigned int ridx
= 0;
140 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
142 // for each particle in this body
143 unsigned int len
= body_size
.data
[body
];
144 assert(body
<= m_particle_tags
.getHeight() && body
<= m_particle_indices
.getHeight());
145 assert(len
<= tags_pitch
&& len
<= indices_pitch
);
147 for (unsigned int i
= 0; i
< len
; i
++)
149 // translate the tag to the current index
150 unsigned int tag
= tags
.data
[body
*tags_pitch
+ i
];
151 unsigned int pidx
= h_rtag
.data
[tag
];
152 indices
.data
[body
*indices_pitch
+ i
] = pidx
;
153 h_particle_offset
.data
[pidx
] = i
;
155 rigid_particle_indices
.data
[ridx
++] = pidx
;
160 //Sort them so they are ordered
161 sort(rigid_particle_indices
.data
, rigid_particle_indices
.data
+ ridx
);
165 //! Internal single use matrix multiply
166 inline static void mat_multiply(Scalar a
[3][3], Scalar b
[3][3], Scalar c
[3][3])
168 c
[0][0] = a
[0][0] * b
[0][0] + a
[0][1] * b
[1][0] + a
[0][2] * b
[2][0];
169 c
[0][1] = a
[0][0] * b
[0][1] + a
[0][1] * b
[1][1] + a
[0][2] * b
[2][1];
170 c
[0][2] = a
[0][0] * b
[0][2] + a
[0][1] * b
[1][2] + a
[0][2] * b
[2][2];
172 c
[1][0] = a
[1][0] * b
[0][0] + a
[1][1] * b
[1][0] + a
[1][2] * b
[2][0];
173 c
[1][1] = a
[1][0] * b
[0][1] + a
[1][1] * b
[1][1] + a
[1][2] * b
[2][1];
174 c
[1][2] = a
[1][0] * b
[0][2] + a
[1][1] * b
[1][2] + a
[1][2] * b
[2][2];
176 c
[2][0] = a
[2][0] * b
[0][0] + a
[2][1] * b
[1][0] + a
[2][2] * b
[2][0];
177 c
[2][1] = a
[2][0] * b
[0][1] + a
[2][1] * b
[1][1] + a
[2][2] * b
[2][1];
178 c
[2][2] = a
[2][0] * b
[0][2] + a
[2][1] * b
[1][2] + a
[2][2] * b
[2][2];
181 /*! \pre all data members have been allocated
182 \post all data members are initialized with data from the particle data
184 void RigidData::initializeData()
187 // get the particle data
188 ArrayHandle
< unsigned int > h_body(m_pdata
->getBodies(), access_location::host
, access_mode::read
);
190 ArrayHandle
<Scalar4
> h_p_orientation(m_pdata
->getOrientationArray(), access_location::host
, access_mode::read
);
191 BoxDim box
= m_pdata
->getBox();
193 // determine the number of rigid bodies
194 unsigned int maxbody
= 0;
195 unsigned int minbody
= NO_BODY
;
196 bool found_body
= false;
197 unsigned int nparticles
= m_pdata
->getN();
198 for (unsigned int j
= 0; j
< nparticles
; j
++)
200 if (h_body
.data
[j
] != NO_BODY
)
203 if (maxbody
< h_body
.data
[j
])
204 maxbody
= h_body
.data
[j
];
205 if (minbody
> h_body
.data
[j
])
206 minbody
= h_body
.data
[j
];
212 m_n_bodies
= maxbody
+ 1; // h_body.data[j] is numbered from 0
215 m_exec_conf
->msg
->error() << "rigid data: Body indices do not start at 0\n";
216 throw runtime_error("Error initializing rigid data");
227 // allocate nbodies-size arrays
228 GPUArray
<unsigned int> body_dof(m_n_bodies
, m_pdata
->getExecConf());
229 GPUArray
<Scalar
> body_mass(m_n_bodies
, m_pdata
->getExecConf());
230 GPUArray
<unsigned int> body_size(m_n_bodies
, m_pdata
->getExecConf());
231 GPUArray
<Scalar4
> moment_inertia(m_n_bodies
, m_pdata
->getExecConf());
232 GPUArray
<Scalar4
> orientation(m_n_bodies
, m_pdata
->getExecConf());
233 GPUArray
<Scalar4
> ex_space(m_n_bodies
, m_pdata
->getExecConf());
234 GPUArray
<Scalar4
> ey_space(m_n_bodies
, m_pdata
->getExecConf());
235 GPUArray
<Scalar4
> ez_space(m_n_bodies
, m_pdata
->getExecConf());
236 GPUArray
<int3
> body_image(m_n_bodies
, m_pdata
->getExecConf());
237 GPUArray
<Scalar4
> conjqm_alloc(m_n_bodies
, m_pdata
->getExecConf());
239 GPUArray
<Scalar4
> com(m_n_bodies
, m_pdata
->getExecConf());
240 GPUArray
<Scalar4
> vel(m_n_bodies
, m_pdata
->getExecConf());
241 GPUArray
<Scalar4
> angmom(m_n_bodies
, m_pdata
->getExecConf());
242 GPUArray
<Scalar4
> angvel(m_n_bodies
, m_pdata
->getExecConf());
243 GPUArray
<Scalar4
> force(m_n_bodies
, m_pdata
->getExecConf());
244 GPUArray
<Scalar4
> torque(m_n_bodies
, m_pdata
->getExecConf());
246 GPUArray
<unsigned int> particle_offset(m_pdata
->getN(), m_pdata
->getExecConf());
248 m_body_dof
.swap(body_dof
);
249 m_body_mass
.swap(body_mass
);
250 m_body_size
.swap(body_size
);
251 m_moment_inertia
.swap(moment_inertia
);
252 m_orientation
.swap(orientation
);
253 m_ex_space
.swap(ex_space
);
254 m_ey_space
.swap(ey_space
);
255 m_ez_space
.swap(ez_space
);
256 m_body_image
.swap(body_image
);
257 m_conjqm
.swap(conjqm_alloc
);
261 m_angmom
.swap(angmom
);
262 m_angvel
.swap(angvel
);
264 m_torque
.swap(torque
);
266 m_particle_offset
.swap(particle_offset
);
269 // determine the largest size of rigid bodies (nmax)
270 ArrayHandle
<unsigned int> body_size_handle(m_body_size
, access_location::host
, access_mode::readwrite
);
271 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
272 body_size_handle
.data
[body
] = 0;
274 for (unsigned int j
= 0; j
< nparticles
; j
++)
276 unsigned int body
= h_body
.data
[j
];
278 body_size_handle
.data
[body
]++;
281 // determine the maximum number of particles in a rigid body
283 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
284 if (m_nmax
< body_size_handle
.data
[body
])
285 m_nmax
= body_size_handle
.data
[body
];
287 // determine body_mass, inertia tensor, com and vel
288 GPUArray
<Scalar
> inertia(6, m_n_bodies
, m_pdata
->getExecConf()); // the inertia tensor is symmetric, therefore we only need to store 6 elements
289 ArrayHandle
<Scalar
> inertia_handle(inertia
, access_location::host
, access_mode::readwrite
);
290 unsigned int inertia_pitch
= inertia
.getPitch();
292 ArrayHandle
<unsigned int> body_dof_handle(m_body_dof
, access_location::host
, access_mode::readwrite
);
293 ArrayHandle
<Scalar
> body_mass_handle(m_body_mass
, access_location::host
, access_mode::readwrite
);
294 ArrayHandle
<Scalar4
> moment_inertia_handle(m_moment_inertia
, access_location::host
, access_mode::readwrite
);
295 ArrayHandle
<Scalar4
> orientation_handle(m_orientation
, access_location::host
, access_mode::readwrite
);
296 ArrayHandle
<Scalar4
> ex_space_handle(m_ex_space
, access_location::host
, access_mode::readwrite
);
297 ArrayHandle
<Scalar4
> ey_space_handle(m_ey_space
, access_location::host
, access_mode::readwrite
);
298 ArrayHandle
<Scalar4
> ez_space_handle(m_ez_space
, access_location::host
, access_mode::readwrite
);
299 ArrayHandle
<int3
> body_image_handle(m_body_image
, access_location::host
, access_mode::readwrite
);
300 ArrayHandle
<Scalar4
> com_handle(m_com
, access_location::host
, access_mode::readwrite
);
302 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
304 body_mass_handle
.data
[body
] = 0.0;
305 com_handle
.data
[body
].x
= 0.0;
306 com_handle
.data
[body
].y
= 0.0;
307 com_handle
.data
[body
].z
= 0.0;
309 inertia_handle
.data
[inertia_pitch
* body
] = 0.0;
310 inertia_handle
.data
[inertia_pitch
* body
+ 1] = 0.0;
311 inertia_handle
.data
[inertia_pitch
* body
+ 2] = 0.0;
312 inertia_handle
.data
[inertia_pitch
* body
+ 3] = 0.0;
313 inertia_handle
.data
[inertia_pitch
* body
+ 4] = 0.0;
314 inertia_handle
.data
[inertia_pitch
* body
+ 5] = 0.0;
317 // determine a nominal box image vector for each body
318 // this is done so that bodies may be "unwrapped" from around the box dimensions in a numerically
319 // stable way by bringing all particles unwrapped coords to being at most slightly outside of the box.
320 std::vector
<int3
> nominal_body_image(m_n_bodies
);
322 ArrayHandle
< int3
> h_image(m_pdata
->getImages(), access_location::host
, access_mode::read
);
323 ArrayHandle
< Scalar4
> h_pos(m_pdata
->getPositions(), access_location::host
, access_mode::read
);
324 for (unsigned int j
= 0; j
< nparticles
; j
++)
326 unsigned int body
= h_body
.data
[j
];
328 nominal_body_image
[body
] = h_image
.data
[j
];
331 // compute the center of mass for each body by summing up mass * \vec{r} for each particle in the body
332 ArrayHandle
< Scalar4
> h_vel(m_pdata
->getVelocities(), access_location::host
, access_mode::read
);
333 for (unsigned int j
= 0; j
< m_pdata
->getN(); j
++)
335 if (h_body
.data
[j
] == NO_BODY
) continue;
337 unsigned int body
= h_body
.data
[j
];
338 Scalar mass_one
= h_vel
.data
[j
].w
;
339 body_mass_handle
.data
[body
] += mass_one
;
340 // unwrap all particles in a body to the same image
341 int3 shift
= make_int3(h_image
.data
[j
].x
- nominal_body_image
[body
].x
,
342 h_image
.data
[j
].y
- nominal_body_image
[body
].y
,
343 h_image
.data
[j
].z
- nominal_body_image
[body
].z
);
344 Scalar3 wrapped
= make_scalar3(h_pos
.data
[j
].x
, h_pos
.data
[j
].y
, h_pos
.data
[j
].z
);
345 Scalar3 unwrapped
= box
.shift(wrapped
, shift
);
347 com_handle
.data
[body
].x
+= mass_one
* unwrapped
.x
;
348 com_handle
.data
[body
].y
+= mass_one
* unwrapped
.y
;
349 com_handle
.data
[body
].z
+= mass_one
* unwrapped
.z
;
352 // complete the COM calculation by dividing by the mass of the body
353 // for the moment, this is left in nominal unwrapped coordinates (it may be slightly outside the box) to enable
354 // computation of the moment of inertia. This will be corrected after the moment of inertia is computed.
355 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
357 Scalar mass_body
= body_mass_handle
.data
[body
];
358 com_handle
.data
[body
].x
/= mass_body
;
359 com_handle
.data
[body
].y
/= mass_body
;
360 com_handle
.data
[body
].z
/= mass_body
;
362 body_image_handle
.data
[body
].x
= nominal_body_image
[body
].x
;
363 body_image_handle
.data
[body
].y
= nominal_body_image
[body
].y
;
364 body_image_handle
.data
[body
].z
= nominal_body_image
[body
].z
;
367 Scalar4 porientation
;
369 InertiaTensor pinertia_tensor
;
370 Scalar rot_mat
[3][3], rot_mat_trans
[3][3], Ibody
[3][3], Ispace
[3][3], tmp
[3][3];
372 ArrayHandle
< unsigned int > h_tag(m_pdata
->getTags(), access_location::host
, access_mode::read
);
374 // determine the inertia tensor then diagonalize it
375 for (unsigned int j
= 0; j
< m_pdata
->getN(); j
++)
377 if (h_body
.data
[j
] == NO_BODY
) continue;
379 unsigned int body
= h_body
.data
[j
];
380 Scalar mass_one
= h_vel
.data
[j
].w
;
381 unsigned int tag
= h_tag
.data
[j
];
383 // unwrap all particles in a body to the same image
384 int3 shift
= make_int3(h_image
.data
[j
].x
- nominal_body_image
[body
].x
,
385 h_image
.data
[j
].y
- nominal_body_image
[body
].y
,
386 h_image
.data
[j
].z
- nominal_body_image
[body
].z
);
387 Scalar3 wrapped
= make_scalar3(h_pos
.data
[j
].x
, h_pos
.data
[j
].y
, h_pos
.data
[j
].z
);
388 Scalar3 unwrapped
= box
.shift(wrapped
, shift
);
390 Scalar dx
= unwrapped
.x
- com_handle
.data
[body
].x
;
391 Scalar dy
= unwrapped
.y
- com_handle
.data
[body
].y
;
392 Scalar dz
= unwrapped
.z
- com_handle
.data
[body
].z
;
394 inertia_handle
.data
[inertia_pitch
* body
+ 0] += mass_one
* (dy
* dy
+ dz
* dz
);
395 inertia_handle
.data
[inertia_pitch
* body
+ 1] += mass_one
* (dz
* dz
+ dx
* dx
);
396 inertia_handle
.data
[inertia_pitch
* body
+ 2] += mass_one
* (dx
* dx
+ dy
* dy
);
397 inertia_handle
.data
[inertia_pitch
* body
+ 3] -= mass_one
* dx
* dy
;
398 inertia_handle
.data
[inertia_pitch
* body
+ 4] -= mass_one
* dy
* dz
;
399 inertia_handle
.data
[inertia_pitch
* body
+ 5] -= mass_one
* dx
* dz
;
401 // take into account the partile inertia moments
402 // get the original particle orientation and inertia tensor from input
403 porientation
= h_p_orientation
.data
[j
];
404 pinertia_tensor
= m_pdata
->getInertiaTensor(tag
);
406 exyzFromQuaternion(porientation
, ex
, ey
, ez
);
408 rot_mat
[0][0] = rot_mat_trans
[0][0] = ex
.x
;
409 rot_mat
[1][0] = rot_mat_trans
[0][1] = ex
.y
;
410 rot_mat
[2][0] = rot_mat_trans
[0][2] = ex
.z
;
412 rot_mat
[0][1] = rot_mat_trans
[1][0] = ey
.x
;
413 rot_mat
[1][1] = rot_mat_trans
[1][1] = ey
.y
;
414 rot_mat
[2][1] = rot_mat_trans
[1][2] = ey
.z
;
416 rot_mat
[0][2] = rot_mat_trans
[2][0] = ez
.x
;
417 rot_mat
[1][2] = rot_mat_trans
[2][1] = ez
.y
;
418 rot_mat
[2][2] = rot_mat_trans
[2][2] = ez
.z
;
420 Ibody
[0][0] = pinertia_tensor
.components
[0];
421 Ibody
[0][1] = Ibody
[1][0] = pinertia_tensor
.components
[1];
422 Ibody
[0][2] = Ibody
[2][0] = pinertia_tensor
.components
[2];
423 Ibody
[1][1] = pinertia_tensor
.components
[3];
424 Ibody
[1][2] = Ibody
[2][1] = pinertia_tensor
.components
[4];
425 Ibody
[2][2] = pinertia_tensor
.components
[5];
427 // convert the particle inertia tensor to the space fixed frame
428 mat_multiply(Ibody
, rot_mat_trans
, tmp
);
429 mat_multiply(rot_mat
, tmp
, Ispace
);
431 inertia_handle
.data
[inertia_pitch
* body
+ 0] += Ispace
[0][0];
432 inertia_handle
.data
[inertia_pitch
* body
+ 1] += Ispace
[1][1];
433 inertia_handle
.data
[inertia_pitch
* body
+ 2] += Ispace
[2][2];
434 inertia_handle
.data
[inertia_pitch
* body
+ 3] += Ispace
[0][1];
435 inertia_handle
.data
[inertia_pitch
* body
+ 4] += Ispace
[1][2];
436 inertia_handle
.data
[inertia_pitch
* body
+ 5] += Ispace
[0][2];
439 // allocate temporary arrays: revision needed!
440 Scalar
**matrix
, *evalues
, **evectors
;
441 matrix
= new Scalar
*[3];
442 evectors
= new Scalar
*[3];
443 evalues
= new Scalar
[3];
444 for (unsigned int j
= 0; j
< 3; j
++)
446 matrix
[j
] = new Scalar
[3];
447 evectors
[j
] = new Scalar
[3];
450 unsigned int dof_one
;
451 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
453 matrix
[0][0] = inertia_handle
.data
[inertia_pitch
* body
+ 0];
454 matrix
[1][1] = inertia_handle
.data
[inertia_pitch
* body
+ 1];
455 matrix
[2][2] = inertia_handle
.data
[inertia_pitch
* body
+ 2];
456 matrix
[0][1] = matrix
[1][0] = inertia_handle
.data
[inertia_pitch
* body
+ 3];
457 matrix
[1][2] = matrix
[2][1] = inertia_handle
.data
[inertia_pitch
* body
+ 4];
458 matrix
[2][0] = matrix
[0][2] = inertia_handle
.data
[inertia_pitch
* body
+ 5];
460 int error
= diagonalize(matrix
, evalues
, evectors
);
462 m_exec_conf
->msg
->warning() << "rigid data: Insufficient Jacobi iterations for diagonalization!\n";
464 // obtain the moment inertia from eigen values
465 moment_inertia_handle
.data
[body
].x
= evalues
[0];
466 moment_inertia_handle
.data
[body
].y
= evalues
[1];
467 moment_inertia_handle
.data
[body
].z
= evalues
[2];
469 // set tiny moment of inertia component to be zero, count the number of degrees of freedom
470 // the actual DOF for temperature calculation is computed in the integrator (TwoStepNVERigid)
471 // where the number of system dimensions is available
472 // The counting below is only for book-keeping
475 Scalar max
= MAX(moment_inertia_handle
.data
[body
].x
, moment_inertia_handle
.data
[body
].y
);
476 max
= MAX(max
, moment_inertia_handle
.data
[body
].z
);
478 if (moment_inertia_handle
.data
[body
].x
< EPSILON
* max
)
481 moment_inertia_handle
.data
[body
].x
= Scalar(0.0);
484 if (moment_inertia_handle
.data
[body
].y
< EPSILON
* max
)
487 moment_inertia_handle
.data
[body
].y
= Scalar(0.0);
490 if (moment_inertia_handle
.data
[body
].z
< EPSILON
* max
)
493 moment_inertia_handle
.data
[body
].z
= Scalar(0.0);
496 body_dof_handle
.data
[body
] = dof_one
;
499 // obtain the principle axes from eigen vectors
500 ex_space_handle
.data
[body
].x
= evectors
[0][0];
501 ex_space_handle
.data
[body
].y
= evectors
[1][0];
502 ex_space_handle
.data
[body
].z
= evectors
[2][0];
504 ey_space_handle
.data
[body
].x
= evectors
[0][1];
505 ey_space_handle
.data
[body
].y
= evectors
[1][1];
506 ey_space_handle
.data
[body
].z
= evectors
[2][1];
508 ez_space_handle
.data
[body
].x
= evectors
[0][2];
509 ez_space_handle
.data
[body
].y
= evectors
[1][2];
510 ez_space_handle
.data
[body
].z
= evectors
[2][2];
512 // create the initial quaternion from the new body frame
513 quaternionFromExyz(ex_space_handle
.data
[body
], ey_space_handle
.data
[body
], ez_space_handle
.data
[body
],
514 orientation_handle
.data
[body
]);
517 // deallocate temporary memory
520 for (unsigned int j
= 0; j
< 3; j
++)
523 delete [] evectors
[j
];
530 // allocate nmax by m_n_bodies arrays, swap to member variables then use array handles to access
531 GPUArray
<unsigned int> particle_tags(m_nmax
, m_n_bodies
, m_pdata
->getExecConf());
532 m_particle_tags
.swap(particle_tags
);
533 ArrayHandle
<unsigned int> particle_tags_handle(m_particle_tags
, access_location::host
, access_mode::readwrite
);
534 unsigned int particle_tags_pitch
= m_particle_tags
.getPitch();
536 GPUArray
<unsigned int> particle_indices(m_nmax
, m_n_bodies
, m_pdata
->getExecConf());
537 m_particle_indices
.swap(particle_indices
);
538 ArrayHandle
<unsigned int> particle_indices_handle(m_particle_indices
, access_location::host
, access_mode::readwrite
);
539 unsigned int particle_indices_pitch
= m_particle_indices
.getPitch();
541 for (unsigned int j
= 0; j
< m_n_bodies
; j
++)
542 for (unsigned int local
= 0; local
< particle_indices_pitch
; local
++)
543 particle_indices_handle
.data
[j
* particle_indices_pitch
+ local
] = NO_INDEX
; // initialize with a sentinel value
545 GPUArray
<Scalar4
> particle_pos(m_nmax
, m_n_bodies
, m_pdata
->getExecConf());
546 m_particle_pos
.swap(particle_pos
);
547 ArrayHandle
<Scalar4
> particle_pos_handle(m_particle_pos
, access_location::host
, access_mode::readwrite
);
548 unsigned int particle_pos_pitch
= m_particle_pos
.getPitch();
550 GPUArray
<Scalar4
> particle_orientation(m_nmax
, m_n_bodies
, m_pdata
->getExecConf());
551 m_particle_orientation
.swap(particle_orientation
);
552 ArrayHandle
<Scalar4
> h_particle_orientation(m_particle_orientation
, access_location::host
, access_mode::readwrite
);
554 GPUArray
<unsigned int> local_indices(m_n_bodies
, m_pdata
->getExecConf());
555 ArrayHandle
<unsigned int> local_indices_handle(local_indices
, access_location::host
, access_mode::readwrite
);
556 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
557 local_indices_handle
.data
[body
] = 0;
559 // Now set the m_nmax according to the actual pitches to avoid dublicating rounding up (e.g. if m_nmax is rounded up to 16 here,
560 // then in the GPUArray constructor the pitch is rounded up once more to be 32.
561 m_nmax
= particle_tags_pitch
;
563 //tally up how many particles belong to rigid bodies
564 unsigned int rigid_particle_count
= 0;
566 // determine the particle indices and particle tags
567 for (unsigned int j
= 0; j
< m_pdata
->getN(); j
++)
569 if (h_body
.data
[j
] == NO_BODY
) continue;
571 rigid_particle_count
++;
573 // get the corresponding body
574 unsigned int body
= h_body
.data
[j
];
575 // get the current index in the body
576 unsigned int current_localidx
= local_indices_handle
.data
[body
];
577 // set the particle index to be this value
578 particle_indices_handle
.data
[body
* particle_indices_pitch
+ current_localidx
] = j
;
579 // set the particle tag to be the tag of this particle
580 particle_tags_handle
.data
[body
* particle_tags_pitch
+ current_localidx
] = h_tag
.data
[j
];
582 // determine the particle position in the body frame
583 // with ex_space, ey_space and ex_space vectors computed from the diagonalization
584 // unwrap all particles in a body to the same image
585 int3 shift
= make_int3(h_image
.data
[j
].x
- nominal_body_image
[body
].x
,
586 h_image
.data
[j
].y
- nominal_body_image
[body
].y
,
587 h_image
.data
[j
].z
- nominal_body_image
[body
].z
);
588 Scalar3 wrapped
= make_scalar3(h_pos
.data
[j
].x
, h_pos
.data
[j
].y
, h_pos
.data
[j
].z
);
589 Scalar3 unwrapped
= box
.shift(wrapped
, shift
);
591 Scalar dx
= unwrapped
.x
- com_handle
.data
[body
].x
;
592 Scalar dy
= unwrapped
.y
- com_handle
.data
[body
].y
;
593 Scalar dz
= unwrapped
.z
- com_handle
.data
[body
].z
;
595 unsigned int idx
= body
* particle_pos_pitch
+ current_localidx
;
596 particle_pos_handle
.data
[idx
].x
= dx
* ex_space_handle
.data
[body
].x
+ dy
* ex_space_handle
.data
[body
].y
+
597 dz
* ex_space_handle
.data
[body
].z
;
598 particle_pos_handle
.data
[idx
].y
= dx
* ey_space_handle
.data
[body
].x
+ dy
* ey_space_handle
.data
[body
].y
+
599 dz
* ey_space_handle
.data
[body
].z
;
600 particle_pos_handle
.data
[idx
].z
= dx
* ez_space_handle
.data
[body
].x
+ dy
* ez_space_handle
.data
[body
].y
+
601 dz
* ez_space_handle
.data
[body
].z
;
603 // initialize h_particle_orientation.data[idx] here from the initial particle orientation. This means
604 // reading the intial particle orientation from ParticleData and translating it backwards into the body frame
606 quatconj(orientation_handle
.data
[body
], qc
);
608 porientation
= h_p_orientation
.data
[j
];
609 quatquat(qc
, porientation
, h_particle_orientation
.data
[idx
]);
610 normalize(h_particle_orientation
.data
[idx
]);
612 // increment the current index by one
613 local_indices_handle
.data
[body
]++;
616 // now that all computations using nominally unwrapped coordinates are done, put the COM into the simulation box
617 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
619 box
.wrap(com_handle
.data
[body
], body_image_handle
.data
[body
]);
622 //initialize rigid_particle_indices
623 GPUArray
<unsigned int> rigid_particle_indices(rigid_particle_count
, m_pdata
->getExecConf());
624 m_rigid_particle_indices
.swap(rigid_particle_indices
);
625 m_num_particles
= rigid_particle_count
;
627 GPUArray
<Scalar4
> particle_oldpos(m_pdata
->getN(), m_pdata
->getExecConf());
628 m_particle_oldpos
.swap(particle_oldpos
);
630 GPUArray
<Scalar4
> particle_oldvel(m_pdata
->getN(), m_pdata
->getExecConf());
631 m_particle_oldvel
.swap(particle_oldvel
);
633 // release particle data for later access
634 } // out of scope for handles
636 // finish up by initializing the indices
640 /* Set position and velocity of constituent particles in rigid bodies in the 1st or second half of integration
641 based on the body center of mass and particle relative position in each body frame.
642 \param set_x if true, positions are updated too. Else just velocities.
645 void RigidData::setRV(bool set_x
)
648 if (m_pdata
->getExecConf()->exec_mode
== ExecutionConfiguration::GPU
)
656 /* Set position and velocity of constituent particles in rigid bodies in the 1st or second half of integration on the CPU
657 based on the body center of mass and particle relative position in each body frame.
658 \param set_x if true, positions are updated too. Else just velocities.
661 void RigidData::setRVCPU(bool set_x
)
664 const BoxDim
& box
= m_pdata
->getBox();
666 // access to the force
667 const GPUArray
< Scalar4
>& net_force
= m_pdata
->getNetForce();
668 ArrayHandle
<Scalar4
> h_net_force(net_force
, access_location::host
, access_mode::read
);
670 // rigid body handles
671 ArrayHandle
<unsigned int> body_size_handle(m_body_size
, access_location::host
, access_mode::read
);
672 ArrayHandle
<Scalar4
> com(m_com
, access_location::host
, access_mode::read
);
673 ArrayHandle
<Scalar4
> vel_handle(m_vel
, access_location::host
, access_mode::read
);
674 ArrayHandle
<Scalar4
> angvel_handle(m_angvel
, access_location::host
, access_mode::read
);
675 ArrayHandle
<Scalar4
> orientation_handle(m_orientation
, access_location::host
, access_mode::read
);
676 ArrayHandle
<int3
> body_image_handle(m_body_image
, access_location::host
, access_mode::read
);
678 ArrayHandle
<unsigned int> particle_indices_handle(m_particle_indices
, access_location::host
, access_mode::read
);
679 unsigned int indices_pitch
= m_particle_indices
.getPitch();
680 ArrayHandle
<Scalar4
> particle_pos_handle(m_particle_pos
, access_location::host
, access_mode::read
);
681 unsigned int particle_pos_pitch
= m_particle_pos
.getPitch();
682 ArrayHandle
<Scalar4
> particle_orientation(m_particle_orientation
, access_location::host
, access_mode::read
);
684 // access the particle data arrays
685 ArrayHandle
<Scalar4
> h_pos(m_pdata
->getPositions(), access_location::host
, access_mode::readwrite
);
686 ArrayHandle
<Scalar4
> h_vel(m_pdata
->getVelocities(), access_location::host
, access_mode::readwrite
);
687 ArrayHandle
<int3
> h_image(m_pdata
->getImages(), access_location::host
, access_mode::readwrite
);
688 ArrayHandle
<Scalar4
> h_p_orientation(m_pdata
->getOrientationArray(), access_location::host
, access_mode::readwrite
);
690 Scalar4 ex_space
, ey_space
, ez_space
;
692 // for each body of all the bodies
693 for (unsigned int body
= 0; body
< m_n_bodies
; body
++)
695 exyzFromQuaternion(orientation_handle
.data
[body
], ex_space
, ey_space
, ez_space
);
697 unsigned int len
= body_size_handle
.data
[body
];
699 for (unsigned int j
= 0; j
< len
; j
++)
701 // get the actual index of particle in the particle arrays
702 unsigned int pidx
= particle_indices_handle
.data
[body
* indices_pitch
+ j
];
703 // get the index of particle in the current rigid body in the particle_pos array
704 unsigned int localidx
= body
* particle_pos_pitch
+ j
;
706 // project the position in the body frame to the space frame: xr = rotation_matrix * particle_pos
707 Scalar xr
= ex_space
.x
* particle_pos_handle
.data
[localidx
].x
708 + ey_space
.x
* particle_pos_handle
.data
[localidx
].y
709 + ez_space
.x
* particle_pos_handle
.data
[localidx
].z
;
710 Scalar yr
= ex_space
.y
* particle_pos_handle
.data
[localidx
].x
711 + ey_space
.y
* particle_pos_handle
.data
[localidx
].y
712 + ez_space
.y
* particle_pos_handle
.data
[localidx
].z
;
713 Scalar zr
= ex_space
.z
* particle_pos_handle
.data
[localidx
].x
714 + ey_space
.z
* particle_pos_handle
.data
[localidx
].y
715 + ez_space
.z
* particle_pos_handle
.data
[localidx
].z
;
719 // x_particle = x_com + xr
720 Scalar3 pos
= make_scalar3(com
.data
[body
].x
+ xr
,
721 com
.data
[body
].y
+ yr
,
722 com
.data
[body
].z
+ zr
);
724 // adjust particle images based on body images
725 h_image
.data
[pidx
] = body_image_handle
.data
[body
];
727 box
.wrap(pos
, h_image
.data
[pidx
]);
728 h_pos
.data
[pidx
].x
= pos
.x
;
729 h_pos
.data
[pidx
].y
= pos
.y
;
730 h_pos
.data
[pidx
].z
= pos
.z
;
732 // update the particle orientation: q_i = quat[body] * particle_quat
733 Scalar4 porientation
;
734 quatquat(orientation_handle
.data
[body
], particle_orientation
.data
[localidx
], porientation
);
735 normalize(porientation
);
736 h_p_orientation
.data
[pidx
] = porientation
;
739 // v_particle = v_com + angvel x xr
740 h_vel
.data
[pidx
].x
= vel_handle
.data
[body
].x
+ angvel_handle
.data
[body
].y
* zr
- angvel_handle
.data
[body
].z
* yr
;
741 h_vel
.data
[pidx
].y
= vel_handle
.data
[body
].y
+ angvel_handle
.data
[body
].z
* xr
- angvel_handle
.data
[body
].x
* zr
;
742 h_vel
.data
[pidx
].z
= vel_handle
.data
[body
].z
+ angvel_handle
.data
[body
].x
* yr
- angvel_handle
.data
[body
].y
* xr
;
748 /* Helper GPU function to set position and velocity of constituent particles in rigid bodies in the 1st or second half of integration
749 based on the body center of mass and particle relative position in each body frame.
750 \param set_x if true, positions are updated too. Else just velocities.
754 void RigidData::setRVGPU(bool set_x
)
761 ArrayHandle
<Scalar4
> d_pos(m_pdata
->getPositions(), access_location::device
, access_mode::readwrite
);
762 ArrayHandle
<Scalar4
> d_vel(m_pdata
->getVelocities(), access_location::device
, access_mode::readwrite
);
763 ArrayHandle
<int3
> d_image(m_pdata
->getImages(), access_location::device
, access_mode::readwrite
);
764 ArrayHandle
<unsigned int> d_body(m_pdata
->getBodies(), access_location::device
, access_mode::read
);
767 ArrayHandle
<unsigned int> rigid_particle_indices(m_rigid_particle_indices
, access_location::device
, access_mode::read
);
769 // access all the needed data
770 ArrayHandle
<Scalar4
> d_porientation(m_pdata
->getOrientationArray(),access_location::device
,access_mode::readwrite
);
772 BoxDim box
= m_pdata
->getBox();
774 ArrayHandle
<Scalar
> body_mass_handle(m_body_mass
, access_location::device
, access_mode::read
);
775 ArrayHandle
<Scalar4
> moment_inertia_handle(m_moment_inertia
, access_location::device
, access_mode::read
);
776 ArrayHandle
<Scalar4
> com_handle(m_com
, access_location::device
, access_mode::readwrite
);
777 ArrayHandle
<Scalar4
> vel_handle(m_vel
, access_location::device
, access_mode::readwrite
);
778 ArrayHandle
<Scalar4
> angvel_handle(m_angvel
, access_location::device
, access_mode::readwrite
);
779 ArrayHandle
<Scalar4
> angmom_handle(m_angmom
, access_location::device
, access_mode::readwrite
);
780 ArrayHandle
<Scalar4
> orientation_handle(m_orientation
, access_location::device
, access_mode::readwrite
);
781 ArrayHandle
<int3
> body_image_handle(m_body_image
, access_location::device
, access_mode::readwrite
);
782 ArrayHandle
<Scalar4
> particle_pos_handle(m_particle_pos
, access_location::device
, access_mode::read
);
783 ArrayHandle
<unsigned int> particle_indices_handle(m_particle_indices
, access_location::device
, access_mode::read
);
784 ArrayHandle
<Scalar4
> force_handle(m_force
, access_location::device
, access_mode::read
);
785 ArrayHandle
<Scalar4
> torque_handle(m_torque
, access_location::device
, access_mode::read
);
787 ArrayHandle
<unsigned int> d_particle_offset(m_particle_offset
, access_location::device
, access_mode::read
);
788 ArrayHandle
<Scalar4
> d_particle_orientation(m_particle_orientation
, access_location::device
, access_mode::readwrite
);
791 // More data is filled in here than I use.
792 gpu_rigid_data_arrays d_rdata
;
793 d_rdata
.n_bodies
= m_n_bodies
;
794 d_rdata
.n_group_bodies
= m_n_bodies
;
795 d_rdata
.nmax
= m_nmax
;
796 d_rdata
.local_beg
= 0;
797 d_rdata
.local_num
= m_n_bodies
;
799 d_rdata
.body_mass
= body_mass_handle
.data
;
800 d_rdata
.moment_inertia
= moment_inertia_handle
.data
;
801 d_rdata
.com
= com_handle
.data
;
802 d_rdata
.vel
= vel_handle
.data
;
803 d_rdata
.angvel
= angvel_handle
.data
;
804 d_rdata
.angmom
= angmom_handle
.data
;
805 d_rdata
.orientation
= orientation_handle
.data
;
806 d_rdata
.body_image
= body_image_handle
.data
;
807 d_rdata
.particle_pos
= particle_pos_handle
.data
;
808 d_rdata
.particle_indices
= particle_indices_handle
.data
;
809 d_rdata
.force
= force_handle
.data
;
810 d_rdata
.torque
= torque_handle
.data
;
811 d_rdata
.particle_offset
= d_particle_offset
.data
;
812 d_rdata
.particle_orientation
= d_particle_orientation
.data
;
815 gpu_rigid_setRV( d_pos
.data
,
821 rigid_particle_indices
.data
,
830 /*! Compute eigenvalues and eigenvectors of 3x3 real symmetric matrix based on Jacobi rotations adapted from Numerical Recipes jacobi() function (LAMMPS)
831 \param matrix Matrix to be diagonalized
832 \param evalues Eigen-values obtained after diagonalized
833 \param evectors Eigen-vectors obtained after diagonalized in columns
837 int RigidData::diagonalize(Scalar
**matrix
, Scalar
*evalues
, Scalar
**evectors
)
840 Scalar tresh
, theta
, tau
, t
, sm
, s
, h
, g
, c
, b
[3], z
[3];
842 for (i
= 0; i
< 3; i
++)
844 for (j
= 0; j
< 3; j
++) evectors
[i
][j
] = 0.0;
845 evectors
[i
][i
] = 1.0;
848 for (i
= 0; i
< 3; i
++)
850 b
[i
] = evalues
[i
] = matrix
[i
][i
];
854 for (int iter
= 1; iter
<= MAXJACOBI
; iter
++)
857 for (i
= 0; i
< 2; i
++)
858 for (j
= i
+1; j
< 3; j
++)
859 sm
+= fabs(matrix
[i
][j
]);
861 if (sm
== 0.0) return 0;
863 if (iter
< 4) tresh
= 0.2*sm
/(3*3);
866 for (i
= 0; i
< 2; i
++)
868 for (j
= i
+1; j
< 3; j
++)
870 g
= 100.0 * fabs(matrix
[i
][j
]);
871 if (iter
> 4 && fabs(evalues
[i
]) + g
== fabs(evalues
[i
])
872 && fabs(evalues
[j
]) + g
== fabs(evalues
[j
]))
874 else if (fabs(matrix
[i
][j
]) > tresh
)
876 h
= evalues
[j
]-evalues
[i
];
877 if (fabs(h
)+g
== fabs(h
)) t
= (matrix
[i
][j
])/h
;
880 theta
= 0.5 * h
/ (matrix
[i
][j
]);
881 t
= 1.0/(fabs(theta
)+sqrt(1.0+theta
*theta
));
882 if (theta
< 0.0) t
= -t
;
885 c
= 1.0/sqrt(1.0+t
*t
);
894 for (k
= 0; k
< i
; k
++) rotate(matrix
,k
,i
,k
,j
,s
,tau
);
895 for (k
= i
+1; k
< j
; k
++) rotate(matrix
,i
,k
,k
,j
,s
,tau
);
896 for (k
= j
+1; k
< 3; k
++) rotate(matrix
,i
,k
,j
,k
,s
,tau
);
897 for (k
= 0; k
< 3; k
++) rotate(evectors
,k
,i
,k
,j
,s
,tau
);
902 for (i
= 0; i
< 3; i
++)
904 evalues
[i
] = b
[i
] += z
[i
];
912 /*! Perform a single Jacobi rotation
913 \param matrix Matrix to be diagonalized
922 void RigidData::rotate(Scalar
**matrix
, int i
, int j
, int k
, int l
, Scalar s
, Scalar tau
)
924 Scalar g
= matrix
[i
][j
];
925 Scalar h
= matrix
[k
][l
];
926 matrix
[i
][j
] = g
- s
* (h
+ g
* tau
);
927 matrix
[k
][l
] = h
+ s
* (g
- h
* tau
);
930 /*! Calculate the quaternion from three axes
931 \param ex_space x-axis unit vector
932 \param ey_space y-axis unit vector
933 \param ez_space z-axis unit vector
934 \param quat returned quaternion
937 void RigidData::quaternionFromExyz(Scalar4
&ex_space
, Scalar4
&ey_space
, Scalar4
&ez_space
, Scalar4
&quat
)
940 // enforce 3 evectors as a right-handed coordinate system
941 // flip 3rd evector if needed
942 Scalar ez0
, ez1
, ez2
; // Cross product of first two vectors
943 ez0
= ex_space
.y
* ey_space
.z
- ex_space
.z
* ey_space
.y
;
944 ez1
= ex_space
.z
* ey_space
.x
- ex_space
.x
* ey_space
.z
;
945 ez2
= ex_space
.x
* ey_space
.y
- ex_space
.y
* ey_space
.x
;
947 // then dot product with the third one
948 if (ez0
* ez_space
.x
+ ez1
* ez_space
.y
+ ez2
* ez_space
.z
< 0.0)
950 ez_space
.x
= -ez_space
.x
;
951 ez_space
.y
= -ez_space
.y
;
952 ez_space
.z
= -ez_space
.z
;
955 // squares of quaternion components
956 Scalar q0sq
= 0.25 * (ex_space
.x
+ ey_space
.y
+ ez_space
.z
+ 1.0);
957 Scalar q1sq
= q0sq
- 0.5 * (ey_space
.y
+ ez_space
.z
);
958 Scalar q2sq
= q0sq
- 0.5 * (ex_space
.x
+ ez_space
.z
);
959 Scalar q3sq
= q0sq
- 0.5 * (ex_space
.x
+ ey_space
.y
);
961 // some component must be greater than 1/4 since they sum to 1
962 // compute other components from it
966 quat
.y
= (ey_space
.z
- ez_space
.y
) / (4.0 * quat
.x
);
967 quat
.z
= (ez_space
.x
- ex_space
.z
) / (4.0 * quat
.x
);
968 quat
.w
= (ex_space
.y
- ey_space
.x
) / (4.0 * quat
.x
);
970 else if (q1sq
>= 0.25)
973 quat
.x
= (ey_space
.z
- ez_space
.y
) / (4.0 * quat
.y
);
974 quat
.z
= (ey_space
.x
+ ex_space
.y
) / (4.0 * quat
.y
);
975 quat
.w
= (ex_space
.z
+ ez_space
.x
) / (4.0 * quat
.y
);
977 else if (q2sq
>= 0.25)
980 quat
.x
= (ez_space
.x
- ex_space
.z
) / (4.0 * quat
.z
);
981 quat
.y
= (ey_space
.x
+ ex_space
.y
) / (4.0 * quat
.z
);
982 quat
.w
= (ez_space
.y
+ ey_space
.z
) / (4.0 * quat
.z
);
984 else if (q3sq
>= 0.25)
987 quat
.x
= (ex_space
.y
- ey_space
.x
) / (4.0 * quat
.w
);
988 quat
.y
= (ez_space
.x
+ ex_space
.z
) / (4.0 * quat
.w
);
989 quat
.z
= (ez_space
.y
+ ey_space
.z
) / (4.0 * quat
.w
);
993 Scalar norm
= 1.0 / sqrt(quat
.x
* quat
.x
+ quat
.y
* quat
.y
+ quat
.z
* quat
.z
+ quat
.w
* quat
.w
);
1001 /*! Calculate the axes from quaternion
1002 \param quat returned quaternion
1003 \param ex_space x-axis unit vector
1004 \param ey_space y-axis unit vector
1005 \param ez_space z-axis unit vector
1008 void RigidData::exyzFromQuaternion(Scalar4
&quat
, Scalar4
&ex_space
, Scalar4
&ey_space
, Scalar4
&ez_space
)
1010 ex_space
.x
= quat
.x
* quat
.x
+ quat
.y
* quat
.y
- quat
.z
* quat
.z
- quat
.w
* quat
.w
;
1011 ex_space
.y
= 2.0 * (quat
.y
* quat
.z
+ quat
.x
* quat
.w
);
1012 ex_space
.z
= 2.0 * (quat
.y
* quat
.w
- quat
.x
* quat
.z
);
1014 ey_space
.x
= 2.0 * (quat
.y
* quat
.z
- quat
.x
* quat
.w
);
1015 ey_space
.y
= quat
.x
* quat
.x
- quat
.y
* quat
.y
+ quat
.z
* quat
.z
- quat
.w
* quat
.w
;
1016 ey_space
.z
= 2.0 * (quat
.z
* quat
.w
+ quat
.x
* quat
.y
);
1018 ez_space
.x
= 2.0 * (quat
.y
* quat
.w
+ quat
.x
* quat
.z
);
1019 ez_space
.y
= 2.0 * (quat
.z
* quat
.w
- quat
.x
* quat
.y
);
1020 ez_space
.z
= quat
.x
* quat
.x
- quat
.y
* quat
.y
- quat
.z
* quat
.z
+ quat
.w
* quat
.w
;
1024 \param body Body index to set angular momentum
1025 \param angmom Angular momentum
1027 void RigidData::setAngMom(unsigned int body
, Scalar3 angmom
)
1029 if (body
>= m_n_bodies
)
1031 m_exec_conf
->msg
->error() << "Error setting angular momentum for body " << body
<< "\n";
1035 ArrayHandle
<Scalar4
> h_angmom(m_angmom
, access_location::host
, access_mode::readwrite
);
1037 h_angmom
.data
[body
].x
= angmom
.x
;
1038 h_angmom
.data
[body
].y
= angmom
.y
;
1039 h_angmom
.data
[body
].z
= angmom
.z
;
1040 h_angmom
.data
[body
].w
= 0;
1043 ArrayHandle
<Scalar4
> h_angvel(m_angvel
, access_location::host
, access_mode::readwrite
);
1044 ArrayHandle
<Scalar4
> h_moment_inertia(m_moment_inertia
, access_location::host
, access_mode::read
);
1045 ArrayHandle
<Scalar4
> h_orientation(m_orientation
, access_location::host
, access_mode::read
);
1046 exyzFromQuaternion(h_orientation
.data
[body
], ex
, ey
, ez
);
1048 computeAngularVelocity(h_angmom
.data
[body
],
1049 h_moment_inertia
.data
[body
],
1053 h_angvel
.data
[body
]);
1056 /*! computeVirialCorrectionStart() must be called at the start of any time step update when there are rigid bodies
1057 present in the system and the virial needs to be computed. It only peforms part of the virial correction. The other
1058 part is completed by calling computeVirialCorrectionEnd()
1060 void RigidData::computeVirialCorrectionStart()
1063 if (m_pdata
->getExecConf()->isCUDAEnabled())
1064 computeVirialCorrectionStartGPU();
1067 computeVirialCorrectionStartCPU();
1071 /*! computeVirialCorrectionEnd() must be called at the end of any time step update when there are rigid bodies
1072 present in the system and the virial needs to be computed. And computeVirialCorrectionStart() must have been
1073 called at the beginning of the step.
1075 void RigidData::computeVirialCorrectionEnd(Scalar deltaT
)
1078 if (m_pdata
->getExecConf()->isCUDAEnabled())
1079 computeVirialCorrectionEndGPU(deltaT
);
1082 computeVirialCorrectionEndCPU(deltaT
);
1085 /*! Helper function that perform the first part necessary to compute the rigid body virial correction on the CPU.
1087 void RigidData::computeVirialCorrectionStartCPU()
1089 // get access to the particle data
1090 ArrayHandle
<Scalar4
> h_pos(m_pdata
->getPositions(), access_location::host
, access_mode::read
);
1091 ArrayHandle
<Scalar4
> h_vel(m_pdata
->getVelocities(), access_location::host
, access_mode::read
);
1092 ArrayHandle
<Scalar4
> h_oldpos(m_particle_oldpos
, access_location::host
, access_mode::overwrite
);
1093 ArrayHandle
<Scalar4
> h_oldvel(m_particle_oldvel
, access_location::host
, access_mode::overwrite
);
1095 // loop through the particles and save the current position and velocity of each one
1096 for (unsigned int i
= 0; i
< m_pdata
->getN(); i
++)
1098 h_oldpos
.data
[i
] = make_scalar4(h_pos
.data
[i
].x
, h_pos
.data
[i
].y
, h_pos
.data
[i
].z
, 0.0);
1099 h_oldvel
.data
[i
] = make_scalar4(h_vel
.data
[i
].y
, h_vel
.data
[i
].y
, h_vel
.data
[i
].z
, 0.0);
1103 /*! Helper function that perform the second part necessary to compute the rigid body virial correction on the CPU.
1105 void RigidData::computeVirialCorrectionEndCPU(Scalar deltaT
)
1107 // get access to the particle data
1108 ArrayHandle
<Scalar4
> h_vel(m_pdata
->getVelocities(), access_location::host
, access_mode::read
);
1109 ArrayHandle
<unsigned int> h_body(m_pdata
->getBodies(), access_location::host
, access_mode::read
);
1110 ArrayHandle
<Scalar4
> h_oldpos(m_particle_oldpos
, access_location::host
, access_mode::read
);
1111 ArrayHandle
<Scalar4
> h_oldvel(m_particle_oldvel
, access_location::host
, access_mode::read
);
1113 ArrayHandle
<Scalar
> h_net_virial( m_pdata
->getNetVirial(), access_location::host
, access_mode::readwrite
);
1114 unsigned int virial_pitch
= m_pdata
->getNetVirial().getPitch();
1115 ArrayHandle
<Scalar4
> h_net_force( m_pdata
->getNetForce(), access_location::host
, access_mode::read
);
1117 // loop through all the particles and compute the virial correction to each one
1118 for (unsigned int i
= 0; i
< m_pdata
->getN(); i
++)
1120 // only correct the virial for body particles
1121 if (h_body
.data
[i
] != NO_BODY
)
1123 // calculate the virial from the position and velocity from the previous step
1124 Scalar mass
= h_vel
.data
[i
].w
;
1125 Scalar4 old_vel
= h_oldvel
.data
[i
];
1126 Scalar4 old_pos
= h_oldpos
.data
[i
];
1128 fc
.x
= mass
* (h_vel
.data
[i
].x
- old_vel
.x
) / deltaT
- h_net_force
.data
[i
].x
;
1129 fc
.y
= mass
* (h_vel
.data
[i
].y
- old_vel
.y
) / deltaT
- h_net_force
.data
[i
].y
;
1130 fc
.z
= mass
* (h_vel
.data
[i
].z
- old_vel
.z
) / deltaT
- h_net_force
.data
[i
].z
;
1132 h_net_virial
.data
[0*virial_pitch
+i
] += old_pos
.x
* fc
.x
;
1133 h_net_virial
.data
[1*virial_pitch
+i
] += old_pos
.x
* fc
.y
;
1134 h_net_virial
.data
[2*virial_pitch
+i
] += old_pos
.x
* fc
.z
;
1135 h_net_virial
.data
[3*virial_pitch
+i
] += old_pos
.y
* fc
.y
;
1136 h_net_virial
.data
[4*virial_pitch
+i
] += old_pos
.y
* fc
.z
;
1137 h_net_virial
.data
[5*virial_pitch
+i
] += old_pos
.z
* fc
.z
;
1144 /*! Helper function that perform the first part necessary to compute the rigid body virial correction on the GPU.
1146 void RigidData::computeVirialCorrectionStartGPU()
1148 // get access to the particle data
1149 ArrayHandle
<Scalar4
> d_pos(m_pdata
->getPositions(), access_location::device
, access_mode::read
);
1150 ArrayHandle
<Scalar4
> d_vel(m_pdata
->getVelocities(), access_location::device
, access_mode::read
);
1151 ArrayHandle
<Scalar4
> d_oldpos(m_particle_oldpos
, access_location::device
, access_mode::overwrite
);
1152 ArrayHandle
<Scalar4
> d_oldvel(m_particle_oldvel
, access_location::device
, access_mode::overwrite
);
1154 // copy the existing position and velocity over to the oldpos arrays
1155 cudaMemcpy(d_oldpos
.data
, d_pos
.data
, sizeof(Scalar4
)*m_pdata
->getN(), cudaMemcpyDeviceToDevice
);
1156 cudaMemcpy(d_oldvel
.data
, d_vel
.data
, sizeof(Scalar4
)*m_pdata
->getN(), cudaMemcpyDeviceToDevice
);
1162 /*! Helper function that perform the second part necessary to compute the rigid body virial correction on the GPU.
1164 void RigidData::computeVirialCorrectionEndGPU(Scalar deltaT
)
1166 // get access to the particle data
1167 ArrayHandle
<Scalar4
> d_vel(m_pdata
->getVelocities(), access_location::device
, access_mode::read
);
1168 ArrayHandle
<unsigned int> d_body(m_pdata
->getBodies(), access_location::device
, access_mode::read
);
1169 ArrayHandle
<Scalar4
> d_oldpos(m_particle_oldpos
, access_location::device
, access_mode::read
);
1170 ArrayHandle
<Scalar4
> d_oldvel(m_particle_oldvel
, access_location::device
, access_mode::read
);
1172 ArrayHandle
<Scalar
> d_net_virial( m_pdata
->getNetVirial(), access_location::device
, access_mode::readwrite
);
1173 unsigned int virial_pitch
= m_pdata
->getNetVirial().getPitch();
1174 ArrayHandle
<Scalar4
> d_net_force( m_pdata
->getNetForce(), access_location::device
, access_mode::read
);
1176 gpu_compute_virial_correction_end(d_net_virial
.data
,
1191 /*! \param snapshot SnapshotRigidData to initialize from
1193 void RigidData::initializeFromSnapshot(const SnapshotRigidData
& snapshot
)
1195 // check that all fields in the snapshot have correct length
1196 if (m_exec_conf
->getRank() == 0 && !snapshot
.validate())
1198 m_exec_conf
->msg
->error() << "init.*: invalid rigid body snapshot."
1199 << std::endl
<< std::endl
;
1200 throw std::runtime_error("Error initializing rigid bodies.");
1203 ArrayHandle
<Scalar4
> h_com(getCOM(), access_location::host
, access_mode::overwrite
);
1204 ArrayHandle
<Scalar4
> h_vel(getVel(), access_location::host
, access_mode::overwrite
);
1205 ArrayHandle
<Scalar4
> h_angmom(getAngMom(), access_location::host
, access_mode::overwrite
);
1206 ArrayHandle
<int3
> h_body_image(getBodyImage(), access_location::host
, access_mode::overwrite
);
1208 // Error out if snapshot contains a different number of bodies
1209 if (getNumBodies() != snapshot
.size
)
1211 m_exec_conf
->msg
->error() << "Re-initialization of rigid bodies not supported." << std::endl
<< std::endl
;
1212 throw std::runtime_error("Error initializing RigidData.");
1215 // We don't need to restore force, torque and orientation because the setup will do the rest,
1216 // and simulation still resumes smoothly.
1217 // NOTE: this may not be true if re-initialized in the middle of the simulation
1218 unsigned int n_bodies
= snapshot
.size
;
1219 for (unsigned int body
= 0; body
< n_bodies
; body
++)
1221 h_com
.data
[body
] = make_scalar4(snapshot
.com
[body
].x
, snapshot
.com
[body
].y
, snapshot
.com
[body
].z
,0.0);
1222 h_vel
.data
[body
] = make_scalar4(snapshot
.vel
[body
].x
, snapshot
.vel
[body
].y
, snapshot
.vel
[body
].z
,0.0);
1223 h_angmom
.data
[body
] = make_scalar4(snapshot
.angmom
[body
].x
, snapshot
.angmom
[body
].y
, snapshot
.angmom
[body
].z
, 0.0);
1224 h_body_image
.data
[body
] = snapshot
.body_image
[body
];
1229 /*! \param snapshot The snapshot to fill with the rigid body data
1231 void RigidData::takeSnapshot(SnapshotRigidData
& snapshot
) const
1233 ArrayHandle
<Scalar4
> h_com(getCOM(), access_location::host
, access_mode::read
);
1234 ArrayHandle
<Scalar4
> h_vel(getVel(), access_location::host
, access_mode::read
);
1235 ArrayHandle
<Scalar4
> h_angmom(getAngMom(), access_location::host
, access_mode::read
);
1236 ArrayHandle
<int3
> h_body_image(getBodyImage(), access_location::host
, access_mode::read
);
1238 // allocate memory in snapshot
1239 unsigned int n_bodies
= getNumBodies();
1240 snapshot
.resize(n_bodies
);
1242 for (unsigned int i
= 0; i
< n_bodies
; ++i
)
1244 snapshot
.com
[i
] = make_scalar3(h_com
.data
[i
].x
,h_com
.data
[i
].y
,h_com
.data
[i
].z
);
1245 snapshot
.vel
[i
] = make_scalar3(h_vel
.data
[i
].x
,h_vel
.data
[i
].y
,h_vel
.data
[i
].z
);
1246 snapshot
.angmom
[i
] = make_scalar3(h_angmom
.data
[i
].x
,h_angmom
.data
[i
].y
,h_angmom
.data
[i
].z
);
1247 snapshot
.body_image
[i
] = h_body_image
.data
[i
];
1251 void SnapshotRigidData::replicate(unsigned int n
)
1253 unsigned int old_size
= size
;
1256 com
.resize(n
*old_size
);
1257 vel
.resize(n
*old_size
);
1258 angmom
.resize(n
*old_size
);
1259 body_image
.resize(n
*old_size
);
1261 for (unsigned int i
= 0; i
< old_size
; ++i
)
1263 for (unsigned int j
= 0; j
< n
; ++j
)
1265 unsigned int k
= j
*old_size
+ i
;
1268 angmom
[k
] = angmom
[i
];
1269 body_image
[k
] = body_image
[i
];
1274 void export_SnapshotRigidData()
1276 class_
<SnapshotRigidData
, boost::shared_ptr
<SnapshotRigidData
> >
1277 ("SnapshotRigidData", init
<>())
1278 .def_readwrite("size", &SnapshotRigidData::size
)
1279 .def_readwrite("com", &SnapshotRigidData::com
)
1280 .def_readwrite("vel", &SnapshotRigidData::vel
)
1281 .def_readwrite("angmom", &SnapshotRigidData::angmom
)
1282 .def_readwrite("body_image", &SnapshotRigidData::body_image
)
1286 void export_RigidData()
1288 class_
<RigidData
, boost::shared_ptr
<RigidData
>, boost::noncopyable
>("RigidData", init
< boost::shared_ptr
<ParticleData
> >())
1289 .def("initializeData", &RigidData::initializeData
)
1290 .def("getNumBodies", &RigidData::getNumBodies
)
1291 .def("getBodyCOM", &RigidData::getBodyCOM
)
1292 .def("setBodyCOM", &RigidData::setBodyCOM
)
1293 .def("getBodyVel", &RigidData::getBodyVel
)
1294 .def("setBodyVel", &RigidData::setBodyVel
)
1295 .def("getBodyOrientation", &RigidData::getBodyOrientation
)
1296 .def("setBodyOrientation", &RigidData::setBodyOrientation
)
1297 .def("getBodyNSize", &RigidData::getBodyNSize
)
1298 .def("getMass", &RigidData::getMass
)
1299 .def("setMass", &RigidData::setMass
)
1300 .def("getBodyAngMom", &RigidData::getBodyAngMom
)
1301 .def("setAngMom", &RigidData::setAngMom
)
1302 .def("getBodyMomInertia", &RigidData::getBodyMomInertia
)
1303 .def("setBodyMomInertia", &RigidData::setBodyMomInertia
)
1304 .def("getParticleTag", &RigidData::getParticleTag
)
1305 .def("getParticleDisp", &RigidData::getParticleDisp
)
1306 .def("setParticleDisp", &RigidData::setParticleDisp
)
1307 .def("getBodyNetForce", &RigidData::getBodyNetForce
)
1308 .def("getBodyNetTorque", &RigidData::getBodyNetTorque
)
1309 .def("setRV", &RigidData::setRV
)
1314 #pragma warning( pop )