File indexing completed on 2025-02-22 09:55:34
0001
0002
0003
0004
0005
0006
0007
0008 #include "fmt/format.h"
0009 #include "fmt/ranges.h"
0010 #include <algorithm>
0011 #include <bitset>
0012
0013 #include "Gaudi/Property.h"
0014 #include "GaudiAlg/GaudiAlgorithm.h"
0015 #include "GaudiAlg/GaudiTool.h"
0016 #include "GaudiAlg/Transformer.h"
0017 #include "GaudiKernel/PhysicalConstants.h"
0018 #include "GaudiKernel/RndmGenerators.h"
0019 #include "GaudiKernel/ToolHandle.h"
0020
0021 #include "DDRec/CellIDPositionConverter.h"
0022 #include "DDRec/Surface.h"
0023 #include "DDRec/SurfaceManager.h"
0024
0025 #include "JugBase/DataHandle.h"
0026 #include "JugBase/IGeoSvc.h"
0027
0028
0029 #include "edm4eic/CalorimeterHitCollection.h"
0030 #include "edm4eic/RawCalorimeterHitCollection.h"
0031
0032 using namespace Gaudi::Units;
0033
0034 namespace Jug::Reco {
0035
0036
0037
0038
0039
0040
0041 class CalorimeterHitReco : public GaudiAlgorithm {
0042 private:
0043
0044 Gaudi::Property<double> m_lUnit{this, "lengthUnit", dd4hep::mm};
0045
0046
0047 Gaudi::Property<unsigned int> m_capADC{this, "capacityADC", 8096};
0048 Gaudi::Property<double> m_dyRangeADC{this, "dynamicRangeADC", 100. * MeV};
0049 Gaudi::Property<unsigned int> m_pedMeanADC{this, "pedestalMean", 400};
0050 Gaudi::Property<double> m_pedSigmaADC{this, "pedestalSigma", 3.2};
0051 Gaudi::Property<double> m_resolutionTDC{this, "resolutionTDC", 10 * ps};
0052
0053
0054 Gaudi::Property<double> m_thresholdFactor{this, "thresholdFactor", 0.0};
0055 Gaudi::Property<double> m_thresholdValue{this, "thresholdValue", 0.0};
0056
0057
0058 Gaudi::Property<double> m_sampFrac{this, "samplingFraction", 1.0};
0059
0060
0061 double dyRangeADC{0};
0062 double thresholdADC{0};
0063 double stepTDC{0};
0064
0065 DataHandle<edm4eic::RawCalorimeterHitCollection> m_inputHitCollection{"inputHitCollection", Gaudi::DataHandle::Reader,
0066 this};
0067 DataHandle<edm4eic::CalorimeterHitCollection> m_outputHitCollection{"outputHitCollection", Gaudi::DataHandle::Writer,
0068 this};
0069
0070
0071 Gaudi::Property<std::string> m_geoSvcName{this, "geoServiceName", "GeoSvc"};
0072 Gaudi::Property<std::string> m_readout{this, "readoutClass", ""};
0073 Gaudi::Property<std::string> m_layerField{this, "layerField", ""};
0074 Gaudi::Property<std::string> m_sectorField{this, "sectorField", ""};
0075 SmartIF<IGeoSvc> m_geoSvc;
0076 dd4hep::BitFieldCoder* id_dec = nullptr;
0077 size_t sector_idx{0}, layer_idx{0};
0078
0079
0080
0081 Gaudi::Property<std::string> m_localDetElement{this, "localDetElement", ""};
0082 Gaudi::Property<std::vector<std::string>> u_localDetFields{this, "localDetFields", {}};
0083 dd4hep::DetElement local;
0084 size_t local_mask = ~0;
0085
0086 public:
0087 CalorimeterHitReco(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc) {
0088 declareProperty("inputHitCollection", m_inputHitCollection, "");
0089 declareProperty("outputHitCollection", m_outputHitCollection, "");
0090 }
0091
0092 StatusCode initialize() override {
0093 if (GaudiAlgorithm::initialize().isFailure()) {
0094 return StatusCode::FAILURE;
0095 }
0096
0097 m_geoSvc = service(m_geoSvcName);
0098 if (!m_geoSvc) {
0099 error() << "Unable to locate Geometry Service. "
0100 << "Make sure you have GeoSvc and SimSvc in the right order in the configuration." << endmsg;
0101 return StatusCode::FAILURE;
0102 }
0103
0104
0105 dyRangeADC = m_dyRangeADC.value() / GeV;
0106
0107
0108 thresholdADC = m_thresholdFactor.value() * m_pedSigmaADC.value() + m_thresholdValue.value();
0109
0110
0111 stepTDC = ns / m_resolutionTDC.value();
0112
0113
0114 if (m_readout.value().empty()) {
0115 return StatusCode::SUCCESS;
0116 }
0117
0118 auto id_spec = m_geoSvc->detector()->readout(m_readout).idSpec();
0119 try {
0120 id_dec = id_spec.decoder();
0121 if (!m_sectorField.value().empty()) {
0122 sector_idx = id_dec->index(m_sectorField);
0123 info() << "Find sector field " << m_sectorField.value() << ", index = " << sector_idx << endmsg;
0124 }
0125 if (!m_layerField.value().empty()) {
0126 layer_idx = id_dec->index(m_layerField);
0127 info() << "Find layer field " << m_layerField.value() << ", index = " << sector_idx << endmsg;
0128 }
0129 } catch (...) {
0130 error() << "Failed to load ID decoder for " << m_readout << endmsg;
0131 return StatusCode::FAILURE;
0132 }
0133
0134
0135 if (!m_localDetElement.value().empty()) {
0136 try {
0137 local = m_geoSvc->detector()->detector(m_localDetElement.value());
0138 info() << "Local coordinate system from DetElement " << m_localDetElement.value() << endmsg;
0139 } catch (...) {
0140 error() << "Failed to locate local coordinate system from DetElement " << m_localDetElement.value() << endmsg;
0141 return StatusCode::FAILURE;
0142 }
0143
0144 } else {
0145 std::vector<std::pair<std::string, int>> fields;
0146 for (auto& f : u_localDetFields.value()) {
0147 fields.emplace_back(f, 0);
0148 }
0149 local_mask = id_spec.get_mask(fields);
0150
0151 if (fields.empty()) {
0152 local_mask = ~0;
0153 }
0154 info() << fmt::format("Local DetElement mask {:#064b} from fields [{}]", local_mask, fmt::join(fields, ", "))
0155 << endmsg;
0156 }
0157
0158 return StatusCode::SUCCESS;
0159 }
0160
0161 StatusCode execute() override {
0162
0163 const auto& rawhits = *m_inputHitCollection.get();
0164
0165 auto& hits = *m_outputHitCollection.createAndPut();
0166 auto converter = m_geoSvc->cellIDPositionConverter();
0167
0168
0169 for (const auto& rh : rawhits) {
0170
0171 #pragma GCC diagnostic push
0172 #pragma GCC diagnostic error "-Wsign-conversion"
0173
0174
0175 if (rh.getAmplitude() < m_pedMeanADC + thresholdADC) {
0176 continue;
0177 }
0178
0179
0180 const float energy =
0181 (((signed)rh.getAmplitude() - (signed)m_pedMeanADC)) / static_cast<float>(m_capADC.value()) * dyRangeADC / m_sampFrac;
0182 const float time = rh.getTimeStamp() / stepTDC;
0183
0184 #pragma GCC diagnostic pop
0185
0186 const auto cellID = rh.getCellID();
0187 const int lid = id_dec != nullptr && !m_layerField.value().empty() ? static_cast<int>(id_dec->get(cellID, layer_idx)) : -1;
0188 const int sid = id_dec != nullptr && !m_sectorField.value().empty() ? static_cast<int>(id_dec->get(cellID, sector_idx)) : -1;
0189
0190 const auto gpos = converter->position(cellID);
0191
0192 if (m_localDetElement.value().empty()) {
0193 auto volman = m_geoSvc->detector()->volumeManager();
0194 local = volman.lookupDetElement(cellID & local_mask);
0195 }
0196 const auto pos = local.nominal().worldToLocal(dd4hep::Position(gpos.x(), gpos.y(), gpos.z()));
0197
0198 std::vector<double> cdim;
0199
0200 if (converter->findReadout(local).segmentation().type() != "NoSegmentation") {
0201 cdim = converter->cellDimensions(cellID);
0202
0203 } else {
0204
0205 cdim = converter->findContext(cellID)->volumePlacement().volume().boundingBox().dimensions();
0206 std::transform(cdim.begin(), cdim.end(), cdim.begin(),
0207 std::bind(std::multiplies<double>(), std::placeholders::_1, 2));
0208 }
0209
0210
0211 const decltype(edm4eic::CalorimeterHitData::position) position(
0212 gpos.x() / m_lUnit, gpos.y() / m_lUnit, gpos.z() / m_lUnit
0213 );
0214 const decltype(edm4eic::CalorimeterHitData::dimension) dimension(
0215 cdim[0] / m_lUnit, cdim[1] / m_lUnit, cdim[2] / m_lUnit
0216 );
0217 const decltype(edm4eic::CalorimeterHitData::local) local_position(
0218 pos.x() / m_lUnit, pos.y() / m_lUnit, pos.z() / m_lUnit
0219 );
0220
0221 hits.push_back({
0222 rh.getCellID(),
0223 energy,
0224 0,
0225 time,
0226 0,
0227 position,
0228 dimension,
0229
0230 sid,
0231 lid,
0232 local_position,
0233 });
0234 }
0235
0236 return StatusCode::SUCCESS;
0237 }
0238
0239 };
0240
0241
0242 DECLARE_COMPONENT(CalorimeterHitReco)
0243
0244 }