File indexing completed on 2024-04-06 12:25:12
0001 #include <cmath>
0002 #include <string>
0003 #include "RecoHGCal/TICL/plugins/LinkingAlgoByDirectionGeometric.h"
0004
0005 #include "DataFormats/GeometrySurface/interface/BoundDisk.h"
0006 #include "DataFormats/HGCalReco/interface/Common.h"
0007
0008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0009
0010 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h"
0011
0012 #include "RecoParticleFlow/PFProducer/interface/PFMuonAlgo.h"
0013 #include "DataFormats/HGCalReco/interface/Trackster.h"
0014
0015 using namespace ticl;
0016
0017 LinkingAlgoByDirectionGeometric::LinkingAlgoByDirectionGeometric(const edm::ParameterSet &conf)
0018 : LinkingAlgoBase(conf),
0019 del_tk_ts_layer1_(conf.getParameter<double>("delta_tk_ts_layer1")),
0020 del_tk_ts_int_(conf.getParameter<double>("delta_tk_ts_interface")),
0021 del_ts_em_had_(conf.getParameter<double>("delta_ts_em_had")),
0022 del_ts_had_had_(conf.getParameter<double>("delta_ts_had_had")),
0023 timing_quality_threshold_(conf.getParameter<double>("track_time_quality_threshold")),
0024 cutTk_(conf.getParameter<std::string>("cutTk")) {}
0025
0026 LinkingAlgoByDirectionGeometric::~LinkingAlgoByDirectionGeometric() {}
0027
0028 void LinkingAlgoByDirectionGeometric::initialize(const HGCalDDDConstants *hgcons,
0029 const hgcal::RecHitTools rhtools,
0030 const edm::ESHandle<MagneticField> bfieldH,
0031 const edm::ESHandle<Propagator> propH) {
0032 hgcons_ = hgcons;
0033 rhtools_ = rhtools;
0034 buildLayers();
0035
0036 bfield_ = bfieldH;
0037 propagator_ = propH;
0038 }
0039
0040 Vector LinkingAlgoByDirectionGeometric::propagateTrackster(const Trackster &t,
0041 const unsigned idx,
0042 float zVal,
0043 std::array<TICLLayerTile, 2> &tracksterTiles) {
0044
0045
0046 Vector const &baryc = t.barycenter();
0047 Vector directnv = t.eigenvectors(0);
0048
0049
0050
0051
0052
0053
0054
0055
0056 directnv = baryc.unit();
0057
0058 zVal *= (baryc.Z() > 0) ? 1 : -1;
0059
0060 float par = (zVal - baryc.Z()) / directnv.Z();
0061 float xOnSurface = par * directnv.X() + baryc.X();
0062 float yOnSurface = par * directnv.Y() + baryc.Y();
0063 Vector tPoint(xOnSurface, yOnSurface, zVal);
0064 if (tPoint.Eta() > 0)
0065 tracksterTiles[1].fill(tPoint.Eta(), tPoint.Phi(), idx);
0066
0067 else if (tPoint.Eta() < 0)
0068 tracksterTiles[0].fill(tPoint.Eta(), tPoint.Phi(), idx);
0069
0070 return tPoint;
0071 }
0072
0073 void LinkingAlgoByDirectionGeometric::findTrackstersInWindow(
0074 const std::vector<std::pair<Vector, unsigned>> &seedingCollection,
0075 const std::array<TICLLayerTile, 2> &tracksterTiles,
0076 const std::vector<Vector> &tracksterPropPoints,
0077 float delta,
0078 unsigned trackstersSize,
0079 std::vector<std::vector<unsigned>> &resultCollection,
0080 bool useMask = false) {
0081
0082
0083
0084
0085
0086 std::vector<int> mask(trackstersSize, 0);
0087 float delta2 = delta * delta;
0088
0089 for (auto &i : seedingCollection) {
0090 float seed_eta = i.first.Eta();
0091 float seed_phi = i.first.Phi();
0092 unsigned seedId = i.second;
0093 auto sideZ = seed_eta > 0;
0094 const TICLLayerTile &tile = tracksterTiles[sideZ];
0095 float eta_min = std::max(abs(seed_eta) - delta, (float)TileConstants::minEta);
0096 float eta_max = std::min(abs(seed_eta) + delta, (float)TileConstants::maxEta);
0097
0098
0099 std::array<int, 4> search_box = tile.searchBoxEtaPhi(eta_min, eta_max, seed_phi - delta, seed_phi + delta);
0100
0101 std::vector<unsigned> in_delta;
0102 std::vector<float> distances2;
0103 for (int eta_i = search_box[0]; eta_i <= search_box[1]; ++eta_i) {
0104 for (int phi_i = search_box[2]; phi_i <= search_box[3]; ++phi_i) {
0105 const auto &in_tile = tile[tile.globalBin(eta_i, (phi_i % TileConstants::nPhiBins))];
0106 for (const unsigned &t_i : in_tile) {
0107
0108 auto sep2 = (tracksterPropPoints[t_i].Eta() - seed_eta) * (tracksterPropPoints[t_i].Eta() - seed_eta) +
0109 (tracksterPropPoints[t_i].Phi() - seed_phi) * (tracksterPropPoints[t_i].Phi() - seed_phi);
0110 if (sep2 < delta2) {
0111 in_delta.push_back(t_i);
0112 distances2.push_back(sep2);
0113 }
0114 }
0115 }
0116 }
0117
0118
0119 std::vector<unsigned> indices(in_delta.size());
0120 std::iota(indices.begin(), indices.end(), 0);
0121 std::sort(indices.begin(), indices.end(), [&](unsigned i, unsigned j) { return distances2[i] < distances2[j]; });
0122
0123
0124 for (const unsigned &index : indices) {
0125 const auto &t_i = in_delta[index];
0126 if (!mask[t_i]) {
0127 resultCollection[seedId].push_back(t_i);
0128 if (useMask)
0129 mask[t_i] = 1;
0130 }
0131 }
0132
0133 }
0134 }
0135
0136 bool LinkingAlgoByDirectionGeometric::timeAndEnergyCompatible(float &total_raw_energy,
0137 const reco::Track &track,
0138 const Trackster &trackster,
0139 const float &tkT,
0140 const float &tkTErr,
0141 const float &tkTimeQual,
0142 bool useMTDTiming) {
0143 float threshold = std::min(0.2 * trackster.raw_energy(), 10.0);
0144
0145 bool energyCompatible = (total_raw_energy + trackster.raw_energy() < track.p() + threshold);
0146
0147 if (!useMTDTiming)
0148 return energyCompatible;
0149
0150
0151
0152
0153 float tsT = trackster.time();
0154 float tsTErr = trackster.timeError();
0155
0156 bool timeCompatible = false;
0157
0158 if (tsT == -99. or tkTimeQual < timing_quality_threshold_)
0159 timeCompatible = true;
0160 else {
0161 timeCompatible = (std::abs(tsT - tkT) < maxDeltaT_ * sqrt(tsTErr * tsTErr + tkTErr * tkTErr));
0162 }
0163
0164 if (LinkingAlgoBase::algo_verbosity_ > VerbosityLevel::Advanced) {
0165 if (!(energyCompatible))
0166 LogDebug("LinkingAlgoByDirectionGeometric")
0167 << "energy incompatible : track p " << track.p() << " trackster energy " << trackster.raw_energy() << "\n";
0168 if (!(timeCompatible))
0169 LogDebug("LinkingAlgoByDirectionGeometric") << "time incompatible : track time " << tkT << " +/- " << tkTErr
0170 << " trackster time " << tsT << " +/- " << tsTErr << "\n";
0171 }
0172 return energyCompatible && timeCompatible;
0173 }
0174
0175 void LinkingAlgoByDirectionGeometric::recordTrackster(const unsigned ts,
0176 const std::vector<Trackster> &tracksters,
0177 const edm::Handle<std::vector<Trackster>> tsH,
0178 std::vector<unsigned> &ts_mask,
0179 float &energy_in_candidate,
0180 TICLCandidate &candidate) {
0181 if (ts_mask[ts])
0182 return;
0183 candidate.addTrackster(edm::Ptr<Trackster>(tsH, ts));
0184 ts_mask[ts] = 1;
0185 energy_in_candidate += tracksters[ts].raw_energy();
0186 }
0187
0188 void LinkingAlgoByDirectionGeometric::dumpLinksFound(std::vector<std::vector<unsigned>> &resultCollection,
0189 const char *label) const {
0190 #ifdef EDM_ML_DEBUG
0191 if (!(LinkingAlgoBase::algo_verbosity_ > VerbosityLevel::Advanced))
0192 return;
0193
0194 LogDebug("LinkingAlgoByDirectionGeometric") << "All links found - " << label << "\n";
0195 LogDebug("LinkingAlgoByDirectionGeometric") << "(seed can either be a track or trackster depending on the step)\n";
0196 for (unsigned i = 0; i < resultCollection.size(); ++i) {
0197 LogDebug("LinkingAlgoByDirectionGeometric") << "seed " << i << " - tracksters : ";
0198 const auto &links = resultCollection[i];
0199 for (unsigned j = 0; j < links.size(); ++j) {
0200 LogDebug("LinkingAlgoByDirectionGeometric") << j;
0201 }
0202 LogDebug("LinkingAlgoByDirectionGeometric") << "\n";
0203 }
0204 #endif
0205 }
0206
0207 void LinkingAlgoByDirectionGeometric::buildLayers() {
0208
0209
0210 float zVal = hgcons_->waferZ(1, true);
0211 std::pair<float, float> rMinMax = hgcons_->rangeR(zVal, true);
0212
0213 float zVal_interface = rhtools_.getPositionLayer(rhtools_.lastLayerEE()).z();
0214 std::pair<float, float> rMinMax_interface = hgcons_->rangeR(zVal_interface, true);
0215
0216 for (int iSide = 0; iSide < 2; ++iSide) {
0217 float zSide = (iSide == 0) ? (-1. * zVal) : zVal;
0218 firstDisk_[iSide] =
0219 std::make_unique<GeomDet>(Disk::build(Disk::PositionType(0, 0, zSide),
0220 Disk::RotationType(),
0221 SimpleDiskBounds(rMinMax.first, rMinMax.second, zSide - 0.5, zSide + 0.5))
0222 .get());
0223
0224 zSide = (iSide == 0) ? (-1. * zVal_interface) : zVal_interface;
0225 interfaceDisk_[iSide] = std::make_unique<GeomDet>(
0226 Disk::build(Disk::PositionType(0, 0, zSide),
0227 Disk::RotationType(),
0228 SimpleDiskBounds(rMinMax_interface.first, rMinMax_interface.second, zSide - 0.5, zSide + 0.5))
0229 .get());
0230 }
0231 }
0232
0233 void LinkingAlgoByDirectionGeometric::linkTracksters(const edm::Handle<std::vector<reco::Track>> tkH,
0234 const edm::Handle<edm::ValueMap<float>> tkTime_h,
0235 const edm::Handle<edm::ValueMap<float>> tkTimeErr_h,
0236 const edm::Handle<edm::ValueMap<float>> tkTimeQual_h,
0237 const std::vector<reco::Muon> &muons,
0238 const edm::Handle<std::vector<Trackster>> tsH,
0239 const bool useMTDTiming,
0240 std::vector<TICLCandidate> &resultLinked,
0241 std::vector<TICLCandidate> &chargedHadronsFromTk) {
0242 const auto &tracks = *tkH;
0243 const auto &tracksters = *tsH;
0244
0245 auto bFieldProd = bfield_.product();
0246 const Propagator &prop = (*propagator_);
0247
0248
0249
0250
0251 std::vector<std::pair<Vector, unsigned>> trackPColl;
0252 std::vector<std::pair<Vector, unsigned>> tkPropIntColl;
0253 std::vector<std::pair<Vector, unsigned>> tsPropIntColl;
0254 std::vector<std::pair<Vector, unsigned>> tsHadPropIntColl;
0255 trackPColl.reserve(tracks.size());
0256 tkPropIntColl.reserve(tracks.size());
0257 tsPropIntColl.reserve(tracksters.size());
0258 tsHadPropIntColl.reserve(tracksters.size());
0259
0260 std::array<TICLLayerTile, 2> tracksterPropTiles = {};
0261 std::array<TICLLayerTile, 2> tsPropIntTiles = {};
0262 std::array<TICLLayerTile, 2> tsHadPropIntTiles = {};
0263
0264
0265 auto isHadron = [&](const Trackster &t) -> bool {
0266 auto boundary_z = rhtools_.getPositionLayer(rhtools_.lastLayerEE()).z();
0267 return (std::abs(t.barycenter().Z()) > boundary_z);
0268 };
0269
0270 if (LinkingAlgoBase::algo_verbosity_ > VerbosityLevel::Advanced)
0271 LogDebug("LinkingAlgoByDirectionGeometric") << "------- Geometric Linking ------- \n";
0272
0273
0274 std::vector<unsigned> candidateTrackIds;
0275 candidateTrackIds.reserve(tracks.size());
0276 for (unsigned i = 0; i < tracks.size(); ++i) {
0277 const auto &tk = tracks[i];
0278 reco::TrackRef trackref = reco::TrackRef(tkH, i);
0279
0280
0281 int muId = PFMuonAlgo::muAssocToTrack(trackref, muons);
0282
0283 if (LinkingAlgoBase::algo_verbosity_ > VerbosityLevel::Advanced) {
0284 if (useMTDTiming) {
0285 LogDebug("LinkingAlgoByDirectionGeometric")
0286 << "track " << i << " - eta " << tk.eta() << " phi " << tk.phi() << " time "
0287 << (*tkTime_h)[reco::TrackRef(tkH, i)] << " time qual " << (*tkTimeQual_h)[reco::TrackRef(tkH, i)]
0288 << " muid " << muId << "\n";
0289 } else {
0290 LogDebug("LinkingAlgoByDirectionGeometric")
0291 << "track " << i << " - eta " << tk.eta() << " phi " << tk.phi() << " muid " << muId << "\n";
0292 }
0293 }
0294
0295 if (!cutTk_((tk)) or muId != -1)
0296 continue;
0297
0298
0299 candidateTrackIds.push_back(i);
0300
0301
0302 if (std::sqrt(tk.p() * tk.p() + ticl::mpion2) < tkEnergyCut_)
0303 continue;
0304
0305 int iSide = int(tk.eta() > 0);
0306 const auto &fts = trajectoryStateTransform::outerFreeState((tk), bFieldProd);
0307
0308 const auto &tsos = prop.propagate(fts, firstDisk_[iSide]->surface());
0309 if (tsos.isValid()) {
0310 Vector trackP(tsos.globalPosition().x(), tsos.globalPosition().y(), tsos.globalPosition().z());
0311 trackPColl.emplace_back(trackP, i);
0312 }
0313
0314 const auto &tsos_int = prop.propagate(fts, interfaceDisk_[iSide]->surface());
0315 if (tsos_int.isValid()) {
0316 Vector trackP(tsos_int.globalPosition().x(), tsos_int.globalPosition().y(), tsos_int.globalPosition().z());
0317 tkPropIntColl.emplace_back(trackP, i);
0318 }
0319 }
0320 tkPropIntColl.shrink_to_fit();
0321 trackPColl.shrink_to_fit();
0322 candidateTrackIds.shrink_to_fit();
0323
0324
0325
0326
0327
0328
0329 std::vector<Vector> tsAllProp;
0330 std::vector<Vector> tsAllPropInt;
0331 tsAllProp.reserve(tracksters.size());
0332 tsAllPropInt.reserve(tracksters.size());
0333
0334 for (unsigned i = 0; i < tracksters.size(); ++i) {
0335 const auto &t = tracksters[i];
0336 if (LinkingAlgoBase::algo_verbosity_ > VerbosityLevel::Advanced)
0337 LogDebug("LinkingAlgoByDirectionGeometric")
0338 << "trackster " << i << " - eta " << t.barycenter().eta() << " phi " << t.barycenter().phi() << " time "
0339 << t.time() << " energy " << t.raw_energy() << "\n";
0340
0341
0342 float zVal = hgcons_->waferZ(1, true);
0343 auto tsP = propagateTrackster(t, i, zVal, tracksterPropTiles);
0344 tsAllProp.emplace_back(tsP);
0345
0346
0347 zVal = rhtools_.getPositionLayer(rhtools_.lastLayerEE()).z();
0348 tsP = propagateTrackster(t, i, zVal, tsPropIntTiles);
0349 tsAllPropInt.emplace_back(tsP);
0350
0351 if (!isHadron(t))
0352 tsPropIntColl.emplace_back(tsP, i);
0353 else {
0354 tsHadPropIntTiles[(t.barycenter().Z() > 0) ? 1 : 0].fill(tsP.Eta(), tsP.Phi(), i);
0355 tsHadPropIntColl.emplace_back(tsP, i);
0356 }
0357 }
0358 tsPropIntColl.shrink_to_fit();
0359 tsHadPropIntColl.shrink_to_fit();
0360
0361
0362
0363
0364 std::vector<std::vector<unsigned>> tsNearTk(tracks.size());
0365 findTrackstersInWindow(trackPColl, tracksterPropTiles, tsAllProp, del_tk_ts_layer1_, tracksters.size(), tsNearTk);
0366
0367
0368
0369 std::vector<std::vector<unsigned>> tsNearTkAtInt(tracks.size());
0370 findTrackstersInWindow(tkPropIntColl, tsPropIntTiles, tsAllPropInt, del_tk_ts_int_, tracksters.size(), tsNearTkAtInt);
0371
0372
0373
0374
0375 std::vector<std::vector<unsigned>> tsNearAtInt(tracksters.size());
0376 findTrackstersInWindow(
0377 tsPropIntColl, tsHadPropIntTiles, tsAllPropInt, del_ts_em_had_, tracksters.size(), tsNearAtInt);
0378
0379
0380
0381 std::vector<std::vector<unsigned>> tsHadNearAtInt(tracksters.size());
0382 findTrackstersInWindow(
0383 tsHadPropIntColl, tsHadPropIntTiles, tsAllPropInt, del_ts_had_had_, tracksters.size(), tsHadNearAtInt);
0384
0385 #ifdef EDM_ML_DEBUG
0386 dumpLinksFound(tsNearTk, "track -> tracksters at layer 1");
0387 dumpLinksFound(tsNearTkAtInt, "track -> tracksters at lastLayerEE");
0388 dumpLinksFound(tsNearAtInt, "EM -> HAD tracksters at lastLayerEE");
0389 dumpLinksFound(tsHadNearAtInt, "HAD -> HAD tracksters at lastLayerEE");
0390 #endif
0391
0392
0393
0394 std::vector<TICLCandidate> chargedCandidates;
0395 std::vector<unsigned int> chargedMask(tracksters.size(), 0);
0396 for (unsigned &i : candidateTrackIds) {
0397 if (tsNearTk[i].empty() && tsNearTkAtInt[i].empty()) {
0398 TICLCandidate chargedHad;
0399 chargedHad.setTrackPtr(edm::Ptr<reco::Track>(tkH, i));
0400 chargedHadronsFromTk.push_back(chargedHad);
0401 continue;
0402 }
0403
0404 TICLCandidate chargedCandidate;
0405 float total_raw_energy = 0.;
0406
0407 auto tkRef = reco::TrackRef(tkH, i);
0408 float track_time = 0.f;
0409 float track_timeErr = 0.f;
0410 float track_timeQual = 0.f;
0411 if (useMTDTiming) {
0412 track_time = (*tkTime_h)[tkRef];
0413 track_timeErr = (*tkTimeErr_h)[tkRef];
0414 track_timeQual = (*tkTimeQual_h)[tkRef];
0415 }
0416
0417 for (const unsigned ts3_idx : tsNearTk[i]) {
0418 if (timeAndEnergyCompatible(total_raw_energy,
0419 tracks[i],
0420 tracksters[ts3_idx],
0421 track_time,
0422 track_timeErr,
0423 track_timeQual,
0424 useMTDTiming)) {
0425 recordTrackster(ts3_idx, tracksters, tsH, chargedMask, total_raw_energy, chargedCandidate);
0426 }
0427 for (const unsigned ts2_idx : tsNearAtInt[ts3_idx]) {
0428 if (timeAndEnergyCompatible(total_raw_energy,
0429 tracks[i],
0430 tracksters[ts2_idx],
0431 track_time,
0432 track_timeErr,
0433 track_timeQual,
0434 useMTDTiming)) {
0435 recordTrackster(ts2_idx, tracksters, tsH, chargedMask, total_raw_energy, chargedCandidate);
0436 }
0437 for (const unsigned ts1_idx : tsHadNearAtInt[ts2_idx]) {
0438 if (timeAndEnergyCompatible(total_raw_energy,
0439 tracks[i],
0440 tracksters[ts1_idx],
0441 track_time,
0442 track_timeErr,
0443 track_timeQual,
0444 useMTDTiming)) {
0445 recordTrackster(ts1_idx, tracksters, tsH, chargedMask, total_raw_energy, chargedCandidate);
0446 }
0447 }
0448 }
0449 for (const unsigned ts1_idx : tsHadNearAtInt[ts3_idx]) {
0450 if (timeAndEnergyCompatible(total_raw_energy,
0451 tracks[i],
0452 tracksters[ts1_idx],
0453 track_time,
0454 track_timeErr,
0455 track_timeQual,
0456 useMTDTiming)) {
0457 recordTrackster(ts1_idx, tracksters, tsH, chargedMask, total_raw_energy, chargedCandidate);
0458 }
0459 }
0460 }
0461 for (const unsigned ts4_idx : tsNearTkAtInt[i]) {
0462 if (timeAndEnergyCompatible(total_raw_energy,
0463 tracks[i],
0464 tracksters[ts4_idx],
0465 track_time,
0466 track_timeErr,
0467 track_timeQual,
0468 useMTDTiming)) {
0469 recordTrackster(ts4_idx, tracksters, tsH, chargedMask, total_raw_energy, chargedCandidate);
0470 }
0471 for (const unsigned ts2_idx : tsNearAtInt[ts4_idx]) {
0472 if (timeAndEnergyCompatible(total_raw_energy,
0473 tracks[i],
0474 tracksters[ts2_idx],
0475 track_time,
0476 track_timeErr,
0477 track_timeQual,
0478 useMTDTiming)) {
0479 recordTrackster(ts2_idx, tracksters, tsH, chargedMask, total_raw_energy, chargedCandidate);
0480 }
0481 for (const unsigned ts1_idx : tsHadNearAtInt[ts2_idx]) {
0482 if (timeAndEnergyCompatible(total_raw_energy,
0483 tracks[i],
0484 tracksters[ts1_idx],
0485 track_time,
0486 track_timeErr,
0487 track_timeQual,
0488 useMTDTiming)) {
0489 recordTrackster(ts1_idx, tracksters, tsH, chargedMask, total_raw_energy, chargedCandidate);
0490 }
0491 }
0492 }
0493 for (const unsigned ts1_idx : tsHadNearAtInt[ts4_idx]) {
0494 if (timeAndEnergyCompatible(total_raw_energy,
0495 tracks[i],
0496 tracksters[ts1_idx],
0497 track_time,
0498 track_timeErr,
0499 track_timeQual,
0500 useMTDTiming)) {
0501 recordTrackster(ts1_idx, tracksters, tsH, chargedMask, total_raw_energy, chargedCandidate);
0502 }
0503 }
0504 }
0505
0506
0507
0508 if (!chargedCandidate.tracksters().empty()) {
0509 chargedCandidate.setTrackPtr(edm::Ptr<reco::Track>(tkH, i));
0510 chargedCandidates.push_back(chargedCandidate);
0511 } else {
0512 TICLCandidate chargedHad;
0513 chargedHad.setTrackPtr(edm::Ptr<reco::Track>(tkH, i));
0514 chargedHadronsFromTk.push_back(chargedHad);
0515 }
0516 }
0517
0518 std::vector<TICLCandidate> neutralCandidates;
0519 std::vector<int> neutralMask(tracksters.size(), 0);
0520 for (unsigned i = 0; i < tracksters.size(); ++i) {
0521 if (chargedMask[i])
0522 continue;
0523
0524 TICLCandidate neutralCandidate;
0525 if (tsNearAtInt[i].empty() && tsHadNearAtInt[i].empty() && !neutralMask[i]) {
0526 neutralCandidate.addTrackster(edm::Ptr<Trackster>(tsH, i));
0527 neutralMask[i] = 1;
0528 neutralCandidates.push_back(neutralCandidate);
0529 continue;
0530 }
0531 if (!neutralMask[i]) {
0532 neutralCandidate.addTrackster(edm::Ptr<Trackster>(tsH, i));
0533 neutralMask[i] = 1;
0534 }
0535 for (const unsigned ts2_idx : tsNearAtInt[i]) {
0536 if (chargedMask[ts2_idx])
0537 continue;
0538 if (!neutralMask[ts2_idx]) {
0539 neutralCandidate.addTrackster(edm::Ptr<Trackster>(tsH, ts2_idx));
0540 neutralMask[ts2_idx] = 1;
0541 }
0542 for (const unsigned ts1_idx : tsHadNearAtInt[ts2_idx]) {
0543 if (chargedMask[ts1_idx])
0544 continue;
0545 if (!neutralMask[ts1_idx]) {
0546 neutralCandidate.addTrackster(edm::Ptr<Trackster>(tsH, ts1_idx));
0547 neutralMask[ts1_idx] = 1;
0548 }
0549 }
0550 }
0551 for (const unsigned ts1_idx : tsHadNearAtInt[i]) {
0552 if (chargedMask[ts1_idx])
0553 continue;
0554 if (!neutralMask[ts1_idx]) {
0555 neutralCandidate.addTrackster(edm::Ptr<Trackster>(tsH, ts1_idx));
0556 neutralMask[ts1_idx] = 1;
0557 }
0558 }
0559
0560 if (!neutralCandidate.tracksters().empty()) {
0561 neutralCandidates.push_back(neutralCandidate);
0562 }
0563 }
0564
0565 resultLinked.insert(std::end(resultLinked), std::begin(neutralCandidates), std::end(neutralCandidates));
0566 resultLinked.insert(std::end(resultLinked), std::begin(chargedCandidates), std::end(chargedCandidates));
0567
0568 }
0569
0570 void LinkingAlgoByDirectionGeometric::fillPSetDescription(edm::ParameterSetDescription &desc) {
0571 desc.add<std::string>("cutTk",
0572 "1.48 < abs(eta) < 3.0 && pt > 1. && quality(\"highPurity\") && "
0573 "hitPattern().numberOfLostHits(\"MISSING_OUTER_HITS\") < 5");
0574 desc.add<double>("delta_tk_ts_layer1", 0.02);
0575 desc.add<double>("delta_tk_ts_interface", 0.03);
0576 desc.add<double>("delta_ts_em_had", 0.03);
0577 desc.add<double>("delta_ts_had_had", 0.03);
0578 desc.add<double>("track_time_quality_threshold", 0.5);
0579 LinkingAlgoBase::fillPSetDescription(desc);
0580 }