MADNESS  version 0.9
sdf_shape_3D.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30 
31  $Id$
32 */
33 
59 #ifndef MADNESS_MRA_SDF_SHAPE_3D_H__INCLUDED
60 #define MADNESS_MRA_SDF_SHAPE_3D_H__INCLUDED
61 
63 
64 namespace madness {
65 
67  class SDFPlane : public SignedDFInterface<3> {
68  protected:
69  const coord_3d normal;
70  const coord_3d point;
71 
72  public:
73 
78  SDFPlane(const coord_3d& normal, const coord_3d& point)
79  : normal(normal*(1.0/sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2])))
80  , point(point)
81  {}
82 
89  double sdf(const coord_3d& pt) const {
90  return (pt[0]-point[0])*normal[0] + (pt[1]-point[1])*normal[1] + (pt[2]-point[2])*normal[2];
91  }
92 
97  coord_3d grad_sdf(const coord_3d& pt) const {
98  MADNESS_EXCEPTION("gradient method is not yet implemented for this shape",0);
99  }
100  };
101 
103  class SDFSphere : public SignedDFInterface<3> {
104  protected:
105  const double radius;
106  const coord_3d center;
107 
108  public:
113  SDFSphere(const double radius, const coord_3d &center)
114  : radius(radius)
115  , center(center)
116  {}
117 
124  double sdf(const coord_3d& pt) const {
125  double temp, r;
126  int i;
127 
128  r = 0.0;
129  for(i = 0; i < 3; ++i) {
130  temp = pt[i] - center[i];
131  r += temp * temp;
132  }
133 
134  return sqrt(r) - radius;
135  }
136 
141  coord_3d grad_sdf(const coord_3d& pt) const {
142  double x = pt[0] - center[0];
143  double y = pt[1] - center[1];
144  double z = pt[2] - center[2];
145  double r = sqrt(x*x + y*y + z*z);
146  coord_3d g;
147  g[0] = x/r;
148  g[1] = y/r;
149  g[2] = z/r;
150  return g;
151  }
152  };
153 
161  class SDFCone : public SignedDFInterface<3> {
162  protected:
163  const coord_3d apex;
164  const double c;
165  const coord_3d dir;
166 
167  public:
173  SDFCone(const double c, const coord_3d &apex, const coord_3d &direc)
174  : apex(apex)
175  , c(c)
176  , dir(direc*(1.0/sqrt(direc[0]*direc[0] + direc[1]*direc[1] + direc[2]*direc[2])))
177  {}
178 
186  double sdf(const coord_3d& pt) const {
187  coord_3d diff;
188  unsigned int i;
189  double dotp;
190 
191  for(i = 0; i < 3; ++i)
192  diff[i] = pt[i] - apex[i];
193 
194  dotp = diff[0]*dir[0] + diff[1]*dir[1] + diff[2]*dir[2];
195 
196  for(i = 0; i < 3; ++i)
197  diff[i] -= dotp * dir[i];
198 
199  return sqrt(diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2])
200  - c * dotp;
201  }
202 
207  coord_3d grad_sdf(const coord_3d& pt) const {
208  MADNESS_EXCEPTION("gradient method is not yet implemented for this shape",0);
209  }
210  };
211 
219  class SDFParaboloid : public SignedDFInterface<3> {
220  protected:
221  const coord_3d apex;
222  const double c;
223  const coord_3d dir;
224  const long double zero;
225  const long double rootzero;
226 
227  public:
233  SDFParaboloid(const double c, const coord_3d &apex, const coord_3d &direc)
234  : apex(apex)
235  , c(c)
236  , dir(direc*(1.0/sqrt(direc[0]*direc[0] + direc[1]*direc[1] + direc[2]*direc[2])))
237  , zero(1.0e-10L)
238  , rootzero(1.0e-14L)
239  {}
240 
282  double sdf(const coord_3d& pt) const {
283  // work in extended precision since this calculation can have
284  // large cancellations
286  unsigned int i, n;
287  long double dotp, d;
288  long double lambda, dist, temp[2], upper;
289  std::vector<long double> roots;
290 
291  // silence warnings
292  lambda = 0.0;
293  dist = 0.0;
294 
295  // avoid lots of casting
296  long double c = (long double)this->c;
297 
298  for(i = 0; i < 3; ++i)
299  diff[i] = pt[i] - apex[i];
300 
301  dotp = diff[0]*dir[0] + diff[1]*dir[1] + diff[2]*dir[2];
302 
303  for(i = 0; i < 3; ++i)
304  diff[i] -= dotp * dir[i];
305 
306  d = diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]
307  - c * dotp;
308  //printf(" %.16Le %.16Le %.16Le\n", c, d, dotp);
309 
310  // get the real roots (Lagrange multipliers) and find the one
311  // that minimizes the distance.
312  // note that real roots must be no bigger than (4dotp+c)/(2c)
313  // from the analytical form
314  roots = get_roots(c, d, dotp);
315  upper = (4.0L*dotp + c) * 0.5L / c;
316  n = 0;
317  for(std::vector<long double>::iterator iter = roots.begin();
318  iter != roots.end(); ++iter) {
319 
320  temp[0] = *iter;
321 
322  // are we in range?
323  if(temp[0] <= upper) {
324 
325  // calculate the distance
326  temp[1] = c*(dotp - temp[0]*c*0.5L + c*0.25L);
327  if(temp[1] < 0.0L) {
328  // temp[1] is analytically non-negative
329  // if we're here, it's noise
330  temp[1] = 0.0L;
331  }
332  else {
333  temp[1] = fabs(temp[0])*sqrt(temp[1]);
334  }
335 
336  if(n == 0) {
337  lambda = temp[0];
338  dist = temp[1];
339  }
340  else {
341  if(temp[1] < dist) {
342  lambda = temp[0];
343  dist = temp[1];
344  }
345  }
346  ++n;
347  }
348  }
349  //printf(" L = %.16Le D = %.16Le\n", lambda, dist);
350 
351  MADNESS_ASSERT(n > 0); // we should have at least one real root...
352 
353  if(d > 0.0L)
354  return (double)dist;
355  else
356  return (double)(-dist);
357  }
358 
363  coord_3d grad_sdf(const coord_3d& pt) const {
364  MADNESS_EXCEPTION("gradient method is not yet implemented for this shape",0);
365  }
366 
367  protected:
394  std::vector<long double> get_roots(const long double c,
395  const long double d, const long double z) const {
396 
397  long double lower, upper, bound;
398  std::vector<long double> roots(0);
399  long double derivroot1, derivroot2, temp;
400  bool hasregion2, keepgoing, foundroot;
401 
402  // calculate the region boundaries
403  lower = 2.0L*(c+z);
404  upper = fabs(c - 2.0L*z);
405  hasregion2 = (upper >= 1.0e-10L);
406 
407  derivroot1 = (lower - upper) / (3.0L*c);
408  derivroot2 = (lower + upper) / (3.0L*c);
409 
410  // first region -------------------------------------------------
411  foundroot = false;
412  upper = derivroot1;
413 
414  // if cubic(upper) < 0.0, there's no root in this region
415  bound = eval_cubic(upper, c, d, z);
416  if(fabs(bound) < zero) {
417  // this is the root!
418  roots.push_back(upper);
419  hasregion2 = false;
420  }
421  if(bound > 0.0L) {
422  // there's a root in region 1: find it!
423 
424  // need to find a lower bound
425  temp = -1.0;
426  do {
427  lower = upper + temp;
428  bound = eval_cubic(lower, c, d, z);
429  if(fabs(bound) < zero) {
430  // found the root!
431  roots.push_back(lower);
432  foundroot = true;
433  break;
434  }
435 
436  keepgoing = (bound > 0.0L);
437  // if we didn't cross the root, we have a better upperbound
438  if(keepgoing)
439  upper = lower;
440  } while(keepgoing);
441 
442  // with a lower and upper bound, find the root!
443  if(!foundroot) {
444  temp = find_root(lower, upper, c, d, z, true);
445  roots.push_back(temp);
446  }
447  }
448  else {
449  // no root in region 1; hence no root in region 2
450  hasregion2 = false;
451  }
452 
453  // second region ------------------------------------------------
454  if(hasregion2) {
455  lower = derivroot1;
456  upper = derivroot2;
457  // the lower range has to be positive the upper range has to be
458  // negative
459  if(lower > 0.0L && upper < 0.0L) {
460  temp = find_root(lower, upper, c, d, z, false);
461  roots.push_back(temp);
462  }
463  }
464 
465  // third region -------------------------------------------------
466  foundroot = false;
467  lower = derivroot2;
468 
469  // if cubic(upper) > 0.0, there's no root in this region
470  bound = eval_cubic(lower, c, d, z);
471  if(fabs(bound) < zero) {
472  // this is the root!
473  roots.push_back(lower);
474  }
475  if(bound < 0.0L) {
476  // there's a root in region 3: find it!
477 
478  // need to find an upper bound
479  temp = 1.0;
480  do {
481  upper = lower + temp;
482  bound = eval_cubic(upper, c, d, z);
483  if(fabs(bound) < zero) {
484  // found the root!
485  roots.push_back(upper);
486  foundroot = true;
487  break;
488  }
489 
490  keepgoing = (bound < 0.0L);
491  // if we didn't cross the root, we have a better lowerbound
492  if(keepgoing)
493  lower = upper;
494  } while(keepgoing);
495 
496  // with a lower and upper bound, find the root!
497  if(!foundroot) {
498  temp = find_root(lower, upper, c, d, z, true);
499  roots.push_back(temp);
500  }
501  }
502 
503  return roots;
504  }
505 
521  long double find_root(long double lower, long double upper,
522  const long double c, const long double d,
523  const long double z, bool dir) const {
524 
525  long double value, middle;
526  do {
527  middle = 0.5L*(upper + lower);
528  value = eval_cubic(middle, c, d, z);
529 
530  if(fabs(value) < zero)
531  return middle;
532 
533  if(value < 0.0L) {
534  if(dir)
535  lower = middle;
536  else
537  upper = middle;
538  }
539  else {
540  if(dir)
541  upper = middle;
542  else
543  lower = middle;
544  }
545  } while(fabs(upper-lower) > rootzero);
546 
547  return middle;
548  }
549 
562  long double eval_cubic(const long double x, const long double c,
563  const long double d, const long double z)
564  const {
565  return ((c*0.5L*x - (c + z))*x + (2.0L*z + c*0.5L))*c*x + d;
566  }
567 
584  long double eval_cubic_deriv(const long double x, const long double c,
585  const long double d, const long double z)
586  const {
587  return c*((1.5L*c*x - 2.0L*(c+z))*x + 2.0L*z + 0.5L*c);
588  }
589  };
590 
594  class SDFBox : public SignedDFInterface<3> {
595  protected:
597  const coord_3d center;
598 
599  public:
604  SDFBox(const coord_3d& length, const coord_3d& center)
605  : lengths(length*0.5), center(center)
606  {}
607 
616  double sdf(const coord_3d& pt) const {
617  double diff, max;
618  int i;
619 
620  max = fabs(pt[0] - center[0]) - lengths[0];
621  for(i = 1; i < 3; ++i) {
622  diff = fabs(pt[i] - center[i]) - lengths[i];
623  if(diff > max)
624  max = diff;
625  }
626 
627  return max;
628  }
629 
634  coord_3d grad_sdf(const coord_3d& pt) const {
635  MADNESS_EXCEPTION("gradient method is not yet implemented for this shape",0);
636  }
637  };
638 
642  class SDFCube : public SDFBox {
643  public:
648  SDFCube(const double length, const coord_3d& center)
649  : SDFBox(coord_3d(length), center)
650  {}
651  };
652 
656  class SDFEllipsoid : public SignedDFInterface<3> {
657  protected:
660 
661  public:
666  SDFEllipsoid(const coord_3d& radii, const coord_3d& center)
667  : radii(radii)
668  , center(center)
669  {}
670 
678  double sdf(const coord_3d& pt) const {
679  double quot, sum;
680  int i;
681 
682  sum = 0.0;
683  for(i = 0; i < 3; ++i) {
684  quot = (pt[i] - center[i]) / radii[i];
685  sum += quot * quot;
686  }
687 
688  return sum - 1.0;
689  }
690 
695  coord_3d grad_sdf(const coord_3d& pt) const {
696  MADNESS_EXCEPTION("gradient method is not yet implemented for this shape",0);
697  }
698  };
699 
701  class SDFCylinder : public SignedDFInterface<3> {
702  protected:
703  double radius;
704  double a;
707 
708  public:
716  SDFCylinder(const double radius, const double length, const coord_3d& axpt, const coord_3d& axis)
717  : radius(radius)
718  , a(length / 2.0)
719  , center(axpt)
720  , axis(axis*(1.0/sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2])))
721  {}
722 
730  double sdf(const coord_3d& pt) const {
731  double dist;
732  coord_3d rel, radial;
733  int i;
734 
735  // axial distance
736  dist = 0.0;
737  for(i = 0; i < 3; ++i) {
738  rel[i] = pt[i] - center[i];
739  dist += rel[i] * axis[i];
740  }
741 
742  // get the radial component
743  for(i = 0; i < 3; ++i)
744  radial[i] = rel[i] - dist * axis[i];
745 
746  return std::max(fabs(dist) - a, sqrt(radial[0]*radial[0] + radial[1]*radial[1]
747  + radial[2]*radial[2]) - radius);
748  }
749 
754  coord_3d grad_sdf(const coord_3d& pt) const {
755  MADNESS_EXCEPTION("gradient method is not yet implemented for this shape",0);
756  }
757  };
758 
759 } // end of madness namespace
760 
761 #endif // MADNESS_MRA_SDF_SHAPE_3D_H__INCLUDED
const coord_3d center
the center of the box
Definition: sdf_shape_3D.h:597
SDFParaboloid(const double c, const coord_3d &apex, const coord_3d &direc)
Constructor for paraboloid.
Definition: sdf_shape_3D.h:233
const coord_3d normal
The normal vector pointing OUTSIDE the surface.
Definition: sdf_shape_3D.h:69
const long double zero
Numerical zero for root-finding in sdf.
Definition: sdf_shape_3D.h:224
double sdf(const coord_3d &pt) const
Computes the normal distance.
Definition: sdf_shape_3D.h:730
const double radius
Radius of sphere.
Definition: sdf_shape_3D.h:105
A spherical surface (3 dimensions)
Definition: sdf_shape_3D.h:103
coord_3d grad_sdf(const coord_3d &pt) const
Definition: sdf_shape_3D.h:695
NDIM const Function< R, NDIM > & g
Definition: mra.h:2179
A paraboloid (3 dimensions)
Definition: sdf_shape_3D.h:219
const coord_3d lengths
Half the length of each side of the box.
Definition: sdf_shape_3D.h:596
const coord_3d point
A point in the plane.
Definition: sdf_shape_3D.h:70
const double c
Curvature/radius of the surface.
Definition: sdf_shape_3D.h:222
const double L
Definition: 3dharmonic.cc:123
SDFPlane(const coord_3d &normal, const coord_3d &point)
SDF for a plane transecting the entire simulation volume.
Definition: sdf_shape_3D.h:78
const coord_3d center
Center of sphere.
Definition: sdf_shape_3D.h:106
coord_3d grad_sdf(const coord_3d &pt) const
Definition: sdf_shape_3D.h:754
SDFSphere(const double radius, const coord_3d &center)
SDF for a sphere.
Definition: sdf_shape_3D.h:113
coord_3d grad_sdf(const coord_3d &pt) const
Computes the gradient of the SDF.
Definition: sdf_shape_3D.h:207
double sdf(const coord_3d &pt) const
Computes the normal distance.
Definition: sdf_shape_3D.h:678
SDFCube(const double length, const coord_3d &center)
Constructor for box.
Definition: sdf_shape_3D.h:648
Defines abstract interfaces and concrete classes signed distance functions and domain masks...
const long double rootzero
Numerical zero for the roots.
Definition: sdf_shape_3D.h:225
SDFCylinder(const double radius, const double length, const coord_3d &axpt, const coord_3d &axis)
Constructor for cylinder.
Definition: sdf_shape_3D.h:716
const coord_3d apex
The apex.
Definition: sdf_shape_3D.h:221
An ellipsoid (3 dimensions)
Definition: sdf_shape_3D.h:656
A cone (3 dimensions)
Definition: sdf_shape_3D.h:161
double sdf(const coord_3d &pt) const
Computes the normal distance.
Definition: sdf_shape_3D.h:616
const coord_3d dir
The direction of the axis, from the apex INSIDE.
Definition: sdf_shape_3D.h:165
const coord_3d apex
The apex.
Definition: sdf_shape_3D.h:163
SDFBox(const coord_3d &length, const coord_3d &center)
Constructor for box.
Definition: sdf_shape_3D.h:604
coord_3d radii
the directional radii
Definition: sdf_shape_3D.h:658
coord_3d center
the central axial point of the cylinder (distance a from both ends)
Definition: sdf_shape_3D.h:705
long double eval_cubic_deriv(const long double x, const long double c, const long double d, const long double z) const
Evaluates the derivative of the cubic equation for the Lagrangian multipliers.
Definition: sdf_shape_3D.h:584
The interface for a signed distance function (sdf).
Definition: sdf_domainmask.h:74
SDFEllipsoid(const coord_3d &radii, const coord_3d &center)
Constructor for ellipsoid.
Definition: sdf_shape_3D.h:666
const double c
The radius.
Definition: sdf_shape_3D.h:164
#define max(a, b)
Definition: lda.h:53
SDFCone(const double c, const coord_3d &apex, const coord_3d &direc)
Constructor for cone.
Definition: sdf_shape_3D.h:173
double a
half the length of the cylinder
Definition: sdf_shape_3D.h:704
std::vector< long double > get_roots(const long double c, const long double d, const long double z) const
Finds real root(s) of the cubic polynomial in the sdf function.
Definition: sdf_shape_3D.h:394
A cube (3 dimensions)
Definition: sdf_shape_3D.h:642
A cylinder (3 dimensions)
Definition: sdf_shape_3D.h:701
double sdf(const coord_3d &pt) const
Computes the normal distance.
Definition: sdf_shape_3D.h:186
coord_3d grad_sdf(const coord_3d &pt) const
Computes the gradient of the SDF.
Definition: sdf_shape_3D.h:363
double sdf(const coord_3d &pt) const
Computes the normal distance.
Definition: sdf_shape_3D.h:124
coord_3d center
the center
Definition: sdf_shape_3D.h:659
tensorT sqrt(const tensorT &s, double tol=1e-8)
Computes matrix square root (not used any more?)
Definition: DFcode/moldft.cc:446
coord_3d grad_sdf(const coord_3d &pt) const
Computes the gradient of the SDF.
Definition: sdf_shape_3D.h:97
coord_3d grad_sdf(const coord_3d &pt) const
Definition: sdf_shape_3D.h:634
double sdf(const coord_3d &pt) const
Computes the normal distance.
Definition: sdf_shape_3D.h:282
long double find_root(long double lower, long double upper, const long double c, const long double d, const long double z, bool dir) const
Definition: sdf_shape_3D.h:521
const mpreal sum(const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode)
Definition: mpreal.cc:241
double sdf(const coord_3d &pt) const
Computes the normal distance.
Definition: sdf_shape_3D.h:89
A box (3 dimensions)
Definition: sdf_shape_3D.h:594
A plane surface (3 dimensions)
Definition: sdf_shape_3D.h:67
coord_3d grad_sdf(const coord_3d &pt) const
Computes the gradient of the SDF.
Definition: sdf_shape_3D.h:141
coord_3d axis
the axial direction of the cylinder
Definition: sdf_shape_3D.h:706
#define MADNESS_EXCEPTION(msg, value)
Definition: worldexc.h:88
long double eval_cubic(const long double x, const long double c, const long double d, const long double z) const
Evaluates the cubic equation for the Lagrangian multipliers.
Definition: sdf_shape_3D.h:562
const coord_3d dir
The direction of the axis, from the apex INSIDE.
Definition: sdf_shape_3D.h:223
double radius
the radius of the cylinder
Definition: sdf_shape_3D.h:703
const mpreal fabs(const mpreal &v, mp_rnd_t rnd_mode)
Definition: mpreal.h:2187
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45