File: TestEstimateSurfaceArea.cpp

package info (click to toggle)
vecgeom 1.2.8%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 24,016 kB
  • sloc: cpp: 88,803; ansic: 6,888; python: 1,035; sh: 582; sql: 538; makefile: 23
file content (358 lines) | stat: -rw-r--r-- 13,041 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
//
// File:    TestEstimateSurfaceArea.cpp
// Purpose: test and benchmark the algorithm in VUnplacedVolume::EstimateSurfaceArea()
// Author:  Evgueni Tcherniaev (evgueni.tcherniaev@cern.ch)

// ensure asserts are compiled in
#undef NDEBUG

#include <cmath>
#include <ctime>
#include "VecGeom/base/Vector3D.h"
#include "VecGeom/volumes/Box.h"
#include "VecGeom/volumes/Trd.h"
#include "VecGeom/volumes/Tube.h"
#include "VecGeom/volumes/Cone.h"
#include "VecGeom/volumes/ScaledShape.h"
#include "VecGeom/volumes/BooleanVolume.h"

using namespace vecgeom;
using Vec3D_t = Vector3D<Precision>;

double error(double real, double expected)
{
  double err = (expected == 0 && real != 0) ? 100 : 0;
  if (expected != 0) {
    err = (int(10000. * (real - expected) / expected)) / 100.;
  }
  return err;
};

/*
/////////////////////////////////////////////////////////////////////////////////
//
// Former algorithm for the surface area estimation. The algorithm does not
// work properly when Safety is underestimated, for example, in case of
// Scaled solids. It has been replaced with the six-point algorithm
// in October 2018 (Geant4 10.05)
//
double EstimateArea_Safety(const VPlacedVolume *solid, int nStat)
{
  double ell = -1.;
  Vec3D_t p;
  Vec3D_t minCorner;
  Vec3D_t maxCorner;
  Vec3D_t delta;

  // min max extents of pSolid along X,Y,Z
  solid->Extent(minCorner, maxCorner);

  // limits
  delta = maxCorner - minCorner;

  if (ell <= 0.) // Automatic definition of skin thickness
  {
    Precision minval = delta.x();
    if (delta.y() < delta.x()) {
      minval = delta.y();
    }
    if (delta.z() < minval) {
      minval = delta.z();
    }
    ell = .01 * minval;
  }

  Precision dd = 2 * ell;
  minCorner.x() -= ell;
  minCorner.y() -= ell;
  minCorner.z() -= ell;
  delta.x() += dd;
  delta.y() += dd;
  delta.z() += dd;

  int inside = 0;
  for (int i = 0; i < nStat; ++i) {
    p = minCorner + Vec3D_t(delta.x() * RNG::Instance().uniform(), delta.y() * RNG::Instance().uniform(),
                            delta.z() * RNG::Instance().uniform());
    if (solid->Contains(p)) {
      if (solid->SafetyToOut(p) < ell) {
        inside++;
      }
    } else {
      if (solid->SafetyToIn(p) < ell) {
        inside++;
      }
    }
  }
  // @@ The conformal correction can be upgraded
  return delta.x() * delta.y() * delta.z() * inside / dd / nStat;
}
*/

