ATLAS Offline Software
Loading...
Searching...
No Matches
TRT_SegmentToTrackTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
10
11#include <cmath>
12
13using Amg::Vector3D;
14using CLHEP::mm;
15
16namespace {
17 Amg::Vector2D project2D(const Amg::Vector3D &vec) {
18 Amg::Vector2D tmp{vec[0],vec[1] };
19 return tmp;
20 }
21}
22namespace InDet {
23
24 // Constructor with parameters:
26 const std::string &name,
27 const IInterface *parent) :
28 AthAlgTool(type,name,parent)
29 {
30 declareInterface<InDet::ITRT_SegmentToTrackTool>( this );
31 }
32
34 = default;
35
36
38
39 ATH_CHECK( AthAlgTool::initialize() );
40
41 ATH_CHECK(m_extrapolator.retrieve() );
42
43 ATH_CHECK(m_fitterTool.retrieve(DisableTool{ !m_doRefit }));
44 ATH_CHECK(m_assoTool.retrieve( DisableTool{m_assoTool.name().empty()} ));
45 ATH_CHECK(m_trackSummaryTool.retrieve( DisableTool{m_trackSummaryTool.name().empty()} ));
46
47 // Get the scoring tool
48 ATH_CHECK( m_scoringTool.retrieve() );
49
50 ATH_CHECK( detStore()->retrieve(m_trtId, "TRT_ID") );
54
55 // Get output print level
56 //
57 ATH_MSG_DEBUG( *this );
58
59 return StatusCode::SUCCESS;
60
61 }
62
64 StatusCode sc = AthAlgTool::finalize();
65 return sc;
66 }
67
68
70 // Dumps relevant information into the MsgStream
72 MsgStream& InDet::TRT_SegmentToTrackTool::dump( MsgStream& out ) const {
73 out<<std::endl;
74 return dumpconditions(out);
75 }
76
78 // Dumps conditions information into the MsgStream
80
81 MsgStream& InDet::TRT_SegmentToTrackTool::dumpconditions( MsgStream& out ) const
82 {
83 int n = 65-m_fitterTool.type().size();
84 std::string s1; for(int i=0; i<n; ++i) s1.append(" "); s1.append("|");
85 n = 65-m_assoTool.type().size();
86 std::string s2; for(int i=0; i<n; ++i) s2.append(" "); s2.append("|");
87 n = 65-m_scoringTool.type().size();
88 std::string s5; for(int i=0; i<n; ++i) s5.append(" "); s5.append("|");
89
90
91 out<<std::endl
92 <<"|----------------------------------------------------------------------"
93 <<"-------------------|"<<std::endl;
94 out<<"| Tool for final track refitting | "<<m_fitterTool.type() <<s1<<std::endl;
95 out<<"| Tool for track scoring | "<<m_scoringTool.type() <<s5<<std::endl;
96 out<<"| Association service | "<<m_assoTool.type() <<s2<<std::endl;
97 out<<"|----------------------------------------------------------------------"
98 <<"-------------------|";
99 return out;
100 }
101
102
104 // Dumps event information into the MsgStream
106 MsgStream& InDet::TRT_SegmentToTrackTool::dumpevent( MsgStream& out ) {
107 return out;
108 }
109
111 // Dumps relevant information into the ostream
113
114 std::ostream& InDet::TRT_SegmentToTrackTool::dump( std::ostream& out ) const
115 {
116 return out;
117 }
118
119
120 Trk::Track* TRT_SegmentToTrackTool::segToTrack(const EventContext& ctx, const Trk::TrackSegment& tS) const {
121
122 ATH_MSG_DEBUG("Transforming the TRT segment into a track...");
123
124 //
125 // Get the track segment fit quality. If not there drop segment
126 //
127 if (!tS.fitQuality()) {
128 ATH_MSG_DEBUG("Segment has no fit quality ! Discard...");
129 return nullptr;
130 }
131 auto fq = tS.fitQuality()->uniqueClone();
132
133 //
134 // Get the track segment information about the initial track parameters
135 //
136 const AmgVector(5)& par = tS.localParameters();
138 const Trk::TrackParameters* segPar =
141 par[Trk::loc2],
142 par[Trk::phi],
143 par[Trk::theta],
144 par[Trk::qOverP],
145 std::move(ep))
146 .release();
147
148 if (segPar) {
149 ATH_MSG_VERBOSE("Initial TRT Segment Parameters : " << (*segPar));
150 } else {
151 ATH_MSG_DEBUG("Could not get initial TRT segment parameters! ");
152 // clean up
153 return nullptr;
154 }
155
156 // --- create new track state on surface vector
157 auto ntsos = std::make_unique<Trk::TrackStates>();
158
159 //
160 // if no refit, make it a perigee
161 //
162 if (!m_doRefit) {
163
164 const Trk::TrackStateOnSurface* par_tsos = nullptr;
165
166 // --- create surface at perigee
167 Amg::Vector3D perigeePosition(0., 0., 0.);
168 Trk::PerigeeSurface perigeeSurface(perigeePosition);
169 // --- turn parameters into perigee...
170 std::unique_ptr<Trk::TrackParameters> tmp =
171 m_extrapolator->extrapolate(ctx, *segPar, perigeeSurface);
172 std::unique_ptr<Trk::Perigee> perParm = nullptr;
173 //pass ownership if of the right type
174 if (tmp && tmp->associatedSurface().type() == Trk::SurfaceType::Perigee) {
175 perParm.reset(static_cast<Trk::Perigee*>(tmp.release()));
176 }
177 if (perParm) {
178 ATH_MSG_VERBOSE("Perigee version of Parameters : " << (*segPar));
179 } else {
180 ATH_MSG_DEBUG("Failed to build perigee parameters.Discard...");
181 ntsos->clear();
182 delete segPar;
183 segPar = nullptr;
184 return nullptr;
185 }
186
187 // now create a perigee TSOS
188 std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes>
189 typePattern;
190 typePattern.set(Trk::TrackStateOnSurface::Perigee);
191 par_tsos = new Trk::TrackStateOnSurface(
192 nullptr, std::move(perParm), nullptr, typePattern);
193 // push new TSOS into the list
194 ntsos->push_back(par_tsos);
195 }
196
197 //
198 // now loop over the TSOS and copy them in
199 //
200
201 // psuedo measurement information
202 int npseudo = 0;
203 double pseudotheta = 0;
204 const Trk::MeasurementBase* pseudo = nullptr;
205 // other measurement information
206 const Trk::Surface *firstsurf = nullptr, *firstecsurf = nullptr,
207 *lastsurf = nullptr;
208 const Trk::MeasurementBase* firstmeas = nullptr;
209 // counters for barrel and endcap
210 int nbarrel = 0, nendcap = 0;
211 // some variables for endcaps
212 std::vector<std::pair<double, double>> points;
213 points.reserve(40);
214 double oldphi = 0;
215
216 const Trk::Surface *surf_zmin=nullptr;
217 const Trk::Surface *surf_zmax=nullptr;
218 int meas_zmin_i=int(tS.numberOfMeasurementBases());
219 int meas_zmax_i=int(tS.numberOfMeasurementBases());
220
221 // loop over the measurements in track segment (tS)
222 for (int it = 0; it < int(tS.numberOfMeasurementBases()); it++) {
223
224 // the track state on service we like to constuct ...
225 const Trk::TrackStateOnSurface* seg_tsos = nullptr;
226
227 // is this ROT a psuedo-measurement ?
228 if (dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(
229 tS.measurement(it))) {
230 // did we have a speudo-measurement before ?
231 if (pseudo) {
232 // get theta from pseudo measurements
233 pseudotheta =
234 std::atan2(tS.measurement(it)->associatedSurface().center().perp(),
235 tS.measurement(it)->associatedSurface().center().z());
236 }
237 // keep this pseudo measurement
238 pseudo = tS.measurement(it);
239 // update counter
240 npseudo++;
241
242 if (m_doRefit) {
243 // refit means we can simply copy the state, otherwise we skip it
244 seg_tsos =
245 new Trk::TrackStateOnSurface(tS.measurement(it)->uniqueClone(), nullptr);
246 }
247
248 } else {
249 //
250 // normal measurement, not a pseudo measurement
251 //
252 // copy measurement
253 seg_tsos =
254 new Trk::TrackStateOnSurface(tS.measurement(it)->uniqueClone(), nullptr);
255 //
256 // --- following is for the hack below
257 //
258
259 // remember first measurement
260 if (!firstmeas)
261 firstmeas = tS.measurement(it);
262 if (!firstsurf)
263 firstsurf = &tS.measurement(it)->associatedSurface();
264 // it is always the last one
265 lastsurf = &tS.measurement(it)->associatedSurface();
266
267 // detect endcap elemeents
269 // increase counter and keep some information
270 nendcap++;
271 if (!firstecsurf)
272 firstecsurf = &tS.measurement(it)->associatedSurface();
273
274 double tmpphi =
275 tS.measurement(it)->associatedSurface().center().phi();
276 if (!points.empty() &&
277 std::abs(tmpphi - oldphi) > M_PI) { // correct for boundary at +/- pi
278 if (tmpphi < 0)
279 tmpphi += 2 * M_PI;
280 else
281 tmpphi -= 2 * M_PI;
282 }
283 // remember oldphi
284 oldphi = tmpphi;
285
286 if (!surf_zmax || std::abs(tS.measurement(it)->associatedSurface().center().z())>std::abs(surf_zmax->center().z())) {
287 surf_zmax = &tS.measurement(it)->associatedSurface();
288 meas_zmax_i = it;
289 }
290 if (!surf_zmin || std::abs(tS.measurement(it)->associatedSurface().center().z())<std::abs(surf_zmin->center().z())) {
291 surf_zmin = &tS.measurement(it)->associatedSurface();
292 meas_zmin_i = it;
293 }
294 // copy the points
295 points.emplace_back(
296 tS.measurement(it)->associatedSurface().center().z(), tmpphi);
297
298 } else
299 nbarrel++;
300
301 //
302 // --- end of hack stuff
303 //
304 }
305
306 // push new TSOS into the list
307 if (seg_tsos)
308 ntsos->push_back(seg_tsos);
309 }
310
311 // Construct the new track
312 Trk::TrackInfo info;
313 info.setPatternRecognitionInfo(Trk::TrackInfo::TRTStandalone);
314
315 // create new track candidate
316 if (!m_doRefit) {
317 return new Trk::Track(info, std::move(ntsos), std::move(fq));
318 } else {
319 //
320 // ----------------------------- this is a horrible hack to make the
321 // segments fittable
322 //
323
324 // in case of only 1 pseudo measurement, use the theta from it.
325 if (npseudo == 1)
326 pseudotheta = pseudo->localParameters()[Trk::theta];
327
328 // we need new perigee parameters
329 double myqoverp = 0, myphi = 0, myd0 = 0, myz0 = 0, mytheta = pseudotheta;
330
331 if (nendcap < 4) {
332 //
333 // --- are we in the barrel mostly
334 //
335
336 // momentum
337 myqoverp = par[4] * std::sin(pseudotheta) / std::sin(par[3]);
338
339 // --- create surface at perigee
340 Amg::Vector3D perigeePosition(0., 0., 0.);
341 Trk::PerigeeSurface perigeeSurface(perigeePosition);
342 // -- get perigee
343 std::unique_ptr<const Trk::TrackParameters> tmp =
344 m_extrapolator->extrapolate(ctx, *segPar, perigeeSurface);
345 std::unique_ptr<const Trk::Perigee> tempper = nullptr;
346 if (tmp && tmp->associatedSurface().type() == Trk::SurfaceType::Perigee) {
347 tempper.reset(static_cast<const Trk::Perigee*>(tmp.release()));
348 }
349 if (!tempper) {
350 ATH_MSG_DEBUG("Could not produce perigee");
351 delete segPar;
352 segPar = nullptr;
353 return nullptr;
354 }
355
356 // keep some values
357 myd0 = tempper->parameters()[Trk::d0];
358 myphi = tempper->parameters()[Trk::phi0];
359
360 } else {
361 //
362 // --- endcap or transition track
363 //
364
365 // get estimate of parameters
366 double sx = 0, sy = 0, sxx = 0, sxy = 0, d = 0;
367 float zmin = points.empty() ? 0 : points.begin()->first, zmax = 0;
368 // loop over all points
369
370 for (auto & point : points) {
371 sx += point.first;
372 sy += point.second;
373 sxy += point.first * point.second;
374 sxx += point.first * point.first;
375 if (std::abs(point.first) > std::abs(zmax)) {
376 zmax = point.first;
377 }
378 if (std::abs(point.first) < std::abs(zmin)) {
379 zmin = point.first;
380 }
381 }
382
383 if (std::abs(pseudotheta) < 1.e-6) {
384 ATH_MSG_DEBUG("pseudomeasurements missing on the segment?");
385
386 if ( meas_zmin_i < int(tS.numberOfMeasurementBases())
387 && meas_zmax_i < int(tS.numberOfMeasurementBases())) {
388 Amg::Vector3D meas_zmin = tS.measurement(meas_zmin_i)->globalPosition();
389 Amg::Vector3D meas_zmax = tS.measurement(meas_zmax_i)->globalPosition();
390 double diff_z (meas_zmax.z() - meas_zmin.z());
391 if (std::abs(diff_z)>1e-6) {
392 double diff_r( meas_zmax.perp() - meas_zmin.perp());
393 pseudotheta = std::atan2(diff_r, diff_z);
394 ATH_MSG_DEBUG("Initial pseudo theta is zero. Compute pseudo from inner- and outermost endcap measurements. delta R: " <<
395 meas_zmax.perp() << " - " << meas_zmin.perp() << " = " << diff_r
396 << " , diff Z: " << meas_zmax.z() << " - " << meas_zmin.z()
397 << " = " << diff_z
398 << " " << pseudotheta);
399 }
400 }
401
402 if (std::abs(pseudotheta) < 1.e-6) {
403 constexpr std::array<float,2> boundary_r {644., 1004.};
404 // true if track extends from endcap A to endcap C:
405 bool is_across_sides=std::signbit(zmin)!=std::signbit(zmax);
406 double r_path=is_across_sides ? 2 * boundary_r[1] : boundary_r[1]-boundary_r[0];
407 double r1 =0.;
408 double r2 =0.;
409 if (surf_zmin && surf_zmax) {
410 bool is_reverse=std::abs(surf_zmin->center().z())>std::abs(surf_zmax->center().z());
411 // use the innermost and outermost surfaces (defined by z-coordinate) to compute the
412 // travel distance in R-direction assume that the outermost surface is always crossed
413 // at the outermost radial position assume more over that the the innermost surface
414 // is either crossed at the innermost or outermost position what ever leads to the
415 // largest travel distance in r.
416
417 std::array<const Trk::Surface *,2> boundary_surface{
418 is_reverse ? surf_zmax : surf_zmin,
419 is_reverse ? surf_zmin : surf_zmax};
420 // true if track goes from the outside to the insde :
421 std::array<Amg::Vector2D,2> translation;
422 std::array<Amg::Vector2D,2> height;
423 for (unsigned int boundary_i=boundary_surface.size(); boundary_i-->0;) {
424 if ( boundary_surface[boundary_i]->type() == Trk::SurfaceType::Line
425 && boundary_surface[boundary_i]->bounds().type() == Trk::SurfaceBounds::Cylinder) {
426 const Trk::CylinderBounds &
427 cylinder_bounds = dynamic_cast<const Trk::CylinderBounds &>(boundary_surface[boundary_i]->bounds());
428 height[boundary_i]= project2D( boundary_surface[boundary_i]->transform().rotation()
429 * Amg::Vector3D(0,0, cylinder_bounds.halflengthZ()) );
430 translation[boundary_i]=project2D( boundary_surface[boundary_i]->transform().translation() );
431 }
432 }
433 r1 = (translation[1] + height[1] - ( translation[0] + height[0])).perp();
434 r2 = (translation[1] + height[1] - ( translation[0] - height[0])).perp();
435 r_path=std::max(r1,r2);
436
437 }
438 pseudotheta = std::atan2(r_path, zmax - zmin);
439 ATH_MSG_DEBUG("Initial pseudo theta is zero. Pseudo theta from inner- and outermost surfaces. Deleta r " << r2 << " - " << r1 << " -> " << r_path
440 << " , delta Z " << zmax << " - " << zmin << " -> " << (zmax-zmin)
441 << " " << pseudotheta);
442 }
443 }
444
445 // get q/p
446 d = (points.size() * sxx - sx * sx);
447 double dphidz = ((points.size() * sxy - sy * sx) / d);
448 myqoverp = (std::abs(pseudotheta) > 1e-6)
449 ? -dphidz / (0.6 * std::tan(pseudotheta))
450 : 1000.;
451
452 // some geometry stuff to estimate further paramters...
453 double halfz = 200.;
454 const Trk::CylinderBounds* cylb =
455 dynamic_cast<const Trk::CylinderBounds*>(&firstsurf->bounds());
456 if (!cylb)
457 ATH_MSG_ERROR("Cast of bounds failed, should never happen");
458 else
459 halfz = cylb->halflengthZ();
460 const Trk::CylinderBounds* cylb2 =
461 dynamic_cast<const Trk::CylinderBounds*>(&lastsurf->bounds());
462 double halfz2 = 200.;
463 if (!cylb2)
464 ATH_MSG_ERROR("Cast of bounds failed, should never happen");
465 else
466 halfz2 = cylb2->halflengthZ();
467 Amg::Vector3D strawdir1 = -firstsurf->transform().rotation().col(2);
468 Amg::Vector3D strawdir2 = -lastsurf->transform().rotation().col(2);
469 Amg::Vector3D pos1;
470 Amg::Vector3D pos2;
471
472 // ME: this is hardcoding, not nice and should be fixed
473 if (std::abs(lastsurf->center().z()) < 2650 * mm) {
474 pos2 = lastsurf->center() + halfz2 * strawdir2;
475 if (nbarrel == 0) {
476 double dr = std::abs(std::tan(pseudotheta) * (lastsurf->center().z() -
477 firstsurf->center().z()));
478 pos1 = firstsurf->center() + (halfz - dr) * strawdir1;
479 } else {
480 double dz = std::abs((pos2.perp() - firstsurf->center().perp()) /
481 std::tan(pseudotheta));
482 if (pos2.z() > 0)
483 dz = -dz;
484 double z1 = pos2.z() + dz;
485 pos1 = Amg::Vector3D(
486 firstsurf->center().x(), firstsurf->center().y(), z1);
487 }
488 } else {
489 double dr = std::abs(std::tan(pseudotheta) *
490 (lastsurf->center().z() - firstsurf->center().z()));
491 pos2 = lastsurf->center() + (dr - halfz2) * strawdir2;
492 pos1 = firstsurf->center() - halfz * strawdir1;
493 }
494
495 // ME: I don't understand this yet, why is this done only if barrel ==
496 // 0, while above this nendcap < 4 ?
497 if (nbarrel == 0 &&
498 std::abs(std::tan(pseudotheta) * (firstsurf->center().z() -
499 lastsurf->center().z())) < 250 * mm &&
500 std::abs(firstsurf->center().z()) > 1000 * mm) {
501
502 // ME: wow this is hacking the vector ...
503 const Trk::MeasurementBase* firstmeas =
504 (**ntsos->begin()).measurementOnTrack();
505 Amg::MatrixX newcov(2, 2);
506 newcov.setZero();
507 newcov(0, 0) = (firstmeas->localCovariance())(0, 0);
508 newcov(1, 1) = (myqoverp != 0) ? .0001 * myqoverp * myqoverp : 1.e-8;
509 Trk::LocalParameters newpar(std::make_pair(0, Trk::locZ),
510 std::make_pair(myqoverp, Trk::qOverP));
511 auto newpseudo =
512 std::make_unique<Trk::PseudoMeasurementOnTrack>(
513 std::move(newpar),
514 std::move(newcov),
515 firstmeas->associatedSurface());
516 // hack replace first measurement with pseudomeasurement
517 ntsos->erase(ntsos->begin());
518 ntsos->insert(ntsos->begin(),
519 new Trk::TrackStateOnSurface(std::move(newpseudo), nullptr));
520 }
521
522 Amg::Vector3D field1;
523
524 MagField::AtlasFieldCache fieldCache;
525
526 // Get field cache object
529 };
530 const AtlasFieldCacheCondObj* fieldCondObj{ *readHandle };
531 if (fieldCondObj == nullptr) {
533 "segToTrack: Failed to retrieve AtlasFieldCacheCondObj with key "
535 return nullptr;
536 }
537 fieldCondObj->getInitializedCache(fieldCache);
538
539 // MT version uses cache
540 fieldCache.getField(Amg::Vector3D(.5 * (pos1 + pos2)).data(),
541 field1.data());
542
543 field1 *= m_fieldUnitConversion; // field in Tesla
544
545 double phideflection =
546 -.3 * (pos2 - pos1).perp() * field1.z() * myqoverp / std::sin(pseudotheta);
547 double precisephi = (nbarrel == 0)
548 ? (pos2 - pos1).phi() - .5 * phideflection
549 : (pos2 - pos1).phi() + .5 * phideflection;
550 double radius = (myqoverp != 0. && field1.z() != 0.)
551 ? -std::sin(pseudotheta) / (.3 * field1.z() * myqoverp)
552 : 1.e6;
553 double precisetheta =
554 (myqoverp != 0.)
555 ? std::atan2(std::abs(radius * phideflection), pos2.z() - pos1.z())
556 : pseudotheta;
557 if (precisetheta < 0)
558 precisetheta += M_PI;
559 if (precisephi < -M_PI)
560 precisephi += 2 * M_PI;
561 if (precisephi > M_PI)
562 precisephi -= 2 * M_PI;
563
564 // now extrapolate backwards from the first surface to get starting
565 // parameters
566 const Trk::StraightLineSurface* surfforpar = nullptr;
567 if (nbarrel == 0)
568 surfforpar = dynamic_cast<const Trk::StraightLineSurface*>(firstsurf);
569 else
570 surfforpar = dynamic_cast<const Trk::StraightLineSurface*>(lastsurf);
571 if (!surfforpar)
572 ATH_MSG_ERROR("Cast of surface failed, should never happen");
573
574 Trk::AtaStraightLine ataline(((nbarrel == 0) ? pos1 : pos2),
575 precisephi,
576 precisetheta,
577 myqoverp,
578 *surfforpar);
579 Trk::PerigeeSurface persurf;
580 const Trk::TrackParameters* extrappar =
581 m_extrapolator->extrapolateDirectly(ctx, ataline, persurf).release();
582
583 // now get parameters
584 if (extrappar) {
585 if (nendcap >= 4) {
586 myphi = extrappar->parameters()[Trk::phi0];
587 myd0 = extrappar->parameters()[Trk::d0];
588 }
589
590 // construct theta again
591 double z0 = extrappar->parameters()[Trk::z0];
592 if (nbarrel == 0)
593 mytheta = std::atan(std::tan(extrappar->parameters()[Trk::theta]) *
594 std::abs((z0 - pos1.z()) / pos1.z()));
595 else
596 mytheta = std::atan(std::tan(extrappar->parameters()[Trk::theta]) *
597 std::abs((z0 - pos2.z()) / pos2.z()));
598
599 if (mytheta < 0)
600 mytheta += M_PI;
601
602 delete extrappar;
603 extrappar = nullptr;
604 }
605 }
606 while (myphi > M_PI)
607 myphi -= 2 * M_PI;
608 while (myphi < -M_PI)
609 myphi += 2 * M_PI;
610
611 double P[5] = { myd0, myz0, myphi, mytheta, myqoverp };
612
613 // create perigee TSOS and add as first (!) TSOS
614
615 auto per =
616 std::make_unique<Trk::Perigee>(P[0], P[1], P[2], P[3], P[4], Trk::PerigeeSurface());
617 std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes>
618 typePattern;
619 typePattern.set(Trk::TrackStateOnSurface::Perigee);
621 nullptr, std::move(per), nullptr, typePattern);
622 ntsos->insert(ntsos->begin(), seg_tsos);
623
624 //
625 // ------------------------------------------------------- now refit the
626 // track
627 //
628
629 Trk::Track newTrack (info, std::move(ntsos), std::move(fq));
630 Trk::Track* fitTrack =
631 m_fitterTool->fit(ctx,newTrack, true, Trk::nonInteracting).release();
632
633 // cleanup
634 if (segPar) {
635 delete segPar;
636 segPar = nullptr;
637 }
638
639 if (!fitTrack) {
640 ATH_MSG_DEBUG("Refit of TRT track segment failed!");
641 return nullptr;
642 }
643
644 //
645 // -------------------------------------- hack the covarinace back to
646 // something reasonable
647 //
648 const Trk::TrackParameters* firstmeaspar = nullptr;
650 fitTrack->trackParameters()->begin();
651 do {
652 // skip pesudo measurements on perigee
653 if ((*parit)->covariance() &&
654 ((*parit)->associatedSurface() == tS.associatedSurface()))
655 firstmeaspar = *parit;
656 ++parit;
657 } while (firstmeaspar == nullptr &&
658 parit != fitTrack->trackParameters()->end());
659
660 // Create new perigee starting from the modified first measurement that
661 // has a more reasonable covariance matrix
662 // const Trk::Perigee* perTrack=dynamic_cast<const
663 // Trk::Perigee*>(fitTrack->perigeeParameters());
664 const Trk::Perigee* perTrack = fitTrack->perigeeParameters();
665
666 if (!perTrack || !perTrack->covariance()) {
667 ATH_MSG_ERROR("Cast of perigee fails, should never happen !");
668 return nullptr;
669 } else {
670 ATH_MSG_VERBOSE ("Perigee after refit with fudges to make it converge : " << (*perTrack) );
671
672 if(firstmeaspar && firstmeaspar->position().perp()<2000*mm && std::abs(firstmeaspar->position().z())<3000*mm){
673
674 // Modify first measurement so that it has reasonable errors on z and theta
675 AmgSymMatrix(5) fcovmat = AmgSymMatrix(5)(*(firstmeaspar->covariance()));
676 // factors by which we like to scale the cov, this takes the original segment errors into account
677 double scaleZ = std::sqrt(tS.localCovariance()(1,1))/std::sqrt( (fcovmat)(1,1));
678 double scaleTheta = std::sqrt(tS.localCovariance()(3,3))/std::sqrt( (fcovmat)(3,3));
679 // now do it
680 fcovmat(1,0)=scaleZ*((fcovmat)(1,0));
681 fcovmat(0,1) = (fcovmat)(1,0);
682 fcovmat(1,1)=tS.localCovariance()(1,1);
683 fcovmat(2,1)=scaleZ*((fcovmat)(2,1));
684 fcovmat(1,2) = (fcovmat)(2,1);
685 fcovmat(3,1)=scaleZ*scaleTheta*((fcovmat)(3,1));
686 fcovmat(1,3) = (fcovmat)(3,1);
687 fcovmat(4,1)=scaleZ*((fcovmat)(4,1));
688 fcovmat(1,4) = (fcovmat)(4,1);
689 fcovmat(3,0)=scaleTheta*((fcovmat)(3,0));
690 fcovmat(0,3) = (fcovmat)(3,0);
691 fcovmat(3,2)=scaleTheta*((fcovmat)(3,2));
692 fcovmat(2,3) = (fcovmat)(3,2);
693 fcovmat(3,3)=tS.localCovariance()(3,3);
694 fcovmat(4,3)=scaleTheta*((fcovmat)(4,3));
695 fcovmat(3,4) = (fcovmat)(4,3);
696
697 // const Amg::VectorX& par = firstmeaspar->parameters();
698 const AmgVector(5)& par = firstmeaspar->parameters();
699 const Trk::TrackParameters* updatedPars =
701 par[Trk::loc1],
702 par[Trk::loc2],
703 par[Trk::phi],
704 par[Trk::theta],
705 par[Trk::qOverP],
706 std::move(fcovmat)).release();
707
708 // now take parameters at first measurement and exptrapolate to perigee
709 const Trk::TrackParameters* newperpar =
710 m_extrapolator->extrapolate(ctx,
711 *updatedPars,
712 perTrack->associatedSurface(),
714 false,
715 Trk::nonInteracting).release();
716 delete updatedPars; updatedPars = nullptr;
717
718 if (!newperpar || !newperpar->covariance()) {
719 ATH_MSG_WARNING ("Can not hack perigee parameters, extrapolation failed");
720 delete newperpar; newperpar = nullptr;
721 } else {
722 // this is a HACK !!!
723 // perTrack is owned by fitTrack which is not const here
724 // thus the const-ness is only removed from somthting which is not strictly const here.
725 AmgSymMatrix(5)& errmat ATLAS_THREAD_SAFE = const_cast<AmgSymMatrix(5)&>(*perTrack->covariance());
726 // overwrite cov in perTrack
727 errmat = *newperpar->covariance();
728 delete newperpar; newperpar = nullptr;
729 // check that new cov makes sense !
730 const AmgSymMatrix(5)& CM = *perTrack->covariance();
731 if( CM(1,1)==0.||CM(3,3)==0. ) {
732 ATH_MSG_DEBUG ("Hacked perigee covariance is CRAP, reject track");
733 delete fitTrack; return nullptr;
734 } else {
735 ATH_MSG_VERBOSE ("Perigee after fit with scaled covariance matrix : " << *perTrack);
736 }
737 }
738 }
739 }
740 // return fitted track
741 return fitTrack;
742 }
743 }
744
745
747 const Trk::PRDtoTrackMap *prd_to_track_map) const {
748
749 ATH_MSG_DEBUG ("Checking whether the TRT segment has already been used...");
750
751 // some counters to be handled
752 int nShared = 0; // Shared drift circles in segment
753 int nHits = 0; // Number of TRT measurements
754
755 if (m_assoTool.isEnabled()&& !prd_to_track_map) ATH_MSG_ERROR("PRDtoTrackMap to be used but not provided by the client");
756 // loop over the track states
757 for(int it=0; it<int(tS.numberOfMeasurementBases()); ++it){
758
759 // remove pseudo measurements
760 if ( dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(tS.measurement(it)) )
761 continue;
762
763 // get the measurment
764 const InDet::TRT_DriftCircleOnTrack* trtcircle = dynamic_cast<const InDet::TRT_DriftCircleOnTrack*>(tS.measurement(it));
765 if (!trtcircle) continue;
766
767 // get PRD measurement
768 const InDet::TRT_DriftCircle* RawDataClus=dynamic_cast<const InDet::TRT_DriftCircle*>(trtcircle->prepRawData());
769 if(!RawDataClus) continue;
770
771 // count up number of hits
772 nHits++;
773
774 if(m_assoTool.isEnabled() && prd_to_track_map && prd_to_track_map->isUsed(*RawDataClus)) nShared++;
775 }
776
777 if(nShared >= int(m_sharedFrac * nHits)) {
778 ATH_MSG_DEBUG ("Too many shared hits.Will drop the TRT segment");
779 return true;
780 } else {
781 return false;
782 }
783
784
785 }
786
788
789 ATH_MSG_DEBUG ("Try to recover low TRT DC segments in crack...");
790
791 // counters
792 int nEC = 0; int nBRL = 0; int firstWheel = -999; int lastLayer = -999;
793
794 // loop over the track states
795 for(int it=0; it<int(tS.numberOfMeasurementBases()); ++it){
796
797 //test if it is a pseudo measurement
798 if ( dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(tS.measurement(it)) )
799 continue;
800
801 // get measurement
802 const InDet::TRT_DriftCircleOnTrack* trtcircle = dynamic_cast<const InDet::TRT_DriftCircleOnTrack*>(tS.measurement(it));
803 if(!trtcircle) continue;
804
805 // get identifier
806 Identifier id = trtcircle->detectorElement()->identify();
807 // barrel or endcap
808 int isB = m_trtId->barrel_ec(id);
809 if (isB==2 || isB==-2) {
810 nEC++;
811 if(nEC == 1)
812 firstWheel = m_trtId->layer_or_wheel(id);
813 }
814 else if (isB==1 || isB==-1) {
815 nBRL++;
816 lastLayer = m_trtId->layer_or_wheel(id);
817 }
818
819 }
820
821 // now the logic
822 return (nEC>0 && nBRL>0) ||
823
824 (nEC==0 && nBRL>0 && lastLayer<2) ||
825
826 (nEC>0 && nBRL==0 && (firstWheel>10 || firstWheel<2));
827
828 }
829
831 // @TODO avoid non const member m_trackScoreTrackMap
832 ATH_MSG_DEBUG ("Add track to the scoring multimap...");
833 //Score the track under investigation
835 bool passBasicSelections = m_scoringTool->passBasicSelections(*trk);
836 if(passBasicSelections){
837 if (m_trackSummaryTool.isEnabled()) {
838 m_trackSummaryTool->computeAndReplaceTrackSummary(*trk,
840 }
841 score = m_scoringTool->score(*trk);
842 }
843 ATH_MSG_DEBUG ("TRT-only: score is " << score);
844
845 if (score==0) {
846 // statistics...
847 ATH_MSG_DEBUG ("Track score is zero, reject it");
849 // clean up
850 delete trk;
851 } else {
852 // add track to map, map is sorted small to big !
853 event_data.m_trackScores.emplace_back(-score, trk );
854 }
855
856
857 }
858
859
861 ITRT_SegmentToTrackTool::EventData &event_data) const {
862
863 ATH_MSG_DEBUG ("Resolving the TRT tracks in score map...");
864
865
866 std::unique_ptr<Trk::PRDtoTrackMap> prd_to_track_map;
867 if (m_assoTool.isEnabled()) {
868 prd_to_track_map=m_assoTool->createPRDtoTrackMap();
869 if (prd_to_track_map_in) {
870 *prd_to_track_map = *prd_to_track_map_in;
871 }
872 }
873
874 //final copy - ownership is passed out of algorithm
875 std::unique_ptr<TrackCollection> final_tracks = std::make_unique<TrackCollection>();
876 final_tracks->reserve( event_data.m_trackScores.size());
877 std::stable_sort(event_data.m_trackScores.begin(),
878 event_data.m_trackScores.end(),
879 []( const std::pair< Trk::TrackScore, Trk::Track* > &a,
880 const std::pair< Trk::TrackScore, Trk::Track* > &b)
881 { return a.first < b.first; });
882
883 for (std::pair< Trk::TrackScore, Trk::Track* > &track_score : event_data.m_trackScores) {
884
885 ATH_MSG_DEBUG ("--- Trying next track "<<track_score.second<<"\t with score "<<-track_score.first);
886
887 // some counters to be handled
888 int nShared = 0; // Shared drift circles in segment
889 int nHits = 0; // Number of TRT measurements
890
891 // get vector of TSOS
892 const Trk::TrackStates* tsos = (track_score.second)->trackStateOnSurfaces();
893
894 // loop over vector of TSOS
895 for ( const Trk::TrackStateOnSurface *a_tsos : *tsos) {
896
897 // get measurment from TSOS
898 const Trk::MeasurementBase* meas = a_tsos->measurementOnTrack();
899 if (!meas)
900 continue;
901
902 // make sure it is a TRT_DC and not a pseudo measurement
904 dynamic_cast<const InDet::TRT_DriftCircleOnTrack*>(meas);
905 if (!rot)
906 continue;
907
908 // get to the PRD object
909 const InDet::TRT_DriftCircle* RawDataClus =
910 dynamic_cast<const InDet::TRT_DriftCircle*>(rot->prepRawData());
911 if (!RawDataClus)
912 continue;
913
914 // count up number of hits
915 nHits++;
916
917 // count up number of shared hits
918 if (m_assoTool.isEnabled() && prd_to_track_map->isUsed(*RawDataClus))
919 nShared++;
920 }
921
922 ATH_MSG_DEBUG ("TRT-only has " << nHits << " hits and " << nShared << " of them are shared");
923
924 // cut on the number of shared hits with the max fraction
925 if(nShared >= int(m_sharedFrac * nHits)) {
926 // statistics
928 ATH_MSG_DEBUG ("Too many shared hits, remove it !");
929 delete track_score.second;
930 continue;
931 }
932
933 // ok, this seems like a useful track
934 final_tracks->push_back(track_score.second);
935
937 ATH_MSG_DEBUG ("TRT-only is accepted");
938
939 //Register the track with the association tool
940 if(m_assoTool.isEnabled()) {
941 if(m_assoTool->addPRDs(*prd_to_track_map,*(track_score.second)).isFailure()) {
942 ATH_MSG_WARNING ("addPRDs() failed!");
943 }
944 }
945
946 }
947
948 return final_tracks.release();
949
950 }
951
952}
#define M_PI
Scalar perp() const
perp method - perpendicular length
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::vector< size_t > vec
#define AmgSymMatrix(dim)
#define AmgVector(rows)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
This is an Identifier helper class for the TRT subdetector.
DataVector< Trk::Track > TrackCollection
This typedef represents a collection of Trk::Track objects.
#define ATLAS_THREAD_SAFE
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
const ServiceHandle< StoreGateSvc > & detStore() const
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
DataModel_detail::const_iterator< DataVector > const_iterator
Standard const_iterator.
Definition DataVector.h:838
virtual Identifier identify() const override final
identifier of this detector element:
Represents 'corrected' measurements from the TRT (for example, corrected for wire sag).
virtual const InDetDD::TRT_BaseElement * detectorElement() const override final
returns the detector element, assoicated with the PRD of this class
virtual const TRT_DriftCircle * prepRawData() const override final
returns the PrepRawData - is a TRT_DriftCircle in this scope
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
virtual Trk::Track * segToTrack(const EventContext &ctx, const Trk::TrackSegment &) const override
virtual StatusCode initialize() override
ToolHandle< Trk::IExtrapolator > m_extrapolator
ToolHandle< Trk::IExtendedTrackSummaryTool > m_trackSummaryTool
static constexpr double m_fieldUnitConversion
virtual TrackCollection * resolveTracks(const Trk::PRDtoTrackMap *prd_to_track_map, ITRT_SegmentToTrackTool::EventData &event_data) const override
Resolve the standalone TRT tracks based on the number of shared TRT hits.
virtual bool segIsUsed(const Trk::TrackSegment &, const Trk::PRDtoTrackMap *prd_to_track_map) const override
Check if the TRT segment has already been assigned a Si extension.
static MsgStream & dumpevent(MsgStream &out)
Tracks that will be passed out of AmbiProcessor.
TRT_SegmentToTrackTool(const std::string &type, const std::string &name, const IInterface *parent)
const TRT_ID * m_trtId
ID TRT helper.
virtual StatusCode finalize() override
ToolHandle< Trk::ITrackScoringTool > m_scoringTool
ToolHandle< Trk::IPRDtoTrackMapTool > m_assoTool
ToolHandle< Trk::ITrackFitter > m_fitterTool
virtual bool toLower(const Trk::TrackSegment &) const override
MsgStream & dumpconditions(MsgStream &out) const
virtual void addNewTrack(Trk::Track *, ITRT_SegmentToTrackTool::EventData &event_data) const override
Add track into the track-score multimap.
virtual MsgStream & dump(MsgStream &out) const override
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
void getField(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT bxyz, double *ATH_RESTRICT deriv=nullptr)
get B field value at given position xyz[3] is in mm, bxyz[3] is in kT if deriv[9] is given,...
Bounds for a cylindrical Surface.
double halflengthZ() const
This method returns the halflengthZ.
std::unique_ptr< FitQuality > uniqueClone() const
NVI uniqueClone.
This class is the pure abstract base class for all fittable tracking measurements.
const LocalParameters & localParameters() const
Interface method to get the LocalParameters.
virtual const Surface & associatedSurface() const =0
Interface method to get the associated Surface.
virtual const Amg::Vector3D & globalPosition() const =0
Interface method to get the global Position.
const Amg::MatrixX & localCovariance() const
Interface method to get the localError.
std::unique_ptr< MeasurementBase > uniqueClone() const
NVI Clone giving up unique pointer.
bool isUsed(const PrepRawData &prd) const
does this PRD belong to at least one track?
const Amg::Vector3D & position() const
Access method for the position.
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
virtual const S & associatedSurface() const override final
Access to the Surface method.
Class describing the Line to which the Perigee refers to.
Class to handle pseudo-measurements in fitters and on track objects.
const MeasurementBase * measurement(unsigned int) const
returns the Trk::MeasurementBase objects depending on the integer
const FitQuality * fitQuality() const
return the FitQuality object, returns NULL if no FitQuality is defined
unsigned int numberOfMeasurementBases() const
Return the number of contained Trk::MeasurementBase (s)
Class for a StraightLineSurface in the ATLAS detector to describe dirft tube and straw like detectors...
Abstract Base Class for tracking surfaces.
virtual ChargedTrackParametersUniquePtr createUniqueTrackParameters(double l1, double l2, double phi, double theat, double qop, std::optional< AmgSymMatrix(5)> cov=std::nullopt) const =0
Use the Surface as a ParametersBase constructor, from local parameters - charged.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
Identifier associatedDetectorElementIdentifier() const
return Identifier of the associated Detector Element
virtual const SurfaceBounds & bounds() const =0
Surface Bounds method.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
Contains information about the 'fitter' of this track.
Class for a generic track segment that holdes polymorphic Trk::MeasurementBase objects,...
const Surface & associatedSurface() const override final
returns the surface for the local to global transformation
represents the track state (measurement, material, fit parameters and quality) at a surface.
@ Perigee
This represents a perigee, and so will contain a Perigee object only.
const DataVector< const TrackParameters > * trackParameters() const
Return a pointer to a vector of TrackParameters.
const Perigee * perigeeParameters() const
return Perigee.
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Primary Vertex Finder.
@ anyDirection
float TrackScore
Definition TrackScore.h:10
DataVector< const Trk::TrackStateOnSurface > TrackStates
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
ParametersT< TrackParametersDim, Charged, StraightLineSurface > AtaStraightLine
@ phi0
Definition ParamDefs.h:65
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ loc2
generic first and second local coordinate
Definition ParamDefs.h:35
@ phi
Definition ParamDefs.h:75
@ loc1
Definition ParamDefs.h:34
@ locZ
local cylindrical
Definition ParamDefs.h:42
@ d0
Definition ParamDefs.h:63
@ z0
Definition ParamDefs.h:64
ParametersBase< TrackParametersDim, Charged > TrackParameters
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
@ knTRTTrk
Number of TRT-only tracks on output.
@ knTrkSegUsed
Number of excluded segments by other TRT segments.
@ knTrkScoreZero
Number of tracks rejected by score zero.
std::vector< std::pair< Trk::TrackScore, Trk::Track * > > m_trackScores