File indexing completed on 2025-08-06 08:18:36
0001 #include "SecondaryVertexFinder.h"
0002 #include "ActsPropagator.h"
0003
0004
0005
0006 #include <trackbase/ActsGeometry.h>
0007 #include <trackbase/TpcDefs.h>
0008 #include <trackbase/TrackFitUtils.h>
0009 #include <trackbase/TrkrCluster.h> // for TrkrCluster
0010 #include <trackbase/TrkrClusterContainer.h>
0011 #include <trackbase/TrkrDefs.h> // for cluskey, getLayer, TrkrId
0012
0013 #include <globalvertex/SvtxVertexMap_v1.h>
0014 #include <globalvertex/SvtxVertex_v1.h>
0015 #include <trackbase_historic/ActsTransformations.h>
0016 #include <trackbase_historic/SvtxTrack.h> // for SvtxTrack, SvtxTrack::C...
0017 #include <trackbase_historic/SvtxTrackMap_v2.h>
0018 #include <trackbase_historic/TrackSeed_v2.h>
0019
0020 #include <Acts/Geometry/GeometryIdentifier.hpp>
0021 #include <Acts/MagneticField/MagneticFieldProvider.hpp>
0022 #include <Acts/Surfaces/PerigeeSurface.hpp>
0023
0024 #include <fun4all/Fun4AllReturnCodes.h>
0025 #include <phool/PHCompositeNode.h>
0026 #include <phool/PHNode.h>
0027 #include <phool/PHNodeIterator.h>
0028
0029 #include <phool/getClass.h>
0030 #include <phool/phool.h>
0031
0032 #include <cmath> // for sqrt, fabs, atan2, cos
0033 #include <iomanip>
0034 #include <iostream> // for operator<<, basic_ostream
0035 #include <map> // for map
0036 #include <set> // for _Rb_tree_const_iterator
0037 #include <utility> // for pair, make_pair
0038
0039 #include <algorithm>
0040 #include <cassert>
0041 #include <functional>
0042 #include <iostream>
0043 #include <numeric>
0044 #include <vector>
0045
0046 #include <Eigen/Dense>
0047
0048 #include <TFile.h>
0049 #include <TH1D.h>
0050 #include <TH2D.h>
0051 #include <TLorentzVector.h>
0052 #include <TNtuple.h>
0053
0054
0055 SecondaryVertexFinder::SecondaryVertexFinder(const std::string& name)
0056 : SubsysReco(name)
0057 {
0058 }
0059
0060
0061 SecondaryVertexFinder::~SecondaryVertexFinder() = default;
0062
0063
0064 int SecondaryVertexFinder::InitRun(PHCompositeNode* topNode)
0065 {
0066 if (_write_electrons_node)
0067 {
0068 CreateOutputNode(topNode);
0069 }
0070
0071 int ret = GetNodes(topNode);
0072 if (ret != Fun4AllReturnCodes::EVENT_OK)
0073 {
0074 return ret;
0075 }
0076
0077 if (_write_ntuple)
0078 {
0079 recomass = new TH2D("recomass", "invariant mass vs pT", 1000, 0, 5, 4000, 0, 2);
0080 hdecaypos = new TH2D("hdecaypos", "decay radius", 200, -40, 40, 200, -40, 40);
0081 hdecaypos->GetXaxis()->SetTitle("decay X (cm)");
0082 hdecaypos->GetYaxis()->SetTitle("decay Y (cm)");
0083 hdecay_radius = new TH1D("hdecay_radius", "Decay Radius", 200, 0, 40.0);
0084
0085 ntp = new TNtuple("ntp", "decay_pairs", "x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:vposx1:vposy1:vposz1:vmomx1:vmomy1:vmomz1:pca_relx_1:pca_rely_1:pca_relz_1:eta1:charge1:tpcClusters_1:quality1:eta1:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:vposx2:vposy2:vposz2:vmomx2:vmomy2:vmomz2:pca_relx_2:pca_rely_2:pca_relz_2:eta2:charge2:tpcClusters_2:quality2:eta2:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:path:has_silicon1:has_silicon2");
0086 }
0087
0088 return ret;
0089 }
0090
0091 void SecondaryVertexFinder::fillNtp(SvtxTrack* track1, SvtxTrack* track2, double dca3dxy1, double dca3dz1, double dca3dxy2, double dca3dz2, Eigen::Vector3d vpos1, Eigen::Vector3d vmom1, Eigen::Vector3d vpos2, Eigen::Vector3d vmom2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, double path, int has_silicon_1, int has_silicon_2)
0092 {
0093 double px1 = track1->get_px();
0094 double py1 = track1->get_py();
0095 double pz1 = track1->get_pz();
0096 auto tpcSeed1 = track1->get_tpc_seed();
0097 size_t tpcClusters1 = tpcSeed1->size_cluster_keys();
0098 double eta1 = asinh(pz1 / sqrt(pow(px1, 2) + pow(py1, 2)));
0099
0100 double px2 = track2->get_px();
0101 double py2 = track2->get_py();
0102 double pz2 = track2->get_pz();
0103 auto tpcSeed2 = track2->get_tpc_seed();
0104 size_t tpcClusters2 = tpcSeed2->size_cluster_keys();
0105 double eta2 = asinh(pz2 / sqrt(pow(px2, 2) + pow(py2, 2)));
0106
0107 auto vtxid = track1->get_vertex_id();
0108 auto svtxVertex = _svtx_vertex_map->get(vtxid);
0109 if (!svtxVertex)
0110 {
0111 return;
0112 }
0113
0114 float reco_info[] = {
0115 track1->get_x(), track1->get_y(), track1->get_z(),
0116 track1->get_px(), track1->get_py(), track1->get_pz(),
0117 (float) dca3dxy1, (float) dca3dz1, (float) vpos1(0), (float) vpos1(1), (float) vpos1(2),
0118 (float) vmom1(0), (float) vmom1(1), (float) vmom1(2),
0119 (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2),
0120 (float) eta1, (float) track1->get_charge(), (float) tpcClusters1,
0121 (float) track1->get_quality(), (float) eta1,
0122 track2->get_x(), track2->get_y(), track2->get_z(),
0123 track2->get_px(), track2->get_py(), track2->get_pz(),
0124 (float) dca3dxy2, (float) dca3dz2, (float) vpos2(0), (float) vpos2(1), (float) vpos2(2),
0125 (float) vmom2(0), (float) vmom2(1), (float) vmom2(2),
0126 (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2),
0127 (float) eta2, (float) track2->get_charge(), (float) tpcClusters2,
0128 (float) track2->get_quality(), (float) eta2,
0129 svtxVertex->get_x(), svtxVertex->get_y(), svtxVertex->get_z(),
0130 (float) pair_dca, (float) invariantMass, (float) invariantPt, (float) path,
0131 (float) has_silicon_1, (float) has_silicon_2};
0132
0133 ntp->Fill(reco_info);
0134 }
0135
0136
0137 int SecondaryVertexFinder::process_event(PHCompositeNode* )
0138 {
0139 if (Verbosity() > 0)
0140 {
0141 std::cout << PHWHERE << " track map size " << _track_map->size() << std::endl;
0142 }
0143
0144
0145 for (auto tr1_it = _track_map->begin(); tr1_it != _track_map->end(); ++tr1_it)
0146 {
0147 auto id1 = tr1_it->first;
0148 auto tr1 = tr1_it->second;
0149
0150 auto vertexId = tr1->get_vertex_id();
0151 const SvtxVertex* svtxVertex = _svtx_vertex_map->get(vertexId);
0152 if (!svtxVertex)
0153 {
0154 if (Verbosity() > 1)
0155 {
0156 std::cout << PHWHERE << " Failed to find vertex id " << vertexId << " skip this track " << std::endl;
0157 }
0158 continue;
0159 }
0160 if (svtxVertex->size_tracks() == 0)
0161 {
0162 continue;
0163 }
0164
0165
0166 if (_require_mvtx && !hasSiliconSeed(tr1))
0167 {
0168 continue;
0169 }
0170
0171 int has_silicon_1 = 0;
0172 if (hasSiliconSeed(tr1))
0173 {
0174 has_silicon_1 = 1;
0175 }
0176
0177 if (Verbosity() > 3)
0178 {
0179 std::cout << "Track1 " << id1 << " details: " << std::endl;
0180 outputTrackDetails(tr1);
0181 }
0182
0183 if (tr1->get_quality() > _qual_cut)
0184 {
0185 continue;
0186 }
0187
0188 auto tpc_seed1 = tr1->get_tpc_seed();
0189 int ntpc1 = tpc_seed1->size_cluster_keys();
0190 if (ntpc1 < 20)
0191 {
0192 continue;
0193 }
0194
0195 float dca3dxy1, dca3dz1, dca3dxysigma1, dca3dzsigma1;
0196 get_dca(tr1, dca3dxy1, dca3dz1, dca3dxysigma1, dca3dzsigma1);
0197
0198
0199 if (!dca3dxy1)
0200 {
0201 std::cout << " get_dca returned NAN " << std::endl;
0202 continue;
0203 }
0204 if (fabs(dca3dxy1) < _track_dcaxy_cut)
0205 {
0206 continue;
0207 }
0208 if (fabs(dca3dz1) < _track_dcaz_cut)
0209 {
0210 continue;
0211 }
0212
0213
0214 for (auto tr2_it = std::next(tr1_it); tr2_it != _track_map->end(); ++tr2_it)
0215 {
0216 auto id2 = tr2_it->first;
0217 auto tr2 = tr2_it->second;
0218
0219
0220 if (_require_mvtx && !hasSiliconSeed(tr2))
0221 {
0222 continue;
0223 }
0224
0225 int has_silicon_2 = 0;
0226 if (hasSiliconSeed(tr2))
0227 {
0228 has_silicon_2 = 1;
0229 }
0230
0231 if (Verbosity() > 3)
0232 {
0233 std::cout << "Track2 " << id2 << " details: " << std::endl;
0234 outputTrackDetails(tr2);
0235 }
0236
0237 if (tr2->get_charge() == tr1->get_charge())
0238 {
0239 continue;
0240 }
0241
0242 if (tr2->get_quality() > _qual_cut)
0243 {
0244 continue;
0245 }
0246
0247 auto tpc2_seed = tr2->get_tpc_seed();
0248 int ntpc2 = tpc2_seed->size_cluster_keys();
0249 if (ntpc2 < 20)
0250 {
0251 continue;
0252 }
0253
0254 float dca3dxy2, dca3dz2, dca3dxysigma2, dca3dzsigma2;
0255 get_dca(tr2, dca3dxy2, dca3dz2, dca3dxysigma2, dca3dzsigma2);
0256
0257 if (!dca3dxy2)
0258 {
0259 std::cout << " get_dca returned NAN " << std::endl;
0260 continue;
0261 }
0262 if (fabs(dca3dxy2) < _track_dcaxy_cut)
0263 {
0264 continue;
0265 }
0266 if (fabs(dca3dz2) < _track_dcaz_cut)
0267 {
0268 continue;
0269 }
0270
0271
0272 if (Verbosity() > 3)
0273 {
0274 std::cout << "Check pair DCA for tracks " << id1 << " and " << id2 << std::endl;
0275 }
0276
0277 double R1;
0278 Eigen::Vector2d center1;
0279 getCircleXYTrack(tr1, R1, center1);
0280 if (Verbosity() > 2)
0281 {
0282 std::cout << std::endl
0283 << "Track 1 circle: " << std::endl;
0284 std::cout << " tr1.x " << tr1->get_x() << " tr1.y " << tr1->get_y() << " tr1.z " << tr1->get_z() << " charge " << tr1->get_charge() << std::endl;
0285 std::cout << " tr1.px " << tr1->get_px() << " tr1.py " << tr1->get_py() << " tr1.pz " << tr1->get_pz() << std::endl;
0286 std::cout << " track1 " << tr1->get_id() << " circle R " << R1 << " (x, y) " << center1(0) << " " << center1(1) << std::endl;
0287 }
0288 double R2;
0289 Eigen::Vector2d center2;
0290 getCircleXYTrack(tr2, R2, center2);
0291 if (Verbosity() > 2)
0292 {
0293 std::cout << "Track 2 circle: " << std::endl;
0294 std::cout << " tr2.x " << tr2->get_x() << " tr2.y " << tr2->get_y() << " tr2.z " << tr2->get_z() << " charge " << tr2->get_charge() << std::endl;
0295 std::cout << " tr2.px " << tr2->get_px() << " tr2.py " << tr2->get_py() << " tr2.pz " << tr2->get_pz() << std::endl;
0296 std::cout << " track2 " << tr2->get_id() << " circle R " << R2 << " (x, y) " << center2(0) << " " << center2(1) << std::endl;
0297 }
0298
0299 std::vector<double> intersections;
0300 if (!circle_circle_intersection(R1, center1(0), center1(1), R2, center2(0), center2(1), intersections))
0301 {
0302 if (Verbosity() > 2)
0303 {
0304 std::cout << " - no intersections, skip this pair" << std::endl;
0305 }
0306 continue;
0307 }
0308
0309 Eigen::Vector2d intersection[2];
0310 if (intersections.size() == 2)
0311 {
0312 intersection[0](0) = intersections[0];
0313 intersection[0](1) = intersections[1];
0314 }
0315 if (intersections.size() == 4)
0316 {
0317 intersection[1](0) = intersections[2];
0318 intersection[1](1) = intersections[3];
0319 }
0320
0321
0322 for (int i = 0; i < 2; ++i)
0323 {
0324 if (intersection[i].norm() == 0)
0325 {
0326 continue;
0327 }
0328
0329 double vradius = sqrt(intersection[i](0) * intersection[i](0) + intersection[i](1) * intersection[i](1));
0330 if (vradius > _max_intersection_radius)
0331 {
0332 continue;
0333 }
0334
0335 double z1 = getZFromIntersectionXY(tr1, R1, center1, intersection[i]);
0336 double z2 = getZFromIntersectionXY(tr2, R2, center2, intersection[i]);
0337 if (Verbosity() > 2)
0338 {
0339 std::cout << " track intersection " << i << " at (x,y) " << intersection[i](0) << " " << intersection[i](1)
0340 << " radius " << vradius << " est. z1 " << z1 << " est. z2 " << z2 << std::endl;
0341 }
0342
0343 if (fabs(z1 - z2) > 2.0)
0344 {
0345 if (Verbosity() > 2)
0346 {
0347 std::cout << " z-mismatch - wrong intersection, skip it " << std::endl;
0348 }
0349 continue;
0350 }
0351
0352 Eigen::Vector3d vpos1(0, 0, 0), vmom1(0, 0, 0);
0353 Eigen::Vector3d vpos2(0, 0, 0), vmom2(0, 0, 0);
0354
0355
0356 Eigen::Vector3d intersect1(intersection[i](0), intersection[i](1), z1);
0357 if (!projectTrackToPoint(tr1, intersect1, vpos1, vmom1))
0358 {
0359 continue;
0360 }
0361 if (Verbosity() > 2)
0362 {
0363 std::cout << " Projected track 1 to point " << intersect1(0) << " " << intersect1(1) << " " << intersect1(2) << std::endl;
0364 std::cout << " has vpos " << vpos1(0) << " " << vpos1(1) << " " << vpos1(2) << std::endl;
0365 }
0366 Eigen::Vector3d intersect2(intersection[i](0), intersection[i](1), z2);
0367 if (!projectTrackToPoint(tr2, intersect2, vpos2, vmom2))
0368 {
0369 continue;
0370 }
0371 if (Verbosity() > 2)
0372 {
0373 std::cout << " Projected track 2 to point " << intersect2(0) << " " << intersect2(1) << " " << intersect2(2) << std::endl;
0374 std::cout << " has vpos " << vpos2(0) << " " << vpos2(1) << " " << vpos2(2) << std::endl;
0375 }
0376
0377
0378 if (fabs(vpos1(2) - vpos2(2)) > _projected_track_z_cut)
0379 {
0380 if (Verbosity() > 0)
0381 {
0382 std::cout << " Warning: projected z positions are screwed up, should not be" << std::endl;
0383 }
0384 continue;
0385 }
0386
0387 if (Verbosity() > 2)
0388 {
0389 std::cout << "Summary for projected pair:" << std::endl;
0390 std::cout << " Fitted tracks: " << std::endl;
0391 std::cout << " tr1.x " << tr1->get_x() << " tr1.y " << tr1->get_y() << " tr1.z " << tr1->get_z() << std::endl;
0392 std::cout << " tr2.x " << tr2->get_x() << " tr2.y " << tr2->get_y() << " tr2.z " << tr2->get_z() << std::endl;
0393 std::cout << " tr1.px " << tr1->get_px() << " tr1.py " << tr1->get_py() << " tr1.pz " << tr1->get_pz() << std::endl;
0394 std::cout << " tr2.px " << tr2->get_px() << " tr2.py " << tr2->get_py() << " tr2.pz " << tr2->get_pz() << std::endl;
0395 std::cout << " Projected tracks: " << std::endl;
0396 std::cout << " pos1.x " << vpos1(0) << " pos1.y " << vpos1(1) << " pos1.z " << vpos1(2) << std::endl;
0397 std::cout << " pos2.x " << vpos2(0) << " pos2.y " << vpos2(1) << " pos2.z " << vpos2(2) << std::endl;
0398 std::cout << " mom1.x " << vmom1(0) << " mom1.y " << vmom1(1) << " mom1.z " << vmom1(2) << std::endl;
0399 std::cout << " mom2.x " << vmom2(0) << " mom2.y " << vmom2(1) << " mom2.z " << vmom2(2) << std::endl;
0400 }
0401
0402
0403 double pair_dca;
0404 Eigen::Vector3d PCA1(0, 0, 0), PCA2(0, 0, 0);
0405 findPcaTwoLines(vpos1, vmom1, vpos2, vmom2, pair_dca, PCA1, PCA2);
0406 if (Verbosity() > 2)
0407 {
0408 std::cout << " pair_dca " << pair_dca << " two_track_dcacut " << _two_track_dcacut << std::endl;
0409 std::cout << " PCA1 " << PCA1(0) << " " << PCA1(1) << " " << PCA1(2) << std::endl;
0410 std::cout << " PCA2 " << PCA2(0) << " " << PCA2(1) << " " << PCA2(2) << std::endl;
0411 }
0412
0413 if (fabs(pair_dca) > _two_track_dcacut)
0414 {
0415 continue;
0416 }
0417
0418
0419
0420 TLorentzVector t1;
0421 Float_t E1 = sqrt(pow(vmom1(0), 2) + pow(vmom1(1), 2) + pow(vmom1(2), 2) + pow(_decaymass, 2));
0422 t1.SetPxPyPzE(vmom1(0), vmom1(1), vmom1(2), E1);
0423
0424 TLorentzVector t2;
0425 Float_t E2 = sqrt(pow(vmom2(0), 2) + pow(vmom2(1), 2) + pow(vmom2(2), 2) + pow(_decaymass, 2));
0426 t2.SetPxPyPzE(vmom2(0), vmom2(1), vmom2(2), E2);
0427
0428 TLorentzVector tsum = t1 + t2;
0429
0430
0431 Eigen::Vector3d PCA = (vpos1 + vpos2) / 2.0;
0432 auto vtxid = tr1->get_vertex_id();
0433 auto vertex1 = _svtx_vertex_map->get(vtxid);
0434 Eigen::Vector3d VTX(vertex1->get_x(), vertex1->get_y(), vertex1->get_z());
0435 Eigen::Vector3d path = PCA - VTX;
0436 double decay_radius = sqrt(pow(PCA(0), 2) + pow(PCA(1), 2));
0437
0438 if (path.norm() > _min_path_cut)
0439 {
0440 if (Verbosity() > 0)
0441 {
0442 std::cout << " Pair mass " << tsum.M() << " pair pT " << tsum.Pt()
0443 << " decay length " << path.norm() << std::endl;
0444 }
0445
0446 if (_write_ntuple)
0447 {
0448 fillNtp(tr1, tr2, dca3dxy1, dca3dz1, dca3dxy2, dca3dz2, vpos1, vmom1, vpos2, vmom2,
0449 PCA1, PCA2, pair_dca, tsum.M(), tsum.Pt(), path.norm(), has_silicon_1, has_silicon_2);
0450 }
0451
0452 if (_write_electrons_node)
0453 {
0454 if (passConversionElectronCuts(tsum, tr1, tr2, pair_dca, PCA, VTX))
0455 {
0456 if (Verbosity() > 0)
0457 {
0458 std::cout << " **** inserting tracks " << tr1->get_id() << " and " << tr2->get_id() << std::endl;
0459 }
0460
0461
0462 _track_map_electrons->insertWithKey(tr1, tr1->get_id());
0463 _track_map_electrons->insertWithKey(tr2, tr2->get_id());
0464
0465 if (_write_ntuple)
0466 {
0467
0468 recomass->Fill(tsum.Pt(), tsum.M());
0469 hdecay_radius->Fill(decay_radius);
0470 hdecaypos->Fill(PCA(0), PCA(1));
0471 }
0472 }
0473 }
0474 }
0475 }
0476 }
0477 }
0478
0479 if (Verbosity() > 0)
0480 {
0481 std::cout << PHWHERE << " electron track map size " << _track_map_electrons->size() << std::endl;
0482 for (auto& _track_map_electron : *_track_map_electrons)
0483 {
0484 auto id = _track_map_electron.first;
0485 auto tr = _track_map_electron.second;
0486
0487 std::cout << " Electron track " << id
0488 << " x " << tr->get_x() << " y " << tr->get_y() << " z " << tr->get_z()
0489 << " px " << tr->get_px() << " py " << tr->get_py() << " pz " << tr->get_pz()
0490 << std::endl;
0491 }
0492 }
0493
0494 return Fun4AllReturnCodes::EVENT_OK;
0495 }
0496
0497 bool SecondaryVertexFinder::passConversionElectronCuts(const TLorentzVector& tsum, SvtxTrack* tr1, SvtxTrack* tr2, float pair_dca, const Eigen::Vector3d& PCA, const Eigen::Vector3d& VTX)
0498 {
0499 bool pass = false;
0500
0501
0502 auto tpc_seed1 = tr1->get_tpc_seed();
0503 unsigned int ntpc1 = tpc_seed1->size_cluster_keys();
0504 auto tpc_seed2 = tr2->get_tpc_seed();
0505 unsigned int ntpc2 = tpc_seed2->size_cluster_keys();
0506 if (ntpc1 < _min_tpc_clusters || ntpc2 < _min_tpc_clusters)
0507 {
0508 return pass;
0509 }
0510
0511
0512 if (fabs(pair_dca) > _conversion_pair_dcacut)
0513 {
0514 return pass;
0515 };
0516
0517 if (tsum.M() > _max_mass_cut)
0518 {
0519 return pass;
0520 }
0521
0522 if (tsum.Pt() < _invariant_pt_cut)
0523 {
0524 return pass;
0525 }
0526
0527 Eigen::Vector3d path = PCA - VTX;
0528 if (path.norm() < 0.2)
0529 {
0530 return pass;
0531 }
0532
0533
0534 Eigen::Vector3d invariant_mom(tsum.Px(), tsum.Py(), tsum.Pz());
0535 double costheta = path.dot(invariant_mom) / (path.norm() * invariant_mom.norm());
0536
0537 if (costheta < _costheta_cut)
0538 {
0539 return pass;
0540 };
0541
0542
0543 if (fabs(tr1->get_eta() - tr2->get_eta()) > _deta_cut)
0544 {
0545 return pass;
0546 };
0547
0548 pass = true;
0549 return pass;
0550 }
0551
0552 double SecondaryVertexFinder::getZFromIntersectionXY(SvtxTrack* track, double& R, Eigen::Vector2d& center, Eigen::Vector2d intersection)
0553 {
0554
0555
0556
0557
0558 double phi0 = atan2(track->get_y() - center(1), track->get_x() - center(0));
0559 double phi1 = atan2(intersection(1) - center(1), intersection(0) - center(0));
0560 double xypath = R * fabs(phi1 - phi0);
0561
0562 double zpath = xypath * track->get_pz() / track->get_pt();
0563 double z = track->get_z() + zpath;
0564 if (Verbosity() > 3)
0565 {
0566 std::cout << " Radius " << R << " center xy " << center(0) << " " << center(1) << " pT " << track->get_pt() << " pz " << track->get_pz() << std::endl;
0567 std::cout << " phi0 " << phi0 << " y0 " << track->get_y() << " x0 " << track->get_x() << std::endl;
0568 std::cout << " phi1 " << phi1 << " intersection y " << intersection(1) << " intersection x " << intersection(0) << std::endl;
0569 std::cout << " xypath " << xypath << " zpath " << zpath << " z0 " << track->get_z() << " z " << z << std::endl;
0570 }
0571
0572 return z;
0573 }
0574
0575 void SecondaryVertexFinder::getCircleXYTrack(SvtxTrack* track, double& R, Eigen::Vector2d& center)
0576 {
0577
0578 double Bz = 1.4;
0579 double x = track->get_x();
0580 double y = track->get_y();
0581 double px = track->get_px();
0582 double py = track->get_py();
0583 double pt = track->get_pt();
0584 int charge = track->get_charge();
0585
0586
0587 R = 3.3 * pt / (Bz * (double) charge) * 100;
0588
0589
0590 Eigen::Vector2d normal(py, -px);
0591 normal /= normal.norm();
0592
0593
0594 Eigen::Vector2d base(x, y);
0595 center = base + R * normal;
0596
0597
0598 R = fabs(R);
0599
0600 return;
0601 }
0602
0603 bool SecondaryVertexFinder::projectTrackToPoint(SvtxTrack* track, Eigen::Vector3d& PCA, Eigen::Vector3d& pos, Eigen::Vector3d& mom)
0604 {
0605 bool ret = true;
0606 PCA *= Acts::UnitConstants::cm;
0607
0608
0609 auto perigee = Acts::Surface::makeShared<Acts::PerigeeSurface>(PCA);
0610
0611 ActsPropagator propagator(_tGeometry);
0612 auto params = propagator.makeTrackParams(track, _svtx_vertex_map);
0613 if (!params.ok())
0614 {
0615
0616 return false;
0617 }
0618
0619 propagator.verbosity(Verbosity());
0620 auto result = propagator.propagateTrack(params.value(), perigee);
0621 if (result.ok())
0622 {
0623 auto resultparams = result.value().second;
0624 auto projectionPos = resultparams.position(_tGeometry->geometry().getGeoContext());
0625 const auto momentum = resultparams.momentum();
0626 pos(0) = projectionPos.x() / Acts::UnitConstants::cm;
0627 pos(1) = projectionPos.y() / Acts::UnitConstants::cm;
0628 pos(2) = projectionPos.z() / Acts::UnitConstants::cm;
0629
0630 mom(0) = momentum.x();
0631 mom(1) = momentum.y();
0632 mom(2) = momentum.z();
0633 }
0634 else
0635 {
0636 if (Verbosity() > 0)
0637 {
0638 std::cout << " Failed projection of track with: " << std::endl;
0639 std::cout << " x,y,z = " << track->get_x() << " " << track->get_y() << " " << track->get_z() << std::endl;
0640 std::cout << " px,py,pz = " << track->get_px() << " " << track->get_py() << " " << track->get_pz() << std::endl;
0641 std::cout << " to point (x,y,z) = " << PCA(0) / Acts::UnitConstants::cm << " "
0642 << PCA(1) / Acts::UnitConstants::cm << " " << PCA(2) / Acts::UnitConstants::cm << std::endl;
0643 }
0644
0645 ret = false;
0646 }
0647
0648 return ret;
0649 }
0650
0651 void SecondaryVertexFinder::outputTrackDetails(SvtxTrack* tr)
0652 {
0653 auto tpc_seed = tr->get_tpc_seed();
0654 int ntpc = tpc_seed->size_cluster_keys();
0655
0656 auto silicon_seed = tr->get_silicon_seed();
0657
0658 int nsilicon = 0;
0659 if (silicon_seed)
0660 {
0661 nsilicon = silicon_seed->size_cluster_keys();
0662 }
0663
0664 auto pt = tr->get_pt();
0665 auto eta = tr->get_eta();
0666 auto x = tr->get_x();
0667 auto y = tr->get_y();
0668 auto z = tr->get_z();
0669 auto qual = tr->get_quality();
0670
0671 std::cout << " ntpc " << ntpc << " nsilicon " << nsilicon << " quality " << qual
0672 << " eta " << eta << std::endl;
0673 std::cout << " pt " << pt << " x " << x << " y " << y << " z " << z << std::endl;
0674
0675 auto vtxid = tr->get_vertex_id();
0676 auto vertex = _svtx_vertex_map->get(vtxid);
0677 std::cout << " vtxid " << vtxid
0678 << " vertex x " << vertex->get_x()
0679 << " vertex y " << vertex->get_y()
0680 << " vertex z " << vertex->get_z()
0681 << std::endl;
0682 }
0683
0684 bool SecondaryVertexFinder::hasSiliconSeed(SvtxTrack* tr)
0685 {
0686 bool ret = false;
0687 auto silicon_seed = tr->get_silicon_seed();
0688 if (silicon_seed)
0689 {
0690 ret = true;
0691 }
0692
0693 return ret;
0694 }
0695
0696 void SecondaryVertexFinder::get_dca(SvtxTrack* track,
0697 float& dca3dxy, float& dca3dz,
0698 float& dca3dxysigma, float& dca3dzsigma)
0699 {
0700 dca3dxy = NAN;
0701 Acts::Vector3 pos(track->get_x(),
0702 track->get_y(),
0703 track->get_z());
0704 Acts::Vector3 mom(track->get_px(),
0705 track->get_py(),
0706 track->get_pz());
0707
0708 auto vtxid = track->get_vertex_id();
0709 auto svtxVertex = _svtx_vertex_map->get(vtxid);
0710 if (!svtxVertex)
0711 {
0712 std::cout << " Failed to find vertex for track " << std::endl;
0713 return;
0714 }
0715
0716 Acts::Vector3 vertex(svtxVertex->get_x(),
0717 svtxVertex->get_y(),
0718 svtxVertex->get_z());
0719
0720 if (Verbosity() > 3)
0721 {
0722 std::cout << " track " << track->get_id() << " vertex id is " << vtxid
0723 << " vertex is " << svtxVertex->get_x() << " "
0724 << svtxVertex->get_y() << " "
0725 << svtxVertex->get_z() << std::endl;
0726 }
0727
0728 pos -= vertex;
0729
0730 Acts::ActsSquareMatrix<3> posCov;
0731 for (int i = 0; i < 3; ++i)
0732 {
0733 for (int j = 0; j < 3; ++j)
0734 {
0735 posCov(i, j) = track->get_error(i, j);
0736 }
0737 }
0738
0739 Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
0740 float phi = atan2(r(1), r(0));
0741 phi *= -1.0;
0742
0743 Acts::RotationMatrix3 rot;
0744 Acts::RotationMatrix3 rot_T;
0745 rot(0, 0) = cos(phi);
0746 rot(0, 1) = -sin(phi);
0747 rot(0, 2) = 0;
0748 rot(1, 0) = sin(phi);
0749 rot(1, 1) = cos(phi);
0750 rot(1, 2) = 0;
0751 rot(2, 0) = 0;
0752 rot(2, 1) = 0;
0753 rot(2, 2) = 1;
0754
0755 rot_T = rot.transpose();
0756
0757 Acts::Vector3 pos_R = rot * pos;
0758 Acts::ActsSquareMatrix<3> rotCov = rot * posCov * rot_T;
0759
0760 dca3dxy = pos_R(0);
0761 dca3dz = pos_R(2);
0762 dca3dxysigma = sqrt(rotCov(0, 0));
0763 dca3dzsigma = sqrt(rotCov(2, 2));
0764 }
0765
0766 void SecondaryVertexFinder::findPcaTwoLines(Eigen::Vector3d pos1, Eigen::Vector3d mom1, Eigen::Vector3d pos2, Eigen::Vector3d mom2,
0767 double& dca, Eigen::Vector3d& PCA1, Eigen::Vector3d& PCA2)
0768 {
0769 Eigen::Vector3d a1(pos1(0), pos1(1), pos1(2));
0770 Eigen::Vector3d b1(mom1(0) / mom1.norm(), mom1(1) / mom1.norm(), mom1(2) / mom1.norm());
0771 Eigen::Vector3d a2(pos2(0), pos2(1), pos2(2));
0772 Eigen::Vector3d b2(mom2(0) / mom2.norm(), mom2(1) / mom2.norm(), mom2(2) / mom2.norm());
0773
0774
0775
0776
0777
0778
0779
0780
0781 auto bcrossb = b1.cross(b2);
0782 auto mag_bcrossb = bcrossb.norm();
0783
0784 auto aminusa = a2 - a1;
0785
0786
0787
0788 dca = 999;
0789 if (mag_bcrossb != 0)
0790 {
0791 dca = bcrossb.dot(aminusa) / mag_bcrossb;
0792 }
0793 else
0794 {
0795 return;
0796 }
0797
0798
0799
0800 double X = b1.dot(b2) - b1.dot(b1) * b2.dot(b2) / b2.dot(b1);
0801 double Y = (a2.dot(b2) - a1.dot(b2)) - (a2.dot(b1) - a1.dot(b1)) * b2.dot(b2) / b2.dot(b1);
0802 double c = Y / X;
0803
0804 double F = b1.dot(b1) / b2.dot(b1);
0805 double G = -(a2.dot(b1) - a1.dot(b1)) / b2.dot(b1);
0806 double d = c * F + G;
0807
0808
0809 PCA1 = a1 + c * b1;
0810 PCA2 = a2 + d * b2;
0811
0812 return;
0813 }
0814
0815
0816
0817
0818 bool SecondaryVertexFinder::circle_circle_intersection(double r0, double x0, double y0, double r1, double x1, double y1, std::vector<double>& intersectionXY)
0819 {
0820 bool ret = true;
0821
0822 Eigen::Vector2d p0(x0, y0);
0823 Eigen::Vector2d p1(x1, y1);
0824
0825 double d = (p0 - p1).norm();
0826
0827
0828
0829
0830 if (d < fabs(r1 - r0))
0831 {
0832 return false;
0833 }
0834 if (d > r0 + r1)
0835 {
0836
0837
0838
0839 double dr = 0.2;
0840 if (fabs(d - (r0 + r1)) < dr)
0841 {
0842
0843 Eigen::Vector2d u0 = (p1 - p0);
0844 u0 /= u0.norm();
0845 Eigen::Vector2d PCA0 = p0 + u0 * r0;
0846
0847 Eigen::Vector2d u1 = (p0 - p1);
0848 u1 /= u1.norm();
0849 Eigen::Vector2d PCA1 = p1 + u1 * r1;
0850
0851 auto PCA = (PCA0 + PCA1) / 2.0;
0852 intersectionXY.push_back(PCA(0));
0853 intersectionXY.push_back(PCA(1));
0854
0855 if (Verbosity() > 2)
0856 {
0857 std::cout << " *** Special case: Barely touching circles: "
0858 << " PCA.x, PCA.y " << PCA(0) << " " << PCA(1) << std::endl;
0859 }
0860 return ret;
0861 }
0862 else
0863 {
0864 return false;
0865 }
0866 }
0867
0868 double a = (r0 * r0 - r1 * r1 + d * d) / (2 * d);
0869 double h = sqrt(r0 * r0 - a * a);
0870
0871 double x2 = x0 + a * (x1 - x0) / d;
0872 double y2 = y0 + a * (y1 - y0) / d;
0873
0874 double x3a = x2 + h * (y1 - y0) / d;
0875 double y3a = y2 - h * (x1 - x0) / d;
0876
0877 double x3b = x2 - h * (y1 - y0) / d;
0878 double y3b = y2 + h * (x1 - x0) / d;
0879
0880 intersectionXY.push_back(x3a);
0881 intersectionXY.push_back(y3a);
0882 intersectionXY.push_back(x3b);
0883 intersectionXY.push_back(y3b);
0884
0885 return ret;
0886 }
0887
0888 int SecondaryVertexFinder::End(PHCompositeNode* )
0889 {
0890 if (_write_ntuple)
0891 {
0892 TFile* fout = new TFile(outfile.c_str(), "recreate");
0893 recomass->Write();
0894 hdecaypos->Write();
0895 hdecay_radius->Write();
0896 ntp->Write();
0897 fout->Close();
0898 }
0899
0900 return Fun4AllReturnCodes::EVENT_OK;
0901 }
0902
0903 int SecondaryVertexFinder::CreateOutputNode(PHCompositeNode* topNode)
0904 {
0905 PHNodeIterator iter(topNode);
0906
0907 PHCompositeNode* dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
0908
0909 if (!dstNode)
0910 {
0911 std::cerr << "DST node is missing, quitting" << std::endl;
0912 throw std::runtime_error("Failed to find DST node in SecondaryVertexFinder");
0913 }
0914
0915 PHNodeIterator dstIter(topNode);
0916 PHCompositeNode* svtxNode = dynamic_cast<PHCompositeNode*>(dstIter.findFirst("PHCompositeNode", "SVTX"));
0917
0918 if (!svtxNode)
0919 {
0920 svtxNode = new PHCompositeNode("SVTX");
0921 dstNode->addNode(svtxNode);
0922 }
0923
0924 if (_write_electrons_node)
0925 {
0926 _track_map_electrons = new SvtxTrackMap_v2;
0927 auto tracks_node = new PHIODataNode<PHObject>(_track_map_electrons, "SvtxTrackMapElectrons", "PHObject");
0928 svtxNode->addNode(tracks_node);
0929 if (Verbosity())
0930 {
0931 std::cout << "Svtx/SvtxTrackMapElectrons node added" << std::endl;
0932 }
0933 }
0934
0935 return true;
0936 }
0937
0938 int SecondaryVertexFinder::GetNodes(PHCompositeNode* topNode)
0939 {
0940 _track_map = findNode::getClass<SvtxTrackMap>(topNode, "SvtxTrackMap");
0941 if (!_track_map)
0942 {
0943 std::cout << PHWHERE << " ERROR: Can't find SvtxTrackMap: " << std::endl;
0944 return Fun4AllReturnCodes::ABORTEVENT;
0945 }
0946
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956 _svtx_vertex_map = findNode::getClass<SvtxVertexMap>(topNode, "SvtxVertexMap");
0957 if (!_svtx_vertex_map)
0958 {
0959 std::cout << PHWHERE << "No vertex node, quit!" << std::endl;
0960 return Fun4AllReturnCodes::ABORTEVENT;
0961 }
0962
0963 _tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0964 if (!_tGeometry)
0965 {
0966 std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl;
0967 return Fun4AllReturnCodes::ABORTEVENT;
0968 }
0969
0970 return Fun4AllReturnCodes::EVENT_OK;
0971 }