Geant4 11.3.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4LogicalVolume.cc
Go to the documentation of this file.
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"
38#include "G4VSolid.hh"
39#include "G4Material.hh"
41#include "G4VisAttributes.hh"
42
43#include "G4UnitsTable.hh"
44
46
47// This new field helps to use the class G4LVManager
48//
49G4LVManager G4LogicalVolume::subInstanceManager;
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
84 instanceID = subInstanceManager.CreateSubInstance();
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{
116 instanceID = subInstanceManager.CreateSubInstance();
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// SetName - Set volume name and notify store of the change
146// ********************************************************************
147//
149{
150 fName = pName;
152}
153
154// ********************************************************************
155// InitialiseWorker
156//
157// This method is similar to the constructor. It is used by each worker
158// thread to achieve the same effect as that of the master thread exept
159// to register the new created instance. This method is invoked explicitly.
160// It does not create a new G4LogicalVolume instance. It only assign the value
161// for the fields encapsulated by the class G4LVData.
162// ********************************************************************
163//
165InitialiseWorker( G4LogicalVolume* /*pMasterObject*/,
166 G4VSolid* pSolid,
167 G4VSensitiveDetector* pSDetector)
168{
169 subInstanceManager.SlaveCopySubInstanceArray();
170
171 SetSolid(pSolid);
172 SetSensitiveDetector(pSDetector); // How this object is available now ?
173 AssignFieldManager(fFieldManager);
174 // Should be set - but a per-thread copy is not available yet
175 // Must not call SetFieldManager(), which propagates FieldMgr
176
177#ifdef CLONE_FIELD_MGR
178 // Create a field FieldManager by cloning
179 //
180 G4FieldManager workerFldMgr = fFieldManager->GetWorkerClone(G4bool* created);
181 if( created || (GetFieldManager() != workerFldMgr) )
182 {
183 SetFieldManager(fFieldManager, false); // which propagates FieldMgr
184 }
185 else
186 {
187 // Field manager existed and is equal to current one
188 //
189 AssignFieldManager(workerFldMgr);
190 }
191#endif
192}
193
194// ********************************************************************
195// Clean
196// ********************************************************************
197//
199{
200 subInstanceManager.FreeSlave();
201}
202
203// ********************************************************************
204// TerminateWorker
205//
206// This method is similar to the destructor. It is used by each worker
207// thread to achieve the partial effect as that of the master thread.
208// For G4LogicalVolume instances, nothing more to do here.
209// ********************************************************************
210//
212TerminateWorker( G4LogicalVolume* /*pMasterObject*/)
213{
214}
215
216// ********************************************************************
217// GetSubInstanceManager
218//
219// Returns the private data instance manager.
220// ********************************************************************
221//
223{
224 return subInstanceManager;
225}
226
227// ********************************************************************
228// GetFieldManager
229// ********************************************************************
230//
235
236// ********************************************************************
237// AssignFieldManager
238// ********************************************************************
239//
241{
242 G4MT_fmanager= fldMgr;
243 if(G4Threading::IsMasterThread()) { fFieldManager = fldMgr; }
244}
245
246// ********************************************************************
247// IsExtended
248// ********************************************************************
249//
251{
252 return false;
253}
254
255// ********************************************************************
256// SetFieldManager
257// ********************************************************************
258//
259void
261 G4bool forceAllDaughters)
262{
263 AssignFieldManager(pNewFieldMgr);
264
265 auto NoDaughters = GetNoDaughters();
266 while ( (NoDaughters--)>0 )
267 {
268 G4LogicalVolume* DaughterLogVol;
269 DaughterLogVol = GetDaughter(NoDaughters)->GetLogicalVolume();
270 if ( forceAllDaughters || (DaughterLogVol->GetFieldManager() == nullptr) )
271 {
272 DaughterLogVol->SetFieldManager(pNewFieldMgr, forceAllDaughters);
273 }
274 }
275}
276
277// ********************************************************************
278// AddDaughter
279// ********************************************************************
280//
282{
283 EVolume daughterType = pNewDaughter->VolumeType();
284
285 // The type of the navigation needed is determined by the first daughter
286 //
287 if( fDaughters.empty() )
288 {
289 fDaughtersVolumeType = daughterType;
290 }
291 else
292 {
293 // Check consistency of detector description
294
295 // 1. A replica or parameterised volume can have only one daughter
296 //
297 if( fDaughters[0]->IsReplicated() )
298 {
299 std::ostringstream message;
300 message << "ERROR - Attempt to place a volume in a mother volume"
301 << G4endl
302 << " already containing a replicated volume." << G4endl
303 << " A volume can either contain several placements" << G4endl
304 << " or a unique replica or parameterised volume !" << G4endl
305 << " Mother logical volume: " << GetName() << G4endl
306 << " Placing volume: " << pNewDaughter->GetName()
307 << G4endl;
308 G4Exception("G4LogicalVolume::AddDaughter()", "GeomMgt0002",
309 FatalException, message,
310 "Replica or parameterised volume must be the only daughter!");
311 }
312 else
313 {
314 // 2. Ensure that Placement and External physical volumes do not mix
315 //
316 if( daughterType != fDaughtersVolumeType )
317 {
318 std::ostringstream message;
319 message << "ERROR - Attempt to place a volume in a mother volume"
320 << G4endl
321 << " already containing a different type of volume." << G4endl
322 << " A volume can either contain" << G4endl
323 << " - one or more placements, OR" << G4endl
324 << " - one or more 'external' type physical volumes." << G4endl
325 << " Mother logical volume: " << GetName() << G4endl
326 << " Volume being placed: " << pNewDaughter->GetName()
327 << G4endl;
328 G4Exception("G4LogicalVolume::AddDaughter()", "GeomMgt0002",
329 FatalException, message,
330 "Cannot mix placements and external physical volumes !");
331 }
332 }
333 }
334
335 // Invalidate previous calculation of mass - if any - for all threads
336 //
337 G4MT_mass = 0.;
338 fDaughters.push_back(pNewDaughter);
339
340 G4LogicalVolume* pDaughterLogical = pNewDaughter->GetLogicalVolume();
341
342 // Propagate the Field Manager, if the daughter has no field Manager
343 //
344 G4FieldManager* pDaughterFieldManager = pDaughterLogical->GetFieldManager();
345
346 // Avoid propagating the fieldManager pointer if null
347 // and daughter's one is null as well...
348 //
349 if( (G4MT_fmanager != nullptr ) && (pDaughterFieldManager == nullptr) )
350 {
351 pDaughterLogical->SetFieldManager(G4MT_fmanager, false);
352 }
353 if (fRegion != nullptr)
354 {
356 fRegion->RegionModified(true);
357 }
358}
359
360// ********************************************************************
361// RemoveDaughter
362// ********************************************************************
363//
365{
366 for (auto i=fDaughters.cbegin(); i!=fDaughters.cend(); ++i )
367 {
368 if (**i==*p)
369 {
370 fDaughters.erase(i);
371 break;
372 }
373 }
374 if (fRegion != nullptr)
375 {
376 fRegion->RegionModified(true);
377 }
378 G4MT_mass = 0.;
379}
380
381// ********************************************************************
382// ClearDaughters
383// ********************************************************************
384//
386{
387 fDaughters.erase(fDaughters.cbegin(), fDaughters.cend());
388 if (fRegion != nullptr)
389 {
390 fRegion->RegionModified(true);
391 }
392 G4MT_mass = 0.;
393}
394
395// ********************************************************************
396// ResetMass
397// ********************************************************************
398//
400{
401 G4MT_mass= 0.0;
402}
403
404// ********************************************************************
405// GetSolid
406// ********************************************************************
407//
409{
410 return instLVdata.fSolid;
411}
412
414{
415 return this->GetSolid( subInstanceManager.offset[instanceID] );
416}
417
418// ********************************************************************
419// SetSolid
420// ********************************************************************
421//
423{
424
425 G4MT_solid = pSolid;
426 this->ResetMass();
427}
428
430{
431 instLVdata.fSolid = pSolid;
432 instLVdata.fMass = 0.0;
433}
434
435// ********************************************************************
436// GetMaterial
437// ********************************************************************
438//
443
444// ********************************************************************
445// SetMaterial
446// ********************************************************************
447//
449{
450 G4MT_material = pMaterial;
451 G4MT_mass = 0.0;
452}
453
454// ********************************************************************
455// UpdateMaterial
456// ********************************************************************
457//
459{
460 G4MT_material=pMaterial;
461 if (fRegion != nullptr) { G4MT_ccouple = fRegion->FindCouple(pMaterial); }
462 G4MT_mass = 0.0;
463}
464
465// ********************************************************************
466// GetSensitiveDetector
467// ********************************************************************
468//
473
474// ********************************************************************
475// SetSensitiveDetector
476// ********************************************************************
477//
479{
480 G4MT_sdetector = pSDetector;
481 if (G4Threading::IsMasterThread()) { fSensitiveDetector = pSDetector; }
482}
483
484// ********************************************************************
485// GetMaterialCutsCouple
486// ********************************************************************
487//
492
493// ********************************************************************
494// SetMaterialCutsCouple
495// ********************************************************************
496//
501
502// ********************************************************************
503// IsAncestor
504//
505// Finds out if the current logical volume is an ancestor of a given
506// physical volume
507// ********************************************************************
508//
509G4bool
511{
512 G4bool isDaughter = IsDaughter(aVolume);
513 if (!isDaughter)
514 {
515 for (auto itDau = fDaughters.cbegin(); itDau != fDaughters.cend(); ++itDau)
516 {
517 isDaughter = (*itDau)->GetLogicalVolume()->IsAncestor(aVolume);
518 if (isDaughter) break;
519 }
520 }
521 return isDaughter;
522}
523
524// ********************************************************************
525// TotalVolumeEntities
526//
527// Returns the total number of physical volumes (replicated or placed)
528// in the tree represented by the current logical volume.
529// ********************************************************************
530//
532{
533 G4int vols = 1;
534 for (auto itDau = fDaughters.cbegin(); itDau != fDaughters.cend(); ++itDau)
535 {
536 G4VPhysicalVolume* physDaughter = (*itDau);
537 vols += physDaughter->GetMultiplicity()
538 *physDaughter->GetLogicalVolume()->TotalVolumeEntities();
539 }
540 return vols;
541}
542
543// ********************************************************************
544// GetMass
545//
546// Returns the mass of the logical volume tree computed from the
547// estimated geometrical volume of each solid and material associated
548// to the logical volume and its daughters.
549// NOTE: the computation may require considerable amount of time,
550// depending from the complexity of the geometry tree.
551// The returned value is cached and can be used for successive
552// calls (default), unless recomputation is forced by providing
553// 'true' for the boolean argument in input. Computation should
554// be forced if the geometry setup has changed after the previous
555// call. By setting the 'propagate' boolean flag to 'false' the
556// method returns the mass of the present logical volume only
557// (subtracted for the volume occupied by the daughter volumes).
558// The extra argument 'parMaterial' is internally used to
559// consider cases of geometrical parameterisations by material.
560// ********************************************************************
561//
563 G4bool propagate,
564 G4Material* parMaterial)
565{
566 // Return the cached non-zero value, if not forced
567 //
568 if ( ((G4MT_mass) != 0.0) && (!forced) ) { return G4MT_mass; }
569
570 // Global density and computed mass associated to the logical
571 // volume without considering its daughters
572 //
573 G4Material* logMaterial = parMaterial != nullptr ? parMaterial : GetMaterial();
574 if (logMaterial == nullptr)
575 {
576 std::ostringstream message;
577 message << "No material 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 if ( GetSolid() == nullptr )
585 {
586 std::ostringstream message;
587 message << "No solid is associated to the logical volume: "
588 << fName << " !" << G4endl
589 << "Sorry, cannot compute the mass ...";
590 G4Exception("G4LogicalVolume::GetMass()", "GeomMgt0002",
591 FatalException, message);
592 return 0.0;
593 }
594 G4double globalDensity = logMaterial->GetDensity();
595 G4double motherMass = GetSolid()->GetCubicVolume() * globalDensity;
596 G4double massSum = motherMass;
597
598 // For each daughter in the tree, subtract the mass occupied
599 // and if required by the propagate flag, add the real daughter's
600 // one computed recursively
601
602 for (auto itDau = fDaughters.cbegin(); itDau != fDaughters.cend(); ++itDau)
603 {
604 G4VPhysicalVolume* physDaughter = (*itDau);
605 G4LogicalVolume* logDaughter = physDaughter->GetLogicalVolume();
606 G4double subMass = 0.0;
607 G4VSolid* daughterSolid = nullptr;
608 G4Material* daughterMaterial = nullptr;
609
610 // Compute the mass to subtract and to add for each daughter
611 // considering its multiplicity (i.e. replicated or not) and
612 // eventually its parameterisation (by solid and/or by material)
613 //
614 for (auto i=0; i<physDaughter->GetMultiplicity(); ++i)
615 {
616 G4VPVParameterisation* physParam = physDaughter->GetParameterisation();
617 if (physParam != nullptr)
618 {
619 daughterSolid = physParam->ComputeSolid(i, physDaughter);
620 daughterSolid->ComputeDimensions(physParam, i, physDaughter);
621 daughterMaterial = physParam->ComputeMaterial(i, physDaughter);
622 }
623 else
624 {
625 daughterSolid = logDaughter->GetSolid();
626 daughterMaterial = logDaughter->GetMaterial();
627 }
628 subMass = daughterSolid->GetCubicVolume() * globalDensity;
629
630 // Subtract the daughter's portion for the mass and, if required,
631 // add the real daughter's mass computed recursively
632 //
633 massSum -= subMass;
634 if (propagate)
635 {
636 massSum += logDaughter->GetMass(true, true, daughterMaterial);
637 }
638 }
639 }
640 G4MT_mass = massSum;
641 return massSum;
642}
643
644// ********************************************************************
645// Change the daughters volume type -- checking proposed values
646//
647// Undertakes primitive checking, to ensure that only 'legal' changes
648// are made:
649// - any type to 'external' ( user responsibility )
650// - the type proposed is checked against the deduced type
651// (for potential switch back to 'internal' type.)
652// Returns success (true) or failure (false)
653//
655{
656 G4bool works = false;
657 if( aType == kExternal )
658 {
659 // It is the responsibility of External Navigator to handle types selected
660 //
661 fDaughtersVolumeType = aType;
662 works = true;
663 }
664 else
665 {
666 EVolume expectedVType = DeduceDaughtersType();
667 works = (expectedVType == aType);
668 if ( works )
669 {
670 fDaughtersVolumeType = aType;
671 }
672 }
673 return works;
674}
675
676// ********************************************************************
677// SetVisAttributes - copy version
678// ********************************************************************
679//
681{
682 if (G4Threading::IsWorkerThread()) return;
683 fVisAttributes = std::make_shared<const G4VisAttributes>(VA);
684}
685
686// ********************************************************************
687// SetVisAttributes
688// ********************************************************************
689//
691{
692 if (G4Threading::IsWorkerThread()) return;
693 fVisAttributes = std::shared_ptr<const G4VisAttributes>(pVA,[](const G4VisAttributes*){});
694}
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
#define G4MT_solid
#define G4MT_fmanager
#define G4MT_sdetector
#define G4MT_material
#define G4MT_mass
#define G4MT_ccouple
G4GeomSplitter< G4LVData > G4LVManager
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4double fMass
G4VSolid * fSolid
static void DeRegister(G4LogicalVolume *pVolume)
static void Register(G4LogicalVolume *pVolume)
static G4LogicalVolumeStore * GetInstance()
G4VSolid * GetSolid() const
G4double GetMass(G4bool forced=false, G4bool propagate=true, G4Material *parMaterial=nullptr)
void SetName(const G4String &pName)
G4bool IsAncestor(const G4VPhysicalVolume *p) const
void SetFieldManager(G4FieldManager *pFieldMgr, G4bool forceToAllDaughters)
void AddDaughter(G4VPhysicalVolume *p)
void SetUserLimits(G4UserLimits *pULimits)
G4VSensitiveDetector * GetSensitiveDetector() const
void TerminateWorker(G4LogicalVolume *ptrMasterObject)
std::size_t GetNoDaughters() const
virtual ~G4LogicalVolume()
void RemoveDaughter(const G4VPhysicalVolume *p)
EVolume DeduceDaughtersType() const
virtual G4bool IsExtended() const
G4bool ChangeDaughtersType(EVolume atype)
static const G4LVManager & GetSubInstanceManager()
G4LogicalVolume(G4VSolid *pSolid, G4Material *pMaterial, const G4String &name, G4FieldManager *pFieldMgr=nullptr, G4VSensitiveDetector *pSDetector=nullptr, G4UserLimits *pULimits=nullptr, G4bool optimise=true)
static void Clean()
G4bool IsDaughter(const G4VPhysicalVolume *p) const
G4Material * GetMaterial() const
G4VPhysicalVolume * GetDaughter(const std::size_t i) const
void PropagateRegion()
void InitialiseWorker(G4LogicalVolume *ptrMasterObject, G4VSolid *pSolid, G4VSensitiveDetector *pSDetector)
G4FieldManager * GetFieldManager() const
void SetVisAttributes(const G4VisAttributes *pVA)
G4int TotalVolumeEntities() const
const G4String & GetName() const
const G4MaterialCutsCouple * GetMaterialCutsCouple() const
void AssignFieldManager(G4FieldManager *fldMgr)
void SetMaterial(G4Material *pMaterial)
void SetSolid(G4VSolid *pSolid)
void SetSensitiveDetector(G4VSensitiveDetector *pSDetector)
void SetMaterialCutsCouple(G4MaterialCutsCouple *cuts)
void UpdateMaterial(G4Material *pMaterial)
G4double GetDensity() const
virtual G4VSolid * ComputeSolid(const G4int, G4VPhysicalVolume *)
virtual G4Material * ComputeMaterial(const G4int repNo, G4VPhysicalVolume *currentVol, const G4VTouchable *parentTouch=nullptr)
virtual EVolume VolumeType() const =0
G4LogicalVolume * GetLogicalVolume() const
virtual G4int GetMultiplicity() const
const G4String & GetName() const
virtual G4VPVParameterisation * GetParameterisation() const =0
virtual void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
Definition G4VSolid.cc:137
virtual G4double GetCubicVolume()
Definition G4VSolid.cc:203
EVolume
Definition geomdefs.hh:83
@ kNormal
Definition geomdefs.hh:84
@ kExternal
Definition geomdefs.hh:87
G4bool IsWorkerThread()
G4bool IsMasterThread()