ATLAS Offline Software
Loading...
Searching...
No Matches
LArOFFCRawChannelBuilder Class Reference

#include <LArOFFCRawChannelBuilder.h>

Inheritance diagram for LArOFFCRawChannelBuilder:

Classes

struct  LayerParams
 Resolved parameters for one layer. More...

Public Member Functions

StatusCode initialize () override
StatusCode execute (const EventContext &ctx) const override
StatusCode finalize () override
virtual StatusCode sysInitialize () override
 Override sysInitialize.
virtual bool isClonable () const override
 Specify if the algorithm is clonable.
virtual StatusCode sysExecute (const EventContext &ctx) override
 Execute an algorithm.
virtual const DataObjIDColl & extraOutputDeps () const override
 Return the list of extra output dependencies.
virtual bool filterPassed (const EventContext &ctx) const
 Get filter decision:
virtual void setFilterPassed (bool state, const EventContext &ctx) const
 Set filter decision:
ServiceHandle< StoreGateSvc > & evtStore ()
 The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
const ServiceHandle< StoreGateSvc > & detStore () const
 The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.
virtual StatusCode sysStart () override
 Handle START transition.
virtual std::vector< Gaudi::DataHandle * > inputHandles () const override
 Return this algorithm's input handles.
virtual std::vector< Gaudi::DataHandle * > outputHandles () const override
 Return this algorithm's output handles.
Gaudi::Details::PropertyBase & declareProperty (Gaudi::Property< T, V, H > &t)
void updateVHKA (Gaudi::Details::PropertyBase &)
MsgStream & msg () const
bool msgLvl (const MSG::Level lvl) const

Protected Member Functions

void renounceArray (SG::VarHandleKeyArray &handlesArray)
 remove all handles from I/O resolution
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce (T &h)
void extraDeps_update_handler (Gaudi::Details::PropertyBase &ExtraDeps)
 Add StoreName to extra input/output deps as needed.

Private Types

typedef ServiceHandle< StoreGateSvcStoreGateSvc_t

Private Member Functions

StatusCode buildLayerMap (const EventContext &ctx) const
std::vector< double > pulseResponse (const ILArShape::ShapeRef_t &shape, const ILArOFC::OFCRef_t &ofc) const
 Filter output for a unit-amplitude pulse, tabulated over every offset of the shape against the OFC window at which the two overlap.
double computeOFFC (const std::vector< short > &samples, int firstSample, const ILArOFC::OFCRef_t &ofc, const ILArShape::ShapeRef_t &shape, double pedestal, const LayerParams &par) const
Gaudi::Details::PropertyBase & declareGaudiProperty (Gaudi::Property< T, V, H > &hndl, const SG::VarHandleKeyType &)
 specialization for handling Gaudi::Property<SG::VarHandleKey>

Static Private Member Functions

static size_t slotOf (int region, int layer)
 Slot for a region code (0=EMB..4=FCAL) and sampling/module; s_nSlots if out of range.
static size_t slotOfKey (const std::string &key)
 Parse "<REGION>/<LAYER>" into a slot. Returns s_nSlots if unparseable.
static std::string keyOfSlot (size_t slot)

Private Attributes

SG::ReadHandleKey< LArDigitContainerm_digitKey
SG::WriteHandleKey< LArRawChannelContainerm_rawChannelKey
SG::ReadCondHandleKey< ILArPedestalm_pedestalKey
SG::ReadCondHandleKey< LArADC2MeVm_adc2MeVKey
SG::ReadCondHandleKey< ILArOFCm_ofcKey
SG::ReadCondHandleKey< ILArShapem_shapeKey
SG::ReadCondHandleKey< LArOnOffIdMappingm_cablingKey
SG::ReadCondHandleKey< LArDSPThresholdsCompletem_run1DSPThresholdsKey
SG::ReadCondHandleKey< AthenaAttributeListm_run2DSPThresholdsKey
Gaudi::Property< float > m_eCutFortQ
Gaudi::Property< bool > m_absECutFortQ
Gaudi::Property< bool > m_useShapeDer
Gaudi::Property< bool > m_useDBFortQ
Gaudi::Property< int > m_firstSample
 Index of the digit sample the OFC window starts at, i.e.
Gaudi::Property< double > m_belowThreshold
 The OFFC extends optimal filtering by finding pulses in the preceding samples and subtracting their expected filter response from the later ones.
Gaudi::Property< int > m_belowTillReset
 Number of consecutive below-threshold samples after which the pending corrections are dropped, so that stale ones cannot persist through a quiet region.
Gaudi::Property< int > m_nPulse
 Maximum number of pulse corrections in flight at once.
Gaudi::Property< double > m_Q3cut
 Quality cut for pulse acceptance.
Gaudi::Property< double > m_Q3Offset
 Absolute term of the Q3 cut, in ADC.
Gaudi::Property< double > m_filterThreshold
 Minimum pile-up corrected amplitude required to accept a pulse peak.
Gaudi::Property< std::map< std::string, double > > m_filterThresholdByLayer
Gaudi::Property< std::map< std::string, double > > m_q3CutByLayer
Gaudi::Property< std::map< std::string, double > > m_q3OffsetByLayer
Gaudi::Property< std::map< std::string, int > > m_nPulseByLayer
Gaudi::Property< std::vector< std::string > > m_enabledLayers
 Layers the correction may run in; empty means all.
std::vector< LayerParamsm_layerParams
std::vector< uint8_t > m_slotByHash ATLAS_THREAD_SAFE
 online hash -> slot, built on the first event: it needs the cabling, which is conditions data with an IOV.
std::once_flag m_slotOnce ATLAS_THREAD_SAFE
StatusCode m_slotStatus ATLAS_THREAD_SAFE {StatusCode::SUCCESS}
const LArOnlineIDm_onlineId = nullptr
const CaloCell_IDm_caloId = nullptr
std::atomic< unsigned long > m_nSubtracted {0}
 Accepted pulses, and those NPulse left no room to subtract.
std::atomic< unsigned long > m_nDropped {0}
DataObjIDColl m_extendedExtraObjects
 Extra output dependency collection, extended by AthAlgorithmDHUpdate to add symlinks.
StoreGateSvc_t m_evtStore
 Pointer to StoreGate (event store by default).
StoreGateSvc_t m_detStore
 Pointer to StoreGate (detector store by default).
std::vector< SG::VarHandleKeyArray * > m_vhka
bool m_varHandleArraysDeclared

Static Private Attributes

static constexpr size_t s_nSlots = 20
 Five regions x at most four samplings.

Detailed Description

Definition at line 35 of file LArOFFCRawChannelBuilder.h.

Member Typedef Documentation

◆ StoreGateSvc_t

typedef ServiceHandle<StoreGateSvc> AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::StoreGateSvc_t
privateinherited

Definition at line 388 of file AthCommonDataStore.h.

Member Function Documentation

◆ buildLayerMap()

StatusCode LArOFFCRawChannelBuilder::buildLayerMap ( const EventContext & ctx) const
private

Definition at line 82 of file LArOFFCRawChannelBuilder.cxx.

83 {
84 // Layer is an IDENTIFIER quantity, not a geometric one, so this needs no
85 // CaloDetDescrManager and has no matching tolerance to get wrong: a
86 // channel resolves to exactly one layer or to none.
87 const LArOnOffIdMapping* cabling{};
88 ATH_CHECK(SG::get(cabling, m_cablingKey, ctx));
89
90 const LArEM_ID* emId = m_caloId->em_idHelper();
91 const LArHEC_ID* hecId = m_caloId->hec_idHelper();
92 const LArFCAL_ID* fcalId = m_caloId->fcal_idHelper();
93
94 m_slotByHash.assign(m_onlineId->channelHashMax(),
95 static_cast<uint8_t>(s_nSlots));
96 size_t nMapped = 0, nUnmapped = 0;
97 for (auto it = m_onlineId->channel_begin(); it != m_onlineId->channel_end();
98 ++it) {
99 const HWIdentifier hw = *it;
100 if (!cabling->isOnlineConnected(hw)) continue;
101 const Identifier cid = cabling->cnvToIdentifier(hw);
102 int region = -1, layer = -1;
103 if (m_caloId->is_em(cid)) {
104 region = std::abs(emId->barrel_ec(cid)) - 1;
105 layer = emId->sampling(cid);
106 } else if (m_caloId->is_hec(cid)) {
107 region = 3;
108 layer = hecId->sampling(cid);
109 } else if (m_caloId->is_fcal(cid)) {
110 region = 4;
111 layer = fcalId->module(cid);
112 } else {
113 continue;
114 }
115 const size_t slot = slotOf(region, layer);
116 if (slot >= s_nSlots) { ++nUnmapped; continue; }
117 m_slotByHash[m_onlineId->channel_Hash(hw)] = static_cast<uint8_t>(slot);
118 ++nMapped;
119 }
120 ATH_MSG_INFO("layer map: " << nMapped << " channels resolved, " << nUnmapped
121 << " outside the known regions (these fall back "
122 "to the global settings)");
123 return StatusCode::SUCCESS;
124}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x,...)
int barrel_ec(const Identifier id) const
return barrel_ec according to :
int sampling(const Identifier id) const
return sampling according to :
int sampling(const Identifier id) const
return sampling [0,3] (only 0 for supercells)
static constexpr size_t s_nSlots
Five regions x at most four samplings.
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
static size_t slotOf(int region, int layer)
Slot for a region code (0=EMB..4=FCAL) and sampling/module; s_nSlots if out of range.
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
@ layer
Definition HitInfo.h:79

