Skip to content
Snippets Groups Projects
CalorimeterHitReco.cpp 7.89 KiB
Newer Older
  • Learn to ignore specific revisions
  • // Reconstruct digitized outputs, paired with Jug::Digi::CalorimeterHitDigi
    // Author: Chao Peng
    // Date: 06/14/2021
    
    
    #include "fmt/format.h"
    #include "fmt/ranges.h"
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
    #include <algorithm>
    #include <bitset>
    
    
    #include "Gaudi/Property.h"
    #include "GaudiAlg/GaudiAlgorithm.h"
    #include "GaudiAlg/GaudiTool.h"
    #include "GaudiAlg/Transformer.h"
    #include "GaudiKernel/PhysicalConstants.h"
    #include "GaudiKernel/RndmGenerators.h"
    #include "GaudiKernel/ToolHandle.h"
    
    #include "DDRec/CellIDPositionConverter.h"
    #include "DDRec/Surface.h"
    #include "DDRec/SurfaceManager.h"
    
    // FCCSW
    #include "JugBase/DataHandle.h"
    #include "JugBase/IGeoSvc.h"
    
    // Event Model related classes
    #include "eicd/CalorimeterHitCollection.h"
    #include "eicd/RawCalorimeterHitCollection.h"
    
    using namespace Gaudi::Units;
    
    namespace Jug::Reco {
    
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
      class CalorimeterHitReco : public GaudiAlgorithm {
      public:
    
        // length unit from dd4hep, should be fixed
        Gaudi::Property<double> m_lUnit{this, "lengthUnit", dd4hep::mm};
    
        // digitization settings, must be consistent with digi class
        Gaudi::Property<int>    m_capADC{this, "capacityADC", 8096};
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
        Gaudi::Property<double> m_dyRangeADC{this, "dynamicRangeADC", 100. * MeV};
    
        Gaudi::Property<int>    m_pedMeanADC{this, "pedestalMean", 400};
        Gaudi::Property<double> m_pedSigmaADC{this, "pedestalSigma", 3.2};
    
        // zero suppression values
        Gaudi::Property<double> m_thresholdADC{this, "thresholdFactor", 3.0};
    
    
        // unitless counterparts of the input parameters
        double                  dyRangeADC;
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
        DataHandle<eic::RawCalorimeterHitCollection> m_inputHitCollection{
            "inputHitCollection", Gaudi::DataHandle::Reader, this};
        DataHandle<eic::CalorimeterHitCollection> m_outputHitCollection{
            "outputHitCollection", Gaudi::DataHandle::Writer, this};
    
    
        // geometry service to get ids, ignored if no names provided
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
        Gaudi::Property<std::string> m_geoSvcName{this, "geoServiceName", "GeoSvc"};
        Gaudi::Property<std::string> m_readout{this, "readoutClass", ""};
        Gaudi::Property<std::string> m_layerField{this, "layerField", ""};
        Gaudi::Property<std::string> m_sectorField{this, "sectorField", ""};
        SmartIF<IGeoSvc>             m_geoSvc;
        dd4hep::BitFieldCoder*       id_dec = nullptr;
        size_t                       sector_idx, layer_idx;
    
        // name of detelment or fields to find the local detector (for global->local transform)
        // if nothing is provided, the lowest level DetElement (from cellID) will be used
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
        Gaudi::Property<std::string>              m_localDetElement{this, "localDetElement", ""};
    
        Gaudi::Property<std::vector<std::string>> u_localDetFields{this, "localDetFields", {}};
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
        dd4hep::Alignment                         local;
        size_t                                    local_mask = ~0;
    
        CalorimeterHitReco(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
        {
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          declareProperty("inputHitCollection", m_inputHitCollection, "");
          declareProperty("outputHitCollection", m_outputHitCollection, "");
    
        }
    
        StatusCode initialize() override
        {
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          if (GaudiAlgorithm::initialize().isFailure()) {
            return StatusCode::FAILURE;
          }
    
          m_geoSvc = service(m_geoSvcName);
          if (!m_geoSvc) {
            error() << "Unable to locate Geometry Service. "
                    << "Make sure you have GeoSvc and SimSvc in the right order in the configuration."
                    << endmsg;
            return StatusCode::FAILURE;
          }
    
    
          // unitless conversion
          dyRangeADC = m_dyRangeADC.value()/GeV;
    
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          // do not get the layer/sector ID if no readout class provided
          if (m_readout.value().empty()) {
            return StatusCode::SUCCESS;
          }
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          auto id_spec = m_geoSvc->detector()->readout(m_readout).idSpec();
          try {
            id_dec = id_spec.decoder();
            if (m_sectorField.value().size()) {
              sector_idx = id_dec->index(m_sectorField);
    
              info() << "Find sector field " << m_sectorField.value() << ", index = " << sector_idx << endmsg;
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
            if (m_layerField.value().size()) {
              layer_idx = id_dec->index(m_layerField);
    
              info() << "Find layer field " << m_layerField.value() << ", index = " << sector_idx << endmsg;
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          } catch (...) {
            error() << "Failed to load ID decoder for " << m_readout << endmsg;
            return StatusCode::FAILURE;
          }
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          // local detector name has higher priority
          if (m_localDetElement.value().size()) {
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
              local = m_geoSvc->detector()->detector(m_localDetElement.value()).nominal();
              info() << "Local coordinate system from DetElement " << m_localDetElement.value()
                     << endmsg;
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
              error() << "Failed to locate local coordinate system from DetElement "
                      << m_localDetElement.value() << endmsg;
              return StatusCode::FAILURE;
    
          // or get from fields
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          } else {
            std::vector<std::pair<std::string, int>> fields;
            for (auto& f : u_localDetFields.value()) {
              fields.push_back({f, 0});
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
            local_mask = id_spec.get_mask(fields);
            // use all fields if nothing provided
            if (fields.empty()) {
              local_mask = ~0;
            }
            info() << fmt::format("Local DetElement mask {:#064b} from fields [{}]", local_mask,
                                  fmt::join(fields, ", "))
                   << endmsg;
          }
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          return StatusCode::SUCCESS;
    
        }
    
        StatusCode execute() override
        {
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
          // input collections
          const auto& rawhits = *m_inputHitCollection.get();
          // create output collections
          auto& hits = *m_outputHitCollection.createAndPut();
    
          // energy time reconstruction
          for (const auto& rh : rawhits) {
            // did not pass the zero-suppression threshold
            if ((rh.amplitude() - m_pedMeanADC) < m_thresholdADC * m_pedSigmaADC) {
              continue;
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
            // convert ADC -> energy
    
            float energy = (rh.amplitude() - m_pedMeanADC) / static_cast<float>(m_capADC.value()) * dyRangeADC;
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
    
            float time = rh.timeStamp(); // ns
            auto  id   = rh.cellID();
    
            int   lid  = ((id_dec != nullptr) && m_layerField.value().size())
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
                          ? static_cast<int>(id_dec->get(id, layer_idx))
                          : -1;
    
            int   sid  = ((id_dec != nullptr) && m_sectorField.value().size())
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
                          ? static_cast<int>(id_dec->get(id, sector_idx))
                          : -1;
            // global positions
            auto gpos = m_geoSvc->cellIDPositionConverter()->position(id);
            // local positions
            if (m_localDetElement.value().empty()) {
              auto volman = m_geoSvc->detector()->volumeManager();
              local       = volman.lookupDetElement(id & local_mask).nominal();
            }
            auto pos = local.worldToLocal(dd4hep::Position(gpos.x(), gpos.y(), gpos.z()));
    
            // auto pos = m_geoSvc->cellIDPositionConverter()->findContext(id)->volumePlacement().position();
            // cell dimension
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
            auto   cdim   = m_geoSvc->cellIDPositionConverter()->cellDimensions(id);
            double dim[3] = {0., 0., 0.};
            for (size_t i = 0; i < cdim.size() && i < 3; ++i) {
              dim[i] = cdim[i] / m_lUnit;
            }
            // debug() << std::bitset<64>(id) << "\n"
            //         <<
            //         m_geoSvc->cellIDPositionConverter()->findContext(id)->volumePlacement().volIDs().str()
            //         << endmsg;
            hits.push_back({
                id,
                -1,
                lid,
                sid, // cell id, cluster id, layer id, sector id
                energy,
                time, // energy, time
                {gpos.x() / m_lUnit, gpos.y() / m_lUnit, gpos.z() / m_lUnit},
                {pos.x() / m_lUnit, pos.y() / m_lUnit, pos.z() / m_lUnit},
                {dim[0], dim[1], dim[2]},
                0 // @TODO: hit type
            });
          }
    
          return StatusCode::SUCCESS;
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
      }; // class CalorimeterHitReco
    
    Sylvester Joosten's avatar
    Sylvester Joosten committed
      DECLARE_COMPONENT(CalorimeterHitReco)
    
    
    } // namespace Jug::Reco