/////////////////////////////////////////////////////////////////////////////////
//
// Benchmark the surface area estimation algorithm(s)
//
void BenchEstimateArea(const VPlacedVolume *solid, double area)
{
  clock_t t;
  double a1e5 = 0;
  double a1e6 = 0;
  double a1e7 = 0;

  /*
  // Test EstimateArea_Safety()
  //
  std::cout << "\n=== Old algorithm based on Safety (replaced in Geant4 10.05)" << std::endl;
  t    = clock();
  a1e5 = EstimateArea_Safety(solid, 100000);
  a1e6 = EstimateArea_Safety(solid, 1000000);
  a1e7 = EstimateArea_Safety(solid, 10000000);
  std::cout << "N = 10^5   Estimated Area = " << a1e5 << " (" << error(a1e5, area) << "%) " << std::endl;
  std::cout << "N = 10^6   Estimated Area = " << a1e6 << " (" << error(a1e6, area) << "%) " << std::endl;
  std::cout << "N = 10^7   Estimated Area = " << a1e7 << " (" << error(a1e7, area) << "%) " << std::endl;
  t = clock() - t;
  std::cout << "   Time: " << (double)t / CLOCKS_PER_SEC << " sec" << std::endl;
  */

  // Test G4VSolid::EstimateSurfaceArea()
  //
  std::cout << "\n=== Current VUnplacedVolume::EstimateSurfaceArea()" << std::endl;
  t    = clock();
  a1e5 = (solid->GetUnplacedVolume())->EstimateSurfaceArea(100000);
  a1e6 = (solid->GetUnplacedVolume())->EstimateSurfaceArea(1000000);
  a1e7 = (solid->GetUnplacedVolume())->EstimateSurfaceArea(10000000);
  std::cout << "N = 10^5   Estimated Area = " << a1e5 << " (" << error(a1e5, area) << "%) " << std::endl;
  std::cout << "N = 10^6   Estimated Area = " << a1e6 << " (" << error(a1e6, area) << "%) " << std::endl;
  std::cout << "N = 10^7   Estimated Area = " << a1e7 << " (" << error(a1e7, area) << "%) " << std::endl;
  t = clock() - t;
  std::cout << "   Time: " << (double)t / CLOCKS_PER_SEC << " sec" << std::endl;
}

/////////////////////////////////////////////////////////////////////////////////
//
void TestScaledTrd()
{
  double dx1 = 200, dx2 = 100, dy1 = 200, dy2 = 100, dz = 800;
  VPlacedVolume *trd = new SimpleTrd("Trd", dx1, dx2, dy1, dy2, dz);

  double sx = 3, sy = 2, sz = 0.2;
  VPlacedVolume *solid = new SimpleScaledShape("Scaled Trd", trd, sx, sy, sz);

  dx1 *= sx;
  dx2 *= sx;
  dy1 *= sy;
  dy2 *= sy;
  dz *= sz;
  double area = 4 * (dx1 * dy1 + dx2 * dy2) + 2 * (dy1 + dy2) * std::hypot(dx1 - dx2, 2 * dz) +
                2 * (dx1 + dx2) * std::hypot(dy1 - dy2, 2 * dz);
  std::cout << "\n*********************************************************"
            << "\n*** Test Scaled Trd - Scale factors (" << sx << ", " << sy << ", " << sz << ")"
            << " *** Surface area : " << area << "\n***" << std::endl;
  std::cout << "Trd->SurfaceArea()    : " << trd->SurfaceArea() << std::endl;
  double surf_area = solid->SurfaceArea();
  std::cout << "solid->SurfaceAarea() : " << surf_area << " (" << error(surf_area, area) << "%) " << std::endl;

  BenchEstimateArea(solid, area);
}

/////////////////////////////////////////////////////////////////////////////////
//
void TestScaledCone()
{
  double rminus = 50, rplus = 10, dz = 50;
  VPlacedVolume *cone = new SimpleCone("Cone", 0, rminus, 0, rplus, dz, 0, kTwoPi);

  double sx = 10, sy = 5, sz = 2;
  VPlacedVolume *solid = new SimpleScaledShape("Scaled Cone", cone, sx, sy, sz);

  double area = 887358;
  std::cout << "\n*********************************************************"
            << "\n*** Test Scaled Cone - Scale factors (" << sx << ", " << sy << ", " << sz << ")"
            << " *** Surface area : " << area << "\n***" << std::endl;
  std::cout << "Cone->SurfaceArea()   : " << cone->SurfaceArea() << std::endl;
  double surf_area = solid->SurfaceArea();
  std::cout << "solid->SurfaceAarea() : " << surf_area << " (" << error(surf_area, area) << "%) " << std::endl;

  BenchEstimateArea(solid, area);
}

