9 #include <ecl/modules/eclTrackClusterMatching/ECLTrackClusterMatchingModule.h>
11 #include <ecl/dbobjects/ECLTrackClusterMatchingParameterizations.h>
12 #include <ecl/dbobjects/ECLTrackClusterMatchingThresholds.h>
13 #include <ecl/utility/utilityFunctions.h>
15 #include <framework/gearbox/Const.h>
16 #include <framework/logging/Logger.h>
17 #include <mdst/dataobjects/HitPatternCDC.h>
28 setDescription(
"Creates and saves a Relation between Tracks and ECLCluster in the DataStore. It uses the existing Relation between Tracks and ExtHit as well as the Relation between ECLCluster and ExtHit.");
29 setPropertyFlags(c_ParallelProcessingCertified);
30 addParam(
"useAngularDistanceMatching", m_angularDistanceMatching,
31 "if true use track cluster matching based on angular distance, if false use matching based on entered crystals",
bool(
true));
32 addParam(
"useOptimizedMatchingConsistency", m_useOptimizedMatchingConsistency,
33 "set false if you want to set the matching criterion on your own",
bool(
true));
34 addParam(
"matchingConsistency", m_matchingConsistency,
35 "the 2D consistency of Delta theta and Delta phi has to exceed this value for a track to be matched to an ECL cluster", 1e-6);
36 addParam(
"matchingPTThreshold", m_matchingPTThreshold,
37 "tracks with pt greater than this value will exclusively be matched based on angular distance", 0.3);
38 addParam(
"brlEdgeTheta", m_brlEdgeTheta,
39 "distance of polar angle from gaps where crystal-entering based matching is applied (in rad)", 0.1);
40 addParam(
"minimalCDCHits", m_minimalCDCHits,
41 "bad VXD-standalone tracks cause (too) low photon efficiency in end caps, temporarily fixed by requiring minimal number of CDC hits",
43 addParam(
"skipZeroChargeTracks", m_skipZeroChargeTracks,
44 "switch to exclude tracks with zero charge from track-cluster matching",
bool(
false));
47 ECLTrackClusterMatchingModule::~ECLTrackClusterMatchingModule()
51 void ECLTrackClusterMatchingModule::initialize()
54 m_tracks.isRequired();
55 m_eclClusters.isRequired();
56 m_eclShowers.isRequired();
57 m_eclCalDigits.isRequired();
58 m_extHits.isRequired();
59 m_trackFitResults.isRequired();
61 if (m_angularDistanceMatching) {
62 m_tracks.registerRelationTo(m_eclShowers);
63 m_tracks.registerRelationTo(m_eclClusters);
64 m_tracks.registerRelationTo(m_eclShowers, DataStore::c_Event, DataStore::c_WriteOut,
"AngularDistance");
65 m_tracks.registerRelationTo(m_eclClusters, DataStore::c_Event, DataStore::c_WriteOut,
"AngularDistance");
68 auto updateParameterizationFunctions = [
this]() {
69 const auto& map = m_matchingParameterizations->getRMSParameterizations();
71 f_phiRMSFWDCROSS = map.at(
"PhiFWDCROSS");
72 f_phiRMSFWDDL = map.at(
"PhiFWDDL");
73 f_phiRMSFWDNEAR = map.at(
"PhiFWDNEAR");
74 f_phiRMSBRLCROSS = map.at(
"PhiBRLCROSS");
75 f_phiRMSBRLDL = map.at(
"PhiBRLDL");
76 f_phiRMSBRLNEAR = map.at(
"PhiBRLNEAR");
77 f_phiRMSBWDCROSS = map.at(
"PhiBWDCROSS");
78 f_phiRMSBWDDL = map.at(
"PhiBWDDL");
79 f_phiRMSBWDNEAR = map.at(
"PhiBWDNEAR");
80 f_thetaRMSFWDCROSS = map.at(
"ThetaFWDCROSS");
81 f_thetaRMSFWDDL = map.at(
"ThetaFWDDL");
82 f_thetaRMSFWDNEAR = map.at(
"ThetaFWDNEAR");
83 f_thetaRMSBRLCROSS = map.at(
"ThetaBRLCROSS");
84 f_thetaRMSBRLDL = map.at(
"ThetaBRLDL");
85 f_thetaRMSBRLNEAR = map.at(
"ThetaBRLNEAR");
86 f_thetaRMSBWDCROSS = map.at(
"ThetaBWDCROSS");
87 f_thetaRMSBWDDL = map.at(
"ThetaBWDDL");
88 f_thetaRMSBWDNEAR = map.at(
"ThetaBWDNEAR");
92 auto updateMatchingThresholds = [
this]() {
93 m_matchingThresholdValuesFWD = m_matchingThresholds->getFWDMatchingThresholdValues();
94 m_matchingThresholdValuesBRL = m_matchingThresholds->getBRLMatchingThresholdValues();
95 m_matchingThresholdValuesBWD = m_matchingThresholds->getBWDMatchingThresholdValues();
99 updateParameterizationFunctions();
100 updateMatchingThresholds();
102 m_matchingParameterizations.addCallback(updateParameterizationFunctions);
103 m_matchingThresholds.addCallback(updateMatchingThresholds);
105 m_tracks.registerRelationTo(m_eclShowers, DataStore::c_Event, DataStore::c_WriteOut,
"EnterCrystal");
106 m_tracks.registerRelationTo(m_eclClusters, DataStore::c_Event, DataStore::c_WriteOut,
"EnterCrystal");
110 void ECLTrackClusterMatchingModule::event()
112 for (
auto& eclCluster : m_eclClusters) {
113 eclCluster.setIsTrack(
false);
115 for (
const Track& track : m_tracks) {
116 const TrackFitResult* fitResult = track.getTrackFitResultWithClosestMass(Const::pion);
119 if (m_skipZeroChargeTracks && fitResult->
getChargeSign() == 0)
continue;
120 double theta = TMath::ACos(fitResult->
getMomentum().CosTheta());
122 if (!m_angularDistanceMatching || pt < m_matchingPTThreshold || trackTowardsGap(theta)) {
125 set<int> uniqueShowerIds;
128 set<int> uniquehypothesisIds;
129 vector<int> hypothesisIds;
130 vector<double> energies;
131 vector<int> arrayIndexes;
137 for (
const auto& extHit : track.getRelationsTo<
ExtHit>()) {
138 if (!isECLEnterHit(extHit))
continue;
139 const int cell = extHit.getCopyID() + 1;
142 const auto idigit = find_if(m_eclCalDigits.begin(), m_eclCalDigits.end(),
143 [&](
const ECLCalDigit & d) { return d.getCellId() == cell; }
146 if (idigit == m_eclCalDigits.end())
continue;
149 for (
auto& shower : idigit->getRelationsFrom<
ECLShower>()) {
150 bool inserted = (uniqueShowerIds.insert(shower.getUniqueId())).second;
153 if (!inserted)
continue;
155 hypothesisIds.push_back(shower.getHypothesisId());
156 energies.push_back(shower.getEnergy());
157 arrayIndexes.push_back(shower.getArrayIndex());
158 uniquehypothesisIds.insert(shower.getHypothesisId());
160 B2DEBUG(29, shower.getArrayIndex() <<
" " << shower.getHypothesisId() <<
" " << shower.getEnergy() <<
" " <<
161 shower.getConnectedRegionId());
167 for (
auto hypothesisId : uniquehypothesisIds) {
168 double highestEnergy = 0.0;
171 for (
unsigned ix = 0; ix < energies.size(); ix++) {
172 if (hypothesisIds[ix] == hypothesisId and energies[ix] > highestEnergy) {
173 highestEnergy = energies[ix];
174 arrayindex = arrayIndexes[ix];
179 if (arrayindex > -1) {
180 auto shower = m_eclShowers[arrayindex];
181 shower->setIsTrack(
true);
182 if (m_angularDistanceMatching) {
183 track.addRelationTo(shower);
184 track.addRelationTo(shower, 1.0,
"AngularDistance");
186 track.addRelationTo(shower, 1.0,
"EnterCrystal");
188 B2DEBUG(29, shower->getArrayIndex() <<
" " << shower->getIsTrack());
192 if (cluster !=
nullptr) {
193 cluster->setIsTrack(
true);
194 if (m_angularDistanceMatching) {
195 track.addRelationTo(cluster);
196 track.addRelationTo(cluster, 1.0,
"AngularDistance");
198 track.addRelationTo(cluster, 1.0,
"EnterCrystal");
204 if (m_angularDistanceMatching) {
206 if (track.getRelationsTo<
ECLCluster>(
"",
"AngularDistance").size() > 0)
continue;
208 if (trackTowardsGap(theta))
continue;
210 ECL::DetectorRegion trackDetectorRegion = ECL::getDetectorRegion(theta);
211 if (pt < m_matchingPTThreshold && trackDetectorRegion != ECL::DetectorRegion::FWD)
continue;
213 map<int, pair<double, int>> hypothesisIdBestQualityCROSSArrayIndexMap;
214 map<int, pair<double, int>> hypothesisIdBestQualityDLArrayIndexMap;
215 map<int, pair<double, int>> hypothesisIdBestQualityNEARArrayIndexMap;
216 set<int> uniqueHypothesisIds;
221 for (
const auto& extHit : track.getRelationsTo<
ExtHit>()) {
222 if (!isECLHit(extHit))
continue;
224 if (!eclCluster)
continue;
226 if (eclShower !=
nullptr) {
229 if (abs(eclDetectorRegion - trackDetectorRegion) == 1)
continue;
231 if (pt < m_matchingPTThreshold && eclDetectorRegion == ECL::DetectorRegion::BRL)
continue;
232 double phiHit = extHit.getPosition().Phi();
233 double phiShower = eclShower->
getPhi();
234 double deltaPhi = phiHit - phiShower;
235 if (deltaPhi > M_PI) {
236 deltaPhi = deltaPhi - 2 * M_PI;
237 }
else if (deltaPhi < -M_PI) {
238 deltaPhi = deltaPhi + 2 * M_PI;
240 double thetaHit = extHit.getPosition().Theta();
241 double thetaShower = eclShower->
getTheta();
242 double deltaTheta = thetaHit - thetaShower;
244 double quality = showerQuality(deltaPhi, deltaTheta, pt, eclDetectorRegion, extHitStatus);
246 bool inserted = (uniqueHypothesisIds.insert(hypothesisId)).second;
248 hypothesisIdBestQualityCROSSArrayIndexMap.insert(make_pair(hypothesisId, make_pair(0, -1)));
249 hypothesisIdBestQualityDLArrayIndexMap.insert(make_pair(hypothesisId, make_pair(0, -1)));
250 hypothesisIdBestQualityNEARArrayIndexMap.insert(make_pair(hypothesisId, make_pair(0, -1)));
252 if (extHitStatus == EXT_ECLCROSS) {
253 if (quality > hypothesisIdBestQualityCROSSArrayIndexMap.at(hypothesisId).first) {
254 hypothesisIdBestQualityCROSSArrayIndexMap[hypothesisId] = make_pair(quality, eclShower->
getArrayIndex());
256 }
else if (extHitStatus == EXT_ECLDL) {
257 if (quality > hypothesisIdBestQualityDLArrayIndexMap.at(hypothesisId).first) {
258 hypothesisIdBestQualityDLArrayIndexMap[hypothesisId] = make_pair(quality, eclShower->
getArrayIndex());
261 if (quality > hypothesisIdBestQualityNEARArrayIndexMap.at(hypothesisId).first) {
262 hypothesisIdBestQualityNEARArrayIndexMap[hypothesisId] = make_pair(quality, eclShower->
getArrayIndex());
268 vector<map<int, pair<double, int>>> hypothesisIdBestQualityArrayIndexMaps;
269 hypothesisIdBestQualityArrayIndexMaps.push_back(hypothesisIdBestQualityCROSSArrayIndexMap);
270 hypothesisIdBestQualityArrayIndexMaps.push_back(hypothesisIdBestQualityDLArrayIndexMap);
271 hypothesisIdBestQualityArrayIndexMaps.push_back(hypothesisIdBestQualityNEARArrayIndexMap);
272 if (m_useOptimizedMatchingConsistency) optimizedPTMatchingConsistency(theta, pt);
273 for (
const auto& uniqueHypothesisId : uniqueHypothesisIds) {
274 for (
const auto& hypothesisIdBestQualityArrayIndexMap : hypothesisIdBestQualityArrayIndexMaps) {
275 if (hypothesisIdBestQualityArrayIndexMap.at(uniqueHypothesisId).first > m_matchingConsistency
276 && hypothesisIdBestQualityArrayIndexMap.at(uniqueHypothesisId).second > -1) {
277 auto shower = m_eclShowers[hypothesisIdBestQualityArrayIndexMap.at(uniqueHypothesisId).second];
278 shower->setIsTrack(
true);
279 track.addRelationTo(shower);
280 track.addRelationTo(shower, 1.0,
"AngularDistance");
282 if (cluster !=
nullptr) {
283 cluster->setIsTrack(
true);
284 track.addRelationTo(cluster);
285 track.addRelationTo(cluster, 1.0,
"AngularDistance");
295 void ECLTrackClusterMatchingModule::terminate()
299 bool ECLTrackClusterMatchingModule::isECLEnterHit(
const ExtHit& extHit)
const
301 if ((extHit.
getDetectorID() != Const::EDetector::ECL))
return false;
302 if ((extHit.
getStatus() != EXT_ENTER))
return false;
303 if (extHit.
getCopyID() == -1)
return false;
307 bool ECLTrackClusterMatchingModule::isECLHit(
const ExtHit& extHit)
const
309 if ((extHit.
getDetectorID() != Const::EDetector::ECL))
return false;
311 if (extHitStatus == EXT_ECLCROSS || extHitStatus == EXT_ECLDL || extHitStatus == EXT_ECLNEAR)
return true;
315 double ECLTrackClusterMatchingModule::showerQuality(
double deltaPhi,
double deltaTheta,
double pt,
316 int eclDetectorRegion,
int hitStatus)
const
318 double phi_consistency = phiConsistency(deltaPhi, pt, eclDetectorRegion, hitStatus);
319 double theta_consistency = thetaConsistency(deltaTheta, pt, eclDetectorRegion, hitStatus);
320 return phi_consistency * theta_consistency * (1 - log(phi_consistency * theta_consistency));
323 double ECLTrackClusterMatchingModule::phiConsistency(
double deltaPhi,
double pt,
int eclDetectorRegion,
int hitStatus)
const
326 if (eclDetectorRegion == ECL::DetectorRegion::FWD || eclDetectorRegion == ECL::DetectorRegion::FWDGap) {
327 if (hitStatus == EXT_ECLCROSS) {
328 phi_RMS = f_phiRMSFWDCROSS.Eval(pt);
329 }
else if (hitStatus == EXT_ECLDL) {
330 phi_RMS = f_phiRMSFWDDL.Eval(pt);
332 phi_RMS = f_phiRMSFWDNEAR.Eval(pt);
334 }
else if (eclDetectorRegion == ECL::DetectorRegion::BRL) {
335 if (hitStatus == EXT_ECLCROSS) {
336 phi_RMS = f_phiRMSBRLCROSS.Eval(pt);
337 }
else if (hitStatus == EXT_ECLDL) {
338 phi_RMS = f_phiRMSBRLDL.Eval(pt);
340 phi_RMS = f_phiRMSBRLNEAR.Eval(pt);
342 }
else if (eclDetectorRegion == ECL::DetectorRegion::BWD || eclDetectorRegion == ECL::DetectorRegion::BWDGap) {
343 if (hitStatus == EXT_ECLCROSS) {
344 phi_RMS = f_phiRMSBWDCROSS.Eval(pt);
345 }
else if (hitStatus == EXT_ECLDL) {
346 phi_RMS = f_phiRMSBWDDL.Eval(pt);
348 phi_RMS = f_phiRMSBWDNEAR.Eval(pt);
353 return erfc(abs(deltaPhi) / phi_RMS);
356 double ECLTrackClusterMatchingModule::thetaConsistency(
double deltaTheta,
double pt,
int eclDetectorRegion,
int hitStatus)
const
359 if (eclDetectorRegion == ECL::DetectorRegion::FWD || eclDetectorRegion == ECL::DetectorRegion::FWDGap) {
360 if (hitStatus == EXT_ECLCROSS) {
361 theta_RMS = f_thetaRMSFWDCROSS.Eval(pt);
362 }
else if (hitStatus == EXT_ECLDL) {
363 theta_RMS = f_thetaRMSFWDDL.Eval(pt);
365 theta_RMS = f_thetaRMSFWDNEAR.Eval(pt);
367 }
else if (eclDetectorRegion == ECL::DetectorRegion::BRL) {
368 if (hitStatus == EXT_ECLCROSS) {
369 theta_RMS = f_thetaRMSBRLCROSS.Eval(pt);
370 }
else if (hitStatus == EXT_ECLDL) {
371 theta_RMS = f_thetaRMSBRLDL.Eval(pt);
373 theta_RMS = f_thetaRMSBRLNEAR.Eval(pt);
375 }
else if (eclDetectorRegion == ECL::DetectorRegion::BWD || eclDetectorRegion == ECL::DetectorRegion::BWDGap) {
376 if (hitStatus == EXT_ECLCROSS) {
377 theta_RMS = f_thetaRMSBWDCROSS.Eval(pt);
378 }
else if (hitStatus == EXT_ECLDL) {
379 theta_RMS = f_thetaRMSBWDDL.Eval(pt);
381 theta_RMS = f_thetaRMSBWDNEAR.Eval(pt);
386 return erfc(abs(deltaTheta) / theta_RMS);
389 bool ECLTrackClusterMatchingModule::trackTowardsGap(
double theta)
const
391 if (ECL::getDetectorRegion(theta) == ECL::DetectorRegion::BRL) {
392 if (ECL::getDetectorRegion(theta - m_brlEdgeTheta) != ECL::DetectorRegion::BRL)
return true;
393 else if (ECL::getDetectorRegion(theta + m_brlEdgeTheta) != ECL::DetectorRegion::BRL)
return true;
398 void ECLTrackClusterMatchingModule::optimizedPTMatchingConsistency(
double theta,
double pt)
400 if (ECL::getDetectorRegion(theta) == ECL::DetectorRegion::FWD || ECL::getDetectorRegion(theta) == ECL::DetectorRegion::FWDGap) {
401 for (
const auto& matchingThresholdPair : m_matchingThresholdValuesFWD) {
402 if (pt < matchingThresholdPair.first) {
403 m_matchingConsistency = matchingThresholdPair.second;
407 }
else if (ECL::getDetectorRegion(theta) == ECL::DetectorRegion::BRL) {
408 for (
const auto& matchingThresholdPair : m_matchingThresholdValuesBRL) {
409 if (theta < matchingThresholdPair.first && pt < matchingThresholdPair.second.first) {
410 m_matchingConsistency = matchingThresholdPair.second.second;
414 }
else if (ECL::getDetectorRegion(theta) == ECL::DetectorRegion::BWD
415 || ECL::getDetectorRegion(theta) == ECL::DetectorRegion::BWDGap) {
416 for (
const auto& matchingThresholdPair : m_matchingThresholdValuesBWD) {
417 if (pt < matchingThresholdPair.first) {
418 m_matchingConsistency = matchingThresholdPair.second;