ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4LogicalVolume.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4LogicalVolume.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 // class G4LogicalVolume implementation
27 //
28 // 15.01.13 G.Cosmo, A.Dotti: Modified for thread-safety for MT
29 // 01.03.05 G.Santin: Added flag for optional propagation of GetMass()
30 // 17.05.02 G.Cosmo: Added flag for optional optimisation
31 // 12.02.99 S.Giani: Default initialization of voxelization quality
32 // 04.08.97 P.M.DeFreitas: Added methods for parameterised simulation
33 // 11.07.95 P.Kent: Initial version
34 // --------------------------------------------------------------------
35 
36 #include "G4LogicalVolume.hh"
37 #include "G4LogicalVolumeStore.hh"
38 #include "G4VSolid.hh"
39 #include "G4Material.hh"
40 #include "G4VPVParameterisation.hh"
41 #include "G4VisAttributes.hh"
42 
43 #include "G4UnitsTable.hh"
44 
46 
47 // This new field helps to use the class G4LVManager
48 //
50 
51 // These macros change the references to fields that are now encapsulated
52 // in the class G4LVData.
53 //
54 #define G4MT_solid ((subInstanceManager.offset[instanceID]).fSolid)
55 #define G4MT_sdetector ((subInstanceManager.offset[instanceID]).fSensitiveDetector)
56 #define G4MT_fmanager ((subInstanceManager.offset[instanceID]).fFieldManager)
57 #define G4MT_material ((subInstanceManager.offset[instanceID]).fMaterial)
58 #define G4MT_mass ((subInstanceManager.offset[instanceID]).fMass)
59 #define G4MT_ccouple ((subInstanceManager.offset[instanceID]).fCutsCouple)
60 #define G4MT_instance (subInstanceManager.offset[instanceID])
61 
62 // ********************************************************************
63 // Constructor - sets member data and adds to logical Store,
64 // voxel pointer for optimisation set to 0 by default.
65 // Initialises daughter vector to 0 length.
66 // ********************************************************************
67 //
69  G4Material* pMaterial,
70  const G4String& name,
71  G4FieldManager* pFieldMgr,
72  G4VSensitiveDetector* pSDetector,
73  G4UserLimits* pULimits,
74  G4bool optimise )
75  : fDaughters(0,(G4VPhysicalVolume*)nullptr), fDaughtersVolumeType(kNormal),
76  fOptimise(optimise)
77 {
78  // Initialize 'Shadow'/master pointers - for use in copying to workers
79  //
80  fSolid = pSolid;
81  fSensitiveDetector = pSDetector;
82  fFieldManager = pFieldMgr;
83 
85  AssignFieldManager(pFieldMgr);
86 
87  G4MT_mass = 0.;
88  G4MT_ccouple = nullptr;
89 
90  SetSolid(pSolid);
91  SetMaterial(pMaterial);
92  SetName(name);
93  SetSensitiveDetector(pSDetector);
94  SetUserLimits(pULimits);
95 
96  // Initialize 'Shadow' data structure - for use by object persistency
97  //
98  lvdata = new G4LVData();
99  lvdata->fSolid = pSolid;
100  lvdata->fMaterial = pMaterial;
101 
102  //
103  // Add to store
104  //
106 }
107 
108 // ********************************************************************
109 // Fake default constructor - sets only member data and allocates memory
110 // for usage restricted to object persistency.
111 // ********************************************************************
112 //
114  : fDaughters(0,(G4VPhysicalVolume*)nullptr), fName("")
115 {
117 
118  SetSensitiveDetector(nullptr); // G4MT_sdetector = nullptr;
119  SetFieldManager(nullptr, false); // G4MT_fmanager = nullptr;
120 
121  G4MT_mass = 0.;
122  G4MT_ccouple = nullptr;
123 
124  // Add to store
125  //
127 }
128 
129 // ********************************************************************
130 // Destructor - Removes itself from solid Store
131 // NOTE: Not virtual
132 // ********************************************************************
133 //
135 {
136  if (!fLock && fRootRegion) // De-register root region first if not locked
137  { // and flagged as root logical-volume
138  fRegion->RemoveRootLogicalVolume(this, true);
139  }
140  delete lvdata;
142 }
143 
144 // ********************************************************************
145 // InitialiseWorker
146 //
147 // This method is similar to the constructor. It is used by each worker
148 // thread to achieve the same effect as that of the master thread exept
149 // to register the new created instance. This method is invoked explicitly.
150 // It does not create a new G4LogicalVolume instance. It only assign the value
151 // for the fields encapsulated by the class G4LVData.
152 // ********************************************************************
153 //
155 InitialiseWorker( G4LogicalVolume* /*pMasterObject*/,
156  G4VSolid* pSolid,
157  G4VSensitiveDetector* pSDetector)
158 {
160 
161  SetSolid(pSolid);
162  SetSensitiveDetector(pSDetector); // How this object is available now ?
164  // Should be set - but a per-thread copy is not available yet
165  // Must not call SetFieldManager(), which propagates FieldMgr
166 
167 #ifdef CLONE_FIELD_MGR
168  // Create a field FieldManager by cloning
169  //
170  G4FieldManager workerFldMgr = fFieldManager->GetWorkerClone(G4bool* created);
171  if( created || (GetFieldManager() != workerFldMgr) )
172  {
173  SetFieldManager(fFieldManager, false); // which propagates FieldMgr
174  }
175  else
176  {
177  // Field manager existed and is equal to current one
178  //
179  AssignFieldManager(workerFldMgr);
180  }
181 #endif
182 }
183 
184 // ********************************************************************
185 // Clean
186 // ********************************************************************
187 //
189 {
191 }
192 
193 // ********************************************************************
194 // TerminateWorker
195 //
196 // This method is similar to the destructor. It is used by each worker
197 // thread to achieve the partial effect as that of the master thread.
198 // For G4LogicalVolume instances, nothing more to do here.
199 // ********************************************************************
200 //
202 TerminateWorker( G4LogicalVolume* /*pMasterObject*/)
203 {
204 }
205 
206 // ********************************************************************
207 // GetSubInstanceManager
208 //
209 // Returns the private data instance manager.
210 // ********************************************************************
211 //
213 {
214  return subInstanceManager;
215 }
216 
217 // ********************************************************************
218 // GetFieldManager
219 // ********************************************************************
220 //
222 {
223  return G4MT_fmanager;
224 }
225 
226 // ********************************************************************
227 // AssignFieldManager
228 // ********************************************************************
229 //
231 {
232  G4MT_fmanager= fldMgr;
233  if(G4Threading::IsMasterThread()) { fFieldManager = fldMgr; }
234 }
235 
236 // ********************************************************************
237 // IsExtended
238 // ********************************************************************
239 //
241 {
242  return false;
243 }
244 
245 // ********************************************************************
246 // SetFieldManager
247 // ********************************************************************
248 //
249 void
251  G4bool forceAllDaughters)
252 {
253  AssignFieldManager(pNewFieldMgr);
254 
255  auto NoDaughters = GetNoDaughters();
256  while ( (NoDaughters--)>0 )
257  {
258  G4LogicalVolume* DaughterLogVol;
259  DaughterLogVol = GetDaughter(NoDaughters)->GetLogicalVolume();
260  if ( forceAllDaughters || (DaughterLogVol->GetFieldManager() == nullptr) )
261  {
262  DaughterLogVol->SetFieldManager(pNewFieldMgr, forceAllDaughters);
263  }
264  }
265 }
266 
267 // ********************************************************************
268 // AddDaughter
269 // ********************************************************************
270 //
272 {
273  EVolume daughterType = pNewDaughter->VolumeType();
274 
275  // The type of the navigation needed is determined by the first daughter
276  //
277  if( fDaughters.empty() )
278  {
279  fDaughtersVolumeType = daughterType;
280  }
281  else
282  {
283  // Check consistency of detector description
284 
285  // 1. A replica or parameterised volume can have only one daughter
286  //
287  if( fDaughters[0]->IsReplicated() )
288  {
289  std::ostringstream message;
290  message << "ERROR - Attempt to place a volume in a mother volume"
291  << G4endl
292  << " already containing a replicated volume." << G4endl
293  << " A volume can either contain several placements" << G4endl
294  << " or a unique replica or parameterised volume !" << G4endl
295  << " Mother logical volume: " << GetName() << G4endl
296  << " Placing volume: " << pNewDaughter->GetName()
297  << G4endl;
298  G4Exception("G4LogicalVolume::AddDaughter()", "GeomMgt0002",
299  FatalException, message,
300  "Replica or parameterised volume must be the only daughter!");
301  }
302  else
303  {
304  // 2. Ensure that Placement and External physical volumes do not mix
305  //
306  if( daughterType != fDaughtersVolumeType )
307  {
308  std::ostringstream message;
309  message << "ERROR - Attempt to place a volume in a mother volume"
310  << G4endl
311  << " already containing a different type of volume." << G4endl
312  << " A volume can either contain" << G4endl
313  << " - one or more placements, OR" << G4endl
314  << " - one or more 'external' type physical volumes." << G4endl
315  << " Mother logical volume: " << GetName() << G4endl
316  << " Volume being placed: " << pNewDaughter->GetName()
317  << G4endl;
318  G4Exception("G4LogicalVolume::AddDaughter()", "GeomMgt0002",
319  FatalException, message,
320  "Cannot mix placements and external physical volumes !");
321  }
322  }
323  }
324 
325  // Invalidate previous calculation of mass - if any - for all threads
326  //
327  G4MT_mass = 0.;
328  fDaughters.push_back(pNewDaughter);
329 
330  G4LogicalVolume* pDaughterLogical = pNewDaughter->GetLogicalVolume();
331 
332  // Propagate the Field Manager, if the daughter has no field Manager
333  //
334  G4FieldManager* pDaughterFieldManager = pDaughterLogical->GetFieldManager();
335 
336  // Avoid propagating the fieldManager pointer if null
337  // and daughter's one is null as well...
338  //
339  if( (G4MT_fmanager != nullptr ) && (pDaughterFieldManager == nullptr) )
340  {
341  pDaughterLogical->SetFieldManager(G4MT_fmanager, false);
342  }
343  if (fRegion)
344  {
345  PropagateRegion();
346  fRegion->RegionModified(true);
347  }
348 }
349 
350 // ********************************************************************
351 // RemoveDaughter
352 // ********************************************************************
353 //
355 {
356  for (auto i=fDaughters.cbegin(); i!=fDaughters.cend(); ++i )
357  {
358  if (**i==*p)
359  {
360  fDaughters.erase(i);
361  break;
362  }
363  }
364  if (fRegion)
365  {
366  fRegion->RegionModified(true);
367  }
368  G4MT_mass = 0.;
369 }
370 
371 // ********************************************************************
372 // ClearDaughters
373 // ********************************************************************
374 //
376 {
377  fDaughters.erase(fDaughters.cbegin(), fDaughters.cend());
378  if (fRegion != nullptr)
379  {
380  fRegion->RegionModified(true);
381  }
382  G4MT_mass = 0.;
383 }
384 
385 // ********************************************************************
386 // ResetMass
387 // ********************************************************************
388 //
390 {
391  G4MT_mass= 0.0;
392 }
393 
394 // ********************************************************************
395 // GetSolid
396 // ********************************************************************
397 //
399 {
400  return instLVdata.fSolid;
401 }
402 
404 {
405  return this->GetSolid( subInstanceManager.offset[instanceID] );
406 }
407 
408 // ********************************************************************
409 // SetSolid
410 // ********************************************************************
411 //
413 {
414 
415  G4MT_solid = pSolid;
416  this->ResetMass();
417 }
418 
419 void G4LogicalVolume::SetSolid(G4LVData& instLVdata, G4VSolid* pSolid)
420 {
421  instLVdata.fSolid = pSolid;
422  instLVdata.fMass = 0.0;
423 }
424 
425 // ********************************************************************
426 // GetMaterial
427 // ********************************************************************
428 //
430 {
431  return G4MT_material;
432 }
433 
434 // ********************************************************************
435 // SetMaterial
436 // ********************************************************************
437 //
439 {
440  G4MT_material = pMaterial;
441  G4MT_mass = 0.0;
442 }
443 
444 // ********************************************************************
445 // UpdateMaterial
446 // ********************************************************************
447 //
449 {
450  G4MT_material=pMaterial;
451  if (fRegion != nullptr) { G4MT_ccouple = fRegion->FindCouple(pMaterial); }
452  G4MT_mass = 0.0;
453 }
454 
455 // ********************************************************************
456 // GetSensitiveDetector
457 // ********************************************************************
458 //
460 {
461  return G4MT_sdetector;
462 }
463 
464 // ********************************************************************
465 // SetSensitiveDetector
466 // ********************************************************************
467 //
469 {
470  G4MT_sdetector = pSDetector;
471  if (G4Threading::IsMasterThread()) { fSensitiveDetector = pSDetector; }
472 }
473 
474 // ********************************************************************
475 // GetMaterialCutsCouple
476 // ********************************************************************
477 //
479 {
480  return G4MT_ccouple;
481 }
482 
483 // ********************************************************************
484 // SetMaterialCutsCouple
485 // ********************************************************************
486 //
488 {
489  G4MT_ccouple = cuts;
490 }
491 
492 // ********************************************************************
493 // IsAncestor
494 //
495 // Finds out if the current logical volume is an ancestor of a given
496 // physical volume
497 // ********************************************************************
498 //
499 G4bool
501 {
502  G4bool isDaughter = IsDaughter(aVolume);
503  if (!isDaughter)
504  {
505  for (auto itDau = fDaughters.cbegin(); itDau != fDaughters.cend(); ++itDau)
506  {
507  isDaughter = (*itDau)->GetLogicalVolume()->IsAncestor(aVolume);
508  if (isDaughter) break;
509  }
510  }
511  return isDaughter;
512 }
513 
514 // ********************************************************************
515 // TotalVolumeEntities
516 //
517 // Returns the total number of physical volumes (replicated or placed)
518 // in the tree represented by the current logical volume.
519 // ********************************************************************
520 //
522 {
523  G4int vols = 1;
524  for (auto itDau = fDaughters.cbegin(); itDau != fDaughters.cend(); ++itDau)
525  {
526  G4VPhysicalVolume* physDaughter = (*itDau);
527  vols += physDaughter->GetMultiplicity()
528  *physDaughter->GetLogicalVolume()->TotalVolumeEntities();
529  }
530  return vols;
531 }
532 
533 // ********************************************************************
534 // GetMass
535 //
536 // Returns the mass of the logical volume tree computed from the
537 // estimated geometrical volume of each solid and material associated
538 // to the logical volume and its daughters.
539 // NOTE: the computation may require considerable amount of time,
540 // depending from the complexity of the geometry tree.
541 // The returned value is cached and can be used for successive
542 // calls (default), unless recomputation is forced by providing
543 // 'true' for the boolean argument in input. Computation should
544 // be forced if the geometry setup has changed after the previous
545 // call. By setting the 'propagate' boolean flag to 'false' the
546 // method returns the mass of the present logical volume only
547 // (subtracted for the volume occupied by the daughter volumes).
548 // The extra argument 'parMaterial' is internally used to
549 // consider cases of geometrical parameterisations by material.
550 // ********************************************************************
551 //
553  G4bool propagate,
554  G4Material* parMaterial)
555 {
556  // Return the cached non-zero value, if not forced
557  //
558  if ( (G4MT_mass) && (!forced) ) { return G4MT_mass; }
559 
560  // Global density and computed mass associated to the logical
561  // volume without considering its daughters
562  //
563  G4Material* logMaterial = parMaterial ? parMaterial : GetMaterial();
564  if (logMaterial == nullptr)
565  {
566  std::ostringstream message;
567  message << "No material associated to the logical volume: "
568  << fName << " !" << G4endl
569  << "Sorry, cannot compute the mass ...";
570  G4Exception("G4LogicalVolume::GetMass()", "GeomMgt0002",
571  FatalException, message);
572  return 0.0;
573  }
574  if ( GetSolid() == nullptr )
575  {
576  std::ostringstream message;
577  message << "No solid is associated to the logical volume: "
578  << fName << " !" << G4endl
579  << "Sorry, cannot compute the mass ...";
580  G4Exception("G4LogicalVolume::GetMass()", "GeomMgt0002",
581  FatalException, message);
582  return 0.0;
583  }
584  G4double globalDensity = logMaterial->GetDensity();
585  G4double motherMass = GetSolid()->GetCubicVolume() * globalDensity;
586  G4double massSum = motherMass;
587 
588  // For each daughter in the tree, subtract the mass occupied
589  // and if required by the propagate flag, add the real daughter's
590  // one computed recursively
591 
592  for (auto itDau = fDaughters.cbegin(); itDau != fDaughters.cend(); ++itDau)
593  {
594  G4VPhysicalVolume* physDaughter = (*itDau);
595  G4LogicalVolume* logDaughter = physDaughter->GetLogicalVolume();
596  G4double subMass = 0.0;
597  G4VSolid* daughterSolid = nullptr;
598  G4Material* daughterMaterial = nullptr;
599 
600  // Compute the mass to subtract and to add for each daughter
601  // considering its multiplicity (i.e. replicated or not) and
602  // eventually its parameterisation (by solid and/or by material)
603  //
604  for (auto i=0; i<physDaughter->GetMultiplicity(); ++i)
605  {
606  G4VPVParameterisation* physParam = physDaughter->GetParameterisation();
607  if (physParam)
608  {
609  daughterSolid = physParam->ComputeSolid(i, physDaughter);
610  daughterSolid->ComputeDimensions(physParam, i, physDaughter);
611  daughterMaterial = physParam->ComputeMaterial(i, physDaughter);
612  }
613  else
614  {
615  daughterSolid = logDaughter->GetSolid();
616  daughterMaterial = logDaughter->GetMaterial();
617  }
618  subMass = daughterSolid->GetCubicVolume() * globalDensity;
619 
620  // Subtract the daughter's portion for the mass and, if required,
621  // add the real daughter's mass computed recursively
622  //
623  massSum -= subMass;
624  if (propagate)
625  {
626  massSum += logDaughter->GetMass(true, true, daughterMaterial);
627  }
628  }
629  }
630  G4MT_mass = massSum;
631  return massSum;
632 }
633 
635 {
637 }
638 
639 // ********************************************************************
640 // Change the daughters volume type -- checking proposed values
641 //
642 // Undertakes primitive checking, to ensure that only 'legal' changes
643 // are made:
644 // - any type to 'external' ( user responsibility )
645 // - the type proposed is checked against the deduced type
646 // (for potential switch back to 'internal' type.)
647 // Returns success (true) or failure (false)
648 //
650 {
651  G4bool works = false;
652  if( aType == kExternal )
653  {
654  // It is the responsibility of External Navigator to handle types selected
655  //
656  fDaughtersVolumeType = aType;
657  works = true;
658  }
659  else
660  {
661  EVolume expectedVType = DeduceDaughtersType();
662  works = (expectedVType == aType);
663  if ( works )
664  {
665  fDaughtersVolumeType = aType;
666  }
667  }
668  return works;
669 }