REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestDetectorReadoutModule.cxx
1/*************************************************************************
2 * This file is part of the REST software framework. *
3 * *
4 * Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) *
5 * For more information see http://gifna.unizar.es/trex *
6 * *
7 * REST is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * REST is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have a copy of the GNU General Public License along with *
18 * REST in $REST_PATH/LICENSE. *
19 * If not, see http://www.gnu.org/licenses/. *
20 * For the list of contributors see $REST_PATH/CREDITS. *
21 *************************************************************************/
22
44
45#ifdef __APPLE__
46#include <unistd.h>
47#endif
48
49#include "TRestDetectorReadoutModule.h"
50
51using namespace std;
52
58
63
68 fReadoutChannel.clear();
69 fId = -1;
70
71 fOrigin = {0, 0};
72 fSize = {0, 0};
73
74 fRotation = 0;
75
76 fDaqIdRange = {-1, -1};
77
78 fTolerance = 1.e-3;
79
80 showWarnings = false;
81}
82
87 Int_t maxID = GetChannel(0)->GetDaqID();
88 Int_t minID = GetChannel(0)->GetDaqID();
89 for (size_t ch = 0; ch < this->GetNumberOfChannels(); ch++) {
90 Int_t daqID = GetChannel(ch)->GetDaqID();
91 if (daqID > maxID) {
92 maxID = daqID;
93 }
94 if (daqID < minID) {
95 minID = daqID;
96 }
97 }
98
99 fDaqIdRange = {minID, maxID};
100}
101
109 // We initialize the mapping readout net to sqrt(numberOfPixels)
110 // However this might not be good for readouts where the pixels are
111 // asymmetric
112 // /////////////////////////////////////////////////////////////////////////////
113 Int_t totalNumberOfPixels = 0;
114 for (size_t ch = 0; ch < this->GetNumberOfChannels(); ch++)
115 totalNumberOfPixels += GetChannel(ch)->GetNumberOfPixels();
116
117 if (nodes == 0) {
118 nodes = TMath::Sqrt(totalNumberOfPixels);
119 nodes = 2 * nodes;
120 }
121
122 cout << "Performing readout mapping optimization (This might require long "
123 "computation time)"
124 << endl;
125 cout << "--------------------------------------------------------------------"
126 "--------------"
127 << endl;
128 cout << "Total number of pixels : " << totalNumberOfPixels << endl;
129 cout << "Nodes : " << nodes << endl;
130
131 fMapping.Initialize(nodes, nodes, GetSize().X(), GetSize().Y());
132
133 for (size_t ch = 0; ch < this->GetNumberOfChannels(); ch++) {
134 for (int px = 0; px < this->GetChannel(ch)->GetNumberOfPixels(); px++) {
135 Double_t xPix = this->GetChannel(ch)->GetPixel(px)->GetCenter().X();
136 Double_t yPix = this->GetChannel(ch)->GetPixel(px)->GetCenter().Y();
137
138 Int_t nodeX = fMapping.GetNodeX(xPix);
139 Int_t nodeY = fMapping.GetNodeY(yPix);
140
141 // This means that two pixels in the readout are associated to the same
142 // node.
143 // If the granularity of the readout is not high enough this may happen
144 // often. This should be just a warning I guess.
145 if (showWarnings && fMapping.isNodeSet(nodeX, nodeY)) {
146 cout << endl;
147 cout << "TRestDetectorReadoutModule. WARNING. Node is already SET!!" << endl;
148 cout << "Trying to associate channel : " << ch << " Pixel : " << px << endl;
149 cout << "Pixel coordinates : ( " << xPix << " , " << yPix << " ) " << endl;
150
151 Int_t tempCh = fMapping.GetChannelByNode(nodeX, nodeY);
152 Int_t tempPix = fMapping.GetPixelByNode(nodeX, nodeY);
153 RESTWarning << "Already associated channel : " << tempCh << " pixel : " << tempPix
154 << RESTendl;
155 Double_t xP = this->GetChannel(tempCh)->GetPixel(tempPix)->GetCenter().X();
156 Double_t yP = this->GetChannel(tempCh)->GetPixel(tempPix)->GetCenter().Y();
157 RESTWarning << "Pixel coordinates : ( " << xP << " , " << yP << " ) " << RESTendl;
158 cout << endl;
159
160 cout << "Increasing the number of mapping of nodes may solve this issue." << endl;
161 cout << endl;
162 }
163 fMapping.SetNode(nodeX, nodeY, ch, px);
164 }
165 }
166
167 for (int i = 0; i < nodes; i++) {
168 printf("Completed : %.2lf %%\r", 100. * (i * (Double_t)nodes) / nodes / nodes);
169 fflush(stdout);
170 for (int j = 0; j < nodes; j++) {
171 Double_t x = fMapping.GetX(i);
172 Double_t y = fMapping.GetY(j);
173 const auto transformedCoordinates = TransformToPlaneCoordinates(x, y);
174
175 if (!fMapping.isNodeSet(i, j)) {
176 for (size_t ch = 0; ch < GetNumberOfChannels() && !fMapping.isNodeSet(i, j); ch++) {
177 for (int px = 0; px < GetChannel(ch)->GetNumberOfPixels() && !fMapping.isNodeSet(i, j);
178 px++) {
179 if (isInsidePixel(ch, px, transformedCoordinates)) {
180 fMapping.SetNode(i, j, ch, px);
181 }
182 }
183 }
184 }
185 }
186 }
187
188 if (!fMapping.AllNodesSet())
189 cout << "Not all nodes set" << endl;
190 else
191 cout << "All Nodes set" << endl;
192
193 for (int i = 0; i < nodes; i++)
194 for (int j = 0; j < nodes; j++) {
195 if (!fMapping.isNodeSet(i, j)) {
196 Double_t x = fMapping.GetX(i);
197 Double_t y = fMapping.GetY(j);
198 const auto transformedCoordinates = TransformToPlaneCoordinates(x, y);
199
200 cout << "Node NOT SET : " << i << " , " << j << " Mapping x : " << x << " y : " << y << endl;
201
202 for (size_t ch = 0; ch < GetNumberOfChannels(); ch++) {
203 for (int px = 0; px < GetChannel(ch)->GetNumberOfPixels(); px++) {
204 if (isInsidePixel(ch, px, transformedCoordinates)) {
205 cout << "X : " << transformedCoordinates.X() << " , "
206 << transformedCoordinates.Y() << " Is inside channel : " << ch
207 << " pixel : " << px << endl;
208 }
209 }
210 }
211 }
212 }
213
214 cout << "Nodes not set : " << fMapping.GetNumberOfNodesNotSet() << endl;
215}
216
221 if (daqID >= GetMinDaqID() && daqID <= GetMaxDaqID()) {
222 return true;
223 }
224 return false;
225}
226
234Int_t TRestDetectorReadoutModule::FindChannel(const TVector2& position) {
235 if (!isInside(position)) {
236 return -1;
237 }
238
239 const auto transformedCoordinates = TransformToModuleCoordinates(position);
240 const auto& x = transformedCoordinates.X();
241 const auto& y = transformedCoordinates.Y();
242
243 Int_t nodeX = fMapping.GetNodeX(x);
244 Int_t nodeY = fMapping.GetNodeY(y);
245
246 Int_t channel = fMapping.GetChannelByNode(nodeX, nodeY);
247 Int_t pixel = fMapping.GetPixelByNode(nodeX, nodeY);
248
249 Int_t repeat = 1;
250 Int_t count = 0;
251 Int_t forward = 1;
252 Int_t xAxis = 1;
253
254 Int_t totalNodes = fMapping.GetNumberOfNodesX() * fMapping.GetNumberOfNodesY();
255
256 // We test if x,y is inside the channel/pixel obtained from the readout
257 // mapping If not we start to look in the readout mapping neighbours
258 while (!this->isInsidePixel(channel, pixel, position)) {
259 count++;
260 if (xAxis == 1 && forward == 1)
261 nodeX++;
262 else if (xAxis == 0 && forward == 1)
263 nodeY++;
264 else if (xAxis == 1 && forward == 0)
265 nodeX--;
266 else if (xAxis == 0 && forward == 0)
267 nodeY--;
268
269 Int_t nNodes = fMapping.GetNumberOfNodesX();
270
271 if (nodeX < 0) nodeX = nNodes - 1;
272 if (nodeY < 0) nodeY = nNodes - 1;
273 if (nodeX >= nNodes) nodeX = 0;
274 if (nodeY >= nNodes) nodeY = 0;
275
276 if (count >= repeat) {
277 if (xAxis == 1 && forward == 1) {
278 xAxis = 0;
279 forward = 0;
280 } else if (xAxis == 0 && forward == 0) {
281 xAxis = 1;
282 forward = 0;
283 repeat++;
284 } else if (xAxis == 1 && forward == 0) {
285 xAxis = 0;
286 forward = 1;
287 } else if (xAxis == 0 && forward == 1) {
288 xAxis = 1;
289 forward = 1;
290 repeat++;
291 }
292
293 count = 0;
294 }
295
296 channel = fMapping.GetChannelByNode(nodeX, nodeY);
297 pixel = fMapping.GetPixelByNode(nodeX, nodeY);
298
299 if (count > totalNodes / 10) {
300 RESTWarning << "TRestDetectorReadoutModule. I did not find any channel for hit position (" << x
301 << "," << y << ") in internal module coordinates" << RESTendl;
302
303 for (size_t ch = 0; ch < GetNumberOfChannels(); ch++)
304 for (int px = 0; px < GetChannel(ch)->GetNumberOfPixels(); px++)
305 if (isInsidePixel(ch, px, position)) {
306 cout << "( " << x << " , " << y << ") Should be in channel " << ch
307 << " pixel : " << px << endl;
308
309 cout << "Corresponding node : nX: " << fMapping.GetNodeX_ForChannelAndPixel(ch, px)
310 << " nY : " << fMapping.GetNodeY_ForChannelAndPixel(ch, px) << endl;
311 cout << "Channel : " << ch << " Pixel : " << px << endl;
312 cout << "Pix X : " << GetChannel(ch)->GetPixel(px)->GetCenter().X()
313 << " Pix Y : " << GetChannel(ch)->GetPixel(px)->GetCenter().Y() << endl;
314 }
315 sleep(5);
316 return -1;
317 }
318 }
319
320 return channel;
321}
322
327Bool_t TRestDetectorReadoutModule::isInside(const TVector2& position) {
328 TVector2 positionRotated = TransformToModuleCoordinates(position);
329
330 if (positionRotated.X() >= 0 && positionRotated.X() <= fSize.X() && positionRotated.Y() >= 0 &&
331 positionRotated.Y() <= fSize.Y())
332 return true;
333
334 return false;
335}
336
341Bool_t TRestDetectorReadoutModule::isInsideChannel(Int_t channel, Double_t x, Double_t y) {
342 return isInsideChannel(channel, {x, y});
343}
344
349Bool_t TRestDetectorReadoutModule::isInsideChannel(Int_t channel, const TVector2& position) {
350 TVector2 pos = TransformToModuleCoordinates(position);
351 for (int idx = 0; idx < GetChannel(channel)->GetNumberOfPixels(); idx++)
352 if (GetChannel(channel)->GetPixel(idx)->isInside(pos)) return true;
353 return false;
354}
355
360Bool_t TRestDetectorReadoutModule::isInsidePixel(Int_t channel, Int_t pixel, const TVector2& position) {
361 if (channel < 0 || pixel < 0) return false;
362
363 TVector2 pos = TransformToModuleCoordinates(position);
364 if (GetChannel(channel)->GetPixel(pixel)->isInside(pos)) return true;
365 return false;
366}
367
374TVector2 TRestDetectorReadoutModule::GetDistanceToModule(const TVector2& position) {
375 TVector2 newPos = TransformToModuleCoordinates(position);
376
377 Double_t dx = 0, dy = 0;
378 if (newPos.X() < 0)
379 dx = -newPos.X();
380 else if (fSize.X() - newPos.X() < 0)
381 dx = fSize.X() - newPos.X();
382
383 if (newPos.Y() < 0)
384 dy = -newPos.Y();
385 else if (fSize.Y() - newPos.Y() < 0)
386 dy = fSize.Y() - newPos.Y();
387
388 TVector2 dist = TVector2(dx, dy);
389 return dist;
390}
395TVector2 TRestDetectorReadoutModule::GetPixelOrigin(Int_t channel, Int_t pixel) {
396 return GetPixelVertex(channel, pixel, 0);
397}
398
406TVector2 TRestDetectorReadoutModule::GetPixelVertex(Int_t channel, Int_t pixel, Int_t vertex) {
407 TVector2 pixPosition = GetChannel(channel)->GetPixel(pixel)->GetVertex(vertex);
408
409 pixPosition = pixPosition.Rotate(fRotation);
410 pixPosition = pixPosition + fOrigin;
411 return pixPosition;
412}
413
421TVector2 TRestDetectorReadoutModule::GetPixelCenter(Int_t channel, Int_t pixel) {
422 TVector2 pixCenter = GetChannel(channel)->GetPixel(pixel)->GetCenter();
423
424 pixCenter = pixCenter.Rotate(fRotation);
425 pixCenter = pixCenter + fOrigin;
426 return pixCenter;
427}
428
436Bool_t TRestDetectorReadoutModule::GetPixelTriangle(Int_t channel, Int_t pixel) {
437 Bool_t type = GetChannel(channel)->GetPixel(pixel)->GetTriangle();
438
439 return type;
440}
441
443 return GetPixelVertex(pix, 0);
444}
445
447 TVector2 pixPosition = pix->GetVertex(vertex);
448 pixPosition = pixPosition.Rotate(fRotation);
449 pixPosition = pixPosition + fOrigin;
450 return pixPosition;
451}
452
454 TVector2 corner1(GetPixelVertex(pix, 0));
455 TVector2 corner2(GetPixelVertex(pix, 2));
456 TVector2 center = (corner1 + corner2) / 2.;
457 return center;
458}
459
461 return pix->GetTriangle();
462}
463
472 TVector2 vertex(0, 0);
473 const TVector2& origin = fOrigin;
474
475 if (n % 4 == 0)
476 return origin;
477 else if (n % 4 == 1) {
478 vertex.Set(fSize.X(), 0);
479 vertex = vertex.Rotate(fRotation);
480
481 vertex = vertex + origin;
482 } else if (n % 4 == 2) {
483 vertex.Set(fSize.X(), fSize.Y());
484 vertex = vertex.Rotate(fRotation);
485
486 vertex = vertex + origin;
487 } else if (n % 4 == 3) {
488 vertex.Set(0, fSize.Y());
489 vertex = vertex.Rotate(fRotation);
490
491 vertex = vertex + origin;
492 }
493 return vertex;
494}
495
500 for (int i = 0; i < rChannel.GetNumberOfPixels(); i++) {
501 // TODO we expect here that the user will only do pixel rotations between 0
502 // and 90 degrees, we must force that on pixel definition or fix it here
503 Double_t oX = rChannel.GetPixel(i)->GetVertex(3).X();
504 Double_t oY = rChannel.GetPixel(i)->GetVertex(3).Y();
505 Double_t sX = rChannel.GetPixel(i)->GetVertex(1).X();
506 Double_t sY = rChannel.GetPixel(i)->GetVertex(1).Y();
507
508 if (oX + fTolerance < 0 || oY + fTolerance < 0 || sX - fTolerance > fSize.X() ||
509 sY - fTolerance > fSize.Y()) {
510 if (showWarnings) {
511 cout << "REST Warning (AddChannel) pixel outside the module boundaries" << endl;
512 cout << "Channel: " << fReadoutChannel.size() << ", Pixel : " << i << endl;
513 cout << "Pixel origin = (" << oX << " , " << oY << ")" << endl;
514 cout << "Pixel size = (" << sX << " , " << sY << ")" << endl;
515 cout << "Module size = (" << fSize.X() << " , " << fSize.Y() << ")" << endl;
516 }
517 }
518 }
519
520 fReadoutChannel.push_back(rChannel);
521}
522
527
531void TRestDetectorReadoutModule::Print(Int_t DetailLevel) {
532 if (DetailLevel >= 0) {
533 RESTMetadata << "-- Readout module : " << GetModuleID() << RESTendl;
534 RESTMetadata << "----------------------------------------------------------------" << RESTendl;
535 RESTMetadata << "-- Origin position : X = " << fOrigin.X() << " mm "
536 << " Y : " << fOrigin.Y() << " mm" << RESTendl;
537 RESTMetadata << "-- Size : X = " << fSize.X() << " Y : " << fSize.Y() << RESTendl;
538 RESTMetadata << "-- Rotation : " << fRotation * units("degrees") << " degrees" << RESTendl;
539 RESTMetadata << "-- Total channels : " << GetNumberOfChannels() << RESTendl;
540 RESTMetadata << "-- Tolerance : " << fTolerance << RESTendl;
541 RESTMetadata << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << RESTendl;
542
543 for (size_t n = 0; n < GetNumberOfChannels(); n++) {
544 fReadoutChannel[n].Print(DetailLevel - 1);
545 }
546 }
547}
Int_t GetDaqID() const
Returns the corresponding daq channel id.
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.
void Initialize(Int_t nX, Int_t nY, Double_t sX, Double_t sY)
Resets the matrix values and allocates memory for the given net size.
Int_t GetNodeX(Double_t x)
Gets the nodeX index corresponding to the x coordinate.
Int_t GetNodeX_ForChannelAndPixel(Int_t ch, Int_t px)
Finds the node index in X for a given channel and pixel ids.
Double_t GetX(Int_t nodeX)
Gets the X position of node (i,j)
void SetNode(Int_t i, Int_t j, Int_t ch, Int_t pix)
Sets the readout channel and pixel corresponding to a mapping node.
Bool_t AllNodesSet()
Checks if all the nodes in the net have been defined.
Int_t GetNumberOfNodesNotSet()
Returns the number of nodes that have not been initialized.
Bool_t isNodeSet(Int_t i, Int_t j)
Checks if the node (i,j) is defined.
Int_t GetNodeY(Double_t y)
Gets the nodeY index corresponding to the y coordinate.
Int_t GetPixelByNode(Int_t i, Int_t j)
Gets the pixel id corresponding to a given node (i,j)
Double_t GetY(Int_t nodeY)
Gets the Y position of node (i,j)
Int_t GetNumberOfNodesX() const
Returns the number of nodes in X.
Int_t GetNodeY_ForChannelAndPixel(Int_t ch, Int_t px)
Finds the node index in Y for a given channel and pixel ids.
Int_t GetChannelByNode(Int_t i, Int_t j)
Gets the channel id corresponding to a given node (i,j)
Int_t GetNumberOfNodesY() const
Returns the number of nodes in Y.
TRestDetectorReadoutModule()
Default TRestDetectorReadoutModule constructor.
std::vector< TRestDetectorReadoutChannel > fReadoutChannel
Int_t GetModuleID() const
Returns the module id.
TVector2 TransformToPlaneCoordinates(Double_t xMod, Double_t yMod) const
TVector2 GetPixelCenter(Int_t channel, Int_t pixel)
Returns the center pixel position for a given channel and pixel indexes.
Int_t GetMinDaqID() const
Returns the minimum daq id number.
*default REST_Warning in TRestDetectorReadout will enable it *void Initialize()
TRestDetectorReadoutModule initialization.
TVector2 GetSize() const
Returns the module size (x, y) in mm.
TVector2 fOrigin
The module (x, y) position relative to the readout plane position.
TRestDetectorReadoutChannel * GetChannel(size_t n)
Returns a pointer to a readout channel by index.
TVector2 GetPixelOrigin(Int_t channel, Int_t pixel)
Returns the pixel origin (left-bottom) position for a given channel and pixel indexes.
TVector2 fSize
The module (x, y) size. All pixels should be contained within this size.
Bool_t GetPixelTriangle(Int_t channel, Int_t pixel)
Returns the pixel type for a given channel and pixel indexes.
Int_t FindChannel(const TVector2 &position)
Returns the channel index corresponding to the absolute coordinates (absX, absY), but relative to the...
Bool_t isInsidePixel(Int_t channel, Int_t pixel, const TVector2 &position)
Determines if the position TVector2 pos is found at a specific pixel id inside the readout channel gi...
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.
void AddChannel(TRestDetectorReadoutChannel &rChannel)
Adds a new channel to the module.
Bool_t isInsideChannel(Int_t channel, Double_t x, Double_t y)
Determines if the position x,y is found in any of the pixels of the readout channel index given.
TVector2 GetVertex(int n) const
Returns the coordinates of the specified vertex index n. The physical coordinates relative to the rea...
Bool_t isInside(const TVector2 &position)
Determines if the position TVector2 pos relative to the readout plane are inside this readout module.
Double_t fRotation
The rotation of the module around the module origin (fModuleOriginX, fModuleOriginY) in radians.
TVector2 TransformToModuleCoordinates(const TVector2 &xyPhysical) const
Int_t GetMaxDaqID() const
Returns the maximum daq id number.
TRestDetectorReadoutMapping fMapping
The readout module uniform grid mapping.
void SetMinMaxDaqIDs()
Initializes the max and min values for the daq channel number.
Int_t fId
The module id given by the readout definition.
virtual ~TRestDetectorReadoutModule()
Default TRestDetectorReadoutModule destructor.
void Print(Int_t DetailLevel=0)
Prints the module details and channels if fullDetail is enabled.
size_t GetNumberOfChannels() const
Returns the total number of channels defined inside the module.
Bool_t isDaqIDInside(Int_t daqID)
Determines if a given daqID number is in the range of the module.
void DoReadoutMapping(Int_t nodes=0)
Starts the readout mapping initialization. This process is computationally expensive but it greatly o...
std::pair< Int_t, Int_t > fDaqIdRange
The minimum and maximum daq channel ids associated to the module.
TVector2 GetDistanceToModule(const TVector2 &position)
Creates a TVector2 with shortest norm going from the given position pos to the module....
A class to store the readout pixel definition used in TRestDetectorReadoutChannel.
TVector2 GetCenter() const
Returns the center TVector2 position of the pixel.
Bool_t GetTriangle() const
Returns true if the pixel is a triangle.
Bool_t isInside(TVector2 pos)
Determines if a given TVector2 pos coordinates are found inside the pixel. The coordinates are refere...
TVector2 GetVertex(int n) const
Returns the specified pixel vertex position.