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