Belle II Software development
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
21using namespace Belle2;
22using namespace std;
23using 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
32int 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
45const G4double kCoplanar_Tolerance = 1E-4;
46
47BelleCrystal::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
145BelleCrystal::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// in front 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
198G4bool 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 << "Vertices 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.
230void 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
242G4ThreeVector 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
248G4ThreeVector 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
254G4bool 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
298EInside 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)
324G4ThreeVector 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
382G4double 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
405G4double 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
430G4double 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);
459exit:
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
474G4double 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) // definitely outside
487 {
488 lmin = 0; iside = i; return true;
489 } else
490 {
491 bool c = nv > 0;
492 if (d < -delta) { // definitely 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);
515exit:
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
541G4GeometryType BelleCrystal::GetEntityType() const
542{
543 return G4String("BelleCrystal");
544}
545
546// Make a clone of the object
547G4VSolid* BelleCrystal::Clone() const
548{
549 return new BelleCrystal(*this);
550}
551
552// Stream object contents to an output stream
553std::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
569unsigned 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}};
570unsigned 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
572const 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
598G4ThreeVector 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))
612G4ThreeVector 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
634G4ThreeVector 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
648double 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
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
703void BelleCrystal::DescribeYourselfTo(G4VGraphicsScene& scene) const
704{
705 scene.AddSolid(*this);
706}
707
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
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
733void 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.
STL namespace.
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