2 Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
3 (HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
4 the University of Michigan All rights reserved.
6 HOOMD-blue may contain modifications ("Contributions") provided, and to which
7 copyright is held, by various Contributors who have granted The Regents of the
8 University of Michigan the right to modify and/or distribute such Contributions.
10 You may redistribute, use, and create derivate works of HOOMD-blue, in source
11 and binary forms, provided you abide by the following conditions:
13 * Redistributions of source code must retain the above copyright notice, this
14 list of conditions, and the following disclaimer both in the code and
15 prominently in any materials provided with the distribution.
17 * Redistributions in binary form must reproduce the above copyright notice, this
18 list of conditions, and the following disclaimer in the documentation and/or
19 other materials provided with the distribution.
21 * All publications and presentations based on HOOMD-blue, including any reports
22 or published results obtained, in whole or in part, with HOOMD-blue, will
23 acknowledge its use according to the terms posted at the time of submission on:
24 http://codeblue.umich.edu/hoomd-blue/citations.html
26 * Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
27 http://codeblue.umich.edu/hoomd-blue/
29 * Apart from the above required attributions, neither the name of the copyright
30 holder nor the names of HOOMD-blue's contributors may be used to endorse or
31 promote products derived from this software without specific prior written
36 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
37 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
39 WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.
41 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
43 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
46 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 // Maintainer: joaander, grva, baschult
52 /*! \file ForceCompute.cc
53 \brief Defines the ForceCompute class
57 #pragma warning( push )
58 #pragma warning( disable : 4244 )
61 #include "ForceCompute.h"
65 #include <boost/python.hpp>
66 using namespace boost::python
;
68 #include <boost/shared_ptr.hpp>
69 #include <boost/bind.hpp>
70 using namespace boost
;
73 #include "Communicator.h"
76 /*! \param sysdef System to compute forces on
77 \post The Compute is initialized and all memory needed for the forces is allocated
78 \post \c force and \c virial GPUarrays are initialized
79 \post All forces are initialized to 0
81 ForceCompute::ForceCompute(boost::shared_ptr
<SystemDefinition
> sysdef
) : Compute(sysdef
), m_particles_sorted(false)
84 assert(m_pdata
->getMaxN() > 0);
86 // allocate data on the host
87 unsigned int max_num_particles
= m_pdata
->getMaxN();
88 GPUArray
<Scalar4
> force(max_num_particles
,exec_conf
);
89 GPUArray
<Scalar
> virial(max_num_particles
,6,exec_conf
);
90 GPUArray
<Scalar4
> torque(max_num_particles
,exec_conf
);
92 m_virial
.swap(virial
);
93 m_torque
.swap(torque
);
95 m_virial_pitch
= m_virial
.getPitch();
97 // connect to the ParticleData to recieve notifications when particles change order in memory
98 m_sort_connection
= m_pdata
->connectParticleSort(bind(&ForceCompute::setParticlesSorted
, this));
100 // connect to the ParticleData to receive notifications when the maximum number of particles changes
101 m_max_particle_num_change_connection
= m_pdata
->connectMaxParticleNumberChange(bind(&ForceCompute::reallocate
, this));
103 // reset external virial
104 for (unsigned int i
= 0; i
< 6; ++i
)
105 m_external_virial
[i
] = Scalar(0.0);
109 /*! \post m_force, m_virial and m_torque are resized to the current maximum particle number
111 void ForceCompute::reallocate()
113 m_force
.resize(m_pdata
->getMaxN());
114 m_virial
.resize(m_pdata
->getMaxN(),6);
115 m_torque
.resize(m_pdata
->getMaxN());
117 // the pitch of the virial array may have changed
118 m_virial_pitch
= m_virial
.getPitch();
121 /*! Frees allocated memory
123 ForceCompute::~ForceCompute()
125 m_sort_connection
.disconnect();
126 m_max_particle_num_change_connection
.disconnect();
129 /*! Sums the total potential energy calculated by the last call to compute() and returns it.
131 Scalar
ForceCompute::calcEnergySum()
133 ArrayHandle
<Scalar4
> h_force(m_force
,access_location::host
,access_mode::read
);
134 // always perform the sum in double precision for better accuracy
135 // this is cheating and is really just a temporary hack to get logging up and running
136 // the potential accuracy loss in simulations needs to be evaluated here and a proper
137 // summation algorithm put in place
138 double pe_total
= 0.0;
139 for (unsigned int i
=0; i
< m_pdata
->getN(); i
++)
141 pe_total
+= (double)h_force
.data
[i
].w
;
146 // reduce potential energy on all processors
147 MPI_Allreduce(MPI_IN_PLACE
, &pe_total
, 1, MPI_DOUBLE
, MPI_SUM
, m_exec_conf
->getMPICommunicator());
150 return Scalar(pe_total
);
153 /*! Performs the force computation.
154 \param timestep Current Timestep
155 \note If compute() has previously been called with a value of timestep equal to
156 the current value, the forces are assumed to already have been computed and nothing will
160 void ForceCompute::compute(unsigned int timestep
)
162 // skip if we shouldn't compute this step
163 if (!m_particles_sorted
&& !shouldCompute(timestep
))
166 computeForces(timestep
);
167 m_particles_sorted
= false;
170 /*! \param num_iters Number of iterations to average for the benchmark
171 \returns Milliseconds of execution time per calculation
173 Calls computeForces repeatedly to benchmark the force compute.
176 double ForceCompute::benchmark(unsigned int num_iters
)
183 if (exec_conf
->isCUDAEnabled())
185 cudaThreadSynchronize();
191 uint64_t start_time
= t
.getTime();
192 for (unsigned int i
= 0; i
< num_iters
; i
++)
196 if (exec_conf
->isCUDAEnabled())
197 cudaThreadSynchronize();
199 uint64_t total_time_ns
= t
.getTime() - start_time
;
201 // convert the run time to milliseconds
202 return double(total_time_ns
) / 1e6
/ double(num_iters
);
205 /*! \param tag Global particle tag
206 \returns Torque of particle referenced by tag
208 Scalar4
ForceCompute::getTorque(unsigned int tag
)
210 unsigned int i
= m_pdata
->getRTag(tag
);
211 bool found
= (i
< m_pdata
->getN());
212 Scalar4 result
= make_scalar4(0.0,0.0,0.0,0.0);
215 ArrayHandle
<Scalar4
> h_torque(m_torque
, access_location::host
, access_mode::read
);
216 result
= h_torque
.data
[i
];
219 if (m_pdata
->getDomainDecomposition())
221 unsigned int owner_rank
= m_pdata
->getOwnerRank(tag
);
222 MPI_Bcast(&result
, sizeof(Scalar4
), MPI_BYTE
, owner_rank
, m_exec_conf
->getMPICommunicator());
228 /*! \param tag Global particle tag
229 \returns Force of particle referenced by tag
231 Scalar3
ForceCompute::getForce(unsigned int tag
)
233 unsigned int i
= m_pdata
->getRTag(tag
);
234 bool found
= (i
< m_pdata
->getN());
235 Scalar3 result
= make_scalar3(0.0,0.0,0.0);
238 ArrayHandle
<Scalar4
> h_force(m_force
, access_location::host
, access_mode::read
);
239 result
= make_scalar3(h_force
.data
[i
].x
, h_force
.data
[i
].y
, h_force
.data
[i
].z
);
242 if (m_pdata
->getDomainDecomposition())
244 unsigned int owner_rank
= m_pdata
->getOwnerRank(tag
);
245 MPI_Bcast(&result
, sizeof(Scalar3
), MPI_BYTE
, owner_rank
, m_exec_conf
->getMPICommunicator());
251 /*! \param tag Global particle tag
252 \param component Virial component (0=xx, 1=xy, 2=xz, 3=yy, 4=yz, 5=zz)
253 \returns Force of particle referenced by tag
255 Scalar
ForceCompute::getVirial(unsigned int tag
, unsigned int component
)
257 unsigned int i
= m_pdata
->getRTag(tag
);
258 bool found
= (i
< m_pdata
->getN());
259 Scalar result
= Scalar(0.0);
262 ArrayHandle
<Scalar
> h_virial(m_virial
, access_location::host
, access_mode::read
);
263 result
= h_virial
.data
[m_virial_pitch
*component
+i
];
266 if (m_pdata
->getDomainDecomposition())
268 unsigned int owner_rank
= m_pdata
->getOwnerRank(tag
);
269 MPI_Bcast(&result
, sizeof(Scalar
), MPI_BYTE
, owner_rank
, m_exec_conf
->getMPICommunicator());
275 /*! \param tag Global particle tag
276 \returns Energy of particle referenced by tag
278 Scalar
ForceCompute::getEnergy(unsigned int tag
)
280 unsigned int i
= m_pdata
->getRTag(tag
);
281 bool found
= (i
< m_pdata
->getN());
282 Scalar result
= Scalar(0.0);
285 ArrayHandle
<Scalar4
> h_force(m_force
, access_location::host
, access_mode::read
);
286 result
= h_force
.data
[i
].w
;
289 if (m_pdata
->getDomainDecomposition())
291 unsigned int owner_rank
= m_pdata
->getOwnerRank(tag
);
292 MPI_Bcast(&result
, sizeof(Scalar
), MPI_BYTE
, owner_rank
, m_exec_conf
->getMPICommunicator());
298 //! Wrapper class for wrapping pure virtual methodos of ForceCompute in python
299 class ForceComputeWrap
: public ForceCompute
, public wrapper
<ForceCompute
>
303 /*! \param sysdef Particle data passed to the base class */
304 ForceComputeWrap(boost::shared_ptr
<SystemDefinition
> sysdef
) : ForceCompute(sysdef
) { }
306 //! Calls the overidden ForceCompute::computeForces()
307 /*! \param timestep parameter to pass on to the overidden method
309 void computeForces(unsigned int timestep
)
311 this->get_override("computeForces")(timestep
);
315 void export_ForceCompute()
317 class_
< ForceComputeWrap
, boost::shared_ptr
<ForceComputeWrap
>, bases
<Compute
>, boost::noncopyable
>
318 ("ForceCompute", init
< boost::shared_ptr
<SystemDefinition
> >())
319 .def("getForce", &ForceCompute::getForce
)
320 .def("getTorque", &ForceCompute::getTorque
)
321 .def("getVirial", &ForceCompute::getVirial
)
322 .def("getEnergy", &ForceCompute::getEnergy
)
327 #pragma warning( pop )