1 //Dear emacs, this is -*-c++-*-
 
    3   Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
 
    8 template<class CONDITIONSCONTAINER>
 
    9 LArCalibPatchingAlg<CONDITIONSCONTAINER>::LArCalibPatchingAlg (const std::string& name, ISvcLocator* pSvcLocator) : 
 
   10   AthAlgorithm(name,pSvcLocator),
 
   15   m_patchMethod(PhiAverage) { }
 
   18 template<class CONDITIONSCONTAINER>
 
   19 StatusCode LArCalibPatchingAlg<CONDITIONSCONTAINER>::initialize() {
 
   21   ATH_CHECK( m_BCKey.initialize() );
 
   22   ATH_CHECK( m_cablingKey.initialize() );
 
   23   ATH_CHECK( m_CLKey.initialize() );
 
   26   if(m_patchMethodProp=="FEBNeighbor") {
 
   27     m_patchMethod=FEBNeighbor;
 
   28     return StatusCode::SUCCESS;
 
   30   else if (m_patchMethodProp=="PhiNeighbor") {
 
   31     m_patchMethod=PhiNeighbor;
 
   32     return StatusCode::SUCCESS;
 
   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;
 
   40     m_patchMethod=PhiAverage;
 
   41     return StatusCode::SUCCESS;
 
   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;
 
   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;
 
   57     m_patchMethod=SetZero;
 
   58     return StatusCode::SUCCESS;
 
   61   ATH_MSG_ERROR ( "Unknown patching method: " << m_patchMethodProp );
 
   62   ATH_MSG_ERROR ( "Allowed values: [Empty, FEBNeighbor, PhiNeighbor, PhiAverage, SetZero]" );
 
   64   return StatusCode::FAILURE; 
 
   67 template<class CONDITIONSCONTAINER>
 
   68 StatusCode LArCalibPatchingAlg<CONDITIONSCONTAINER>::stop() {
 
   69   ATH_MSG_INFO ( "Entering LArCalibPatchingAlg" );
 
   71      ATH_CHECK( detStore()->retrieve(m_onlineHelper, "LArOnline_SuperCellID") );
 
   72      ATH_CHECK( detStore()->retrieve(m_caloId, "CaloCell_SuperCell_ID") );
 
   74      ATH_CHECK( detStore()->retrieve(m_onlineHelper, "LArOnlineID") );
 
   75      ATH_CHECK( detStore()->retrieve(m_caloId, "CaloCell_ID") );
 
   78   if(m_isSC) m_bcMask.setSC();
 
   79   ATH_CHECK(m_bcMask.buildBitMask(m_problemsToPatch,msg()));
 
   81   const EventContext& ctx = Gaudi::Hive::currentContext();
 
   83   SG::ReadCondHandle<LArBadChannelCont> readHandle{m_BCKey, ctx};
 
   84   const LArBadChannelCont *bcCont {*readHandle};
 
   86      ATH_MSG_ERROR( "Do not have Bad chan container !!!" );
 
   87      return StatusCode::FAILURE;
 
   90   SG::ReadCondHandle<LArOnOffIdMapping> cablingHdl{m_cablingKey, ctx};
 
   91   const LArOnOffIdMapping* cabling = *cablingHdl;
 
   93      ATH_MSG_ERROR( "Do not have OnOff Id mapping !!!" );
 
   94      return StatusCode::FAILURE;
 
   97   SG::ReadCondHandle<LArCalibLineMapping> clHdl{m_CLKey, ctx};
 
   98   const LArCalibLineMapping *clCont {*clHdl};
 
  100      ATH_MSG_ERROR( "Do not have calib line mapping !!!" );
 
  101      return StatusCode::FAILURE;
 
  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
 
  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 );
 
  116   else { //Same container for reading and writing
 
  118       ATH_CHECK( detStore()->retrieve(m_contIn,m_containerKey) ); //const-retrieve
 
  119       m_contOut=const_cast<CONDITIONSCONTAINER*>(m_contIn);
 
  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  << "'" );
 
  128   LArBadChanBitPacking packing;
 
  129   LArBadChanSCBitPacking scpacking;
 
  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 );
 
  147       ATH_MSG_WARNING ( "Failed to patch channel 0x" << MSG::hex << chid.get_identifier32().get_compact() << MSG::dec <<" Gain:" << igain );
 
  149       }//end if channel is in bad-channel database
 
  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 );
 
  160           ATH_MSG_WARNING ( "Failed to patch channel 0x" << MSG::hex << chid.get_identifier32().get_compact() << MSG::dec <<" Gain:" << igain );
 
  162       }//end if m_patchAllMissing
 
  164         ATH_MSG_ERROR ( "Channel remains un-patched!" );
 
  166     }//end loop over all channels
 
  167   }//end loop over all gains
 
  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;
 
  178   ATH_MSG_INFO ( "Done with LArCalibPatchingAlg" );
 
  179   ATH_MSG_DEBUG ( detStore()->dump() );
 
  180   return StatusCode::SUCCESS;
 
  183 template<class CONDITIONSCONTAINER>
 
  184 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::patch(const HWIdentifier chid, const int gain, const LArBadChannelCont* bcCont, const LArOnOffIdMapping* cabling, const LArCalibLineMapping *clCont) {
 
  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
 
  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);
 
  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); 
 
  208         ATH_MSG_ERROR ( "Failed to insert correction for channel 0x" << MSG::hex << chid.get_compact() 
 
  209                             << MSG::dec <<", gain " << gain << "." );
 
  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 );
 
  215       }//end if patch connected and good
 
  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 << "." );
 
  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 );
 
  232     }//end if patch connected and good
 
  235     ATH_MSG_ERROR ( "None of the FEB neighbors is good!" );
 
  237   } else if (m_patchMethod==PhiNeighbor) {
 
  238     //    (*m_log) << MSG::ERROR << "Patching Method 'Phi-neighbor' not yet implemented." << endmsg;
 
  240       const Identifier id=cabling->cnvToIdentifier(chid);
 
  241       int eta, phi, phi_min, phi_max, phi_range;
 
  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 );
 
  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); 
 
  272           ATH_MSG_ERROR ( "Failed to insert correction for channel 0x" << MSG::hex << chid.get_compact() 
 
  273                               << MSG::dec << ", gain " << gain << "." );
 
  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 <<")" );
 
  279      }//end if neighbor is good
 
  281       ATH_MSG_ERROR ( "All phi-neighbors of channel 0x" << MSG::hex << chid.get_compact() << MSG::dec 
 
  282                       << " are either absent or bad." );
 
  284     }catch(LArID_Exception& except) {
 
  285       ATH_MSG_ERROR ( "LArID_Exception caught!" );
 
  289   else if (m_patchMethod==PhiAverage) {
 
  291     if (!getAverage(chid,gain,patch,bcCont,cabling)){
 
  292       ATH_MSG_ERROR ( "Failed get phi-average!" );
 
  295       ATH_MSG_DEBUG ( "Got a phi-average..." );
 
  297     ATH_CHECK( m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel), false );
 
  300   else if (m_patchMethod==FEBAverage) {
 
  302     if (!getAverage(chid,gain,patch,bcCont, cabling, false)){
 
  303       ATH_MSG_ERROR ( "Failed get FEB-average!" );
 
  306       ATH_MSG_DEBUG ( "Got a FEB-average..." );
 
  308     ATH_CHECK( m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel), false );
 
  311   else if (m_patchMethod==SetZero) {
 
  313     if (!setZero(chid, gain, patch)){
 
  314       ATH_MSG_ERROR ( "Failed set Zero!" );
 
  317       ATH_MSG_DEBUG ( "Set zero ..." );
 
  319     ATH_CHECK( m_contOut->insertCorrection(chid,patch,gain,m_useCorrChannel), false );
 
  323     ATH_MSG_ERROR ( "Unknown correction method." );
 
  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;
 
  333     const Identifier id=cabling->cnvToIdentifier(chid);
 
  334     int eta,phi, phi_min, phi_max;
 
  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 );
 
  349     if ((phi_max-phi_min)%distance) {
 
  350       ATH_MSG_ERROR ( "Can't divide " << (phi_min-phi_max) << " by " << distance );
 
  354     int nSteps=(phi_max-phi_min)/distance;
 
  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);
 
  369         ATH_MSG_VERBOSE ( "This cell is bad as well. Ignored." );
 
  370     }//end loop over phi-steps
 
  372   }catch(LArID_Exception& except) {
 
  373     ATH_MSG_ERROR ( "LArID_Exception caught!" );
 
  378 template<class CONDITIONSCONTAINER>
 
  379 std::vector<HWIdentifier>& LArCalibPatchingAlg<CONDITIONSCONTAINER>::getFEBChans(const HWIdentifier chid, const LArBadChannelCont* bcCont) {
 
  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);
 
  390         ATH_MSG_VERBOSE ( "This channel is bad as well. Ignored." );
 
  392   }//end loop over chans
 
  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) {
 
  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!" );
 
  407   size_t s=m_contIn->get(symCells[0],gain).m_vRamp.size();
 
  408   patch.m_vRamp.clear();
 
  409   patch.m_vRamp.resize(s);
 
  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) {
 
  416         ATH_MSG_WARNING ("Cell with same phi but different size of ramp polynom found!" );
 
  418         ATH_MSG_WARNING ("Cell with same FEB but different size of ramp polynom found!" );
 
  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] << " ";
 
  427     msg() << MSG::DEBUG << endmsg;
 
  432       ATH_MSG_ERROR ( "No good ramp with same phi found!" );
 
  434       ATH_MSG_ERROR ( "No good ramp with same FEB found!" );
 
  438  for (size_t i=0;i<s;i++)
 
  439    patch.m_vRamp[i]=patch.m_vRamp[i]/nCells;
 
  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;
 
  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*/) {
 
  453   std::vector<HWIdentifier>& symCells=getPhiRing(chid, bcCont, cabling);  
 
  455   if (symCells.empty()) {
 
  456     ATH_MSG_ERROR ( "No symmetry cells found!" );
 
  460   const size_t nPhases=m_contIn->get(symCells[0],gain).m_vOFC_a.size();
 
  462     ATH_MSG_ERROR ( "OFC of neighbor nPhase=0!" );
 
  465   const size_t nSamples=m_contIn->get(symCells[0],gain).mvOFC_a[0].size();
 
  467     ATH_MSG_ERROR ( "OFC of neighbor nSamples=0!" );
 
  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));
 
  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" );
 
  486     if (ofc.timeOffset()!=timeOffset) {
 
  487       ATH_MSG_WARNING ("Cell with same phi but different time-offset found! Ignored" );
 
  490     if (ofc.timeBinWidth()!=timeBinWidth) {
 
  491       ATH_MSG_WARNING ("Cell with same phi but different time-offset found! Ignored" );
 
  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];
 
  506     ATH_MSG_ERROR ( "No good OFC set with same phi found!" );
 
  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;
 
  517  //FIXME: We should somehow watch the rms....
 
  519   LArOFCP1 tmp (timeOffset,
 
  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*/) {
 
  530   const std::vector<HWIdentifier>& symCells=getPhiRing(chid, bcCont, cabling);  
 
  533   if (symCells.empty()) {
 
  534     ATH_MSG_ERROR ( "No symmetry cells found!" );
 
  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
 
  544   LArWaveHelper wHelper;
 
  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
 
  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();
 
  555       wHelper.getDMax(cwave, tmax);
 
  557     auto& dacWave=neighbors_per_dac[ourDAC];
 
  558     dacWave.tmax_wave.emplace_back(hwid,tmax,&cwave);
 
  559     dacWave.tmaxAvg+=tmax;
 
  562     ATH_MSG_WARNING("Ignoring wave with peak-time=" << tmax << ", DAC=" << ourDAC << " found in channel " << m_onlineHelper->channel_name(hwid) << ", gain " << gain);
 
  564     }//end loop over DACs
 
  565   }// end loop over sym-cells
 
  567   ATH_MSG_DEBUG(" neighbors_per_dac size "<<neighbors_per_dac.size());
 
  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);
 
  574   //Align waves accoring to their peak-time and sum them
 
  575   std::vector<std::pair<LArCaliWave,unsigned> > alignedWaveSums;
 
  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;
 
  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.");
 
  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);
 
  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);
 
  603     }//end loop over symmetic waves for one dac value
 
  605       ATH_MSG_ERROR("Cannot calculate patch wave for channel " <<  m_onlineHelper->channel_name(chid)  << ", gain="<< gain << ", DAC=" << dac << ", no usable neighbors found");
 
  609   }//end loop over DAC values
 
  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);
 
  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) {
 
  625   ATH_MSG_DEBUG ( "Starting getAverage for LArAutoCorr" );
 
  627     ATH_MSG_ERROR ( "No phi-average for AutoCorr!" );
 
  630   std::vector<HWIdentifier>& symCells = getFEBChans(chid, bcCont);
 
  631   if (symCells.empty()) {
 
  632     ATH_MSG_ERROR ( "No symmetry cells found!" );
 
  635   size_t s=m_contIn->get(symCells[0],gain).m_vAutoCorr.size();
 
  636   patch.m_vAutoCorr.clear();
 
  637   patch.m_vAutoCorr.resize(s);
 
  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!" );
 
  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] << " ";
 
  651     msg() << MSG::DEBUG << endmsg;
 
  655       ATH_MSG_ERROR ( "No good autocorr with same FEB found!" );
 
  658   for (size_t i=0;i<s;i++)
 
  659    patch.m_vAutoCorr[i]=patch.m_vAutoCorr[i]/nCells;
 
  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;
 
  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) {
 
  673   std::vector<HWIdentifier>& symCells=getPhiRing(chid, bcCont, cabling);  
 
  675   patch.m_MphysOverMcal=0;
 
  678   for (HWIdentifier hwid : symCells) {
 
  679     const float mPmC=m_contIn->get(hwid,gain);
 
  681       patch.m_MphysOverMcal+=mPmC;
 
  687    ATH_MSG_ERROR ( "No good symmetry cells found!" );
 
  690  patch.m_MphysOverMcal/=nCells;
 
  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*/) {
 
  701   std::vector<HWIdentifier>& symCells=getPhiRing(chid, bcCont, cabling);  
 
  706   for (HWIdentifier hwid : symCells) {
 
  707     const LArSingleFloatP& sf=m_contIn->get(hwid,gain);
 
  709       patch.m_data+=sf.m_data;
 
  715    ATH_MSG_ERROR ( "No good symmetry cells found!" );
 
  718  patch.m_data/=nCells;
 
  723 template<class CONDITIONSCONTAINER>
 
  724 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(const HWIdentifier chid, const int gain, LArRampP1& patch) {
 
  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.;
 
  733 template<class CONDITIONSCONTAINER>
 
  734 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(const HWIdentifier chid, const int gain, LArOFCP1& patch) {
 
  736   const size_t nPhases=m_contIn->get(chid,gain).m_vOFC_a.size();
 
  738     ATH_MSG_ERROR ( "OFC of nPhase=0 !" );
 
  741   const size_t nSamples=m_contIn->get(chid,gain).mvOFC_a[0].size();
 
  743     ATH_MSG_ERROR ( "OFC of nSamples=0 !" );
 
  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);
 
  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 !!!");
 
  760 template<class CONDITIONSCONTAINER>
 
  761 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(const HWIdentifier chid, const int gain, LArAutoCorrP1& patch) {
 
  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.;
 
  770 #ifdef LARRAWCONDITIONS_LARSINGLEFLOATP
 
  771 template<class CONDITIONSCONTAINER>
 
  772 bool LArCalibPatchingAlg<CONDITIONSCONTAINER>::setZero(LArSingleFloatP& patch) {
 
  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;
 
  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;
 
  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;
 
  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;