48#include "math/ConvexHull.hpp"
60#include "math/qhull.hpp"
61#include "utils/simError.h"
67ConvexHull::ConvexHull() :
Hull(), options_(
"qhull FA Qt Pp QJ"), dim_(3) {}
69void ConvexHull::computeHull(vector<StuntDouble*> bodydoubles) {
70#ifdef HAVE_QHULL_REENTRANT
76 int numpoints = bodydoubles.size();
80 vertexT *vertex, **vertexp;
85 vector<double> ptArray(numpoints * dim_);
88 vector<StuntDouble*>::iterator SD;
91 for (SD = bodydoubles.begin(); SD != bodydoubles.end(); ++SD) {
92 Vector3d pos = (*SD)->getPos();
93 ptArray[dim_ * i] = pos.
x();
94 ptArray[dim_ * i + 1] = pos.
y();
95 ptArray[dim_ * i + 2] = pos.
z();
100 boolT ismalloc = False;
104#ifdef HAVE_QHULL_REENTRANT
105 qh_init_A(qh, NULL, NULL, stderr, 0, NULL);
106 int exitcode = setjmp(qh->errexit);
108 qh->NOerrexit = False;
109 qh_initflags(qh,
const_cast<char*
>(options_.c_str()));
110 qh_init_B(qh, &ptArray[0], numpoints, dim_, ismalloc);
113 exitcode = qh_ERRnone;
114 qh->NOerrexit = True;
116 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
117 "ConvexHull: Qhull failed to compute convex hull");
118 painCave.isFatal = 1;
122 qh_init_A(NULL, NULL, stderr, 0, NULL);
123 int exitcode = setjmp(qh errexit);
125 qh_initflags(
const_cast<char*
>(options_.c_str()));
126 qh_init_B(&ptArray[0], numpoints, dim_, ismalloc);
129 exitcode = qh_ERRnone;
132 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
133 "ConvexHull: Qhull failed to compute convex hull");
134 painCave.isFatal = 1;
145 MPI_Comm_size(MPI_COMM_WORLD, &nproc);
146 MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
148 int localHullSites = 0;
150 vector<int> hullSitesOnProc(nproc, 0);
151 vector<int> coordsOnProc(nproc, 0);
152 vector<int> displacements(nproc, 0);
153 vector<int> vectorDisplacements(nproc, 0);
155 vector<double> coords;
157 vector<int> indexMap;
158 vector<double> masses;
163#ifdef HAVE_QHULL_REENTRANT
164 int idx = qh_pointid(qh, vertex->point);
166 int idx = qh_pointid(vertex->point);
169 indexMap.push_back(idx);
171 coords.push_back(ptArray[dim_ * idx]);
172 coords.push_back(ptArray[dim_ * idx + 1]);
173 coords.push_back(ptArray[dim_ * idx + 2]);
175 StuntDouble* sd = bodydoubles[idx];
177 Vector3d vel = sd->
getVel();
178 vels.push_back(vel.
x());
179 vels.push_back(vel.
y());
180 vels.push_back(vel.
z());
182 masses.push_back(sd->
getMass());
185 MPI_Allgather(&localHullSites, 1, MPI_INT, &hullSitesOnProc[0], 1, MPI_INT,
188 int globalHullSites = 0;
189 for (
int iproc = 0; iproc < nproc; iproc++) {
190 globalHullSites += hullSitesOnProc[iproc];
191 coordsOnProc[iproc] = dim_ * hullSitesOnProc[iproc];
194 displacements[0] = 0;
195 vectorDisplacements[0] = 0;
197 for (
int iproc = 1; iproc < nproc; iproc++) {
198 displacements[iproc] =
199 displacements[iproc - 1] + hullSitesOnProc[iproc - 1];
200 vectorDisplacements[iproc] =
201 vectorDisplacements[iproc - 1] + coordsOnProc[iproc - 1];
204 vector<double> globalCoords(dim_ * globalHullSites);
205 vector<double> globalVels(dim_ * globalHullSites);
206 vector<double> globalMasses(globalHullSites);
208 int count = coordsOnProc[myrank];
210 MPI_Allgatherv(&coords[0], count, MPI_DOUBLE, &globalCoords[0],
211 &coordsOnProc[0], &vectorDisplacements[0], MPI_DOUBLE,
214 MPI_Allgatherv(&vels[0], count, MPI_DOUBLE, &globalVels[0], &coordsOnProc[0],
215 &vectorDisplacements[0], MPI_DOUBLE, MPI_COMM_WORLD);
217 MPI_Allgatherv(&masses[0], localHullSites, MPI_DOUBLE, &globalMasses[0],
218 &hullSitesOnProc[0], &displacements[0], MPI_DOUBLE,
222#ifdef HAVE_QHULL_REENTRANT
223 qh_freeqhull(qh, !qh_ALL);
224 qh_memfreeshort(qh, &curlong, &totlong);
226 qh_freeqhull(!qh_ALL);
227 qh_memfreeshort(&curlong, &totlong);
229 if (curlong || totlong) {
230 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
231 "ConvexHull: qhull internal warning:\n"
232 "\tdid not free %d bytes of long memory (%d pieces)",
234 painCave.isFatal = 1;
238#ifdef HAVE_QHULL_REENTRANT
239 qh_init_A(qh, NULL, NULL, stderr, 0, NULL);
240 exitcode = setjmp(qh->errexit);
242 qh->NOerrexit = False;
243 qh_initflags(qh,
const_cast<char*
>(options_.c_str()));
244 qh_init_B(qh, &globalCoords[0], globalHullSites, dim_, ismalloc);
247 exitcode = qh_ERRnone;
248 qh->NOerrexit = True;
250 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
251 "ConvexHull: Qhull failed to compute convex hull");
252 painCave.isFatal = 1;
256 qh_init_A(NULL, NULL, stderr, 0, NULL);
257 exitcode = setjmp(qh errexit);
259 qh NOerrexit = False;
260 qh_initflags(
const_cast<char*
>(options_.c_str()));
261 qh_init_B(&globalCoords[0], globalHullSites, dim_, ismalloc);
264 exitcode = qh_ERRnone;
267 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
268 "ConvexHull: Qhull failed to compute global convex hull");
269 painCave.isFatal = 1;
280#ifdef HAVE_QHULL_REENTRANT
289 Vector3d V3dNormal(facet->normal[0], facet->normal[1], facet->normal[2]);
290 face.setUnitNormal(V3dNormal);
292#ifdef HAVE_QHULL_REENTRANT
293 RealType faceArea = qh_facetarea(qh, facet);
294 face.setArea(faceArea);
295 vertices = qh_facet3vertex(qh, facet);
296 coordT* center = qh_getcenter(qh, vertices);
298 RealType faceArea = qh_facetarea(facet);
299 face.setArea(faceArea);
300 vertices = qh_facet3vertex(facet);
301 coordT* center = qh_getcenter(vertices);
303 Vector3d V3dCentroid(center[0], center[1], center[2]);
304 face.setCentroid(V3dCentroid);
306 Vector3d faceVel = V3Zero;
308 RealType faceMass = 0.0;
312 FOREACHvertex_(vertices) {
313#ifdef HAVE_QHULL_REENTRANT
314 int id = qh_pointid(qh, vertex->point);
316 int id = qh_pointid(vertex->point);
318 p[ver][0] = vertex->point[0];
319 p[ver][1] = vertex->point[1];
320 p[ver][2] = vertex->point[2];
325 vel = Vector3d(globalVels[dim_ *
id], globalVels[dim_ *
id + 1],
326 globalVels[dim_ *
id + 2]);
327 mass = globalMasses[id];
332 int localID =
id - displacements[myrank];
334 if (localID >= 0 && localID < hullSitesOnProc[myrank]) {
335 face.addVertexSD(bodydoubles[indexMap[localID]]);
337 face.addVertexSD(NULL);
340 vel = bodydoubles[id]->getVel();
341 mass = bodydoubles[id]->getMass();
342 face.addVertexSD(bodydoubles[
id]);
344 faceVel = faceVel + vel;
345 faceMass = faceMass + mass;
349 face.addVertices(p[0], p[1], p[2]);
350 face.setFacetMass(faceMass);
351 face.setFacetVelocity(faceVel / RealType(3.0));
363 Triangles_.push_back(face);
364#ifdef HAVE_QHULL_REENTRANT
365 qh_settempfree(qh, &vertices);
367 qh_settempfree(&vertices);
371#ifdef HAVE_QHULL_REENTRANT
372 qh_getarea(qh, qh->facet_list);
373 volume_ = qh->totvol;
375 qh_freeqhull(qh, !qh_ALL);
376 qh_memfreeshort(qh, &curlong, &totlong);
379 qh_getarea(qh facet_list);
383 qh_freeqhull(!qh_ALL);
384 qh_memfreeshort(&curlong, &totlong);
386 if (curlong || totlong) {
387 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
388 "ConvexHull: qhull internal warning:\n"
389 "\tdid not free %d bytes of long memory (%d pieces)",
391 painCave.isFatal = 1;
Vector3d getVel()
Returns the current velocity of this stuntDouble.
RealType getMass()
Returns the mass of this stuntDouble.
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.