File indexing completed on 2024-10-03 05:27:16
0001 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0002 #include "DataFormats/Common/interface/ValueMap.h"
0003 #include "RecoLocalCalo/HGCalRecProducers/interface/ComputeClusterTime.h"
0004 #include "TrackstersPCA.h"
0005
0006 #include <iostream>
0007 #include <set>
0008
0009 #include <Eigen/Core>
0010 #include <Eigen/Dense>
0011 #include <vector>
0012 #include <functional>
0013
0014 void ticl::assignPCAtoTracksters(std::vector<Trackster> &tracksters,
0015 const std::vector<reco::CaloCluster> &layerClusters,
0016 const edm::ValueMap<std::pair<float, float>> &layerClustersTime,
0017 double z_limit_em,
0018 const hgcal::RecHitTools &rhtools,
0019 bool computeLocalTime,
0020 bool energyWeight,
0021 bool clean,
0022 int minLayer,
0023 int maxLayer) {
0024 LogDebug("TrackstersPCA_Eigen") << "------- Eigen -------" << std::endl;
0025
0026 for (auto &trackster : tracksters) {
0027 LogDebug("TrackstersPCA_Eigen") << "start testing teackster with size:" << trackster.vertices().size() << std::endl;
0028
0029 Eigen::Vector3f point;
0030 point << 0., 0., 0.;
0031 Eigen::Vector3f barycenter;
0032 barycenter << 0., 0., 0.;
0033 Eigen::Vector3f filtered_barycenter;
0034 filtered_barycenter << 0., 0., 0.;
0035
0036 auto fillPoint = [&](const reco::CaloCluster &c, const float weight = 1.f) {
0037 point[0] = weight * c.x();
0038 point[1] = weight * c.y();
0039 point[2] = weight * c.z();
0040 };
0041
0042
0043 trackster.setRawEnergy(0.f);
0044 trackster.setRawEmEnergy(0.f);
0045 trackster.setRawPt(0.f);
0046 trackster.setRawEmPt(0.f);
0047
0048 size_t N = trackster.vertices().size();
0049 if (N == 0)
0050 continue;
0051 float weight = 1.f / N;
0052 float weights2_sum = 0.f;
0053
0054 std::vector<float> layerClusterEnergies;
0055
0056 for (size_t i = 0; i < N; ++i) {
0057 auto fraction = 1.f / trackster.vertex_multiplicity(i);
0058 trackster.addToRawEnergy(layerClusters[trackster.vertices(i)].energy() * fraction);
0059 if (std::abs(layerClusters[trackster.vertices(i)].z()) <= z_limit_em)
0060 trackster.addToRawEmEnergy(layerClusters[trackster.vertices(i)].energy() * fraction);
0061
0062
0063 if (energyWeight)
0064 weight = layerClusters[trackster.vertices(i)].energy() * fraction;
0065 fillPoint(layerClusters[trackster.vertices(i)], weight);
0066 for (size_t j = 0; j < 3; ++j)
0067 barycenter[j] += point[j];
0068
0069 layerClusterEnergies.push_back(layerClusters[trackster.vertices(i)].energy());
0070 }
0071 float raw_energy = trackster.raw_energy();
0072 float inv_raw_energy = 1.f / raw_energy;
0073 if (energyWeight)
0074 barycenter *= inv_raw_energy;
0075 trackster.setBarycenter(ticl::Trackster::Vector(barycenter));
0076
0077 LogDebug("TrackstersPCA_Eigen") << "cleaning is :" << clean << std::endl;
0078
0079 std::vector<unsigned> filtered_idx;
0080 float filtered_energy = 0;
0081 float inv_filtered_energy = 0;
0082 if (clean) {
0083
0084 auto maxE_vertex = std::distance(layerClusterEnergies.begin(),
0085 std::max_element(layerClusterEnergies.begin(), layerClusterEnergies.end()));
0086 auto maxE_layer = getLayerFromLC(layerClusters[trackster.vertices(maxE_vertex)], rhtools);
0087
0088 auto vertices_by_layer = sortByLayer(trackster, layerClusters, rhtools);
0089
0090 for (unsigned i = 1; i <= rhtools.lastLayer(); ++i) {
0091 auto vertices_in_layer = vertices_by_layer[i];
0092 if (vertices_in_layer.empty())
0093 continue;
0094
0095 std::vector<float> energies_in_layer;
0096 for (auto vrt : vertices_in_layer)
0097 energies_in_layer.push_back(layerClusters[trackster.vertices(vrt)].energy());
0098
0099 unsigned maxEid_inLayer = std::distance(energies_in_layer.begin(),
0100 std::max_element(energies_in_layer.begin(), energies_in_layer.end()));
0101
0102
0103 if ((int)i >= (int)maxE_layer - minLayer && (int)i <= (int)maxE_layer + maxLayer) {
0104 auto filtered_vert = vertices_in_layer[maxEid_inLayer];
0105 filtered_idx.push_back(filtered_vert);
0106
0107 const auto &maxE_LC = layerClusters[trackster.vertices(filtered_vert)];
0108 fillPoint(maxE_LC, maxE_LC.energy() * (1.f / trackster.vertex_multiplicity(filtered_vert)));
0109 for (size_t j = 0; j < 3; ++j)
0110 filtered_barycenter[j] += point[j];
0111 filtered_energy += maxE_LC.energy();
0112 }
0113 }
0114 inv_filtered_energy = 1. / filtered_energy;
0115 filtered_barycenter *= inv_filtered_energy;
0116 }
0117 LogDebug("TrackstersPCA_Eigen") << "min, max " << minLayer << " " << maxLayer << std::endl;
0118
0119 std::pair<float, float> timeTrackster;
0120 if (computeLocalTime)
0121 timeTrackster = ticl::computeLocalTracksterTime(trackster, layerClusters, layerClustersTime, barycenter, N);
0122 else
0123 timeTrackster = ticl::computeTracksterTime(trackster, layerClustersTime, N);
0124
0125 trackster.setTimeAndError(timeTrackster.first, timeTrackster.second);
0126 LogDebug("TrackstersPCA") << "Use energy weighting: " << energyWeight << std::endl;
0127 LogDebug("TrackstersPCA") << "\nTrackster characteristics: " << std::endl;
0128 LogDebug("TrackstersPCA") << "Size: " << N << std::endl;
0129 LogDebug("TrackstersPCA") << "Energy: " << trackster.raw_energy() << std::endl;
0130 LogDebug("TrackstersPCA") << "raw_pt: " << trackster.raw_pt() << std::endl;
0131 LogDebug("TrackstersPCA") << "Means: " << barycenter[0] << ", " << barycenter[1] << ", " << barycenter[2]
0132 << std::endl;
0133 LogDebug("TrackstersPCA") << "Time: " << trackster.time() << " +/- " << trackster.timeError() << std::endl;
0134
0135 if (N > 2) {
0136 Eigen::Vector3f sigmas;
0137 sigmas << 0., 0., 0.;
0138 Eigen::Vector3f sigmasEigen;
0139 sigmasEigen << 0., 0., 0.;
0140 Eigen::Matrix3f covM = Eigen::Matrix3f::Zero();
0141
0142
0143
0144
0145 auto calc_covM = [&](size_t i) {
0146 fillPoint(layerClusters[trackster.vertices(i)]);
0147 if (energyWeight && trackster.raw_energy()) {
0148 weight = (layerClusters[trackster.vertices(i)].energy() / trackster.vertex_multiplicity(i)) *
0149 (clean ? inv_filtered_energy : inv_raw_energy);
0150 if (trackster.vertex_multiplicity(i) > 1)
0151 LogDebug("TrackstersPCA_Eigen")
0152 << "trackster.vertex_multiplicity(i) :" << trackster.vertex_multiplicity(i);
0153 }
0154 weights2_sum += weight * weight;
0155 for (size_t x = 0; x < 3; ++x) {
0156 for (size_t y = 0; y <= x; ++y) {
0157 covM(x, y) += weight * (point[x] - (clean ? filtered_barycenter[x] : barycenter[x])) *
0158 (point[y] - (clean ? filtered_barycenter[y] : barycenter[y]));
0159 covM(y, x) = covM(x, y);
0160 }
0161 }
0162 };
0163 if (clean) {
0164 for (size_t i : filtered_idx) {
0165 calc_covM(i);
0166 }
0167 } else {
0168 for (size_t i = 0; i < N; ++i) {
0169 calc_covM(i);
0170 }
0171 }
0172
0173 covM *= 1.f / (1.f - weights2_sum);
0174
0175
0176 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f>::RealVectorType eigenvalues_fromEigen;
0177 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f>::EigenvectorsType eigenvectors_fromEigen;
0178 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigensolver(covM);
0179 if (eigensolver.info() != Eigen::Success) {
0180 eigenvalues_fromEigen = eigenvalues_fromEigen.Zero();
0181 eigenvectors_fromEigen = eigenvectors_fromEigen.Zero();
0182 } else {
0183 eigenvalues_fromEigen = eigensolver.eigenvalues();
0184 eigenvectors_fromEigen = eigensolver.eigenvectors();
0185 }
0186
0187
0188 auto calc_spread = [&](size_t i) {
0189 fillPoint(layerClusters[trackster.vertices(i)]);
0190 sigmas += weight * (point - (clean ? filtered_barycenter : barycenter)).cwiseAbs2();
0191 Eigen::Vector3f point_transformed =
0192 eigenvectors_fromEigen * (point - (clean ? filtered_barycenter : barycenter));
0193 if (energyWeight && raw_energy)
0194 weight = (layerClusters[trackster.vertices(i)].energy() / trackster.vertex_multiplicity(i)) *
0195 (clean ? inv_filtered_energy : inv_raw_energy);
0196 sigmasEigen += weight * (point_transformed.cwiseAbs2());
0197 };
0198
0199 if (clean) {
0200 for (size_t i : filtered_idx) {
0201 calc_spread(i);
0202 }
0203 } else {
0204 for (size_t i = 0; i < N; ++i) {
0205 calc_spread(i);
0206 }
0207 }
0208
0209 sigmas /= (1.f - weights2_sum);
0210 sigmasEigen /= (1.f - weights2_sum);
0211
0212 trackster.fillPCAVariables(eigenvalues_fromEigen,
0213 eigenvectors_fromEigen,
0214 sigmas,
0215 sigmasEigen,
0216 3,
0217 ticl::Trackster::PCAOrdering::ascending);
0218
0219 LogDebug("TrackstersPCA") << "EigenValues from Eigen/Tr(cov): " << eigenvalues_fromEigen[2] / covM.trace() << ", "
0220 << eigenvalues_fromEigen[1] / covM.trace() << ", "
0221 << eigenvalues_fromEigen[0] / covM.trace() << std::endl;
0222 LogDebug("TrackstersPCA") << "EigenValues from Eigen: " << eigenvalues_fromEigen[2] << ", "
0223 << eigenvalues_fromEigen[1] << ", " << eigenvalues_fromEigen[0] << std::endl;
0224 LogDebug("TrackstersPCA") << "EigenVector 3 from Eigen: " << eigenvectors_fromEigen(0, 2) << ", "
0225 << eigenvectors_fromEigen(1, 2) << ", " << eigenvectors_fromEigen(2, 2) << std::endl;
0226 LogDebug("TrackstersPCA") << "EigenVector 2 from Eigen: " << eigenvectors_fromEigen(0, 1) << ", "
0227 << eigenvectors_fromEigen(1, 1) << ", " << eigenvectors_fromEigen(2, 1) << std::endl;
0228 LogDebug("TrackstersPCA") << "EigenVector 1 from Eigen: " << eigenvectors_fromEigen(0, 0) << ", "
0229 << eigenvectors_fromEigen(1, 0) << ", " << eigenvectors_fromEigen(2, 0) << std::endl;
0230 LogDebug("TrackstersPCA") << "Original sigmas: " << sigmas[0] << ", " << sigmas[1] << ", " << sigmas[2]
0231 << std::endl;
0232 LogDebug("TrackstersPCA") << "SigmasEigen in PCA space: " << sigmasEigen[2] << ", " << sigmasEigen[1] << ", "
0233 << sigmasEigen[0] << std::endl;
0234 LogDebug("TrackstersPCA") << "covM: \n" << covM << std::endl;
0235 }
0236 }
0237 }
0238
0239 std::pair<float, float> ticl::computeLocalTracksterTime(const Trackster &trackster,
0240 const std::vector<reco::CaloCluster> &layerClusters,
0241 const edm::ValueMap<std::pair<float, float>> &layerClustersTime,
0242 const Eigen::Vector3f &barycenter,
0243 size_t N) {
0244 float tracksterTime = 0.;
0245 float tracksterTimeErr = 0.;
0246
0247 auto project_lc_to_pca = [](const std::array<float, 3> &point, const std::array<float, 3> &segment_end) {
0248 float dot_product = 0.0;
0249 float segment_dot = 0.0;
0250
0251 for (int i = 0; i < 3; ++i) {
0252 dot_product += point[i] * segment_end[i];
0253 segment_dot += segment_end[i] * segment_end[i];
0254 }
0255
0256 float projection = 0.0;
0257 if (segment_dot != 0.0) {
0258 projection = dot_product / segment_dot;
0259 }
0260
0261 std::array<float, 3> closest_point;
0262 for (int i = 0; i < 3; ++i) {
0263 closest_point[i] = projection * segment_end[i];
0264 }
0265
0266 float distanceSquared = 0.f;
0267 for (int i = 0; i < 3; ++i) {
0268 distanceSquared += std::pow(point[i] - closest_point[i], 2);
0269 }
0270 return distanceSquared;
0271 };
0272
0273 constexpr float c = 29.9792458;
0274 for (size_t i = 0; i < N; ++i) {
0275
0276 float timeE = layerClustersTime.get(trackster.vertices(i)).second;
0277 if (timeE > 0.f) {
0278 float time = layerClustersTime.get(trackster.vertices(i)).first;
0279 timeE = 1.f / pow(timeE, 2);
0280 float x = layerClusters[trackster.vertices(i)].x();
0281 float y = layerClusters[trackster.vertices(i)].y();
0282 float z = layerClusters[trackster.vertices(i)].z();
0283
0284 if (project_lc_to_pca({{x, y, z}}, {{barycenter[0], barycenter[1], barycenter[2]}}) < 9.f) {
0285 float invz = 1.f / z;
0286 float deltaT = 1.f / c *
0287 std::sqrt(((barycenter[2] * invz - 1.f) * x) * ((barycenter[2] * invz - 1.f) * x) +
0288 ((barycenter[2] * invz - 1.f) * y) * ((barycenter[2] * invz - 1.f) * y) +
0289 (barycenter[2] - z) * (barycenter[2] - z));
0290 time = std::abs(barycenter[2]) < std::abs(z) ? time - deltaT : time + deltaT;
0291
0292 tracksterTime += time * timeE;
0293 tracksterTimeErr += timeE;
0294 }
0295 }
0296 }
0297 if (tracksterTimeErr > 0.f)
0298 return {tracksterTime / tracksterTimeErr, 1.f / std::sqrt(tracksterTimeErr)};
0299 else
0300 return {-99.f, -1.f};
0301 }
0302
0303 std::pair<float, float> ticl::computeTracksterTime(const Trackster &trackster,
0304 const edm::ValueMap<std::pair<float, float>> &layerClustersTime,
0305 size_t N) {
0306 std::vector<float> times;
0307 std::vector<float> timeErrors;
0308
0309 for (size_t i = 0; i < N; ++i) {
0310 float timeE = layerClustersTime.get(trackster.vertices(i)).second;
0311 if (timeE > 0.f) {
0312 times.push_back(layerClustersTime.get(trackster.vertices(i)).first);
0313 timeErrors.push_back(1.f / pow(timeE, 2));
0314 }
0315 }
0316
0317 hgcalsimclustertime::ComputeClusterTime timeEstimator;
0318 return timeEstimator.fixSizeHighestDensity(times, timeErrors);
0319 }