Skip to content

Commit 5c506e8

Browse files
starsdongXin DongXin DongXin Dongpre-commit-ci[bot]
authored
SecondaryVertices factory based on Helix method (#2144)
### Briefly, what does this PR introduce? ### What kind of change does this PR introduce? - [ ] Bug fix (issue #__) - [x] New feature (issue #__) - [ ] Documentation update - [ ] Other: __ ### Please check if this PR fulfills the following: - [x] Tests for the changes have been added - [x] Documentation has been added / updated - [x] Changes have been communicated to collaborators ### Does this PR introduce breaking changes? What changes might users need to make to their code? None ### Does this PR change default behavior? New SecondaryVerticesHelix factory added into reco plugin, SecondaryVerticesHelix object (currently with edm4eic:Vertex structure) saved in PODIO --------- Co-authored-by: Xin Dong <[email protected]> Co-authored-by: Xin Dong <[email protected]> Co-authored-by: Xin Dong <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Xin Dong <[email protected]> Co-authored-by: Wouter Deconinck <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Dmitry Kalinkin <[email protected]>
1 parent 77016d0 commit 5c506e8

File tree

8 files changed

+1096
-1
lines changed

8 files changed

+1096
-1
lines changed

src/algorithms/reco/Helix.cc

Lines changed: 600 additions & 0 deletions
Large diffs are not rendered by default.

src/algorithms/reco/Helix.h

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// FIXME SPDX-License-Identifier: TBD
2+
// Copyright (C) 1997 - 2025 The STAR Collaboration, Xin Dong, Rongrong Ma
3+
4+
#pragma once
5+
6+
#include <edm4eic/ReconstructedParticleCollection.h>
7+
#include <edm4eic/TrackParametersCollection.h>
8+
#include <edm4eic/unit_system.h>
9+
#include <edm4hep/Vector3f.h>
10+
#include <stdlib.h>
11+
#include <cmath>
12+
#include <iterator>
13+
#include <utility>
14+
15+
namespace eicrecon {
16+
17+
class Helix {
18+
bool mSingularity; // true for straight line case (B=0)
19+
edm4hep::Vector3f mOrigin;
20+
double mDipAngle;
21+
double mCurvature;
22+
double mPhase;
23+
int mH; // -sign(q*B);
24+
25+
double mCosDipAngle;
26+
double mSinDipAngle;
27+
double mCosPhase;
28+
double mSinPhase;
29+
30+
public:
31+
/// curvature, dip angle, phase, origin, h
32+
Helix(const double c, const double dip, const double phase, const edm4hep::Vector3f& o,
33+
const int h = -1);
34+
35+
/// momentum, origin, b_field, charge
36+
Helix(const edm4hep::Vector3f& p, const edm4hep::Vector3f& o, const double B, const int q);
37+
38+
/// ReconstructParticle, b field
39+
Helix(const edm4eic::ReconstructedParticle& p, const double b_field);
40+
41+
~Helix() = default;
42+
43+
double dipAngle() const;
44+
double curvature() const; /// 1/R in xy-plane
45+
double phase() const; /// aziumth in xy-plane measured from ring center
46+
double xcenter() const; /// x-center of circle in xy-plane
47+
double ycenter() const; /// y-center of circle in xy-plane
48+
int h() const; /// -sign(q*B);
49+
50+
const edm4hep::Vector3f& origin() const; /// starting point
51+
52+
void setParameters(double c, double dip, double phase, const edm4hep::Vector3f& o, int h);
53+
54+
void setParameters(const edm4hep::Vector3f& p, const edm4hep::Vector3f& o, const double B,
55+
const int q);
56+
57+
/// edm4eic::TrackParameters, b field
58+
void setParameters(const edm4eic::TrackParameters& trk, const double b_field);
59+
60+
/// coordinates of helix at point s
61+
double x(double s) const;
62+
double y(double s) const;
63+
double z(double s) const;
64+
65+
edm4hep::Vector3f at(double s) const;
66+
67+
/// pointing vector of helix at point s
68+
double cx(double s) const;
69+
double cy(double s) const;
70+
double cz(double s = 0) const;
71+
72+
edm4hep::Vector3f cat(double s) const;
73+
74+
/// returns period length of helix
75+
double period() const;
76+
77+
/// path length at given r (cylindrical r)
78+
std::pair<double, double> pathLength(double r) const;
79+
80+
/// path length at given r (cylindrical r, cylinder axis at x,y)
81+
std::pair<double, double> pathLength(double r, double x, double y);
82+
83+
/// path length at distance of closest approach to a given point
84+
double pathLength(const edm4hep::Vector3f& p, bool scanPeriods = true) const;
85+
86+
/// path length at intersection with plane
87+
double pathLength(const edm4hep::Vector3f& r, const edm4hep::Vector3f& n) const;
88+
89+
/// path length at distance of closest approach in the xy-plane to a given point
90+
double pathLength(double x, double y) const;
91+
92+
/// path lengths at dca between two helices
93+
std::pair<double, double> pathLengths(const Helix&, double minStepSize = 10 * edm4eic::unit::um,
94+
double minRange = 10 * edm4eic::unit::cm) const;
95+
96+
/// minimal distance between point and helix
97+
double distance(const edm4hep::Vector3f& p, bool scanPeriods = true) const;
98+
99+
/// checks for valid parametrization
100+
bool valid(double world = 1.e+5) const { return !bad(world); }
101+
int bad(double world = 1.e+5) const;
102+
103+
/// move the origin along the helix to s which becomes then s=0
104+
void moveOrigin(double s);
105+
106+
static const double NoSolution;
107+
108+
void setCurvature(double); /// performs also various checks
109+
void setPhase(double);
110+
void setDipAngle(double);
111+
112+
/// value of S where distance in x-y plane is minimal
113+
double fudgePathLength(const edm4hep::Vector3f&) const;
114+
115+
// Requires: signed Magnetic Field
116+
edm4hep::Vector3f momentum(double) const; // returns the momentum at origin
117+
edm4hep::Vector3f momentumAt(double, double) const; // returns momentum at S
118+
int charge(double) const; // returns charge of particle
119+
// 2d DCA to x,y point signed relative to curvature
120+
double curvatureSignedDistance(double x, double y);
121+
// 2d DCA to x,y point signed relative to rotation
122+
double geometricSignedDistance(double x, double y);
123+
// 3d DCA to 3d point signed relative to curvature
124+
double curvatureSignedDistance(const edm4hep::Vector3f&);
125+
// 3d DCA to 3d point signed relative to rotation
126+
double geometricSignedDistance(const edm4hep::Vector3f&);
127+
128+
//
129+
void Print() const;
130+
131+
}; // end class Helix
132+
133+
//
134+
// Inline functions
135+
//
136+
inline int Helix::h() const { return mH; }
137+
138+
inline double Helix::dipAngle() const { return mDipAngle; }
139+
140+
inline double Helix::curvature() const { return mCurvature; }
141+
142+
inline double Helix::phase() const { return mPhase; }
143+
144+
inline double Helix::x(double s) const {
145+
if (mSingularity)
146+
return mOrigin.x - s * mCosDipAngle * mSinPhase;
147+
else
148+
return mOrigin.x + (cos(mPhase + s * mH * mCurvature * mCosDipAngle) - mCosPhase) / mCurvature;
149+
}
150+
151+
inline double Helix::y(double s) const {
152+
if (mSingularity)
153+
return mOrigin.y + s * mCosDipAngle * mCosPhase;
154+
else
155+
return mOrigin.y + (sin(mPhase + s * mH * mCurvature * mCosDipAngle) - mSinPhase) / mCurvature;
156+
}
157+
158+
inline double Helix::z(double s) const { return mOrigin.z + s * mSinDipAngle; }
159+
160+
inline double Helix::cx(double s) const {
161+
if (mSingularity)
162+
return -mCosDipAngle * mSinPhase;
163+
else
164+
return -sin(mPhase + s * mH * mCurvature * mCosDipAngle) * mH * mCosDipAngle;
165+
}
166+
167+
inline double Helix::cy(double s) const {
168+
if (mSingularity)
169+
return mCosDipAngle * mCosPhase;
170+
else
171+
return cos(mPhase + s * mH * mCurvature * mCosDipAngle) * mH * mCosDipAngle;
172+
}
173+
174+
inline double Helix::cz(double /* s */) const { return mSinDipAngle; }
175+
176+
inline const edm4hep::Vector3f& Helix::origin() const { return mOrigin; }
177+
178+
inline edm4hep::Vector3f Helix::at(double s) const { return edm4hep::Vector3f(x(s), y(s), z(s)); }
179+
180+
inline edm4hep::Vector3f Helix::cat(double s) const {
181+
return edm4hep::Vector3f(cx(s), cy(s), cz(s));
182+
}
183+
184+
inline double Helix::pathLength(double X, double Y) const {
185+
return fudgePathLength(edm4hep::Vector3f(X, Y, 0));
186+
}
187+
inline int Helix::bad(double WorldSize) const {
188+
189+
// int ierr;
190+
if (!::finite(mDipAngle))
191+
return 11;
192+
if (!::finite(mCurvature))
193+
return 12;
194+
195+
// ierr = mOrigin.bad(WorldSize);
196+
// if (ierr) return 3+ierr*100;
197+
198+
if (::fabs(mDipAngle) > 1.58)
199+
return 21;
200+
double qwe = ::fabs(::fabs(mDipAngle) - M_PI / 2);
201+
if (qwe < 1. / WorldSize)
202+
return 31;
203+
204+
if (::fabs(mCurvature) > WorldSize)
205+
return 22;
206+
if (mCurvature < 0)
207+
return 32;
208+
209+
if (abs(mH) != 1)
210+
return 24;
211+
212+
return 0;
213+
}
214+
215+
} // namespace eicrecon
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
// Copyright (C) 2025 Daniel Brandenburg, Xin Dong
3+
4+
#include <DD4hep/Fields.h>
5+
#include <Evaluator/DD4hepUnits.h>
6+
#include <Math/GenVector/Cartesian3D.h>
7+
#include <Math/GenVector/DisplacementVector3D.h>
8+
#include <edm4eic/VertexCollection.h>
9+
#include <edm4eic/unit_system.h>
10+
#include <edm4hep/Vector3f.h>
11+
#include <edm4hep/Vector4f.h>
12+
#include <edm4hep/utils/vector_utils.h>
13+
#include <fmt/core.h>
14+
#include <cmath>
15+
#include <gsl/pointers>
16+
#include <utility>
17+
#include <vector>
18+
19+
#include "algorithms/reco/Helix.h"
20+
#include "algorithms/reco/SecondaryVerticesHelix.h"
21+
#include "algorithms/reco/SecondaryVerticesHelixConfig.h"
22+
#include "services/particle/ParticleSvc.h"
23+
24+
namespace eicrecon {
25+
26+
/**
27+
* @brief Initialize the SecondaryVerticesHelix Algorithm
28+
*
29+
*/
30+
void SecondaryVerticesHelix::init() {}
31+
32+
/**
33+
* @brief Produce a list of secondary vertex candidates
34+
*
35+
* @param rcvtx - input collection of all vertex candidates
36+
* @return edm4eic::VertexCollection
37+
*/
38+
void SecondaryVerticesHelix::process(const SecondaryVerticesHelix::Input& input,
39+
const SecondaryVerticesHelix::Output& output) const {
40+
const auto [rcvtx, rcparts] = input;
41+
auto [out_secondary_vertices] = output;
42+
43+
auto& particleSvc = algorithms::ParticleSvc::instance();
44+
45+
if ((*rcvtx).size() == 0) {
46+
info("No primary vertex in this event! Skip secondary vertex finder!");
47+
return;
48+
}
49+
const auto pVtxPos4f = (*rcvtx)[0].getPosition();
50+
// convert to cm
51+
edm4hep::Vector3f pVtxPos(pVtxPos4f.x * edm4eic::unit::mm / edm4eic::unit::cm,
52+
pVtxPos4f.y * edm4eic::unit::mm / edm4eic::unit::cm,
53+
pVtxPos4f.z * edm4eic::unit::mm / edm4eic::unit::cm);
54+
55+
auto fieldObj = m_det->field();
56+
auto field = fieldObj.magneticField(
57+
{pVtxPos4f.x / edm4eic::unit::mm * dd4hep::mm, pVtxPos4f.y / edm4eic::unit::mm * dd4hep::mm,
58+
pVtxPos4f.z / edm4eic::unit::mm * dd4hep::mm}); // in unit of dd4hep::tesla
59+
float b_field = field.z();
60+
61+
info("\tPrimary vertex = ({},{},{})cm \t b field = {} tesla", pVtxPos.x, pVtxPos.y, pVtxPos.z,
62+
b_field / dd4hep::tesla);
63+
64+
std::vector<Helix> hVec;
65+
hVec.clear();
66+
std::vector<unsigned int> indexVec;
67+
indexVec.clear();
68+
for (unsigned int i = 0; const auto& p : *rcparts) {
69+
if (p.getCharge() == 0)
70+
continue;
71+
Helix h(p, b_field);
72+
double dca = h.distance(pVtxPos) * edm4eic::unit::cm;
73+
if (dca < m_cfg.minDca)
74+
continue;
75+
76+
hVec.push_back(h);
77+
indexVec.push_back(i);
78+
++i;
79+
}
80+
81+
if (hVec.size() != indexVec.size())
82+
return;
83+
84+
debug("\tVector size {}, {}", hVec.size(), indexVec.size());
85+
86+
for (unsigned int i1 = 0; i1 < hVec.size(); ++i1) {
87+
for (unsigned int i2 = i1 + 1; i2 < hVec.size(); ++i2) {
88+
const auto& p1 = (*rcparts)[indexVec[i1]];
89+
const auto& p2 = (*rcparts)[indexVec[i2]];
90+
91+
if (!(m_cfg.unlikesign && p1.getCharge() + p2.getCharge() == 0))
92+
continue;
93+
94+
const auto& h1 = hVec[i1];
95+
const auto& h2 = hVec[i2];
96+
97+
// Helix function uses cm unit
98+
double dca1 = h1.distance(pVtxPos) * edm4eic::unit::cm;
99+
double dca2 = h2.distance(pVtxPos) * edm4eic::unit::cm;
100+
if (dca1 < m_cfg.minDca || dca2 < m_cfg.minDca)
101+
continue;
102+
103+
std::pair<double, double> const ss = h1.pathLengths(h2);
104+
edm4hep::Vector3f h1AtDcaTo2 = h1.at(ss.first);
105+
edm4hep::Vector3f h2AtDcaTo1 = h2.at(ss.second);
106+
107+
double dca12 = edm4hep::utils::magnitude(h1AtDcaTo2 - h2AtDcaTo1) * edm4eic::unit::cm;
108+
if (std::isnan(dca12))
109+
continue;
110+
if (dca12 > m_cfg.maxDca12)
111+
continue;
112+
edm4hep::Vector3f pairPos = 0.5 * (h1AtDcaTo2 + h2AtDcaTo1);
113+
114+
edm4hep::Vector3f h1MomAtDca = h1.momentumAt(ss.first, b_field);
115+
edm4hep::Vector3f h2MomAtDca = h2.momentumAt(ss.second, b_field);
116+
edm4hep::Vector3f pairMom = h1MomAtDca + h2MomAtDca;
117+
118+
double e1 =
119+
std::hypot(edm4hep::utils::magnitude(h1MomAtDca), particleSvc.particle(p1.getPDG()).mass);
120+
double e2 =
121+
std::hypot(edm4hep::utils::magnitude(h2MomAtDca), particleSvc.particle(p2.getPDG()).mass);
122+
double pairE = e1 + e2;
123+
double angle = edm4hep::utils::angleBetween(pairMom, pairPos - pVtxPos);
124+
if (cos(angle) < m_cfg.minCostheta)
125+
continue;
126+
127+
double beta = edm4hep::utils::magnitude(pairMom) / pairE;
128+
double time = edm4hep::utils::magnitude(pairPos - pVtxPos) / (beta * dd4hep::c_light);
129+
edm4hep::Vector3f dL = pairPos - pVtxPos; // in cm
130+
edm4hep::Vector3f decayL(dL.x * edm4eic::unit::cm, dL.y * edm4eic::unit::cm,
131+
dL.z * edm4eic::unit::cm);
132+
double dca2pv = edm4hep::utils::magnitude(decayL) * sin(angle);
133+
if (dca2pv > m_cfg.maxDca)
134+
continue;
135+
136+
auto v0 = out_secondary_vertices->create();
137+
v0.setType(2); // 2 for secondary
138+
v0.setPosition({(float)(pairPos.x * edm4eic::unit::cm / edm4eic::unit::mm),
139+
(float)(pairPos.y * edm4eic::unit::cm / edm4eic::unit::mm),
140+
(float)(pairPos.z * edm4eic::unit::cm / edm4eic::unit::mm), (float)time});
141+
v0.addToAssociatedParticles(p1);
142+
v0.addToAssociatedParticles(p2);
143+
144+
info("One secondary vertex found at (x,y,z) = ({}, {}, {}) mm.",
145+
pairPos.x * edm4eic::unit::cm / edm4eic::unit::mm,
146+
pairPos.y * edm4eic::unit::cm / edm4eic::unit::mm,
147+
pairPos.x * edm4eic::unit::cm / edm4eic::unit::mm);
148+
149+
} // end i2
150+
} // end i1
151+
152+
} // end process
153+
154+
} // namespace eicrecon

0 commit comments

Comments
 (0)