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