File indexing completed on 2025-07-02 07:54:32
0001
0002
0003 #include <Evaluator/DD4hepUnits.h>
0004 #include <edm4eic/ClusterCollection.h>
0005 #include <edm4eic/ReconstructedParticleCollection.h>
0006 #include <edm4hep/Vector3f.h>
0007 #include <edm4hep/utils/vector_utils.h>
0008 #include <fmt/core.h>
0009 #include <cmath>
0010 #include <gsl/pointers>
0011 #include <stdexcept>
0012 #include <vector>
0013
0014 #include "FarForwardNeutralsReconstruction.h"
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 namespace eicrecon {
0027
0028 void FarForwardNeutralsReconstruction::init() {
0029
0030 try {
0031 m_gammaZMax =
0032 m_cfg.gammaZMaxOffset + m_detector->constant<double>(m_cfg.offsetPositionName) / dd4hep::mm;
0033 } catch (std::runtime_error&) {
0034 m_gammaZMax = m_cfg.gammaZMaxOffset + 35800;
0035 trace("Failed to get {} from the detector, using default value of {}", m_cfg.offsetPositionName,
0036 m_gammaZMax);
0037 }
0038
0039 if (m_cfg.neutronScaleCorrCoeffHcal.size() < 3) {
0040 error("Invalid configuration. m_cfg.neutronScaleCorrCoeffHcal should have at least 3 "
0041 "parameters");
0042 throw std::runtime_error("Invalid configuration. m_cfg.neutronScaleCorrCoeffHcal should have "
0043 "at least 3 parameters");
0044 }
0045 if (m_cfg.gammaScaleCorrCoeffHcal.size() < 3) {
0046 error("Invalid configuration. m_cfg.gamma_scale_corr_coeff_ecal should have at least 3 "
0047 "parameters");
0048 throw std::runtime_error("Invalid configuration. m_cfg.gamma_scale_corr_coeff_ecal should "
0049 "have at least 3 parameters");
0050 }
0051 trace("gamma detection params: max length={}, max width={}, max z={}", m_cfg.gammaMaxLength,
0052 m_cfg.gammaMaxWidth, m_gammaZMax);
0053 }
0054
0055 double FarForwardNeutralsReconstruction::calc_corr(double Etot, const std::vector<double>& coeffs) {
0056 return coeffs[0] + coeffs[1] / sqrt(Etot) + coeffs[2] / Etot;
0057 }
0058
0059
0060
0061
0062
0063
0064 bool FarForwardNeutralsReconstruction::isGamma(const edm4eic::Cluster& cluster) const {
0065 double l1 = sqrt(cluster.getShapeParameters(4)) * dd4hep::mm;
0066 double l2 = sqrt(cluster.getShapeParameters(5)) * dd4hep::mm;
0067 double l3 = sqrt(cluster.getShapeParameters(6)) * dd4hep::mm;
0068
0069
0070 double z = (cluster.getPosition().z * cos(m_cfg.globalToProtonRotation) +
0071 cluster.getPosition().x * sin(m_cfg.globalToProtonRotation)) *
0072 dd4hep::mm;
0073 trace("z recon = {}", z);
0074 trace("l1 = {}, l2 = {}, l3 = {}", l1, l2, l3);
0075 bool isZMoreThanMax = (z > m_gammaZMax);
0076 bool isLengthMoreThanMax =
0077 (l1 > m_cfg.gammaMaxLength || l2 > m_cfg.gammaMaxLength || l3 > m_cfg.gammaMaxLength);
0078 bool areWidthsMoreThanMax = static_cast<int>(l1 > m_cfg.gammaMaxWidth) +
0079 static_cast<int>(l2 > m_cfg.gammaMaxWidth) +
0080 static_cast<int>(l3 > m_cfg.gammaMaxWidth) >=
0081 2;
0082 return !(isZMoreThanMax || isLengthMoreThanMax || areWidthsMoreThanMax);
0083 }
0084
0085 void FarForwardNeutralsReconstruction::process(
0086 const FarForwardNeutralsReconstruction::Input& input,
0087 const FarForwardNeutralsReconstruction::Output& output) const {
0088 const auto [clustersHcal] = input;
0089 auto [out_neutrals] = output;
0090
0091 double Etot_hcal = 0;
0092 double Emax = 0;
0093 edm4hep::Vector3f n_position;
0094 for (const auto& cluster : *clustersHcal) {
0095 double E = cluster.getEnergy();
0096
0097 if (isGamma(cluster)) {
0098 auto rec_part = out_neutrals->create();
0099 rec_part.setPDG(22);
0100 edm4hep::Vector3f position = cluster.getPosition();
0101 double corr = calc_corr(E, m_cfg.gammaScaleCorrCoeffHcal);
0102 E = E / (1 + corr);
0103 double p = E;
0104 double r = edm4hep::utils::magnitude(position);
0105 edm4hep::Vector3f momentum = position * (p / r);
0106 rec_part.setEnergy(E);
0107 rec_part.setMomentum(momentum);
0108 rec_part.setReferencePoint(position);
0109 rec_part.setCharge(0);
0110 rec_part.setMass(0);
0111 rec_part.addToClusters(cluster);
0112 continue;
0113 }
0114
0115 Etot_hcal += E;
0116 if (E > Emax) {
0117 Emax = E;
0118 n_position = cluster.getPosition();
0119 }
0120 }
0121
0122 double Etot = Etot_hcal;
0123 static const double m_neutron = m_particleSvc.particle(2112).mass;
0124 int n_neutrons = 0;
0125 if (Etot > 0 && Emax > 0) {
0126 auto rec_part = out_neutrals->create();
0127 double corr = calc_corr(Etot, m_cfg.neutronScaleCorrCoeffHcal);
0128 Etot_hcal = Etot_hcal / (1 + corr);
0129 Etot = Etot_hcal;
0130 rec_part.setEnergy(Etot);
0131 rec_part.setPDG(2112);
0132 double p = sqrt(Etot * Etot - m_neutron * m_neutron);
0133 double r = edm4hep::utils::magnitude(n_position);
0134 edm4hep::Vector3f momentum = n_position * (p / r);
0135 rec_part.setMomentum(momentum);
0136 rec_part.setReferencePoint(n_position);
0137 rec_part.setCharge(0);
0138 rec_part.setMass(m_neutron);
0139 for (const auto& cluster : *clustersHcal) {
0140 rec_part.addToClusters(cluster);
0141 }
0142 n_neutrons = 1;
0143 } else {
0144 n_neutrons = 0;
0145 }
0146 debug("Found {} neutron candidates", n_neutrons);
0147 }
0148 }