45#include "math/ConvexHull.hpp"
57#include "math/qhull.hpp"
58#include "utils/simError.h"
64ConvexHull::ConvexHull() :
Hull(), options_(
"qhull FA Qt Pp QJ"), dim_(3) {}
66void ConvexHull::computeHull(vector<StuntDouble*> bodydoubles) {
67#ifdef HAVE_QHULL_REENTRANT
73 int numpoints = bodydoubles.size();
77 vertexT *vertex, **vertexp;
82 vector<double> ptArray(numpoints * dim_);
85 vector<StuntDouble*>::iterator SD;
88 for (SD = bodydoubles.begin(); SD != bodydoubles.end(); ++SD) {
90 ptArray[dim_ * i] = pos.
x();
91 ptArray[dim_ * i + 1] = pos.
y();
92 ptArray[dim_ * i + 2] = pos.
z();
97 boolT ismalloc = False;
101#ifdef HAVE_QHULL_REENTRANT
102 qh_init_A(qh, NULL, NULL, stderr, 0, NULL);
103 int exitcode = setjmp(qh->errexit);
105 qh->NOerrexit = False;
106 qh_initflags(qh,
const_cast<char*
>(options_.c_str()));
107 qh_init_B(qh, &ptArray[0], numpoints, dim_, ismalloc);
110 exitcode = qh_ERRnone;
111 qh->NOerrexit = True;
113 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
114 "ConvexHull: Qhull failed to compute convex hull");
115 painCave.isFatal = 1;
119 qh_init_A(NULL, NULL, stderr, 0, NULL);
120 int exitcode = setjmp(qh errexit);
122 qh_initflags(
const_cast<char*
>(options_.c_str()));
123 qh_init_B(&ptArray[0], numpoints, dim_, ismalloc);
126 exitcode = qh_ERRnone;
129 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
130 "ConvexHull: Qhull failed to compute convex hull");
131 painCave.isFatal = 1;
142 MPI_Comm_size(MPI_COMM_WORLD, &nproc);
143 MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
145 int localHullSites = 0;
147 vector<int> hullSitesOnProc(nproc, 0);
148 vector<int> coordsOnProc(nproc, 0);
149 vector<int> displacements(nproc, 0);
150 vector<int> vectorDisplacements(nproc, 0);
152 vector<double> coords;
154 vector<int> indexMap;
155 vector<double> masses;
160#ifdef HAVE_QHULL_REENTRANT
161 int idx = qh_pointid(qh, vertex->point);
163 int idx = qh_pointid(vertex->point);
166 indexMap.push_back(idx);
168 coords.push_back(ptArray[dim_ * idx]);
169 coords.push_back(ptArray[dim_ * idx + 1]);
170 coords.push_back(ptArray[dim_ * idx + 2]);
175 vels.push_back(vel.
x());
176 vels.push_back(vel.
y());
177 vels.push_back(vel.
z());
179 masses.push_back(sd->
getMass());
182 MPI_Allgather(&localHullSites, 1, MPI_INT, &hullSitesOnProc[0], 1, MPI_INT,
185 int globalHullSites = 0;
186 for (
int iproc = 0; iproc < nproc; iproc++) {
187 globalHullSites += hullSitesOnProc[iproc];
188 coordsOnProc[iproc] = dim_ * hullSitesOnProc[iproc];
191 displacements[0] = 0;
192 vectorDisplacements[0] = 0;
194 for (
int iproc = 1; iproc < nproc; iproc++) {
195 displacements[iproc] =
196 displacements[iproc - 1] + hullSitesOnProc[iproc - 1];
197 vectorDisplacements[iproc] =
198 vectorDisplacements[iproc - 1] + coordsOnProc[iproc - 1];
201 vector<double> globalCoords(dim_ * globalHullSites);
202 vector<double> globalVels(dim_ * globalHullSites);
203 vector<double> globalMasses(globalHullSites);
205 int count = coordsOnProc[myrank];
207 MPI_Allgatherv(&coords[0], count, MPI_DOUBLE, &globalCoords[0],
208 &coordsOnProc[0], &vectorDisplacements[0], MPI_DOUBLE,
211 MPI_Allgatherv(&vels[0], count, MPI_DOUBLE, &globalVels[0], &coordsOnProc[0],
212 &vectorDisplacements[0], MPI_DOUBLE, MPI_COMM_WORLD);
214 MPI_Allgatherv(&masses[0], localHullSites, MPI_DOUBLE, &globalMasses[0],
215 &hullSitesOnProc[0], &displacements[0], MPI_DOUBLE,
219#ifdef HAVE_QHULL_REENTRANT
220 qh_freeqhull(qh, !qh_ALL);
221 qh_memfreeshort(qh, &curlong, &totlong);
223 qh_freeqhull(!qh_ALL);
224 qh_memfreeshort(&curlong, &totlong);
226 if (curlong || totlong) {
227 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
228 "ConvexHull: qhull internal warning:\n"
229 "\tdid not free %d bytes of long memory (%d pieces)",
231 painCave.isFatal = 1;
235#ifdef HAVE_QHULL_REENTRANT
236 qh_init_A(qh, NULL, NULL, stderr, 0, NULL);
237 exitcode = setjmp(qh->errexit);
239 qh->NOerrexit = False;
240 qh_initflags(qh,
const_cast<char*
>(options_.c_str()));
241 qh_init_B(qh, &globalCoords[0], globalHullSites, dim_, ismalloc);
244 exitcode = qh_ERRnone;
245 qh->NOerrexit = True;
247 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
248 "ConvexHull: Qhull failed to compute convex hull");
249 painCave.isFatal = 1;
253 qh_init_A(NULL, NULL, stderr, 0, NULL);
254 exitcode = setjmp(qh errexit);
256 qh NOerrexit = False;
257 qh_initflags(
const_cast<char*
>(options_.c_str()));
258 qh_init_B(&globalCoords[0], globalHullSites, dim_, ismalloc);
261 exitcode = qh_ERRnone;
264 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
265 "ConvexHull: Qhull failed to compute global convex hull");
266 painCave.isFatal = 1;
277#ifdef HAVE_QHULL_REENTRANT
286 Vector3d V3dNormal(facet->normal[0], facet->normal[1], facet->normal[2]);
287 face.setUnitNormal(V3dNormal);
289#ifdef HAVE_QHULL_REENTRANT
290 RealType faceArea = qh_facetarea(qh, facet);
291 face.setArea(faceArea);
292 vertices = qh_facet3vertex(qh, facet);
293 coordT* center = qh_getcenter(qh, vertices);
295 RealType faceArea = qh_facetarea(facet);
296 face.setArea(faceArea);
297 vertices = qh_facet3vertex(facet);
298 coordT* center = qh_getcenter(vertices);
300 Vector3d V3dCentroid(center[0], center[1], center[2]);
301 face.setCentroid(V3dCentroid);
305 RealType faceMass = 0.0;
309 FOREACHvertex_(vertices) {
310#ifdef HAVE_QHULL_REENTRANT
311 int id = qh_pointid(qh, vertex->point);
313 int id = qh_pointid(vertex->point);
315 p[ver][0] = vertex->point[0];
316 p[ver][1] = vertex->point[1];
317 p[ver][2] = vertex->point[2];
322 vel =
Vector3d(globalVels[dim_ *
id], globalVels[dim_ *
id + 1],
323 globalVels[dim_ *
id + 2]);
324 mass = globalMasses[id];
329 int localID =
id - displacements[myrank];
331 if (localID >= 0 && localID < hullSitesOnProc[myrank]) {
332 face.addVertexSD(bodydoubles[indexMap[localID]]);
334 face.addVertexSD(NULL);
337 vel = bodydoubles[id]->getVel();
338 mass = bodydoubles[id]->getMass();
339 face.addVertexSD(bodydoubles[
id]);
341 faceVel = faceVel + vel;
342 faceMass = faceMass + mass;
346 face.addVertices(p[0], p[1], p[2]);
347 face.setFacetMass(faceMass);
348 face.setFacetVelocity(faceVel / RealType(3.0));
360 Triangles_.push_back(face);
361#ifdef HAVE_QHULL_REENTRANT
362 qh_settempfree(qh, &vertices);
364 qh_settempfree(&vertices);
368#ifdef HAVE_QHULL_REENTRANT
369 qh_getarea(qh, qh->facet_list);
370 volume_ = qh->totvol;
372 qh_freeqhull(qh, !qh_ALL);
373 qh_memfreeshort(qh, &curlong, &totlong);
376 qh_getarea(qh facet_list);
380 qh_freeqhull(!qh_ALL);
381 qh_memfreeshort(&curlong, &totlong);
383 if (curlong || totlong) {
384 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
385 "ConvexHull: qhull internal warning:\n"
386 "\tdid not free %d bytes of long memory (%d pieces)",
388 painCave.isFatal = 1;
"Don't move, or you're dead! Stand up! Captain, we've got them!"
Vector3d getVel()
Returns the current velocity of this stuntDouble.
RealType getMass()
Returns the mass of this stuntDouble.
Triangle provides geometric data to OpenMD.
Real & z()
Returns reference of the third element of Vector3.
Real & x()
Returns reference of the first element of Vector3.
Real & y()
Returns reference of the second element of Vector3.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.