Belle II Software  release-08-01-10
BelleCrystal.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 /* Own header. */
10 #include <ecl/geometry/BelleCrystal.h>
11 
12 /* Geant4 headers. */
13 #include <G4AffineTransform.hh>
14 #include <G4VoxelLimits.hh>
15 #include <G4VGraphicsScene.hh>
16 #include <G4VPVParameterisation.hh>
17 
18 /* CLHEP headers. */
19 #include <CLHEP/Random/RandFlat.h>
20 
21 using namespace Belle2;
22 using namespace std;
23 using namespace ECL;
24 
25 #define DO_QUOTE(X) #X
26 #define QUOTE(X) DO_QUOTE(X)
27 
28 #define PERFCOUNTER 0
29 //#define MATCHNAME sv_fwd_crystal2
30 
31 #if PERFCOUNTER==1
32 int counter[6];
33 # define COUNTER(x) counter[x]++
34 #else
35 # define COUNTER(x)
36 #endif
37 
38 #ifdef MATCHNAME
39 # define MATCHOUT(x) if(fmatch) cout<<x<<"\n";
40 #else
41 # define MATCHOUT(x) {}
42 #endif
43 
44 // Accuracy of coplanarity
45 const G4double kCoplanar_Tolerance = 1E-4;
46 
47 BelleCrystal::BelleCrystal(const G4String& pName, int n,
48  const G4ThreeVector* pt)
49  : G4CSGSolid(pName), nsides(n), fPlanes(nsides), fx(2 * nsides)
50 {
51 #if PERFCOUNTER==1
52  memset(fcounter, 0, sizeof(fcounter));
53 #endif
54 #ifdef MATCHNAME
55  // cppcheck-suppress ConfigurationNotChecked
56  fmatch = GetName() == QUOTE(MATCHNAME);
57  cout.precision(17);
58 #endif
59  // ref = new G4Trap("dummy",pt);
60  fDz = abs(pt[2 * nsides - 1].z());
61  for (unsigned int i = 0; i < 2 * nsides; i++) {
62  fx[i].x = pt[i].x();
63  fx[i].y = pt[i].y();
64  }
65  // cout<<pName<<" "<<fx.data()<<endl;
66  // for(int i=0; i<2*nsides + 2*(nsides-2); i++) ivertx(i);
67 
68  auto isConvex = [](std::vector<Point_t>::const_iterator begin, std::vector<Point_t>::const_iterator end) -> bool {
69  bool sign = false;
70  int np = end - begin;
71  for (int i0 = 0; i0 < np; i0++)
72  {
73  int i1 = (i0 + 1) % np, i2 = (i0 + 2) % np;
74  const Point_t& r2 = *(begin + i2), &r1 = *(begin + i1), &r0 = *(begin + i0);
75  double dx1 = r2.x - r1.x, dy1 = r2.y - r1.y;
76  double dx2 = r0.x - r1.x, dy2 = r0.y - r1.y;
77  double x = dx1 * dy2 - dy1 * dx2;
78  if (i0 == 0) sign = x > 0;
79  else {
80  if (sign != (x > 0)) return false;
81  }
82  }
83  return true;
84  };
85 
86  auto isClockwise = [](std::vector<Point_t>::const_iterator begin, std::vector<Point_t>::const_iterator end) -> bool {
87  std::vector<Point_t>::const_iterator it = begin;
88  Point_t r0 = *it++;
89  double sum = 0;
90  for (; it != end;)
91  {
92  Point_t r1 = *it++; sum += (r1.x - r0.x) * (r1.y + r0.y);
93  r0 = r1;
94  }
95  Point_t r1 = *begin; sum += (r1.x - r0.x) * (r1.y + r0.y);
96  return sum > 0;
97  };
98 
99  if (!isConvex(fx.begin(), fx.begin() + nsides)) {
100  std::ostringstream message;
101  message << "At -z polygon is not convex: " << GetName();
102  G4Exception("BelleCrystal::BelleCrystal()", "BelleCrystal", FatalException, message);
103  }
104  if (!isConvex(fx.begin() + nsides, fx.end())) {
105  std::ostringstream message;
106  message << "At +z polygon is not convex: " << GetName();
107  G4Exception("BelleCrystal::BelleCrystal()", "BelleCrystal", FatalException, message);
108  }
109 
110  if (isClockwise(fx.begin(), fx.begin() + nsides)) {
111  std::ostringstream message;
112  message << "At -z polygon is not in anti-clockwise order: " << GetName();
113  G4Exception("BelleCrystal::BelleCrystal()", "BelleCrystal", FatalException, message);
114  }
115  if (isClockwise(fx.begin() + nsides, fx.end())) {
116  std::ostringstream message;
117  message << "At +z polygon is not in anti-clockwise order: " << GetName();
118  G4Exception("BelleCrystal::BelleCrystal()", "BelleCrystal", FatalException, message);
119  }
120 
121  // sanity check
122  const G4ThreeVector* pm = pt, *pp = pt + nsides;
123  bool zm = pm[0].z() < 0, zp = pp[0].z() > 0;
124  for (unsigned int i = 1; i < nsides; i++) {
125  zm = zm && (pm[i - 1].z() - pm[i].z()) < kCarTolerance;
126  zp = zp && (pp[i - 1].z() - pp[i].z()) < kCarTolerance;
127  }
128  bool zpm = abs(pm[0].z() + pp[0].z()) < kCarTolerance;
129  if (!(zm && zp && zpm)) {
130  std::ostringstream message;
131  message << "Invalid vertice coordinates for Solid: " << GetName() << " " << zp << " " << zm << " " << zpm;
132  G4Exception("BelleCrystal::BelleCrystal()", "BelleCrystal", FatalException, message);
133  }
134  if (nsides > 3) {
135  for (unsigned int i = 0; i < nsides; i++)
136  MakePlane(pt[i], pt[i + nsides], pt[((i + 1) % (nsides)) + nsides], pt[(i + 1) % nsides], fPlanes[i]);
137  } else {
138  std::ostringstream message;
139  message << "Wrong number of sides for Belle Crystal: " << GetName() << " nsides = " << nsides;
140  G4Exception("BelleCrystal::BelleCrystal()", "BelleCrystal", FatalException, message);
141  }
142 }
143 
144 // Nominal constructor for BelleCrystal
145 BelleCrystal::BelleCrystal(const G4String& pName)
146  : G4CSGSolid(pName), nsides(0), fDz(0)
147 {
148 }
149 
150 // Fake default constructor - sets only member data and allocates memory
151 // for usage restricted to object persistency.
153  : G4CSGSolid(a), nsides(0), fDz(0)
154 {
155 }
156 
157 // Destructor
159 {
160 #if PERFCOUNTER==1
161  cout << GetName() << " ";
162  for (int i = 0; i < 6; i++) cout << counter[i] << " "; cout << endl;
163  exit(0);
164 #endif
165  // delete ref;
166 }
167 
168 // Copy constructor
170  : G4CSGSolid(rhs), nsides(rhs.nsides), fDz(rhs.fDz), fPlanes(rhs.fPlanes), fx(rhs.fx)
171 {
172 }
173 
174 // Assignment operator
176 {
177  // Check assignment to self
178  if (this == &rhs) { return *this; }
179 
180  // Copy base class data
181  G4CSGSolid::operator=(rhs);
182 
183  // Copy data
184  nsides = rhs.nsides;
185  fDz = rhs.fDz;
186  fx = rhs.fx;
187  fPlanes = rhs.fPlanes;
188 
189  return *this;
190 }
191 
192 // Calculate the coef's of the plane p1->p2->p3->p4->p1
193 // where the ThreeVectors 1-4 are in anti-clockwise order when viewed from
194 // infront of the plane (i.e. from normal direction).
195 //
196 // Return true if the ThreeVectors are coplanar + set coef;s
197 // false if ThreeVectors are not coplanar
198 G4bool BelleCrystal::MakePlane(const G4ThreeVector& p1, const G4ThreeVector& p2,
199  const G4ThreeVector& p3, const G4ThreeVector& p4,
200  Plane_t& plane) const
201 {
202  G4ThreeVector v12 = p2 - p1;
203  G4ThreeVector v13 = p3 - p1;
204  G4ThreeVector v14 = p4 - p1;
205  G4ThreeVector Vcross = v12.cross(v13);
206 
207  if (std::fabs(Vcross.dot(v14) / (Vcross.mag()*v14.mag())) > kCoplanar_Tolerance) {
208  std::ostringstream message;
209  message << "Verticies are not in the same plane: " << GetName() << " volume =" << Vcross.dot(v14);
210  G4Exception("BelleCrystal::MakePlane()", "BelleCrystal", FatalException, message);
211  }
212 
213  double a = +(p4.y() - p2.y()) * (p3.z() - p1.z()) - (p3.y() - p1.y()) * (p4.z() - p2.z());
214  double b = -(p4.x() - p2.x()) * (p3.z() - p1.z()) + (p3.x() - p1.x()) * (p4.z() - p2.z());
215  double c = +(p4.x() - p2.x()) * (p3.y() - p1.y()) - (p3.x() - p1.x()) * (p4.y() - p2.y());
216  double sd = sqrt(a * a + b * b + c * c); // so now vector plane.(a,b,c) is unit
217  a /= sd;
218  b /= sd;
219  c /= sd;
220  plane.n = G4ThreeVector(a, b, c);
221  plane.d = -(a * p1.x() + b * p1.y() + c * p1.z());
222 
223  // plane.n = (p4-p2).cross(p3-p1).unit();
224  // plane.d =-(plane.n*p1);
225  return true;
226 }
227 
228 // Dispatch to parameterisation for replication mechanism dimension
229 // computation & modification.
230 void BelleCrystal::ComputeDimensions(G4VPVParameterisation*,
231  const G4int,
232  const G4VPhysicalVolume*)
233 {
234  G4Exception("BelleCrystal::ComputeDimensions()",
235  "GeomSolids0001", FatalException,
236  "BelleCrystal does not support Parameterisation.");
237  // std::cout<<"ComputeDimensions"<<std::endl;
238  // p->ComputeDimensions(*this,n,pRep);
239 }
240 
241 // by component min
242 G4ThreeVector min(const G4ThreeVector& a, const G4ThreeVector& b)
243 {
244  return G4ThreeVector(std::min(a.x(), b.x()), std::min(a.y(), b.y()), std::min(a.z(), b.z()));
245 }
246 
247 // by component max
248 G4ThreeVector max(const G4ThreeVector& a, const G4ThreeVector& b)
249 {
250  return G4ThreeVector(std::max(a.x(), b.x()), std::max(a.y(), b.y()), std::max(a.z(), b.z()));
251 }
252 
253 // Calculate extent under transform and specified limit
254 G4bool BelleCrystal::CalculateExtent(const EAxis pAxis,
255  const G4VoxelLimits& bb,
256  const G4AffineTransform& pTransform,
257  G4double& pMin, G4double& pMax) const
258 {
259  const double inf = std::numeric_limits<double>::infinity();
260  G4ThreeVector v0(inf, inf, inf), v1(-inf, -inf, -inf);
261  for (unsigned int i = 0; i < 2 * nsides; i++) {
262  G4ThreeVector v = pTransform.TransformPoint(vertex(i));
263  v0 = min(v0, v);
264  v1 = max(v1, v);
265  }
266  G4ThreeVector b0(bb.GetMinXExtent(), bb.GetMinYExtent(), bb.GetMinZExtent());
267  G4ThreeVector b1(bb.GetMaxXExtent(), bb.GetMaxYExtent(), bb.GetMaxZExtent());
268 
269  v0 = max(v0, b0);
270  v1 = min(v1, b1);
271 
272  switch (pAxis) {
273  case kXAxis: pMin = v0.x(); pMax = v1.x(); break;
274  case kYAxis: pMin = v0.y(); pMax = v1.y(); break;
275  case kZAxis: pMin = v0.z(); pMax = v1.z(); break;
276  default: break;
277  }
278 
279  G4bool flag = false;
280  if ((pMin < inf) || (pMax > -inf)) {
281  flag = true;
282  // Add tolerance to avoid precision troubles
283  pMin -= kCarTolerance ;
284  pMax += kCarTolerance ;
285  }
286  // do {
287  // double t_pMin, t_pMax;
288  // bool t_flag = ref->CalculateExtent(pAxis, bb, pTransform, t_pMin, t_pMax);
289  // if(flag!=t_flag||abs(t_pMin-pMin)>kCarTolerance||abs(t_pMax-pMax)>kCarTolerance){
290  // cout<<GetName()<<" "<<pAxis<<" "<<bb<<" "<<pTransform<<t_pMin-pMin<<" "<<t_pMax-pMax<<endl;
291  // exit(0);
292  // }
293  // } while(0);
294  return flag;
295 }
296 
297 // Return whether point inside/outside/on surface, using tolerance
298 EInside BelleCrystal::Inside(const G4ThreeVector& p) const
299 {
300  COUNTER(0);
301  MATCHOUT("Inside(p) " << p.x() << " " << p.y() << " " << p.z());
302  // return ref->Inside(p);
303  double d = std::fabs(p.z()) - fDz;
304  unsigned int i = 0;
305  do {
306  const Plane_t& t = fPlanes[i++];
307  d = max(t.n * p + t.d, d);
308  } while (i < nsides);
309  const G4double delta = 0.5 * kCarTolerance;
310  int in = 0;
311  in += d <= delta;
312  in += d <= -delta;
313 
314  EInside res = EInside(in);
315  // if(res != ref->Inside(p)){
316  // cout<<GetName()<<" "<<p<<endl;
317  // exit(0);
318  // }
319  return res;
320 }
321 
322 // Calculate side nearest to p, and return normal
323 // If 2+ sides equidistant, first side's normal returned (arbitrarily)
324 G4ThreeVector BelleCrystal::SurfaceNormal(const G4ThreeVector& p) const
325 {
326  // return ref->SurfaceNormal(p);
327  COUNTER(1);
328  MATCHOUT("SurfaceNormal(p) " << p.x() << " " << p.y() << " " << p.z());
329  const G4double delta = 0.5 * kCarTolerance;
330  G4double safe = kInfinity;
331  unsigned int iside = 0, kside = 0;
332  vector<double> adist(nsides + 2);
333  auto dist = [delta, &safe, &iside, &kside, &adist](double d, unsigned int i) -> void {
334  d = std::abs(d);
335  adist[i] = d;
336  iside = (d < safe) ? i : iside;
337  safe = min(d, safe);
338  kside += d < delta;
339  };
340 
341  unsigned int i = 0;
342  do {
343  const Plane_t& t = fPlanes[i];
344  dist(t.n * p + t.d, i++);
345  } while (i < nsides);
346  do {
347  dist(p.z() - fDz, i++);
348  dist(p.z() + fDz, i++);
349  } while (0);
350 
351  G4ThreeVector res;
352  if (kside > 1) {
353  i = 0;
354  do {
355  if (adist[i++] < delta) res += fPlanes[i].n;
356  } while (i < nsides);
357  do {
358  if (adist[i++] < delta) res.setZ(res.z() + 1.0);
359  if (adist[i++] < delta) res.setZ(res.z() - 1.0);
360  } while (0);
361  res = res.unit();
362  } else {
363  if (iside < nsides) {
364  res = fPlanes[iside].n;
365  } else if (iside == nsides) {
366  res = G4ThreeVector(0, 0, 1);
367  } else {
368  res = G4ThreeVector(0, 0, -1);
369  }
370  }
371  // if((res- ref->SurfaceNormal(p)).mag()>kCarTolerance){
372  // cout<<GetName()<<" "<<p<<" "<<res-ref->SurfaceNormal(p)<<endl;
373  // exit(0);
374  // }
375 
376  return res;
377 }
378 
379 // Calculate exact shortest distance to any boundary from outside
380 // This is the best fast estimation of the shortest distance to trap
381 // - Returns 0 is ThreeVector inside
382 G4double BelleCrystal::DistanceToIn(const G4ThreeVector& p) const
383 {
384  // return ref->DistanceToIn(p);
385  COUNTER(2);
386  MATCHOUT("DistanceToIn(p) " << p.x() << " " << p.y() << " " << p.z());
387  G4double d = std::fabs(p.z()) - fDz;
388  unsigned int i = 0;
389  do {
390  const Plane_t& t = fPlanes[i++];
391  d = max(t.n * p + t.d, d);
392  } while (i < nsides);
393  d = max(d, 0.0);
394 
395  // if(abs(d - ref->DistanceToIn(p))>kCarTolerance){
396  // cout<<GetName()<<" "<<p<<" "<<d-ref->DistanceToIn(p)<<endl;
397  // exit(0);
398  // }
399  // if(fmatch&&d==0.0) cout<<"inside\n";
400  return d;
401 }
402 
403 // Calculate exact shortest distance to any boundary from inside
404 // - Returns 0 is ThreeVector outside
405 G4double BelleCrystal::DistanceToOut(const G4ThreeVector& p) const
406 {
407  // return ref->DistanceToOut(p);
408  COUNTER(3);
409  MATCHOUT("DistanceToOut(p) " << p.x() << " " << p.y() << " " << p.z());
410  G4double d = fDz - std::fabs(p.z());
411  unsigned int i = 0;
412  do {
413  const Plane_t& t = fPlanes[i++];
414  d = min(-(t.n * p + t.d), d);
415  } while (i < nsides);
416  d = max(d, 0.0);
417  // if(abs(d - ref->DistanceToOut(p))>0){
418  // cout<<GetName()<<" "<<p<<" "<<d<<" "<<ref->DistanceToOut(p)<<" "<<fDz-ref->GetZHalfLength()<<endl;
419  // exit(0);
420  // }
421  return d;
422 }
423 
424 // Calculate distance to shape from outside - return kInfinity if no intersection
425 //
426 // ALGORITHM:
427 // For each component, calculate pair of minimum and maximum intersection
428 // values for which the particle is in the extent of the shape
429 // - The smallest (MAX minimum) allowed distance of the pairs is intersect
430 G4double BelleCrystal::DistanceToIn(const G4ThreeVector& p,
431  const G4ThreeVector& v) const
432 {
433  // return ref->DistanceToIn(p,v);
434  COUNTER(4);
435  MATCHOUT("DistanceToIn(p,v) " << p.x() << " " << p.y() << " " << p.z() << " " << v.x() << " " << v.y() << " " << v.z());
436  G4double delta = 0.5 * kCarTolerance;
437  double tin = 0, tout = kInfinity;
438  auto outside = [delta, &tin, &tout](double d, double nv) -> bool {
439  double t = -d / nv;
440  if (nv < 0)
441  tin = max(tin, t);
442  else
443  {
444  if (d >= -delta) return true;
445  tout = min(tout, t);
446  }
447  return false;
448  };
449 
450  unsigned int i = 0;
451  do {
452  const Plane_t& t = fPlanes[i++];
453  if (outside(t.n * p + t.d, t.n * v)) {tin = kInfinity; goto exit;}
454  } while (i < nsides);
455  do {
456  if (outside(p.z() - fDz, v.z())) {tin = kInfinity; goto exit;}
457  if (outside(-p.z() - fDz, -v.z())) {tin = kInfinity; goto exit;}
458  } while (0);
459 exit:
460  double res = (tin > tout) ? kInfinity : tin;
461  // G4int oldprc = cout.precision(16);
462  // if(nsides==5) cout<<GetName()<<" "<<p.x()<<" "<<p.y()<<" "<<p.z()<<" "<<v.x()<<" "<<v.y()<<" "<<v.z()<<" "<<res<<endl;
463  // cout.precision(oldprc);
464 
465  // if(abs(res - ref->DistanceToIn(p,v))>kCarTolerance){
466  // cout<<GetName()<<" "<<p<<" "<<v<<" "<<res-ref->DistanceToIn(p,v)<<endl;
467  // exit(0);
468  // }
469  return res;
470 }
471 
472 // Calculate distance to surface of shape from inside
473 // Calculate distance to x/y/z planes - smallest is exiting distance
474 G4double BelleCrystal::DistanceToOut(const G4ThreeVector& p, const G4ThreeVector& v,
475  const G4bool calcNorm, G4bool* IsValid, G4ThreeVector* n) const
476 {
477  // return ref->DistanceToOut(p,v,calcNorm,IsValid,n);
478  COUNTER(5);
479  MATCHOUT("DistanceToOut(p,v) " << p.x() << " " << p.y() << " " << p.z() << " " << v.x() << " " << v.y() << " " << v.z() << " " <<
480  calcNorm);
481  const G4double delta = 0.5 * kCarTolerance;
482  unsigned int iside = 10;
483  G4double lmin = kInfinity;
484 
485  auto outside = [delta, &lmin, &iside](double d, double nv, unsigned int i) -> bool {
486  if (d > delta) // definitly outside
487  {
488  lmin = 0; iside = i; return true;
489  } else
490  {
491  bool c = nv > 0;
492  if (d < -delta) { // definitly inside
493  if (c) { // has to point to the same direction
494  d = -d;
495  if (d < nv * lmin) {lmin = d / nv; iside = i;}
496  }
497  } else { // surface
498  if (c) { // points outside
499  lmin = 0; iside = i; return true;
500  }
501  }
502  }
503  return false;
504  };
505 
506  unsigned int i = 0;
507  do {
508  const Plane_t& t = fPlanes[i];
509  if (outside(t.n * p + t.d, t.n * v, i++)) goto exit;
510  } while (i < nsides);
511  do {
512  if (outside(p.z() - fDz, v.z(), i++)) goto exit;
513  if (outside(-p.z() - fDz, -v.z(), i++)) goto exit;
514  } while (0);
515 exit:
516  if (calcNorm) {
517  *IsValid = true;
518  if (iside < nsides) {
519  *n = fPlanes[iside].n;
520  } else if (iside == nsides) {
521  *n = G4ThreeVector(0, 0, 1);
522  } else {
523  *n = G4ThreeVector(0, 0, -1);
524  }
525  }
526  // G4int oldprc = cout.precision(16);
527  // if(nsides==5) cout<<GetName()<<" "<<p.x()<<" "<<p.y()<<" "<<p.z()<<" "<<v.x()<<" "<<v.y()<<" "<<v.z()<<" "<<calcNorm<<" "<<lmin<<endl;
528  // cout.precision(oldprc);
529  // do {
530  // G4bool t_IsValid; G4ThreeVector t_n;
531  // double t_lmin = ref->DistanceToOut(p,v,calcNorm,&t_IsValid,&t_n);
532  // if(abs(lmin - t_lmin)>kCarTolerance||*IsValid!=t_IsValid||(*n - t_n).mag()>kCarTolerance){
533  // cout<<GetName()<<" "<<p<<" "<<v<<" "<<lmin-t_lmin<<(*n-t_n)<<endl;
534  // exit(0);
535  // }
536  // } while(0);
537  return lmin;
538 }
539 
540 // GetEntityType
541 G4GeometryType BelleCrystal::GetEntityType() const
542 {
543  return G4String("BelleCrystal");
544 }
545 
546 // Make a clone of the object
547 G4VSolid* BelleCrystal::Clone() const
548 {
549  return new BelleCrystal(*this);
550 }
551 
552 // Stream object contents to an output stream
553 std::ostream& BelleCrystal::StreamInfo(std::ostream& os) const
554 {
555  G4int oldprc = os.precision(16);
556  os << "-----------------------------------------------------------\n"
557  << " *** Dump for solid - " << GetName() << " ***\n"
558  << " ===================================================\n"
559  << " Solid type: BelleCrystal\n"
560  << " Parameters: \n"
561  << " crystal side plane equations:\n"
562  << "-----------------------------------------------------------\n";
563  os.precision(oldprc);
564 
565  return os;
566 }
567 
568 // triangle vertices are ordered in anti-clockwise order looking from outside the solid
569 unsigned int ivertx4[][3] = {{0, 5, 4}, {0, 1, 5}, {1, 7, 5}, {1, 3, 7}, {3, 6, 7}, {3, 2, 6}, {2, 4, 6}, {2, 0, 4}, {0, 3, 1}, {0, 2, 3}, {4, 5, 7}, {4, 7, 6}};
570 unsigned int ivertx5[][3] = {{0, 6, 5}, {0, 1, 6}, {1, 7, 6}, {1, 2, 7}, {2, 8, 7}, {2, 3, 8}, {3, 9, 8}, {3, 4, 9}, {4, 5, 9}, {4, 0, 5}, {0, 2, 1}, {0, 3, 2}, {0, 4, 3}, {5, 6, 7}, {5, 7, 8}, {5, 8, 9}};
571 
572 const unsigned int* BelleCrystal::ivertx(unsigned int it) const
573 {
574  static unsigned int vert[3];
575  // if(nsides==4) return ivertx4[it];
576  if (nsides == 0) return ivertx4[it];
577  // else if(nsides==5) { vert[0] = ivertx5[it][0], vert[1] = ivertx5[it][1], vert[2] = ivertx5[it][2];}
578  else {
579  if (it < 2 * nsides) {
580  int j = it / 2;
581  if ((it & 1) == 0) {
582  vert[0] = j, vert[2] = j + nsides, vert[1] = ((j + 1) % nsides) + nsides;
583  } else {
584  vert[0] = j, vert[2] = ((j + 1) % nsides) + nsides, vert[1] = (j + 1) % nsides;
585  }
586  } else if (it < 2 * nsides + (nsides - 2)) {
587  int j = it - 2 * nsides;
588  vert[0] = 0, vert[2] = 1 + j, vert[1] = 2 + j;
589  } else {
590  int j = it - (2 * nsides + (nsides - 2));
591  vert[0] = nsides, vert[2] = nsides + 2 + j, vert[1] = nsides + 1 + j;
592  }
593  }
594  // cout<<it<<" {"<<vert[0]<<", "<<vert[1]<<", "<<vert[2]<<"}"<<endl;
595  return vert;
596 }
597 
598 G4ThreeVector crossplanes(const Plane_t& p0, const Plane_t& p1, double Dz)
599 {
600  const G4ThreeVector& n0 = p0.n;
601  const G4ThreeVector& n1 = p1.n;
602  double A = n0.z() * Dz + p0.d;
603  double B = n1.z() * Dz + p1.d;
604  double iD = 1 / (n0.y() * n1.x() - n0.x() * n1.y());
605  double x = (A * n1.y() - B * n0.y()) * iD;
606  double y = (B * n0.x() - A * n1.x()) * iD;
607  double z = Dz;
608  return G4ThreeVector(x, y, z);
609 }
610 
611 #define PACK(k0,k1,w,n) ((((k0)<<(0))+((k1)<<(w)))<<((2*w)*n))
612 G4ThreeVector BelleCrystal::vertex(unsigned int i) const
613 {
614  double Dz = (i < nsides) ? -fDz : fDz;
615 
616  // if(nsides==4) {
617  // const unsigned char w = 2, mask = ((1<<w)-1);
618  // unsigned int map = PACK(0,2,w,0)+PACK(0,3,w,1)+PACK(1,2,w,2)+PACK(1,3,w,3); // 20 bits
619  // map >>= (2*w)*(i%4);
620  // int k0 = map&mask, k1 = (map>>2)&mask;
621  // return crossplanes(fPlanes[k0],fPlanes[k1],Dz);
622  // } else if(nsides==5){
623  // const unsigned char w = 3, mask = ((1<<w)-1);
624  // unsigned int map = PACK(0,4,w,0)+PACK(1,0,w,1)+PACK(2,1,w,2)+PACK(3,2,w,3)+PACK(4,3,w,4); // 30 bits
625  // map >>= (2*w)*(i%5);
626  // int k0 = map&mask, k1 = (map>>w)&mask;
627  // return crossplanes(fPlanes[k0],fPlanes[k1],Dz);
628  // }
629  return G4ThreeVector(fx[i].x, fx[i].y, Dz);
630 }
631 #undef PACK
632 
633 // uniformly sampled point over triangle
634 G4ThreeVector BelleCrystal::GetPointOnTriangle(int it) const
635 {
636  // barycentric coordinates
637  double a1 = CLHEP::RandFlat::shoot(0., 1.), a2 = CLHEP::RandFlat::shoot(0., 1.);
638  if (a1 + a2 > 1) { a1 = 1 - a1; a2 = 1 - a2;}
639  double a0 = 1 - (a1 + a2);
640  const unsigned int* iv = ivertx(it);
641  G4ThreeVector p0 = vertex(iv[0]), p1 = vertex(iv[1]), p2 = vertex(iv[2]);
642  G4ThreeVector r1(p0.x()*a0 + p1.x()*a1 + p2.x()*a2,
643  p0.y()*a0 + p1.y()*a1 + p2.y()*a2,
644  p0.z()*a0 + p1.z()*a1 + p2.z()*a2);
645  return r1;
646 }
647 
648 double BelleCrystal::area(int it, double& vol) const
649 {
650  const unsigned int* iv = ivertx(it);
651  G4ThreeVector p0 = vertex(iv[0]), p1 = vertex(iv[1]), p2 = vertex(iv[2]);
652  // std::cout<<it<<" "<<p0<<" "<<p1<<" "<<p2<<std::endl;
653  G4ThreeVector n = (p1 - p0).cross(p2 - p0);
654  vol = n * p0;
655  return 0.5 * n.mag();
656 }
657 
659 {
660  fareas.clear();
661  int nt = 2 * nsides + 2 * (nsides - 2); // total number of triangles
662  fareas.reserve(nt);
663  double totarea = 0, totvol = 0;
664  for (int i = 0; i < nt; i++) {
665  double v, s = area(i, v);
666  totarea += s;
667  totvol += v;
668  fareas.push_back(totarea);
669  // cout<<i<<" "<<s<<" "<<v<<endl;
670  }
671  return totvol / 6;
672 }
673 
675 {
676  // cout<<GetName()<<" GetCubicVolume "<<fCubicVolume<<endl;
677  if (fCubicVolume == 0.0) {
678  fCubicVolume = getvolarea();
679  fSurfaceArea = fareas.back();
680  }
681  return fCubicVolume;
682 }
683 
685 {
686  if (fSurfaceArea == 0.0) {
687  fCubicVolume = getvolarea();
688  fSurfaceArea = fareas.back();
689  }
690  return fSurfaceArea;
691 }
692 
693 // GetPointOnSurface
694 G4ThreeVector BelleCrystal::GetPointOnSurface() const
695 {
696  if (fareas.size() == 0) getvolarea();
697  double r = CLHEP::RandFlat::shoot(0., fareas.back());
698  std::vector<double>::const_iterator it = std::lower_bound(fareas.begin(), fareas.end(), r);
699  return (it != fareas.end()) ? GetPointOnTriangle(it - fareas.begin()) : GetPointOnSurface();
700 }
701 
702 // Methods for visualisation
703 void BelleCrystal::DescribeYourselfTo(G4VGraphicsScene& scene) const
704 {
705  scene.AddSolid(*this);
706 }
707 
708 PolyhedronBelleCrystal::PolyhedronBelleCrystal(int n, const G4ThreeVector* pt)
709 {
710  int nsides = n / 2;
711  AllocateMemory(n, nsides + 2 * (nsides - 2));
712  for (int i = 0; i < n; i++) pV[i + 1] = pt[i];
713 
714  int count = 1;
715  for (int j = 0; j < nsides; j++)
716  pF[count++] = G4Facet(1 + j, 0, 1 + (j + 1) % nsides, 0, 1 + ((j + 1) % nsides) + nsides, 0, 1 + j + nsides, 0);
717  for (int j = 0; j < nsides - 2; j++) pF[count++] = G4Facet(1 + nsides, 0, 2 + j + nsides, 0, 3 + j + nsides, 0, 0, 0);
718  for (int j = 0; j < nsides - 2; j++) pF[count++] = G4Facet(1, 0, 3 + j, 0, 2 + j, 0, 0, 0);
719  SetReferences();
720 }
721 
723 
724 G4Polyhedron* BelleCrystal::CreatePolyhedron() const
725 {
726  int np = 2 * nsides;
727  vector<G4ThreeVector> pt(np);
728  for (int i = 0; i < np; i++) pt[i] = vertex(i);
729  return new PolyhedronBelleCrystal(np, pt.data());
730 }
731 
732 // Function to define the bounding box
733 void BelleCrystal::BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const
734 {
735  // All extremums will be at vertices
736  int np = 2 * nsides;
737  G4ThreeVector pt;
738 
739  // Placeholder vectors
740  const double inf = std::numeric_limits<double>::infinity();
741  G4ThreeVector minimum(inf, inf, inf), maximum(-inf, -inf, -inf);
742 
743  for (int i = 0; i < np; i++) {
744  pt = vertex(i);
745 
746  // Assign new minimum and new maximum
747  minimum = min(minimum, pt);
748  maximum = max(maximum, pt);
749  }
750 
751  // Assign
752  pMin = minimum;
753  pMax = maximum;
754 }
R E
internal precision of FFTW codelets
a Belle crystal in Geant4
Definition: BelleCrystal.h:37
std::vector< Plane_t > fPlanes
vector of planes
Definition: BelleCrystal.h:146
G4GeometryType GetEntityType() const
Get entity type.
void DescribeYourselfTo(G4VGraphicsScene &scene) const
Visualisation functions.
const unsigned int * ivertx(unsigned int i) const
get the ith vertex
G4ThreeVector GetPointOnTriangle(int) const
Returns a random point on the surface of one of the faces.
G4Polyhedron * CreatePolyhedron() const
create polyhedron
G4bool MakePlane(const G4ThreeVector &p1, const G4ThreeVector &p2, const G4ThreeVector &p3, const G4ThreeVector &p4, Plane_t &plane) const
Calculate the coef's of the plane p1->p2->p3->p4->p1 where the ThreeVectors 1-4 are in anti-clockwise...
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const
Two vectors define an axis-parallel bounding box for the shape.
double area(int, double &) const
triangle area
G4double GetCubicVolume()
get the Cubic volume
G4ThreeVector vertex(unsigned int i) const
return ith vertex
BelleCrystal & operator=(const BelleCrystal &rhs)
assignment operator
G4ThreeVector GetPointOnSurface() const
get point on surface
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
calculate the extent of the volume
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
Calculate side nearest to p, and return normal.
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
Calculate exact shortest distance to any boundary from outside.
virtual ~BelleCrystal()
Destructor.
G4VSolid * Clone() const
Make a clone of the object.
std::ostream & StreamInfo(std::ostream &os) const
Stream object contents to an output stream.
std::vector< double > fareas
vector of area values
Definition: BelleCrystal.h:149
double getvolarea() const
get volume area
EInside Inside(const G4ThreeVector &p) const
Return whether point inside/outside/on surface, using tolerance.
std::vector< Point_t > fx
vector of points
Definition: BelleCrystal.h:147
G4double GetSurfaceArea()
get the surface area
BelleCrystal(const G4String &pName)
Constructor for "nominal" BelleCrystal.
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
compute the dimensions
unsigned int nsides
the number of sides
Definition: BelleCrystal.h:144
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=0, G4ThreeVector *n=0) const
Calculate exact shortest distance to any boundary from inside.
Belle crystal in polyhedron.
Definition: BelleCrystal.h:153
PolyhedronBelleCrystal(int, const G4ThreeVector *)
constructor
virtual ~PolyhedronBelleCrystal()
destructor
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.
struct for plane
Definition: BelleCrystal.h:24
G4ThreeVector n
Normal unit vector (a,b,c)
Definition: BelleCrystal.h:25
double d
offset (d)
Definition: BelleCrystal.h:26
struct for Point
Definition: BelleCrystal.h:31
double y
y coordinate
Definition: BelleCrystal.h:33
double x
x coordinate
Definition: BelleCrystal.h:32