ATLAS Offline Software
LArCalibPatchingAlg.icc
Go to the documentation of this file.
1 //Dear emacs, this is -*-c++-*-
2 /*
3  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
4 */
5 
6 #include <tuple>
7 
8 template<class CONDITIONSCONTAINER>
9 LArCalibPatchingAlg<CONDITIONSCONTAINER>::LArCalibPatchingAlg (const std::string& name, ISvcLocator* pSvcLocator) :
10  AthAlgorithm(name,pSvcLocator),
11  m_onlineHelper(0),
12  m_caloId(0),
13  m_contIn(0),
14  m_contOut(0),
15  m_patchMethod(PhiAverage) { }
16 
17 
18 template<class CONDITIONSCONTAINER>
19 StatusCode LArCalibPatchingAlg<CONDITIONSCONTAINER>::initialize() {
20 
21  ATH_CHECK( m_BCKey.initialize() );
22  ATH_CHECK( m_cablingKey.initialize() );
23  ATH_CHECK( m_CLKey.initialize() );
24 
25 
26  if(m_patchMethodProp=="FEBNeighbor") {
27  m_patchMethod=FEBNeighbor;
28  return StatusCode::SUCCESS;
29  }
30  else if (m_patchMethodProp=="PhiNeighbor") {
31  m_patchMethod=PhiNeighbor;
32  return StatusCode::SUCCESS;
33  }
34  else if (m_patchMethodProp=="PhiAverage") {
35  if (typeid(CONDITIONSCONTAINER)==typeid(LArAutoCorrComplete)) {
36  ATH_MSG_ERROR ( "PhiAverage not implemented for LArAutoCorrComlete."
37  << "Please choose other patching strategy" );
38  return StatusCode::FAILURE;
39  }
40  m_patchMethod=PhiAverage;
41  return StatusCode::SUCCESS;
42  }
43  else if (m_patchMethodProp=="FEBAverage") {
44  if (typeid(CONDITIONSCONTAINER)==typeid(LArCaliWaveContainer)) {
45  ATH_MSG_ERROR ( "FEBAverage not implemented for CaliWaveContainer."
46  << "Please choose other patching strategy" );
47  return StatusCode::FAILURE;
48  }
49  m_patchMethod=FEBAverage;
50  return StatusCode::SUCCESS;
51  } else if (m_patchMethodProp=="SetZero") {
52  if (typeid(CONDITIONSCONTAINER)==typeid(LArCaliWaveContainer)) {
53  ATH_MSG_ERROR ( "SetZero not implemented for CaliWaveContainer."
54  << "Please choose other patching strategy" );
55  return StatusCode::FAILURE;
56  }
57  m_patchMethod=SetZero;
58  return StatusCode::SUCCESS;
59  }
60 
61  ATH_MSG_ERROR ( "Unknown patching method: " << m_patchMethodProp );
62  ATH_MSG_ERROR ( "Allowed values: [Empty, FEBNeighbor, PhiNeighbor, PhiAverage, SetZero]" );
63 
64  return StatusCode::FAILURE;
65 }
66 
67 template<class CONDITIONSCONTAINER>
68 StatusCode LArCalibPatchingAlg<CONDITIONSCONTAINER>::stop() {
69  ATH_MSG_INFO ( "Entering LArCalibPatchingAlg" );
70  if(m_isSC) {
71  ATH_CHECK( detStore()->retrieve(m_onlineHelper, "LArOnline_SuperCellID") );
72  ATH_CHECK( detStore()->retrieve(m_caloId, "CaloCell_SuperCell_ID") );
73  } else {
74  ATH_CHECK( detStore()->retrieve(m_onlineHelper, "LArOnlineID") );
75  ATH_CHECK( detStore()->retrieve(m_caloId, "CaloCell_ID") );
76  }
77 
78  if(m_isSC) m_bcMask.setSC();
79  ATH_CHECK(m_bcMask.buildBitMask(m_problemsToPatch,msg()));
80 
81  const EventContext& ctx = Gaudi::Hive::currentContext();
82 
83  SG::ReadCondHandle<LArBadChannelCont> readHandle{m_BCKey, ctx};
84  const LArBadChannelCont *bcCont {*readHandle};
85  if(!bcCont) {
86  ATH_MSG_ERROR( "Do not have Bad chan container !!!" );
87  return StatusCode::FAILURE;
88  }
89 
90  SG::ReadCondHandle<LArOnOffIdMapping> cablingHdl{m_cablingKey, ctx};
91  const LArOnOffIdMapping* cabling = *cablingHdl;
92  if(!cabling) {
93  ATH_MSG_ERROR( "Do not have OnOff Id mapping !!!" );
94  return StatusCode::FAILURE;
95  }
96 
97  SG::ReadCondHandle<LArCalibLineMapping> clHdl{m_CLKey, ctx};
98  const LArCalibLineMapping *clCont {*clHdl};
99  if(!clCont) {
100  ATH_MSG_ERROR( "Do not have calib line mapping !!!" );
101  return StatusCode::FAILURE;
102  }
103 
104  if (m_newContainerKey.size()) {
105  //New container key give -> different containers for reading and writing
106  ATH_CHECK( detStore()->retrieve(m_contIn,m_containerKey) ); //const-retrieve
107 
108  m_contOut=new CONDITIONSCONTAINER();
109  m_contOut->setGroupingType((LArConditionsContainerBase::GroupingType)m_contIn->groupingType());
110  ATH_CHECK( m_contOut->initialize() );
111  ATH_CHECK( detStore()->record(m_contOut,m_newContainerKey) );
112  ATH_CHECK( setSymlink(m_contOut) );
113  ATH_MSG_INFO ( "Loaded input container " << m_containerKey
114  << ", write to new container " << m_newContainerKey );
115  }
116  else { //Same container for reading and writing
117  if (m_unlock) {
118  ATH_CHECK( detStore()->retrieve(m_contIn,m_containerKey) ); //const-retrieve
119  m_contOut=const_cast<CONDITIONSCONTAINER*>(m_contIn);
120  }
121  else{
122  ATH_CHECK( detStore()->retrieve(m_contOut,m_containerKey) ); //non-const retrieve
123  m_contIn=const_cast<const CONDITIONSCONTAINER*>(m_contOut);
124  ATH_MSG_INFO ( "Work on container '" << m_containerKey << "'" );
125  }
126  }
127 
128  LArBadChanBitPacking packing;
129  LArBadChanSCBitPacking scpacking;
130 
131  unsigned maxgain;
132  if(m_isSC) maxgain=CaloGain::LARMEDIUMGAIN; else maxgain=CaloGain::LARNGAIN;
133  for (unsigned igain=CaloGain::LARHIGHGAIN;
134  igain<maxgain ; ++igain ) {
135  CONTIT it=m_contIn->begin(igain);
136  CONTIT it_e=m_contIn->end(igain);
137  for (;it!=it_e;it++) {
138  const HWIdentifier chid = it.channelId();
139  if (!cabling->isOnlineConnected(chid)) continue; //Don't care about disconnected channels
140  if (m_bcMask.cellShouldBeMasked(bcCont,chid)) {
141  const std::string bcType = m_isSC ? scpacking.stringStatus(bcCont->status(chid)) : packing.stringStatus(bcCont->status(chid));
142  ATH_MSG_INFO ( "Found problematic channel 0x" << MSG::hex << chid.get_identifier32().get_compact() << MSG::dec << " [" << bcType << "]"
143  <<" Gain:" << igain << " " << m_onlineHelper->channel_name(chid) << ". Trying to patch." );
144  if (patch(chid,igain, bcCont, cabling, clCont)) {
145  ATH_MSG_INFO ( "Sucessfully patched channel 0x" << MSG::hex << chid.get_identifier32().get_compact() << MSG::dec <<" Gain:" << igain );
146  } else {
147  ATH_MSG_WARNING ( "Failed to patch channel 0x" << MSG::hex << chid.get_identifier32().get_compact() << MSG::dec <<" Gain:" << igain );
148  }
149  }//end if channel is in bad-channel database
150  else
151  if (it->isEmpty()) { //check if data-object is empty (eg the default instance
152  ATH_MSG_ERROR ( "The channel 0x" << MSG::hex << chid.get_identifier32().get_compact() << MSG::dec
153  <<" Gain:" << igain << " " << m_onlineHelper->channel_name(chid)
154  << " has no calibration but is not (yet?) flagged in the bad-channel database" );
155  if (m_patchAllMissing) {
156  ATH_MSG_INFO ( "Will try to patch anyway." );
157  if (patch(chid,igain, bcCont, cabling, clCont)) {
158  ATH_MSG_INFO ( "Sucessfully patched channel 0x" << MSG::hex << chid.get_identifier32().get_compact() << MSG::dec <<" Gain:" << igain );
159  } else {
160  ATH_MSG_WARNING ( "Failed to patch channel 0x" << MSG::hex << chid.get_identifier32().get_compact() << MSG::dec <<" Gain:" << igain );
161  }
162  }//end if m_patchAllMissing
163  else
164  ATH_MSG_ERROR ( "Channel remains un-patched!" );
165  }//end if isEmpty
166  }//end loop over all channels
167  }//end loop over all gains
168 
169  std::vector<unsigned> completedChans = m_contOut->completeCorrectionChannels();
170  if (completedChans.size()>0 && m_useCorrChannel) {
171  msg() << MSG::INFO << "Artificially inserted correction subsets in COOL channels";
172  for(size_t j=0;j<completedChans.size();++j)
173  msg() << MSG::INFO << " " << completedChans[j];
174  msg() << MSG::INFO << endmsg;
175  }
176 
177 
178  ATH_MSG_INFO ( "Done with LArCalibPatchingAlg" );
179  ATH_MSG_DEBUG ( detStore()->dump() );
180  return StatusCode::SUCCESS;
181 }
182 
183 template<class CONDITIONSCONTAINER>
184 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::patch(const HWIdentifier chid, const int gain, const LArBadChannelCont* bcCont, const LArOnOffIdMapping* cabling, const LArCalibLineMapping *clCont) {
185 
186  if(m_doNotPatchCBs.size()>0) { // check if this channel is not on excluded CalibBoard
187  const std::vector<HWIdentifier>& cLids=clCont->calibSlotLine(chid);
188  for(unsigned cl=0; cl<cLids.size(); ++cl) {
189  const HWIdentifier calibModuleID = m_onlineHelper->calib_module_Id(cLids[cl]);
190  if (std::find(m_doNotPatchCBs.begin(),m_doNotPatchCBs.end(),calibModuleID.get_identifier32().get_compact()) != m_doNotPatchCBs.end()) { // we should not patch this channel
191  return false;
192  }
193  } // over CLs
194  }
195 
196  if (m_patchMethod==FEBNeighbor){
197  const HWIdentifier febId=m_onlineHelper->feb_Id(chid);
198  const int febChan=m_onlineHelper->channel(chid);
199  HWIdentifier chid_patch(0);
200  if (febChan>0) {
201  //try lower channel
202  chid_patch=m_onlineHelper->channel_Id(febId, febChan-1);
203  if (cabling->isOnlineConnected(chid_patch) && bcCont->status(chid_patch).good()) {
204  const LArCondObj patch=m_contIn->get(chid_patch,gain); //Should be the const-get method
205  if (!patch.isEmpty()) {
206  StatusCode sc=m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel);
207  if (sc.isFailure())
208  ATH_MSG_ERROR ( "Failed to insert correction for channel 0x" << MSG::hex << chid.get_compact()
209  << MSG::dec <<", gain " << gain << "." );
210  else
211  ATH_MSG_INFO ( "Replaced channel 0x" << MSG::hex << chid.get_compact()
212  << " by it's left FEB neighbor 0x" << chid_patch.get_compact() << MSG::dec );
213  return true;
214  }
215  }//end if patch connected and good
216  }//end if febChan
217  if (febChan<(m_onlineHelper->channelInSlotMax(febId)-1)) {
218  chid_patch=m_onlineHelper->channel_Id(febId, febChan+1);
219  if (cabling->isOnlineConnected(chid_patch) && bcCont->status(chid_patch).good()) {
220  const LArCondObj patch=m_contIn->get(chid_patch,gain); //Should be the const-get method
221  if (!patch.isEmpty()) {
222  StatusCode sc=m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel);
223  if (sc.isFailure()) {
224  ATH_MSG_ERROR ( "Failed to insert correction for channel 0x" << MSG::hex << chid.get_compact()
225  << MSG::dec << ", gain " << gain << "." );
226  }
227  else {
228  ATH_MSG_INFO ( "Replaced channel 0x" << MSG::hex << chid.get_compact()
229  << " by it's right FEB neighbor 0x" << chid_patch.get_compact() << MSG::dec );
230  return true;
231  }
232  }//end if patch connected and good
233  }//end if chan<max
234  }
235  ATH_MSG_ERROR ( "None of the FEB neighbors is good!" );
236  return false;
237  } else if (m_patchMethod==PhiNeighbor) {
238  // (*m_log) << MSG::ERROR << "Patching Method 'Phi-neighbor' not yet implemented." << endmsg;
239  try {
240  const Identifier id=cabling->cnvToIdentifier(chid);
241  int eta, phi, phi_min, phi_max, phi_range;
242  Identifier regionID;
243  regionID=m_caloId->region_id(id);
244  eta = m_caloId->eta(id);
245  phi = m_caloId->phi(id);
246  phi_min =m_caloId->phi_min(regionID);
247  phi_max =m_caloId->phi_max(regionID);
248  phi_range=phi_max-phi_min+1;
249  if (eta==CaloCell_ID::NOT_VALID || phi==CaloCell_ID::NOT_VALID || phi_min==CaloCell_ID::NOT_VALID || phi_max==CaloCell_ID::NOT_VALID) {
250  ATH_MSG_ERROR ( "CaloCell_ID returned NOT_VALID for offline id 0x"<< std::hex << id.get_compact()
251  <<", online id 0x" << chid.get_compact() << std::dec );
252  return false;
253  }
254  ATH_MSG_VERBOSE ( "Problem channel has phi="<< phi << " eta=" << eta );
255  //Try both phi-neighbors
256  int phi_list[4]={phi-1,phi+1,phi-2,phi+2};
257  for (unsigned i=0;i<4;i++) {
258  int phi_patch=phi_list[i];
259  if (phi_patch<m_caloId->phi_min(regionID)) phi_patch=phi_patch+phi_range;
260  if (phi_patch>m_caloId->phi_max(regionID)) phi_patch=phi_patch-phi_range+phi_min;
261  ATH_MSG_VERBOSE ( "Iteration " << i << " Using cell with phi="
262  << phi_patch << " eta=" << eta );
263  //std::cout << "i=" << i << " Using cell with phi="
264  // << phi_patch << " eta=" << eta << std::endl;
265  Identifier patch_id=m_caloId->cell_id(regionID,eta,phi_patch);
266  HWIdentifier chid_patch=cabling->createSignalChannelID(patch_id);
267  if (bcCont->status(chid_patch).good()) {
268  const LArCondObj patch=m_contIn->get(chid_patch,gain);
269  if (!patch.isEmpty()) {
270  StatusCode sc=m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel);
271  if (sc.isFailure())
272  ATH_MSG_ERROR ( "Failed to insert correction for channel 0x" << MSG::hex << chid.get_compact()
273  << MSG::dec << ", gain " << gain << "." );
274  else
275  ATH_MSG_INFO ( "Replaced channel 0x" << MSG::hex << chid.get_compact()
276  << " by neighbor 0x" << chid_patch.get_compact() << MSG::dec << " (phi " << phi << " to " << phi_patch <<")" );
277  return true;
278  }//end if isEmtpy()
279  }//end if neighbor is good
280  }// end for loop
281  ATH_MSG_ERROR ( "All phi-neighbors of channel 0x" << MSG::hex << chid.get_compact() << MSG::dec
282  << " are either absent or bad." );
283  return false;
284  }catch(LArID_Exception& except) {
285  ATH_MSG_ERROR ( "LArID_Exception caught!" );
286  return false;
287  }
288  }
289  else if (m_patchMethod==PhiAverage) {
290  LArCondObj patch;
291  if (!getAverage(chid,gain,patch,bcCont,cabling)){
292  ATH_MSG_ERROR ( "Failed get phi-average!" );
293  return false;
294  } else {
295  ATH_MSG_DEBUG ( "Got a phi-average..." );
296  }
297  ATH_CHECK( m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel), false );
298  return true;
299  }
300  else if (m_patchMethod==FEBAverage) {
301  LArCondObj patch;
302  if (!getAverage(chid,gain,patch,bcCont, cabling, false)){
303  ATH_MSG_ERROR ( "Failed get FEB-average!" );
304  return false;
305  } else {
306  ATH_MSG_DEBUG ( "Got a FEB-average..." );
307  }
308  ATH_CHECK( m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel), false );
309  return true;
310  }
311  else if (m_patchMethod==SetZero) {
312  LArCondObj patch;
313  if (!setZero(chid, gain, patch)){
314  ATH_MSG_ERROR ( "Failed set Zero!" );
315  return false;
316  } else {
317  ATH_MSG_DEBUG ( "Set zero ..." );
318  }
319  ATH_CHECK( m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel), false );
320  return true;
321  }
322  else //failed...
323  ATH_MSG_ERROR ( "Unknown correction method." );
324  return false;
325 }
326 
327 
328 template<class CONDITIONSCONTAINER>
329 std::vector<HWIdentifier>& LArCalibPatchingAlg<CONDITIONSCONTAINER>::getPhiRing(const HWIdentifier chid, const LArBadChannelCont* bcCont, const LArOnOffIdMapping* cabling, unsigned distance) {
330  if (distance==0) distance=1;
331  m_idList.clear();
332  try {
333  const Identifier id=cabling->cnvToIdentifier(chid);
334  int eta,phi, phi_min, phi_max;
335  Identifier regionID;
336  regionID=m_caloId->region_id(id);
337  eta = m_caloId->eta(id);
338  phi = m_caloId->phi(id);
339  phi_min =m_caloId->phi_min(regionID);
340  phi_max =m_caloId->phi_max(regionID);
341  ATH_MSG_VERBOSE ( "Assembling phi-ring for eta=" << eta << " phi=" << phi );
342  //std::cout << "Assembling phi-ring for eta=" << eta << " phi=" << phi << std::endl;
343  if (eta==CaloCell_ID::NOT_VALID || phi==CaloCell_ID::NOT_VALID || phi_min==CaloCell_ID::NOT_VALID || phi_max==CaloCell_ID::NOT_VALID) {
344  ATH_MSG_ERROR ( "CaloCell_ID returned NOT_VALID for offline id 0x"<< std::hex << id.get_compact()
345  <<", online id 0x" << chid.get_compact() << std::dec );
346  return m_idList;
347  }
348 
349  if ((phi_max-phi_min)%distance) {
350  ATH_MSG_ERROR ( "Can't divide " << (phi_min-phi_max) << " by " << distance );
351  return m_idList;
352  }
353 
354  int nSteps=(phi_max-phi_min)/distance;
355 
356  for (int i=1;i<=nSteps;i++) {
357  int phi_patch=phi+i*distance;
358  if (phi_patch>phi_max) phi_patch=phi_patch-phi_max+phi_min-1;
359  ATH_MSG_VERBOSE ( "i=" << i << " Adding cell with phi="
360  << phi_patch << " eta=" << eta );
361  //std::cout << "i=" << i << " Adding cell with phi="
362  // << phi_patch << " eta=" << eta << std::endl;
363  Identifier patch_id=m_caloId->cell_id(regionID,eta,phi_patch);
364  HWIdentifier chid_patch=cabling->createSignalChannelID(patch_id);
365  if (bcCont->status(chid_patch).good()) {
366  m_idList.push_back(chid_patch);
367  }
368  else
369  ATH_MSG_VERBOSE ( "This cell is bad as well. Ignored." );
370  }//end loop over phi-steps
371 
372  }catch(LArID_Exception& except) {
373  ATH_MSG_ERROR ( "LArID_Exception caught!" );
374  }
375  return m_idList;
376 }
377 
378 template<class CONDITIONSCONTAINER>
379 std::vector<HWIdentifier>& LArCalibPatchingAlg<CONDITIONSCONTAINER>::getFEBChans(const HWIdentifier chid, const LArBadChannelCont* bcCont) {
380  m_idList.clear();
381  HWIdentifier febid = m_onlineHelper->feb_Id(chid);
382  ATH_MSG_VERBOSE ( "Assembling list of channels for FEB=" << febid );
383  for (int i=0;i<128;++i) {
384  HWIdentifier fchan = m_onlineHelper->channel_Id(febid,i);
385  if(fchan == chid) continue;
386  ATH_MSG_VERBOSE ( " Adding channel =" << i );
387  if (bcCont->status(fchan).good()) {
388  m_idList.push_back(fchan);
389  } else {
390  ATH_MSG_VERBOSE ( "This channel is bad as well. Ignored." );
391  }
392  }//end loop over chans
393 
394  return m_idList;
395 }
396 
397 
398 template<class CONDITIONSCONTAINER>
399 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::getAverage(const HWIdentifier chid, const int gain, LArRampP1& patch, const LArBadChannelCont* bcCont, const LArOnOffIdMapping* cabling, bool isphi) {
400 
401  std::vector<HWIdentifier>& symCells =
402  isphi ? getPhiRing(chid, bcCont, cabling) : getFEBChans(chid, bcCont);
403  if (symCells.empty()) {
404  ATH_MSG_ERROR ( "No symmetry cells found!" );
405  return false;
406  }
407  size_t s=m_contIn->get(symCells[0],gain).m_vRamp.size();
408  patch.m_vRamp.clear();
409  patch.m_vRamp.resize(s);
410  unsigned nCells=0;
411  for (HWIdentifier hwid : symCells) {
412  const LArRampP1& ramp=m_contIn->get(hwid,gain);
413  if (ramp.m_vRamp.size()==0) continue; //This one is empty...
414  if (ramp.m_vRamp.size()!=s) {
415  if(isphi) {
416  ATH_MSG_WARNING ("Cell with same phi but different size of ramp polynom found!" );
417  } else {
418  ATH_MSG_WARNING ("Cell with same FEB but different size of ramp polynom found!" );
419  }
420  continue;
421  }
422  msg() << MSG::DEBUG << "Adding cell 0x"<< std::hex << hwid.get_compact() << std::dec << " Ramp:";
423  for (size_t i=0;i<s;i++) {
424  patch.m_vRamp[i]+=ramp.m_vRamp[i];
425  msg() << MSG::DEBUG << ramp.m_vRamp[i] << " ";
426  }
427  msg() << MSG::DEBUG << endmsg;
428  nCells++;
429  }
430  if (nCells==0) {
431  if(isphi) {
432  ATH_MSG_ERROR ( "No good ramp with same phi found!" );
433  } else {
434  ATH_MSG_ERROR ( "No good ramp with same FEB found!" );
435  }
436  return false;
437  }
438  for (size_t i=0;i<s;i++)
439  patch.m_vRamp[i]=patch.m_vRamp[i]/nCells;
440 
441  //FIXME: We should somehow watch the rms....
442  msg() << MSG::INFO << "Patched Ramp (based on " << nCells << " channels):" ;
443  for (size_t i=0;i<s;i++)
444  msg() << MSG::INFO << " " << patch.m_vRamp[i];
445  msg() << MSG::INFO << endmsg;
446  return true;
447 }
448 
449 
450 template<class CONDITIONSCONTAINER>
451 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::getAverage(const HWIdentifier chid, const int gain, LArOFCP1& patch, const LArBadChannelCont* bcCont, const LArOnOffIdMapping* cabling, bool /*isphi*/) {
452 
453  std::vector<HWIdentifier>& symCells=getPhiRing(chid, bcCont, cabling);
454 
455  if (symCells.empty()) {
456  ATH_MSG_ERROR ( "No symmetry cells found!" );
457  return false;
458  }
459 
460  const size_t nPhases=m_contIn->get(symCells[0],gain).m_vOFC_a.size();
461  if (!nPhases) {
462  ATH_MSG_ERROR ( "OFC of neighbor nPhase=0!" );
463  return false;
464  }
465  const size_t nSamples=m_contIn->get(symCells[0],gain).mvOFC_a[0].size();
466  if (!nSamples) {
467  ATH_MSG_ERROR ( "OFC of neighbor nSamples=0!" );
468  return false;
469  }
470 
471  float timeOffset = m_contIn->get(symCells[0],gain).m_timeOffset;
472  float timeBinWidth = m_contIn->get(symCells[0],gain).m_timeBinWidth;
473  std::vector<std::vector<float> > ofc_a;
474  std::vector<std::vector<float> > ofc_b;
475  ofc_a.resize(nPhases,std::vector<float>(nSamples));
476  ofc_b.resize(nPhases,std::vector<float>(nSamples));
477 
478  unsigned nCells=0;
479  for (HWIdentifier hwid : symCells) {
480  const LArOFCP1& ofc=m_contIn->get(hwid,gain);
481  if (ofc.OFC_aSize()==0 || ofc.OFC_bSize()==0) continue; //This one is empty...
482  if (ofc.OFC_aSize()!=nPhases) {
483  ATH_MSG_WARNING ("Cell with same phi but different nPhases found! Ignored" );
484  continue;
485  }
486  if (ofc.timeOffset()!=timeOffset) {
487  ATH_MSG_WARNING ("Cell with same phi but different time-offset found! Ignored" );
488  continue;
489  }
490  if (ofc.timeBinWidth()!=timeBinWidth) {
491  ATH_MSG_WARNING ("Cell with same phi but different time-offset found! Ignored" );
492  continue;
493  }
494 
495  ATH_MSG_DEBUG ( "Adding cell 0x"<< std::hex << hwid.get_compact() << std::dec );
496  for (size_t iPhase=0;iPhase<nPhases;++iPhase) {
497  //Check size of vector?
498  for (size_t iSample=0;iSample<nSamples;++iSample) {
499  ofc_a[iPhase][iSample]+=ofc.OFC_a(iPhase)[iSample];
500  ofc_b[iPhase][iSample]+=ofc.OFC_b(iPhase)[iSample];
501  }
502  }
503  nCells++;
504  }
505  if (nCells==0) {
506  ATH_MSG_ERROR ( "No good OFC set with same phi found!" );
507  return false;
508  }
509 
510  for (size_t iPhase=0;iPhase<nPhases;++iPhase) {
511  //Check size of vector?
512  for (size_t iSample=0;iSample<nSamples;++iSample) {
513  ofc_a[iPhase][iSample]/=nCells;
514  ofc_b[iPhase][iSample]/=nCells;
515  }
516  }
517  //FIXME: We should somehow watch the rms....
518 
519  LArOFCP1 tmp (timeOffset,
520  timeBinWidth,
521  ofc_a, ofc_b);
522  patch.setFrom (tmp);
523 
524  return true;
525 }
526 
527 template<class CONDITIONSCONTAINER>
528 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::getAverage(const HWIdentifier chid, const int gain, LArCaliWaveVec& patch,const LArBadChannelCont* bcCont, const LArOnOffIdMapping* cabling, bool /*isphi*/) {
529 
530  const std::vector<HWIdentifier>& symCells=getPhiRing(chid, bcCont, cabling);
531 
532 
533  if (symCells.empty()) {
534  ATH_MSG_ERROR ( "No symmetry cells found!" );
535  return false;
536  }
537  patch.clear();
538 
539  struct perDAC_t {
540  std::vector<std::tuple<HWIdentifier,double,const LArCaliWave*> > tmax_wave; //Identifier, tmax and ptr to wave, all neighbors
541  double tmaxAvg=0; //average peak time of all neighbors
542  };
543 
544  LArWaveHelper wHelper;
545 
546  // Organize waves per DAC and calculate tmax (peaking time)
547  std::map<int,perDAC_t> neighbors_per_dac; //In most cases, there is only one DAC, eg one entry in this map
548 
549  ATH_MSG_DEBUG(" symCells size "<<symCells.size());
550  for (HWIdentifier hwid : symCells) {
551  for (const LArCaliWave& cwave : m_contIn->get(hwid,gain)) {
552  ATH_MSG_VERBOSE("found wave in channel " << m_onlineHelper->channel_name(hwid) << ", gain " << gain);
553  const int ourDAC = cwave.getDAC();
554  double tmax=-1;
555  wHelper.getDMax(cwave, tmax);
556  if (tmax > 0 ) {
557  auto& dacWave=neighbors_per_dac[ourDAC];
558  dacWave.tmax_wave.emplace_back(hwid,tmax,&cwave);
559  dacWave.tmaxAvg+=tmax;
560  }
561  else {
562  ATH_MSG_WARNING("Ignoring wave with peak-time=" << tmax << ", DAC=" << ourDAC << " found in channel " << m_onlineHelper->channel_name(hwid) << ", gain " << gain);
563  }
564  }//end loop over DACs
565  }// end loop over sym-cells
566 
567  ATH_MSG_DEBUG(" neighbors_per_dac size "<<neighbors_per_dac.size());
568 
569  for (auto& dacWave : neighbors_per_dac) {
570  dacWave.second.tmaxAvg/=dacWave.second.tmax_wave.size();
571  ATH_MSG_DEBUG("Average tmax computed " << dacWave.second.tmaxAvg << " for DAC=" << dacWave.first << ", to patch channel " << m_onlineHelper->channel_name(chid) << ", gain " << gain);
572  }
573 
574  //Align waves accoring to their peak-time and sum them
575  std::vector<std::pair<LArCaliWave,unsigned> > alignedWaveSums;
576 
577  for (const auto& dacWave : neighbors_per_dac) {//loop over DAC values
578  const int& dac=dacWave.first;
579  const perDAC_t& neighbors=dacWave.second;
580  const double& tmaxAvg=neighbors.tmaxAvg;
581  bool first=true;
582 
583  for (const auto& [hwid, tmax, wave] : neighbors.tmax_wave) {
584  if (std::fabs(tmaxAvg-tmax) > wave->getWave().size()*wave->getDt()/2.0) {//Don't allow very long time shifts
585  ATH_MSG_WARNING("Peaking time of symmetric channel " << m_onlineHelper->channel_name(hwid)
586  << ", DAC=" << dac << ", gain=" << gain << " is too far off the average (" << std::fabs(tmaxAvg-tmax) << "). Ignoring.");
587  continue;
588  }
589  if (first) {
590  //First (useable) wave for this DAC value. Initialize a LArCaliWave object for it
591  alignedWaveSums.emplace_back(LArCaliWave(wHelper.Dtranslate(*wave, tmaxAvg - tmax).getWave(),wave->getDt(),wave->getDAC(),wave->getIsPulsedInt(),wave->getFlag()),1);
592  ATH_MSG_DEBUG("Adding wave of symmetric channel " << m_onlineHelper->channel_name(hwid)
593  << ", DAC=" << dac << ", gain=" << gain << " shifted by " << tmaxAvg-tmax);
594  first=false;
595  }
596  else {
597  //Subsequent waves fro this DAC value: Add them.
598  alignedWaveSums.back().first+=wHelper.Dtranslate(*wave, tmaxAvg - tmax);
599  alignedWaveSums.back().second++;
600  ATH_MSG_DEBUG("Summing wave of symmetric channel " << m_onlineHelper->channel_name(hwid)
601  << ", DAC=" << dac << ", gain=" << gain << " shifted by " << tmaxAvg-tmax);
602  }
603  }//end loop over symmetic waves for one dac value
604  if (first) {
605  ATH_MSG_ERROR("Cannot calculate patch wave for channel " << m_onlineHelper->channel_name(chid) << ", gain="<< gain << ", DAC=" << dac << ", no usable neighbors found");
606  return false;
607  }
608 
609  }//end loop over DAC values
610 
611  //Final loop to divide wave by number-of-waves to get the average, then push-back into return container
612  for (auto& waveSum : alignedWaveSums) { //Loop over DAC values
613  LArCaliWave& wave=waveSum.first;
614  wave*=(1./waveSum.second);
615  ATH_MSG_INFO("Calculated average wave for channel " << m_onlineHelper->channel_name(chid) << ", gain="<< gain << ", DAC=" << waveSum.first.getDAC()
616  << ", based on " << waveSum.second << " neighbors");
617  patch.push_back(wave);
618  }
619  return true;
620 }
621 
622 template<class CONDITIONSCONTAINER>
623 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::getAverage(const HWIdentifier chid, const int gain, LArAutoCorrP1& patch, const LArBadChannelCont* bcCont, const LArOnOffIdMapping* /*cabling*/, bool isphi) {
624 
625  ATH_MSG_DEBUG ( "Starting getAverage for LArAutoCorr" );
626  if(isphi) {
627  ATH_MSG_ERROR ( "No phi-average for AutoCorr!" );
628  return false;
629  }
630  std::vector<HWIdentifier>& symCells = getFEBChans(chid, bcCont);
631  if (symCells.empty()) {
632  ATH_MSG_ERROR ( "No symmetry cells found!" );
633  return false;
634  }
635  size_t s=m_contIn->get(symCells[0],gain).m_vAutoCorr.size();
636  patch.m_vAutoCorr.clear();
637  patch.m_vAutoCorr.resize(s);
638  unsigned nCells=0;
639  for (HWIdentifier hwid : symCells) {
640  const LArAutoCorrP1& ac=m_contIn->get(hwid,gain);
641  if (ac.m_vAutoCorr.size()==0) continue; //This one is empty...
642  if (ac.m_vAutoCorr.size()!=s) {
643  ATH_MSG_WARNING ("Cell with same FEB but different size of autocorr found!" );
644  continue;
645  }
646  msg() << MSG::DEBUG << "Adding cell 0x"<< std::hex << hwid.get_compact() << std::dec << " AC:";
647  for (size_t i=0;i<s;i++) {
648  patch.m_vAutoCorr[i]+=ac.m_vAutoCorr[i];
649  msg() << MSG::DEBUG << ac.m_vAutoCorr[i] << " ";
650  }
651  msg() << MSG::DEBUG << endmsg;
652  nCells++;
653  }
654  if (nCells==0) {
655  ATH_MSG_ERROR ( "No good autocorr with same FEB found!" );
656  return false;
657  }
658  for (size_t i=0;i<s;i++)
659  patch.m_vAutoCorr[i]=patch.m_vAutoCorr[i]/nCells;
660 
661  //FIXME: We should somehow watch the rms....
662  msg() << MSG::INFO << "Patched autocorr (based on " << nCells << " channels):" ;
663  for (size_t i=0;i<s;i++)
664  msg() << MSG::INFO << " " << patch.m_vAutoCorr[i];
665  msg() << MSG::INFO << endmsg;
666  return true;
667 }
668 
669 #ifdef LARRAWCONDITIONS_LARMPHYSOVERMCALP
670 template<class CONDITIONSCONTAINER>
671 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::getAverage(const HWIdentifier chid, const int gain, LArMphysOverMcalP1& patch, const LArBadChannelCont* bcCont, const LArOnOffIdMapping* cabling, bool isphi) {
672 
673  std::vector<HWIdentifier>& symCells=getPhiRing(chid, bcCont, cabling);
674 
675  patch.m_MphysOverMcal=0;
676 
677  unsigned nCells=0;
678  for (HWIdentifier hwid : symCells) {
679  const float mPmC=m_contIn->get(hwid,gain);
680  if (mPmC>0) {
681  patch.m_MphysOverMcal+=mPmC;
682  nCells++;
683  }
684  }
685 
686  if (nCells==0) {
687  ATH_MSG_ERROR ( "No good symmetry cells found!" );
688  return false;
689  }
690  patch.m_MphysOverMcal/=nCells;
691  return true;
692 }
693 #endif
694 
695 
696 
697 #ifdef LARRAWCONDITIONS_LARSINGLEFLOATP
698 template<class CONDITIONSCONTAINER>
699 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::getAverage(const HWIdentifier chid, const int gain, LArSingleFloatP& patch, const LArBadChannelCont* bcCont, const LArOnOffIdMapping* cabling, bool /*isphi*/) {
700 
701  std::vector<HWIdentifier>& symCells=getPhiRing(chid, bcCont, cabling);
702 
703  patch.m_data=0;
704 
705  unsigned nCells=0;
706  for (HWIdentifier hwid : symCells) {
707  const LArSingleFloatP& sf=m_contIn->get(hwid,gain);
708  if (!sf.isEmpty()) {
709  patch.m_data+=sf.m_data;
710  nCells++;
711  }
712  }
713 
714  if (nCells==0) {
715  ATH_MSG_ERROR ( "No good symmetry cells found!" );
716  return false;
717  }
718  patch.m_data/=nCells;
719  return true;
720 }
721 #endif
722 
723 template<class CONDITIONSCONTAINER>
724 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(const HWIdentifier chid, const int gain, LArRampP1& patch) {
725 
726  size_t s=m_contIn->get(chid,gain).m_vRamp.size();
727  patch.m_vRamp.clear();
728  patch.m_vRamp.resize(s);
729  for (size_t i=0; i<s; ++i) patch.m_vRamp[i] = 0.;
730  return true;
731 }
732 
733 template<class CONDITIONSCONTAINER>
734 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(const HWIdentifier chid, const int gain, LArOFCP1& patch) {
735 
736  const size_t nPhases=m_contIn->get(chid,gain).m_vOFC_a.size();
737  if (!nPhases) {
738  ATH_MSG_ERROR ( "OFC of nPhase=0 !" );
739  return false;
740  }
741  const size_t nSamples=m_contIn->get(chid,gain).mvOFC_a[0].size();
742  if (!nSamples) {
743  ATH_MSG_ERROR ( "OFC of nSamples=0 !" );
744  return false;
745  }
746 
747  LArOFCP1 newvals (patch.timeOffset(), patch.timeBinWidth(),
748  std::vector<std::vector<float> > (nPhases, std::vector<float> (nSamples, 0)),
749  std::vector<std::vector<float> > (nPhases, std::vector<float> (nSamples, 0)));
750  patch.setFrom (newvals);
751  return true;
752 }
753 
754 template<class CONDITIONSCONTAINER>
755 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(const HWIdentifier /*chid*/, const int /*gain*/, LArCaliWaveVec& /*patch*/) {
756  ATH_MSG_ERROR ( "Not implemented, should not come here !!!");
757  return false;
758 }
759 
760 template<class CONDITIONSCONTAINER>
761 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(const HWIdentifier chid, const int gain, LArAutoCorrP1& patch) {
762 
763  size_t s=m_contIn->get(chid,gain).m_vAutoCorr.size();
764  patch.m_vAutoCorr.clear();
765  patch.m_vAutoCorr.resize(s);
766  for (size_t i=0; i<s; ++i) patch.m_vAutoCorr[i] = 0.;
767  return true;
768 }
769 
770 #ifdef LARRAWCONDITIONS_LARSINGLEFLOATP
771 template<class CONDITIONSCONTAINER>
772 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(LArSingleFloatP& patch) {
773  patch.m_data=0.;
774  return true;
775 }
776 #endif
777 
778 
779 template<class CONDITIONSCONTAINER>
780 StatusCode LArCalibPatchingAlg<CONDITIONSCONTAINER>::setSymlink(const LArRampComplete* ramp) const {
781  ATH_CHECK( detStore()->symLink(ramp, static_cast<const ILArRamp*>(ramp)) );
782  return StatusCode::SUCCESS;
783 }
784 
785 
786 template<class CONDITIONSCONTAINER>
787 StatusCode LArCalibPatchingAlg<CONDITIONSCONTAINER>::setSymlink(const LArOFCComplete* ofc) const {
788  ATH_CHECK( detStore()->symLink(ofc, static_cast<const ILArOFC*>(ofc)) );
789  return StatusCode::SUCCESS;
790 }
791 
792 
793 template<class CONDITIONSCONTAINER>
794 StatusCode LArCalibPatchingAlg<CONDITIONSCONTAINER>::setSymlink(const LArMphysOverMcalComplete* ramp) const {
795  ATH_CHECK( detStore()->symLink(ramp, static_cast<const ILArMphysOverMcal*>(ramp)) );
796  return StatusCode::SUCCESS;
797 }
798 
799 template<class CONDITIONSCONTAINER>
800 StatusCode LArCalibPatchingAlg<CONDITIONSCONTAINER>::setSymlink(const LArAutoCorrComplete* ac) const {
801  ATH_CHECK( detStore()->symLink(ac, static_cast<const ILArAutoCorr*>(ac)) );
802  return StatusCode::SUCCESS;
803 }
804 
805