ATLAS Offline Software
Loading...
Searching...
No Matches
SensitiveDetectorBase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5
6
7// Base class
9// Geant4 includes used in functions
10#include "G4LogicalVolumeStore.hh"
11#include "G4MultiSensitiveDetector.hh"
12#include "G4SDManager.hh"
13// STL includes
14#include <sstream>
15
16
18 const std::string& name,
19 const IInterface* parent)
20 : base_class(type,name,parent)
21{
22}
23
24// Athena method used to set up the SDs for the current worker thread.
26{
27 ATH_MSG_VERBOSE( name() << "::initializeSD()" );
28
29 // Sanity check for volume configuration problems.
30 // It would be better to have a more robust solution for this.
31 if(m_volumeNames.empty() != m_noVolumes) {
32 ATH_MSG_ERROR("Initializing SD from " << name() << ", NoVolumes = "
33 << (m_noVolumes? "true" : "false") << ", but LogicalVolumeNames = "
34 << m_volumeNames.value());
35 return StatusCode::FAILURE;
36 }
37
38 // Make sure SD isn't already registered
39 if(getSD())
40 {
41 ATH_MSG_ERROR("Trying to create a SD which already exists!");
42 return StatusCode::FAILURE;
43 }
44
45 // Make the SD stored by this tool
46 auto sd = std::unique_ptr<G4VSensitiveDetector>(makeSD());
47 if(!sd)
48 {
49 ATH_MSG_ERROR("Failed to create SD!");
50 return StatusCode::FAILURE;
51 }
52 setSD(sd.get());
53
54 // Assign the SD to our list of volumes
55 ATH_CHECK( assignSD( std::move(sd), m_volumeNames.value() ) );
56
57 ATH_MSG_DEBUG( "Initialized and added SD " << name() );
58 return StatusCode::SUCCESS;
59}
60
61//-----------------------------------------------------------------------------
62// Assign an SD to a list of volumes
63//-----------------------------------------------------------------------------
65assignSD(std::unique_ptr<G4VSensitiveDetector> sd, const std::vector<std::string>& volumes) const
66{
67 // Propagate verbosity setting to the SD
68 if(msgLvl(MSG::VERBOSE)) sd->SetVerboseLevel(10);
69 else if(msgLvl(MSG::DEBUG)) sd->SetVerboseLevel(5);
70
71 // Add the sensitive detector to the SD manager in G4 for SDs,
72 // even if it has no volumes associated to it.
73 auto sdMgr = G4SDManager::GetSDMpointer();
74 auto sdPtr = sd.get();
75 // SDManager is now the SD owner
76 //for later use
77 auto sdName = sd->GetName();
78 sdMgr->AddNewDetector(sd.release());
79
80 if(!volumes.empty()) {
81 bool gotOne = false;
82 auto logicalVolumeStore = G4LogicalVolumeStore::GetInstance();
83 for(const auto& volumeName : volumes) {
84 // Keep track of how many volumes we find with this name string.
85 // We allow for multiple matches.
86 int numFound = 0;
87
88 // Find volumes with this name
89 for(auto* logVol : *logicalVolumeStore) {
90
91 ATH_MSG_VERBOSE("Check whether "<<logVol->GetName()<<" belongs to the set of sensitive detectors "<<volumeName);
92 if( matchStrings( volumeName.data(), logVol->GetName() ) ){
93 ++numFound;
94 SetSensitiveDetector(logVol, sdPtr);
95 }
96
97 }
98 // Warn if no volumes were found
99 if(numFound == 0) {
100 ATH_MSG_WARNING("Volume " << volumeName <<
101 " not found in G4LogicalVolumeStore.");
102 }
103 else {
104 ATH_MSG_VERBOSE("Found " << numFound << " copies of LV " << volumeName <<
105 "; SD " << sdName << " assigned.");
106 gotOne = true;
107 }
108
109 }
110
111 // Abort if we have failed to assign any volume
112 if(!gotOne) {
113 ATH_MSG_ERROR( "Failed to assign *any* volume to SD " << name() <<
114 " and expected at least one. Size of the volume store "<<G4LogicalVolumeStore::GetInstance()->size() );
115 return StatusCode::FAILURE;
116 }
117 }
118
119 return StatusCode::SUCCESS;
120}
121
122G4VSensitiveDetector* SensitiveDetectorBase::getSD()
123{
124#ifdef G4MULTITHREADED
125 // Get current thread-ID
126 const auto tid = std::this_thread::get_id();
127 // Retrieve it from the SD map
128 auto sdPair = m_sdThreadMap.find(tid);
129 if(sdPair == m_sdThreadMap.end()) return nullptr;
130 return sdPair->second;
131#else
132 return m_SD;
133#endif
134}
135
136void SensitiveDetectorBase::setSD(G4VSensitiveDetector* sd)
137{
138#ifdef G4MULTITHREADED
139 const auto tid = std::this_thread::get_id();
140 ATH_MSG_DEBUG("Creating and registering SD " << sd << " in thread " << tid);
141 m_sdThreadMap.insert( std::make_pair(tid, sd) );
142#else
143 m_SD = sd;
144#endif
145}
146
147//This function was adapted from the example found at
148//https://www.geeksforgeeks.org/wildcard-character-matching/
149bool SensitiveDetectorBase::matchStrings(const char *first, const char *second)
150{
151 // If we reach at the end of both strings, we are done
152 if (*first == '\0' && *second == '\0')
153 return true;
154
155 // If there are consecutive '*' present in the first string
156 // advance to the next character
157 if(*first == '*' && *(first + 1) == '*')
158 return matchStrings(first + 1, second);
159
160 // Make sure that the characters after '*' are present in second string.
161 if (*first == '*' && *(first + 1) != '\0' && *second == '\0')
162 return false;
163
164 // If the current characters of both strings match
165 if (*first == *second)
166 return matchStrings(first + 1, second + 1);
167
168 // If there is *, then there are two possibilities
169 // a) We consider current character of second string
170 // b) We ignore current character of second string.
171 if (*first == '*')
172 return matchStrings(first + 1, second) || matchStrings(first, second + 1);
173 return false;
174}
175
177SetSensitiveDetector(G4LogicalVolume* logVol, G4VSensitiveDetector* aSD) const
178{
179 // New Logic: allow for "multiple" SDs being attached to a single LV.
180 // To do that we use a special proxy SD called G4MultiSensitiveDetector
181
182 // Get existing SD if already set and check if it is of the special type
183 G4VSensitiveDetector* originalSD = logVol->GetSensitiveDetector();
184 if ( originalSD == nullptr )
185 {
186 logVol->SetSensitiveDetector(aSD);
187 }
188 else
189 {
190 G4MultiSensitiveDetector* msd = dynamic_cast<G4MultiSensitiveDetector*>(originalSD);
191 if ( msd != nullptr )
192 {
193 msd->AddSD(aSD);
194 }
195 else
196 {
197 // Construct a unique name using the volume address
198 std::stringstream ss;
200 const G4String msdname = "/MultiSD_" + logVol->GetName() + ss.str();
201 msd = new G4MultiSensitiveDetector(std::move(msdname));
202 // We need to register the proxy to have correct handling of IDs
203 G4SDManager::GetSDMpointer()->AddNewDetector(msd);
204 msd->AddSD(originalSD);
205 msd->AddSD(aSD);
206 logVol->SetSensitiveDetector(msd);
207 }
208 }
209}
210
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static Double_t ss
StatusCode assignSD(std::unique_ptr< G4VSensitiveDetector > sd, const std::vector< std::string > &volumes) const
Assign SD to a list of volumes.
G4VSensitiveDetector * m_SD
The sensitive detector to which this thing corresponds.
Gaudi::Property< std::vector< std::string > > m_volumeNames
All the volumes to which this SD is assigned.
StatusCode initializeSD() override
Setup an SD in the current thread.
Gaudi::Property< bool > m_noVolumes
This SensitiveDetector has no volumes associated with it.
SensitiveDetectorBase(const std::string &type, const std::string &name, const IInterface *parent)
Standard constructor.
static bool matchStrings(const char *first, const char *second)
Match two strings with wildcard support.
G4VSensitiveDetector * getSD()
Retrieve the current SD.
void setSD(G4VSensitiveDetector *)
Set the current SD.
void SetSensitiveDetector(G4LogicalVolume *, G4VSensitiveDetector *) const
Method stolen from G4VUserDetectorConstruction in G4 10.2.