45#include "math/AlphaHull.hpp"
57#include "math/qhull.hpp"
58#include "utils/simError.h"
64double calculate_circumradius(pointT* p0, pointT* p1, pointT* p2,
int dim);
66AlphaHull::AlphaHull(
double alpha) :
67 Hull(), dim_(4), alpha_(alpha), options_(
"qhull d QJ Tcv Pp") {}
69void AlphaHull::computeHull(vector<StuntDouble*> bodydoubles) {
70#ifdef HAVE_QHULL_REENTRANT
76 int numpoints = bodydoubles.size();
81 facetT *facet, *neighbor;
82 pointT* interiorPoint;
85 vector<double> ptArray(numpoints * dim_);
88 vector<StuntDouble*>::iterator SD;
91 for (SD = bodydoubles.begin(); SD != bodydoubles.end(); ++SD) {
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 "AlphaHull: 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 "AlphaHull: Qhull failed to compute convex hull");
134 painCave.isFatal = 1;
144 MPI_Comm_size(MPI_COMM_WORLD, &nproc);
145 MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
147 int localHullSites = 0;
149 vector<int> hullSitesOnProc(nproc, 0);
150 vector<int> coordsOnProc(nproc, 0);
151 vector<int> displacements(nproc, 0);
152 vector<int> vectorDisplacements(nproc, 0);
154 vector<double> coords;
156 vector<int> indexMap;
157 vector<double> masses;
162#ifdef HAVE_QHULL_REENTRANT
163 int idx = qh_pointid(qh, vertex->point);
165 int idx = qh_pointid(vertex->point);
168 indexMap.push_back(idx);
170 coords.push_back(ptArray[dim_ * idx]);
171 coords.push_back(ptArray[dim_ * idx + 1]);
172 coords.push_back(ptArray[dim_ * idx + 2]);
173 coords.push_back(ptArray[dim_ * idx + 3]);
178 vels.push_back(vel.
x());
179 vels.push_back(vel.
y());
180 vels.push_back(vel.
z());
183 masses.push_back(sd->
getMass());
186 MPI_Allgather(&localHullSites, 1, MPI_INT, &hullSitesOnProc[0], 1, MPI_INT,
189 int globalHullSites = 0;
190 for (
int iproc = 0; iproc < nproc; iproc++) {
191 globalHullSites += hullSitesOnProc[iproc];
192 coordsOnProc[iproc] = dim_ * hullSitesOnProc[iproc];
195 displacements[0] = 0;
196 vectorDisplacements[0] = 0;
198 for (
int iproc = 1; iproc < nproc; iproc++) {
199 displacements[iproc] =
200 displacements[iproc - 1] + hullSitesOnProc[iproc - 1];
201 vectorDisplacements[iproc] =
202 vectorDisplacements[iproc - 1] + coordsOnProc[iproc - 1];
205 vector<double> globalCoords(dim_ * globalHullSites);
206 vector<double> globalVels(dim_ * globalHullSites);
207 vector<double> globalMasses(globalHullSites);
209 int count = coordsOnProc[myrank];
211 MPI_Allgatherv(&coords[0], count, MPI_DOUBLE, &globalCoords[0],
212 &coordsOnProc[0], &vectorDisplacements[0], MPI_DOUBLE,
215 MPI_Allgatherv(&vels[0], count, MPI_DOUBLE, &globalVels[0], &coordsOnProc[0],
216 &vectorDisplacements[0], MPI_DOUBLE, MPI_COMM_WORLD);
218 MPI_Allgatherv(&masses[0], localHullSites, MPI_DOUBLE, &globalMasses[0],
219 &hullSitesOnProc[0], &displacements[0], MPI_DOUBLE,
223#ifdef HAVE_QHULL_REENTRANT
224 qh_freeqhull(qh, !qh_ALL);
225 qh_memfreeshort(qh, &curlong, &totlong);
227 qh_freeqhull(!qh_ALL);
228 qh_memfreeshort(&curlong, &totlong);
230 if (curlong || totlong) {
231 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
232 "AlphaHull: qhull internal warning:\n"
233 "\tdid not free %d bytes of long memory (%d pieces)",
235 painCave.isFatal = 1;
239#ifdef HAVE_QHULL_REENTRANT
240 qh_init_A(qh, NULL, NULL, stderr, 0, NULL);
241 exitcode = setjmp(qh->errexit);
243 qh->NOerrexit = False;
244 qh_initflags(qh,
const_cast<char*
>(options_.c_str()));
245 qh_init_B(qh, &globalCoords[0], globalHullSites, dim_, ismalloc);
248 exitcode = qh_ERRnone;
249 qh->NOerrexit = True;
251 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
252 "AlphaHull: Qhull failed to compute convex hull");
253 painCave.isFatal = 1;
257 qh_init_A(NULL, NULL, stderr, 0, NULL);
258 exitcode = setjmp(qh errexit);
260 qh NOerrexit = False;
261 qh_initflags(
const_cast<char*
>(options_.c_str()));
262 qh_init_B(&globalCoords[0], globalHullSites, dim_, ismalloc);
265 exitcode = qh_ERRnone;
268 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
269 "AlphaHull: Qhull failed to compute convex hull");
270 painCave.isFatal = 1;
278#ifdef HAVE_QHULL_REENTRANT
279 qh_setvoronoi_all(qh);
285 vector<vector<int>> facetlist;
288#ifdef HAVE_QHULL_REENTRANT
289 setT* set = qh_settemp(qh, 4 * qh->num_facets);
291 interiorPoint = qh->interior_point;
293 setT* set = qh_settemp(4 * qh num_facets);
295 interiorPoint = qh interior_point;
298#ifdef HAVE_QHULL_REENTRANT
299 FORALLfacet_(qh->facet_list) {
301 FORALLfacet_(qh facet_list) {
304 if (!facet->upperdelaunay) {
308 vertexT* vertex = (vertexT*)(facet->vertices->e[0].p);
310#ifdef HAVE_QHULL_REENTRANT
311 double* center = qh_facetcenter(qh, facet->vertices);
313 double* center = qh_facetcenter(facet->vertices);
315 double radius = qh_pointdist(center, vertex->point, dim_ - 1);
318 if (radius > alpha_) {
325#ifdef HAVE_QHULL_REENTRANT
326 facet->visitid = qh->visit_id;
327 qh_makeridges(qh, facet);
329 facet->visitid = qh visit_id;
330 qh_makeridges(facet);
332 ridgeT *ridge, **ridgep;
333 int goodTriangles = 0;
334 FOREACHridge_(facet->ridges) {
335 neighbor = otherfacet_(ridge, facet);
336#ifdef HAVE_QHULL_REENTRANT
337 if ((neighbor->visitid != qh->visit_id)) {
339 if ((neighbor->visitid != qh visit_id)) {
342 pointT* p0 = ((vertexT*)(ridge->vertices->e[0].p))->point;
343 pointT* p1 = ((vertexT*)(ridge->vertices->e[1].p))->point;
344 pointT* p2 = ((vertexT*)(ridge->vertices->e[2].p))->point;
346 radius = calculate_circumradius(p0, p1, p2, dim_ - 1);
348 if (radius <= alpha_) {
351#ifdef HAVE_QHULL_REENTRANT
352 qh_setappend(qh, &set, ridge);
354 qh_setappend(&set, ridge);
363 if (goodTriangles == 4) facet->good =
true;
369#ifdef HAVE_QHULL_REENTRANT
370 facet->visitid = qh->visit_id;
372 facet->visitid = qh visit_id;
377#ifdef HAVE_QHULL_REENTRANT
378 qh_makeridges(qh, facet);
380 qh_makeridges(facet);
382 ridgeT *ridge, **ridgep;
383 FOREACHridge_(facet->ridges) {
384 neighbor = otherfacet_(ridge, facet);
385#ifdef HAVE_QHULL_REENTRANT
386 if ((neighbor->visitid != qh->visit_id)) {
387 qh_setappend(qh, &set, ridge);
390 if ((neighbor->visitid != qh visit_id)) { qh_setappend(&set, ridge); }
399 ridgeT *ridge, **ridgep;
401 if ((!ridge->top->good || !ridge->bottom->good ||
402 ridge->top->upperdelaunay || ridge->bottom->upperdelaunay)) {
404 int vertex_n, vertex_i;
409 RealType faceMass = 0.0;
412 vector<int> vertexlist;
414#ifdef HAVE_QHULL_REENTRANT
415 FOREACHvertex_i_(qh, ridge->vertices) {
417 FOREACHvertex_i_(ridge->vertices) {
419#ifdef HAVE_QHULL_REENTRANT
420 int id = qh_pointid(qh, vertex->point);
422 int id = qh_pointid(vertex->point);
424 p[ver][0] = vertex->point[0];
425 p[ver][1] = vertex->point[1];
426 p[ver][2] = vertex->point[2];
430 vertexlist.push_back(
id);
432 vel = bodydoubles[id]->getVel();
433 mass = bodydoubles[id]->getMass();
434 face.addVertexSD(bodydoubles[
id]);
436 faceVel = faceVel + vel;
437 faceMass = faceMass + mass;
439 facetlist.push_back(vertexlist);
440 face.addVertices(p[0], p[1], p[2]);
441 face.setFacetMass(faceMass);
442 face.setFacetVelocity(faceVel / RealType(3.0));
444 RealType area = face.getArea();
446 Vector3d normal = face.getUnitNormal();
447 RealType dist = normal[0] * interiorPoint[0] +
448 normal[1] * interiorPoint[1] +
449 normal[2] * interiorPoint[2];
450#ifdef HAVE_QHULL_REENTRANT
451 volume_ += dist * area / qh->hull_dim;
453 volume_ += dist * area / qh hull_dim;
456 Triangles_.push_back(face);
460#ifdef HAVE_QHULL_REENTRANT
461 qh_freeqhull(qh, !qh_ALL);
462 qh_memfreeshort(qh, &curlong, &totlong);
464 qh_freeqhull(!qh_ALL);
465 qh_memfreeshort(&curlong, &totlong);
467 if (curlong || totlong) {
468 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
469 "AlphaHull: qhull internal warning:\n"
470 "\tdid not free %d bytes of long memory (%d pieces)",
472 painCave.isFatal = 1;
477double calculate_circumradius(pointT* p0, pointT* p1, pointT* p2,
int dim) {
478 coordT a = qh_pointdist(p0, p1, dim);
479 coordT b = qh_pointdist(p1, p2, dim);
480 coordT c = qh_pointdist(p2, p0, dim);
482 coordT sum = (a + b + c) * 0.5;
483 coordT area = sum * (a + b - sum) * (a + c - sum) * (b + c - sum);
484 return (
double)(a * b * c) / (4 * sqrt(area));
"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.
Real lengthSquare()
Returns the squared length of this vector.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.