text: #ifndef __InitialClusteringStepBase_H__
  #define __InitialClusteringStepBase_H__
  
  #include "FWCore/ParameterSet/interface/ParameterSet.h"
  #include "DataFormats/Common/interface/Handle.h"
  #include "DataFormats/ParticleFlowReco/interface/PFRecHit.h"
  #include "DataFormats/ParticleFlowReco/interface/PFRecHitFwd.h"
  #include "DataFormats/ParticleFlowReco/interface/PFCluster.h"
  #include "DataFormats/ParticleFlowReco/interface/PFClusterFwd.h"
  #include "DataFormats/Common/interface/RefToBaseVector.h"
  
  #include <string>
  #include <iostream>
  #include <unordered_map>
  #include <tuple>
  
  namespace edm {
    class Event;
    class EventSetup;
  }  // namespace edm
  
  #include "FWCore/Framework/interface/ConsumesCollector.h"
  
  class InitialClusteringStepBase {
    typedef InitialClusteringStepBase ICSB;
  
  public:
    InitialClusteringStepBase(const edm::ParameterSet& conf, edm::ConsumesCollector& cc)
        : _nSeeds(0),
          _nClustersFound(0),
          _layerMap({{"PS2", (int)PFLayer::PS2},
                     {"PS1", (int)PFLayer::PS1},
                     {"ECAL_ENDCAP", (int)PFLayer::ECAL_ENDCAP},
                     {"ECAL_BARREL", (int)PFLayer::ECAL_BARREL},
                     {"NONE", (int)PFLayer::NONE},
                     {"HCAL_BARREL1", (int)PFLayer::HCAL_BARREL1},
                     {"HCAL_BARREL2_RING0", (int)PFLayer::HCAL_BARREL2},
                     {"HCAL_BARREL2_RING1", 100 * (int)PFLayer::HCAL_BARREL2},
                     {"HCAL_ENDCAP", (int)PFLayer::HCAL_ENDCAP},
                     {"HF_EM", (int)PFLayer::HF_EM},
                     {"HF_HAD", (int)PFLayer::HF_HAD},
                     {"HGCAL", (int)PFLayer::HGCAL}}),
          _algoName(conf.getParameter<std::string>("algoName")) {
      const std::vector<edm::ParameterSet>& thresholds = conf.getParameterSetVector("thresholdsByDetector");
      for (const auto& pset : thresholds) {
        const std::string& det = pset.getParameter<std::string>("detector");
  
        std::vector<int> depths;
        std::vector<double> thresh_E;
        std::vector<double> thresh_pT;
        std::vector<double> thresh_pT2;
  
        if (det == std::string("HCAL_BARREL1") || det == std::string("HCAL_ENDCAP")) {
          depths = pset.getParameter<std::vector<int> >("depths");
          thresh_E = pset.getParameter<std::vector<double> >("gatheringThreshold");
          thresh_pT = pset.getParameter<std::vector<double> >("gatheringThresholdPt");
          if (thresh_E.size() != depths.size() || thresh_pT.size() != depths.size()) {
            throw cms::Exception("InvalidGatheringThreshold")
                << "gatheringThresholds mismatch with the numbers of depths";
          }
        } else {
          depths.push_back(0);
          thresh_E.push_back(pset.getParameter<double>("gatheringThreshold"));
          thresh_pT.push_back(pset.getParameter<double>("gatheringThresholdPt"));
        }
  
        for (unsigned int i = 0; i < thresh_pT.size(); ++i) {
          thresh_pT2.push_back(thresh_pT[i] * thresh_pT[i]);
        }
  
        auto entry = _layerMap.find(det);
        if (entry == _layerMap.end()) {
          throw cms::Exception("InvalidDetectorLayer")
              << "Detector layer : " << det << " is not in the list of recognized"
              << " detector layers!";
        }
        _thresholds.emplace(_layerMap.find(det)->second, std::make_tuple(depths, thresh_E, thresh_pT2));
      }
    }
    virtual ~InitialClusteringStepBase() = default;
    // get rid of things we should never use...
    InitialClusteringStepBase(const ICSB&) = delete;
    ICSB& operator=(const ICSB&) = delete;
  
    virtual void update(const edm::EventSetup&) {}
  
    virtual void updateEvent(const edm::Event&) {}
  
    virtual void buildClusters(const edm::Handle<reco::PFRecHitCollection>&,
                               const std::vector<bool>& mask,    // mask flags
                               const std::vector<bool>& seeds,   // seed flags
                               reco::PFClusterCollection&) = 0;  //output
  
    std::ostream& operator<<(std::ostream& o) const {
      o << "InitialClusteringStep with algo \"" << _algoName << "\" located " << _nSeeds << " seeds and built "
        << _nClustersFound << " clusters from those seeds. ";
      return o;
    }
  
    void reset() { _nSeeds = _nClustersFound = 0; }
  
  protected:
    reco::PFRecHitRef makeRefhit(const edm::Handle<reco::PFRecHitCollection>& h, const unsigned i) const {
      return reco::PFRecHitRef(h, i);
    }
    unsigned _nSeeds, _nClustersFound;  // basic performance information
    const std::unordered_map<std::string, int> _layerMap;
  
    typedef std::tuple<std::vector<int>, std::vector<double>, std::vector<double> > I3tuple;
    std::unordered_map<int, I3tuple> _thresholds;
  
  private:
    const std::string _algoName;
  };
  
  std::ostream& operator<<(std::ostream& o, const InitialClusteringStepBase& a);
  
  #include "FWCore/PluginManager/interface/PluginFactory.h"
  typedef edmplugin::PluginFactory<InitialClusteringStepBase*(const edm::ParameterSet&, edm::ConsumesCollector&)>
      InitialClusteringStepFactory;
  
  #endif
  