◆ computeOFFC()

double LArOFFCRawChannelBuilder::computeOFFC ( const std::vector< short > & samples,
int firstSample,
const ILArOFC::OFCRef_t & ofc,
const ILArShape::ShapeRef_t & shape,
double pedestal,
const LayerParams & par ) const
private

Definition at line 153 of file LArOFFCRawChannelBuilder.cxx.

158 {
159 // OFFC parameters (configured via job options)
160 // belowThreshold : ADC threshold to detect quiet regions
161 // belowTillReset : consecutive quiet samples before cache reset
162 // npulse : max number of overlapping pulses tracked
163 // Q3cut : shape-consistency cut for pulse acceptance
164 // filterThreshold : minimum filtered amplitude to seed a pulse
165
166 const int nSamples = samples.size();
167 const int ofcLen = ofc.size();
168
169 // Checked by the caller. The filter at position i needs samples
170 // i ... i+ofcLen-1, and every position it is evaluated at gets a corrected
171 // value, so the last one is nSamples-ofcLen.
172 if (ofcLen <= 0 || firstSample < 0 || firstSample + ofcLen > nSamples) {
173 ATH_MSG_WARNING("Cannot run the OFFC on " << nSamples << " samples with "
174 << ofcLen << " OFCs from sample "
175 << firstSample);
176 return 0.0;
177 }
178
179 // Pedestal subtraction
180 std::vector<double> samp_no_ped(nSamples);
181 for (int i = 0; i < nSamples; ++i)
182 samp_no_ped[i] = samples[i] - pedestal;
183
184 std::vector<double> reco(nSamples, 0.0);
185
186 // Precompute the filter response to a unit-amplitude pulse. cache[lagZero]
187 // is the correction of the sample being filtered, cache[lagZero+n] that of
188 // the one n later.
189 std::vector<double> response = pulseResponse(shape, ofc);
190 const int responseSize = response.size();
191 if (responseSize == 0) {
192 ATH_MSG_WARNING("Empty pulse response, shape size " << shape.size()
193 << " OFC size " << ofcLen);
194 return 0.0;
195 }
196
197 // Entry of response[] a pulse is found at. Pulses are identified as local
198 // maxima of 'filtered', so the template has to be anchored where the
199 // response peaks: that follows whatever alignment the OFCs carry, which is
200 // neither fixed nor the same for every channel (see LArOFCCondAlg).
201 const int lagZero = anchorIndex(response);
202 if (response[lagZero] <= 0.0) {
203 ATH_MSG_WARNING("Pulse response is nowhere positive, cannot subtract");
204 return 0.0;
205 }
206
207 // A is the filter output at that peak, so the template must be 1 there. It
208 // only already is when the response happens to peak where the OFCs were
209 // matched to the shape.
210 const double peakResponse = response[lagZero];
211 for (double& r : response)
212 r /= peakResponse;
213 std::vector<double> cache(responseSize, 0.0);
214
215 // A pulse writes cache entries lagZero ... responseSize-2, and entry k is
216 // consumed k-lagZero iterations later, so that is how long a slot stays busy.
217 const int correctionLength = responseSize - 2 - lagZero;
218
219 // Sample at which each pulse slot becomes available again
220 std::vector<int> slotFreeAt(par.nPulse, 0);
221 int belowCounter = 0;
222
223 const int loopEnd = std::max(0, nSamples - ofcLen + 1);
224
225 for (int i = 0; i < loopEnd; ++i) {
226
227 // Reset the correction cache after an extended quiet region
228 if (std::abs(samp_no_ped[i]) < par.belowThreshold)
229 ++belowCounter;
230 else
231 belowCounter = 0;
232
233 if (par.belowTillReset > 0 && belowCounter >= par.belowTillReset) {
234 belowCounter = 0;
235 std::fill(cache.begin(), cache.end(), 0.0);
236 // The corrections these slots were tracking have just been dropped, so
237 // the slots have to be released with them
238 std::fill(slotFreeAt.begin(), slotFreeAt.end(), 0);
239 }
240
241 // Standard OF filtering
242 double filtered = 0.0;
243 for (int j = 0; j < ofcLen; ++j)
244 filtered += samp_no_ped[i + j] * ofc[j];
245
246 // Corrected value of the sample just filtered, before anything found this
247 // iteration is subtracted from it
248 const double recoCurrent = filtered + cache[lagZero];
249
250 // Candidate peak: where a pulse would be in time with the OFCs, not where
251 // the pulse itself is largest. The search trails the filtering by one, a
252 // maximum can only be recognised once the following sample is in.
253 const int peak = i - 1;
254 if (peak + q3Lags.front() >= 0) {
255 const double A = reco.at(peak);
256
257 // Local maximum + amplitude cut on the corrected waveform: a pulse
258 // riding on the tail of one already subtracted need not be a local
259 // maximum of the raw filter output at all.
260 if (A > par.filterThreshold && A > reco.at(peak - 1) && A > recoCurrent) {
261
262 auto responseVal = [&](int lag) {
263 const int k = lagZero + lag;
264 return (k >= 0 && k < responseSize) ? response[k] : 0.0;
265 };
266 // reco[] is final for the peak and everything before it; the sample
267 // being filtered is not stored yet, and no later lag can occur here.
268 auto recoVal = [&](int lag) {
269 return lag <= 0 ? reco.at(peak + lag) : recoCurrent;
270 };
271
272 double Q3 = 0.0;
273 for (int lag : q3Lags)
274 Q3 += std::abs(recoVal(lag) - A * responseVal(lag));
275
276 // Accept pulse and subtract its forward correction, if NPulse leaves
277 // room for it. Shape mismatch scales with the amplitude while the
278 // noise floor does not, so the cut carries one term of each: written
279 // as a product rather than a ratio to avoid dividing, and A>0 here for
280 // any sensible FilterThreshold.
281 if (Q3 < par.q3Offset + par.q3Cut * A) {
282 const auto slot = std::ranges::find_if(
283 slotFreeAt, [i](int freeAt) { return freeAt <= i; });
284 if (slot == slotFreeAt.end()) {
285 ++m_nDropped;
286 } else {
287 // The pulse peaks one sample back, so its lag n lands on the entry
288 // for sample i+n-1, i.e. cache[lagZero+n-1]
289 for (int k = lagZero; k + 1 < responseSize; ++k)
290 cache[k] -= response[k + 1] * A;
291 *slot = i + correctionLength;
293 }
294 }
295 }
296 }
297
298 // Corrected filter output of this sample, now including any pulse just
299 // accepted one sample back
300 reco[i] = filtered + cache[lagZero];
301
302 // Advance correction cache in time
303 std::rotate(cache.begin(), cache.begin() + 1, cache.end());
304 cache.back() = 0.0;
305 }
306
307 // Corrected equivalent of the plain OF amplitude, which is the filter output
308 // of the window starting at firstSample
309 return reco[firstSample];
310}
#define ATH_MSG_WARNING(x,...)
MDT_Response response
std::vector< double > pulseResponse(const ILArShape::ShapeRef_t &shape, const ILArOFC::OFCRef_t &ofc) const
Filter output for a unit-amplitude pulse, tabulated over every offset of the shape against the OFC wi...
std::atomic< unsigned long > m_nDropped
std::atomic< unsigned long > m_nSubtracted
Accepted pulses, and those NPulse left no room to subtract.
int r
Definition globals.cxx:22
float j(const xAOD::IParticle &, const xAOD::TrackMeasurementValidation &hit, const Eigen::Matrix3d &jab_inv)
const IIntersectionCache * cache() const
Retrieve the associated cache block, if it exists.
void rotate(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > mid, typename DataModel_detail::iterator< DVL > end)
Specialization of rotate for DataVector/List.