/////////////////////////////////////////////////////////////////////////////////
//
void TestUnionSolid()
{
  double rbig = 100, zbig = 100;
  GenericUnplacedTube big(0, rbig, zbig, 0, kTwoPi);
  LogicalVolume lbig("Big Tube", &big);
  auto pbig = lbig.Place();

  double rsml = 25, zsml = 170;
  GenericUnplacedTube small(0, rsml, zsml, 0, kTwoPi);
  LogicalVolume lsmall("Small Tube", &small);

  double offset = 60;
  auto psmall0  = lsmall.Place();
  auto psmall1  = lsmall.Place(new Transformation3D(offset, 0, 0));
  auto psmall2  = lsmall.Place(new Transformation3D(-offset, 0, 0));
  auto psmall3  = lsmall.Place(new Transformation3D(0, offset, 0));
  auto psmall4  = lsmall.Place(new Transformation3D(0, -offset, 0));

  UnplacedBooleanVolume<kUnion> union1(kUnion, pbig, psmall0);
  LogicalVolume lsolid1("Union_1", &union1);
  auto psolid1 = lsolid1.Place();

  UnplacedBooleanVolume<kUnion> union2(kUnion, psolid1, psmall1);
  LogicalVolume lsolid2("Union_2", &union2);
  auto psolid2 = lsolid2.Place();

  UnplacedBooleanVolume<kUnion> union3(kUnion, psolid2, psmall2);
  LogicalVolume lsolid3("Union_3", &union3);
  auto psolid3 = lsolid3.Place();

  UnplacedBooleanVolume<kUnion> union4(kUnion, psolid3, psmall3);
  LogicalVolume lsolid4("Union_4", &union4);
  auto psolid4 = lsolid4.Place();

  UnplacedBooleanVolume<kUnion> union5(kUnion, psolid4, psmall4);
  LogicalVolume lsolid5("Union_5", &union5);
  auto psolid5 = lsolid5.Place();

  double sbig = 2 * zbig * kTwoPi * rbig + 2 * kPi * rbig * rbig;
  double sadd = 2 * (zsml - zbig) * kTwoPi * rsml;
  double area = sbig + 5 * sadd;
  std::cout << "\n*********************************************************"
            << "\n*** Test Union Solid - Disk plus 5 cylinders *** Surface area : " << area << "\n***" << std::endl;
  std::cout << "Disk area         : " << sbig << std::endl;
  std::cout << "Increment area    : " << sadd << std::endl;
  std::cout << "Real surface area : " << area << std::endl;
  double surf_area = psolid5->SurfaceArea();
  std::cout << "solid->SurfaceAarea() : " << surf_area << " (" << error(surf_area, area) << "%) " << std::endl;

  BenchEstimateArea(psolid5, area);
}

/////////////////////////////////////////////////////////////////////////////////
//
void TestSubtractionSolid()
{
  double rbig = 100, zbig = 100;
  GenericUnplacedTube big(0, rbig, zbig, 0, kTwoPi);
  LogicalVolume lbig("Big Tube", &big);
  auto pbig = lbig.Place();

  double rsml = 25, zsml = 170;
  GenericUnplacedTube small(0, rsml, zsml, 0, kTwoPi);
  LogicalVolume lsmall("Small Tube", &small);

  double offset = 60;
  auto psmall0  = lsmall.Place();
  auto psmall1  = lsmall.Place(new Transformation3D(offset, 0, 0));
  auto psmall2  = lsmall.Place(new Transformation3D(-offset, 0, 0));
  auto psmall3  = lsmall.Place(new Transformation3D(0, offset, 0));
  auto psmall4  = lsmall.Place(new Transformation3D(0, -offset, 0));

  UnplacedBooleanVolume<kSubtraction> union1(kSubtraction, pbig, psmall0);
  LogicalVolume lsolid1("Subtraction_1", &union1);
  auto psolid1 = lsolid1.Place();

  UnplacedBooleanVolume<kSubtraction> union2(kSubtraction, psolid1, psmall1);
  LogicalVolume lsolid2("Subtraction_2", &union2);
  auto psolid2 = lsolid2.Place();

  UnplacedBooleanVolume<kSubtraction> union3(kSubtraction, psolid2, psmall2);
  LogicalVolume lsolid3("Subtraction_3", &union3);
  auto psolid3 = lsolid3.Place();

  UnplacedBooleanVolume<kSubtraction> union4(kSubtraction, psolid3, psmall3);
  LogicalVolume lsolid4("Subtraction_4", &union4);
  auto psolid4 = lsolid4.Place();

  UnplacedBooleanVolume<kSubtraction> union5(kSubtraction, psolid4, psmall4);
  LogicalVolume lsolid5("Subtraction_5", &union5);
  auto psolid5 = lsolid5.Place();

  double sbig  = 2 * zbig * kTwoPi * rbig + 2 * kPi * rbig * rbig;
  double shole = 2 * zbig * kTwoPi * rsml - 2 * kPi * rsml * rsml;
  double area  = sbig + 5 * shole;
  std::cout << "\n*********************************************************"
            << "\n*** Test Subtraction Solid - Disk with 5 holes *** Surface area : " << area << "\n***" << std::endl;
  std::cout << "Disk area         : " << sbig << std::endl;
  std::cout << "Increment area    : " << shole << std::endl;
  std::cout << "Real surface area : " << area << std::endl;
  double surf_area = psolid5->SurfaceArea();
  std::cout << "solid->SurfaceAarea() : " << surf_area << " (" << error(surf_area, area) << "%) " << std::endl;

  BenchEstimateArea(psolid5, area);
}

