Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
static G4GEOM_DLL G4ThreadLocal T * offset
G4int CreateSubInstance()
void SlaveCopySubInstanceArray()
G4double fMass
G4Material * fMaterial
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
void RemoveRootLogicalVolume(G4LogicalVolume *lv, G4bool scan=true)
Definition G4Region.cc:342
G4MaterialCutsCouple * FindCouple(G4Material *mat)
void RegionModified(G4bool flag)
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:188
EVolume
Definition geomdefs.hh:83
@ kNormal
Definition geomdefs.hh:84
@ kExternal
Definition geomdefs.hh:87
G4bool IsWorkerThread()
G4bool IsMasterThread()