◆ declareGaudiProperty()

Gaudi::Details::PropertyBase & AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::declareGaudiProperty ( Gaudi::Property< T, V, H > & hndl,
const SG::VarHandleKeyType &  )
inlineprivateinherited

specialization for handling Gaudi::Property<SG::VarHandleKey>

Definition at line 156 of file AthCommonDataStore.h.

158 {
160 hndl.value(),
161 hndl.documentation());
162
163 }
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)

◆ declareProperty()

Gaudi::Details::PropertyBase & AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::declareProperty ( Gaudi::Property< T, V, H > & t)
inlineinherited

Definition at line 145 of file AthCommonDataStore.h.

145 {
146 typedef typename SG::HandleClassifier<T>::type htype;
148 }
Gaudi::Details::PropertyBase & declareGaudiProperty(Gaudi::Property< T, V, H > &hndl, const SG::VarHandleKeyType &)
specialization for handling Gaudi::Property<SG::VarHandleKey>

◆ detStore()

const ServiceHandle< StoreGateSvc > & AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::detStore ( ) const
inlineinherited

The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.

Definition at line 95 of file AthCommonDataStore.h.

◆ evtStore()

ServiceHandle< StoreGateSvc > & AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::evtStore ( )
inlineinherited

The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.

Definition at line 85 of file AthCommonDataStore.h.

◆ execute()

StatusCode LArOFFCRawChannelBuilder::execute ( const EventContext & ctx) const
override

Definition at line 454 of file LArOFFCRawChannelBuilder.cxx.

