Geant4 10.7.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// 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// 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//
155InitialiseWorker( G4LogicalVolume* /*pMasterObject*/,
156 G4VSolid* pSolid,
157 G4VSensitiveDetector* pSDetector)
158{
159 subInstanceManager.SlaveCopySubInstanceArray();
160
161 SetSolid(pSolid);
162 SetSensitiveDetector(pSDetector); // How this object is available now ?
163 AssignFieldManager(fFieldManager);
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{
190 subInstanceManager.FreeSlave();
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//
202TerminateWorker( 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//
249void
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 {
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
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//
499G4bool
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{
636 fVisAttributes = new G4VisAttributes(VA);
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}
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:35
#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:57
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)
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)
virtual ~G4LogicalVolume()
void RemoveDaughter(const G4VPhysicalVolume *p)
size_t GetNoDaughters() const
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
void PropagateRegion()
G4VPhysicalVolume * GetDaughter(const G4int i) const
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
Definition: G4Material.hh:178
void RemoveRootLogicalVolume(G4LogicalVolume *lv, G4bool scan=true)
Definition: G4Region.cc:318
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:125
virtual G4double GetCubicVolume()
Definition: G4VSolid.cc:176
EVolume
Definition: geomdefs.hh:83
@ kNormal
Definition: geomdefs.hh:84
@ kExternal
Definition: geomdefs.hh:87
G4bool IsMasterThread()
Definition: G4Threading.cc:124