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 sdMgr->AddNewDetector(sd.release());
77
78 if(!volumes.empty()) {
79 bool gotOne = false;
80 auto logicalVolumeStore = G4LogicalVolumeStore::GetInstance();
81 for(const auto& volumeName : volumes) {
82 // Keep track of how many volumes we find with this name string.
83 // We allow for multiple matches.
84 int numFound = 0;
85
86 // Find volumes with this name
87 for(auto* logVol : *logicalVolumeStore) {
88
89 ATH_MSG_VERBOSE("Check whether "<<logVol->GetName()<<" belongs to the set of sensitive detectors "<<volumeName);
90 if( matchStrings( volumeName.data(), logVol->GetName() ) ){
91 ++numFound;
92 SetSensitiveDetector(logVol, sdPtr);
93 }
94
95 }
96 // Warn if no volumes were found
97 if(numFound == 0) {
98 ATH_MSG_WARNING("Volume " << volumeName <<
99 " not found in G4LogicalVolumeStore.");
100 }
101 else {
102 ATH_MSG_VERBOSE("Found " << numFound << " copies of LV " << volumeName <<
103 "; SD " << sd->GetName() << " assigned.");
104 gotOne = true;
105 }
106
107 }
108
109 // Abort if we have failed to assign any volume
110 if(!gotOne) {
111 ATH_MSG_ERROR( "Failed to assign *any* volume to SD " << name() <<
112 " and expected at least one. Size of the volume store "<<G4LogicalVolumeStore::GetInstance()->size() );
113 return StatusCode::FAILURE;
114 }
115 }
116
117 return StatusCode::SUCCESS;
118}
119
120G4VSensitiveDetector* SensitiveDetectorBase::getSD()
121{
122#ifdef G4MULTITHREADED
123 // Get current thread-ID
124 const auto tid = std::this_thread::get_id();
125 // Retrieve it from the SD map
126 auto sdPair = m_sdThreadMap.find(tid);
127 if(sdPair == m_sdThreadMap.end()) return nullptr;
128 return sdPair->second;
129#else
130 return m_SD;
131#endif
132}
133
134void SensitiveDetectorBase::setSD(G4VSensitiveDetector* sd)
135{
136#ifdef G4MULTITHREADED
137 const auto tid = std::this_thread::get_id();
138 ATH_MSG_DEBUG("Creating and registering SD " << sd << " in thread " << tid);
139 m_sdThreadMap.insert( std::make_pair(tid, sd) );
140#else
141 m_SD = sd;
142#endif
143}
144
145//This function was adapted from the example found at
146//https://www.geeksforgeeks.org/wildcard-character-matching/
147bool SensitiveDetectorBase::matchStrings(const char *first, const char *second)
148{
149 // If we reach at the end of both strings, we are done
150 if (*first == '\0' && *second == '\0')
151 return true;
152
153 // If there are consecutive '*' present in the first string
154 // advance to the next character
155 if(*first == '*' && *(first + 1) == '*')
156 return matchStrings(first + 1, second);
157
158 // Make sure that the characters after '*' are present in second string.
159 if (*first == '*' && *(first + 1) != '\0' && *second == '\0')
160 return false;
161
162 // If the current characters of both strings match
163 if (*first == *second)
164 return matchStrings(first + 1, second + 1);
165
166 // If there is *, then there are two possibilities
167 // a) We consider current character of second string
168 // b) We ignore current character of second string.
169 if (*first == '*')
170 return matchStrings(first + 1, second) || matchStrings(first, second + 1);
171 return false;
172}
173
175SetSensitiveDetector(G4LogicalVolume* logVol, G4VSensitiveDetector* aSD) const
176{
177 // New Logic: allow for "multiple" SDs being attached to a single LV.
178 // To do that we use a special proxy SD called G4MultiSensitiveDetector
179
180 // Get existing SD if already set and check if it is of the special type
181 G4VSensitiveDetector* originalSD = logVol->GetSensitiveDetector();
182 if ( originalSD == nullptr )
183 {
184 logVol->SetSensitiveDetector(aSD);
185 }
186 else
187 {
188 G4MultiSensitiveDetector* msd = dynamic_cast<G4MultiSensitiveDetector*>(originalSD);
189 if ( msd != nullptr )
190 {
191 msd->AddSD(aSD);
192 }
193 else
194 {
195 // Construct a unique name using the volume address
196 std::stringstream ss;
198 const G4String msdname = "/MultiSD_" + logVol->GetName() + ss.str();
199 msd = new G4MultiSensitiveDetector(std::move(msdname));
200 // We need to register the proxy to have correct handling of IDs
201 G4SDManager::GetSDMpointer()->AddNewDetector(msd);
202 msd->AddSD(originalSD);
203 msd->AddSD(aSD);
204 logVol->SetSensitiveDetector(msd);
205 }
206 }
207}
208
#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.