8#include "trg/cdc/modules/fitting/CDCTrigger3DFitterModule.h"
10#include <framework/datastore/RelationVector.h>
11#include <cdc/dataobjects/WireID.h>
12#include <cdc/geometry/CDCGeometryPar.h>
24 "The 3D fitter module of the CDC trigger.\n"
25 "1. Selects stereo hits around a given 2D track by Hough voting\n"
26 "2. Performs a linear fit in the s-z plane (s: 2D arclength).\n"
30 "Name of the input StoreArray of CDCHits.",
31 string(
"CDCHits4Trg"));
33 "Name of the input StoreArray of CDCTriggerSegmentHits.",
36 "Name of the event time object.",
39 "Name of the StoreArray holding the input tracks from the 2D finder.",
40 string(
"TRGCDC2DFinderTracks"));
42 "Name of the StoreArray holding the 3D output tracks.",
43 string(
"TRGCDC3DFitterTracks"));
45 "Minimal number of votes in Hough voting.",
68 m_xtCurve.resize(m_nStereoLayer, vector<double>(m_maxDriftTime));
69 m_nWire.resize(m_nStereoLayer, 0);
70 m_rWire.resize(m_nStereoLayer, 0);
71 m_phiBW.resize(m_nStereoLayer, vector<double>(cdc.getMaxNumberOfCellsPerLayer()));
72 m_zBW.resize(m_nStereoLayer, 0);
73 m_stereoAngle.resize(m_nStereoLayer, 0);
75 for (
int iLayer = 0; iLayer < m_nStereoLayer; ++iLayer) {
77 int iStereoSuperLayer = iLayer / m_nLayerInSuperLayer;
78 int iLayerInSL = iLayer % m_nLayerInSuperLayer;
79 int iCLayer = 8 + 12 * iStereoSuperLayer + iLayerInSL;
82 for (
int iTick = 0; iTick < (int)
m_xtCurve[iLayer].size(); ++iTick) {
83 double t = iTick * 2 * cdc.getTdcBinWidth();
85 double driftLength_left = cdc.getDriftLength(t, iCLayer, 0);
86 double driftLength_right = cdc.getDriftLength(t, iCLayer, 1);
87 m_xtCurve[iLayer][iTick] = (driftLength_left + driftLength_right) / 2;
91 m_nWire[iLayer] = cdc.nWiresInLayer(iCLayer);
94 m_rWire[iLayer] = cdc.senseWireR(iCLayer);
97 for (
int iWire = 0; iWire < m_nWire[iLayer]; iWire++) {
98 const B2Vector3D& wirePosBW = cdc.wireBackwardPosition(iCLayer, iWire);
99 m_phiBW[iLayer][iWire] = wirePosBW.
Phi();
104 const B2Vector3D& wirePosB = cdc.wireBackwardPosition(iCLayer, 0);
105 const B2Vector3D& wirePosF = cdc.wireForwardPosition(iCLayer, 0);
106 const B2Vector3D wireDirection = wirePosF - wirePosB;
107 m_zBW[iLayer] = wirePosB.
Z();
108 m_stereoAngle[iLayer] = wireDirection.
Theta();
109 if (wirePosF.
Phi() < wirePosB.
Phi())m_stereoAngle[iLayer] *= -1;
119 double omega =
m_tracks2D[iTrack]->getOmega();
121 vector<vector<CDCHit*>> preselectedHits =
preselector(phi0, omega);
123 vector<vector<double>> sCand =
sConverter(preselectedHits, omega);
124 vector<vector<double>> zCand =
zConverter(preselectedHits, phi0, omega);
127 voter.vote(sCand, zCand);
128 auto [z0Voter, cotVoter, voteCount] = voter.findPeak();
132 B2DEBUG(100,
"vote count is lower than threshold (in 3D Fitter)");
136 auto [s, z] =
selector(sCand, zCand, z0Voter, cotVoter);
138 auto [z0, cot] =
fitter(s, z);
141 if (isnan(z0) || isnan(cot)) {
142 B2DEBUG(100,
"3D fit failed");
152 m_tracks2D[iTrack]->addRelationTo(fittedTrack);
158vector<vector<CDCHit*>>
161 vector<vector<CDCHit*>> preselectedHits(m_nStereoLayer, vector<CDCHit*>());
174 for (
int iHit : iHitInEachLayer) {
175 if (iHit == -1)
continue;
178 int iWire = hits[iHit]->getIWire();
180 if (iWireBeginList[iLayer] == -1)
continue;
182 if (iWireBeginList[iLayer] + 10 - 1 < m_nWire[iLayer]) {
183 if (iWireBeginList[iLayer] <= iWire && iWire < iWireBeginList[iLayer] + 10) {
184 preselectedHits[iLayer].push_back(hits[iHit]);
187 if (iWireBeginList[iLayer] <= iWire || iWire < (iWireBeginList[iLayer] + 10) % m_nWire[iLayer]) {
188 preselectedHits[iLayer].push_back(hits[iHit]);
193 return preselectedHits;
196vector<vector<double>>
199 vector<vector<double>> s(m_nStereoLayer, vector<double>());
201 for (
int iLayer = 0; iLayer < m_nStereoLayer; iLayer++) {
202 for (
int iHit = 0; iHit < (int)preselectedHits[iLayer].size(); iHit++) {
203 for (
int lr = 1; lr <= 2; lr++) {
204 double _s = 2 / omega * asin(1.0 / 2 * m_rWire[iLayer] * omega);
205 s[iLayer].push_back(_s);
212vector<vector<double>>
215 vector<vector<double>> z(m_nStereoLayer, vector<double>());
217 for (
int iLayer = 0; iLayer < m_nStereoLayer; iLayer++) {
218 for (
CDCHit* hit : preselectedHits[iLayer]) {
221 double phiCross =
calPhiCross(m_rWire[iLayer], phi0, omega);
222 for (
int lr = 1; lr <= 2; lr++) {
225 phiHit = phiCross + driftLength / m_rWire[iLayer];
226 }
else if (lr == 2) {
227 phiHit = phiCross - driftLength / m_rWire[iLayer];
229 double deltaPhi =
normalizeAngle(phiHit - m_phiBW[iLayer][hit->getIWire()]);
230 double _z = m_zBW[iLayer] + m_rWire[iLayer] * deltaPhi / tan(m_stereoAngle[iLayer]);
231 z[iLayer].push_back(_z);
238CDCTrigger3DFitterModule::HoughVoter::HoughVoter()
240 votingCell.resize(nCellZ0, vector<int>(nCellZ0, 0));
244CDCTrigger3DFitterModule::HoughVoter::vote(
const vector<vector<double>>& sCand,
const vector<vector<double>>& zCand)
250 for (
int iLayer = 0; iLayer < m_nStereoLayer; iLayer++) {
251 for (
int iHit = 0; iHit < (int)sCand[iLayer].size(); iHit++) {
252 double s = sCand[iLayer][iHit];
253 double z = zCand[iLayer][iHit];
255 for (
int iCot = 0; iCot < nCellCot; iCot++) {
256 int iZ0Shift = floor((z - (-cellWidthZ0 / 2)) / cellWidthZ0);
258 double cotLower = getCotCellValue(iCot - 0.5);
259 double z0Lower = -s * cotLower;
260 int iZ0Lower = digitizeZ0(z0Lower) - iZ0Shift;
262 double cotUpper = getCotCellValue(iCot + 0.5);
263 double z0Upper = -s * cotUpper;
264 int iZ0Upper = digitizeZ0(z0Upper) - iZ0Shift;
266 for (
int iZ0 = max(iZ0Lower, 0); iZ0 < min(iZ0Upper + 1, nCellZ0); iZ0++) {
267 votingCell[iZ0][iCot] |= (1 << iLayer);
274tuple<double, double, int>
275CDCTrigger3DFitterModule::HoughVoter::findPeak()
279 for (
int iZ0 = 0; iZ0 < nCellZ0; iZ0++) {
280 for (
int iCot = nCellCot - 1; iCot >= 0; iCot--) {
281 int count = __builtin_popcount(votingCell[iZ0][iCot]);
282 if (maxCount <= count) {
284 z0 = getZ0CellValue(iZ0);
285 cot = getCotCellValue(iCot);
289 return make_tuple(z0, cot, maxCount);
292pair<vector<double>, vector<double>>
295 vector<double> sSelected(m_nStereoLayer, -1);
296 vector<double> zSelected(m_nStereoLayer, -1);
298 for (
int iLayer = 0; iLayer < m_nStereoLayer; iLayer++) {
299 double minDeltaZ = m_maxZSelection;
300 for (
int iHit = 0; iHit < (int)sCand[iLayer].size(); iHit++) {
301 double zVoter = sCand[iLayer][iHit] * cot + z0;
302 double deltaZ = abs(zCand[iLayer][iHit] - zVoter);
303 if (deltaZ < minDeltaZ) {
305 sSelected[iLayer] = sCand[iLayer][iHit];
306 zSelected[iLayer] = zCand[iLayer][iHit];
311 return make_pair(sSelected, zSelected);
318 double nHit = 0, sum_s = 0, sum_z = 0, sum_sz = 0, sum_ss = 0;
319 for (
int iLayer = 0; iLayer < m_nStereoLayer; iLayer++) {
321 if (s[iLayer] < 0)
continue;
326 sum_sz += s[iLayer] * z[iLayer];
327 sum_ss += s[iLayer] * s[iLayer];
330 double denominator = nHit * sum_ss - sum_s * sum_s;
331 double z0 = (-sum_s * sum_sz + sum_ss * sum_z) / denominator;
332 double cot = (nHit * sum_sz - sum_s * sum_z) / denominator;
333 return make_pair(z0, cot);
342 int iStereoSuperLayer = (iContinuousLayer - 8) / 12;
343 int iLayerInSL = iContinuousLayer - 8 - 12 * iStereoSuperLayer;
344 return iStereoSuperLayer * m_nLayerInSuperLayer + iLayerInSL;
350 return atan2(sin(angle), cos(angle));
358 double phiCross = phi0 - asin(1.0 / 2 * r * omega);
365 vector<int> iWireBeginList(m_nStereoLayer, -1);
367 for (
int iLayer = 0; iLayer < m_nStereoLayer; iLayer++) {
368 int iStereoSuperLayer = iLayer / m_nLayerInSuperLayer;
369 int iLayerInSL = iLayer % m_nLayerInSuperLayer;
372 if (abs(1.0 / 2 * m_rWire[iLayer] * omega) > 1)
continue;
374 double phiCross =
calPhiCross(m_rWire[iLayer], phi0, omega);
375 if (phiCross < 0) phiCross += 2 * M_PI;
377 double iWireCross = phiCross / (2 * M_PI) * m_nWire[iLayer];
378 if (iLayerInSL % 2 == 1) iWireCross -= 0.5;
382 if (iStereoSuperLayer == 0 || iStereoSuperLayer == 2) {
384 iWireEnd = (int)(ceil(iWireCross)) % m_nWire[iLayer];
385 iWireBegin = (iWireEnd - 10 + m_nWire[iLayer]) % m_nWire[iLayer];
387 iWireBegin = (int)(ceil(iWireCross)) % m_nWire[iLayer];
389 iWireBeginList[iLayer] = iWireBegin;
391 return iWireBeginList;
402 vector<int> iHitInEachCell(m_nCellInTS, -1);
403 for (
int iHit = 0; iHit < (int)hits.size(); iHit++) {
416 int diffILayer = hit.getICLayer() - priorityILayer;
417 int diffIWire = hit.getIWire() - priorityIWire;
418 if (diffIWire < -2) diffIWire += m_nWire[iLayer];
419 if (diffIWire > 2) diffIWire -= m_nWire[iLayer];
429 int iTSCell = m_cellIDInTS[make_pair(diffILayer, diffIWire)];
430 iHitInEachCell[iTSCell] = iHit;
434 vector<int> iHitInEachLayer(m_nLayerInSuperLayer, -1);
435 vector<vector<int>> selectOrder{{1, 0, 2}, {3, 4}, {5}, {7, 6}, {9, 10, 8}};
436 for (
int iLayerInSL = 0; iLayerInSL < m_nLayerInSuperLayer; iLayerInSL++) {
437 for (
int iCell : selectOrder[iLayerInSL]) {
438 if (iHitInEachCell[iCell] == -1)
continue;
439 iHitInEachLayer[iLayerInSL] = iHitInEachCell[iCell];
444 return iHitInEachLayer;
453 double driftTime = 0;
457 int hitTime = (int)floor((cdc.getT0(
WireID(hit.getID())) / cdc.getTdcBinWidth() - hit.getTDCCount() + 0.5) / 2);
459 driftTime = hitTime - T0;
461 if (driftTime < 0)driftTime = 0;
462 if (driftTime >= m_maxDriftTime)driftTime = m_maxDriftTime - 1;
DataType Phi() const
The azimuth angle.
DataType Z() const
access variable Z (= .at(2) without boundary check)
DataType Theta() const
The polar angle.
bool hasBinnedEventT0(const Const::EDetector detector) const
Check if one of the detectors in the given set has a binned t0 estimation.
int getBinnedEventT0(const Const::EDetector detector) const
Return the stored binned event t0 for the given detector or 0 if nothing stored.
Class containing the result of the unpacker in raw data and the result of the digitizer in simulation...
Class for the Hough voter.
std::string m_EventTimeName
name of the event time StoreObjPtr
std::pair< double, double > fitter(const std::vector< double > &s, const std::vector< double > &z)
Performance linear fitting with the selected s and z.
StoreArray< CDCTriggerTrack > m_tracks2D
list of 2D input tracks
std::vector< std::vector< double > > m_xtCurve
CDC geometry constants.
std::vector< std::vector< CDCHit * > > preselector(double phi0, double omega)
Select 10 wires which crosses with the given 2D track.
std::string m_CDCHitCollectionName
Name of the StoreArray containing the input CDChits.
virtual void initialize() override
Initialize the module and register DataStore arrays.
CDCTrigger3DFitterModule()
Constructor, for setting module description and parameters.
virtual void event() override
Run the 3D fitter for an event.
std::string m_outputCollectionName
Name of the StoreArray containing the resulting 3D tracks.
std::vector< std::vector< double > > zConverter(const std::vector< std::vector< CDCHit * > > &preselectedHits, double phi0, double omega)
Calculate z at the hit position.
StoreArray< CDCTriggerSegmentHit > m_TSHits
list of track segment hits
double getDriftLength(const CDCHit hit)
Get drift length.
double calPhiCross(double r, double phi0, double omega)
Calculate phi coordinate of the crossing point of the given radius and the given 2D track.
std::string m_inputCollectionName
Name of the StoreArray containing the input tracks from the 2D fitter.
double normalizeAngle(double angle)
Convert the given angle(rad) to the range [-pi, pi].
int getIStereoLayer(int iContinuousLayer)
Convert continuous layer ID (0–55) -> stereo layer ID (0–19).
std::string m_TSHitCollectionName
Name of the StoreArray containing the input track segment hits.
StoreArray< CDCTriggerTrack > m_tracks3D
list of 3D output tracks
std::vector< int > select5Cells(const CDCTriggerSegmentHit *TS)
1 cell is selected in each layer to reduce LUT comsumption.
int m_minVoteCount
Minimal number of votes in Hough voting.
StoreObjPtr< BinnedEventT0 > m_eventTime
StoreObjPtr containing the event time.
std::vector< std::vector< double > > sConverter(const std::vector< std::vector< CDCHit * > > &preselectedHits, double omega)
Calculate s(arc length of the 2D track) at the hit position.
std::pair< std::vector< double >, std::vector< double > > selector(const std::vector< std::vector< double > > &sCand, const std::vector< std::vector< double > > &zCand, double z0, double cot)
Select the nearest hits from the voter result.
std::vector< int > getIWireBegin(double phi0, double omega)
Get the beginning wire ID of the preselection range(10 wires) for each layer.
Combination of several CDCHits to a track segment hit for the trigger.
unsigned short getPriorityPosition() const
get position of the priority cell within the track segment (0: no hit, 3: 1st priority,...
unsigned short getIWire() const
get wire number of priority wire within layer.
unsigned short getID() const
get the encoded wire number of the priority wire.
unsigned short getISuperLayer() const
get super layer number.
Track created by the CDC trigger.
The Class for CDC Geometry Parameters.
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
void setDescription(const std::string &description)
Sets the description of the module.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Class for type safe access to objects that are referred to in relations.
RelationVector< TO > getRelationsTo(const std::string &name="", const std::string &namedRelation="") const
Get the relations that point from this object to another store array.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
bool requireRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, const std::string &namedRelation="") const
Produce error if no relation from this array to 'toArray' has been registered.
T * appendNew()
Construct a new T object at the end of the array.
int getEntries() const
Get the number of objects in the array.
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Class to identify a wire inside the CDC.
unsigned short getICLayer() const
Getter for continuous layer numbering.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.