48#include "math/AlphaHull.hpp"
60#include "math/qhull.hpp"
61#include "utils/simError.h"
67double calculate_circumradius(pointT* p0, pointT* p1, pointT* p2,
int dim);
69AlphaHull::AlphaHull(
double alpha) :
70 Hull(), dim_(4), alpha_(alpha), options_(
"qhull d QJ Tcv Pp") {}
72void AlphaHull::computeHull(vector<StuntDouble*> bodydoubles) {
73#ifdef HAVE_QHULL_REENTRANT
79 int numpoints = bodydoubles.size();
84 facetT *facet, *neighbor;
85 pointT* interiorPoint;
88 vector<double> ptArray(numpoints * dim_);
91 vector<StuntDouble*>::iterator SD;
94 for (SD = bodydoubles.begin(); SD != bodydoubles.end(); ++SD) {
95 Vector3d pos = (*SD)->getPos();
96 ptArray[dim_ * i] = pos.
x();
97 ptArray[dim_ * i + 1] = pos.
y();
98 ptArray[dim_ * i + 2] = pos.
z();
103 boolT ismalloc = False;
107#ifdef HAVE_QHULL_REENTRANT
108 qh_init_A(qh, NULL, NULL, stderr, 0, NULL);
109 int exitcode = setjmp(qh->errexit);
111 qh->NOerrexit = False;
112 qh_initflags(qh,
const_cast<char*
>(options_.c_str()));
113 qh_init_B(qh, &ptArray[0], numpoints, dim_, ismalloc);
116 exitcode = qh_ERRnone;
117 qh->NOerrexit = True;
119 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
120 "AlphaHull: Qhull failed to compute convex hull");
121 painCave.isFatal = 1;
125 qh_init_A(NULL, NULL, stderr, 0, NULL);
126 int exitcode = setjmp(qh errexit);
128 qh_initflags(
const_cast<char*
>(options_.c_str()));
129 qh_init_B(&ptArray[0], numpoints, dim_, ismalloc);
132 exitcode = qh_ERRnone;
135 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
136 "AlphaHull: Qhull failed to compute convex hull");
137 painCave.isFatal = 1;
147 MPI_Comm_size(MPI_COMM_WORLD, &nproc);
148 MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
150 int localHullSites = 0;
152 vector<int> hullSitesOnProc(nproc, 0);
153 vector<int> coordsOnProc(nproc, 0);
154 vector<int> displacements(nproc, 0);
155 vector<int> vectorDisplacements(nproc, 0);
157 vector<double> coords;
159 vector<int> indexMap;
160 vector<double> masses;
165#ifdef HAVE_QHULL_REENTRANT
166 int idx = qh_pointid(qh, vertex->point);
168 int idx = qh_pointid(vertex->point);
171 indexMap.push_back(idx);
173 coords.push_back(ptArray[dim_ * idx]);
174 coords.push_back(ptArray[dim_ * idx + 1]);
175 coords.push_back(ptArray[dim_ * idx + 2]);
176 coords.push_back(ptArray[dim_ * idx + 3]);
178 StuntDouble* sd = bodydoubles[idx];
180 Vector3d vel = sd->
getVel();
181 vels.push_back(vel.
x());
182 vels.push_back(vel.
y());
183 vels.push_back(vel.
z());
186 masses.push_back(sd->
getMass());
189 MPI_Allgather(&localHullSites, 1, MPI_INT, &hullSitesOnProc[0], 1, MPI_INT,
192 int globalHullSites = 0;
193 for (
int iproc = 0; iproc < nproc; iproc++) {
194 globalHullSites += hullSitesOnProc[iproc];
195 coordsOnProc[iproc] = dim_ * hullSitesOnProc[iproc];
198 displacements[0] = 0;
199 vectorDisplacements[0] = 0;
201 for (
int iproc = 1; iproc < nproc; iproc++) {
202 displacements[iproc] =
203 displacements[iproc - 1] + hullSitesOnProc[iproc - 1];
204 vectorDisplacements[iproc] =
205 vectorDisplacements[iproc - 1] + coordsOnProc[iproc - 1];
208 vector<double> globalCoords(dim_ * globalHullSites);
209 vector<double> globalVels(dim_ * globalHullSites);
210 vector<double> globalMasses(globalHullSites);
212 int count = coordsOnProc[myrank];
214 MPI_Allgatherv(&coords[0], count, MPI_DOUBLE, &globalCoords[0],
215 &coordsOnProc[0], &vectorDisplacements[0], MPI_DOUBLE,
218 MPI_Allgatherv(&vels[0], count, MPI_DOUBLE, &globalVels[0], &coordsOnProc[0],
219 &vectorDisplacements[0], MPI_DOUBLE, MPI_COMM_WORLD);
221 MPI_Allgatherv(&masses[0], localHullSites, MPI_DOUBLE, &globalMasses[0],
222 &hullSitesOnProc[0], &displacements[0], MPI_DOUBLE,
226#ifdef HAVE_QHULL_REENTRANT
227 qh_freeqhull(qh, !qh_ALL);
228 qh_memfreeshort(qh, &curlong, &totlong);
230 qh_freeqhull(!qh_ALL);
231 qh_memfreeshort(&curlong, &totlong);
233 if (curlong || totlong) {
234 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
235 "AlphaHull: qhull internal warning:\n"
236 "\tdid not free %d bytes of long memory (%d pieces)",
238 painCave.isFatal = 1;
242#ifdef HAVE_QHULL_REENTRANT
243 qh_init_A(qh, NULL, NULL, stderr, 0, NULL);
244 exitcode = setjmp(qh->errexit);
246 qh->NOerrexit = False;
247 qh_initflags(qh,
const_cast<char*
>(options_.c_str()));
248 qh_init_B(qh, &globalCoords[0], globalHullSites, dim_, ismalloc);
251 exitcode = qh_ERRnone;
252 qh->NOerrexit = True;
254 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
255 "AlphaHull: Qhull failed to compute convex hull");
256 painCave.isFatal = 1;
260 qh_init_A(NULL, NULL, stderr, 0, NULL);
261 exitcode = setjmp(qh errexit);
263 qh NOerrexit = False;
264 qh_initflags(
const_cast<char*
>(options_.c_str()));
265 qh_init_B(&globalCoords[0], globalHullSites, dim_, ismalloc);
268 exitcode = qh_ERRnone;
271 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
272 "AlphaHull: Qhull failed to compute convex hull");
273 painCave.isFatal = 1;
281#ifdef HAVE_QHULL_REENTRANT
282 qh_setvoronoi_all(qh);
288 vector<vector<int>> facetlist;
291#ifdef HAVE_QHULL_REENTRANT
292 setT* set = qh_settemp(qh, 4 * qh->num_facets);
294 interiorPoint = qh->interior_point;
296 setT* set = qh_settemp(4 * qh num_facets);
298 interiorPoint = qh interior_point;
301#ifdef HAVE_QHULL_REENTRANT
302 FORALLfacet_(qh->facet_list) {
304 FORALLfacet_(qh facet_list) {
307 if (!facet->upperdelaunay) {
311 vertexT* vertex = (vertexT*)(facet->vertices->e[0].p);
313#ifdef HAVE_QHULL_REENTRANT
314 double* center = qh_facetcenter(qh, facet->vertices);
316 double* center = qh_facetcenter(facet->vertices);
318 double radius = qh_pointdist(center, vertex->point, dim_ - 1);
321 if (radius > alpha_) {
328#ifdef HAVE_QHULL_REENTRANT
329 facet->visitid = qh->visit_id;
330 qh_makeridges(qh, facet);
332 facet->visitid = qh visit_id;
333 qh_makeridges(facet);
335 ridgeT *ridge, **ridgep;
336 int goodTriangles = 0;
337 FOREACHridge_(facet->ridges) {
338 neighbor = otherfacet_(ridge, facet);
339#ifdef HAVE_QHULL_REENTRANT
340 if ((neighbor->visitid != qh->visit_id)) {
342 if ((neighbor->visitid != qh visit_id)) {
345 pointT* p0 = ((vertexT*)(ridge->vertices->e[0].p))->point;
346 pointT* p1 = ((vertexT*)(ridge->vertices->e[1].p))->point;
347 pointT* p2 = ((vertexT*)(ridge->vertices->e[2].p))->point;
349 radius = calculate_circumradius(p0, p1, p2, dim_ - 1);
351 if (radius <= alpha_) {
354#ifdef HAVE_QHULL_REENTRANT
355 qh_setappend(qh, &set, ridge);
357 qh_setappend(&set, ridge);
366 if (goodTriangles == 4) facet->good =
true;
372#ifdef HAVE_QHULL_REENTRANT
373 facet->visitid = qh->visit_id;
375 facet->visitid = qh visit_id;
380#ifdef HAVE_QHULL_REENTRANT
381 qh_makeridges(qh, facet);
383 qh_makeridges(facet);
385 ridgeT *ridge, **ridgep;
386 FOREACHridge_(facet->ridges) {
387 neighbor = otherfacet_(ridge, facet);
388#ifdef HAVE_QHULL_REENTRANT
389 if ((neighbor->visitid != qh->visit_id)) {
390 qh_setappend(qh, &set, ridge);
393 if ((neighbor->visitid != qh visit_id)) { qh_setappend(&set, ridge); }
402 ridgeT *ridge, **ridgep;
404 if ((!ridge->top->good || !ridge->bottom->good ||
405 ridge->top->upperdelaunay || ridge->bottom->upperdelaunay)) {
407 int vertex_n, vertex_i;
410 Vector3d faceVel = V3Zero;
412 RealType faceMass = 0.0;
415 vector<int> vertexlist;
417#ifdef HAVE_QHULL_REENTRANT
418 FOREACHvertex_i_(qh, ridge->vertices) {
420 FOREACHvertex_i_(ridge->vertices) {
422#ifdef HAVE_QHULL_REENTRANT
423 int id = qh_pointid(qh, vertex->point);
425 int id = qh_pointid(vertex->point);
427 p[ver][0] = vertex->point[0];
428 p[ver][1] = vertex->point[1];
429 p[ver][2] = vertex->point[2];
433 vertexlist.push_back(
id);
435 vel = bodydoubles[id]->getVel();
436 mass = bodydoubles[id]->getMass();
437 face.addVertexSD(bodydoubles[
id]);
439 faceVel = faceVel + vel;
440 faceMass = faceMass + mass;
442 facetlist.push_back(vertexlist);
443 face.addVertices(p[0], p[1], p[2]);
444 face.setFacetMass(faceMass);
445 face.setFacetVelocity(faceVel / RealType(3.0));
447 RealType area = face.getArea();
449 Vector3d normal = face.getUnitNormal();
450 RealType dist = normal[0] * interiorPoint[0] +
451 normal[1] * interiorPoint[1] +
452 normal[2] * interiorPoint[2];
453#ifdef HAVE_QHULL_REENTRANT
454 volume_ += dist * area / qh->hull_dim;
456 volume_ += dist * area / qh hull_dim;
459 Triangles_.push_back(face);
463#ifdef HAVE_QHULL_REENTRANT
464 qh_freeqhull(qh, !qh_ALL);
465 qh_memfreeshort(qh, &curlong, &totlong);
467 qh_freeqhull(!qh_ALL);
468 qh_memfreeshort(&curlong, &totlong);
470 if (curlong || totlong) {
471 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
472 "AlphaHull: qhull internal warning:\n"
473 "\tdid not free %d bytes of long memory (%d pieces)",
475 painCave.isFatal = 1;
480double calculate_circumradius(pointT* p0, pointT* p1, pointT* p2,
int dim) {
481 coordT a = qh_pointdist(p0, p1, dim);
482 coordT b = qh_pointdist(p1, p2, dim);
483 coordT c = qh_pointdist(p2, p0, dim);
485 coordT sum = (a + b + c) * 0.5;
486 coordT area = sum * (a + b - sum) * (a + c - sum) * (b + c - sum);
487 return (
double)(a * b * c) / (4 * sqrt(area));
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.
Real lengthSquare() const
Returns the squared length of this vector.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.