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