ATLAS Offline Software
Loading...
Searching...
No Matches
LArRampBuilder.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#include "LArRampBuilder.h"
8
12
13#include <Eigen/Dense>
14
15#include <fstream>
16
18
20{
21 StatusCode sc;
22 if ( m_isSC ) {
23 ATH_MSG_DEBUG("==== LArRampBuilder - looking at SuperCells ====");
24 const LArOnline_SuperCellID* ll;
25 sc = detStore()->retrieve(ll, "LArOnline_SuperCellID");
26 if (sc.isFailure()) {
27 msg(MSG::ERROR) << "Could not get LArOnlineID helper !" << endmsg;
28 return StatusCode::FAILURE;
29 }
30 else {
31 m_onlineHelper = static_cast<const LArOnlineID_Base*>(ll);
32 ATH_MSG_DEBUG("Found the LArOnlineID helper");
33 }
34
35 } else { // m_isSC
36 const LArOnlineID* ll;
37 sc = detStore()->retrieve(ll, "LArOnlineID");
38 if (sc.isFailure()) {
39 msg(MSG::ERROR) << "Could not get LArOnlineID helper !" << endmsg;
40 return StatusCode::FAILURE;
41 }
42 else {
43 m_onlineHelper = static_cast<const LArOnlineID_Base*>(ll);
44 ATH_MSG_DEBUG(" Found the LArOnlineID helper. ");
45 }
46
47 }
48
49 ATH_CHECK( m_cablingKey.initialize() );
50 ATH_CHECK( m_cablingKeySC.initialize(m_isSC) );
51
53 if(m_isSC) m_bcMask.setSC();
54 ATH_CHECK(m_bcMask.buildBitMask(m_problemsToMask,msg()));
55
56 //Intermediate ramp object (DAC/ADC pairs)
57 m_ramps=std::make_unique<LArConditionsContainer<ACCRAMP> >();
58 ATH_CHECK(m_ramps->setGroupingType(m_groupingType,msg()));
59 ATH_CHECK(m_ramps->initialize());
60
63
64 unsigned int online_id_max = m_onlineHelper->channelHashMax() ;
65 m_thePedestal.resize(online_id_max,-1);
66
67 return StatusCode::SUCCESS;
68}
69
70
72
73 // choose reconstructiom mode
74 if ( m_recoTypeProp == std::string("Parabola") ) {
76 StatusCode sc=m_peakParabolaTool.retrieve();
77 if (sc!=StatusCode::SUCCESS) {
78 ATH_MSG_ERROR( "Can't get LArParabolaPeakRecoTool" );
79 return;
80 }
81 ATH_MSG_DEBUG("LArParabolaPeakRecoTool retrieved with success!");
82
83 if(m_correctBias){
84 // if using parabola, get offlineID helper to obtain the layer (needed for correction)
85 const CaloCell_ID* idHelper = nullptr;
86 if ( detStore()->retrieve (idHelper, "CaloCell_ID").isSuccess() ) {
87 m_emId = idHelper->em_idHelper();
88 }
89 if (!m_emId) {
90 ATH_MSG_ERROR( "Could not access lar EM ID helper" );
91 return ;
92 }
93
94 }
95 m_peakShapeTool.disable();
96 m_peakOFTool.disable();
97 // Shape reconstruction
98 } else if (m_recoTypeProp == std::string("Shape") ) {
100 ATH_MSG_INFO( "ShapePeakReco mode is ON ! ");
101 if (m_peakShapeTool.retrieve().isFailure()) {
102 ATH_MSG_ERROR( "Can't get LArShapePeakRecoTool");
103 return;
104 }
105 ATH_MSG_DEBUG("LArShapePeakRecoTool retrieved with success!");
106 m_peakParabolaTool.disable();
107 m_peakOFTool.disable();
108 // OFC recontruction
109 } else if ( m_recoTypeProp == std::string("OF") ) {
111 if (m_peakOFTool.retrieve().isFailure()) {
112 ATH_MSG_ERROR( "Can't get LArOFPeakRecoTool");
113 return;
114 }
115 ATH_MSG_DEBUG("LArOFPeakRecoTool retrieved with success!");
116 m_peakShapeTool.disable();
117 m_peakParabolaTool.disable();
118 }
119}
120
121// ********************** EXECUTE ****************************
123{
124
125 StatusCode sc;
126 if ( m_event_counter < 100 || m_event_counter%100==0 )
127 ATH_MSG_INFO( "Processing event " << m_event_counter);
129
130 if (m_keylist.size()==0) {
131 ATH_MSG_ERROR( "Key list is empty! No containers to process!");
132 return StatusCode::FAILURE;
133 }
134
135 const LArFebErrorSummary* febErrSum=nullptr;
136 if (evtStore()->contains<LArFebErrorSummary>("LArFebErrorSummary")) {
137 sc=evtStore()->retrieve(febErrSum);
138 if (sc.isFailure()) {
139 ATH_MSG_ERROR( "Failed to retrieve FebErrorSummary object!");
140 return sc;
141 }
142 }
143 else
144 if (m_event_counter==1)
145 ATH_MSG_WARNING("No FebErrorSummaryObject found! Feb errors not checked!");
146
147 const LArOnOffIdMapping* cabling(nullptr);
148 if( m_isSC ){
150 cabling = {*cablingHdl};
151 if(!cabling) {
152 ATH_MSG_ERROR("Do not have mapping object " << m_cablingKeySC.key());
153 return StatusCode::FAILURE;
154 }
155 }else{
157 cabling = {*cablingHdl};
158 if(!cabling) {
159 ATH_MSG_ERROR("Do not have mapping object " << m_cablingKey.key());
160 return StatusCode::FAILURE;
161 }
162 }
163
164
165 std::vector<std::string>::const_iterator key_it=m_keylist.begin();
166 std::vector<std::string>::const_iterator key_it_e=m_keylist.end();
167
168 const LArAccumulatedCalibDigitContainer* larAccumulatedCalibDigitContainer = nullptr;
169
170
171 // if using Shape Reco method, retrieve caliWaveContainer (only once !)
172 // FT remove the bitwise &&->&
173 if ( m_recoType == SHAPE && m_ipassShape==0) {
174
175 m_ipassShape = 1;
176
177 // keep only 8 samples of wave - dont need all samples for pseudo-OF reco
178 std::vector<double> tempWave;
179 int NSamplesKeep = 8;
180 tempWave.resize(24*NSamplesKeep);
181
182 m_CaliWaves.resize(3);
183 m_CaliDACs.resize(3);
184 m_IndexDAC0.resize(3);
185 m_IndexHighestDAC.resize(3);
186
187 // retrieve cali wave container
188
189 const LArCaliWaveContainer* caliWaveContainer = nullptr;
190 ATH_MSG_WARNING("Will retrieve LArCaliWaveContainer ");
191 sc= detStore()->retrieve(caliWaveContainer,"CaliWave");
192 if (sc.isFailure()) {
193 ATH_MSG_WARNING("Cannot read LArCaliWaveContainer from StoreGate for key 'CaliWave' ! ");
194 return StatusCode::FAILURE;
195 }
196 ATH_MSG_DEBUG("Succefully retrieved LArCaliWaveContainer from StoreGate!");
197 for (;key_it!=key_it_e;++key_it) { //Loop over all containers that are to be processed (e.g. different gains)
198
199 // first, set reference DAC (dirty hardcoding for now...)
201 if(*key_it == "HIGH") {
202 gainref=CaloGain::LARHIGHGAIN;
203 }else if(*key_it == "MEDIUM") {
205 }else if(*key_it == "LOW") {
206 gainref=CaloGain::LARLOWGAIN;
207 }
208
209 m_CaliWaves[gainref].resize(m_onlineHelper->channelHashMax());
210 m_CaliDACs[gainref].resize(m_onlineHelper->channelHashMax());
211 m_IndexDAC0[gainref].resize(m_onlineHelper->channelHashMax());
212 m_IndexHighestDAC[gainref].resize(m_onlineHelper->channelHashMax());
213
214 // Set gain from key value
215 int gain = CaloGain::LARHIGHGAIN;
216 if ((*key_it) == "MEDIUM") gain = CaloGain::LARMEDIUMGAIN;
217 else if ((*key_it) == "LOW") gain = CaloGain::LARLOWGAIN;
218
219 // extract from all the waves the ones we are interested in (a given DAC value)
220 // and order them by hash ID in a vector
222 const_iterator itVec = caliWaveContainer->begin(gain);
223 const_iterator itVec_e = caliWaveContainer->end(gain);
224
225 for (; itVec != itVec_e; ++itVec) {
226
227 for (const LArCaliWave& larCaliWave : *itVec) { //Loop over all cells
228 unsigned int DAC = larCaliWave.getDAC();
229 IdentifierHash chidwave_hash = m_onlineHelper->channel_Hash(itVec.channelId());
230
231 bool IsBad = false;
232 for(int i=0;i<24*NSamplesKeep;i++){
233 tempWave[i] = larCaliWave.getSample(i);
234 if(tempWave[i]<-500) { // check that this wave is not corrupted
235 IsBad = true;
236 break;
237 }
238 }
239
240 if(IsBad) continue; // if corrupted wave, skip it;
241
242 m_CaliWaves[gainref][chidwave_hash].push_back(tempWave);
243 m_CaliDACs[gainref][chidwave_hash].push_back(DAC);
244
245 // remember index of highest DAC value for this cell (i.e. non-saturating)
246 if(DAC > m_CaliDACs[gainref][chidwave_hash][m_IndexHighestDAC[gainref][chidwave_hash]]) m_IndexHighestDAC[gainref][chidwave_hash]=m_CaliDACs[gainref][chidwave_hash].size()-1;
247
248 // remember which index corresponds to DAC0
249 if(m_dac0sub && DAC == m_DAC0) {
250 m_IndexDAC0[gainref][chidwave_hash] = m_CaliDACs[gainref][chidwave_hash].size()-1;
251 ATH_MSG_DEBUG("Cell " << chidwave_hash << ": DAC0 is at index = " << m_IndexDAC0[gainref][chidwave_hash]);
252 }
253 } // loop over dac values
254 } // loop over cells
255 } // Loop over gains
256
257 sc= detStore()->remove(caliWaveContainer);
258 if (sc.isFailure()) {
259 ATH_MSG_WARNING("Cannot remove LArCaliWaveContainer from StoreGate ! ");
260 return StatusCode::FAILURE;
261 }
262 ATH_MSG_DEBUG("Successfully removed LArCaliWaveContainer from StoreGate ");
263
264 } // m_ipassShape
265
266
267
268
269 // now start to deal with digits
270 int foundkey = 0;
271 for (;key_it!=key_it_e;++key_it) { //Loop over all containers that are to be processed (e.g. different gains)
272
273 sc= evtStore()->retrieve(larAccumulatedCalibDigitContainer,*key_it);
274 if (sc.isFailure()) {
275 ATH_MSG_WARNING("Cannot read LArAccumulatedCalibDigitContainer from StoreGate! key=" << *key_it);
276 if ( (std::next(key_it) == key_it_e) && foundkey==0 ){
277 ATH_MSG_ERROR("None of the provided LArAccumulatedDigitContainer keys could be read");
278 return StatusCode::FAILURE;
279 }else{
280 continue;
281 }
282 }
283 ++foundkey;
284 HWIdentifier lastFailedFEB(0);
285
286 if(larAccumulatedCalibDigitContainer->empty()) {
287 ATH_MSG_DEBUG("LArAccumulatedCalibDigitContainer with key=" << *key_it << " is empty ");
288 } else {
289 ATH_MSG_DEBUG("LArAccumulatedCalibDigitContainer with key=" << *key_it << " has size " << larAccumulatedCalibDigitContainer->size());
290 }
291
292 for (const LArAccumulatedCalibDigit* digit : *larAccumulatedCalibDigitContainer) { //Loop over all cells
293
294 if (!(digit->isPulsed())){ //Check if cell is pulsed
295 continue; //Cell not pulsed -> ignore
296 }
297
298 HWIdentifier chid=digit->hardwareID();
299 HWIdentifier febid=m_onlineHelper->feb_Id(chid);
300 if (febErrSum) {
301 const uint16_t febErrs=febErrSum->feb_error(febid);
302 if (febErrs & m_fatalFebErrorPattern) {
303 if (febid!=lastFailedFEB) {
304 lastFailedFEB=febid;
305 ATH_MSG_ERROR( "Event " << m_event_counter << " Feb " << m_onlineHelper->channel_name(febid)
306 << " reports error(s):" << febErrSum->error_to_string(febErrs) << ". Data ignored.");
307 }
308 continue;
309 }
310 }
311
312
313 if (m_delay==-1) { //First (pulsed) cell to be processed:
314 m_delay=digit->delay();
315 }
316 else
317 if (m_delay!=digit->delay()) {
318 ATH_MSG_ERROR( "Delay does not match! Found " << digit->delay() << " expected: " << m_delay);
319 continue; //Ignore this cell
320 }
321
322 CaloGain::CaloGain gain=digit->gain();
323 if (gain<0 || gain>CaloGain::LARNGAIN)
324 {ATH_MSG_ERROR( "Found not-matching gain number ("<< (int)gain <<")");
325 return StatusCode::FAILURE;
326 }
327
328 // if using bias-corrected Parabola tool or OFC Tool, get the pedestal
329 if ( (m_recoType == PARABOLA && m_correctBias ) || m_recoType == OF) {
330
331 //GU, try to get only once the pedestal per channel...
332 IdentifierHash chid_hash = m_onlineHelper->channel_Hash(chid);
333 if (m_thePedestal[chid_hash] < 0) {
334
335 //Pointer to conditions data objects
336 const ILArPedestal* larPedestal=nullptr;
337 sc=detStore()->retrieve(larPedestal);
338 if (sc.isFailure()) {
339 ATH_MSG_FATAL( "No pedestals found in database. Aborting executiong." );
340 return sc;
341 }
342
343 if (larPedestal) {
344 float DBpedestal = larPedestal->pedestal(chid,gain);
345 if (DBpedestal >= (1.0+LArElecCalib::ERRORCODE) ) {
346 m_thePedestal[chid_hash]=DBpedestal;
347 } else {
348 ATH_MSG_WARNING("No pedestal value found for cell hash ID = "
349 << chid_hash << " " << m_onlineHelper->channel_name(chid)
350 << ". Skipping channel."
351 );
352 continue;
353 }
354 } else {
355 ATH_MSG_WARNING("No pedestal value found for cell hash ID = "
356 << chid_hash << " " << m_onlineHelper->channel_name(chid)
357 << ". Skipping channel."
358 );
359 continue;
360 }
361
362 ATH_MSG_DEBUG(" channel,pedestal " << m_onlineHelper->channel_name(chid) << " "
363 << m_thePedestal[chid_hash]);
364
365 } // m_ipassPedestal
366 }
367
368 LArCalibTriggerAccumulator& accpoints=(m_ramps->get(chid,gain))[digit->DAC()];
369 LArCalibTriggerAccumulator::ERRTYPE ec=accpoints.add(digit->sampleSum(),digit->sample2Sum(),digit->nTriggers());
371 ATH_MSG_ERROR( "Failed to accumulate sub-steps: Inconsistent number of ADC samples");
372 }
374 ATH_MSG_ERROR( "Failed to accumulate sub-steps: Numeric Overflow");
375 }
376 }//End loop over all cells
377 } //End loop over all containers
378
379 return StatusCode::SUCCESS;
380}
381
382// ********************** FINALIZE ****************************
384{
385 ATH_MSG_INFO( "in stop.");
386
387 //retrieve BadChannel info:
388 const LArBadChannelCont* bcCont=nullptr;
389 if (m_doBadChannelMask) {
391 bcCont=(*bcContHdl);
392 }
393
394 StatusCode sc;
395 //Create transient ramp object (to be filled later) (one object for all gains)
396 std::unique_ptr<LArRampComplete> larRampComplete;
397 if (m_saveRecRamp){
398 larRampComplete=std::make_unique<LArRampComplete>();
399 ATH_CHECK(larRampComplete->setGroupingType(m_groupingType,msg()));
400 ATH_CHECK(larRampComplete->initialize());
401 }
402
403 const LArOnOffIdMapping* cabling(nullptr);
404 if( m_isSC ){
405 ATH_MSG_INFO("setting up SC cabling");
407 cabling = {*cablingHdl};
408 if(!cabling) {
409 ATH_MSG_ERROR("Do not have mapping object " << m_cablingKeySC.key());
410 return StatusCode::FAILURE;
411 }
412 }else{
413 ATH_MSG_INFO("setting up calo cabling");
415 cabling = {*cablingHdl};
416 if(!cabling) {
417 ATH_MSG_ERROR("Do not have mapping object " << m_cablingKey.key());
418 return StatusCode::FAILURE;
419 }
420 }
421
422
423 const ILArRinj* rinj=nullptr;
424 if(m_ishec) {
425 ATH_CHECK(detStore()->retrieve(rinj,m_hec_key));
426 }
427
428 int containerCounter=0;
429
430 int NRamp=0;
431
432 for (unsigned k=0;k<(int)CaloGain::LARNGAIN;k++) {
436 if (cell_it==cell_it_e) {
437 ATH_MSG_INFO( "No ramp points found for gain " << gain);
438 continue; //No data for this gain
439 }
440 //Create transient object for raw ramp (one container per gain)
441 std::unique_ptr<LArRawRampContainer> larRawRampContainer;
442 if (m_saveRawRamp) {
443 larRawRampContainer=std::make_unique<LArRawRampContainer>();
444 }
445
446 //Inner loop goes over the cells.
447 for (;cell_it!=cell_it_e;cell_it++){
448
449 const HWIdentifier chid = cell_it.channelId();
450
451 ACCRAMP::const_iterator dac_it=cell_it->begin();
452 ACCRAMP::const_iterator dac_it_e=cell_it->end();
453 auto rawramp=std::make_unique<LArRawRamp>(chid,gain);
454
455 std::vector<float> peak;
456 float adcpeak, timepeak;
457 std::vector<float> adc0v;
458 bool isADCsat = false;
459
460
461
462
463 for (;dac_it!=dac_it_e;++dac_it) {
464
465 LArRawRamp::RAMPPOINT_t ramppoint;
466
467 adcpeak = -999.;
468 timepeak = -999.;
469 // prepare samples
470 float MaxADC = 0;
471 int iMaxADC = 0;
472 // if DAC0, fill adc0v vector
473 if(m_dac0sub && dac_it->first== m_DAC0){
474 // check that DAC0 is the first DAC of list
475
476 if(dac_it!=cell_it->begin())
477 ATH_MSG_ERROR( "DAC0 is not the first DAC ? This might be a problem... " );
478 adc0v = dac_it->second.mean();
479 ramppoint.Samples = adc0v;
480 ramppoint.RMS = dac_it->second.RMS();
481 ramppoint.NTriggers = dac_it->second.nTriggers();
482 }else{// if not DAC0, substract DAC0 to current DAC
483 const size_t nS=dac_it->second.nsamples();
484 adc0v.resize(nS,0.0);
485 ramppoint.Samples.resize(nS);
486 ramppoint.RMS.resize(nS);
487 ramppoint.NTriggers = dac_it->second.nTriggers();
488 for(size_t k=0;k<nS;++k){
489 ramppoint.Samples[k]=dac_it->second.mean(k) - adc0v[k];
490 ramppoint.RMS[k]=dac_it->second.RMS(k);
491 // find sample max and its index
492 if(ramppoint.Samples[k]>MaxADC){
493 MaxADC = ramppoint.Samples[k];
494 iMaxADC = k;
495 }
496 }
497 }
498
499 // reconstruct
500 if ( m_recoType == OF) {
501 if (!m_dac0sub) {
502 IdentifierHash chid_hash = m_onlineHelper->channel_Hash(chid);
503 for (size_t k=0;k<ramppoint.Samples.size();++k) {
504 ramppoint.Samples[k] = ramppoint.Samples[k] - m_thePedestal[chid_hash];
505 }
506 }
507
508 //The following lines have been moved here from LArOFPeakReco tool:
509 float delay=m_delay;
510 unsigned kMax = max_element(ramppoint.Samples.begin(),ramppoint.Samples.end()) - ramppoint.Samples.begin() ;
511 unsigned kLow, kUp;
512 //unsigned nIter=0;
513 if(!m_iterate) { // No iteration, original code
514 if ( kMax < 2 || kMax+2 >= ramppoint.Samples.size() ) {
515 // probably wrong max for small signal = noise artifact
516 kMax=2;
517 bool isgood=true;
518 if(m_doBadChannelMask && m_bcMask.cellShouldBeMasked(bcCont,chid)) isgood=false;
519 if (cabling->isOnlineConnected(chid) && isgood) {
520 ATH_MSG_WARNING( "Not enough samples around the maximum! Use kMax=2 ("
521 << m_onlineHelper->channel_name(chid) <<", DAC=" << dac_it->first
522 << ", Amp[2]=" << ramppoint.Samples[2] << " )" );
523 if (msgLvl(MSG::VERBOSE)) {
524 msg(MSG::VERBOSE) << " Samples: ";
525 for (unsigned k=0;k<ramppoint.Samples.size();k++)
526 msg() << ramppoint.Samples[k] << " ";
527 msg() << endmsg;
528 }//end if verbose message
529 }//end if bad or disconnected channel
530 }//end if kmax out-of-range
531
532 // convention delay=0 OFC use samp 0-1-2-3-4
533 // delay=24 OFC use samp 1-2-3-4-5
534 // => if kmax=2 : choose OFC with delay + delayShift
535 // if kmax=3 : choose OFC with delay+ delayShift+24
536 // if kmax=4 : stick to kmax=3
537 //GU temporary hardcoded number. To move to jobOptions
538
539 if (kMax==4) kMax=3;
540 if (kMax==3) delay += (m_delayShift+24);
541 if (kMax==2) delay += m_delayShift;
542 ATH_MSG_VERBOSE("kMax " << kMax << " delay " << delay);
543 delay=(delay-0.5)*(25./24.);
544 //Call OF peak reco tool with no iteration and peak-sample forced to kMax
545 kLow = kUp = kMax;
546 } else { // code with iteration
547 kLow = kMax - 2;
548 kUp = kMax + 2;
549 delay = 0.;
550 //nIter = 10;
551 }
552 const LArOFPeakRecoTool::Result results=m_peakOFTool->peak(ramppoint.Samples,chid,gain,delay,0,kMax,kLow,kUp);
553 if (results.getValid()) {
554 adcpeak = results.getAmplitude();
555 timepeak = results.getTau();
556 }
557 else
558 ATH_MSG_ERROR( "LArOFPeak reco tool returns invalid result.");
559
560
561 } else if ( m_recoType == SHAPE) {
562
563 IdentifierHash chid_hash = m_onlineHelper->channel_Hash(chid);
564
565 // reconstruct for non-DAC0 values and non-saturating waves
566 if(dac_it->first!= m_DAC0 && dac_it->first <= m_CaliDACs[gain][chid_hash][m_IndexHighestDAC[gain][chid_hash]]){
567
568 // find appropriate wave
569 unsigned int GoodIndex = 9999;
570 for(unsigned int i=0;i<m_CaliDACs[gain][chid_hash].size();i++){
571 if(dac_it->first == m_CaliDACs[gain][chid_hash][i]) GoodIndex=i;
572 }
573 if(GoodIndex == 9999) {
574 ATH_MSG_WARNING("No wave found for cell = " << chid_hash << ", DAC = " << dac_it->first);
575 float min = 9999999;
576 for(unsigned int i=0;i<m_CaliDACs[gain][chid_hash].size();i++){
577 int dacdiff = dac_it->first - m_CaliDACs[gain][chid_hash][i];
578 if(abs(dacdiff)<min)
579 {
580 min=abs(dacdiff);
581 GoodIndex=i;
582 }
583 }
584 ATH_MSG_WARNING("Replace with DAC = " << m_CaliDACs[gain][chid_hash][GoodIndex]);
585 }
586 // substract DAC0 wave
587 for(unsigned int k=0;k<m_CaliWaves[gain][chid_hash][GoodIndex].size();k++){
588 m_CaliWaves[gain][chid_hash][GoodIndex][k] -= m_CaliWaves[gain][chid_hash][m_IndexDAC0[gain][chid_hash]][k];
589 }
590
591 // apply reconstruction
592 if(!m_CaliWaves[gain][chid_hash][GoodIndex].empty()){
593 peak=m_peakShapeTool->peak(ramppoint.Samples,m_CaliWaves[gain][chid_hash][GoodIndex]);
594 ATH_MSG_DEBUG("cell chid=" << chid.get_compact() << ",peak= " << peak[0]);
595 }else{
596 ATH_MSG_ERROR( "No wave for this cell chid=" << chid.get_compact() << ",hash= " << chid_hash);
597 peak.push_back(-999);
598 peak.push_back(-999);
599 }
600
601 if(peak.size()>1){
602 adcpeak = peak[0];
603 timepeak = peak[1];
604 }
605 }
606 } else if ( m_recoType == PARABOLA ) {
607
608 if(m_correctBias){
609
610 IdentifierHash chid_hash = m_onlineHelper->channel_Hash(chid);
611
612 // get layer for correction
613 Identifier id=cabling->cnvToIdentifier(chid);
614 int layer=m_emId->sampling(id);
615 peak=m_peakParabolaTool->peak(ramppoint.Samples,layer,m_thePedestal[chid_hash]);
616
617 }else{
618 // call peak reco without layer --> no bias correction
619 peak=m_peakParabolaTool->peak(ramppoint.Samples);
620 }
621 adcpeak = peak[0];
622 timepeak = peak[1];
623
624
625 } else {
626 ATH_MSG_ERROR( "Both OF and Parabola reconstruction modes not available!" ) ;
627 return StatusCode::FAILURE ;
628 }
629
630 ramppoint.ADC = adcpeak;
631 ramppoint.DAC = dac_it->first;
632
633 if( !m_isSC && m_ishec && m_onlineHelper->isHECchannel(chid)) {
634 if(rinj) {
635 const float rinjval = rinj->Rinj(chid);
636 if(rinjval < 4) ramppoint.DAC /= 2;
637 }
638 }
639
640 ramppoint.iMaxSample = iMaxADC;
641 ramppoint.TimeMax = timepeak;
642
643
644 // only add to rawramp non saturing points (using rawdata information)
645
646 if( (dac_it->first>= m_minDAC) && ramppoint.ADC > -998
647 && ((m_maxADC <= 0) || (MaxADC < m_maxADC)) ) {
648 rawramp->add(ramppoint);
649 }
650 else if ((m_maxADC > 0)&&(MaxADC >= m_maxADC)) {
651 isADCsat = true; // if ADC saturated at least once, it should be notified
652 if(ramppoint.DAC < 200){
653 ATH_MSG_DEBUG("Saturated low DAC: "<<m_onlineHelper->channel_name(chid)<<" at DAC "<<dac_it->first<<" ADC "<< MaxADC);
654 } else {
655 ATH_MSG_DEBUG("Saturated: "<<m_onlineHelper->channel_name(chid)<<" at DAC "<<dac_it->first<<" ADC "<< MaxADC);
656 }
657 }else{
658 ATH_MSG_DEBUG("Fail ramp selection: "<<chid<<" "<<dac_it->first<<" "<<m_minDAC<<" "<<ramppoint.ADC<<" "<<MaxADC<<" "<<m_maxADC);
659 }
660 }
661
662 //Build ramp object..........
663 if (larRampComplete) {
664 std::vector<LArRawRamp::RAMPPOINT_t>& data=rawramp->theRamp();
665 sort(data.begin(),data.end()); //Sort vector of raw data (necessary to cut off nonlinar high ADC-values)
666 std::vector<float> rampCoeffs;
667 std::vector<int> vSat;
668 StatusCode sc=rampfit(m_degree+1,data,rampCoeffs,vSat,chid,cabling,bcCont);
669 if (sc!=StatusCode::SUCCESS){
670 if (!cabling->isOnlineConnected(chid))
671 ATH_MSG_DEBUG("Failed to produce ramp for disconnected channel " << m_onlineHelper->channel_name(chid));
672 else if (m_doBadChannelMask && m_bcMask.cellShouldBeMasked(bcCont,chid))
673 ATH_MSG_INFO( "Failed to produce ramp for known bad channel " << m_onlineHelper->channel_name(chid));
674 else
675 ATH_MSG_ERROR( "Failed to produce ramp for channel " << m_onlineHelper->channel_name(chid));
676 }
677 else{
678 if(rampCoeffs[1]<0)
679 ATH_MSG_ERROR( "Negative 1rst order coef for ramp = " << rampCoeffs[1] << " for channel "
680 << m_onlineHelper->channel_name(chid) );
681
682 if (vSat[0] != -1) { rawramp->setsat(vSat[0]); } // if a saturation point was found in rampfit, record it
683 else {
684 if (isADCsat) { rawramp->setsat(data.size()-1); } // if no saturation point was found, and ADC saturation happened, record the last ramp point
685 if (!isADCsat) { rawramp->setsat(data.size()); } // if no saturation point was found, and ADC saturation did not happen, record the ramp size
686 }
687
688 //Produce transient object
689 larRampComplete->set(chid,(int)gain,rampCoeffs);
690 NRamp++;
691 }// end else (rampfitting suceeded)
692 }// end if (build ramp object)
693 //Save raw ramp for this cell, if requested by jobOpts
694 if (larRawRampContainer){
695 larRawRampContainer->push_back(std::move(rawramp));
696 }
697 }//end loop cells
698
699 if (larRawRampContainer) {
700 std::string key;
701 switch (gain) {
703 key="HIGH";
704 break;
706 key="MEDIUM";
707 break;
709 key="LOW";
710 break;
711 default:
712 key="UNKNOWN";
713 break;
714 }
715 key = m_keyoutput + key;
716 ATH_MSG_INFO( "Recording LArRawRampContainer for gain " << (int)gain << " key=" << key);
717 sc=detStore()->record(std::move(larRawRampContainer),key);
718 if (sc.isFailure()) {
719 ATH_MSG_ERROR( "Failed to record LArRawRamp object");
720 }
721 }// end if larRawRampContainer
722 ++containerCounter;
723 }//end loop over containers
724
725 if (containerCounter==0) {
726 ATH_MSG_WARNING("No Ramps have been produced. No data found.");
727 return StatusCode::FAILURE;
728 }
729
730 if (larRampComplete){ //Save the transient Ramp object.
731
732 ATH_MSG_INFO( " Summary : Number of cells with a ramp value computed : " << NRamp );
733 ATH_MSG_INFO( " Summary : Number of Barrel PS cells side A or C (connected+unconnected): 3904+ 192 = 4096 ");
734 ATH_MSG_INFO( " Summary : Number of Barrel cells side A or C (connected+unconnected): 50944+2304 = 53248 ");
735 ATH_MSG_INFO( " Summary : Number of EMEC cells side A or C (connected+unconnected): 31872+3456 = 35328 ");
736 ATH_MSG_INFO( " Summary : Number of HEC cells side A or C (connected+unconnected): 2816+ 256 = 3072 ");
737 ATH_MSG_INFO( " Summary : Number of FCAL cells side A or C (connected+unconnected): 1762+ 30 = 1792 ");
738
739
740 sc=detStore()->record(std::move(larRampComplete),m_keyoutput);
741 if (sc.isFailure()) {
742 ATH_MSG_ERROR( "Failed to record LArRampComplete object");
743 }
745 if (sc.isFailure()) {
746 ATH_MSG_ERROR( "Failed to symlink LArRawRamp object");
747 }
748 }
749 m_ramps.reset();//Not needed any more. Free memory.
750 ATH_MSG_INFO( "LArRampBuilder has finished.");
751 return StatusCode::SUCCESS;
752}// end finalize-method.
753
754
755StatusCode LArRampBuilder::rampfit(unsigned deg, const std::vector<LArRawRamp::RAMPPOINT_t>& data,
756 std::vector<float>& rampCoeffs, std::vector<int>& vSat,
757 const HWIdentifier chid, const LArOnOffIdMapping* cabling,
758 const LArBadChannelCont* bcCont) {
759 unsigned linRange=data.size();
760 if (linRange<2) {
761 bool isgood=true;
762 if(m_doBadChannelMask && m_bcMask.cellShouldBeMasked(bcCont,chid)) isgood=false;
763 if (cabling->isOnlineConnected(chid) && isgood ) {
764 ATH_MSG_ERROR( "Not enough datapoints (" << linRange << ") to fit a polynom!" );
765 return StatusCode::FAILURE;
766 }
767 else {
768 ATH_MSG_DEBUG("Not enough datapoints (" << linRange << ") to fit a polynom for a disconnected or known bad channel!" );
769 return StatusCode::FAILURE;
770 }
771 }
772 int satpoint = -1;
773 if (m_satSlope) {
774
775 float thisslope = 0., meanslope = 0.;
776 std::vector<float> accslope;
777 accslope.push_back(0);
778 for (unsigned int DACIndex=1;DACIndex<linRange;DACIndex++){
779 thisslope = (data[DACIndex].ADC - data[DACIndex-1].ADC)/(data[DACIndex].DAC - data[DACIndex-1].DAC);
780
781 float scut;
782 if(m_onlineHelper->isHECchannel(chid) && DACIndex < 5) {
783 scut = meanslope/4.;
784 } else { scut = meanslope/10.;}
785 if ( (satpoint == -1) && ((meanslope-thisslope) > scut) ) {
786 satpoint = DACIndex;
787 if (satpoint <= 4) {
788 ATH_MSG_DEBUG("Only "<<satpoint<<" points to fit, chid: "<<std::hex<<chid.get_identifier32().get_compact()<<std::dec);
789 ATH_MSG_DEBUG(meanslope<<" "<<thisslope<<" | "<<data[DACIndex-1].ADC<<" "<<data[DACIndex].ADC);
790 }
791 } // saturation was reached
792
793 meanslope = ( thisslope + (DACIndex-1)*(accslope[DACIndex-1]) )/DACIndex;
794 accslope.push_back(meanslope);
795
796 }
797
798 if (satpoint != -1) { linRange = satpoint; } // if a saturation was found, linRange becomes the saturation index
799
800 }
801 vSat.push_back(satpoint);
802
803 if (!m_withIntercept) {
804 deg--;
805 }
806 bool isgood=true;
807 if(m_doBadChannelMask && m_bcMask.cellShouldBeMasked(bcCont,chid)) isgood=false;
808 if (deg>linRange) {
809 if (cabling->isOnlineConnected(chid) && isgood )
810 ATH_MSG_ERROR( "Not enough datapoints before saturation (" << linRange << ") to fit a polynom of degree " << deg << "chid: "<<std::hex<<chid.get_identifier32().get_compact()<<std::dec);
811 else
812 ATH_MSG_DEBUG("Not enough datapoints before saturation (" << linRange << ") to fit a polynom of degree " << deg << "chid: "<<std::hex<<chid.get_identifier32().get_compact()<<std::dec
813 << " (channel disconnected or known to be bad)");
814
815 return StatusCode::FAILURE;
816 }
817
818 if (data[linRange-1].DAC>0 && data[linRange-1].ADC<m_deadChannelCut && data[linRange-1].ADC!=-999.) {
819 ATH_MSG_ERROR( "DAC= " << data[linRange-1].DAC << " yields ADC= " << data[linRange-1].ADC
820 << ". Dead channel?" );
821 return StatusCode::FAILURE;
822 }
823
824 int begin = 0;
825 if(data[0].DAC == m_DAC0) begin = 1; // starts at 1 to skip DAC=0
826
827 Eigen::MatrixXd alpha(deg,deg);
828 Eigen::VectorXd beta(deg);
829 float sigma2 = 1.;
830 for (unsigned k=0;k<deg;k++)
831 for (unsigned j=0;j<=k;j++)
832 {
833 alpha(k,j)=0;
834 for (unsigned i=begin;i<linRange;i++)
835 {
836 // we are not storing any error on the reconstructed
837 // peaks, but we can simply use the error on the sample
838 // means (RMS/sqrt(NTriggers)) to account for any
839 // potential variation on the number of accumulated
840 // triggers. BTW, this would be proportional to the ADC
841 // uncertainly but used as *DAC* uncertainty: in the limit
842 // in which the ramp is linear this is still correct, and
843 // anyway better than nothing. -- M.D. 13/7/2009
844 sigma2 = 1.;
845 if ( data[i].NTriggers ) {
846 //float sigma2 = (data[i].RMS[0]*data[i].RMS[0])/data[i].NTriggers;
847 sigma2 = 100./data[i].NTriggers;
848 }
849 // just use trigger number, assume RMS is constant for
850 // all DAC points (same noise). The 100. scale factor is
851 // there to guarantee the same results with respect to
852 // previous fits withour errors (having usually 100
853 // triggers), because of potential numerical
854 // differences when inverting the fit matrix even if
855 // errors are all the same.
856 if (m_withIntercept) {
857 alpha(k,j)+=(std::pow(data[i].ADC,(int)k)*std::pow(data[i].ADC,(int)j))/sigma2;
858 } else {
859 alpha(k,j)+=(std::pow(data[i].ADC,(int)k+1)*std::pow(data[i].ADC,(int)j+1))/sigma2;
860 }
861 alpha(j,k)=alpha(k,j); //Use symmetry
862 }
863 }
864
865 for (unsigned k=0;k<deg;k++)
866 {
867 beta[k]=0;
868 for (unsigned i=begin;i<linRange;i++) {
869 sigma2 = 1.;
870 if ( data[i].NTriggers ) {
871 sigma2 = 100./data[i].NTriggers;
872 }
873 if (m_withIntercept) {
874 beta[k]+=(data[i].DAC*pow(data[i].ADC,(int)k))/sigma2;
875 } else {
876 beta[k]+=(data[i].DAC*pow(data[i].ADC,(int)k+1))/sigma2;
877 }
878 }
879 }
880
881 //HepVector comp=solve(alpha,beta);
882 const Eigen::VectorXd comp=alpha.colPivHouseholderQr().solve(beta);
883
884 //Fill RampDB object
885 if (!m_withIntercept)
886 rampCoeffs.push_back(0);
887
888 for (int l=0;l<comp.size() ;l++)
889 rampCoeffs.push_back(comp[l]);
890
891#ifdef LARRAMPBUILDER_DEBUGOUTPUT
892 // ****************************************
893 // Output for Dugging:
894 for (unsigned i=1;i<data.size();i++)
895 std::cout << data[i].DAC << " " << data[i].ADC << " " << std::endl;
896 std::cout << "LinRange= " << linRange << " satpoint= " << satpoint<<std::endl;
897 for (unsigned k=0;k<deg;k++) {
898 std::cout<<"Beta "<<k<<" "<<beta[k]<<std::endl;
899 for (unsigned j=0;j<=k;j++) {
900 std::cout<<"Alpha "<<j<<" "<<alpha(k,j)<<std::endl;
901 }
902 }
903
904 //Calculate error:
905 double sigma=0;
906 for (unsigned k=0;k<linRange;k++) //Run over all data points
907 {double DACcalc=comp[0];
908 for (int i=1;i<comp.size();i++) //Apply polynom
909 DACcalc+=comp[i]*pow(data[k].ADC,i);
910 sigma+=(DACcalc-data[k].DAC)*(DACcalc-data[k].DAC);
911 }
912 sigma=sqrt(sigma);
913 if (linRange>1)
914 sigma=sigma/(linRange-1);
915
916 std::cout << "Components: ";
917 for (int i=0;i<comp.size();i++)
918 std::cout << comp[i] << " ";
919 std::cout << "sigma=" << sigma << std::endl;
920#undef LARRAMPBUILDER_DEBUGOUTPUT
921#endif
922
923 return StatusCode::SUCCESS;
924}
#define endmsg
#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_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
a traits class that associates a CLID to a type T It also detects whether T inherits from Gaudi DataO...
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
double delay(std::size_t d)
LArBadXCont< LArBadChannel > LArBadChannelCont
static Double_t sc
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
#define deg
static const Attributes_t empty
constexpr int pow(int base, int exp) noexcept
#define min(a, b)
Definition cfImp.cxx:40
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
MsgStream & msg() const
Helper class for offline cell identifiers.
Definition CaloCell_ID.h:34
const LArEM_ID * em_idHelper() const
access to EM idHelper
Definition CaloCell_ID.h:63
size_type size() const noexcept
Returns the number of elements in the collection.
bool empty() const noexcept
Returns true if the collection is empty.
virtual float pedestal(const HWIdentifier &id, int gain) const =0
virtual const float & Rinj(const HWIdentifier &id) const =0
value_type get_compact() const
Get the compact id.
This is a "hash" representation of an Identifier.
value_type get_compact() const
Get the compact id.
Identifier32 get_identifier32() const
Get the 32-bit version Identifier, will be invalid if >32 bits needed.
Container class for LArAccumulatedCalibDigit.
Data class for calibration ADC samples preprocessed by the DSP.
Liquid Argon Cumulative Wave Container.
Helper class to accumulate calibration triggers.
ERRTYPE add(const std::vector< short > &digits)
accumulated individual set of digits.
ConditionsMap::const_iterator ConstConditionsMapIterator
ConstConditionsMapIterator begin(unsigned int gain) const
get iterator for all channels for a gain
ConstConditionsMapIterator end(unsigned int gain) const
end of all channels for this gain
ConditionsMap::iterator ConditionsMapIterator
Holds information from the FEB Error Summary.
static std::string error_to_string(uint16_t error)
interpret the error in string
uint16_t feb_error(HWIdentifier febid) const
get error for feb
LArOFIterResults Result
Helper for the Liquid Argon Calorimeter cell identifiers.
std::unique_ptr< LArConditionsContainer< ACCRAMP > > m_ramps
Gaudi::Property< bool > m_doBadChannelMask
IntegerProperty m_maxADC
SG::ReadCondHandleKey< LArBadChannelCont > m_bcContKey
PublicToolHandle< LArParabolaPeakRecoTool > m_peakParabolaTool
BooleanProperty m_satSlope
IntegerProperty m_deadChannelCut
LArBadChannelMask m_bcMask
Gaudi::Property< std::string > m_hec_key
virtual StatusCode stop()
Gaudi::Property< std::string > m_groupingType
std::vector< float > m_thePedestal
std::vector< std::vector< std::vector< unsigned int > > > m_CaliDACs
BooleanProperty m_dac0sub
unsigned m_event_counter
Gaudi::Property< bool > m_ishec
Gaudi::Property< bool > m_isSC
std::vector< std::vector< std::vector< std::vector< double > > > > m_CaliWaves
const LArOnlineID_Base * m_onlineHelper
Gaudi::Property< std::vector< std::string > > m_keylist
std::vector< std::vector< int > > m_IndexHighestDAC
Gaudi::Property< std::string > m_keyoutput
FloatProperty m_delayShift
std::vector< std::vector< int > > m_IndexDAC0
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
IntegerProperty m_degree
StringProperty m_recoTypeProp
StatusCode rampfit(unsigned deg, const std::vector< LArRawRamp::RAMPPOINT_t > &data, std::vector< float > &rampCoeffs, std::vector< int > &vSat, const HWIdentifier chid, const LArOnOffIdMapping *cabling, const LArBadChannelCont *bcCont)
StatusCode execute()
UnsignedIntegerProperty m_minDAC
Gaudi::Property< bool > m_iterate
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKeySC
uint16_t m_fatalFebErrorPattern
StatusCode initialize()
ToolHandle< LArOFPeakRecoTool > m_peakOFTool
BooleanProperty m_withIntercept
const LArEM_Base_ID * m_emId
UnsignedIntegerProperty m_DAC0
Gaudi::Property< std::vector< std::string > > m_problemsToMask
BooleanProperty m_correctBias
BooleanProperty m_saveRawRamp
BooleanProperty m_saveRecRamp
PublicToolHandle< LArShapePeakRecoTool > m_peakShapeTool
std::vector< float > Samples
Definition LArRawRamp.h:36
std::vector< float > RMS
Definition LArRawRamp.h:37
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
@ LARMEDIUMGAIN
Definition CaloGain.h:18
@ LARLOWGAIN
Definition CaloGain.h:18
@ LARNGAIN
Definition CaloGain.h:19
@ LARHIGHGAIN
Definition CaloGain.h:18