CbmRoot
Loading...
Searching...
No Matches
CbmStsAlgoFindHits.cxx
Go to the documentation of this file.
1/* Copyright (C) 2013-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Volker Friese [committer] */
4
10
11#include "CbmDigiManager.h"
12#include "CbmGeometryUtils.h"
13#include "CbmStsCluster.h"
14#include "CbmStsDigi.h"
15#include "CbmStsHit.h"
16#include "CbmStsParSensor.h"
17#include "CbmStsParSensorCond.h"
18
19#include <TGeoMatrix.h>
20#include <TMath.h>
21
22#include <iostream>
23
24using std::pair;
25using std::vector;
26
27// ----- Constructor ---------------------------------------------------
29// -------------------------------------------------------------------------
30
31
32// ----- Create a new hit ----------------------------------------------
33void CbmStsAlgoFindHits::CreateHit(Double_t xLocal, Double_t yLocal, Double_t varX, Double_t varY, Double_t varXY,
34 const CbmStsCluster& clusterF, const CbmStsCluster& clusterB, UInt_t indexF,
35 UInt_t indexB, Double_t du, Double_t dv)
36{
37
38 // --- Check output array
39 assert(fHits);
40
41 // --- Transform into global coordinate system
42 Double_t local[3] = {xLocal, yLocal, 0.};
43 Double_t global[3];
44
45 if (fMatrix) {
46 fMatrix->LocalToMaster(local, global);
48 }
49 else {
50 global[0] = local[0];
51 global[1] = local[1];
52 global[2] = local[2];
53 } //? no transformation matrix available
54
55 Double_t error[3] = {TMath::Sqrt(varX), TMath::Sqrt(varY), 0.};
56
57 // --- Calculate hit time (average of cluster times)
58 Double_t hitTime = 0.5 * (clusterF.GetTime() + clusterB.GetTime());
59 Double_t etF = clusterF.GetTimeError();
60 Double_t etB = clusterB.GetTimeError();
61 Double_t hitTimeError = 0.5 * TMath::Sqrt(etF * etF + etB * etB);
62
63 // --- Create hit
64 fHits->emplace_back(fAddress, global, error, varXY, indexF, indexB, hitTime, hitTimeError, du, dv);
65
66 return;
67}
68// -------------------------------------------------------------------------
69
70
71// ----- Algorithm execution -------------------------------------------
72Long64_t CbmStsAlgoFindHits::Exec(const vector<CbmStsCluster>& clustersF, const vector<CbmStsCluster>& clustersB,
73 vector<CbmStsHit>& hits, UInt_t address, Double_t timeCutSig, Double_t timeCutAbs,
74 Double_t dY, UInt_t nStrips, Double_t pitch, Double_t stereoF, Double_t stereoB,
75 Double_t lorentzF, Double_t lorentzB, TGeoHMatrix* matrix)
76{
77
78 // Assert validity of parameters
79 assert(nStrips > 0);
80 assert(pitch > 0.);
81 assert(TMath::Abs(stereoF - stereoB) > 0.1);
82
83 // Set internal parameters
84 fAddress = address;
85 fNofStrips = nStrips;
86 fDy = dY;
87 fPitch = pitch;
88 fStereoF = stereoF;
89 fStereoB = stereoB;
90 fLorentzF = lorentzF;
91 fLorentzB = lorentzB;
92 fMatrix = matrix;
93 fHits = &hits;
94 fHits->clear();
95 fTanStereoF = TMath::Tan(fStereoF * TMath::DegToRad());
96 fTanStereoB = TMath::Tan(fStereoB * TMath::DegToRad());
98 fDx = Double_t(fNofStrips) * fPitch;
99
100 // Determine the maximum cluster time errors
101 Double_t maxTerrF = 0.;
102 for (auto& cluster : clustersF) {
103 if (cluster.GetTimeError() > maxTerrF) maxTerrF = cluster.GetTimeError();
104 }
105 Double_t maxTerrB = 0.;
106 for (auto& cluster : clustersB) {
107 if (cluster.GetTimeError() > maxTerrB) maxTerrB = cluster.GetTimeError();
108 }
109 const Double_t maxTerrF2 = maxTerrF * maxTerrF;
110 const Double_t maxTerrB2 = maxTerrB * maxTerrB;
111 const Double_t max_sigma_both = 4. * TMath::Sqrt(maxTerrF2 + maxTerrB2);
112
113 // --- Loop over front and back side clusters
114 Long64_t nHits = 0;
115 Int_t startB = 0;
116 for (UInt_t iClusterF = 0; iClusterF < clustersF.size(); iClusterF++) {
117 const CbmStsCluster& clusterF = clustersF[iClusterF];
118
119 Double_t tF = clusterF.GetTime();
120 Double_t tFerr2 = clusterF.GetTimeError() * clusterF.GetTimeError();
121 Double_t max_sigma = 4. * TMath::Sqrt(tFerr2 + maxTerrB2);
122
123 for (UInt_t iClusterB = startB; iClusterB < clustersB.size(); iClusterB++) {
124 const CbmStsCluster& clusterB = clustersB[iClusterB];
125
126 Double_t timeDiff = tF - clusterB.GetTime();
127
128 if ((timeDiff > 0) && (timeDiff > max_sigma_both)) {
129 startB++;
130 continue;
131 }
132 else if ((timeDiff > 0) && (timeDiff > max_sigma)) {
133 continue;
134 }
135 else if ((timeDiff < 0) && (fabs(timeDiff) > max_sigma))
136 break;
137
138 // Cut on time difference of the two clusters
139 Double_t timeCut = -1.;
140 if (timeCutAbs > 0.)
141 timeCut = timeCutAbs; // absolute cut value
142 else {
143 if (timeCutSig > 0.) {
144 Double_t eF = clusterF.GetTimeError();
145 Double_t eB = clusterB.GetTimeError();
146 timeCut = timeCutSig * TMath::Sqrt(eF * eF + eB * eB);
147 } //? cut calculated from cluster errors
148 }
149 if (fabs(clusterF.GetTime() - clusterB.GetTime()) > timeCut) continue;
150
151 // --- Calculate intersection points
152 Int_t nOfHits = IntersectClusters(clusterF, clusterB, iClusterF, iClusterB);
153 nHits += nOfHits;
154
155 } //# clusters back side
156
157 } //# clusters front side
158
159 return nHits;
160}
161// -------------------------------------------------------------------------
162
163
164// ----- Get cluster position at read-out edge -------------------------
165void CbmStsAlgoFindHits::GetClusterPosition(Double_t centre, Double_t& xCluster, Int_t& side)
166{
167
168 // Take integer channel
169 Int_t iChannel = Int_t(centre);
170 Double_t xDif = centre - Double_t(iChannel);
171
172 // Calculate corresponding strip on sensor
173 Int_t iStrip = -1;
174 pair<Int_t, Int_t> stripSide = GetStrip(iChannel);
175 iStrip = stripSide.first;
176 side = stripSide.second;
177
178 // Re-add difference to integer channel. Convert channel to
179 // coordinate
180 xCluster = (Double_t(iStrip) + xDif + 0.5) * fPitch;
181
182 // Correct for Lorentz-Shift
183 // Simplification: The correction uses only the y component of the
184 // magnetic field. The shift is calculated using the mid-plane of the
185 // sensor, which is not correct for tracks not traversing the entire
186 // sensor thickness (i.e., are created or stopped somewhere in the sensor).
187 // However, this is the best one can do in reconstruction.
188 if (side == 0)
189 xCluster -= fLorentzF;
190 else
191 xCluster -= fLorentzB;
192
193 return;
194}
195// -------------------------------------------------------------------------
196
197
198// ----- Get strip and side from channel number ------------------------
199pair<Int_t, Int_t> CbmStsAlgoFindHits::GetStrip(UInt_t channel) const
200{
201
202 Int_t stripNr = -1;
203 Int_t side = -1;
204
205 // --- Determine front or back side
206 if (channel < fNofStrips) { // front side
207 side = 0;
208 stripNr = channel;
209 }
210 else { // back side
211 side = 1;
212 stripNr = channel - fNofStrips;
213 }
214
215 // --- Horizontal cross-connection
216 while (stripNr < 0)
217 stripNr += fNofStrips;
218 while (stripNr >= Int_t(fNofStrips))
219 stripNr -= fNofStrips;
220
221 return (pair<Int_t, Int_t>(stripNr, side));
222}
223// -------------------------------------------------------------------------
224
225
226// ----- Intersection of two lines along the strips --------------------
227Bool_t CbmStsAlgoFindHits::Intersect(Double_t xF, Double_t exF, Double_t xB, Double_t exB, Double_t& x, Double_t& y,
228 Double_t& varX, Double_t& varY, Double_t& varXY)
229{
230
231 // In the coordinate system with origin at the bottom left corner,
232 // a line along the strips with coordinate x0 at the top edge is
233 // given by the function y(x) = Dy - ( x - x0 ) / tan(phi), if
234 // the stereo angle phi does not vanish. Two lines yF(x), yB(x) with top
235 // edge coordinates xF, xB intersect at
236 // x = ( tan(phiB)*xF - tan(phiF)*xB ) / (tan(phiB) - tan(phiF)
237 // y = Dy + ( xB - xF ) / ( tan(phiB) - tan(phiF) )
238 // For the case that one of the stereo angles vanish (vertical strips),
239 // the calculation of the intersection is straightforward.
240
241 // --- First check whether stereo angles are different. Else there is
242 // --- no intersection.
243 if (TMath::Abs(fStereoF - fStereoB) < 0.5) {
244 x = -1000.;
245 y = -1000.;
246 return kFALSE;
247 }
248
249 // --- Now treat vertical front strips
250 if (TMath::Abs(fStereoF) < 0.001) {
251 x = xF;
252 y = fDy - (xF - xB) / fTanStereoB;
253 varX = exF * exF;
254 varY = (exF * exF + exB * exB) / fTanStereoB / fTanStereoB;
255 varXY = -1. * exF * exF / fTanStereoB;
256 return IsInside(x - fDx / 2., y - fDy / 2.);
257 }
258
259 // --- Maybe the back side has vertical strips?
260 if (TMath::Abs(fStereoB) < 0.001) {
261 x = xB;
262 y = fDy - (xB - xF) / fTanStereoF;
263 varX = exB * exB;
264 varY = (exF * exF + exB * exB) / fTanStereoF / fTanStereoF;
265 varXY = -1. * exB * exB / fTanStereoF;
266 return IsInside(x - fDx / 2., y - fDy / 2.);
267 }
268
269 // --- OK, both sides have stereo angle
270 x = (fTanStereoB * xF - fTanStereoF * xB) / (fTanStereoB - fTanStereoF);
271 y = fDy + (xB - xF) / (fTanStereoB - fTanStereoF);
272 varX = fErrorFac * (exF * exF * fTanStereoB * fTanStereoB + exB * exB * fTanStereoF * fTanStereoF);
273 varY = fErrorFac * (exF * exF + exB * exB);
274 varXY = -1. * fErrorFac * (exF * exF * fTanStereoB + exB * exB * fTanStereoF);
275
276 // --- Check for being in active area.
277 return IsInside(x - fDx / 2., y - fDy / 2.);
278}
279// -------------------------------------------------------------------------
280
281
282// ----- Intersect two clusters ----------------------------------------
283Int_t CbmStsAlgoFindHits::IntersectClusters(const CbmStsCluster& clusterF, const CbmStsCluster& clusterB, UInt_t indexF,
284 UInt_t indexB)
285{
286
287 // --- Calculate cluster centre position on readout edge
288 Int_t side = -1;
289 Double_t xF = -1.;
290 Double_t xB = -1.;
291 GetClusterPosition(clusterF.GetPosition(), xF, side);
292 //std::cout << "Cluster position " << clusterF.GetPosition() << ": x "
293 // << xF << " side " << side;
294 if (side != 0) {
295 std::cout << "Cluster position " << clusterF.GetPosition() << ": x " << xF << " side " << side << std::endl;
296 }
297 assert(side == 0);
298 Double_t exF = clusterF.GetPositionError() * fPitch;
299 Double_t du = exF * TMath::Cos(TMath::DegToRad() * fStereoF);
300 GetClusterPosition(clusterB.GetPosition(), xB, side);
301 assert(side == 1);
302 Double_t exB = clusterB.GetPositionError() * fPitch;
303 Double_t dv = exB * TMath::Cos(TMath::DegToRad() * fStereoB);
304
305 // --- Should be inside active area
306 if (!(xF >= 0. || xF <= fDx)) return 0;
307 if (!(xB >= 0. || xB <= fDx)) return 0;
308
309 // --- Hit counter
310 Int_t nHits = 0;
311
312 // --- Calculate number of line segments due to horizontal
313 // --- cross-connection. If x(y=0) does not fall on the bottom edge,
314 // --- the strip is connected to the one corresponding to the line
315 // --- with top edge coordinate xF' = xF +/- Dx. For odd combinations
316 // --- of stereo angle and sensor dimensions, this could even happen
317 // --- multiple times. For each of these lines, the intersection with
318 // --- the line on the other side is calculated. If inside the active area,
319 // --- a hit is created.
320 Int_t nF = Int_t((xF + fDy * fTanStereoF) / fDx);
321 Int_t nB = Int_t((xB + fDy * fTanStereoB) / fDx);
322
323 // --- If n is positive, all lines from 0 to n must be considered,
324 // --- if it is negative (phi negative), all lines from n to 0.
325 Int_t nF1 = TMath::Min(0, nF);
326 Int_t nF2 = TMath::Max(0, nF);
327 Int_t nB1 = TMath::Min(0, nB);
328 Int_t nB2 = TMath::Max(0, nB);
329
330 // --- Double loop over possible lines
331 Double_t xC = -1.; // x coordinate of intersection point
332 Double_t yC = -1.; // y coordinate of intersection point
333 Double_t varX = 0.; // variance of xC
334 Double_t varY = 0.; // variance of yC
335 Double_t varXY = 0.; // covariance xC-yC
336 for (Int_t iF = nF1; iF <= nF2; iF++) {
337 Double_t xFi = xF - Double_t(iF) * fDx;
338 for (Int_t iB = nB1; iB <= nB2; iB++) {
339 Double_t xBi = xB - Double_t(iB) * fDx;
340
341 // --- Intersect the two lines
342 Bool_t found = Intersect(xFi, exF, xBi, exB, xC, yC, varX, varY, varXY);
343 if (found) {
344
345 // --- Transform into sensor system with origin at sensor centre
346 xC -= 0.5 * fDx;
347 yC -= 0.5 * fDy;
348 // --- Create the hit
349 CreateHit(xC, yC, varX, varY, varXY, clusterF, clusterB, indexF, indexB, du, dv);
350 nHits++;
351
352 } //? Intersection of lines
353 } // lines on back side
354 } // lines on front side
355
356 return nHits;
357
358 return 0;
359}
360// -------------------------------------------------------------------------
361
362
363// ----- Check whether a point is inside the active area ---------------
364Bool_t CbmStsAlgoFindHits::IsInside(Double_t x, Double_t y)
365{
366 if (x < -fDx / 2.) return kFALSE;
367 if (x > fDx / 2.) return kFALSE;
368 if (y < -fDy / 2.) return kFALSE;
369 if (y > fDy / 2.) return kFALSE;
370 return kTRUE;
371}
372// -------------------------------------------------------------------------
373
374
ClassImp(CbmConverterManager)
Data class for STS clusters.
Data class for a reconstructed hit in the STS.
static vector< vector< QAHit > > hits
Algorithm for hit finding in the sensors of the CBM-STS.
Double_t fDy
Active size in y [cm].
Bool_t Intersect(Double_t xF, Double_t exF, Double_t xB, Double_t exB, Double_t &x, Double_t &y, Double_t &varX, Double_t &varY, Double_t &varXY)
Intersection point of two strips / cluster centres.
std::pair< Int_t, Int_t > GetStrip(UInt_t channel) const
Get strip and side from module channel.
Double_t fLorentzF
Lorentz shift correction front side [cm].
Double_t fPitch
Strip pitch [cm].
Double_t fStereoF
Stereo angle front side [deg].
CbmStsAlgoFindHits()
Constructor.
UInt_t fAddress
Unique address for hits (sensor)
Double_t fTanStereoB
Tangent of stereo angle back side.
Double_t fErrorFac
For calculation of the hit error.
Double_t fTanStereoF
///< Transformation matrix to global C.S.
void CreateHit(Double_t xLocal, Double_t yLocal, Double_t varX, Double_t varY, Double_t varXY, const CbmStsCluster &clusterF, const CbmStsCluster &clusterB, UInt_t indexF, UInt_t indexB, Double_t du=0., Double_t dv=0.)
Create a new hit in the output array.
Double_t fStereoB
Stereo angle back side [deg].
void GetClusterPosition(Double_t ClusterCentre, Double_t &xCluster, Int_t &side)
Int_t IntersectClusters(const CbmStsCluster &clusterF, const CbmStsCluster &clusterB, UInt_t indexF, UInt_t indexB)
Find the intersection points of two clusters.
UInt_t fNofStrips
Number of strips.
Double_t fDx
Active size in x [cm].
Bool_t IsInside(Double_t x, Double_t y)
Check whether a point (x,y) is inside the active area.
std::vector< CbmStsHit > * fHits
Output vector of hits.
Double_t fLorentzB
Lorentz shift correction back side [cm].
Long64_t Exec(const std::vector< CbmStsCluster > &clustersF, const std::vector< CbmStsCluster > &clustersB, std::vector< CbmStsHit > &hits, UInt_t address, Double_t timeCutSig, Double_t timeCutAbs, Double_t dY, UInt_t nStrips, Double_t pitch, Double_t stereoF, Double_t stereoB, Double_t lorentzF, Double_t lorentzB, TGeoHMatrix *matrix)
Execute algorithm.
Data class for STS clusters.
double GetPositionError() const
Cluster position error @value Error (r.m.s.) of cluster position in channel number units.
double GetTime() const
Get cluster time.
double GetPosition() const
Cluster position @value Cluster position in channel number units.
double GetTimeError() const
Get error of cluster time.
void LocalToMasterCovarianceMatrix(const TGeoMatrix &m, Double_t &covXX, Double_t &covXY, Double_t &covYY)
Convert the local X/Y covariance matrix to global coordinates.