GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TTrific.cxx
Go to the documentation of this file.
1#include <iostream>
2#include "TTrific.h"
3#include "TRandom.h"
4#include "TMath.h"
5
6//declaration of static variables that won't change from event to event
7Int_t TTrific::fGridX = 0;
8Int_t TTrific::fGridY = 0;
9
10//declaration of constant variables
11
12//grid parameters for TRIFIC
13const std::array<double, 12> TTrific::fXmm = {-33, -27, -21, -15, -9, -3, 3, 9, 15, 21, 27, 33}; //mm distance to the middle of each wire set readout from centre of grid
14const std::array<double, 12> TTrific::fYmm = {42, 36, 28, 20, 12, 4, -4, -12, -20, -28, -36, -42};
15
16//angle that grids are offset by (in rads)
17const double TTrific::fAngle = (60. / 180.) * TMath::Pi();
18const TVector3 TTrific::fNormalGridVec = TVector3(0, -TMath::Cos(fAngle), TMath::Sin(fAngle)); //vector that points normal to the grid
19
20//normal to the faces
21//double spacing = 10.0; //mm between each grid
22//double initialSpacing = 20.0; //mm from the window to the first grid
23
24//in cartesian coordinates
25const double TTrific::fSpacingCart = 13.0; //mm
26const double TTrific::fInitialSpacingCart = 28.0; //mm
27double TTrific::fTargetToWindowCart = 700.0; //mm. Non-constant static that represents the target to window distance. Will be different depending on SHARC, TIP, etc
28//can be changed via SetSharc(), SetTip(), SetCustomTargetChamber().
29
30bool TTrific::fSetCoreWave = false;
31
33{
34 Clear();
35}
36
38{
39 rhs.Copy(*this);
40}
41
42void TTrific::Copy(TObject& rhs) const
43{
44 TDetector::Copy(rhs);
45
46 static_cast<TTrific&>(rhs).fXFragments = fXFragments;
47 static_cast<TTrific&>(rhs).fYFragments = fYFragments;
48 static_cast<TTrific&>(rhs).fSingFragments = fSingFragments;
49
50 static_cast<TTrific&>(rhs).fTrificBits = 0;
51}
52
53void TTrific::Print(Option_t*) const
54{
55 // Prints out TTrific members.
56 Print(std::cout);
57}
58
59void TTrific::Print(std::ostream& out) const
60{
61 std::ostringstream str;
62 str << GetMultiplicity() << " hits" << std::endl;
63 str << fXFragments.size() << " xHits" << std::endl;
64 str << fYFragments.size() << " yHits" << std::endl;
65 str << fSingFragments.size() << " singHits" << std::endl;
66 out << str.str();
67}
68
70{
71 rhs.Copy(*this);
72 return *this;
73}
74
75void TTrific::AddFragment(const std::shared_ptr<const TFragment>& frag, TChannel* chan)
76{
77 auto* hit = new TTrificHit(*frag);
78
79 //separate the fragments depending on if they are x, y, or single readout grids.
80 //this is based on the ArraySubPosition value of the hit.
81 switch(chan->GetMnemonic()->ArraySubPosition()) {
83 fXFragments.push_back(hit);
84 break;
86 fYFragments.push_back(hit);
87 break;
88 default:
89 fSingFragments.push_back(hit);
90 break;
91 };
92
93 AddHit(hit);
94}
95
96void TTrific::Clear(Option_t* option)
97{
98
99 TDetector::Clear(option);
100
101 fXFragments.clear(); //!
102 fYFragments.clear(); //!
103 fSingFragments.clear(); //!
104
105 fTrificBits = 0;
106
107 //clear the static event variables
108 //fParticle.SetXYZ(0,0,0); //!
109 //fRange = 0; //!
110}
111
113{
114 //check if we have already found the X grid location yet. If so, we don't need to do it again.
115 if(fGridX == 0) { //if fGridX == 0, then this will trigger indicating that we haven't found the X grid number yet
116 if(!fXFragments.empty()) { //we have to have an x-grid hit in this event to determine the x-grid number
117 TTrificHit* hit = fXFragments.at(0);
118 fGridX = hit->GetDetector();
119 }
120 }
121 //check if we have already found the Y grid location yet. If so, we don't need to do it again.
122 if(fGridY == 0) { //if fGridY == 0, then this will trigger indicating that we haven't found the Y grid number yet
123 if(!fYFragments.empty()) { //we have to have an y-grid hit in this event to determine the y-grid number
124 TTrificHit* hit = fYFragments.at(0);
125 fGridY = hit->GetDetector();
126 }
127 }
128}
129
130TVector3 TTrific::GetPosition(Int_t detectorNumber)
131{
132 //this is called on a TRIFIC hit, and will use the GetPosition() function below to calculate
133 //the x,y,z position of the hit at that grid number
134 //gives outputs in (x,y,z) in cartesian (beam) coordinates
135 // the coordinates (0,0,0) correspond to the centre of the target location, where (presumably) the beam is hitting the target
136
137 //detectorNumber is indexed at 1.
138
139 //TRIFIC only holds 24 detectors, so doesn't make sense to get the position for detectors 25+. Also doesn't make sense to get the position for grid numbers <1.
140 if(24 < detectorNumber || 1 > detectorNumber) { return {1., -1., -1. * abs(detectorNumber)}; }
141 //-1*abs(detNum) ensures we return a value of (-1,-1,-#), which indicates a problem
142
143 TVector3 vec = TTrific::GetPosition();
144
145 //check if TTrific::GetPosition() returned an error vector for bad reconstruction. If so, we don't need to do anything more and can return an error vector
146 if(TVector3(-100, -100, -100) == vec) { return vec; } //this vector should be well outside expected XY coordinates
147
148 double zCart = fTargetToWindowCart + fInitialSpacingCart + fSpacingCart * detectorNumber; //cartesian distance to the grid of choice in the z-direction
149 //this ignores the extra (or lack of) Z due to the tilt of the grids
150 //this includes the target-to-window distance. This can be set via SetSharc() or SetTip() (or via other yet-defined functions)
151
152 zCart += zCart * vec.Y() / (TMath::Sqrt(3) - vec.Y()); //this adds (or subtracts) the extra Z distance (Z') due to the offset in Y (which are tilted at 30 degs. from vertical)
153 //notes on geometry: 30-60-90 triangle, so Y=sqrt(3)*Z', and Y/(Z+Z') = tan(theta)
154
155 return {zCart * vec.X(), zCart * vec.Y(), zCart};
156}
157
159{
160 //Will calculate the x,y,z vector for the TRIFIC event and then return a 3-D vector
161 //that represents the TRIFIC event
162
163 //check if we've already calculated the position for this event. If so, just return it. If not, then reset the position variable.
165 fParticle.SetXYZ(0, 0, 0);
166 //flag that we're going to (try to at least) calculate the position vector for this event
168
169 //Get the grids that are the X and Y grids in this setup
170 GetXYGrid();
171
172 //if we don't have both an x and y grid hit in this event, position reconstruction won't be possible.
173 if(fXFragments.empty() || fYFragments.empty()) {
174 //return an error vector
175 fParticle.SetXYZ(-100, -100, -100);
176 return fParticle;
177 }
178
179 double xMean = 0.0;
180 double xEngTotal = 0.0;
181
182 std::vector<int> hitXDets; //vector to hold the x-segments that have a nonzero hit in them
183
184 for(auto* hit : fXFragments) {
185 Int_t seg = hit->GetSegment();
186
187 if(3 > hit->GetEnergy()) { continue; } //arbitrary threshold to avoid weird E<0 events
188
189 xMean += fXmm[seg] * hit->GetEnergy();
190 xEngTotal += hit->GetEnergy();
191
192 hitXDets.push_back(seg);
193 }
194
195 //check if hitXDets.size() is zero. This happens when we have an x-grid hit or hits, but the energy for all hits is below our arbitrary "noise" threshold.
196 //without this, the function will seg-fault when it tries to check for the continuity
197 if(hitXDets.empty()) {
198 //return an error vector
199 fParticle.SetXYZ(-100, -100, -100);
200 return fParticle;
201 }
202
203 //to check for hit continuity in the grids, we need to sort the vector of segments and then check that every segment
204 //between the first and last segment with a nonzero energy in the array is present. If not, we have a discontinuous hit
205 //and will return an error vector for now. in the future we might instead flag this event
206 //Ex: we want hits that like this: [0,0,4,3,5,6,5,3] not [0,0,5,0,0,2,3,0]
207 //where the index of the example vector is the segment number and the value is the energy
208
209 std::sort(hitXDets.begin(), hitXDets.end());
210
211 for(unsigned int i = 1; i < hitXDets.size(); i++) { //note: this currently just rejects pileup events outright. The class will be modified later to deal with pileup properly
212 if(hitXDets[i] != hitXDets[i - 1] + 1) {
213 fParticle.SetXYZ(-100, -100, -100);
214 return fParticle;
215 }
216 }
217
218 //divide weighted mean by total energy
219 xMean /= xEngTotal;
220
221 //now we do the same for the y-hits
222
223 double yMean = 0.0;
224 double yEngTotal = 0.0;
225
226 std::vector<int> hitYDets; //vector to hold the y-segments that have a nonzero hit in them
227
228 for(auto* hit : fYFragments) {
229 //TDetectorHit *hit = i;
230 Int_t seg = hit->GetSegment();
231
232 if(3 > hit->GetEnergy()) { continue; } //arbitrary threshold to avoid weird E<0 events
233
234 yMean += fYmm[seg] * hit->GetEnergy();
235 yEngTotal += hit->GetEnergy();
236
237 hitYDets.push_back(seg);
238 }
239
240 //check if hitYDets.size() is zero. This happens when we have an y-grid hit or hits, but the energy for all hits is below our arbitrary "noise" threshold.
241 //without this, the function will seg-fault when it tries to check for the continuity
242 if(hitYDets.empty()) {
243 //return an error vector
244 fParticle.SetXYZ(-100, -100, -100);
245 return fParticle;
246 }
247
248 //check again for continuity
249
250 std::sort(hitYDets.begin(), hitYDets.end());
251
252 //this will search through the sorted vector to ensure continuity
253 for(unsigned int i = 1; i < hitYDets.size(); i++) {
254 if(hitYDets[i] != hitYDets[i - 1] + 1) { //again, this rejects pileup events
255 fParticle.SetXYZ(-100, -100, -100);
256 return fParticle;
257 }
258 }
259
260 //divide weighted mean by total energy
261 yMean /= yEngTotal;
262
263 //convert them into cartesion coordinates
264 double yCart = yMean * TMath::Sin(fAngle); //shifts from grid coordinates to XYZ coordinates
265 double zYCart = fTargetToWindowCart + fInitialSpacingCart + fSpacingCart * fGridY + yMean * TMath::Cos(fAngle); //add the initial distance from target to grid, window to the grid, plus the number of gaps between the initial grid and the Y grid, plus the extra z-amount due to the hit location
266 double zXCart = fTargetToWindowCart + fInitialSpacingCart + fSpacingCart * fGridX; //adds the initial distance from target to grid, window to grid, plus gaps until the x grid. No angle dependence since the grids aren't shifted in angle in x-direction
267
268 double tanX = xMean / zXCart; //determine tangent of the angle in the XY plane
269 double tanY = yCart / zYCart; //tan of angle in YZ plane
270
271 //the particle trajectory below is working under the assumption that the beam is centered and hitting the target at exactly (0,0,0)
272 //while this may not be 100% true, the beam should be tuned enough that any deviations from that will be small
273
274 fParticle.SetXYZ(tanX, tanY, 1); //unnormalized "unit" vector of the particle's trajectory.
275 // "X" and "Y" coordinates are the tangent of the angles of the trajectory in the XY and YZ planes, respectively
276 //this is all done relative to the target centre
277
278 //TVector3 particleCart = TVector3(xMean,yCart,1); //this makes the vector in cartesian as opposed to angles.
279
280 //double ratioZX = 1./fNormalGridVec.Dot(fParticle.Unit()); //the Z->R corretion factor
281
282 //fParticle.Print();
283
284 return fParticle;
285}
286
288{
289 //Gets the last grid with an event in it
290 //can't just use the size of fHits because there is no guarantee that every
291 //grid gets an event, plus the XY position grids may have multiplicity>1
292
293 //check if we've already calculated the fRange for this event. If so, return it. If not, we need to reset the range.
295 fRange = 0;
296
297 //first we'll check the single grid fragment, since there are more of them and they extend further
298 for(auto* hit : fSingFragments) {
299 if(hit->GetDetector() > fRange) { fRange = hit->GetDetector(); }
300 }
301 //check if the range is less than the furthest position grid. If so, we need to check that the range isn't at the x or y grid
302 //this was changed because there is no guarantee that the x and y grids will stay at positions 3 and 5, so this is generic
303
304 //determine the x and y grid locations
305 GetXYGrid();
306
307 //check if the range is less than the max of the grid numbers+1. The +1 is because the higher grid number will be at std::max(xGrid,yGrid) by default
308 if(fRange < std::max(fGridX, fGridY) + 1) {
309 if(fRange < fGridX && !fXFragments.empty()) { fRange = fGridX; } //we need to check if the current range is less than the x grid AND that there is an x-grid hit in this event
310 if(fRange < fGridY && !fYFragments.empty()) { fRange = fGridY; } //we need to check if the current range is less than the y grid AND that there is a y-grid hit in this event
311 } //there may be a problem here if fXFragments.size() != 0 (or Y frags too) but all the fragments have E<arb cutoff. However, GetRange() isn't referenced in any other function currently,
312 //and the likelihood of that occuring is very small I think.
313
314 //flag that we've calculated the range for this event
316
317 return fRange;
318}
319
320/*
321TVector2 TTrific::GetEdESimple()
322{
323 //this will calculate a simple E vs dE based only on the energies in the grids at the start and end of trific
324
325 double dE = 0.;
326 double E = 0.;
327
328 for (auto hit: fSingFragments){
329 if (hit->GetEnergy() < 3) continue; //arbitrary threshold to avoid E<0 events.
330 if (hit->GetDetector() < 6){
331 dE += hit->GetEnergy();
332 }
333 else if (hit->GetDetector() > 18 && hit->GetDetector() < 23){
334 E += hit->GetEnergy();
335 }
336 }
337
338 TVector2 EdE;
339 EdE.Set(E,dE);
340
341 return EdE;
342}*/
const TMnemonic * GetMnemonic() const
virtual Int_t GetDetector() const
!
void Copy(TObject &) const override
!
Definition TDetector.cxx:24
virtual Short_t GetMultiplicity() const
Definition TDetector.h:73
void Clear(Option_t *="") override
!
Definition TDetector.h:68
virtual void AddHit(TDetectorHit *hit)
Definition TDetector.h:63
virtual EMnemonic ArraySubPosition() const
Definition TMnemonic.h:62
void SetBit(T bit, Bool_t flag)
Bool_t TestBit(T bit) const
TTransientBits< UShort_t > fTrificBits
Definition TTrific.h:104
void Copy(TObject &) const override
!
Definition TTrific.cxx:42
TTrific()
Definition TTrific.cxx:32
std::vector< TTrificHit * > fXFragments
Definition TTrific.h:100
static Int_t fGridY
Definition TTrific.h:116
Int_t GetRange()
!
Definition TTrific.cxx:287
void Clear(Option_t *="") override
!
Definition TTrific.cxx:96
static const double fAngle
Definition TTrific.h:117
static double fTargetToWindowCart
Definition TTrific.h:95
TVector3 GetPosition()
!
Definition TTrific.cxx:158
static const std::array< double, 12 > fYmm
Definition TTrific.h:14
std::vector< TTrificHit * > fYFragments
Definition TTrific.h:101
static const std::array< double, 12 > fXmm
Definition TTrific.h:13
void AddFragment(const std::shared_ptr< const TFragment > &, TChannel *chan) override
!
Definition TTrific.cxx:75
static Int_t fGridX
Definition TTrific.h:115
std::vector< TTrificHit * > fSingFragments
Definition TTrific.h:102
static bool fSetCoreWave
! Flag for Waveforms ON/OFF
Definition TTrific.h:98
void Print(Option_t *opt="") const override
!
Definition TTrific.cxx:53
Int_t fRange
!
Definition TTrific.h:108
TVector3 fParticle
!
Definition TTrific.h:106
void GetXYGrid()
!
Definition TTrific.cxx:112
static const double fInitialSpacingCart
Definition TTrific.h:94
static const TVector3 fNormalGridVec
Definition TTrific.h:118
static const double fSpacingCart
Definition TTrific.h:93
TTrific & operator=(const TTrific &)
!
Definition TTrific.cxx:69