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