REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestDetectorReadoutPlane.cxx
1
33
34#include "TRestDetectorReadoutPlane.h"
35
36using namespace std;
37
43
48
53 Int_t nChannels = 0;
54 for (size_t md = 0; md < GetNumberOfModules(); md++) {
55 nChannels += fReadoutModules[md].GetNumberOfChannels();
56 }
57 return nChannels;
58}
59
64void TRestDetectorReadoutPlane::SetNormal(const TVector3& normal) {
65 fNormal = normal.Unit();
66 // prevent user from declaring the zero vector as normal
67 if (TMath::Abs(fNormal.Mag2() - 1.0) > 1E-6) {
68 // only the zero vector will have a magnitude different from 1.0 after normalization
69 RESTError << "TRestDetectorReadoutPlane::SetNormal : normal vector cannot be zero." << RESTendl;
70 exit(1);
71 }
72 UpdateAxes();
73}
74
79 if (height < 0) {
80 fHeight = 0;
81 RESTError << "TRestDetectorReadoutPlane::SetHeight : height cannot be negative." << RESTendl;
82 exit(1);
83 } else {
84 fHeight = height;
85 }
86}
87
92 for (size_t md = 0; md < GetNumberOfModules(); md++) {
93 if (fReadoutModules[md].GetModuleID() == modID) return &fReadoutModules[md];
94 }
95
96 cout << "REST ERROR (GetReadoutModuleByID) : Module ID : " << modID << " was not found" << endl;
97 return nullptr;
98}
99
111Double_t TRestDetectorReadoutPlane::GetX(Int_t modID, Int_t chID) {
113
114 TRestDetectorReadoutChannel* rChannel = rModule->GetChannel(chID);
115
116 Double_t x = numeric_limits<Double_t>::quiet_NaN();
117
118 if (rChannel->GetNumberOfPixels() == 1) {
119 Double_t sX = rChannel->GetPixel(0)->GetSize().X();
120 Double_t sY = rChannel->GetPixel(0)->GetSize().Y();
121
122 if (sX > 2 * sY) return x;
123
124 x = rModule->GetPixelCenter(chID, 0).X();
125
126 return x;
127 }
128
129 if (rChannel->GetNumberOfPixels() > 1) {
130 Int_t nPix = rChannel->GetNumberOfPixels();
131
132 // We check the origin of consecutive pixels to check if it goes X or Y
133 // direction. Perhaps more complex readouts need some changes here
134 Double_t x1 = rChannel->GetPixel(0)->GetCenter().X();
135 Double_t x2 = rChannel->GetPixel(nPix - 1)->GetCenter().X();
136
137 Double_t y1 = rChannel->GetPixel(0)->GetCenter().Y();
138 Double_t y2 = rChannel->GetPixel(nPix - 1)->GetCenter().Y();
139
140 /*
141 cout << "Pixel 0. X : " << x1 << " Y : " << y1 endl;
142 cout << "Pixel N. X : " << x2 << " Y : " << y2 endl;
143 */
144
145 Double_t deltaX = abs(x2 - x1);
146 Double_t deltaY = abs(y2 - y1);
147
148 Int_t rotation = (Int_t)(std::round(rModule->GetRotation() * units("degrees")));
149 if (rotation % 90 == 0) {
150 if (rotation / 90 % 2 == 0) // rotation is 0, 180, 360...
151 {
152 if (deltaY > deltaX) x = rModule->GetPixelCenter(chID, 0).X();
153 } else // rotation is 90, 270... We need to invert x and y
154 {
155 if (deltaY < deltaX) x = rModule->GetPixelCenter(chID, 0).X();
156 }
157 } else {
158 // we choose to output x only when deltaY > deltaX under non-90 deg rotation
159 // otherwise it is a y channel and should return nan
160 if (deltaY > deltaX) x = rModule->GetPixelCenter(chID, 0).X();
161 }
162 }
163
164 return x;
165}
166
178Double_t TRestDetectorReadoutPlane::GetY(Int_t modID, Int_t chID) {
180
181 TRestDetectorReadoutChannel* rChannel = rModule->GetChannel(chID);
182
183 Double_t y = numeric_limits<Double_t>::quiet_NaN();
184
185 if (rChannel->GetNumberOfPixels() == 1) {
186 Double_t sX = rChannel->GetPixel(0)->GetSize().X();
187 Double_t sY = rChannel->GetPixel(0)->GetSize().Y();
188
189 if (sY > 2 * sX) return y;
190
191 y = rModule->GetPixelCenter(chID, 0).Y();
192
193 return y;
194 }
195
196 if (rChannel->GetNumberOfPixels() > 1) {
197 Int_t nPix = rChannel->GetNumberOfPixels();
198
199 // We check the origin of consecutive pixels to check if it goes X or Y
200 // direction. Perhaps more complex readouts need some changes here
201 Double_t x1 = rChannel->GetPixel(0)->GetCenter().X();
202 Double_t x2 = rChannel->GetPixel(nPix - 1)->GetCenter().X();
203
204 Double_t y1 = rChannel->GetPixel(0)->GetCenter().Y();
205 Double_t y2 = rChannel->GetPixel(nPix - 1)->GetCenter().Y();
206
207 /*
208 cout << "Pix id : " << rChannel->GetPixel(0)->GetID() << " X1 : " << x1
209 << endl; cout << "Pix id : " << rChannel->GetPixel(1)->GetID() << " X2 :
210 " << x2 << endl; cout << "Pix id : " << rChannel->GetPixel(0)->GetID() <<
211 " Y1 : " << y1 << endl; cout << "Pix id : " <<
212 rChannel->GetPixel(1)->GetID() << " Y2 : " << y2 << endl;
213 */
214
215 Double_t deltaX = abs(x2 - x1);
216 Double_t deltaY = abs(y2 - y1);
217
218 Int_t rotation = (Int_t)std::round(rModule->GetRotation() * units("degrees"));
219 if (rotation % 90 == 0) {
220 if (rotation / 90 % 2 == 0) // rotation is 0, 180, 360...
221 {
222 if (deltaY < deltaX) y = rModule->GetPixelCenter(chID, 0).Y();
223 } else // rotation is 90, 270... We need to invert x and y
224 {
225 if (deltaY > deltaX) y = rModule->GetPixelCenter(chID, 0).Y();
226 }
227 } else {
228 // we choose to output y only when deltaY < deltaX under non-90 deg rotation
229 // otherwise it is a x channel and should return nan
230 if (deltaY < deltaX) y = rModule->GetPixelCenter(chID, 0).Y();
231 }
232 }
233
234 return y;
235}
236
244Int_t TRestDetectorReadoutPlane::FindChannel(Int_t module, const TVector2& position) {
245 const auto relativePosition = position - TVector2{fPosition.X(), fPosition.Y()};
246
247 // TODO : check first if (modX,modY) is inside the module.
248 // If not return error.
249 // FindChannel will take a long time to search for the channel if it is not
250 // there. It will be faster
251
252 return fReadoutModules[module].FindChannel(relativePosition);
253}
254
259Double_t TRestDetectorReadoutPlane::GetDistanceTo(const TVector3& pos) const {
260 return (pos - GetPosition()).Dot(GetNormal());
261}
262
271 TVector3 pos = TVector3(0, 0, z);
272
273 return isZInsideDriftVolume(pos);
274}
275
284 for (size_t m = 0; m < GetNumberOfModules(); m++)
285 if (fReadoutModules[m].isDaqIDInside(daqId)) return true;
286
287 return false;
288}
289
299Int_t TRestDetectorReadoutPlane::isZInsideDriftVolume(const TVector3& position) {
300 TVector3 posNew = TVector3(position.X() - fPosition.X(), position.Y() - fPosition.Y(), position.Z());
301
302 Double_t distance = GetDistanceTo(posNew);
303
304 if (distance > 0 && distance < fHeight) return 1;
305
306 return 0;
307}
308
320Int_t TRestDetectorReadoutPlane::GetModuleIDFromPosition(Double_t x, Double_t y, Double_t z) {
321 TVector3 pos = TVector3(x, y, z);
322
323 return GetModuleIDFromPosition(pos);
324}
337 TVector3 posNew = TVector3(pos.X() - fPosition.X(), pos.Y() - fPosition.Y(), pos.Z());
338
339 Double_t distance = GetDistanceTo(posNew);
340
341 if (distance > 0 && distance < fHeight) {
342 for (size_t m = 0; m < GetNumberOfModules(); m++) {
343 if (fReadoutModules[m].isInside(posNew.X(), posNew.Y())) {
344 return fReadoutModules[m].GetModuleID();
345 }
346 }
347 }
348
349 return -1;
350}
351
356void TRestDetectorReadoutPlane::Print(Int_t DetailLevel) {
357 if (DetailLevel >= 0) {
358 RESTMetadata << "-- Readout plane : " << GetID() << RESTendl;
359 RESTMetadata << "----------------------------------------------------------------" << RESTendl;
360 RESTMetadata << "-- Position : X = " << fPosition.X() << " mm, "
361 << " Y : " << fPosition.Y() << " mm, Z : " << fPosition.Z() << " mm" << RESTendl;
362 RESTMetadata << "-- Normal vector : X = " << fNormal.X() << " mm, "
363 << " Y : " << fNormal.Y() << " mm, Z : " << fNormal.Z() << " mm" << RESTendl;
364 RESTMetadata << "-- X-axis vector : X = " << fAxisX.X() << " mm, "
365 << " Y : " << fAxisX.Y() << " mm, Z : " << fAxisX.Z() << " mm" << RESTendl;
366 RESTMetadata << "-- Y-axis vector : Y = " << fAxisY.X() << " mm, Y : " << fAxisY.Y()
367 << " mm, Z : " << fAxisY.Z() << " mm" << RESTendl;
368 RESTMetadata << "-- Cathode Position : X = " << GetCathodePosition().X() << " mm, "
369 << " Y : " << GetCathodePosition().Y() << " mm, Z : " << GetCathodePosition().Z()
370 << " mm" << RESTendl;
371 RESTMetadata << "-- Height : " << fHeight << " mm" << RESTendl;
372 RESTMetadata << "-- Charge collection : " << fChargeCollection << RESTendl;
373 RESTMetadata << "-- Total modules : " << GetNumberOfModules() << RESTendl;
374 RESTMetadata << "-- Total channels : " << GetNumberOfChannels() << RESTendl;
375 RESTMetadata << "----------------------------------------------------------------" << RESTendl;
376
377 for (size_t i = 0; i < GetNumberOfModules(); i++) {
378 fReadoutModules[i].Print(DetailLevel - 1);
379 }
380 }
381}
382
387
393 Double_t x[4];
394 Double_t y[4];
395
396 double xmin, xmax, ymin, ymax;
397
398 GetBoundaries(xmin, xmax, ymin, ymax);
399
400 TH2Poly* readoutHistogram = new TH2Poly("ReadoutHistogram", "ReadoutHistogram", xmin, xmax, ymin, ymax);
401
402 for (size_t mdID = 0; mdID < this->GetNumberOfModules(); mdID++) {
404
405 int nChannels = module->GetNumberOfChannels();
406
407 for (int ch = 0; ch < nChannels; ch++) {
408 TRestDetectorReadoutChannel* channel = module->GetChannel(ch);
409 Int_t nPixels = channel->GetNumberOfPixels();
410
411 for (int px = 0; px < nPixels; px++) {
412 for (int v = 0; v < 4; v++) {
413 x[v] = module->GetPixelVertex(ch, px, v).X();
414 y[v] = module->GetPixelVertex(ch, px, v).Y();
415 }
416
417 readoutHistogram->AddBin(4, x, y);
418 }
419 }
420 }
421
422 readoutHistogram->SetStats(false);
423
424 return readoutHistogram;
425}
426
430void TRestDetectorReadoutPlane::GetBoundaries(double& xmin, double& xmax, double& ymin, double& ymax) {
431 Double_t x[4];
432 Double_t y[4];
433
434 xmin = 1E9, xmax = -1E9, ymin = 1E9, ymax = -1E9;
435
436 for (size_t mdID = 0; mdID < this->GetNumberOfModules(); mdID++) {
438
439 for (int v = 0; v < 4; v++) {
440 x[v] = module->GetVertex(v).X();
441 y[v] = module->GetVertex(v).Y();
442
443 if (x[v] < xmin) xmin = x[v];
444 if (y[v] < ymin) ymin = y[v];
445 if (x[v] > xmax) xmax = x[v];
446 if (y[v] > ymax) ymax = y[v];
447 }
448 }
449}
450
451void TRestDetectorReadoutPlane::UpdateAxes() { // idempotent
452 const TVector3 zUnit = {0, 0, 1};
453 fAxisX = {1, 0, 0};
454 fAxisY = {0, 1, 0};
455
456 constexpr double tolerance = 1E-6;
457
458 // Check if fNormal is different from (0,0,1)
459 if ((fNormal - zUnit).Mag2() < tolerance) {
460 // do nothing
461 } else if ((fNormal + zUnit).Mag2() < tolerance) {
462 // normal vector is opposite to (0,0,1), we must also flip the axes
463 fAxisX = {0, -1, 0};
464 fAxisY = {-1, 0, 0};
465 } else {
466 // Calculate the rotation axis by taking the cross product between the original normal and fNormal
467 TVector3 rotationAxis = zUnit.Cross(fNormal);
468
469 // Calculate the rotation angle using the dot product between the original normal and fNormal
470 double rotationAngle = acos(zUnit.Dot(fNormal) / (zUnit.Mag() * fNormal.Mag()));
471
472 // Rotate the axes around the rotation axis by the rotation angle
473 fAxisX.Rotate(rotationAngle, rotationAxis);
474 fAxisY.Rotate(rotationAngle, rotationAxis);
475 }
476
477 // rotate around normal by rotation angle (angle in radians)
478 fAxisX.Rotate(fRotation, fNormal);
479 fAxisY.Rotate(fRotation, fNormal);
480
481 // verify that fNormal, fAxisX and fAxisY are orthogonal and unitary
482 if (TMath::Abs(fNormal.Mag2() - 1.0) > tolerance || TMath::Abs(fAxisX.Mag2() - 1.0) > tolerance ||
483 TMath::Abs(fAxisY.Mag2() - 1.0) > tolerance) {
484 RESTError << "TRestDetectorReadoutPlane::UpdateAxes() : "
485 << "The normal vector, the X-axis vector and the Y-axis vector must be unitary."
486 << RESTendl;
487 exit(1);
488 }
489 if (TMath::Abs(fNormal.Dot(fAxisX)) > tolerance || TMath::Abs(fNormal.Dot(fAxisY)) > tolerance ||
490 TMath::Abs(fAxisX.Dot(fAxisY)) > tolerance) {
491 RESTError << "TRestDetectorReadoutPlane::UpdateAxes() : "
492 << "The normal vector, the X-axis vector and the Y-axis vector must be orthogonal."
493 << RESTendl;
494 exit(1);
495 }
496 // verify that the correct order of axes is being used: X cross Y = normal (and not - normal)
497 if ((fAxisX.Cross(fAxisY) - fNormal).Mag2() > tolerance) {
498 RESTError
499 << "TRestDetectorReadoutPlane::UpdateAxes() : "
500 << "The normal vector is not the cross product between the X-axis vector and the Y-axis vector."
501 << RESTendl;
502 exit(1);
503 }
504}
505
506void TRestDetectorReadoutPlane::SetRotation(Double_t radians) {
507 // sets fRotation modulo 2pi
508 fRotation = TVector2::Phi_0_2pi(radians);
509 UpdateAxes();
510}
511
512TVector2 TRestDetectorReadoutPlane::GetPositionInPlane(const TVector3& point) const {
513 // Given a point in space, returns the position of the point in the plane using the plane's axes
514 // The position is returned in the plane's local coordinates (in mm)
515 return {fAxisX.Dot(point - fPosition),
516 fAxisY.Dot(point - fPosition)}; // dot product between vectors is the projection
517}
518
519TVector3 TRestDetectorReadoutPlane::GetPositionInWorld(const TVector2& point, Double_t height) const {
520 return fPosition + point.X() * fAxisX + point.Y() * fAxisY + height * fNormal;
521}
522
523Double_t TRestDetectorReadoutPlane::GetDistanceToPlane(const TVector3& point) const {
524 return (point - fPosition).Dot(fNormal);
525}
526
527void TRestDetectorReadoutPlane::SetAxisX(const TVector3& axis) {
528 const TVector3 axisInPlane = (axis - axis.Dot(fNormal) * fNormal).Unit();
529 if (axisInPlane.Mag2() < 1E-6) {
530 RESTError << "TRestDetectorReadoutPlane::SetAxisX() : "
531 << "The X-axis vector must not be parallel to the normal vector." << RESTendl;
532 exit(1);
533 }
534
535 // compute the angle between the new axis and the old axis
536 const Double_t angle = fAxisX.Angle(axisInPlane);
537
538 SetRotation(fRotation - angle);
539}
Int_t GetNumberOfPixels()
Returns the total number of pixels inside the readout channel.
TRestDetectorReadoutPixel * GetPixel(int n)
Returns a pointer to the pixel n by index.
TVector2 GetPixelCenter(Int_t channel, Int_t pixel)
Returns the center pixel position for a given channel and pixel indexes.
TRestDetectorReadoutChannel * GetChannel(size_t n)
Returns a pointer to a readout channel by index.
Double_t GetRotation() const
Returns the module rotation in degrees.
TVector2 GetPixelVertex(Int_t channel, Int_t pixel, Int_t vertex)
Returns any of the pixel vertex position for a given channel and pixel indexes.
TVector2 GetVertex(int n) const
Returns the coordinates of the specified vertex index n. The physical coordinates relative to the rea...
size_t GetNumberOfChannels() const
Returns the total number of channels defined inside the module.
TVector2 GetCenter() const
Returns the center TVector2 position of the pixel.
TVector2 GetSize()
Returns a TVector2 with the pixel size.
Bool_t isDaqIDInside(Int_t daqId)
This method determines if the daqId given is associated to any of the readout readout channels in any...
Int_t GetNumberOfChannels()
Returns the total number of channels in the readout plane.
Int_t isZInsideDriftVolume(Double_t z)
This method determines if a given position in z is inside the drift volume drifting distance for this...
TRestDetectorReadoutModule * GetModuleByID(Int_t modID)
Returns a pointer to a module using its internal module id.
void SetNormal(const TVector3 &normal)
It updates the value of the normal vector and recalculates the corresponding X and Y axis.
TH2Poly * GetReadoutHistogram()
Creates and returns a TH2Poly object with the readout pixel description.
TVector3 GetNormal() const
Returns a TVector3 with a vector normal to the readout plane.
Double_t fRotation
Rotation (in radians) of the readout plane around the normal vector.
TVector3 GetPosition() const
Returns a TVector3 with the readout plane position.
Double_t fChargeCollection
The fraction of charge/energy this readout plane collects from a hit position.
void Print(Int_t DetailLevel=0)
Prints information with details of the readout plane and modules defined inside the readout plane.
TRestDetectorReadoutPlane()
Default TRestDetectorReadoutPlane constructor.
void Draw()
Draws the readout plane using GetReadoutHistogram.
Double_t GetX(Int_t modID, Int_t chID)
Returns the X coordinate of a given channel in a given module using their internal module and channel...
Double_t GetDistanceTo(const TVector3 &pos) const
Returns the perpendicular distance to the readout plane from a given position pos.
Int_t FindChannel(Int_t module, const TVector2 &position)
Finds the readout channel index for a given module stored in a given module index stored in the reado...
Double_t fHeight
A length in mm that confers a 3rd dimension to the readout plane and defines a volume.
void GetBoundaries(double &xmin, double &xmax, double &ymin, double &ymax)
Finds the xy boundaries of the readout plane delimited by the modules.
Double_t GetY(Int_t modID, Int_t chID)
Returns the Y coordinate of a given channel in a given module using their internal module and channel...
size_t GetNumberOfModules()
Returns the total number of modules in the readout plane.
virtual ~TRestDetectorReadoutPlane()
Default TRestDetectorReadoutPlane destructor.
TVector3 fPosition
The position of the readout plane that defines the origin (0,0) in plane coordinates.
TVector3 GetCathodePosition() const
Returns a TVector3 with the cathode position.
void SetHeight(Double_t d)
Used to define the height of the readout volume with sign crosscheck.
TVector3 fAxisX
A vector contained in the plane that defines the plane X-axis.
TVector3 fAxisY
A vector contained in the plane that defines the plane Y-axis.
TVector3 fNormal
A vector that defines the plane orientation and the side of the active volume.
Int_t GetID() const
Returns an integer with the plane id number.
std::vector< TRestDetectorReadoutModule > fReadoutModules
< A list of TRestDetectorReadoutModule components contained in the readout plane.
Int_t GetModuleIDFromPosition(const TVector3 &position)
This method returns the module id where pos is found. The z-coordinate must be found in between the c...