ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4Voxelizer.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4Voxelizer.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 // G4Voxelizer implementation
27 //
28 // 19.10.12 Marek Gayer, created
29 // --------------------------------------------------------------------
30 
31 #include <iostream>
32 #include <iomanip>
33 #include <sstream>
34 #include <algorithm>
35 #include <set>
36 
37 #include "G4VSolid.hh"
38 
39 #include "G4Orb.hh"
40 #include "G4Voxelizer.hh"
41 #include "G4SolidStore.hh"
42 #include "Randomize.hh"
43 #include "G4PhysicalConstants.hh"
44 #include "G4GeometryTolerance.hh"
45 #include "G4CSGSolid.hh"
46 #include "G4Orb.hh"
47 #include "G4Types.hh"
48 #include "geomdefs.hh"
49 
50 using namespace std;
51 
53 
54 //______________________________________________________________________________
56  : fBoundingBox("VoxBBox", 1, 1, 1)
57 {
59 
61 
63 
65 }
66 
67 //______________________________________________________________________________
69 {
70 }
71 
72 //______________________________________________________________________________
74 {
75  // by reserving the size of candidates, we would avoid reallocation of
76  // the vector which could cause fragmentation
77  //
78  std::vector<G4int> xyz(3), max(3), candidates(fTotalCandidates);
79  const std::vector<G4int> empty(0);
80 
81  for (auto i = 0; i <= 2; ++i) max[i] = fBoundaries[i].size();
82  unsigned int size = max[0] * max[1] * max[2];
83 
84  fEmpty.Clear();
85  fEmpty.ResetBitNumber(size-1);
86  fEmpty.ResetAllBits(true);
87 
88  for (xyz[2] = 0; xyz[2] < max[2]; ++xyz[2])
89  {
90  for (xyz[1] = 0; xyz[1] < max[1]; ++xyz[1])
91  {
92  for (xyz[0] = 0; xyz[0] < max[0]; ++xyz[0])
93  {
94  if (GetCandidatesVoxelArray(xyz, candidates))
95  {
96  G4int index = GetVoxelsIndex(xyz);
97  fEmpty.SetBitNumber(index, false);
98 
99  // rather than assigning directly with:
100  // "fCandidates[index] = candidates;", in an effort to ensure that
101  // capacity would be just exact, we rather use following 3 lines
102  //
103  std::vector<G4int> &c = (fCandidates[index] = empty);
104  c.reserve(candidates.size());
105  c.assign(candidates.begin(), candidates.end());
106  }
107  }
108  }
109  }
110 #ifdef G4SPECSDEBUG
111  G4cout << "Non-empty voxels count: " << fCandidates.size() << G4endl;
112 #endif
113 }
114 
115 //______________________________________________________________________________
116 void G4Voxelizer::BuildVoxelLimits(std::vector<G4VSolid*>& solids,
117  std::vector<G4Transform3D>& transforms)
118 {
119  G4Rotate3D rot;
120  G4Translate3D transl ;
122 
123  // "BuildVoxelLimits"'s aim is to store the coordinates of the origin as
124  // well as the half lengths related to the bounding box of each node.
125  // These quantities are stored in the array "fBoxes" (6 different values per
126  // node
127  //
128  if (G4int numNodes = solids.size()) // Number of nodes in "multiUnion"
129  {
130  fBoxes.resize(numNodes); // Array which will store the half lengths
131  fNPerSlice = 1 + (fBoxes.size() - 1) / (8 * sizeof(unsigned int));
132 
133  // related to a particular node, but also
134  // the coordinates of its origin
135 
137 
138  for (G4int i = 0; i < numNodes; ++i)
139  {
140  G4VSolid& solid = *solids[i];
141  G4Transform3D transform = transforms[i];
143 
144  solid.BoundingLimits(min, max);
145  if (solid.GetEntityType() == "G4Orb")
146  {
147  G4Orb& orb = *(G4Orb*) &solid;
148  G4ThreeVector orbToleranceVector;
149  G4double tolerance = orb.GetRadialTolerance() / 2.0;
150  orbToleranceVector.set(tolerance,tolerance,tolerance);
151  min -= orbToleranceVector;
152  max += orbToleranceVector;
153  }
154  else
155  {
156  min -= toleranceVector;
157  max += toleranceVector;
158  }
159  TransformLimits(min, max, transform);
160  fBoxes[i].hlen = (max - min) / 2;
161  transform.getDecomposition(scale,rot,transl);
162  fBoxes[i].pos = transl.getTranslation();
163  }
164  fTotalCandidates = fBoxes.size();
165  }
166 }
167 
168 //______________________________________________________________________________
169 void G4Voxelizer::BuildVoxelLimits(std::vector<G4VFacet*>& facets)
170 {
171  // "BuildVoxelLimits"'s aim is to store the coordinates of the origin as well
172  // as the half lengths related to the bounding box of each node.
173  // These quantities are stored in the array "fBoxes" (6 different values per
174  // node.
175 
176  if (G4int numNodes = facets.size()) // Number of nodes
177  {
178  fBoxes.resize(numNodes); // Array which will store the half lengths
179  fNPerSlice = 1+(fBoxes.size()-1)/(8*sizeof(unsigned int));
180 
181  G4ThreeVector toleranceVector(10*fTolerance, 10*fTolerance, 10*fTolerance);
182 
183  for (G4int i = 0; i < numNodes; ++i)
184  {
185  G4VFacet &facet = *facets[i];
187  G4ThreeVector x(1,0,0), y(0,1,0), z(0,0,1);
188  G4ThreeVector extent;
189  max.set (facet.Extent(x), facet.Extent(y), facet.Extent(z));
190  min.set (-facet.Extent(-x), -facet.Extent(-y), -facet.Extent(-z));
191  min -= toleranceVector;
192  max += toleranceVector;
193  G4ThreeVector hlen = (max - min) / 2;
194  fBoxes[i].hlen = hlen;
195  fBoxes[i].pos = min + hlen;
196  }
197  fTotalCandidates = fBoxes.size();
198  }
199 }
200 
201 //______________________________________________________________________________
203 {
204  // "DisplayVoxelLimits" displays the dX, dY, dZ, pX, pY and pZ for each node
205 
206  G4int numNodes = fBoxes.size();
207  G4int oldprec = G4cout.precision(16);
208  for(G4int i = 0; i < numNodes; ++i)
209  {
210  G4cout << setw(10) << setiosflags(ios::fixed) <<
211  " -> Node " << i+1 << ":\n" <<
212  "\t * [x,y,z] = " << fBoxes[i].hlen <<
213  "\t * [x,y,z] = " << fBoxes[i].pos << "\n";
214  }
215  G4cout.precision(oldprec);
216 }
217 
218 //______________________________________________________________________________
219 void G4Voxelizer::CreateSortedBoundary(std::vector<G4double>& boundary,
220  G4int axis)
221 {
222  // "CreateBoundaries"'s aim is to determine the slices induced by the
223  // bounding fBoxes, along each axis. The created boundaries are stored
224  // in the array "boundariesRaw"
225 
226  G4int numNodes = fBoxes.size(); // Number of nodes in structure
227 
228  // Determination of the boundaries along x, y and z axis
229  //
230  for(G4int i = 0 ; i < numNodes; ++i)
231  {
232  // For each node, the boundaries are created by using the array "fBoxes"
233  // built in method "BuildVoxelLimits"
234  //
235  G4double p = fBoxes[i].pos[axis], d = fBoxes[i].hlen[axis];
236 
237  // x boundaries
238  //
239 #ifdef G4SPECSDEBUG
240  G4cout << "Boundary " << p - d << " - " << p + d << G4endl;
241 #endif
242  boundary[2*i] = p - d;
243  boundary[2*i+1] = p + d;
244  }
245  std::sort(boundary.begin(), boundary.end());
246 }
247 
248 //______________________________________________________________________________
250 {
251  // "SortBoundaries" orders the boundaries along each axis (increasing order)
252  // and also does not take into account redundant boundaries, i.e. if two
253  // boundaries are separated by a distance strictly inferior to "tolerance".
254  // The sorted boundaries are respectively stored in:
255  // * boundaries[0..2]
256 
257  // In addition, the number of elements contained in the three latter arrays
258  // are precise thanks to variables: boundariesCountX, boundariesCountY and
259  // boundariesCountZ.
260 
261  if (G4int numNodes = fBoxes.size())
262  {
263  const G4double tolerance = fTolerance / 100.0;
264  // Minimal distance to discriminate two boundaries.
265 
266  std::vector<G4double> sortedBoundary(2*numNodes);
267 
268  G4int considered;
269 
270  for (auto j = 0; j <= 2; ++j)
271  {
272  CreateSortedBoundary(sortedBoundary, j);
273  std::vector<G4double> &boundary = fBoundaries[j];
274  boundary.clear();
275 
276  considered = 0;
277 
278  for(G4int i = 0 ; i < 2*numNodes; ++i)
279  {
280  G4double newBoundary = sortedBoundary[i];
281 #ifdef G4SPECSDEBUG
282  if (j == 0) G4cout << "Examining " << newBoundary << "..." << G4endl;
283 #endif
284  G4int size = boundary.size();
285  if(!size || std::abs(boundary[size-1] - newBoundary) > tolerance)
286  {
287  considered++;
288  {
289 #ifdef G4SPECSDEBUG
290  if (j == 0) G4cout << "Adding boundary " << newBoundary << "..."
291  << G4endl;
292 #endif
293  boundary.push_back(newBoundary);
294  continue;
295  }
296  }
297  // If two successive boundaries are too close from each other,
298  // only the first one is considered
299  }
300 
301  G4int n = boundary.size();
302  G4int max = 100000;
303  if (n > max/2)
304  {
305  G4int skip = n / (max /2); // n has to be 2x bigger then 50.000.
306  // therefore only from 100.000 reduced
307  std::vector<G4double> reduced;
308  for (G4int i = 0; i < n; ++i)
309  {
310  // 50 ok for 2k, 1000, 2000
311  G4int size = boundary.size();
312  if (i % skip == 0 || i == 0 || i == size - 1)
313  {
314  // this condition of merging boundaries was wrong,
315  // it did not count with right part, which can be
316  // completely ommited and not included in final consideration.
317  // Now should be OK
318  //
319  reduced.push_back(boundary[i]);
320  }
321  }
322  boundary = reduced;
323  }
324  }
325  }
326 }
327 
328 //______________________________________________________________________________
330 {
331  char axis[3] = {'X', 'Y', 'Z'};
332  for (auto i = 0; i <= 2; ++i)
333  {
334  G4cout << " * " << axis[i] << " axis:" << G4endl << " | ";
336  }
337 }
338 
339 //______________________________________________________________________________
340 void G4Voxelizer::DisplayBoundaries(std::vector<G4double> &boundaries)
341 {
342  // Prints the positions of the boundaries of the slices on the three axes
343 
344  G4int count = boundaries.size();
345  G4int oldprec = G4cout.precision(16);
346  for(G4int i = 0; i < count; ++i)
347  {
348  G4cout << setw(10) << setiosflags(ios::fixed) << boundaries[i];
349  if(i != count-1) G4cout << "-> ";
350  }
351  G4cout << "|" << G4endl << "Number of boundaries: " << count << G4endl;
352  G4cout.precision(oldprec);
353 }
354 
355 //______________________________________________________________________________
356 void G4Voxelizer::BuildBitmasks(std::vector<G4double> boundaries[],
357  G4SurfBits bitmasks[], G4bool countsOnly)
358 {
359  // "BuildListNodes" stores in the bitmasks solids present in each slice
360  // along an axis.
361 
362  G4int numNodes = fBoxes.size();
363  G4int bitsPerSlice = GetBitsPerSlice();
364 
365  for (auto k = 0; k < 3; ++k)
366  {
367  G4int total = 0;
368  std::vector<G4double>& boundary = boundaries[k];
369  G4int voxelsCount = boundary.size() - 1;
370  G4SurfBits& bitmask = bitmasks[k];
371 
372  if (!countsOnly)
373  {
374  bitmask.Clear();
375 #ifdef G4SPECSDEBUG
376  G4cout << "Allocating bitmask..." << G4endl;
377 #endif
378  bitmask.SetBitNumber(voxelsCount*bitsPerSlice-1, false);
379  // it is here so we can set the maximum number of bits. this line
380  // will rellocate the memory and set all to zero
381  }
382  std::vector<G4int>& candidatesCount = fCandidatesCounts[k];
383  candidatesCount.resize(voxelsCount);
384 
385  for(G4int i = 0 ; i < voxelsCount; ++i) { candidatesCount[i] = 0; }
386 
387  // Loop on the nodes, number of slices per axis
388  //
389  for(G4int j = 0 ; j < numNodes; ++j)
390  {
391  // Determination of the minimum and maximum position along x
392  // of the bounding boxe of each node
393  //
394  G4double p = fBoxes[j].pos[k], d = fBoxes[j].hlen[k];
395 
396  G4double min = p - d; // - localTolerance;
397  G4double max = p + d; // + localTolerance;
398 
399  G4int i = BinarySearch(boundary, min);
400  if (i < 0) { i = 0; }
401 
402  do // Loop checking, 13.08.2015, G.Cosmo
403  {
404  if (!countsOnly)
405  {
406  bitmask.SetBitNumber(i*bitsPerSlice+j);
407  }
408  candidatesCount[i]++;
409  ++total;
410  ++i;
411  }
412  while (max > boundary[i] && i < voxelsCount);
413  }
414  }
415 #ifdef G4SPECSDEBUG
416  G4cout << "Build list nodes completed." << G4endl;
417 #endif
418 }
419 
420 //______________________________________________________________________________
422 {
423  // Decodes the candidates in mask as G4String.
424 
425  stringstream ss;
426  G4int numNodes = fBoxes.size();
427 
428  for(G4int i=0; i<numNodes; ++i)
429  {
430  if (bits.TestBitNumber(i)) { ss << i+1 << " "; }
431  }
432  return ss.str();
433 }
434 
435 //______________________________________________________________________________
437 {
438  // Prints which solids are present in the slices previously elaborated.
439 
440  char axis[3] = {'X', 'Y', 'Z'};
441  G4int size=8*sizeof(G4int)*fNPerSlice;
442  G4SurfBits bits(size);
443 
444  for (auto j = 0; j <= 2; ++j)
445  {
446  G4cout << " * " << axis[j] << " axis:" << G4endl;
447  G4int count = fBoundaries[j].size();
448  for(G4int i=0; i < count-1; ++i)
449  {
450  G4cout << " Slice #" << i+1 << ": [" << fBoundaries[j][i]
451  << " ; " << fBoundaries[j][i+1] << "] -> ";
452  bits.set(size,(const char *)fBitmasks[j].fAllBits+i
453  *fNPerSlice*sizeof(G4int));
454  G4String result = GetCandidatesAsString(bits);
455  G4cout << "[ " << result.c_str() << "] " << G4endl;
456  }
457  }
458 }
459 
460 //______________________________________________________________________________
462 {
463  G4ThreeVector min(fBoundaries[0].front(),
464  fBoundaries[1].front(),
465  fBoundaries[2].front());
466  G4ThreeVector max(fBoundaries[0].back(),
467  fBoundaries[1].back(),
468  fBoundaries[2].back());
469  BuildBoundingBox(min, max);
470 }
471 
472 //______________________________________________________________________________
474  G4ThreeVector& amax,
475  G4double tolerance)
476 {
477  for (auto i = 0; i <= 2; ++i)
478  {
479  G4double min = amin[i];
480  G4double max = amax[i];
481  fBoundingBoxSize[i] = (max - min) / 2 + tolerance * 0.5;
482  fBoundingBoxCenter[i] = min + fBoundingBoxSize[i];
483  }
487 }
488 
489 // algorithm -
490 
491 // in order to get balanced voxels, merge should always unite those regions,
492 // where the number of voxels is least the number.
493 // We will keep sorted list (std::set) with all voxels. there will be
494 // comparator function between two voxels, which will tell if voxel is less
495 // by looking at his right neighbor.
496 // First, we will add all the voxels into the tree.
497 // We will be pick the first item in the tree, merging it, adding the right
498 // merged voxel into the a list for future reduction (fBitmasks will be
499 // rebuilded later, therefore they need not to be updated).
500 // The merged voxel need to be added to the tree again, so it's position
501 // would be updated.
502 
503 //______________________________________________________________________________
505  G4ThreeVector& reductionRatio)
506 {
507  G4double maxTotal = (G4double) fCandidatesCounts[0].size()
508  * fCandidatesCounts[1].size() * fCandidatesCounts[2].size();
509 
510  if (maxVoxels > 0 && maxVoxels < maxTotal)
511  {
512  G4double ratio = (G4double) maxVoxels / maxTotal;
513  ratio = std::pow(ratio, 1./3.);
514  if (ratio > 1) { ratio = 1; }
515  reductionRatio.set(ratio,ratio,ratio);
516  }
517 }
518 
519 //______________________________________________________________________________
520 void G4Voxelizer::BuildReduceVoxels(std::vector<G4double> boundaries[],
521  G4ThreeVector reductionRatio)
522 {
523  for (auto k = 0; k <= 2; ++k)
524  {
525  std::vector<G4int> &candidatesCount = fCandidatesCounts[k];
526  G4int max = candidatesCount.size();
527  std::vector<G4VoxelInfo> voxels(max);
528  G4VoxelComparator comp(voxels);
529  std::set<G4int, G4VoxelComparator> voxelSet(comp);
530  std::vector<G4int> mergings;
531 
532  for (G4int j = 0; j < max; ++j)
533  {
534  G4VoxelInfo &voxel = voxels[j];
535  voxel.count = candidatesCount[j];
536  voxel.previous = j - 1;
537  voxel.next = j + 1;
538  voxels[j] = voxel;
539  }
540 
541  for (G4int j = 0; j < max - 1; ++j) { voxelSet.insert(j); }
542  // we go to size-1 to make sure we will not merge the last element
543 
544  G4double reduction = reductionRatio[k];
545  if (reduction != 0)
546  {
547  G4int count = 0, currentCount;
548  while ((currentCount = voxelSet.size()) > 2)
549  {
550  G4double currentRatio = 1 - (G4double) count / max;
551  if ((currentRatio <= reduction) && (currentCount <= 1000))
552  break;
553  const G4int pos = *voxelSet.begin();
554  mergings.push_back(pos + 1);
555 
556  G4VoxelInfo& voxel = voxels[pos];
557  G4VoxelInfo& nextVoxel = voxels[voxel.next];
558 
559  if (voxelSet.erase(pos) != 1)
560  {
561  ;// k = k;
562  }
563  if (voxel.next != max - 1)
564  if (voxelSet.erase(voxel.next) != 1)
565  {
566  ;// k = k;
567  }
568  if (voxel.previous != -1)
569  if (voxelSet.erase(voxel.previous) != 1)
570  {
571  ;// k = k;
572  }
573  nextVoxel.count += voxel.count;
574  voxel.count = 0;
575  nextVoxel.previous = voxel.previous;
576 
577  if (voxel.next != max - 1)
578  voxelSet.insert(voxel.next);
579 
580  if (voxel.previous != -1)
581  {
582  voxels[voxel.previous].next = voxel.next;
583  voxelSet.insert(voxel.previous);
584  }
585  ++count;
586  } // Loop checking, 13.08.2015, G.Cosmo
587  }
588 
589  if (mergings.size())
590  {
591  std::sort(mergings.begin(), mergings.end());
592 
593  const std::vector<G4double>& boundary = boundaries[k];
594  int mergingsSize = mergings.size();
595  vector<G4double> reducedBoundary;
596  G4int skip = mergings[0], i = 0;
597  max = boundary.size();
598  for (G4int j = 0; j < max; ++j)
599  {
600  if (j != skip)
601  {
602  reducedBoundary.push_back(boundary[j]);
603  }
604  else if (++i < mergingsSize)
605  {
606  skip = mergings[i];
607  }
608  }
609  boundaries[k] = reducedBoundary;
610  }
611 /*
612  G4int count = 0;
613  while (true) // Loop checking, 13.08.2015, G.Cosmo
614  {
615  G4double reduction = reductionRatio[k];
616  if (reduction == 0)
617  break;
618  G4int currentCount = voxelSet.size();
619  if (currentCount <= 2)
620  break;
621  G4double currentRatio = 1 - (G4double) count / max;
622  if (currentRatio <= reduction && currentCount <= 1000)
623  break;
624  const G4int pos = *voxelSet.begin();
625  mergings.push_back(pos);
626 
627  G4VoxelInfo &voxel = voxels[pos];
628  G4VoxelInfo &nextVoxel = voxels[voxel.next];
629 
630  voxelSet.erase(pos);
631  if (voxel.next != max - 1) { voxelSet.erase(voxel.next); }
632  if (voxel.previous != -1) { voxelSet.erase(voxel.previous); }
633 
634  nextVoxel.count += voxel.count;
635  voxel.count = 0;
636  nextVoxel.previous = voxel.previous;
637 
638  if (voxel.next != max - 1)
639  voxelSet.insert(voxel.next);
640 
641  if (voxel.previous != -1)
642  {
643  voxels[voxel.previous].next = voxel.next;
644  voxelSet.insert(voxel.previous);
645  }
646  ++count;
647  }
648 
649  if (mergings.size())
650  {
651  std::sort(mergings.begin(), mergings.end());
652 
653  std::vector<G4double> &boundary = boundaries[k];
654  std::vector<G4double> reducedBoundary(boundary.size() - mergings.size());
655  G4int skip = mergings[0] + 1, cur = 0, i = 0;
656  max = boundary.size();
657  for (G4int j = 0; j < max; ++j)
658  {
659  if (j != skip)
660  {
661  reducedBoundary[cur++] = boundary[j];
662  }
663  else
664  {
665  if (++i < (G4int)mergings.size()) { skip = mergings[i] + 1; }
666  }
667  }
668  boundaries[k] = reducedBoundary;
669  }
670 */
671  }
672 }
673 
674 //______________________________________________________________________________
675 void G4Voxelizer::BuildReduceVoxels2(std::vector<G4double> boundaries[],
676  G4ThreeVector reductionRatio)
677 {
678  for (auto k = 0; k <= 2; ++k)
679  {
680  std::vector<G4int> &candidatesCount = fCandidatesCounts[k];
681  G4int max = candidatesCount.size();
682  G4int total = 0;
683  for (G4int i = 0; i < max; ++i) total += candidatesCount[i];
684 
685  G4double reduction = reductionRatio[k];
686  if (reduction == 0)
687  break;
688 
689  G4int destination = (G4int) (reduction * max) + 1;
690  if (destination > 1000) destination = 1000;
691  if (destination < 2) destination = 2;
692  G4double average = ((G4double)total / max) / reduction;
693 
694  std::vector<G4int> mergings;
695 
696  std::vector<G4double> &boundary = boundaries[k];
697  std::vector<G4double> reducedBoundary(destination);
698 
699  G4int sum = 0, cur = 0;
700  for (G4int i = 0; i < max; ++i)
701  {
702  sum += candidatesCount[i];
703  if (sum > average * (cur + 1) || i == 0)
704  {
705  G4double val = boundary[i];
706  reducedBoundary[cur] = val;
707  ++cur;
708  if (cur == destination)
709  break;
710  }
711  }
712  reducedBoundary[destination-1] = boundary[max];
713  boundaries[k] = reducedBoundary;
714  }
715 }
716 
717 //______________________________________________________________________________
718 void G4Voxelizer::Voxelize(std::vector<G4VSolid*>& solids,
719  std::vector<G4Transform3D>& transforms)
720 {
721  BuildVoxelLimits(solids, transforms);
722  BuildBoundaries();
725  BuildEmpty(); // this does not work well for multi-union,
726  // actually only makes performance slower,
727  // these are only pre-calculated but not used by multi-union
728 
729  for (auto i = 0; i < 3; ++i)
730  {
731  fCandidatesCounts[i].resize(0);
732  }
733 }
734 
735 //______________________________________________________________________________
736 void G4Voxelizer::CreateMiniVoxels(std::vector<G4double> boundaries[],
737  G4SurfBits bitmasks[])
738 {
739  std::vector<G4int> voxel(3), maxVoxels(3);
740  for (auto i = 0; i <= 2; ++i) maxVoxels[i] = boundaries[i].size();
741 
743  for (voxel[2] = 0; voxel[2] < maxVoxels[2] - 1; ++voxel[2])
744  {
745  for (voxel[1] = 0; voxel[1] < maxVoxels[1] - 1; ++voxel[1])
746  {
747  for (voxel[0] = 0; voxel[0] < maxVoxels[0] - 1; ++voxel[0])
748  {
749  std::vector<G4int> candidates;
750  if (GetCandidatesVoxelArray(voxel, bitmasks, candidates, 0))
751  {
752  // find a box for corresponding non-empty voxel
753  G4VoxelBox box;
754  for (auto i = 0; i <= 2; ++i)
755  {
756  G4int index = voxel[i];
757  const std::vector<G4double> &boundary = boundaries[i];
758  G4double hlen = 0.5 * (boundary[index+1] - boundary[index]);
759  box.hlen[i] = hlen;
760  box.pos[i] = boundary[index] + hlen;
761  }
762  fVoxelBoxes.push_back(box);
763  std::vector<G4int>(candidates).swap(candidates);
764  fVoxelBoxesCandidates.push_back(candidates);
765  }
766  }
767  }
768  }
769 }
770 
771 //______________________________________________________________________________
772 void G4Voxelizer::Voxelize(std::vector<G4VFacet*>& facets)
773 {
774  G4int maxVoxels = fMaxVoxels;
775  G4ThreeVector reductionRatio = fReductionRatio;
776 
777  G4int size = facets.size();
778  if (size < 10)
779  {
780  for (G4int i = 0; i < (G4int) facets.size(); ++i)
781  {
782  if (facets[i]->GetNumberOfVertices() > 3) size++;
783  }
784  }
785 
786  if ((size >= 10 || maxVoxels > 0) && maxVoxels != 0 && maxVoxels != 1)
787  {
788 #ifdef G4SPECSDEBUG
789  G4cout << "Building voxel limits..." << G4endl;
790 #endif
791 
792  BuildVoxelLimits(facets);
793 
794 #ifdef G4SPECSDEBUG
795  G4cout << "Building boundaries..." << G4endl;
796 #endif
797 
798  BuildBoundaries();
799 
800 #ifdef G4SPECSDEBUG
801  G4cout << "Building bitmasks..." << G4endl;
802 #endif
803 
804  BuildBitmasks(fBoundaries, 0, true);
805 
806  if (maxVoxels < 0 && reductionRatio == G4ThreeVector())
807  {
808  maxVoxels = fTotalCandidates;
809  if (fTotalCandidates > 1000000) maxVoxels = 1000000;
810  }
811 
812  SetReductionRatio(maxVoxels, reductionRatio);
813 
815 
816 #ifdef G4SPECSDEBUG
817  G4cout << "Total number of voxels: " << fCountOfVoxels << G4endl;
818 #endif
819 
820  BuildReduceVoxels2(fBoundaries, reductionRatio);
821 
823 
824 #ifdef G4SPECSDEBUG
825  G4cout << "Total number of voxels after reduction: "
826  << fCountOfVoxels << G4endl;
827 #endif
828 
829 #ifdef G4SPECSDEBUG
830  G4cout << "Building bitmasks..." << G4endl;
831 #endif
832 
834 
835  G4ThreeVector reductionRatioMini;
836 
837  G4SurfBits bitmasksMini[3];
838 
839  // section for building mini voxels
840 
841  std::vector<G4double> miniBoundaries[3];
842 
843  for (auto i = 0; i <= 2; ++i) { miniBoundaries[i] = fBoundaries[i]; }
844 
845  G4int voxelsCountMini = (fCountOfVoxels >= 1000)
846  ? 100 : fCountOfVoxels / 10;
847 
848  SetReductionRatio(voxelsCountMini, reductionRatioMini);
849 
850 #ifdef G4SPECSDEBUG
851  G4cout << "Building reduced voxels..." << G4endl;
852 #endif
853 
854  BuildReduceVoxels(miniBoundaries, reductionRatioMini);
855 
856 #ifdef G4SPECSDEBUG
857  G4int total = CountVoxels(miniBoundaries);
858  G4cout << "Total number of mini voxels: " << total << G4endl;
859 #endif
860 
861 #ifdef G4SPECSDEBUG
862  G4cout << "Building mini bitmasks..." << G4endl;
863 #endif
864 
865  BuildBitmasks(miniBoundaries, bitmasksMini);
866 
867 #ifdef G4SPECSDEBUG
868  G4cout << "Creating Mini Voxels..." << G4endl;
869 #endif
870 
871  CreateMiniVoxels(miniBoundaries, bitmasksMini);
872 
873 #ifdef G4SPECSDEBUG
874  G4cout << "Building bounding box..." << G4endl;
875 #endif
876 
878 
879 #ifdef G4SPECSDEBUG
880  G4cout << "Building empty..." << G4endl;
881 #endif
882 
883  BuildEmpty();
884 
885 #ifdef G4SPECSDEBUG
886  G4cout << "Deallocating unnecessary fields during runtime..." << G4endl;
887 #endif
888  // deallocate fields unnecessary during runtime
889  //
890  fBoxes.resize(0);
891  for (auto i = 0; i < 3; ++i)
892  {
893  fCandidatesCounts[i].resize(0);
894  fBitmasks[i].Clear();
895  }
896  }
897 }
898 
899 
900 //______________________________________________________________________________
901 void G4Voxelizer::GetCandidatesVoxel(std::vector<G4int>& voxels)
902 {
903  // "GetCandidates" should compute which solids are possibly contained in
904  // the voxel defined by the three slices characterized by the passed indexes.
905 
906  G4cout << " Candidates in voxel [" << voxels[0] << " ; " << voxels[1]
907  << " ; " << voxels[2] << "]: ";
908  std::vector<G4int> candidates;
909  G4int count = GetCandidatesVoxelArray(voxels, candidates);
910  G4cout << "[ ";
911  for (G4int i = 0; i < count; ++i) G4cout << candidates[i];
912  G4cout << "] " << G4endl;
913 }
914 
915 //______________________________________________________________________________
917  std::vector<G4int>& list, G4int i)
918 {
919  for (G4int byte = 0; byte < (G4int) (sizeof(unsigned int)); ++byte)
920  {
921  if (G4int maskByte = mask & 0xFF)
922  {
923  for (G4int bit = 0; bit < 8; ++bit)
924  {
925  if (maskByte & 1)
926  { list.push_back(8*(sizeof(unsigned int)*i+ byte) + bit); }
927  if (!(maskByte >>= 1)) break;
928  }
929  }
930  mask >>= 8;
931  }
932 }
933 
934 //______________________________________________________________________________
936  const G4Transform3D& transformation) const
937 {
938  // The goal of this method is to convert the quantities min and max
939  // (representing the bounding box of a given solid in its local frame)
940  // to the main frame, using "transformation"
941 
942  G4ThreeVector vertices[8] = // Detemination of the vertices thanks to
943  { // the extension of each solid:
944  G4ThreeVector(min.x(), min.y(), min.z()), // 1st vertice:
945  G4ThreeVector(min.x(), max.y(), min.z()), // 2nd vertice:
946  G4ThreeVector(max.x(), max.y(), min.z()),
947  G4ThreeVector(max.x(), min.y(), min.z()),
948  G4ThreeVector(min.x(), min.y(), max.z()),
949  G4ThreeVector(min.x(), max.y(), max.z()),
950  G4ThreeVector(max.x(), max.y(), max.z()),
951  G4ThreeVector(max.x(), min.y(), max.z())
952  };
953 
956 
957  // Loop on th vertices
958  G4int limit = sizeof(vertices) / sizeof(G4ThreeVector);
959  for (G4int i = 0 ; i < limit; ++i)
960  {
961  // From local frame to the global one:
962  // Current positions on the three axis:
963  G4ThreeVector current = GetGlobalPoint(transformation, vertices[i]);
964 
965  // If need be, replacement of the min & max values:
966  if (current.x() > max.x()) max.setX(current.x());
967  if (current.x() < min.x()) min.setX(current.x());
968 
969  if (current.y() > max.y()) max.setY(current.y());
970  if (current.y() < min.y()) min.setY(current.y());
971 
972  if (current.z() > max.z()) max.setZ(current.z());
973  if (current.z() < min.z()) min.setZ(current.z());
974  }
975 }
976 
977 //______________________________________________________________________________
979  std::vector<G4int> &list, G4SurfBits *crossed) const
980 {
981  // Method returning the candidates corresponding to the passed point
982 
983  list.clear();
984 
985  for (auto i = 0; i <= 2; ++i)
986  {
987  if(point[i] < fBoundaries[i].front() || point[i] >= fBoundaries[i].back())
988  return 0;
989  }
990 
991  if (fTotalCandidates == 1)
992  {
993  list.push_back(0);
994  return 1;
995  }
996  else
997  {
998  if (fNPerSlice == 1)
999  {
1000  unsigned int mask = 0xFFffFFff;
1001  G4int slice;
1002  if (fBoundaries[0].size() > 2)
1003  {
1004  slice = BinarySearch(fBoundaries[0], point.x());
1005  if (!(mask = ((unsigned int*) fBitmasks[0].fAllBits)[slice]))
1006  return 0;
1007  }
1008  if (fBoundaries[1].size() > 2)
1009  {
1010  slice = BinarySearch(fBoundaries[1], point.y());
1011  if (!(mask &= ((unsigned int*) fBitmasks[1].fAllBits)[slice]))
1012  return 0;
1013  }
1014  if (fBoundaries[2].size() > 2)
1015  {
1016  slice = BinarySearch(fBoundaries[2], point.z());
1017  if (!(mask &= ((unsigned int*) fBitmasks[2].fAllBits)[slice]))
1018  return 0;
1019  }
1020  if (crossed && (!(mask &= ~((unsigned int*)crossed->fAllBits)[0])))
1021  return 0;
1022 
1023  FindComponentsFastest(mask, list, 0);
1024  }
1025  else
1026  {
1027  unsigned int* masks[3], mask; // masks for X,Y,Z axis
1028  for (auto i = 0; i <= 2; ++i)
1029  {
1030  G4int slice = BinarySearch(fBoundaries[i], point[i]);
1031  masks[i] = ((unsigned int*) fBitmasks[i].fAllBits)
1032  + slice * fNPerSlice;
1033  }
1034  unsigned int* maskCrossed = crossed
1035  ? (unsigned int*)crossed->fAllBits : 0;
1036 
1037  for (G4int i = 0 ; i < fNPerSlice; ++i)
1038  {
1039  // Logic "and" of the masks along the 3 axes x, y, z:
1040  // removing "if (!" and ") continue" => slightly slower
1041  //
1042  if (!(mask = masks[0][i])) continue;
1043  if (!(mask &= masks[1][i])) continue;
1044  if (!(mask &= masks[2][i])) continue;
1045  if (maskCrossed && !(mask &= ~maskCrossed[i])) continue;
1046 
1047  FindComponentsFastest(mask, list, i);
1048  }
1049  }
1050 /*
1051  if (fNPerSlice == 1)
1052  {
1053  unsigned int mask;
1054  G4int slice = BinarySearch(fBoundaries[0], point.x());
1055  if (!(mask = ((unsigned int *) fBitmasks[0].fAllBits)[slice]
1056  )) return 0;
1057  slice = BinarySearch(fBoundaries[1], point.y());
1058  if (!(mask &= ((unsigned int *) fBitmasks[1].fAllBits)[slice]
1059  )) return 0;
1060  slice = BinarySearch(fBoundaries[2], point.z());
1061  if (!(mask &= ((unsigned int *) fBitmasks[2].fAllBits)[slice]
1062  )) return 0;
1063  if (crossed && (!(mask &= ~((unsigned int *)crossed->fAllBits)[0])))
1064  return 0;
1065 
1066  FindComponentsFastest(mask, list, 0);
1067  }
1068  else
1069  {
1070  unsigned int *masks[3], mask; // masks for X,Y,Z axis
1071  for (auto i = 0; i <= 2; ++i)
1072  {
1073  G4int slice = BinarySearch(fBoundaries[i], point[i]);
1074  masks[i] = ((unsigned int *) fBitmasks[i].fAllBits) + slice*fNPerSlice;
1075  }
1076  unsigned int *maskCrossed =
1077  crossed ? (unsigned int *)crossed->fAllBits : 0;
1078 
1079  for (G4int i = 0 ; i < fNPerSlice; ++i)
1080  {
1081  // Logic "and" of the masks along the 3 axes x, y, z:
1082  // removing "if (!" and ") continue" => slightly slower
1083  //
1084  if (!(mask = masks[0][i])) continue;
1085  if (!(mask &= masks[1][i])) continue;
1086  if (!(mask &= masks[2][i])) continue;
1087  if (maskCrossed && !(mask &= ~maskCrossed[i])) continue;
1088 
1089  FindComponentsFastest(mask, list, i);
1090  }
1091  }
1092 */
1093  }
1094  return list.size();
1095 }
1096 
1097 //______________________________________________________________________________
1098 G4int
1099 G4Voxelizer::GetCandidatesVoxelArray(const std::vector<G4int>& voxels,
1100  const G4SurfBits bitmasks[],
1101  std::vector<G4int>& list,
1102  G4SurfBits* crossed) const
1103 {
1104  list.clear();
1105 
1106  if (fTotalCandidates == 1)
1107  {
1108  list.push_back(0);
1109  return 1;
1110  }
1111  else
1112  {
1113  if (fNPerSlice == 1)
1114  {
1115  unsigned int mask;
1116  if (!(mask = ((unsigned int *) bitmasks[0].fAllBits)[voxels[0]]))
1117  return 0;
1118  if (!(mask &= ((unsigned int *) bitmasks[1].fAllBits)[voxels[1]]))
1119  return 0;
1120  if (!(mask &= ((unsigned int *) bitmasks[2].fAllBits)[voxels[2]]))
1121  return 0;
1122  if (crossed && (!(mask &= ~((unsigned int *)crossed->fAllBits)[0])))
1123  return 0;
1124 
1125  FindComponentsFastest(mask, list, 0);
1126  }
1127  else
1128  {
1129  unsigned int *masks[3], mask; // masks for X,Y,Z axis
1130  for (auto i = 0; i <= 2; ++i)
1131  {
1132  masks[i] = ((unsigned int *) bitmasks[i].fAllBits)
1133  + voxels[i]*fNPerSlice;
1134  }
1135  unsigned int *maskCrossed = crossed != nullptr
1136  ? (unsigned int *)crossed->fAllBits : 0;
1137 
1138  for (G4int i = 0 ; i < fNPerSlice; ++i)
1139  {
1140  // Logic "and" of the masks along the 3 axes x, y, z:
1141  // removing "if (!" and ") continue" => slightly slower
1142  //
1143  if (!(mask = masks[0][i])) continue;
1144  if (!(mask &= masks[1][i])) continue;
1145  if (!(mask &= masks[2][i])) continue;
1146  if (maskCrossed && !(mask &= ~maskCrossed[i])) continue;
1147 
1148  FindComponentsFastest(mask, list, i);
1149  }
1150  }
1151  }
1152  return list.size();
1153 }
1154 
1155 //______________________________________________________________________________
1156 G4int
1157 G4Voxelizer::GetCandidatesVoxelArray(const std::vector<G4int>& voxels,
1158  std::vector<G4int>& list, G4SurfBits* crossed) const
1159 {
1160  // Method returning the candidates corresponding to the passed point
1161 
1162  return GetCandidatesVoxelArray(voxels, fBitmasks, list, crossed);
1163 }
1164 
1165 //______________________________________________________________________________
1167 {
1168  for (auto i = 0; i < 3; ++i)
1169  {
1170  if (point[i] < fBoundaries[i].front() || point[i] > fBoundaries[i].back())
1171  return false;
1172  }
1173  return true;
1174 }
1175 
1176 //______________________________________________________________________________
1177 G4double
1179  const G4ThreeVector& direction) const
1180 {
1181  G4ThreeVector pointShifted = point - fBoundingBoxCenter;
1182  G4double shift = fBoundingBox.DistanceToIn(pointShifted, direction);
1183  return shift;
1184 }
1185 
1186 //______________________________________________________________________________
1187 G4double
1189 {
1190  G4ThreeVector pointShifted = point - fBoundingBoxCenter;
1191  G4double shift = MinDistanceToBox(pointShifted, fBoundingBoxSize);
1192  return shift;
1193 }
1194 
1195 //______________________________________________________________________________
1196 G4double
1198  const G4ThreeVector& f)
1199 {
1200  // Estimates the isotropic safety from a point outside the current solid to
1201  // any of its surfaces. The algorithm may be accurate or should provide a
1202  // fast underestimate.
1203 
1204  G4double safe, safx, safy, safz;
1205  safe = safx = -f.x() + std::abs(aPoint.x());
1206  safy = -f.y() + std::abs(aPoint.y());
1207  if ( safy > safe ) safe = safy;
1208  safz = -f.z() + std::abs(aPoint.z());
1209  if ( safz > safe ) safe = safz;
1210  if (safe < 0.0) return 0.0; // point is inside
1211 
1212  G4double safsq = 0.0;
1213  G4int count = 0;
1214  if ( safx > 0 ) { safsq += safx*safx; ++count; }
1215  if ( safy > 0 ) { safsq += safy*safy; ++count; }
1216  if ( safz > 0 ) { safsq += safz*safz; ++count; }
1217  if (count == 1) return safe;
1218  return std::sqrt(safsq);
1219 }
1220 
1221 //______________________________________________________________________________
1222 G4double
1224  const G4ThreeVector& direction,
1225  std::vector<G4int>& curVoxel) const
1226 {
1227  G4double shift = kInfinity;
1228 
1229  G4int cur = 0; // the smallest index, which would be than increased
1230  for (G4int i = 0; i <= 2; ++i)
1231  {
1232  // Looking for the next voxels on the considered direction X,Y,Z axis
1233  //
1234  const std::vector<G4double>& boundary = fBoundaries[i];
1235  G4int index = curVoxel[i];
1236  if (direction[i] >= 1e-10)
1237  {
1238  ++index;
1239  }
1240  else
1241  {
1242  if (direction[i] > -1e-10)
1243  continue;
1244  }
1245  G4double dif = boundary[index] - point[i];
1246  G4double distance = dif / direction[i];
1247 
1248  if (shift > distance)
1249  {
1250  shift = distance;
1251  cur = i;
1252  }
1253  }
1254 
1255  if (shift != kInfinity)
1256  {
1257  // updating current voxel using the index corresponding
1258  // to the closest voxel boundary on the ray
1259 
1260  if (direction[cur] > 0)
1261  {
1262  if (++curVoxel[cur] >= (G4int) fBoundaries[cur].size() - 1)
1263  shift = kInfinity;
1264  }
1265  else
1266  {
1267  if (--curVoxel[cur] < 0)
1268  shift = kInfinity;
1269  }
1270  }
1271 
1272 /*
1273  for (auto i = 0; i <= 2; ++i)
1274  {
1275  // Looking for the next voxels on the considered direction X,Y,Z axis
1276  //
1277  const std::vector<G4double> &boundary = fBoundaries[i];
1278  G4int cur = curVoxel[i];
1279  if(direction[i] >= 1e-10)
1280  {
1281  if (boundary[++cur] - point[i] < fTolerance) // make sure shift would
1282  if (++cur >= (G4int) boundary.size()) // be non-zero
1283  continue;
1284  }
1285  else
1286  {
1287  if(direction[i] <= -1e-10)
1288  {
1289  if (point[i] - boundary[cur] < fTolerance) // make sure shift would
1290  if (--cur < 0) // be non-zero
1291  continue;
1292  }
1293  else
1294  continue;
1295  }
1296  G4double dif = boundary[cur] - point[i];
1297  G4double distance = dif / direction[i];
1298 
1299  if (shift > distance)
1300  shift = distance;
1301  }
1302 */
1303  return shift;
1304 }
1305 
1306 //______________________________________________________________________________
1307 G4bool
1309  const G4ThreeVector& direction,
1310  std::vector<G4int>& curVoxel) const
1311 {
1312  for (auto i = 0; i <= 2; ++i)
1313  {
1314  G4int index = curVoxel[i];
1315  const std::vector<G4double> &boundary = fBoundaries[i];
1316 
1317  if (direction[i] > 0)
1318  {
1319  if (point[i] >= boundary[++index])
1320  if (++curVoxel[i] >= (G4int) boundary.size() - 1)
1321  return false;
1322  }
1323  else
1324  {
1325  if (point[i] < boundary[index])
1326  if (--curVoxel[i] < 0)
1327  return false;
1328  }
1329 #ifdef G4SPECSDEBUG
1330  G4int indexOK = BinarySearch(boundary, point[i]);
1331  if (curVoxel[i] != indexOK)
1332  curVoxel[i] = indexOK; // put breakpoint here
1333 #endif
1334  }
1335  return true;
1336 }
1337 
1338 //______________________________________________________________________________
1340 {
1341  fMaxVoxels = max;
1342  fReductionRatio.set(0,0,0);
1343 }
1344 
1345 //______________________________________________________________________________
1346 void G4Voxelizer::SetMaxVoxels(const G4ThreeVector& ratioOfReduction)
1347 {
1348  fMaxVoxels = -1;
1349  fReductionRatio = ratioOfReduction;
1350 }
1351 
1352 //______________________________________________________________________________
1354 {
1355  fDefaultVoxelsCount = count;
1356 }
1357 
1358 //______________________________________________________________________________
1360 {
1361  return fDefaultVoxelsCount;
1362 }
1363 
1364 //______________________________________________________________________________
1366 {
1367  G4int size = fEmpty.GetNbytes();
1368  size += fBoxes.capacity() * sizeof(G4VoxelBox);
1369  size += sizeof(G4double) * (fBoundaries[0].capacity()
1370  + fBoundaries[1].capacity() + fBoundaries[2].capacity());
1371  size += sizeof(G4int) * (fCandidatesCounts[0].capacity()
1372  + fCandidatesCounts[1].capacity() + fCandidatesCounts[2].capacity());
1373  size += fBitmasks[0].GetNbytes() + fBitmasks[1].GetNbytes()
1374  + fBitmasks[2].GetNbytes();
1375 
1376  G4int csize = fCandidates.size();
1377  for (G4int i = 0; i < csize; ++i)
1378  {
1379  size += sizeof(vector<G4int>) + fCandidates[i].capacity() * sizeof(G4int);
1380  }
1381 
1382  return size;
1383 }