Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/examples/advanced/dna/moleculardna/src/OctreeNode.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 //
 27 #include "OctreeNode.hh"
 28 
 29 #include "G4VPhysicalVolume.hh"
 30 
 31 #include <cassert>
 32 #include <utility>
 33 
 34 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 35 
 36 OctreeNode::OctreeNode(const G4ThreeVector& position, const G4ThreeVector& halfLengths,
 37                        G4int maxContents, OctreeNode* parent)
 38   : fPosition(position),
 39     fHalfLengths(halfLengths),
 40     fMaxContents(maxContents),
 41     fParent(parent),
 42     fChildren(std::array<OctreeNode*, 8>())
 43 {
 44   fHalfLengthsMag = fHalfLengths.mag();
 45 }
 46 
 47 OctreeNode::~OctreeNode()
 48 {
 49   // Delete children
 50   for (auto& it : fChildren) {
 51     delete it;
 52   }
 53 }
 54 
 55 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 56 
 57 const OctreeNode* OctreeNode::GetChildFromPosition(const G4ThreeVector& pos) const
 58 {
 59   G4ThreeVector localPosition = pos - fPosition;
 60 
 61   // Get the right child
 62   // The scheme is defined by quadrant as follows:
 63   // Zero is treated as positive
 64   // X Y Z Index | X Y Z Index
 65   // + + +   0   | - + +   4
 66   // + + -   1   | - + -   5
 67   // + - +   2   | - - +   6
 68   // + - -   3   | - - -   7
 69   int bit2 = (localPosition.getX() < 0) ? 4 : 0;
 70   int bit1 = (localPosition.getY() < 0) ? 2 : 0;
 71   int bit0 = (localPosition.getZ() < 0) ? 1 : 0;
 72   return fChildren[bit0 + bit1 + bit2];
 73 }
 74 
 75 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 76 
 77 // Non-const version of above function. Ugly but useful in this case
 78 OctreeNode* OctreeNode::GetChildFromPosition(const G4ThreeVector& pos)
 79 {
 80   G4ThreeVector localPosition = pos - fPosition;
 81 
 82   // Get the right child
 83   // The scheme is defined by quadrant as follows:
 84   // Zero is treated as positive
 85   // X Y Z Index | X Y Z Index
 86   // + + +   0   | - + +   4
 87   // + + -   1   | - + -   5
 88   // + - +   2   | - - +   6
 89   // + - -   3   | - - -   7
 90   int bit2 = (localPosition.getX() < 0) ? 4 : 0;
 91   int bit1 = (localPosition.getY() < 0) ? 2 : 0;
 92   int bit0 = (localPosition.getZ() < 0) ? 1 : 0;
 93   int idx = bit0 + bit1 + bit2;
 94 
 95   assert(idx < (int)fChildren.size());
 96   return fChildren[idx];
 97 }
 98 
 99 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
