GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TSiLi.cxx
Go to the documentation of this file.
1#include "TSiLi.h"
2
3// Having these in Clear() caused issues as functions can be called abstract with out initialising a TSiLi
4int TSiLi::fRingNumber = 10;
6double TSiLi::fOffsetPhi = -165. * TMath::Pi() / 180.; // For SPICE. Sectors upstream.
7double TSiLi::fOuterDiameter = 94.;
8double TSiLi::fInnerDiameter = 16.;
9double TSiLi::fTargetDistance = -117.8;
10
11double TSiLi::fSiLiNoiseFac = 4;
12double TSiLi::fSiLiDefaultDecay = 4616.18;
13double TSiLi::fSiLiDefaultRise = 20.90;
14double TSiLi::fSiLiDefaultBaseline = -4300;
15double TSiLi::fBaseFreq = 4;
16
19
20int TSiLi::fFitSiLiShape = 0; // 0 no. 1 try if normal fit fail. 2 yes
21
23{
24 Clear();
25}
26
27void TSiLi::Copy(TObject& rhs) const
28{
29 TDetector::Copy(rhs);
30 static_cast<TSiLi&>(rhs).fAddbackHits = fAddbackHits;
31 static_cast<TSiLi&>(rhs).fSiLiBits = 0;
32}
33
34TSiLi::TSiLi(const TSiLi& rhs) : TDetector(rhs)
35{
36 rhs.Copy(*this);
37}
38
39void TSiLi::Clear(Option_t* opt)
40{
42 fAddbackHits.clear();
44}
45
47{
48 rhs.Copy(*this);
49 return *this;
50}
51
52void TSiLi::Print(Option_t*) const
53{
54 Print(std::cout);
55}
56
57void TSiLi::Print(std::ostream& out) const
58{
59 std::ostringstream str;
60 str << GetMultiplicity() << " sili_hits" << std::endl;
61 str << fAddbackHits.size() << " sili_addback_hits" << std::endl;
62 out << str.str();
63}
64
65void TSiLi::AddFragment(const std::shared_ptr<const TFragment>& frag, TChannel* chan)
66{
67 if(frag == nullptr || chan == nullptr) {
68 return;
69 }
70
71 auto* hit = new TSiLiHit(*frag); // Waveform fitting happens in ctor now
72 AddHit(hit);
73}
74
75// For mapping you may want to us -position.X() to account for looking upstream
76TVector3 TSiLi::GetPosition(int ring, int sector, bool smear)
77{
78
79 double dist = fTargetDistance;
80
81 double ring_width = (fOuterDiameter - fInnerDiameter) * 0.5 / fRingNumber; // radial width!
82 double inner_radius = fInnerDiameter / 2.0;
83 double phi_width = 2. * TMath::Pi() / fSectorNumber;
84 double phi = phi_width * sector; // the phi angle....
85 phi += fOffsetPhi;
86 double radius = inner_radius + ring_width * (ring + 0.5);
87 if(smear) {
88 double sep = ring_width * 0.025;
89 double r1 = radius - ring_width * 0.5 + sep;
90 double r2 = radius + ring_width * 0.5 - sep;
91 radius = sqrt(gRandom->Uniform(r1 * r1, r2 * r2));
92 double sepphi = sep / radius;
93 phi = gRandom->Uniform(phi - phi_width * 0.5 + sepphi, phi + phi_width * 0.5 - sepphi);
94 }
95
96 return {cos(phi) * radius, sin(phi) * radius, dist};
97}
98
99double TSiLi::GetSegmentArea(Int_t seg)
100{
101 int r = GetRing(seg);
102 double ring_width = (fOuterDiameter - fInnerDiameter) * 0.5 / fRingNumber; // radial width!
103 double r1 = fInnerDiameter + r * ring_width;
104 double r2 = fInnerDiameter + (r + 1) * ring_width;
105
106 return (TMath::Pi() * (r2 * r2 - r1 * r1)) / fSectorNumber;
107}
108
110{
111 /// Get the ith addback hit. This function calls GetAddbackMultiplicity to check the range of the index.
112 /// This automatically calculates all addback hits if they haven't been calculated before.
113 if(i < GetAddbackMultiplicity()) {
114 return &fAddbackHits.at(i);
115 }
116 std::cerr << "Addback hits are out of range" << std::endl;
117 throw grsi::exit_exception(1);
118 return nullptr;
119}
120
122{
123 if(i < GetRejectMultiplicity()) {
124 return GetSiLiHit(fRejectHits[i]);
125 }
126 std::cerr << "Reject hits are out of range" << std::endl;
127 throw grsi::exit_exception(1);
128 return nullptr;
129}
130
132{
134 return fRejectHits.size();
135}
136
137// Currently Addback
138//
139// Itterate through all pixel hits
140// If the hit has not yet been assigned to a "cluster" a new cluster is created containing it.
141// The hit is compared all subsequent hits against fAddbackCriterion
142// If they are accepted neighbours the second hit is also added to the cluster
143//
144// fAddbackCriterion checks if hits are within 2 pixels and compares times and energy
145//
146// Clusters >1 hit are accepted or rejected on a few criteria:
147// >3 hits all rejected
148// Clusters of 2 or 3 which are discontinuous (missing middle pixel) are rejected
149// Clusters spanning 3 sectors are rejected as impossible
150// Clusters spanning 3 rings and a single sector are accepted IF energy of middle segment is large enough
151//
152// Additionally clusters can be rejected if any of constituent hit is tagged as potential preamp-noise-crosstalk.
153// This rules out many 3 hit events.
154//
155// Most of these rules favour clean spectra rather than efficiency, as currently noise dominates and addback events are not usable.
156
158{
159 // Automatically builds the addback hits using the addback_criterion (if the size of the addback_hits vector is zero)
160 // and return the number of addback hits.
161 int16_t basehits = GetMultiplicity();
162
163 // if the addback has been reset, clear the addback hits
165 return fAddbackHits.size();
166 }
167 fAddbackHits.clear();
168 fRejectHits.clear();
169
170 if(basehits == 0) {
172 return 0;
173 }
174
175 //Do the addback if it hasnt been done
176 if(fAddbackHits.empty() && fRejectHits.empty()) {
177 //Check if any of the initial hits could be preamp noise induction
178 std::vector<bool> fPreampRejectedHit(basehits, false);
179 for(int i = 0; i < basehits; i++) {
180 for(int j = i + 1; j < basehits; j++) {
182 fPreampRejectedHit[i] = true;
183 fPreampRejectedHit[j] = true;
184 }
185 }
186 }
187
188 std::vector<unsigned> clusters_id(basehits, 0);
189 std::vector<std::vector<unsigned>> Clusters;
190 std::vector<bool> hasreject;
191
192 // In this loop we check all hits for pairing
193 for(int i = 0; i < basehits; i++) {
194 if(clusters_id[i] < 1) { // If not yet paired start a new cluster
195 std::vector<unsigned> newCluster(1, i);
196 Clusters.push_back(newCluster);
197 clusters_id[i] = Clusters.size();
198 hasreject.push_back(fPreampRejectedHit[i]);
199 }
200 unsigned clus_id = clusters_id[i];
201
202 for(int j = i + 1; j < basehits; j++) {
204 Clusters[clus_id - 1].push_back(j);
205 if(fPreampRejectedHit[j]) { hasreject[clus_id - 1] = true; }
206 clusters_id[j] = clus_id;
207 }
208 }
209 }
210
211 // Clusters are lists of hit index that have been identified as coincident near neighbours
212 // Will be length 1 if no neighbours.
213 // AddCluster applies additional rules
214 for(unsigned int i = 0; i < Clusters.size(); i++) {
215 TSiLi::AddCluster(Clusters[i], hasreject[i]);
216 }
217
219 }
220
221 return fAddbackHits.size();
222}
223
225{
226 double e = one->GetEnergy() / two->GetEnergy();
227 if(fCoincidenceTime(one, two)) {
228 if(e > 0.05 && e < 50) { // very basic energy gate to suppress noise issues
229 int dring = std::abs(one->GetRing() - two->GetRing());
230 int dsector = std::abs(one->GetSector() - two->GetSector());
231 if(dsector > 5) { dsector = 12 - dsector; }
232
233 //if(dsector+dring==1)return true;
234 //Changed to enable handing a missing middle pixel
235 if(dsector + dring < 3) { return true; }
236 }
237 }
238
239 return false;
240}
241
242// Intentionally no energy check as one of the two channels may have been calibrated to zero
243// but we still want to know when they are coincident for this check.
245{
246 if(fCoincidenceTime(one, two)) {
247 if(one->GetPreamp() == two->GetPreamp()) {
248 if(std::abs(one->GetPin() - two->GetPin()) < 2) {
249 return true;
250 }
251 }
252 }
253 return false;
254}
255
257{
258 double time = 0.;
259 if(one->GetTimeFit() > 0 && two->GetTimeFit() > 0) {
260 time = (one->GetTimeFit() - two->GetTimeFit()) * 10;
261 } else {
262 time = one->GetTime() - two->GetTime();
263 }
264
265 return std::abs(time) < fSiLiCoincidenceTime;
266}
267
268void TSiLi::AddCluster(std::vector<unsigned>& cluster, bool ContainsReject)
269{
270 if(cluster.empty()) { return; }
271 if(!fRejectPossibleCrosstalk) { ContainsReject = false; }
272
273 if(cluster.size() > 3) {
274 ContainsReject = true;
275 }
276
277 if(cluster.size() > 1 && !ContainsReject) {
278 TSiLiHit* A = static_cast<TSiLiHit*>(GetHit(cluster[0]));
279 TSiLiHit* B = static_cast<TSiLiHit*>(GetHit(cluster[1]));
280 int rA = A->GetRing();
281 int rB = B->GetRing();
282 int sA = A->GetSector();
283 int sB = B->GetSector();
284 int rAB = std::abs(rA - rB);
285 int sAB = std::abs(sA - sB);
286 if(sAB > 5) { sAB = 12 - sAB; }
287
288 if(cluster.size() == 2) {
289 //Reject events with missing middle pixel
290 if(rAB + sAB > 1) { ContainsReject = true; }
291 } else {
292 TSiLiHit* C = static_cast<TSiLiHit*>(GetHit(cluster[2]));
293 int rC = C->GetRing();
294 int sC = C->GetSector();
295 int rAC = std::abs(rA - rC);
296 int rBC = std::abs(rB - rC);
297 int sAC = std::abs(sA - sC);
298 int sBC = std::abs(sB - sC);
299
300 if(sAC > 5) { sAC = 12 - sAC; }
301 if(sBC > 5) { sBC = 12 - sBC; }
302
303 if(rA == rB && rB == rC) {
304 //Reject events that cross 3 sectors
305 ContainsReject = true;
306 } else if(rAB + sAB > 2 || rAC + sAC > 2 || rBC + sBC > 2) {
307 //Reject events that are too far apart (1 or more missing middles)
308 ContainsReject = true;
309 } else {
310 //Must be an allowed L OR 3 rings same sector
311 if(sA == sB && sB == sC) {
312 //if event crosses 3 rings
313 double midE = 0.;
314 if(((rA - rB) * (rA - rC)) < 0) {
315 midE = A->GetEnergy();
316 } else if(((rB - rA) * (rB - rC)) < 0) {
317 midE = B->GetEnergy();
318 } else {
319 midE = C->GetEnergy();
320 }
321
322 //Minimum possible energy
323 if(midE < 1400) { ContainsReject = true; }
324 }
325 }
326 }
327 }
328
329 if(ContainsReject) {
330 for(unsigned int j : cluster) {
331 fRejectHits.push_back(j);
332 }
333 } else {
334 uint s = fAddbackHits.size();
335 // We have to add it and THEN do the SumHit because the push_back copies the charge but not the energy,
336 // which is the bit we sum
337 // This is desired behaviour of TDetectorHit for speed of sorts, but messy for the addback, which should
338 // only be done "on the fly" not stored to TSiLi on disk
339 fAddbackHits.emplace_back();
340 for(unsigned int j : cluster) {
341 fAddbackHits[s].SumHit(GetSiLiHit(j));
342 }
343 }
344 // Note: I got rid of ordering the cluster first.
345 // There is really no way of knowing which is first for a double hits.
346 // For a triple hit there are 2 possible & opposite orders, it would probably be best to take the middle. But why bother?
347}
348
349// Just a useful function for some dynamic tools
350std::vector<TGraph> TSiLi::UpstreamShapes()
351{
352 std::vector<TGraph> ret;
353
354 double inner_radius = fInnerDiameter / 2.0;
355 double ring_width = (fOuterDiameter - fInnerDiameter) * 0.5 / fRingNumber; // radial width!
356 double phi_width = 2. * TMath::Pi() / fSectorNumber;
357
358 for(int ring = 0; ring < fRingNumber; ring++) {
359 double r1 = inner_radius + ring_width * ring;
360 double r2 = r1 + ring_width;
361
362 for(int sector = 0; sector < fSectorNumber; sector++) {
363 double phi = (phi_width * sector) + fOffsetPhi - (0.5 * phi_width);
364
365 TGraph G;
366 for(int i = 0; i <= 10; i++) {
367 double x = r1 * TMath::Cos(phi + i * (phi_width / 10.0));
368 double y = r1 * TMath::Sin(phi + i * (phi_width / 10.0));
369 G.SetPoint(G.GetN(), x, y);
370 }
371
372 for(int i = 10; i >= 0; i--) {
373 double x = r2 * TMath::Cos(phi + i * (phi_width / 10.0));
374 double y = r2 * TMath::Sin(phi + i * (phi_width / 10.0));
375 G.SetPoint(G.GetN(), x, y);
376 }
377
378 G.SetPoint(G.GetN(), (r1)*TMath::Cos(phi), (r1)*TMath::Sin(phi));
379
380 ret.push_back(G);
381 }
382 }
383 return ret;
384}
virtual Double_t GetTime(const ETimeFlag &correct_flag=ETimeFlag::kAll, Option_t *opt="") const
Returns a time value to the nearest nanosecond!
void Copy(TObject &) const override
!
Definition TDetector.cxx:24
virtual Short_t GetMultiplicity() const
Definition TDetector.h:70
virtual TDetectorHit * GetHit(const int &index) const
Definition TDetector.cxx:84
void Clear(Option_t *="") override
!
Definition TDetector.cxx:67
virtual void AddHit(TDetectorHit *hit)
Definition TDetector.h:60
double GetEnergy(Option_t *opt=nullptr) const override
Definition TSiLiHit.cxx:203
Int_t GetPreamp() const
Definition TSiLiHit.cxx:178
Int_t GetSector() const
Definition TSiLiHit.cxx:174
Int_t GetRing() const
Definition TSiLiHit.cxx:170
Int_t GetPin() const
Definition TSiLiHit.cxx:182
Double_t GetTimeFit() const
Definition TSiLiHit.h:40
Definition TSiLi.h:15
Int_t GetAddbackMultiplicity()
Definition TSiLi.cxx:157
bool fCoincidenceTime(TSiLiHit *, TSiLiHit *)
Definition TSiLi.cxx:256
static int fFitSiLiShape
!
Definition TSiLi.h:115
static double fSiLiDefaultDecay
Definition TSiLi.h:82
void Print(Option_t *opt="") const override
Definition TSiLi.cxx:52
static double fBaseFreq
!
Definition TSiLi.h:116
bool fRejectCriterion(TSiLiHit *, TSiLiHit *)
Definition TSiLi.cxx:244
static std::vector< TGraph > UpstreamShapes()
Definition TSiLi.cxx:350
void Copy(TObject &) const override
Definition TSiLi.cxx:27
void Clear(Option_t *opt="") override
Definition TSiLi.cxx:39
std::vector< unsigned int > fRejectHits
!
Definition TSiLi.h:120
TSiLiHit * GetSiLiHit(const Int_t &i=0) const
Definition TSiLi.h:45
static int fRingNumber
for geometery
Definition TSiLi.h:127
static double fOuterDiameter
!
Definition TSiLi.h:130
static double fSiLiDefaultBaseline
Definition TSiLi.h:84
TSiLiHit * GetRejectHit(const Int_t &i=0)
Definition TSiLi.cxx:121
static double fSiLiNoiseFac
Definition TSiLi.h:81
static double fSiLiDefaultRise
Definition TSiLi.h:83
void AddCluster(std::vector< unsigned > &, bool=false)
Definition TSiLi.cxx:268
void AddFragment(const std::shared_ptr< const TFragment > &, TChannel *) override
!
Definition TSiLi.cxx:65
TSiLi()
Definition TSiLi.cxx:22
TTransientBits< UChar_t > fSiLiBits
Definition TSiLi.h:122
TSiLi & operator=(const TSiLi &)
Definition TSiLi.cxx:46
Int_t GetRejectMultiplicity()
Definition TSiLi.cxx:131
static Int_t GetRing(Int_t seg)
Definition TSiLi.h:86
static double fSiLiCoincidenceTime
!
Definition TSiLi.h:135
TSiLiHit * GetAddbackHit(const Int_t &i=0)
Definition TSiLi.cxx:109
static double fOffsetPhi
!
Definition TSiLi.h:129
std::vector< TSiLiHit > fAddbackHits
!
Definition TSiLi.h:119
static bool fRejectPossibleCrosstalk
!
Definition TSiLi.h:136
bool fAddbackCriterion(TSiLiHit *, TSiLiHit *)
Definition TSiLi.cxx:224
static double GetSegmentArea(Int_t seg)
Definition TSiLi.cxx:99
static double fInnerDiameter
!
Definition TSiLi.h:131
static double fTargetDistance
!
Definition TSiLi.h:132
static int fSectorNumber
!
Definition TSiLi.h:128
static TVector3 GetPosition(int ring, int sector, bool smear=false)
Definition TSiLi.cxx:76
void SetBit(T bit, Bool_t flag)
Bool_t TestBit(T bit) const