/////////////////////////////////////////////////////////////////////////////////
//
void TestIntersectionSolid()
{
  double dx = 100, dy1 = 50, dy2 = 80, dz = 500;
  UnplacedBox box1(dx, dy1, dz);
  LogicalVolume lbox1("box1", &box1);
  auto pbox1 = lbox1.Place();

  UnplacedBox box2(dx, dy2, dz);
  LogicalVolume lbox2("box2", &box2);
  double ang = 60;
  auto pbox2 = lbox2.Place(new Transformation3D(0, 0, 0, 0, ang, 0));

  UnplacedBooleanVolume<kIntersection> solid(kIntersection, pbox1, pbox2);
  LogicalVolume lsolid("Intersection", &solid);
  auto psolid = lsolid.Place();

  double deg  = kPi / 180;
  double side = 2 * dx / Sin(ang * deg);
  double area = 4 * dx * side + 8 * side * Min(dy1, dy2);
  std::cout << "\n*********************************************************"
            << "\n*** Test Intersection Solid - two intersecting bars *** Surface area : " << area << "\n***"
            << std::endl;
  double surf_area = psolid->SurfaceArea();
  std::cout << "solid->SurfaceAarea() : " << surf_area << " (" << error(surf_area, area) << "%) " << std::endl;

  BenchEstimateArea(psolid, area);
}

/////////////////////////////////////////////////////////////////////////////////
//
void TestSubtractionNull()
{
  double dbig = 100;
  UnplacedBox big(dbig, dbig, dbig);
  LogicalVolume lbig("Big Box", &big);
  auto pbig = lbig.Place();

  double dsml = 10;
  UnplacedBox sml(dsml, dsml, dsml);
  LogicalVolume lsml("Sml Box", &sml);
  auto psml = lsml.Place();

  UnplacedBooleanVolume<kSubtraction> solid(kSubtraction, psml, pbig);
  LogicalVolume lsolid("Null", &solid);
  auto psolid = lsolid.Place();

  double area = 0;
  std::cout << "\n*********************************************************"
            << "\n*** Test Subtraction Solid - Null object *** Surface area: " << area << "\n***" << std::endl;
  std::cout << "Big box area      : " << pbig->SurfaceArea() << std::endl;
  std::cout << "Small box area    : " << psml->SurfaceArea() << std::endl;
  double surf_area = psolid->SurfaceArea();
  std::cout << "solid->SurfaceAarea() : " << surf_area << " (" << error(surf_area, area) << "%) " << std::endl;

  BenchEstimateArea(psolid, area);
}

/////////////////////////////////////////////////////////////////////////////////
//
int main()
{
  TestScaledTrd();
  TestScaledCone();
  TestUnionSolid();
  TestSubtractionSolid();
  TestIntersectionSolid();
  TestSubtractionNull();
  return 0;
}