ATLAS Offline Software
Loading...
Searching...
No Matches
SCT_ReadCalibDataCondAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
6
8
13
14// Include STL stuff
15#include <limits>
16#include <memory>
17
18using namespace SCT_ConditionsData;
19
20// Utility functions
21namespace {
22 float coerceToFloatRange(const double value) {
23 const double maxfloat{std::numeric_limits<float>::max()};
24 const double minfloat{std::numeric_limits<float>::min()};
25 return static_cast<float>(std::clamp(value,minfloat,maxfloat));
26 }
27}
28
29SCT_ReadCalibDataCondAlg::SCT_ReadCalibDataCondAlg(const std::string& name, ISvcLocator* pSvcLocator)
30 : ::AthCondAlgorithm(name, pSvcLocator)
31{
32 m_ignoreDefects.value().push_back("NOISE_SLOPE");
33 m_ignoreDefectParameters.value().push_back(-1000.);
34
35 m_ignoreDefects.value().push_back("OFFSET_SLOPE");
36 m_ignoreDefectParameters.value().push_back(-1000.);
37
38 m_ignoreDefects.value().push_back("GAIN_SLOPE");
39 m_ignoreDefectParameters.value().push_back(-1000.);
40
41 m_ignoreDefects.value().push_back("BAD_OPE");
42 m_ignoreDefectParameters.value().push_back(-1000.);
43
44 m_ignoreDefects.value().push_back("NO_HI");
45 m_ignoreDefectParameters.value().push_back(1.);
46 // 1. means 100%. Only NO_HI defects with >100% are considered, i.e., all NO_HI defects are ignored.
47
48 m_ignoreDefects.value().push_back("LO_GAIN");
49 m_ignoreDefectParameters.value().push_back(-1000.);
50
51 m_ignoreDefects.value().push_back("HI_GAIN");
52 m_ignoreDefectParameters.value().push_back(-1000.);
53}
54
56 ATH_MSG_DEBUG("initialize " << name());
57
58 // Get SCT helper
59 ATH_CHECK(detStore()->retrieve(m_id_sct, "SCT_ID"));
60
61 // Read Cond Handle
62 ATH_CHECK(m_readKeyGain.initialize());
63 ATH_CHECK(m_readKeyNoise.initialize());
64 ATH_CHECK(m_SCTDetEleCollKey.initialize());
65
66 // Write Cond Handles
67 for (unsigned int i{GAIN}; i<NFEATURES; i++) {
69 if ( i==GAIN) writeKeyData = &m_writeKeyGain;
70 else if (i==NOISE) writeKeyData = &m_writeKeyNoise;
71 if (writeKeyData==nullptr) continue;
72 ATH_CHECK(writeKeyData->initialize());
73 }
74 ATH_CHECK(m_writeKeyInfo.initialize());
75
76 // Fit Defects
77 m_defectMapIntToString[0] = "UNKNOWN"; //<! Defect type not in this map, add!
78 m_defectMapIntToString[1] = "DEAD"; //<! Output always < 1%
79 m_defectMapIntToString[2] = "STUCKON"; //<! Output always > 98%
80 m_defectMapIntToString[3] = "UNDER"; //<! Occupancy never reaches max, always less than 95%
81 m_defectMapIntToString[4] = "OVER"; //<! Occcupancy greater than 100%
82 m_defectMapIntToString[5] = "BADFIT"; //<! The fit was not good for some reason - parameter is a chi2 cut
83 // NPt Gain Defects
84 m_defectMapIntToString[32] = "VLO_GAIN"; //<! Gain < 0.3 * chip average
85 m_defectMapIntToString[9] = "LO_GAIN"; //<! Gain < 0.75 * chip average
86 m_defectMapIntToString[10] = "HI_GAIN"; //<! Gain > 1.25 * chip average
87 m_defectMapIntToString[11] = "LO_OFFSET"; //<! Offset < -100
88 m_defectMapIntToString[12] = "HI_OFFSET"; //<! Offset > 200
89 m_defectMapIntToString[13] = "UNBONDED"; //<! Noise <= 750
90 m_defectMapIntToString[14] = "PARTBONDED"; //<! Noise <= 1100
91 m_defectMapIntToString[15] = "NOISY"; //<! Noise > 1.15* av chip noise
92 m_defectMapIntToString[33] = "V_NOISY"; //<! Noise > 1.25* av chip noise
93 m_defectMapIntToString[34] = "NOISE_SLOPE"; //<! Slope in noise across module, slope/chan > 1.
94 m_defectMapIntToString[35] = "OFFSET_SLOPE"; //<! Slope in offset across module, slope/chan > 0.07
95 m_defectMapIntToString[36] = "GAIN_SLOPE"; //<! Slope in gain across module, slope/chan > 0.04
96 // Noise Occupancy Defects
97 m_defectMapIntToString[19] = "NO_HI"; //<! High noise occupancy, 0.0005
98 m_defectMapIntToString[37] = "BAD_OPE"; //<! Bad occupancy per event variance/binomial variance > 2.0)
99 m_defectMapIntToString[38] = "DOUBTR_HI"; //<! High double trigger noise occupancy, > 5
100 m_defectMapIntToString[41] = "LO_GAIN_ABSOLUTE"; // <! Gain < 15 mV/fC, newly added for Run 3
101 m_defectMapIntToString[42] = "LO_NOISE"; // <! Noise < 0.75 * chip average, newly added for Run 3
102 m_defectMapIntToString[43] = "VLO_NOISE"; // <! Noise < 0.5 * chip average, newly added for Run 3
103 m_defectMapIntToString[44] = "VLO_NOISE_SHORT"; // <! Noise < 0.7 * chip average, newly added for Run 3
104
105 //Check ignoreDefects vectors are the same size
106 if (m_ignoreDefects.value().size() != m_ignoreDefectParameters.value().size()) {
107 ATH_MSG_FATAL("IgnoreDefect != IgnoreDefectsParameters, check job options!");
108 return StatusCode::FAILURE;
109 }
110
111 return StatusCode::SUCCESS;
112}
113
114StatusCode SCT_ReadCalibDataCondAlg::execute(const EventContext& ctx) const {
115 ATH_MSG_DEBUG("execute " << name());
116
117 // Write Cond Handle
118 bool validWriteCondHandle{true};
119 // Do we have a valid Write Cond Handle for current time?
121 for (unsigned int i{GAIN}; i<NFEATURES; i++) {
122 if (writeHandleData[i].isValid()) {
123 ATH_MSG_DEBUG("CondHandle " << writeHandleData[i].fullKey() << " is already valid."
124 << ". In theory this should not be called, but may happen"
125 << " if multiple concurrent events are being processed out of order.");
126 } else {
127 validWriteCondHandle = false;
128 }
129 }
131 if (writeHandleInfo.isValid()) {
132 ATH_MSG_DEBUG("CondHandle " << writeHandleInfo.fullKey() << " is already valid."
133 << ". In theory this should not be called, but may happen"
134 << " if multiple concurrent events are being processed out of order.");
135 } else {
136 validWriteCondHandle = false;
137 }
138 if (validWriteCondHandle) return StatusCode::SUCCESS;
139
140 // Read Cond Handle
142 const CondAttrListCollection* readCdo[NFEATURES]{*readHandle[GAIN], *readHandle[NOISE]};
143 for (unsigned int i{GAIN}; i<NFEATURES; i++) {
144 if (readCdo[i]==nullptr) {
145 ATH_MSG_FATAL("Null pointer to the read conditions object " << readHandle[i].key());
146 return StatusCode::FAILURE;
147 }
148 // Add dependency
149 writeHandleData[i].addDependency(readHandle[i]);
150 writeHandleInfo.addDependency(readHandle[i]);
151 ATH_MSG_INFO("Size of CondAttrListCollection " << readHandle[i].fullKey() << " readCdo->size()= " << readCdo[i]->size());
152 ATH_MSG_INFO("Range of input is " << readHandle[i].getRange());
153 }
154
155 // Get SCT_DetectorElementCollection
157 const InDetDD::SiDetectorElementCollection* elements{sctDetEle.retrieve()};
158 if (elements==nullptr) {
159 ATH_MSG_FATAL(m_SCTDetEleCollKey.fullKey() << " could not be retrieved");
160 return StatusCode::FAILURE;
161 }
162 for (unsigned int i{GAIN}; i<NFEATURES; i++) {
163 writeHandleData[i].addDependency(sctDetEle);
164 }
165 writeHandleInfo.addDependency(sctDetEle);
166
167 // Construct the output Cond Object and fill it in
168 std::unique_ptr<SCT_CalibDefectData> writeCdoData[NFEATURES]{nullptr, nullptr};
169 for (unsigned int i{GAIN}; i<NFEATURES; i++) {
170 writeCdoData[i] = std::make_unique<SCT_CalibDefectData>();
171 }
172 std::unique_ptr<SCT_AllGoodStripInfo> writeCdoInfo{std::make_unique<SCT_AllGoodStripInfo>()};
173 // Initialize arrays and all strips to True
174 for (int w{0}; w!=NUMBER_OF_WAFERS; ++w) {
175 for (int s{0}; s!=STRIPS_PER_WAFER; ++s) {
176 (*writeCdoInfo)[w][s]=true;
177 }
178 }
179
180
181 // Create pointer to CalibDataDefect object
183
184 // loop over collection
185 for (unsigned int i{GAIN}; i<NFEATURES; i++) {
186 CondAttrListCollection::const_iterator itLoop{readCdo[i]->begin()};
187 CondAttrListCollection::const_iterator itLoop_end{readCdo[i]->end()};
188 for (; itLoop!=itLoop_end; ++itLoop) {
189 CondAttrListCollection::ChanNum chanNum{(*itLoop).first};
190 const coral::AttributeList &anAttrList{(*itLoop).second};
191
192 // Convert chanNum=offlineID into identifier
193 Identifier moduleId{chanNum};
194 IdentifierHash hashId0{m_id_sct->wafer_hash(moduleId)};
195 IdentifierHash hashId1;
196 m_id_sct->get_other_side(hashId0, hashId1);
197
198 // Check for PhiSwap readout
199 const InDetDD::SiDetectorElement* p_element{elements->getDetectorElement(hashId0)};
200 bool phiSwap0Present{p_element->swapPhiReadoutDirection()};
201 p_element = (elements->getDetectorElement(hashId1));
202 bool phiSwap1Present{p_element->swapPhiReadoutDirection()};
203
204 // Clear theseDefects
205 theseDefects.begDefects.clear();
206 theseDefects.endDefects.clear();
207 theseDefects.typeOfDefect.clear();
208 theseDefects.parValue.clear();
209
210 // Get all defect parameters from COOL attrib list
211 const std::string &gaindefectb{(anAttrList["defectBeginChannel"]).data<std::string>()};
212 const std::string &gaindefecte{(anAttrList["defectEndChannel"]).data<std::string>()};
213 const std::string &defectType{(anAttrList["defectType"]).data<std::string>()};
214 const std::string &parValue{(anAttrList["defectParameter"]).data<std::string>()};
215
216 // Convert the defect strings to vectors
217 std::vector<unsigned int> gaindefectbvec;
218 fillEmptyVectorFromString(gaindefectb, gaindefectbvec);
219 std::vector<unsigned int> gaindefectevec;
220 fillEmptyVectorFromString(gaindefecte, gaindefectevec);
221 std::vector<unsigned int> defectTypevec;
222 fillEmptyVectorFromString(defectType, defectTypevec);
223 std::vector<double> parValuevec;
224 fillEmptyVectorFromString(parValue, parValuevec);
225
226 // Fill the Calib defect objects
227 long unsigned int gainvec_size{gaindefectbvec.size()};
228 for (long unsigned int i{0}; i<gainvec_size; ++i) {
229 // Check existence of the defect index to avoid failure when a new defect is added in SCT DAQ.
230 if (m_defectMapIntToString.find(defectTypevec[i]) == m_defectMapIntToString.end()) {
231 ATH_MSG_DEBUG("Defect type " << defectTypevec[i] << " is not defined! This defect is ignored.");
232 } else {
233 theseDefects.typeOfDefect.push_back(m_defectMapIntToString.at(defectTypevec[i]));
234 theseDefects.begDefects.push_back(gaindefectbvec[i]);
235 theseDefects.endDefects.push_back(gaindefectevec[i]);
236 theseDefects.parValue.push_back(coerceToFloatRange(parValuevec[i]));
237 }
238 }
239 // Fill the isGoodWaferArray
240 if (not theseDefects.begDefects.empty()) {
241 for (unsigned int i{0}; i<theseDefects.begDefects.size(); ++i) { // loop over all defects
242 // Check for defects and their limits not to take into account in isGood
243 bool ignoreDefect{false};
244 unsigned int ig{0};
245 while (ig<m_ignoreDefects.value().size()) { //loop until found defect or end of ignoredefects
246 if (m_ignoreDefects.value()[ig] == theseDefects.typeOfDefect[i]) {
247 if ( m_ignoreDefectParameters.value()[ig]<-999. ) ignoreDefect = true; //no check on parameter value, defect ignored
248 else if (theseDefects.typeOfDefect[i]=="NO_HI" and m_ignoreDefectParameters.value()[ig]>theseDefects.parValue[i]) ignoreDefect = true; //noise below threshold, > 0.0005 (in DB, so default values printed here)
249 else if (theseDefects.typeOfDefect[i]=="NOISY" and m_ignoreDefectParameters.value()[ig]>theseDefects.parValue[i]) ignoreDefect = true; //noise below threshold, > 1.15* av chip average
250 else if (theseDefects.typeOfDefect[i]=="V_NOISY" and m_ignoreDefectParameters.value()[ig]>theseDefects.parValue[i]) ignoreDefect = true; //noise below threshold, > 1.25* av chip average
251 else if (theseDefects.typeOfDefect[i]=="VLO_GAIN" and m_ignoreDefectParameters.value()[ig]<theseDefects.parValue[i]) ignoreDefect = true; // gain to low, < 0.3 * chip average
252 else if (theseDefects.typeOfDefect[i]=="LO_GAIN" and m_ignoreDefectParameters.value()[ig]<theseDefects.parValue[i]) ignoreDefect = true; // gain to low < 0.75 * chip average
253 else if (theseDefects.typeOfDefect[i]=="HI_GAIN" and m_ignoreDefectParameters.value()[ig]>theseDefects.parValue[i]) ignoreDefect = true; // gain to high > 1.25 * chip average
254 else if (theseDefects.typeOfDefect[i]=="LO_OFFSET" and m_ignoreDefectParameters.value()[ig]>theseDefects.parValue[i]) ignoreDefect = true; // offset to low < -100
255 else if (theseDefects.typeOfDefect[i]=="HI_OFFSET" and m_ignoreDefectParameters.value()[ig]<theseDefects.parValue[i]) ignoreDefect = true; // offset to high > 200
256 }
257 ig++;
258 }
259 if (not ignoreDefect) {
260 //set the isGoodBool value for all strips for this defect
261 for (unsigned int strip = theseDefects.begDefects[i]; strip <= theseDefects.endDefects[i]; ++strip) {
262 // Check for phiSwap and which wafer side before filling isGood vector
263 if (strip < STRIPS_PER_WAFER) { //side 0 0->767
264 const unsigned int waferId0{hashId0};
265 SCT_WaferGoodStripInfo& thisWaferIsGoodData0{(*writeCdoInfo)[waferId0]};
266 const unsigned int side0StripNumber{phiSwap0Present ? ( STRIPS_PER_WAFER-1-strip) : strip};
267 thisWaferIsGoodData0[side0StripNumber] = false;
268 } else { // side 1 768->1535 => 0->767
269 const unsigned int waferId1{hashId1};
270 SCT_WaferGoodStripInfo& thisWaferIsGoodData1{(*writeCdoInfo)[waferId1]};
271 const unsigned int side1StripNumber{phiSwap1Present ? (2*STRIPS_PER_WAFER-1-strip) : (strip-STRIPS_PER_WAFER)};
272 thisWaferIsGoodData1[side1StripNumber] = false;
273 }
274 }
275 }
276 }
277 }
278
279 // Fill the CalibDefectData maps with the Calib defect objects
280 if (i==GAIN) {
281 if (theseDefects.begDefects.empty()) {
282 ATH_MSG_DEBUG("No NPtGain defects for module " << moduleId);
283 continue;
284 }
285 if (not (writeCdoData[i]->addModule(moduleId, theseDefects))) {
286 ATH_MSG_ERROR("Unable to add module " << moduleId << " to NPtGain defect map");
287 return StatusCode::RECOVERABLE;
288 } else {
289 ATH_MSG_DEBUG("Defects for module " << moduleId << " added to NPG defect map");
290 }
291 } else if (i==NOISE) {
292 if (theseDefects.begDefects.empty()) {
293 ATH_MSG_DEBUG("No NoiseOccupancy defects for module " << moduleId);
294 continue;
295 }
296 if (not (writeCdoData[i]->addModule(moduleId, theseDefects))) {
297 ATH_MSG_ERROR("Unable to add module " << moduleId << " to NoiseOccupancy defect map");
298 return StatusCode::RECOVERABLE;
299 } else {
300 ATH_MSG_DEBUG("Defects for module " << moduleId << " added to NoiseOccupancy defect map");
301 }
302 }
303 }
304 }
305
306 // Record the output cond objects
307 ATH_MSG_DEBUG("There are " << writeCdoInfo->size() << " elements in " << writeHandleInfo.key());
308 if (writeHandleInfo.record(std::move(writeCdoInfo)).isFailure()) {
309 ATH_MSG_FATAL("Could not record SCT_AllGoodStripInfo " << writeHandleInfo.key()
310 << " with EventRange " << writeHandleInfo.getRange() << " into Conditions Store");
311 return StatusCode::FAILURE;
312 }
313 ATH_MSG_INFO("recorded new CDO " << writeHandleInfo.key() << " with range " << writeHandleInfo.getRange() << " into Conditions Store");
314 for (unsigned int i{GAIN}; i<NFEATURES; i++) {
315 ATH_MSG_DEBUG("There are " << writeCdoData[i]->size() << " elements in " << writeHandleData[i].key());
316 if (writeHandleData[i].record(std::move(writeCdoData[i])).isFailure()) {
317 ATH_MSG_FATAL("Could not record SCT_CalibDefectData " << writeHandleData[i].key()
318 << " with EventRange " << writeHandleData[i].getRange() << " into Conditions Store");
319 return StatusCode::FAILURE;
320 }
321 ATH_MSG_INFO("recorded new CDO " << writeHandleData[i].key() << " with range " << writeHandleData[i].getRange() << " into Conditions Store");
322 }
323
324 return StatusCode::SUCCESS;
325}
326
328 ATH_MSG_DEBUG("finalize " << name());
329 return StatusCode::SUCCESS;
330}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
header file containing the number of elements and enumerated type of parameters which may be retrieve...
This is an Identifier helper class for the SCT subdetector.
std::array< bool, SCT_ConditionsData::STRIPS_PER_WAFER > SCT_WaferGoodStripInfo
Class for data object used in SCT_ReadCalibDataCondAlg and SCT_AllGoodStripInfo.
const ServiceHandle< StoreGateSvc > & detStore() const
Base class for conditions algorithms.
This class is a collection of AttributeLists where each one is associated with a channel number.
const_iterator end() const
const_iterator begin() const
Access to Chan/AttributeList pairs via iterators.
ChanAttrListMap::const_iterator const_iterator
This is a "hash" representation of an Identifier.
Class to hold the SiDetectorElement objects to be put in the detector store.
const SiDetectorElement * getDetectorElement(const IdentifierHash &hash) const
Class to hold geometrical description of a silicon detector element.
bool swapPhiReadoutDirection() const
Determine if readout direction between online and offline needs swapping.
SG::ReadCondHandleKey< CondAttrListCollection > m_readKeyNoise
SG::WriteCondHandleKey< SCT_AllGoodStripInfo > m_writeKeyInfo
SG::ReadCondHandleKey< InDetDD::SiDetectorElementCollection > m_SCTDetEleCollKey
SG::WriteCondHandleKey< SCT_CalibDefectData > m_writeKeyNoise
const SCT_ID * m_id_sct
Handle to SCT ID helper.
SG::WriteCondHandleKey< SCT_CalibDefectData > m_writeKeyGain
std::map< int, std::string > m_defectMapIntToString
virtual StatusCode execute(const EventContext &ctx) const override final
virtual StatusCode finalize() override final
virtual StatusCode initialize() override final
SCT_ReadCalibDataCondAlg(const std::string &name, ISvcLocator *pSvcLocator)
FloatArrayProperty m_ignoreDefectParameters
SG::ReadCondHandleKey< CondAttrListCollection > m_readKeyGain
StatusCode initialize(bool used=true)
const_pointer_type retrieve()
const std::string & key() const
void addDependency(const EventIDRange &range)
const EventIDRange & getRange() const
StatusCode record(const EventIDRange &range, T *t)
record handle, with explicit range DEPRECATED
const DataObjID & fullKey() const