100 
101 void OctreeNode::AddPhysicalVolume(G4VPhysicalVolume* pv)
102 {
103   // Consider adding test for the validity of the PV position
104   if (this->HasChildren()) {
105     OctreeNode* child = this->GetChildFromPosition(pv->GetTranslation());
106     child->AddPhysicalVolume(pv);
107   }
108   else {
109     // if there are fMaxContents elements in the bin, we need to split
110     // the bin before adding a new element.
111     if ((G4int)fContents.size() == fMaxContents) {
112       this->Split();
113       this->AddPhysicalVolume(pv);
114     }
115     else {
116       fContents.push_back(pv);
117     }
118   }
119 }
120 
121 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
122 
123 void OctreeNode::Split()
124 {
125   G4ThreeVector hl = 0.5 * fHalfLengths;
126   G4double xp = fPosition.getX();
127   G4double yp = fPosition.getY();
128   G4double zp = fPosition.getZ();
129   G4double xl = hl.getX();
130   G4double yl = hl.getY();
131   G4double zl = hl.getZ();
132   G4ThreeVector newpos;
133 
134   // Construct children
135   newpos = G4ThreeVector(xp + xl, yp + yl, zp + zl);
136   fChildren[0] = new OctreeNode(newpos, hl, fMaxContents, this);
137   newpos = G4ThreeVector(xp + xl, yp + yl, zp - zl);
138   fChildren[1] = new OctreeNode(newpos, hl, fMaxContents, this);
139   newpos = G4ThreeVector(xp + xl, yp - yl, zp + zl);
140   fChildren[2] = new OctreeNode(newpos, hl, fMaxContents, this);
141   newpos = G4ThreeVector(xp + xl, yp - yl, zp - zl);
142   fChildren[3] = new OctreeNode(newpos, hl, fMaxContents, this);
143   newpos = G4ThreeVector(xp - xl, yp + yl, zp + zl);
144   fChildren[4] = new OctreeNode(newpos, hl, fMaxContents, this);
145   newpos = G4ThreeVector(xp - xl, yp + yl, zp - zl);
146   fChildren[5] = new OctreeNode(newpos, hl, fMaxContents, this);
147   newpos = G4ThreeVector(xp - xl, yp - yl, zp + zl);
148   fChildren[6] = new OctreeNode(newpos, hl, fMaxContents, this);
149   newpos = G4ThreeVector(xp - xl, yp - yl, zp - zl);
150   fChildren[7] = new OctreeNode(newpos, hl, fMaxContents, this);
151 
152   // Distribute contents to children
153 
154   for (int i = fContents.size() - 1; i >= 0; --i) {
155     G4VPhysicalVolume* pv = fContents[i];
156     OctreeNode* child = this->GetChildFromPosition(pv->GetTranslation());
157     assert(child != this);
158     child->AddPhysicalVolume(pv);
159   }
160   fContents.clear();
161 }
162 
163 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
164 
165 std::vector<G4VPhysicalVolume*> OctreeNode::GetContents() const
166 {
167   if (this->HasChildren())  // if has sub-nodes
168   {
169     std::vector<G4VPhysicalVolume*> vec;
170     std::vector<G4VPhysicalVolume*> childCont;
171     for (auto it = fChildren.begin(); it != fChildren.end(); ++it) {
172       childCont = (*it)->GetContents();
173       for (auto jt = childCont.begin(); jt != childCont.end(); ++jt) {
174         vec.push_back(*jt);
175       }
176     }
177     return vec;
178   }
179   else  // if no sub-nodes
180   {
181     return fContents;
182   }
183 }
184 
185 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
186 
187 // Search for Octree nodes in a volume
188 const std::vector<G4VPhysicalVolume*> OctreeNode::SearchOctree(const G4ThreeVector& pos,
189                                                                G4double _rad) const
190 {
191   // Need to search based on absolute position of each volume rather than
192   // relative  position, and maintain a list of candidate nodes and
193   // final nodes within the radius
194 
195   std::vector<const OctreeNode*> nodes;
196   std::vector<const OctreeNode*> candidates;
197   nodes.reserve(512);
198   candidates.reserve(512);
199 
200   if (this->HasChildren()) {
201     for (auto it = this->GetChildren().begin(); it != this->GetChildren().end(); it++) {
202       candidates.push_back(*it);
203     }
204   }
205   else {
206     candidates.push_back(this);
207   }
208 
209   const OctreeNode* aNode;
210   G4double d;
211   while (!candidates.empty()) {
212     aNode = candidates.back();
213     candidates.pop_back();
214     d = (aNode->GetPosition() - pos).mag() - aNode->GetHalfLengthsMag();
215     // if node within circle
216     if (d < _rad) {
217       if (aNode->HasChildren()) {
218         for (auto it = aNode->GetChildren().begin(); it != aNode->GetChildren().end(); ++it) {
219           candidates.push_back(*it);
220         }
221       }
222       else {
223         nodes.push_back(aNode);
224       }
225     }
226   }
227 
228   // G4cout << "Found " << nodes.size() << " nodes" << G4endl;
229 
230   // Get the physical volumes
231   G4double r2 = _rad * _rad;
232   std::vector<G4VPhysicalVolume*> pvols;
233   for (auto it = nodes.begin(); it != nodes.end(); ++it) {
234     std::vector<G4VPhysicalVolume*> conts = (*it)->GetContents();
235     for (auto jt = conts.begin(); jt != conts.end(); ++jt) {
236       if ((pos - (*jt)->GetTranslation()).mag2() < r2) {
237         pvols.push_back((*jt));
238       }
239     }
240   }
241   // G4cout << "Found " << pvols.size() << " candidates" << G4endl;
242   return pvols;
243 }
244 
245 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
246 
247 // Search for Octree nodes in a volume
248 void OctreeNode::SearchOctree(const G4ThreeVector& pos, std::vector<G4VPhysicalVolume*>& out,
249                               G4double _rad) const
250 {
251   // Need to search based on absolute position of each volume rather than
252   // relative  position, and maintain a list of candidate nodes and
253   // final nodes within the radius
254 
255   std::vector<const OctreeNode*> nodes;
256   std::vector<const OctreeNode*> candidates;
257   nodes.reserve(512);
258   candidates.reserve(512);
259 
260   if (this->HasChildren()) {
261     for (auto it = this->GetChildren().begin(); it != this->GetChildren().end(); ++it) {
262       candidates.push_back(*it);
263     }
264   }
265   else {
266     candidates.push_back(this);
267   }
268 
269   const OctreeNode* aNode;
270   G4double d;
271   while (!candidates.empty()) {
272     aNode = candidates.back();
273     candidates.pop_back();
274     d = (aNode->GetPosition() - pos).mag() - aNode->GetHalfLengthsMag();
275     // if node within circle
276     if (d < _rad) {
277       if (aNode->HasChildren()) {
278         for (auto it = aNode->GetChildren().begin(); it != aNode->GetChildren().end(); it++) {
279           candidates.push_back(*it);
280         }
281       }
282       else {
283         nodes.push_back(aNode);
284       }
285     }
286   }
287 
288   // Get the physical volumes
289   G4double r2 = _rad * _rad;
290   for (auto it = nodes.begin(); it != nodes.end(); ++it) {
291     std::vector<G4VPhysicalVolume*> conts = (*it)->GetContents();
292     for (auto jt = conts.begin(); jt != conts.end(); ++jt) {
293       if ((pos - (*jt)->GetTranslation()).mag2() < r2) {
294         out.push_back((*jt));
295       }
296     }
297   }
298 }
299 
300 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
301 
302 const std::vector<G4VPhysicalVolume*> OctreeNode::SearchOctree(const G4ThreeVector& pos) const
303 {
304   const OctreeNode* child = GetChildFromPosition(pos);
305   return child->GetContents();
306 }
307 
308 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
309 
310 G4int OctreeNode::GetNumberOfTerminalNodes()
311 {
312   if (!this->HasChildren()) {
313     return 1;
314   }
315   // sum the number of nodes of each child
316   G4int n = 0;
317   for (auto it = this->GetChildren().begin(); it != this->GetChildren().end(); ++it) {
318     n = n + (*it)->GetNumberOfTerminalNodes();
319   }
320 
321   return n;
322 }
323 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
324