454 {
455
456 ATH_MSG_VERBOSE("Executing LArOFFCRawChannelBuilder::execute");
457
458 // Get event inputs from read handles:
459 const LArDigitContainer* inputContainer{};
460 ATH_CHECK(SG::get(inputContainer, m_digitKey, ctx));
461
462 // Write output via write handle
463 auto outputContainer = std::make_unique<LArRawChannelContainer>();
464
465 // Get Conditions input
466 const ILArPedestal* peds{};
467 ATH_CHECK(SG::get(peds, m_pedestalKey, ctx));
468
469 const LArADC2MeV* adc2MeVs{};
470 ATH_CHECK(SG::get(adc2MeVs, m_adc2MeVKey, ctx));
471
472 const ILArOFC* ofcs{nullptr};
473 ATH_CHECK(SG::get(ofcs, m_ofcKey, ctx));
474
475 const ILArShape* shapes{};
476 ATH_CHECK(SG::get(shapes, m_shapeKey, ctx));
477
478 const LArOnOffIdMapping* cabling{};
479 ATH_CHECK(SG::get(cabling, m_cablingKey, ctx));
480
481 std::unique_ptr<LArDSPThresholdsFlat> run2DSPThresh;
482 const LArDSPThresholdsComplete* run1DSPThresh = nullptr;
483 ATH_CHECK(SG::get(run1DSPThresh, m_run1DSPThresholdsKey, ctx));
484 if (m_useDBFortQ) {
485 if (!m_run2DSPThresholdsKey.empty()) {
486 SG::ReadCondHandle<AthenaAttributeList> dspThrshAttr(
488 run2DSPThresh = std::make_unique<LArDSPThresholdsFlat>(*dspThrshAttr);
489 if (!run2DSPThresh->good()) [[unlikely]] {
491 "Failed to initialize LArDSPThresholdFlat from attribute list "
492 "loaded from "
493 << m_run2DSPThresholdsKey.key() << ". Aborting.");
494 return StatusCode::FAILURE;
495 }
496 } else if (!m_run1DSPThresholdsKey.empty()) {
497 SG::ReadCondHandle<LArDSPThresholdsComplete> dspThresh(
499 run1DSPThresh = dspThresh.cptr();
500 } else {
501 ATH_MSG_ERROR("No DSP threshold configured.");
502 return StatusCode::FAILURE;
503 }
504 }
505
506 // Loop over digits:
507 // Built once on the first event, not in initialize(): it needs the
508 // cabling, which is conditions data with an IOV.
509 std::call_once(m_slotOnce, [&]() {
510 m_slotStatus = this->buildLayerMap(ctx);
511 });
512 ATH_CHECK(m_slotStatus);
513
514 for (const LArDigit* digit : *inputContainer) {
515
516 const size_t firstSample = m_firstSample;
517
518 const HWIdentifier id = digit->hardwareID();
519
520 const bool connected = cabling->isOnlineConnected(id);
521
522 // Per-layer parameters. The last entry is the global fallback, used for
523 // any channel outside the five known regions.
524 const IdentifierHash hash = m_onlineId->channel_Hash(id);
525 const size_t slot = (hash < m_slotByHash.size())
526 ? static_cast<size_t>(m_slotByHash[hash])
527 : s_nSlots;
528 const LayerParams& par = m_layerParams[slot];
529
530 const std::vector<short>& samples = digit->samples();
531 const int gain = digit->gain();
532 const float p = peds->pedestal(id, gain);
533
534 // The following autos will resolve either into vectors or vector-proxies
535 const auto& ofca = ofcs->OFC_a(id, gain);
536 const auto& adc2mev = adc2MeVs->ADC2MEV(id, gain);
537 const size_t nOFC = ofca.size();
538
539 if (ATH_UNLIKELY(nOFC == 0)) {
540 if (!connected)
541 continue; // No conditions for disconencted channel, who cares?
542 ATH_MSG_ERROR("No valid OFCs for connected channel "
543 << m_onlineId->channel_name(id) << " gain " << gain);
544 return StatusCode::FAILURE;
545 }
546
547 // Sanity check on input conditions data: ensure the samples vector is
548 // compatible with the ofc_a size when preceeding samples are saved.
549 // Compared this way round because samples.size()-firstSample would wrap
550 // for a short digit.
551 if (samples.size() < firstSample + nOFC) {
552 ATH_MSG_ERROR("digit has " << samples.size() << " samples, need at least "
553 << firstSample + nOFC << " for firstSample "
554 << firstSample << " and OFC_a size " << nOFC);
555 return StatusCode::FAILURE;
556 }
557
558 if (p == ILArPedestal::ERRORCODE) [[unlikely]] {
559 if (!connected)
560 continue; // No conditions for disconencted channel, who cares?
561 ATH_MSG_ERROR("No valid pedestal for connected channel "
562 << m_onlineId->channel_name(id) << " gain " << gain);
563 return StatusCode::FAILURE;
564 }
565
566 if (adc2mev.size() < 2) [[unlikely]] {
567 if (!connected)
568 continue; // No conditions for disconencted channel, who cares?
569 ATH_MSG_ERROR("No valid ADC2MeV for connected channel "
570 << m_onlineId->channel_name(id) << " gain " << gain);
571 return StatusCode::FAILURE;
572 }
573
574 // Apply OFFC to get amplitude
575 // Evaluate sums in double-precision to get consistent results
576 // across platforms.
577
578 bool saturated = false;
579 // Check saturation AND discount pedestal
580 std::vector<double> samp_no_ped(nOFC, 0.0);
581 for (size_t i = 0; i < nOFC; ++i) {
582 if (samples[i + firstSample] == 4096 || samples[i + firstSample] == 0)
583 saturated = true;
584 samp_no_ped[i] = samples[i + firstSample] - p;
585 }
586
587 uint16_t iquaShort = 0;
588 float tau = 0;
589
590 uint16_t prov = LArProv::DEFAULTRECO; // Means all constants from DB
591 if (saturated)
592 prov |= LArProv::SATURATED;
593
594 float ecut(0.);
595 if (m_useDBFortQ) {
596 if (run2DSPThresh) {
597 ecut = run2DSPThresh->tQThr(id);
598 } else if (run1DSPThresh) {
599 ecut = run1DSPThresh->tQThr(id);
600 } else {
601 ATH_MSG_ERROR("DSP threshold problem");
602 return StatusCode::FAILURE;
603 }
604 } else {
605 ecut = m_eCutFortQ;
606 }
607
608 const auto& fullShape = shapes->Shape(id, gain);
609
610 double A = computeOFFC(samples, firstSample, ofca, fullShape, p, par);
611
612 const float E = adc2mev[0] + A * adc2mev[1];
613
614 const float E1 = m_absECutFortQ.value() ? std::fabs(E) : E;
615
616 if (E1 > ecut) {
617 ATH_MSG_VERBOSE("Channel " << m_onlineId->channel_name(id) << " gain "
618 << gain
619 << " above threshold for tQ computation");
620 prov |= LArProv::QTPRESENT; // time+quality information are available
621
622 // Get time by applying OFC-b coefficients:
623 const auto& ofcb = ofcs->OFC_b(id, gain);
624 double At = 0;
625 for (size_t i = 0; i < nOFC; ++i) {
626 At += static_cast<double>(samp_no_ped[i]) * ofcb[i];
627 }
628
629 // Divide A*t/A to get time
630 tau = (std::fabs(A) > 0.1) ? At / A : 0.0;
631
632 // Get Q-factor. The shape has to be offset by the index the OFC window
633 // is matched to, which is not the digit offset: the digitisation writes
634 // shape index k-nPreceedingSamples into digit sample k. Reading it back
635 // from the conditions also covers the HEC shift and the fallback that
636 // LArOFCCondAlg applies per channel.
637 const std::vector<double> resp = pulseResponse(fullShape, ofca);
638 const int shapeShift =
639 resp.empty() ? -1 : anchorIndex(resp) - static_cast<int>(nOFC) + 1;
640
641 if (shapeShift < 0 || fullShape.size() < nOFC + shapeShift) [[unlikely]] {
642 if (!connected)
643 continue; // No conditions for disconnected channel, who cares?
644 ATH_MSG_ERROR("No valid shape for channel "
645 << m_onlineId->channel_name(id) << " gain " << gain);
646 ATH_MSG_ERROR("Got size " << fullShape.size() << " and offset "
647 << shapeShift << ", expected at least "
648 << nOFC << " samples from there");
649 return StatusCode::FAILURE;
650 }
651
652 std::span<const float> shape(fullShape.data() + shapeShift,
653 fullShape.size() - shapeShift);
654
655 double q = 0;
656 if (m_useShapeDer) {
657 const auto& fullshapeDer = shapes->ShapeDer(id, gain);
658 if (fullshapeDer.size() < nOFC + shapeShift) [[unlikely]] {
659 ATH_MSG_ERROR("No valid shape derivative for channel "
660 << m_onlineId->channel_name(id) << " gain " << gain);
661 ATH_MSG_ERROR("Got size " << fullshapeDer.size()
662 << ", expected at least "
663 << nOFC + shapeShift);
664 return StatusCode::FAILURE;
665 }
666
667 std::span<const float> shapeDer(fullshapeDer.data() + shapeShift,
668 fullshapeDer.size() - shapeShift);
669
670
671 for (size_t i = 0; i < nOFC; ++i) {
672 q += std::pow((A * (shape[i] - tau * shapeDer[i]) - (samp_no_ped[i])),
673 2);
674 }
675 } // end if useShapeDer
676 else {
677 // Q-factor w/o shape derivative
678 for (size_t i = 0; i < nOFC; ++i) {
679 q += std::pow((A * shape[i] - (samp_no_ped[i])), 2);
680 }
681 }
682
683 // Clamp before the cast, q can exceed the range of int
684 iquaShort = static_cast<uint16_t>(std::min(q, 65535.0));
685
686 tau -= ofcs->timeOffset(id, gain);
687 tau *= (Gaudi::Units::nanosecond /
688 Gaudi::Units::picosecond); // Convert time to ps
689 } // end if above cut
690
691 outputContainer->emplace_back(id, static_cast<int>(std::floor(E + 0.5)),
692 static_cast<int>(std::floor(tau + 0.5)),
693 iquaShort, prov, (CaloGain::CaloGain)gain);
694 }
695
696 SG::WriteHandle<LArRawChannelContainer> outputHandle(m_rawChannelKey, ctx);
697 ATH_CHECK(outputHandle.record(std::move(outputContainer)));
698
699 return StatusCode::SUCCESS;
700}
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_UNLIKELY(x)
virtual OFCRef_t OFC_b(const HWIdentifier &id, int gain, int tbin=0) const =0
virtual OFCRef_t OFC_a(const HWIdentifier &id, int gain, int tbin=0) const =0
access to OFCs by online ID, gain, and tbin (!=0 for testbeam)
virtual float timeOffset(const HWIdentifier &CellID, int gain) const =0
virtual float pedestal(const HWIdentifier &id, int gain) const =0
virtual ShapeRef_t Shape(const HWIdentifier &id, int gain, int tbin=0, int mode=0) const =0
virtual ShapeRef_t ShapeDer(const HWIdentifier &id, int gain, int tbin=0, int mode=0) const =0
const LArVectorProxy ADC2MEV(const HWIdentifier &id, int gain) const
Definition LArADC2MeV.h:32
float tQThr(const HWIdentifier chid) const
SG::WriteHandleKey< LArRawChannelContainer > m_rawChannelKey
Gaudi::Property< bool > m_useDBFortQ
SG::ReadCondHandleKey< ILArShape > m_shapeKey
Gaudi::Property< bool > m_absECutFortQ
SG::ReadCondHandleKey< LArADC2MeV > m_adc2MeVKey
std::vector< LayerParams > m_layerParams
Gaudi::Property< int > m_firstSample
Index of the digit sample the OFC window starts at, i.e.
double computeOFFC(const std::vector< short > &samples, int firstSample, const ILArOFC::OFCRef_t &ofc, const ILArShape::ShapeRef_t &shape, double pedestal, const LayerParams &par) const
SG::ReadCondHandleKey< ILArPedestal > m_pedestalKey
Gaudi::Property< float > m_eCutFortQ
SG::ReadHandleKey< LArDigitContainer > m_digitKey
StatusCode buildLayerMap(const EventContext &ctx) const
SG::ReadCondHandleKey< ILArOFC > m_ofcKey
Gaudi::Property< bool > m_useShapeDer
SG::ReadCondHandleKey< AthenaAttributeList > m_run2DSPThresholdsKey
SG::ReadCondHandleKey< LArDSPThresholdsComplete > m_run1DSPThresholdsKey
setScaleOne setStatusOne saturated
setWord1 uint16_t
#define unlikely(x)
Resolved parameters for one layer.

◆ extraDeps_update_handler()

void AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::extraDeps_update_handler ( Gaudi::Details::PropertyBase & ExtraDeps)
protectedinherited

Add StoreName to extra input/output deps as needed.

use the logic of the VarHandleKey to parse the DataObjID keys supplied via the ExtraInputs and ExtraOuputs Properties to add the StoreName if it's not explicitly given

◆ extraOutputDeps()

const DataObjIDColl & AthCommonAlgorithm< Gaudi::Algorithm >::extraOutputDeps ( ) const
overridevirtualinherited

Return the list of extra output dependencies.

This list is extended to include symlinks implied by inheritance relations.

Definition at line 89 of file AthCommonAlgorithm.cxx.

54{
55 // If we didn't find any symlinks to add, just return the collection
56 // from the base class. Otherwise, return the extended collection.
57 if (!m_extendedExtraObjects.empty()) {
59 }
61}
Common base class for algorithms.

◆ filterPassed()

virtual bool AthCommonAlgorithm< Gaudi::Algorithm >::filterPassed ( const EventContext & ctx) const
inlinevirtualinherited

Get filter decision:

Definition at line 93 of file AthCommonAlgorithm.h.

93 {
94 return execState( ctx ).filterPassed();
95 }
virtual bool filterPassed(const EventContext &ctx) const
Get filter decision:

◆ finalize()

StatusCode LArOFFCRawChannelBuilder::finalize ( )
override

Definition at line 442 of file LArOFFCRawChannelBuilder.cxx.

442 {
443 const unsigned long dropped = m_nDropped;
444 ATH_MSG_INFO("Subtracted " << m_nSubtracted.load() << " pulses, dropped "
445 << dropped << " for want of a free slot (NPulse = "
446 << m_nPulse.value() << ")");
447 if (dropped > 0)
448 ATH_MSG_WARNING(dropped
449 << " accepted pulses were not subtracted: their correction "
450 "is missing from the output. Raise NPulse to keep them");
451 return StatusCode::SUCCESS;
452}
Gaudi::Property< int > m_nPulse
Maximum number of pulse corrections in flight at once.

◆ initialize()

StatusCode LArOFFCRawChannelBuilder::initialize ( )
override

Definition at line 312 of file LArOFFCRawChannelBuilder.cxx.

312 {
313 ATH_CHECK(m_digitKey.initialize());
314 ATH_CHECK(m_rawChannelKey.initialize());
315 ATH_CHECK(m_pedestalKey.initialize());
316 ATH_CHECK(m_adc2MeVKey.initialize());
317 ATH_CHECK(m_ofcKey.initialize());
318 ATH_CHECK(m_shapeKey.initialize());
319 ATH_CHECK(m_cablingKey.initialize());
322
323 if (m_useDBFortQ) {
324 if (m_run1DSPThresholdsKey.empty() && m_run2DSPThresholdsKey.empty()) {
326 "useDB requested but neither Run1... nor Run2... initialized.");
327 return StatusCode::FAILURE;
328 }
329 }
330
331 ATH_CHECK(detStore()->retrieve(m_onlineId, "LArOnlineID"));
332 ATH_CHECK(detStore()->retrieve(m_caloId, "CaloCell_ID"));
333
334 // Resolve the per-layer table once. Every slot starts at the global values,
335 // so a job that sets no per-layer property behaves exactly as before.
336 m_layerParams.assign(s_nSlots + 1,
340 auto applyD = [&](const std::map<std::string, double>& m, const char* what,
341 double LayerParams::*field) -> StatusCode {
342 for (const auto& [key, val] : m) {
343 const size_t slot = slotOfKey(key);
344 if (slot >= s_nSlots) {
345 ATH_MSG_ERROR(what << " has key '" << key
346 << "' which is not <REGION>/<LAYER> with REGION in "
347 "EMB, EMEC-OW, EMEC-IW, HEC, FCAL and LAYER 0-3");
348 return StatusCode::FAILURE;
349 }
350 m_layerParams[slot].*field = val;
351 }
352 return StatusCode::SUCCESS;
353 };
354 ATH_CHECK(applyD(m_filterThresholdByLayer, "FilterThresholdByLayer",
356 ATH_CHECK(applyD(m_q3CutByLayer, "Q3CutByLayer", &LayerParams::q3Cut));
357 ATH_CHECK(applyD(m_q3OffsetByLayer, "Q3OffsetByLayer",
359 for (const auto& [key, val] : m_nPulseByLayer) {
360 const size_t slot = slotOfKey(key);
361 if (slot >= s_nSlots) {
362 ATH_MSG_ERROR("NPulseByLayer has unparseable key '" << key << "'");
363 return StatusCode::FAILURE;
364 }
365 if (val < 1) {
366 ATH_MSG_ERROR("NPulseByLayer['" << key << "'] is " << val
367 << ", must be >= 1");
368 return StatusCode::FAILURE;
369 }
370 m_layerParams[slot].nPulse = val;
371 }
372
373 // Disabling is an unreachable threshold, not a separate branch: no
374 // amplitude satisfies A > filterThreshold, so nothing is subtracted and
375 // the output is bit-identical to the plain OF (verified to 0 ADC).
376 if (!m_enabledLayers.empty()) {
377 std::vector<bool> on(s_nSlots + 1, false);
378 for (const std::string& key : m_enabledLayers.value()) {
379 const size_t slot = slotOfKey(key);
380 if (slot >= s_nSlots) {
381 ATH_MSG_ERROR("EnabledLayers contains unparseable key '" << key << "'");
382 return StatusCode::FAILURE;
383 }
384 on[slot] = true;
385 }
386 size_t nOff = 0;
387 for (size_t slot = 0; slot <= s_nSlots; ++slot) {
388 if (slot < s_nSlots && on[slot]) continue;
389 m_layerParams[slot].filterThreshold =
390 std::numeric_limits<double>::max();
391 ++nOff;
392 }
393 ATH_MSG_INFO("forward correction enabled in "
394 << m_enabledLayers.size() << " layers; " << nOff
395 << " slots left at the Optimal Filter");
396 }
397 for (size_t slot = 0; slot < s_nSlots; ++slot) {
398 const LayerParams& p = m_layerParams[slot];
399 if (p.filterThreshold == std::numeric_limits<double>::max()) continue;
400 ATH_MSG_DEBUG(keyOfSlot(slot) << ": Q3Cut=" << p.q3Cut << " Q3Offset="
401 << p.q3Offset << " FilterThreshold="
402 << p.filterThreshold << " NPulse="
403 << p.nPulse);
404 }
405
406 // The earliest testable candidate peak sits -q3Lags.front() samples into the
407 // digit, so anything less leaves no room to find a pulse before the in-time
408 // window and the forward correction can never contribute.
409 const int minFirstSample = -q3Lags.front() + 1;
410 if (m_firstSample < minFirstSample) {
411 ATH_MSG_ERROR("firstSample is "
412 << m_firstSample.value() << ", must be >= " << minFirstSample
413 << " for the OFFC to find any pulse before the in-time "
414 "window (set LAr.ROD.nPreceedingSamples accordingly)");
415 return StatusCode::FAILURE;
416 }
417
418 if (m_nPulse < 0) {
419 ATH_MSG_ERROR("NPulse is " << m_nPulse.value() << ", must be >= 0");
420 return StatusCode::FAILURE;
421 }
422 if (m_nPulse == 0) {
424 "NPulse is 0, no pulse will be subtracted and the OFFC reduces to "
425 "plain optimal filtering");
426 }
427
428 const std::string cutmsg = m_absECutFortQ.value() ? "fabs(E)" : "E";
429 if (m_useDBFortQ) {
430 ATH_MSG_INFO("Time and quality computed for "
431 << cutmsg << " above the threshold from COOL folder "
432 << m_run1DSPThresholdsKey.key() << " (run1) "
433 << m_run2DSPThresholdsKey.key() << " (run2)");
434 } else {
435 ATH_MSG_INFO("Time and quality computed for " << cutmsg << " above "
436 << m_eCutFortQ.value());
437 }
438
439 return StatusCode::SUCCESS;
440}
#define ATH_MSG_DEBUG(x,...)
const ServiceHandle< StoreGateSvc > & detStore() const
Gaudi::Property< std::map< std::string, int > > m_nPulseByLayer
static std::string keyOfSlot(size_t slot)
Gaudi::Property< double > m_belowThreshold
The OFFC extends optimal filtering by finding pulses in the preceding samples and subtracting their e...
Gaudi::Property< std::map< std::string, double > > m_q3OffsetByLayer
Gaudi::Property< double > m_filterThreshold
Minimum pile-up corrected amplitude required to accept a pulse peak.
static size_t slotOfKey(const std::string &key)
Parse "<REGION>/<LAYER>" into a slot. Returns s_nSlots if unparseable.
Gaudi::Property< double > m_Q3Offset
Absolute term of the Q3 cut, in ADC.
Gaudi::Property< std::map< std::string, double > > m_q3CutByLayer
Gaudi::Property< double > m_Q3cut
Quality cut for pulse acceptance.
Gaudi::Property< int > m_belowTillReset
Number of consecutive below-threshold samples after which the pending corrections are dropped,...
Gaudi::Property< std::vector< std::string > > m_enabledLayers
Layers the correction may run in; empty means all.
Gaudi::Property< std::map< std::string, double > > m_filterThresholdByLayer

◆ inputHandles()

virtual std::vector< Gaudi::DataHandle * > AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::inputHandles ( ) const
overridevirtualinherited

Return this algorithm's input handles.

We override this to include handle instances from key arrays if they have not yet been declared. See comments on updateVHKA.

◆ isClonable()

virtual bool AthCommonAlgorithm< Gaudi::Algorithm >::isClonable ( ) const
inlineoverridevirtualinherited

Specify if the algorithm is clonable.

Only relevant for non-reentrant algorithms. Actual number of clones needs to be set via the "Cardinality" property.

Reimplemented in AFP_DigiTop, AlgB, AlgT, BCM_Digitization, CscDigitBuilder, CscDigitToCscRDO, G4AtlasAlg, G4RunAlg, HGTD_Digitization, HiveAlgBase, InDet::GNNSeedingTrackMaker, InDet::SCT_Clusterization, InDet::SiSPGNNTrackMaker, InDet::SiSPSeededTrackFinder, InDet::SiTrackerSpacePointFinder, ISF::SimKernelMT, ITk::StripDigitization, ITkPixelCablingAlg, ITkStripCablingAlg, LArHitEMapMaker, LArTTL1Maker, LUCID_DigiTop, LVL1::L1TopoSimulation, MergeCalibHits, MergeGenericMuonSimHitColl, MergeHijingPars, MergeMcEventCollection, MergeTrackRecordCollection, MergeTruthJets, MergeTruthParticles, MuonDigitizer, PileUpMTAlg, PixelDigitization, RoIBResultToxAOD, SCT_ByteStreamErrorsTestAlg, SCT_CablingCondAlgFromCoraCool, SCT_CablingCondAlgFromText, SCT_ConditionsParameterTestAlg, SCT_ConditionsSummaryTestAlg, SCT_ConfigurationConditionsTestAlg, SCT_Digitization, SCT_FlaggedConditionTestAlg, SCT_LinkMaskingTestAlg, SCT_MajorityConditionsTestAlg, SCT_ModuleVetoTestAlg, SCT_MonitorConditionsTestAlg, SCT_PrepDataToxAOD, SCT_RawDataToxAOD, SCT_ReadCalibChipDataTestAlg, SCT_ReadCalibDataTestAlg, SCT_RODVetoTestAlg, SCT_SensorsTestAlg, SCT_SiliconConditionsTestAlg, SCT_StripVetoTestAlg, SCT_TdaqEnabledTestAlg, SCT_TestCablingAlg, SCTEventFlagWriter, SCTRawDataProvider, SCTSiLorentzAngleTestAlg, SCTSiPropertiesTestAlg, SGInputLoader, Simulation::BeamEffectsAlg, TileHitVecToCnt, TileMuonFitter, TilePulseForTileMuonReceiver, TileRawChannelMaker, TRTDigitization, and ZDC_DigiTop.

Definition at line 68 of file AthCommonAlgorithm.h.

68 {
69 return true;
70 }

◆ keyOfSlot()

std::string LArOFFCRawChannelBuilder::keyOfSlot ( size_t slot)
staticprivate

Definition at line 76 of file LArOFFCRawChannelBuilder.cxx.

76 {
77 if (slot >= s_nSlots) return "?";
78 return std::string(regionNames[slot / maxLayer]) + "/" +
79 std::to_string(slot % maxLayer);
80}

◆ msg()

MsgStream & AthCommonMsg< Gaudi::Algorithm >::msg ( ) const
inlineinherited

Definition at line 24 of file AthCommonMsg.h.

24 {
25 return this->msgStream();
26 }

◆ msgLvl()

bool AthCommonMsg< Gaudi::Algorithm >::msgLvl ( const MSG::Level lvl) const
inlineinherited

Definition at line 30 of file AthCommonMsg.h.

30 {
31 return this->msgLevel(lvl);
32 }

◆ outputHandles()

virtual std::vector< Gaudi::DataHandle * > AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::outputHandles ( ) const
overridevirtualinherited

Return this algorithm's output handles.

We override this to include handle instances from key arrays if they have not yet been declared. See comments on updateVHKA.

◆ pulseResponse()

std::vector< double > LArOFFCRawChannelBuilder::pulseResponse ( const ILArShape::ShapeRef_t & shape,
const ILArOFC::OFCRef_t & ofc ) const
private

Filter output for a unit-amplitude pulse, tabulated over every offset of the shape against the OFC window at which the two overlap.

Entry k is the response for an offset of k-(ofc.size()-1) samples.

Definition at line 126 of file LArOFFCRawChannelBuilder.cxx.

127 {
128 // Filter output for a unit-amplitude pulse: same correlation as the
129 // filtering loop in computeOFFC, samples replaced by the shape. Writing it
130 // as a convolution.
131
132 const int shapeSize = shape.size();
133 const int ofcSize = ofc.size();
134
135 auto shapeVal = [&](int k) {
136 return (k >= 0 && k < shapeSize) ? shape[k] : 0.0f;
137 };
138
139 // response[k] is the filter output for a pulse offset by k-(ofcSize-1)
140 // samples from the OFC window, tabulated over the whole range where the two
141 // overlap. Where the in-time position falls inside it is up to the OFCs.
142 std::vector<double> response(std::max(0, shapeSize + ofcSize - 1), 0.0);
143
144 for (int k = 0; k < static_cast<int>(response.size()); ++k) {
145 const int offset = k - (ofcSize - 1);
146 for (int j = 0; j < ofcSize; ++j)
147 response[k] += shapeVal(offset + j) * ofc[j];
148 }
149
150 return response;
151}

◆ renounce()

std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::renounce ( T & h)
inlineprotectedinherited

Definition at line 380 of file AthCommonDataStore.h.

381 {
382 h.renounce();
384 }
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce(T &h)

◆ renounceArray()

void AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::renounceArray ( SG::VarHandleKeyArray & handlesArray)
inlineprotectedinherited

remove all handles from I/O resolution

Definition at line 364 of file AthCommonDataStore.h.

364 {
366 }

◆ setFilterPassed()

virtual void AthCommonAlgorithm< Gaudi::Algorithm >::setFilterPassed ( bool state,
const EventContext & ctx ) const
inlinevirtualinherited

Set filter decision:

Reimplemented in AthFilterAlgorithm.

Definition at line 99 of file AthCommonAlgorithm.h.

99 {
101 }
virtual void setFilterPassed(bool state, const EventContext &ctx) const
Set filter decision:

◆ slotOf()

size_t LArOFFCRawChannelBuilder::slotOf ( int region,
int layer )
staticprivate

Slot for a region code (0=EMB..4=FCAL) and sampling/module; s_nSlots if out of range.

Definition at line 54 of file LArOFFCRawChannelBuilder.cxx.

54 {
55 if (region < 0 || region >= static_cast<int>(regionNames.size()))
56 return s_nSlots;
57 if (layer < 0 || layer >= maxLayer) return s_nSlots;
58 return static_cast<size_t>(region) * maxLayer + static_cast<size_t>(layer);
59}

◆ slotOfKey()

size_t LArOFFCRawChannelBuilder::slotOfKey ( const std::string & key)
staticprivate

Parse "<REGION>/<LAYER>" into a slot. Returns s_nSlots if unparseable.

Definition at line 61 of file LArOFFCRawChannelBuilder.cxx.

61 {
62 const auto slash = key.rfind('/');
63 if (slash == std::string::npos || slash + 1 >= key.size()) return s_nSlots;
64 const std::string region = key.substr(0, slash);
65 int layer = -1;
66 try {
67 layer = std::stoi(key.substr(slash + 1));
68 } catch (...) {
69 return s_nSlots;
70 }
71 for (size_t r = 0; r < regionNames.size(); ++r)
72 if (region == regionNames[r]) return slotOf(static_cast<int>(r), layer);
73 return s_nSlots;
74}

◆ sysExecute()

StatusCode AthCommonAlgorithm< Gaudi::Algorithm >::sysExecute ( const EventContext & ctx)
overridevirtualinherited

Execute an algorithm.

We override this in order to work around an issue with the Algorithm base class storing the event context in a member variable that can cause crashes in MT jobs.

Reimplemented in AthAnalysisAlgorithm.

Definition at line 80 of file AthCommonAlgorithm.cxx.

41{
42 return BaseAlg::sysExecute (ctx);
43}

◆ sysInitialize()

StatusCode AthCommonAlgorithm< Gaudi::Algorithm >::sysInitialize ( )
overridevirtualinherited

Override sysInitialize.

Override sysInitialize from the base class.

Loop through all output handles, and if they're WriteCondHandles, automatically register them and this Algorithm with the CondSvc

Scan through all outputHandles, and if they're WriteCondHandles, register them with the CondSvc

Reimplemented from AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >.

Reimplemented in AthAnalysisAlgorithm, AthFilterAlgorithm, AthHistogramAlgorithm, HypoBase, InputMakerBase, and PyAthena::Alg.

Definition at line 60 of file AthCommonAlgorithm.cxx.

71 {
73
74 if (sc.isFailure()) {
75 return sc;
76 }
77
78 ServiceHandle<ICondSvc> cs("CondSvc",name());
79 for (auto h : outputHandles()) {
80 if (h->isCondition() && h->mode() == Gaudi::DataHandle::Writer) {
81 // do this inside the loop so we don't create the CondSvc until needed
82 if ( cs.retrieve().isFailure() ) {
83 ATH_MSG_WARNING("no CondSvc found: won't autoreg WriteCondHandles");
85 }
86 if (cs->regHandle(this,*h).isFailure()) {
88 ATH_MSG_ERROR("unable to register WriteCondHandle " << h->fullKey()
89 << " with CondSvc");
90 }
91 }
92 }
93 return sc;
94}
virtual StatusCode sysInitialize() override
virtual std::vector< Gaudi::DataHandle * > outputHandles() const override

◆ sysStart()

virtual StatusCode AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::sysStart ( )
overridevirtualinherited

Handle START transition.

We override this in order to make sure that conditions handle keys can cache a pointer to the conditions container.

◆ updateVHKA()

void AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::updateVHKA ( Gaudi::Details::PropertyBase & )
inlineinherited

Definition at line 308 of file AthCommonDataStore.h.

308 {
309 // debug() << "updateVHKA for property " << p.name() << " " << p.toString()
310 // << " size: " << m_vhka.size() << endmsg;
311 for (auto &a : m_vhka) {
313 for (auto k : keys) {
314 k->setOwner(this);
315 }
316 }
317 }

Member Data Documentation

◆ ATLAS_THREAD_SAFE [1/3]

StatusCode m_slotStatus LArOFFCRawChannelBuilder::ATLAS_THREAD_SAFE {StatusCode::SUCCESS}
mutableprivate

Definition at line 202 of file LArOFFCRawChannelBuilder.h.

202{StatusCode::SUCCESS};

◆ ATLAS_THREAD_SAFE [2/3]

std::once_flag m_slotOnce LArOFFCRawChannelBuilder::ATLAS_THREAD_SAFE
mutableprivate

Definition at line 201 of file LArOFFCRawChannelBuilder.h.

◆ ATLAS_THREAD_SAFE [3/3]

std::vector<uint8_t> m_slotByHash LArOFFCRawChannelBuilder::ATLAS_THREAD_SAFE
mutableprivate

online hash -> slot, built on the first event: it needs the cabling, which is conditions data with an IOV.

Definition at line 200 of file LArOFFCRawChannelBuilder.h.

◆ m_absECutFortQ

Gaudi::Property<bool> LArOFFCRawChannelBuilder::m_absECutFortQ
private
Initial value:
{
this, "absECut", true, "Cut on fabs(E) for Q and t computation"}

Definition at line 79 of file LArOFFCRawChannelBuilder.h.

79 {
80 this, "absECut", true, "Cut on fabs(E) for Q and t computation"};

◆ m_adc2MeVKey

SG::ReadCondHandleKey<LArADC2MeV> LArOFFCRawChannelBuilder::m_adc2MeVKey
private
Initial value:
{
this, "ADC2MeVKey", "LArADC2MeV", "SG Key of ADC2MeV conditions object"}

Definition at line 58 of file LArOFFCRawChannelBuilder.h.

58 {
59 this, "ADC2MeVKey", "LArADC2MeV", "SG Key of ADC2MeV conditions object"};

◆ m_belowThreshold

Gaudi::Property<double> LArOFFCRawChannelBuilder::m_belowThreshold
private
Initial value:
{
this, "BelowThreshold", 0,
"ADC threshold below which samples are treated as noise"}

The OFFC extends optimal filtering by finding pulses in the preceding samples and subtracting their expected filter response from the later ones.

At every position of the pedestal-subtracted digit it applies:

  • the optimal filter,
  • a local-maximum pulse search on the corrected filter output,
  • a shape-consistency (Q3) cut against that same response,
  • and a forward subtraction of the response of each accepted pulse. ADC threshold below which samples are considered noise. Consecutive samples below this threshold increment a counter used to decide when to reset the forward-subtraction cache.

Definition at line 108 of file LArOFFCRawChannelBuilder.h.

108 {
109 this, "BelowThreshold", 0,
110 "ADC threshold below which samples are treated as noise"};

◆ m_belowTillReset

Gaudi::Property<int> LArOFFCRawChannelBuilder::m_belowTillReset
private
Initial value:
{
this, "BelowTillReset", 0,
"Number of consecutive noise samples before cache reset (<=0 disables)"}

Number of consecutive below-threshold samples after which the pending corrections are dropped, so that stale ones cannot persist through a quiet region.

Either this or BelowThreshold at zero disables the reset.

Definition at line 115 of file LArOFFCRawChannelBuilder.h.

115 {
116 this, "BelowTillReset", 0,
117 "Number of consecutive noise samples before cache reset (<=0 disables)"};

◆ m_cablingKey

SG::ReadCondHandleKey<LArOnOffIdMapping> LArOFFCRawChannelBuilder::m_cablingKey
private
Initial value:
{
this, "CablingKey", "LArOnOffIdMap",
"SG Key of LArOnOffIdMapping object"}

Definition at line 65 of file LArOFFCRawChannelBuilder.h.

65 {
66 this, "CablingKey", "LArOnOffIdMap",
67 "SG Key of LArOnOffIdMapping object"};

◆ m_caloId

const CaloCell_ID* LArOFFCRawChannelBuilder::m_caloId = nullptr
private

Definition at line 207 of file LArOFFCRawChannelBuilder.h.

◆ m_detStore

StoreGateSvc_t AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::m_detStore
privateinherited

Pointer to StoreGate (detector store by default).

Definition at line 393 of file AthCommonDataStore.h.

◆ m_digitKey

SG::ReadHandleKey<LArDigitContainer> LArOFFCRawChannelBuilder::m_digitKey
private
Initial value:
{
this, "LArDigitKey", "FREE", "SG Key of LArDigitContainer"}

Definition at line 46 of file LArOFFCRawChannelBuilder.h.

46 {
47 this, "LArDigitKey", "FREE", "SG Key of LArDigitContainer"};

◆ m_eCutFortQ

Gaudi::Property<float> LArOFFCRawChannelBuilder::m_eCutFortQ
private
Initial value:
{this, "ECutFortQ", 256.0,
"Time and Quality will be computed only "
"for channels with E above this value"}

Definition at line 76 of file LArOFFCRawChannelBuilder.h.

76 {this, "ECutFortQ", 256.0,
77 "Time and Quality will be computed only "
78 "for channels with E above this value"};

◆ m_enabledLayers

Gaudi::Property<std::vector<std::string> > LArOFFCRawChannelBuilder::m_enabledLayers
private
Initial value:
{
this, "EnabledLayers", {},
"Layers where the correction may fire; empty means all"}

Layers the correction may run in; empty means all.

A layer left out gets an unreachable FilterThreshold, so nothing is subtracted and the output is bit-identical to the plain OF – no separate code path.

Definition at line 172 of file LArOFFCRawChannelBuilder.h.

172 {
173 this, "EnabledLayers", {},
174 "Layers where the correction may fire; empty means all"};

◆ m_evtStore

StoreGateSvc_t AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::m_evtStore
privateinherited

Pointer to StoreGate (event store by default).

Definition at line 390 of file AthCommonDataStore.h.

◆ m_extendedExtraObjects

DataObjIDColl AthCommonAlgorithm< Gaudi::Algorithm >::m_extendedExtraObjects
privateinherited

Extra output dependency collection, extended by AthAlgorithmDHUpdate to add symlinks.

Empty if no symlinks were found.

Definition at line 108 of file AthCommonAlgorithm.h.

◆ m_filterThreshold

Gaudi::Property<double> LArOFFCRawChannelBuilder::m_filterThreshold
private
Initial value:
{
this, "FilterThreshold", 0,
"Minimum corrected amplitude for pulse finding"}

Minimum pile-up corrected amplitude required to accept a pulse peak.

This suppresses spurious pulse finding due to noise fluctuations.

Definition at line 145 of file LArOFFCRawChannelBuilder.h.

145 {
146 this, "FilterThreshold", 0,
147 "Minimum corrected amplitude for pulse finding"};

◆ m_filterThresholdByLayer

Gaudi::Property<std::map<std::string, double> > LArOFFCRawChannelBuilder::m_filterThresholdByLayer
private
Initial value:
{
this, "FilterThresholdByLayer", {},
"Per-layer FilterThreshold, keyed <REGION>/<LAYER>; unlisted layers "
"fall back to FilterThreshold"}

Definition at line 155 of file LArOFFCRawChannelBuilder.h.

155 {
156 this, "FilterThresholdByLayer", {},
157 "Per-layer FilterThreshold, keyed <REGION>/<LAYER>; unlisted layers "
158 "fall back to FilterThreshold"};

◆ m_firstSample

Gaudi::Property<int> LArOFFCRawChannelBuilder::m_firstSample
private
Initial value:
{
this, "firstSample", 0,
"Index of the digit sample the OFC window starts at"}

Index of the digit sample the OFC window starts at, i.e.

the amplitude is that of sum_j (samples[firstSample+j]-pedestal)*OFC_a[j]. Not an offset into the reference shape: the digitisation writes shape index k-nPreceedingSamples into digit sample k.

Definition at line 90 of file LArOFFCRawChannelBuilder.h.

90 {
91 this, "firstSample", 0,
92 "Index of the digit sample the OFC window starts at"};

◆ m_layerParams

std::vector<LayerParams> LArOFFCRawChannelBuilder::m_layerParams
private

Definition at line 189 of file LArOFFCRawChannelBuilder.h.

◆ m_nDropped

std::atomic<unsigned long> LArOFFCRawChannelBuilder::m_nDropped {0}
mutableprivate

Definition at line 212 of file LArOFFCRawChannelBuilder.h.

212{0};

◆ m_nPulse

Gaudi::Property<int> LArOFFCRawChannelBuilder::m_nPulse
private
Initial value:
{
this, "NPulse", 0, "Maximum number of pulse corrections in flight"}

Maximum number of pulse corrections in flight at once.

A slot is held until the pulse response has been fully subtracted, which for a typical shape outlasts the digit: in practice this caps the pulses per digit.

Definition at line 122 of file LArOFFCRawChannelBuilder.h.

122 {
123 this, "NPulse", 0, "Maximum number of pulse corrections in flight"};

◆ m_nPulseByLayer

Gaudi::Property<std::map<std::string, int> > LArOFFCRawChannelBuilder::m_nPulseByLayer
private
Initial value:
{
this, "NPulseByLayer", {},
"Per-layer NPulse; unlisted layers fall back to NPulse"}

Definition at line 165 of file LArOFFCRawChannelBuilder.h.

165 {
166 this, "NPulseByLayer", {},
167 "Per-layer NPulse; unlisted layers fall back to NPulse"};

◆ m_nSubtracted

std::atomic<unsigned long> LArOFFCRawChannelBuilder::m_nSubtracted {0}
mutableprivate

Accepted pulses, and those NPulse left no room to subtract.

Only touched on the rare accepted-pulse branch, summarised in finalize().

Definition at line 211 of file LArOFFCRawChannelBuilder.h.

211{0};

◆ m_ofcKey

SG::ReadCondHandleKey<ILArOFC> LArOFFCRawChannelBuilder::m_ofcKey
private
Initial value:
{this, "OFCKey", "LArOFC",
"SG Key of OFC conditions object"}

Definition at line 60 of file LArOFFCRawChannelBuilder.h.

60 {this, "OFCKey", "LArOFC",
61 "SG Key of OFC conditions object"};

◆ m_onlineId

const LArOnlineID* LArOFFCRawChannelBuilder::m_onlineId = nullptr
private

Definition at line 206 of file LArOFFCRawChannelBuilder.h.

◆ m_pedestalKey

SG::ReadCondHandleKey<ILArPedestal> LArOFFCRawChannelBuilder::m_pedestalKey
private
Initial value:
{
this, "PedestalKey", "LArPedestal",
"SG Key of Pedestal conditions object"}

Definition at line 55 of file LArOFFCRawChannelBuilder.h.

55 {
56 this, "PedestalKey", "LArPedestal",
57 "SG Key of Pedestal conditions object"};

◆ m_Q3cut

Gaudi::Property<double> LArOFFCRawChannelBuilder::m_Q3cut
private
Initial value:
{
this, "Q3Cut", 0.1,
"Shape-consistency cut for pulse acceptance, on Q3/A"}

Quality cut for pulse acceptance.

Q3 sums the absolute residuals of the corrected filter output against the expected response at lags -2, -1 and +1 from the candidate peak, and is zero for a clean pulse of any amplitude. The cut is applied to Q3/A, so it is a fractional mismatch and does not have to be rescaled with the pulse size. Pulses below it are accepted and subtracted.

Definition at line 131 of file LArOFFCRawChannelBuilder.h.

131 {
132 this, "Q3Cut", 0.1,
133 "Shape-consistency cut for pulse acceptance, on Q3/A"};

◆ m_q3CutByLayer

Gaudi::Property<std::map<std::string, double> > LArOFFCRawChannelBuilder::m_q3CutByLayer
private
Initial value:
{
this, "Q3CutByLayer", {},
"Per-layer Q3Cut; unlisted layers fall back to Q3Cut"}

Definition at line 159 of file LArOFFCRawChannelBuilder.h.

159 {
160 this, "Q3CutByLayer", {},
161 "Per-layer Q3Cut; unlisted layers fall back to Q3Cut"};

◆ m_Q3Offset

Gaudi::Property<double> LArOFFCRawChannelBuilder::m_Q3Offset
private
Initial value:
{
this, "Q3Offset", 2.0,
"Absolute term of the Q3 cut in ADC, covering the noise floor"}

Absolute term of the Q3 cut, in ADC.

Q3 has a noise floor of a few times the sample noise whatever the amplitude, so a purely relative cut would reject small pulses on noise alone. Set this comparable to FilterThreshold, the smallest amplitude worth looking at.

Definition at line 139 of file LArOFFCRawChannelBuilder.h.

139 {
140 this, "Q3Offset", 2.0,
141 "Absolute term of the Q3 cut in ADC, covering the noise floor"};

◆ m_q3OffsetByLayer

Gaudi::Property<std::map<std::string, double> > LArOFFCRawChannelBuilder::m_q3OffsetByLayer
private
Initial value:
{
this, "Q3OffsetByLayer", {},
"Per-layer Q3Offset; unlisted layers fall back to Q3Offset"}

Definition at line 162 of file LArOFFCRawChannelBuilder.h.

162 {
163 this, "Q3OffsetByLayer", {},
164 "Per-layer Q3Offset; unlisted layers fall back to Q3Offset"};

◆ m_rawChannelKey

SG::WriteHandleKey<LArRawChannelContainer> LArOFFCRawChannelBuilder::m_rawChannelKey
private
Initial value:
{
this, "LArRawChannelKey", "LArRawChannels",
"SG key of the output LArRawChannelContainer"}

Definition at line 50 of file LArOFFCRawChannelBuilder.h.

50 {
51 this, "LArRawChannelKey", "LArRawChannels",
52 "SG key of the output LArRawChannelContainer"};

◆ m_run1DSPThresholdsKey

SG::ReadCondHandleKey<LArDSPThresholdsComplete> LArOFFCRawChannelBuilder::m_run1DSPThresholdsKey
private
Initial value:
{
this, "Run1DSPThresholdsKey", "",
"SG Key for thresholds to compute time and quality, run 1"}

Definition at line 68 of file LArOFFCRawChannelBuilder.h.

68 {
69 this, "Run1DSPThresholdsKey", "",
70 "SG Key for thresholds to compute time and quality, run 1"};

◆ m_run2DSPThresholdsKey

SG::ReadCondHandleKey<AthenaAttributeList> LArOFFCRawChannelBuilder::m_run2DSPThresholdsKey
private
Initial value:
{
this, "Run2DSPThresholdsKey", "",
"SG Key for thresholds to compute time and quality, run 2"}

Definition at line 71 of file LArOFFCRawChannelBuilder.h.

71 {
72 this, "Run2DSPThresholdsKey", "",
73 "SG Key for thresholds to compute time and quality, run 2"};

◆ m_shapeKey

SG::ReadCondHandleKey<ILArShape> LArOFFCRawChannelBuilder::m_shapeKey
private
Initial value:
{
this, "ShapeKey", "LArShape", "SG Key of Shape conditions object"}

Definition at line 62 of file LArOFFCRawChannelBuilder.h.

62 {
63 this, "ShapeKey", "LArShape", "SG Key of Shape conditions object"};

◆ m_useDBFortQ

Gaudi::Property<bool> LArOFFCRawChannelBuilder::m_useDBFortQ
private
Initial value:
{this, "useDB", true,
"Use DB for cut on t,Q"}

Definition at line 84 of file LArOFFCRawChannelBuilder.h.

84 {this, "useDB", true,
85 "Use DB for cut on t,Q"};

◆ m_useShapeDer

Gaudi::Property<bool> LArOFFCRawChannelBuilder::m_useShapeDer
private
Initial value:
{
this, "useShapeDer", true,
"Use shape derivative in Q-factor computation"}

Definition at line 81 of file LArOFFCRawChannelBuilder.h.

81 {
82 this, "useShapeDer", true,
83 "Use shape derivative in Q-factor computation"};

◆ m_varHandleArraysDeclared

bool AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::m_varHandleArraysDeclared
privateinherited

Definition at line 399 of file AthCommonDataStore.h.

◆ m_vhka

std::vector<SG::VarHandleKeyArray*> AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::m_vhka
privateinherited

Definition at line 398 of file AthCommonDataStore.h.

◆ s_nSlots

size_t LArOFFCRawChannelBuilder::s_nSlots = 20
staticconstexprprivate

Five regions x at most four samplings.

m_layerParams holds s_nSlots+1: the last entry is the global fallback for channels outside those.

Definition at line 188 of file LArOFFCRawChannelBuilder.h.


The documentation for this class was generated from the following files: