source: trunk/source/geometry/management/src/G4SmartVoxelHeader.cc @ 1340

Last change on this file since 1340 was 1340, checked in by garnier, 14 years ago

update ti head

File size: 45.1 KB
Line 
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// $Id: G4SmartVoxelHeader.cc,v 1.39 2010/09/06 09:39:21 gcosmo Exp $
28// GEANT4 tag $Name: geommng-V09-03-05 $
29//
30//
31// class G4SmartVoxelHeader
32//
33// Implementation
34//
35// Define G4GEOMETRY_VOXELDEBUG for debugging information on G4cout
36//
37// History:
38// 29.04.02 Use 3D voxelisation for non consuming replication - G.C.
39// 18.04.01 Migrated to STL vector - G.C.
40// 12.02.99 Introduction of new quality/smartless: max for (slices/candid) S.G.
41// 11.02.99 Voxels at lower levels are now built for collapsed slices      S.G.
42// 21.07.95 Full implementation, supporting non divided physical volumes
43// 14.07.95 Initial version - stubb definitions only
44// --------------------------------------------------------------------
45
46#include "G4SmartVoxelHeader.hh"
47
48#include "G4ios.hh"
49
50#include "G4LogicalVolume.hh"
51#include "G4VPhysicalVolume.hh"
52#include "G4VoxelLimits.hh"
53
54#include "voxeldefs.hh"
55#include "G4AffineTransform.hh"
56#include "G4VSolid.hh"
57#include "G4VPVParameterisation.hh"
58
59// ***************************************************************************
60// Constructor for topmost header, to begin voxel construction at a
61// given logical volume.
62// Constructs target List of volumes, calls "Build and refine" constructor.
63// Assumes all daughters represent single volumes (ie. no divisions
64// or parametric)
65// ***************************************************************************
66//
67G4SmartVoxelHeader::G4SmartVoxelHeader(G4LogicalVolume* pVolume,
68                                       G4int pSlice)
69  : fminEquivalent(pSlice),
70    fmaxEquivalent(pSlice),
71    fparamAxis(kUndefined)
72{
73  G4int nDaughters = pVolume->GetNoDaughters();
74  G4VoxelLimits limits;   // Create `unlimited' limits object
75
76  // Determine whether daughter is replicated
77  //
78  if ((nDaughters!=1) || (!pVolume->GetDaughter(0)->IsReplicated()))
79  {
80    // Daughter not replicated => conventional voxel Build
81    // where each daughters extents are computed
82    //
83    BuildVoxels(pVolume);
84  }
85  else
86  {
87    // Single replicated daughter
88    //
89    BuildReplicaVoxels(pVolume);
90  }
91}
92
93// ***************************************************************************
94// Protected constructor:
95// builds and refines voxels between specified limits, considering only
96// the physical volumes numbered `pCandidates'. `pSlice' is used to set max
97// and min equivalent slice nos for the header - they apply to the level
98// of the header, not its nodes.
99// ***************************************************************************
100//
101G4SmartVoxelHeader::G4SmartVoxelHeader(G4LogicalVolume* pVolume,
102                                 const G4VoxelLimits& pLimits,
103                                 const G4VolumeNosVector* pCandidates,
104                                       G4int pSlice)
105  : fminEquivalent(pSlice),
106    fmaxEquivalent(pSlice),
107    fparamAxis(kUndefined)
108{
109#ifdef G4GEOMETRY_VOXELDEBUG
110  G4cout << "**** G4SmartVoxelHeader::G4SmartVoxelHeader" << G4endl
111         << "     Limits " << pLimits << G4endl
112         << "     Candidate #s = " ;
113  for (size_t i=0;i<pCandidates->size();i++)
114  {
115    G4cout << (*pCandidates)[i] << " ";
116  }
117  G4cout << G4endl;
118#endif   
119
120  BuildVoxelsWithinLimits(pVolume,pLimits,pCandidates);
121}
122
123// ***************************************************************************
124// Destructor:
125// deletes all proxies and underlying objects.
126// ***************************************************************************
127//
128G4SmartVoxelHeader::~G4SmartVoxelHeader()
129{
130  // Manually destroy underlying nodes/headers
131  // Delete collected headers and nodes once only
132  //
133  G4int node, proxy, maxNode=fslices.size();
134  G4SmartVoxelProxy *lastProxy=0;
135  G4SmartVoxelNode *dyingNode, *lastNode=0;
136  G4SmartVoxelHeader *dyingHeader, *lastHeader=0;
137
138  for (node=0; node<maxNode; node++)
139  {
140    if (fslices[node]->IsHeader())
141    {
142      dyingHeader = fslices[node]->GetHeader();
143      if (lastHeader!=dyingHeader)
144      {
145        lastHeader = dyingHeader;
146        lastNode = 0;
147        delete dyingHeader;
148      }
149    }
150    else
151    {
152      dyingNode = fslices[node]->GetNode();
153      if (dyingNode!=lastNode)
154      {
155        lastNode=dyingNode;
156        lastHeader=0;
157        delete dyingNode;
158      }
159    }
160  }
161  // Delete proxies
162  //
163  for (proxy=0; proxy<maxNode; proxy++)
164  {
165    if (fslices[proxy]!=lastProxy)
166    {
167      lastProxy = fslices[proxy];
168      delete lastProxy;
169    }
170  }
171  // Don't need to clear slices
172  // fslices.clear();
173}
174
175// ***************************************************************************
176// Equality operator: returns true if contents are equivalent.
177// Implies a deep search through contained nodes/header.
178// Compares headers' axes,sizes,extents. Returns false if different.
179// For each contained proxy, determines whether node/header, compares and
180// returns if different. Compares and returns if proxied nodes/headers
181// are different.
182// ***************************************************************************
183//
184G4bool G4SmartVoxelHeader::operator == (const G4SmartVoxelHeader& pHead) const
185{
186  if ( (GetAxis()      == pHead.GetAxis())
187    && (GetNoSlices()  == pHead.GetNoSlices())
188    && (GetMinExtent() == pHead.GetMinExtent())
189    && (GetMaxExtent() == pHead.GetMaxExtent()) )
190  {
191    G4int node, maxNode;
192    G4SmartVoxelProxy *leftProxy, *rightProxy;
193    G4SmartVoxelHeader *leftHeader, *rightHeader;
194    G4SmartVoxelNode *leftNode, *rightNode;
195
196    maxNode=GetNoSlices();
197    for (node=0; node<maxNode; node++)
198    {
199      leftProxy  = GetSlice(node);
200      rightProxy = pHead.GetSlice(node);
201      if (leftProxy->IsHeader())
202      {
203        if (rightProxy->IsNode())
204        {
205          return false;
206        }
207        else
208        {
209          leftHeader  = leftProxy->GetHeader();
210          rightHeader = rightProxy->GetHeader();
211          if (!(*leftHeader==*rightHeader))
212          {
213            return false;
214          }
215        }
216      }
217      else
218      {
219        if (rightProxy->IsHeader())
220        {
221          return false;
222        }
223        else
224        {
225          leftNode  = leftProxy->GetNode();
226          rightNode = rightProxy->GetNode();
227          if (!(*leftNode==*rightNode))
228          {
229            return false;
230          }
231        }
232      }
233    }
234    return true;
235  }
236  else
237  {
238    return false;
239  }
240}
241
242// ***************************************************************************
243// Builds voxels for daughters specified volume, in NON-REPLICATED case
244// o Create List of target volume nos (all daughters; 0->noDaughters-1)
245// o BuildWithinLimits does Build & also determines mother dimensions.
246// ***************************************************************************
247//
248void G4SmartVoxelHeader::BuildVoxels(G4LogicalVolume* pVolume)
249{
250  G4VoxelLimits limits;   // Create `unlimited' limits object
251  G4int nDaughters = pVolume->GetNoDaughters();
252
253  G4VolumeNosVector targetList;
254  targetList.reserve(nDaughters);
255  for (G4int i=0; i<nDaughters; i++)
256  {
257    targetList.push_back(i);
258  }
259  BuildVoxelsWithinLimits(pVolume, limits, &targetList);
260}
261
262// ***************************************************************************
263// Builds voxels for specified volume containing a single replicated volume.
264// If axis is not specified (i.e. "kUndefined"), 3D voxelisation is applied,
265// and the best axis is determined according to heuristics as for placements.
266// ***************************************************************************
267//
268void G4SmartVoxelHeader::BuildReplicaVoxels(G4LogicalVolume* pVolume)
269{
270  G4VPhysicalVolume *pDaughter=0;
271
272  // Replication data
273  //
274  EAxis axis;
275  G4int nReplicas;
276  G4double width,offset;
277  G4bool consuming;
278
279  // Consistency check: pVolume should contain single replicated volume
280  //
281  if ( (pVolume->GetNoDaughters()==1)
282    && (pVolume->GetDaughter(0)->IsReplicated()==true) )
283  {
284    // Obtain replication data
285    //
286    pDaughter=pVolume->GetDaughter(0);
287    pDaughter->GetReplicationData(axis,nReplicas,width,offset,consuming);
288    fparamAxis = axis;
289    if ( consuming==false )
290    {
291      G4VoxelLimits limits;   // Create `unlimited' limits object
292      G4VolumeNosVector targetList;
293      targetList.reserve(nReplicas);
294      for (G4int i=0; i<nReplicas; i++)
295      {
296        targetList.push_back(i);
297      }
298      if (axis != kUndefined)
299      {
300        // Apply voxelisation along the specified axis only
301
302        G4ProxyVector* pSlices=BuildNodes(pVolume,limits,&targetList,axis);
303        faxis = axis;
304        fslices = *pSlices;
305        delete pSlices;
306
307        // Calculate and set min and max extents given our axis
308        //
309        const G4AffineTransform origin;
310        pVolume->GetSolid()->CalculateExtent(faxis, limits, origin,
311                                             fminExtent, fmaxExtent);
312        // Calculate equivalent nos
313        //
314        BuildEquivalentSliceNos();
315        CollectEquivalentNodes();   // Collect common nodes
316      }
317      else
318      {
319        // Build voxels similarly as for normal placements considering
320        // all three cartesian axes.
321
322        BuildVoxelsWithinLimits(pVolume, limits, &targetList);
323      }
324    }
325    else
326    {
327      // Replication is consuming -> Build voxels directly
328      //
329      // o Cartesian axes - range is -width*nREplicas/2 to +width*nREplicas/2
330      //                    nReplicas replications result
331      // o Radial axis (rho) = range is 0 to width*nReplicas
332      //                    nReplicas replications result
333      // o Phi axi       - range is offset to offset+width*nReplicas radians
334      //
335      // Equivalent slices no computation & collection not required - all
336      // slices are different
337      //
338      switch (axis)
339      {
340        case kXAxis:
341        case kYAxis:
342        case kZAxis:
343          fminExtent = -width*nReplicas*0.5;
344          fmaxExtent =  width*nReplicas*0.5;
345          break;
346        case kRho:
347          fminExtent = offset;
348          fmaxExtent = width*nReplicas+offset;
349          break;
350        case kPhi:
351          fminExtent = offset;
352          fmaxExtent = offset+width*nReplicas;
353          break;
354        default:
355          G4cerr << "ERROR - G4SmartVoxelHeader::BuildReplicaVoxels()"
356                 << G4endl
357                 << "        Illegal axis !" << G4endl;
358          G4Exception("G4SmartVoxelHeader::BuildReplicaVoxels()", "FatalError",
359                      FatalException, "Illegal axis.");
360          break;
361      } 
362      faxis = axis;   // Set axis
363      BuildConsumedNodes(nReplicas);
364      if ( (axis==kXAxis) || (axis==kYAxis) || (axis==kZAxis) )
365      {
366        // Sanity check on extent
367        //
368        G4double emin = kInfinity, emax = -kInfinity;
369        G4VoxelLimits limits;
370        G4AffineTransform origin;
371        pVolume->GetSolid()->CalculateExtent(axis, limits, origin, emin, emax);
372        if ( (std::fabs((emin-fminExtent)/fminExtent) +
373              std::fabs((emax-fmaxExtent)/fmaxExtent)) > 0.05)
374        {
375          G4cerr << "ERROR - G4SmartVoxelHeader::BuildReplicaVoxels()"
376                 << G4endl
377                 << "        Replicated geometry, logical volume: "
378                 << pVolume->GetName() << G4endl;
379          G4Exception("G4SmartVoxelHeader::BuildReplicaVoxels", "FatalError",
380                      FatalException, "Sanity check: wrong solid extent.");
381        }
382      }
383    }
384  }
385  else
386  {
387    G4cerr << "ERROR - G4SmartVoxelHeader::BuildReplicaVoxels()"
388           << G4endl
389           << "        There must be a single replicated volume !" << G4endl;
390    G4Exception("G4SmartVoxelHeader::BuildReplicaVoxels", "InvalidSetup",
391                FatalException, "Only one replicated daughter is allowed !");
392  }
393}
394
395// ***************************************************************************
396// Builds `consumed nodes': nReplicas nodes each containing one replication,
397// numbered in sequence 0->nReplicas-1
398// o Modifies fslices `in place'
399// o faxis,fminExtent,fmaxExtent NOT modified.
400// ***************************************************************************
401//
402void G4SmartVoxelHeader::BuildConsumedNodes(G4int nReplicas)
403{
404  G4int nNode, nVol;
405  G4SmartVoxelNode *pNode;
406  G4SmartVoxelProxy *pProxyNode;
407
408  // Create and fill nodes in temporary G4NodeVector (on stack)
409  //
410  G4NodeVector nodeList;
411  nodeList.reserve(nReplicas);
412  for (nNode=0; nNode<nReplicas; nNode++)
413  {
414    pNode=new G4SmartVoxelNode(nNode);
415    if (!pNode)
416    {
417      G4cerr << "ERROR - G4SmartVoxelHeader::BuildConsumedNodes()" << G4endl
418             << "        Node allocation failed." << G4endl;
419      G4Exception("G4SmartVoxelHeader::BuildConsumedNodes()", "FatalError",
420                  FatalException, "Node allocation error.");
421    }
422    nodeList.push_back(pNode);
423  }
424  for (nVol=0; nVol<nReplicas; nVol++)
425  {
426    nodeList[nVol]->Insert(nVol);   // Insert replication of number
427  }                                 // identical to voxel number
428
429  // Create & fill proxy List `in place' by modifying instance data fslices
430  //
431  fslices.clear();
432  for (nNode=0; nNode<nReplicas; nNode++)
433  {
434    pProxyNode = new G4SmartVoxelProxy(nodeList[nNode]);
435    if (!pProxyNode)
436    {
437      G4cerr << "ERROR - G4SmartVoxelHeader::BuildConsumedNodes()" << G4endl
438             << "        Proxy node allocation failed." << G4endl;
439      G4Exception("G4SmartVoxelHeader::BuildConsumedNodes()", "FatalError",
440                  FatalException, "Proxy node allocation error.");
441    }
442    fslices.push_back(pProxyNode);
443  }
444}
445
446// ***************************************************************************
447// Builds and refines voxels between specified limits, considering only
448// the physical volumes numbered `pCandidates'.
449// o Chooses axis
450// o Determines min and max extents (of mother solid) within limits.
451// ***************************************************************************
452//
453void
454G4SmartVoxelHeader::BuildVoxelsWithinLimits(G4LogicalVolume* pVolume,
455                                            G4VoxelLimits pLimits,
456                                      const G4VolumeNosVector* pCandidates)
457{
458  // Choose best axis for slicing by:
459  // 1. Trying all unlimited cartesian axes
460  // 2. Select axis which gives greatest no slices
461
462  G4ProxyVector *pGoodSlices=0, *pTestSlices, *tmpSlices;
463  G4double goodSliceScore=kInfinity, testSliceScore;
464  EAxis goodSliceAxis = kXAxis;
465  EAxis testAxis      = kXAxis;
466  G4int node, maxNode, iaxis;
467  G4VoxelLimits noLimits;
468
469  // Try all non-limited cartesian axes
470  //
471  for (iaxis=0; iaxis<3; iaxis++)
472  {
473    switch(iaxis)
474    {
475      case 0:
476        testAxis = kXAxis;
477        break;
478      case 1:
479        testAxis = kYAxis;
480        break;
481      case 2:
482        testAxis = kZAxis;
483        break;
484    }
485    if (!pLimits.IsLimited(testAxis))
486    {
487      pTestSlices = BuildNodes(pVolume,pLimits,pCandidates,testAxis);
488      testSliceScore = CalculateQuality(pTestSlices);
489      if ( (!pGoodSlices) || (testSliceScore<goodSliceScore) )
490      {
491        goodSliceAxis  = testAxis;
492        goodSliceScore = testSliceScore;
493        tmpSlices      = pGoodSlices;
494        pGoodSlices    = pTestSlices;
495        pTestSlices    = tmpSlices;
496      }
497      if (pTestSlices)
498      {
499        // Destroy pTestSlices and all its contents
500        //
501        maxNode=pTestSlices->size();
502        for (node=0; node<maxNode; node++)
503        {
504          delete (*pTestSlices)[node]->GetNode();
505        }
506        G4SmartVoxelProxy* tmpProx;
507        while (pTestSlices->size()>0)
508        {
509          tmpProx = pTestSlices->back();
510          pTestSlices->pop_back();
511          for (G4ProxyVector::iterator i=pTestSlices->begin();
512                                       i!=pTestSlices->end(); )
513          {
514            if (*i==tmpProx)
515            {
516              i = pTestSlices->erase(i);
517            }
518            else
519            {
520              ++i;
521            }
522          }
523          if ( tmpProx ) { delete tmpProx; }
524        }
525        delete pTestSlices;
526      }
527    }
528  }
529  // Check for error case.. when limits already 3d,
530  // so cannot select a new axis
531  //
532  if (!pGoodSlices)
533  {
534    G4cerr << "ERROR - G4SmartVoxelHeader::BuildVoxelsWithinLimits()"
535           << G4endl
536           << "        Illegal limits: only 3 dimensions allowed." << G4endl;
537    G4Exception("G4SmartVoxelHeader::BuildVoxelsWithinLimits()",
538                "InvalidSetup", FatalException,
539                "Cannot select more than 3 axis for optimisation.");
540    return;
541  }
542
543  //
544  // We have selected pGoodSlices, with a score testSliceScore
545  //
546
547  // Store chosen axis, slice ptr
548  //
549  fslices=*pGoodSlices; // Set slice information, copy ptrs in collection
550  delete pGoodSlices;   // Destroy slices vector, but not contained
551                        // proxies or nodes
552  faxis=goodSliceAxis;
553
554#ifdef G4GEOMETRY_VOXELDEBUG
555  G4cout << G4endl << "     Volume = " << pVolume->GetName()
556         << G4endl << "     Selected axis = " << faxis << G4endl;
557  for (size_t islice=0; islice<fslices.size(); islice++)
558  {
559    G4cout << "     Node #" << islice << " = {";
560    for (G4int j=0; j<fslices[islice]->GetNode()->GetNoContained(); j++)
561    {
562      G4cout << " " << fslices[islice]->GetNode()->GetVolume(j);
563    }
564    G4cout << " }" << G4endl;
565  }
566  G4cout << G4endl;
567#endif
568
569  // Calculate and set min and max extents given our axis
570  //
571  G4VSolid* outerSolid = pVolume->GetSolid();
572  const G4AffineTransform origin;
573  if(!outerSolid->CalculateExtent(faxis,pLimits,origin,fminExtent,fmaxExtent))
574  {
575    outerSolid->CalculateExtent(faxis,noLimits,origin,fminExtent,fmaxExtent);
576  }
577
578  // Calculate equivalent nos
579  //
580  BuildEquivalentSliceNos();
581  CollectEquivalentNodes();     // Collect common nodes
582  RefineNodes(pVolume,pLimits); // Refine nodes creating headers
583
584  // No common headers can exist because collapsed by construction
585}
586
587// ***************************************************************************
588// Calculates and stores the minimum and maximum equivalent neighbour
589// values for all slices at our level.
590//
591// Precondition: all slices are nodes.
592// For each potential start of a group of equivalent nodes:
593// o searches forwards in fslices to find group end
594// o loops from start to end setting start and end slices.
595// ***************************************************************************
596//
597void G4SmartVoxelHeader::BuildEquivalentSliceNos()
598{
599  G4int sliceNo, minNo, maxNo, equivNo;
600  G4int maxNode = fslices.size();
601  G4SmartVoxelNode *startNode, *sampleNode;
602  for (sliceNo=0; sliceNo<maxNode; sliceNo++)
603  {
604    minNo = sliceNo;
605
606    // Get first node (see preconditions - will throw exception if a header)
607    //
608    startNode = fslices[minNo]->GetNode();
609
610    // Find max equivalent
611    //
612    for (equivNo=minNo+1; equivNo<maxNode; equivNo++)
613    {
614      sampleNode = fslices[equivNo]->GetNode();
615      if (!((*startNode) == (*sampleNode))) { break; }
616    }
617    maxNo = equivNo-1;
618    if (maxNo != minNo)
619    {
620      // Set min and max nos
621      //
622      for (equivNo=minNo; equivNo<=maxNo; equivNo++)
623      {
624        sampleNode = fslices[equivNo]->GetNode();
625        sampleNode->SetMinEquivalentSliceNo(minNo);
626        sampleNode->SetMaxEquivalentSliceNo(maxNo);
627      }
628      // Advance outer loop to end of equivalent group
629      //
630      sliceNo = maxNo;
631    }
632  }
633}
634
635// ***************************************************************************
636// Collects common nodes at our level, deleting all but one to save
637// memory, and adjusting stored slice pointers appropriately.
638//
639// Preconditions:
640// o the slices have not previously be "collected"
641// o all of the slices are nodes.
642// ***************************************************************************
643//
644void G4SmartVoxelHeader::CollectEquivalentNodes()
645{
646  G4int sliceNo, maxNo, equivNo;
647  G4int maxNode=fslices.size();
648  G4SmartVoxelNode *equivNode;
649  G4SmartVoxelProxy *equivProxy;
650
651  for (sliceNo=0; sliceNo<maxNode; sliceNo++)
652  {
653    equivProxy=fslices[sliceNo];
654
655    // Assumption (see preconditions): all slices are nodes
656    //
657    equivNode = equivProxy->GetNode();
658    maxNo = equivNode->GetMaxEquivalentSliceNo();
659    if (maxNo != sliceNo)
660    {
661#ifdef G4GEOMETRY_VOXELDEBUG
662      G4cout << "**** G4SmartVoxelHeader::CollectEquivalentNodes" << G4endl
663             << "     Collecting Nodes = " 
664             << sliceNo << " - " << maxNo << G4endl;
665#endif
666      // Do collection between sliceNo and maxNo inclusive
667      //
668      for (equivNo=sliceNo+1; equivNo<=maxNo; equivNo++)
669      {
670        delete fslices[equivNo]->GetNode();
671        delete fslices[equivNo];
672        fslices[equivNo] = equivProxy;
673      }
674      sliceNo = maxNo;
675    }
676  }
677}
678
679// ***************************************************************************
680// Collects common headers at our level, deleting all but one to save
681// memory, and adjusting stored slice pointers appropriately.
682//
683// Preconditions:
684// o if a header forms part of a range of equivalent slices
685//   (ie. GetMaxEquivalentSliceNo()>GetMinEquivalentSliceNo()),
686//   it is assumed that all slices in the range are headers.
687// o this will be true if a constant Expression is used to evaluate
688//   when to refine nodes.
689// ***************************************************************************
690//
691void G4SmartVoxelHeader::CollectEquivalentHeaders()
692{
693  G4int sliceNo, maxNo, equivNo;
694  G4int maxNode = fslices.size();
695  G4SmartVoxelHeader *equivHeader, *sampleHeader;
696  G4SmartVoxelProxy *equivProxy;
697
698  for (sliceNo=0; sliceNo<maxNode; sliceNo++)
699  {
700    equivProxy = fslices[sliceNo];
701    if (equivProxy->IsHeader())
702    {
703      equivHeader = equivProxy->GetHeader();
704      maxNo = equivHeader->GetMaxEquivalentSliceNo();
705      if (maxNo != sliceNo)
706      {
707        // Attempt collection between sliceNo and maxNo inclusive:
708        // look for common headers. All slices between sliceNo and maxNo
709        // are guaranteed to be headers but may not have equal contents
710        //
711#ifdef G4GEOMETRY_VOXELDEBUG
712        G4cout << "**** G4SmartVoxelHeader::CollectEquivalentHeaders" << G4endl
713               << "     Collecting Headers =";
714#endif
715        for (equivNo=sliceNo+1; equivNo<=maxNo; equivNo++)
716        {
717          sampleHeader = fslices[equivNo]->GetHeader();
718          if ( (*sampleHeader) == (*equivHeader) )
719          {
720#ifdef G4GEOMETRY_VOXELDEBUG
721            G4cout << " " << equivNo;
722#endif
723            // Delete sampleHeader + proxy and replace with equivHeader/Proxy
724            //
725            delete sampleHeader;
726            delete fslices[equivNo];
727            fslices[equivNo] = equivProxy;
728          }
729          else
730          {
731            // Not equal. Set this header to be
732            // the current header for comparisons
733            //
734            equivProxy  = fslices[equivNo];
735            equivHeader = equivProxy->GetHeader();
736          }
737
738        }
739#ifdef G4GEOMETRY_VOXELDEBUG
740        G4cout << G4endl;
741#endif
742        // Skip past examined slices
743        //
744        sliceNo = maxNo;
745      }
746    }
747  }
748}
749
750// ***************************************************************************
751// Builds the nodes corresponding to slices between the specified limits
752// and along the specified axis, using candidate volume no.s in the vector
753// pCandidates. If the `daughters' are replicated volumes (ie. the logical
754// volume has a single replicated/parameterised volume for a daughter)
755// the candidate no.s are interpreted as PARAMETERISED volume no.s &
756// PARAMETERISATIONs are applied to compute transformations & solid
757// dimensions appropriately. The volume must be parameterised - ie. has a
758// parameterisation object & non-consuming) - in this case.
759//
760// Returns pointer to built node "structure" (guaranteed non NULL) consisting
761// of G4SmartVoxelNodeProxies referring to G4SmartVoxelNodes.
762// ***************************************************************************
763//
764G4ProxyVector* G4SmartVoxelHeader::BuildNodes(G4LogicalVolume* pVolume,
765                                              G4VoxelLimits pLimits,
766                                        const G4VolumeNosVector* pCandidates,
767                                              EAxis pAxis)
768{
769  G4double motherMinExtent= kInfinity, motherMaxExtent= -kInfinity,
770           targetMinExtent= kInfinity, targetMaxExtent= -kInfinity;
771  G4VPhysicalVolume *pDaughter=0;
772  G4VPVParameterisation *pParam=0;
773  G4VSolid *targetSolid;
774  G4AffineTransform targetTransform;
775  G4bool replicated;
776  G4int nCandidates = pCandidates->size();
777  G4int nVol, nNode, targetVolNo;
778  G4VoxelLimits noLimits;
779   
780#ifdef G4GEOMETRY_VOXELDEBUG
781  G4cout << "**** G4SmartVoxelHeader::BuildNodes" << G4endl
782         << "     Limits = " << pLimits << G4endl
783         << "       Axis = " << pAxis << G4endl
784         << " Candidates = " << nCandidates << G4endl;
785#endif
786
787  // Compute extent of logical volume's solid along this axis
788  // NOTE: results stored locally and not preserved/reused
789  //
790  G4VSolid* outerSolid = pVolume->GetSolid();
791  const G4AffineTransform origin;
792  if( !outerSolid->CalculateExtent(pAxis, pLimits, origin,
793                                   motherMinExtent, motherMaxExtent) )
794  {
795    outerSolid->CalculateExtent(pAxis, noLimits, origin,
796                                motherMinExtent, motherMaxExtent);
797  }
798  G4VolumeExtentVector minExtents(nCandidates,0.);
799  G4VolumeExtentVector maxExtents(nCandidates,0.);
800
801  if ( (pVolume->GetNoDaughters()==1)
802    && (pVolume->GetDaughter(0)->IsReplicated()==true) )
803  {
804    // Replication data not required: only parameterisation object
805    // and volume no. List used
806    //
807    pDaughter = pVolume->GetDaughter(0);
808    pParam = pDaughter->GetParameterisation();
809    if (!pParam)
810    {
811      G4cerr << "PANIC! - G4SmartVoxelHeader::BuildNodes()" << G4endl
812             << "         Replicated volume with no parameterisation object !"
813             << G4endl;
814      G4Exception("G4SmartVoxelHeader::BuildNodes()", "InvalidSetup",
815                  FatalException, "Missing parameterisation.");
816      return 0;
817    }
818
819    // Setup daughter's transformations
820    //
821    targetTransform = G4AffineTransform(pDaughter->GetRotation(),
822                                        pDaughter->GetTranslation());
823    replicated = true;
824  }
825    else
826  {
827    replicated = false;
828  }
829   
830  // Compute extents
831  //
832  for (nVol=0; nVol<nCandidates; nVol++)
833  {
834    targetVolNo=(*pCandidates)[nVol];
835    if (replicated == false)
836    {
837      pDaughter=pVolume->GetDaughter(targetVolNo);
838
839      // Setup daughter's transformations
840      //
841      targetTransform = G4AffineTransform(pDaughter->GetRotation(),
842                                          pDaughter->GetTranslation());
843      // Get underlying (and setup) solid
844      //
845      targetSolid = pDaughter->GetLogicalVolume()->GetSolid();
846    }
847    else
848    {
849      // Find  solid
850      //
851      targetSolid = pParam->ComputeSolid(targetVolNo,pDaughter);
852
853      // Setup solid
854      //
855      targetSolid->ComputeDimensions(pParam,targetVolNo,pDaughter);
856
857      // Setup transform
858      //
859      pParam->ComputeTransformation(targetVolNo,pDaughter);
860      targetTransform = G4AffineTransform(pDaughter->GetRotation(),
861                                          pDaughter->GetTranslation());
862    }
863    // Calculate extents
864    //
865    if(!targetSolid->CalculateExtent(pAxis, pLimits, targetTransform,
866                                     targetMinExtent, targetMaxExtent))
867    {
868      targetSolid->CalculateExtent(pAxis, noLimits, targetTransform,
869                                   targetMinExtent,targetMaxExtent);
870    }
871    minExtents[nVol] = targetMinExtent;
872    maxExtents[nVol] = targetMaxExtent;
873
874#ifdef G4GEOMETRY_VOXELDEBUG
875   G4cout << "---------------------------------------------------" << G4endl
876          << "     Volume = " << pDaughter->GetName() << G4endl
877          << " Min Extent = " << targetMinExtent << G4endl
878          << " Max Extent = " << targetMaxExtent << G4endl
879          << "---------------------------------------------------" << G4endl;
880#endif
881
882    // Check not entirely outside mother when processing toplevel nodes
883    //
884    if ( (!pLimits.IsLimited()) && ((targetMaxExtent<=motherMinExtent)
885                                  ||(targetMinExtent>=motherMaxExtent)) )
886    {
887      G4cerr << "PANIC! - G4SmartVoxelHeader::BuildNodes()" << G4endl
888             << "         Daughter physical volume "
889             << pDaughter->GetName() << G4endl
890             << "         is entirely outside mother logical volume "
891             << pVolume->GetName() << " !!" << G4endl;
892      G4Exception("G4SmartVoxelHeader::BuildNodes()", "InvalidSetup",
893                  FatalException, "Overlapping daughter with mother volume.");
894    }
895
896#ifdef G4GEOMETRY_VOXELDEBUG
897    // Check for straddling volumes when debugging.
898    // If a volume is >kStraddlePercent percent over the mother
899    // boundary, print a warning.
900    //
901    if (!pLimits.IsLimited())
902    {
903      G4double width;
904      G4int kStraddlePercent=5;
905      width = maxExtents[nVol]-minExtents[nVol];
906      if ( (((motherMinExtent-minExtents[nVol])*100/width) > kStraddlePercent)
907         ||(((maxExtents[nVol]-motherMaxExtent)*100/width) > kStraddlePercent) )
908      {
909        G4cout << "**** G4SmartVoxelHeader::BuildNodes" << G4endl
910               << "     WARNING : Daughter # " << nVol
911               << " name = " << pDaughter->GetName() << G4endl
912               << "     Crosses mother boundary of logical volume, name = " 
913               << pVolume->GetName() << G4endl
914               << "     by more than " << kStraddlePercent
915               << "%" << G4endl;
916      }
917    }
918#endif
919  }
920
921  // Extents of all daughters known
922
923  // Calculate minimum slice width, only including volumes inside the limits
924  //
925  G4double minWidth = kInfinity;
926  G4double currentWidth;
927  for (nVol=0; nVol<nCandidates; nVol++)
928  {
929    // currentWidth should -always- be a positive value. Inaccurate computed extent
930    // from the solid or situations of malformed geometries (overlaps) may lead to
931    // negative values and therefore unpredictable crashes !
932    //
933    currentWidth = std::abs(maxExtents[nVol]-minExtents[nVol]);
934    if ( (currentWidth<minWidth)
935      && (maxExtents[nVol]>=pLimits.GetMinExtent(pAxis))
936      && (minExtents[nVol]<=pLimits.GetMaxExtent(pAxis)) )
937    {
938      minWidth = currentWidth;
939    }
940  }
941
942  // No. of Nodes formula - nearest integer to
943  // mother width/half min daughter width +1
944  //
945  G4double noNodesExactD = ((motherMaxExtent-motherMinExtent)*2.0/minWidth)+1.0;
946
947  // Compare with "smartless quality", i.e. the average number of slices
948  // used per contained volume.
949  //
950  G4double smartlessComputed = noNodesExactD / nCandidates;
951  G4double smartlessUser = pVolume->GetSmartless();
952  G4double smartless = (smartlessComputed <= smartlessUser)
953                       ? smartlessComputed : smartlessUser;
954  G4double noNodesSmart = smartless*nCandidates;
955  G4int    noNodesExactI = G4int(noNodesSmart);
956  G4int    noNodes = ((noNodesSmart-noNodesExactI)>=0.5)
957                     ? noNodesExactI+1 : noNodesExactI;
958  if( noNodes == 0 ) { noNodes=1; }
959
960#ifdef G4GEOMETRY_VOXELDEBUG
961  G4cout << "     Smartless computed = " << smartlessComputed << G4endl
962         << "     Smartless volume = " << smartlessUser
963         << " => # Smartless = " << smartless << G4endl;
964  G4cout << "     Min width = " << minWidth
965         << " => # Nodes = " << noNodes << G4endl;
966#endif
967
968  if (noNodes>kMaxVoxelNodes)
969  {
970    noNodes=kMaxVoxelNodes;
971#ifdef G4GEOMETRY_VOXELDEBUG
972    G4cout << "     Nodes Clipped to = " << kMaxVoxelNodes << G4endl;
973#endif   
974  }
975  G4double nodeWidth = (motherMaxExtent-motherMinExtent)/noNodes;
976
977  // Create G4VoxelNodes. Will Add proxies before setting fslices
978  //
979  G4NodeVector* nodeList = new G4NodeVector();
980  if (!nodeList)
981  {
982    G4cerr << "ERROR - G4SmartVoxelHeader::BuildNodes()" << G4endl
983           << "        NodeList allocation failed." << G4endl;
984    G4Exception("G4SmartVoxelHeader::BuildNodes()", "FatalError",
985                FatalException, "NodeList allocation error.");
986    return 0;
987  }
988  nodeList->reserve(noNodes);
989
990  for (nNode=0; nNode<noNodes; nNode++)
991  {
992    G4SmartVoxelNode *pNode;
993    pNode = new G4SmartVoxelNode(nNode);
994    if (!pNode)
995    {
996      G4cerr << "ERROR - G4SmartVoxelHeader::BuildNodes()" << G4endl
997             << "        Node allocation failed." << G4endl;
998      G4Exception("G4SmartVoxelHeader::BuildNodes()", "FatalError",
999                  FatalException, "Node allocation error.");
1000      return 0;
1001    }
1002    nodeList->push_back(pNode);
1003  }
1004
1005  // All nodes created (empty)
1006
1007  // Fill nodes: Step through extent lists
1008  //
1009  for (nVol=0; nVol<nCandidates; nVol++)
1010  {
1011    G4int nodeNo, minContainingNode, maxContainingNode;
1012    minContainingNode = G4int((minExtents[nVol]-motherMinExtent)/nodeWidth);
1013    maxContainingNode = G4int((maxExtents[nVol]-motherMinExtent)/nodeWidth);
1014
1015    // Only add nodes that are inside the limits of the axis
1016    //
1017    if ( (maxContainingNode>=0) && (minContainingNode<noNodes) )
1018    {
1019      // If max extent is on max boundary => maxContainingNode=noNodes:
1020      // should be one less as nodeList has noNodes entries
1021      //
1022      if (maxContainingNode>=noNodes)
1023      {
1024        maxContainingNode = noNodes-1;
1025      }
1026      //
1027      // Protection against protruding volumes
1028      //
1029      if (minContainingNode<0)
1030      {
1031        minContainingNode=0;
1032      }
1033      for (nodeNo=minContainingNode; nodeNo<=maxContainingNode; nodeNo++)
1034      {
1035        (*nodeList)[nodeNo]->Insert((*pCandidates)[nVol]);
1036      }
1037    }
1038  }
1039
1040  // All nodes filled
1041
1042  // Create proxy List : caller has deletion responsibility
1043  // (but we must delete nodeList *itself* - not the contents)
1044  //
1045  G4ProxyVector* proxyList = new G4ProxyVector();
1046  if (!proxyList)
1047  {
1048    G4cerr << "ERROR - G4SmartVoxelHeader::BuildNodes()" << G4endl
1049           << "        Proxy list allocation failed." << G4endl;
1050    G4Exception("G4SmartVoxelHeader::BuildNodes()", "FatalError",
1051                FatalException, "Proxy list allocation error.");
1052    return 0;
1053  }
1054  proxyList->reserve(noNodes);
1055
1056  //
1057  // Fill proxy List
1058  //
1059  for (nNode=0; nNode<noNodes; nNode++)
1060  {
1061    // Get rid of possible excess capacity in the internal node vector
1062    //
1063    ((*nodeList)[nNode])->Shrink();
1064    G4SmartVoxelProxy* pProxyNode = new G4SmartVoxelProxy((*nodeList)[nNode]);
1065    if (!pProxyNode)
1066    {
1067      G4cerr << "ERROR - G4SmartVoxelHeader::BuildNodes()" << G4endl
1068             << "        Proxy node allocation failed." << G4endl;
1069      G4Exception("G4SmartVoxelHeader::BuildNodes()", "FatalError",
1070                  FatalException, "Proxy node allocation failed.");
1071      return 0;
1072    }
1073    proxyList->push_back(pProxyNode);
1074  }
1075  delete nodeList;
1076  return proxyList;
1077}
1078
1079// ***************************************************************************
1080// Calculate a "quality value" for the specified vector of voxels.
1081// The value returned should be >0 and such that the smaller the number
1082// the higher the quality of the slice.
1083//
1084// Preconditions: pSlice must consist of G4SmartVoxelNodeProxies only
1085// Process:
1086// o Examine each node in turn, summing:
1087//      no. of non-empty nodes
1088//      no. of volumes in each node
1089// o Calculate Quality=sigma(volumes in nod)/(no. of non-empty nodes)
1090//      if all nodes empty, return kInfinity
1091// o Call G4Exception on finding a G4SmartVoxelHeaderProxy
1092// ***************************************************************************
1093//
1094G4double G4SmartVoxelHeader::CalculateQuality(G4ProxyVector *pSlice)
1095{
1096  G4double quality;
1097  G4int nNodes = pSlice->size();
1098  G4int noContained, maxContained=0, sumContained=0, sumNonEmptyNodes=0;
1099  G4SmartVoxelNode *node;
1100
1101  for (G4int i=0; i<nNodes; i++)
1102  {
1103    if ((*pSlice)[i]->IsNode())
1104    {
1105      // Definitely a node. Add info to running totals
1106      //
1107      node = (*pSlice)[i]->GetNode();
1108      noContained = node->GetNoContained();
1109      if (noContained)
1110      {
1111        sumNonEmptyNodes++;
1112        sumContained += noContained;
1113        //
1114        // Calc maxContained for statistics
1115        //
1116        if (noContained>maxContained)
1117        {
1118          maxContained = noContained;
1119        }
1120      }
1121    }
1122    else
1123    {
1124      G4cout << "ERROR - G4SmartVoxelHeader::CalculateQuality()" << G4endl
1125             << "        Not defined for sliced volumes." << G4endl;
1126      G4Exception("G4SmartVoxelHeader::CalculateQuality()", "NotApplicable",
1127                  FatalException, "Not applicable to replicated volumes.");
1128    }
1129  }
1130
1131  // Calculate quality with protection against no non-empty nodes
1132  //
1133  if (sumNonEmptyNodes)
1134  {
1135    quality = sumContained/sumNonEmptyNodes;
1136  }
1137  else
1138  {
1139    quality = kInfinity;
1140  }
1141
1142#ifdef G4GEOMETRY_VOXELDEBUG
1143  G4cout << "**** G4SmartVoxelHeader::CalculateQuality" << G4endl
1144         << "     Quality = " << quality << G4endl
1145         << "     Nodes = " << nNodes
1146         << " of which " << sumNonEmptyNodes << " non empty" << G4endl
1147         << "     Max Contained = " << maxContained << G4endl;
1148#endif
1149
1150  return quality;
1151}
1152
1153// ***************************************************************************
1154// Examined each contained node, refines (creates a replacement additional
1155// dimension of voxels) when there is more than one voxel in the slice.
1156// Does not refine further if already limited in two dimensions (=> this
1157// is the third level of limits)
1158//
1159// Preconditions: slices (nodes) have been built.
1160// ***************************************************************************
1161//
1162void G4SmartVoxelHeader::RefineNodes(G4LogicalVolume* pVolume,
1163                                     G4VoxelLimits pLimits)
1164{
1165  G4int refinedDepth=0, minVolumes;
1166  G4int maxNode = fslices.size();
1167
1168  if (pLimits.IsXLimited()) 
1169  {
1170    refinedDepth++;
1171  }
1172  if (pLimits.IsYLimited()) 
1173  {
1174    refinedDepth++;
1175  }
1176  if (pLimits.IsZLimited()) 
1177  {
1178    refinedDepth++;
1179  }
1180
1181  // Calculate minimum number of volumes necessary to refine
1182  //
1183  switch (refinedDepth)
1184  {
1185    case 0:
1186      minVolumes=kMinVoxelVolumesLevel2;
1187      break;
1188    case 1:
1189      minVolumes=kMinVoxelVolumesLevel3;
1190      break;
1191    default:
1192      minVolumes=10000;   // catch refinedDepth=3 and errors
1193      break;
1194  }
1195
1196  if (refinedDepth<2)
1197  {
1198    G4int targetNo, noContainedDaughters, minNo, maxNo, replaceNo, i;
1199    G4double sliceWidth = (fmaxExtent-fminExtent)/maxNode;
1200    G4VoxelLimits newLimits;
1201    G4SmartVoxelNode* targetNode;
1202    G4SmartVoxelProxy* targetNodeProxy;
1203    G4SmartVoxelHeader* replaceHeader;
1204    G4SmartVoxelProxy* replaceHeaderProxy;
1205    G4VolumeNosVector* targetList;
1206    G4SmartVoxelProxy* lastProxy;
1207     
1208    for (targetNo=0; targetNo<maxNode; targetNo++)
1209    {
1210      // Assume all slices are nodes (see preconditions)
1211      //
1212      targetNodeProxy = fslices[targetNo];
1213      targetNode = targetNodeProxy->GetNode();
1214
1215      if (targetNode->GetNoContained() >= minVolumes)
1216      {
1217        noContainedDaughters = targetNode->GetNoContained();
1218        targetList = new G4VolumeNosVector();
1219        if (!targetList)
1220        {
1221          G4cerr << "ERROR - G4SmartVoxelHeader::RefineNodes()" << G4endl
1222                 << "        Target volume node list allocation failed."
1223                 << G4endl;
1224          G4Exception("G4SmartVoxelHeader::RefineNodes()",
1225                      "FatalError", FatalException,
1226                      "Target volume node list allocation error.");
1227          return;
1228        }
1229        targetList->reserve(noContainedDaughters);
1230        for (i=0; i<noContainedDaughters; i++)
1231        {
1232          targetList->push_back(targetNode->GetVolume(i));
1233        }
1234        minNo = targetNode->GetMinEquivalentSliceNo();
1235        maxNo = targetNode->GetMaxEquivalentSliceNo();
1236
1237#ifdef G4GEOMETRY_VOXELDEBUG
1238        G4cout << "**** G4SmartVoxelHeader::RefineNodes" << G4endl
1239               << "     Refining nodes " << minNo
1240               << " - " << maxNo << " inclusive" << G4endl;
1241#endif
1242        if (minNo > maxNo)    // Delete node and list to be replaced
1243        {                     // and avoid further action ...
1244          delete targetNode;
1245          delete targetList;
1246          return;
1247        }
1248
1249        // Delete node proxies at start of collected sets of nodes/headers
1250        //
1251        lastProxy=0;
1252        for (replaceNo=minNo; replaceNo<=maxNo; replaceNo++)
1253        {
1254          if (lastProxy != fslices[replaceNo])
1255          {
1256            lastProxy=fslices[replaceNo];
1257            delete lastProxy;
1258          }
1259        }
1260        // Delete node to be replaced
1261        //
1262        delete targetNode;
1263
1264        // Create new headers + proxies and replace in fslices
1265        //
1266        newLimits = pLimits;
1267        newLimits.AddLimit(faxis,fminExtent+sliceWidth*minNo,
1268                           fminExtent+sliceWidth*(maxNo+1));
1269        replaceHeader = new G4SmartVoxelHeader(pVolume,newLimits,
1270                                               targetList,replaceNo);
1271        if (!replaceHeader)
1272        {
1273          G4cerr << "ERROR - G4SmartVoxelHeader::RefineNodes()" << G4endl
1274                 << "        Refined VoxelHeader allocation failed." << G4endl;
1275          G4Exception("G4SmartVoxelHeader::RefineNodes()", "FatalError",
1276                      FatalException, "Refined VoxelHeader allocation error.");
1277          return;
1278        }
1279        replaceHeader->SetMinEquivalentSliceNo(minNo);
1280        replaceHeader->SetMaxEquivalentSliceNo(maxNo);
1281        replaceHeaderProxy = new G4SmartVoxelProxy(replaceHeader);
1282        if (!replaceHeaderProxy)
1283        {
1284          G4cerr << "ERROR - G4SmartVoxelHeader::RefineNodes()" << G4endl
1285                 << "        Refined VoxelProxy allocation failed." << G4endl;
1286          G4Exception("G4SmartVoxelHeader::RefineNodes()", "FatalError",
1287                      FatalException, "Refined VoxelProxy allocation error.");
1288          return;
1289        }
1290        for (replaceNo=minNo; replaceNo<=maxNo; replaceNo++)
1291        {
1292          fslices[replaceNo] = replaceHeaderProxy;
1293        }
1294        // Finished replacing current `equivalent' group
1295        //
1296        delete targetList;
1297        targetNo=maxNo;
1298      }
1299    }
1300  }
1301}
1302
1303// ***************************************************************************
1304// Returns true if all slices have equal contents.
1305// Preconditions: all equal slices have been collected.
1306// Procedure:
1307// o checks all slice proxy pointers are equal
1308// o returns true if only one slice or all slice proxies pointers equal.
1309// ***************************************************************************
1310//
1311G4bool G4SmartVoxelHeader::AllSlicesEqual() const
1312{
1313  G4int noSlices = fslices.size();
1314  G4SmartVoxelProxy* refProxy;
1315
1316  if (noSlices>1)
1317  {
1318    refProxy=fslices[0];
1319    for (G4int i=1; i<noSlices; i++)
1320    {
1321      if (refProxy!=fslices[i])
1322      {
1323        return false;
1324      }
1325    }
1326  }
1327  return true;
1328}
1329
1330// ***************************************************************************
1331// Streaming operator for debugging.
1332// ***************************************************************************
1333//
1334std::ostream& operator << (std::ostream& s, const G4SmartVoxelHeader& h)
1335{
1336  s << "Axis = " << G4int(h.faxis) << G4endl;
1337  G4SmartVoxelProxy *collectNode=0, *collectHead=0;
1338  G4int collectNodeNo=0;
1339  G4int collectHeadNo=0;
1340  size_t i, j;
1341  G4bool haveHeaders=false;
1342
1343  for (i=0; i<h.fslices.size(); i++)
1344  {
1345    s << "Slice #" << i << " = ";
1346    if (h.fslices[i]->IsNode())
1347    {
1348      if (h.fslices[i]!=collectNode)
1349      {
1350        s << "{";
1351        for (G4int j=0; j<h.fslices[i]->GetNode()->GetNoContained(); j++)
1352        {
1353          s << " " << h.fslices[i]->GetNode()->GetVolume(j);
1354        }
1355        s << " }" << G4endl;
1356        collectNode = h.fslices[i];
1357        collectNodeNo = i;
1358      }
1359      else
1360      {
1361        s << "As slice #" << collectNodeNo << G4endl;
1362      }
1363    }
1364    else
1365    {
1366      haveHeaders=true;
1367      if (h.fslices[i] != collectHead)
1368      {
1369        s << "Header" << G4endl;
1370        collectHead = h.fslices[i];
1371        collectHeadNo = i;
1372      }
1373      else
1374      {
1375        s << "As slice #" << collectHeadNo << G4endl;
1376      }
1377    }
1378  }
1379
1380  if (haveHeaders)
1381  {
1382    collectHead=0;
1383    for (j=0; j<h.fslices.size(); j++)
1384    {
1385      if (h.fslices[j]->IsHeader())
1386      {
1387        s << "Header at Slice #" << j << " = ";
1388        if (h.fslices[j] != collectHead)
1389        {
1390          s << G4endl
1391            << (*(h.fslices[j]->GetHeader()));
1392          collectHead = h.fslices[j];
1393          collectHeadNo = j;
1394        }
1395        else
1396        {
1397          s << "As slice #" << collectHeadNo << G4endl;
1398        }
1399      }
1400    }
1401  }
1402  return s;
1403}
Note: See TracBrowser for help on using the repository browser.