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 <vector>
50 
51 #include "TRestDetectorReadoutModule.h"
52 bool RESTREADOUT_DECODINGFILE_ERROR = false;
53 
54 using namespace std;
55 
61 
66 
71  fReadoutChannel.clear();
72  fId = -1;
73 
74  fOrigin = {0, 0};
75  fSize = {0, 0};
76 
77  fRotation = 0;
78 
79  fDaqIdRange = {-1, -1};
80 
81  fTolerance = 1.e-3;
82 
83  showWarnings = false;
84 
85  fFirstDaqChannel = 0;
86 
87  fMappingNodes = 0;
88 
89  fDecoding = false;
90 
91  fDecodingFile = "";
92 
93  fMappingNodes = 0;
94 }
95 
100  Int_t maxID = GetChannel(0)->GetDaqID();
101  Int_t minID = GetChannel(0)->GetDaqID();
102  for (size_t ch = 0; ch < this->GetNumberOfChannels(); ch++) {
103  Int_t daqID = GetChannel(ch)->GetDaqID();
104  if (daqID > maxID) {
105  maxID = daqID;
106  }
107  if (daqID < minID) {
108  minID = daqID;
109  }
110  }
111 
112  fDaqIdRange = {minID, maxID};
113 }
114 
122  // We initialize the mapping readout net to sqrt(numberOfPixels)
123  // However this might not be good for readouts where the pixels are
124  // asymmetric
125  // /////////////////////////////////////////////////////////////////////////////
126  Int_t totalNumberOfPixels = 0;
127  for (size_t ch = 0; ch < this->GetNumberOfChannels(); ch++)
128  totalNumberOfPixels += GetChannel(ch)->GetNumberOfPixels();
129 
130  if (fMappingNodes == 0) {
131  fMappingNodes = TMath::Sqrt(totalNumberOfPixels);
132  fMappingNodes = 2 * fMappingNodes;
133  }
134 
135  cout << "Performing readout mapping optimization (This might require long "
136  "computation time)"
137  << endl;
138  cout << "--------------------------------------------------------------------"
139  "--------------"
140  << endl;
141  cout << "Total number of pixels : " << totalNumberOfPixels << endl;
142  cout << "Nodes : " << fMappingNodes << endl;
143 
144  fMapping.Initialize(fMappingNodes, fMappingNodes, GetSize().X(), GetSize().Y());
145 
146  for (size_t ch = 0; ch < this->GetNumberOfChannels(); ch++) {
147  for (int px = 0; px < this->GetChannel(ch)->GetNumberOfPixels(); px++) {
148  Double_t xPix = this->GetChannel(ch)->GetPixel(px)->GetCenter().X();
149  Double_t yPix = this->GetChannel(ch)->GetPixel(px)->GetCenter().Y();
150 
151  Int_t nodeX = fMapping.GetNodeX(xPix);
152  Int_t nodeY = fMapping.GetNodeY(yPix);
153 
154  // This means that two pixels in the readout are associated to the same
155  // node.
156  // If the granularity of the readout is not high enough this may happen
157  // often. This should be just a warning I guess.
158  if (showWarnings && fMapping.isNodeSet(nodeX, nodeY)) {
159  cout << endl;
160  cout << "TRestDetectorReadoutModule. WARNING. Node is already SET!!" << endl;
161  cout << "Trying to associate channel : " << ch << " Pixel : " << px << endl;
162  cout << "Pixel coordinates : ( " << xPix << " , " << yPix << " ) " << endl;
163 
164  Int_t tempCh = fMapping.GetChannelByNode(nodeX, nodeY);
165  Int_t tempPix = fMapping.GetPixelByNode(nodeX, nodeY);
166  RESTWarning << "Already associated channel : " << tempCh << " pixel : " << tempPix
167  << RESTendl;
168  Double_t xP = this->GetChannel(tempCh)->GetPixel(tempPix)->GetCenter().X();
169  Double_t yP = this->GetChannel(tempCh)->GetPixel(tempPix)->GetCenter().Y();
170  RESTWarning << "Pixel coordinates : ( " << xP << " , " << yP << " ) " << RESTendl;
171  cout << endl;
172 
173  cout << "Increasing the number of mapping of nodes may solve this issue." << endl;
174  cout << endl;
175  }
176  fMapping.SetNode(nodeX, nodeY, ch, px);
177  }
178  }
179 
180  for (int i = 0; i < fMappingNodes; i++) {
181  printf("Completed : %.2lf %%\r",
182  100. * (i * (Double_t)fMappingNodes) / fMappingNodes / fMappingNodes);
183  fflush(stdout);
184  for (int j = 0; j < fMappingNodes; j++) {
185  Double_t x = fMapping.GetX(i);
186  Double_t y = fMapping.GetY(j);
187  const auto transformedCoordinates = TransformToPlaneCoordinates({x, y});
188 
189  if (!fMapping.isNodeSet(i, j)) {
190  for (size_t ch = 0; ch < GetNumberOfChannels() && !fMapping.isNodeSet(i, j); ch++) {
191  for (int px = 0; px < GetChannel(ch)->GetNumberOfPixels() && !fMapping.isNodeSet(i, j);
192  px++) {
193  if (IsInsidePixel(ch, px, transformedCoordinates)) {
194  fMapping.SetNode(i, j, ch, px);
195  }
196  }
197  }
198  }
199  }
200  }
201 
202  if (!fMapping.AllNodesSet())
203  cout << "Not all nodes set" << endl;
204  else
205  cout << "All Nodes set" << endl;
206 
207  for (int i = 0; i < fMappingNodes; i++)
208  for (int j = 0; j < fMappingNodes; j++) {
209  if (!fMapping.isNodeSet(i, j)) {
210  Double_t x = fMapping.GetX(i);
211  Double_t y = fMapping.GetY(j);
212  const auto transformedCoordinates = TransformToPlaneCoordinates({x, y});
213 
214  cout << "Node NOT SET : " << i << " , " << j << " Mapping x : " << x << " y : " << y << endl;
215 
216  for (size_t ch = 0; ch < GetNumberOfChannels(); ch++) {
217  for (int px = 0; px < GetChannel(ch)->GetNumberOfPixels(); px++) {
218  if (IsInsidePixel(ch, px, transformedCoordinates)) {
219  cout << "X : " << transformedCoordinates.X() << " , "
220  << transformedCoordinates.Y() << " Is inside channel : " << ch
221  << " pixel : " << px << endl;
222  }
223  }
224  }
225  }
226  }
227 
228  cout << "Nodes not set : " << fMapping.GetNumberOfNodesNotSet() << endl;
229 }
230 
234 void TRestDetectorReadoutModule::SetDecodingFile(const std::string& decodingFile) {
235  fDecodingFile = decodingFile;
236 
237  if (fDecodingFile == "Not defined" || fDecodingFile.empty() || RESTREADOUT_DECODINGFILE_ERROR) {
238  fDecoding = false;
239  } else {
240  fDecoding = true;
241  }
242 
243  if (fDecoding && !TRestTools::fileExists(fDecodingFile)) {
244  RESTWarning << "The decoding file does not exist!" << RESTendl;
245  RESTWarning << "--------------------------------" << RESTendl;
246  RESTWarning << "File : " << fDecodingFile << RESTendl;
247  RESTWarning << "Default decoding will be used. readoutChannel=daqChannel" << RESTendl;
248  RESTWarning << "To avoid this message and use the default decoding define : "
249  "decodingFile=\"\""
250  << RESTendl;
251  RESTWarning << "--------------------------------" << RESTendl;
252  RESTWarning << "Press a KEY to continue..." << RESTendl;
253  GetChar();
254  fDecoding = false;
255  RESTREADOUT_DECODINGFILE_ERROR = true;
256  }
257 
258  std::vector<std::pair<Int_t, Int_t>> rdChannel;
259  if (fDecoding && TRestTools::fileExists(fDecodingFile)) {
260  FILE* f = fopen(fDecodingFile.c_str(), "r");
261  Int_t daq, readout;
262  while (!feof(f)) {
263  if (fscanf(f, "%d\t%d\n", &daq, &readout) <= 0) {
264  RESTError << "TRestDetectorReadoutModule::UpdateDecoding. Problem reading decoding"
265  << RESTendl;
266  RESTError << "This error might need support at REST forum" << RESTendl;
267  exit(-1);
268  }
269  // we skip blank daq channels if readout id is <0
270  // e.g. daq id: 22, readout id: -1
271  if (readout >= 0) {
272  rdChannel.push_back(std::make_pair(readout, daq + fFirstDaqChannel));
273  }
274  }
275  fclose(f);
276  }
277 
278  if (fDecoding && (unsigned int)this->GetNumberOfChannels() != rdChannel.size()) {
279  RESTError << "TRestDetectorReadout."
280  << " The number of channels defined in the readout is not the same"
281  << " as the number of channels found in the decoding." << RESTendl;
282  exit(1);
283  }
284 
285  for (size_t ch = 0; ch < this->GetNumberOfChannels(); ch++) {
286  if (!fDecoding) {
287  Int_t id = ch;
288  rdChannel.push_back(std::make_pair(id, id + fFirstDaqChannel));
289  }
290 
291  // WRONG version before -->
292  // fModuleDefinitions[mid].GetChannel(ch)->SetID( rChannel[ch] );
293  const auto& [readout, daq] = rdChannel[ch];
294  if (!this->GetChannel(readout)) {
295  RESTError << "Problem setting readout channel " << readout << " with daq id: " << daq << RESTendl;
296  continue;
297  }
298  this->GetChannel(readout)->SetDaqID(daq);
299  this->GetChannel(readout)->SetChannelID(readout);
300  }
301 
302  this->SetMinMaxDaqIDs();
303 }
304 
309  if (daqID >= GetMinDaqID() && daqID <= GetMaxDaqID()) {
310  return true;
311  }
312  return false;
313 }
314 
322 Int_t TRestDetectorReadoutModule::FindChannel(const TVector2& position) {
323  if (!IsInside(position)) {
324  return -1;
325  }
326 
327  const auto transformedCoordinates = TransformToModuleCoordinates(position);
328  const auto& x = transformedCoordinates.X();
329  const auto& y = transformedCoordinates.Y();
330 
331  Int_t nodeX = fMapping.GetNodeX(x);
332  Int_t nodeY = fMapping.GetNodeY(y);
333 
334  Int_t channel = fMapping.GetChannelByNode(nodeX, nodeY);
335  Int_t pixel = fMapping.GetPixelByNode(nodeX, nodeY);
336 
337  Int_t repeat = 1;
338  Int_t count = 0;
339  Int_t forward = 1;
340  Int_t xAxis = 1;
341 
342  Int_t totalNodes = fMapping.GetNumberOfNodesX() * fMapping.GetNumberOfNodesY();
343 
344  // We test if x,y is inside the channel/pixel obtained from the readout
345  // mapping If not we start to look in the readout mapping neighbours
346  while (!this->IsInsidePixel(channel, pixel, position)) {
347  count++;
348  if (xAxis == 1 && forward == 1)
349  nodeX++;
350  else if (xAxis == 0 && forward == 1)
351  nodeY++;
352  else if (xAxis == 1 && forward == 0)
353  nodeX--;
354  else if (xAxis == 0 && forward == 0)
355  nodeY--;
356 
357  Int_t nNodes = fMapping.GetNumberOfNodesX();
358 
359  if (nodeX < 0) nodeX = nNodes - 1;
360  if (nodeY < 0) nodeY = nNodes - 1;
361  if (nodeX >= nNodes) nodeX = 0;
362  if (nodeY >= nNodes) nodeY = 0;
363 
364  if (count >= repeat) {
365  if (xAxis == 1 && forward == 1) {
366  xAxis = 0;
367  forward = 0;
368  } else if (xAxis == 0 && forward == 0) {
369  xAxis = 1;
370  forward = 0;
371  repeat++;
372  } else if (xAxis == 1 && forward == 0) {
373  xAxis = 0;
374  forward = 1;
375  } else if (xAxis == 0 && forward == 1) {
376  xAxis = 1;
377  forward = 1;
378  repeat++;
379  }
380 
381  count = 0;
382  }
383 
384  channel = fMapping.GetChannelByNode(nodeX, nodeY);
385  pixel = fMapping.GetPixelByNode(nodeX, nodeY);
386 
387  if (count > totalNodes / 10) {
388  RESTWarning << "TRestDetectorReadoutModule. I did not find any channel for hit position (" << x
389  << "," << y << ") in internal module coordinates" << RESTendl;
390 
391  for (size_t ch = 0; ch < GetNumberOfChannels(); ch++)
392  for (int px = 0; px < GetChannel(ch)->GetNumberOfPixels(); px++)
393  if (IsInsidePixel(ch, px, position)) {
394  cout << "( " << x << " , " << y << ") Should be in channel " << ch
395  << " pixel : " << px << endl;
396 
397  cout << "Corresponding node : nX: " << fMapping.GetNodeX_ForChannelAndPixel(ch, px)
398  << " nY : " << fMapping.GetNodeY_ForChannelAndPixel(ch, px) << endl;
399  cout << "Channel : " << ch << " Pixel : " << px << endl;
400  cout << "Pix X : " << GetChannel(ch)->GetPixel(px)->GetCenter().X()
401  << " Pix Y : " << GetChannel(ch)->GetPixel(px)->GetCenter().Y() << endl;
402  }
403  sleep(5);
404  return -1;
405  }
406  }
407 
408  return channel;
409 }
410 
415 Bool_t TRestDetectorReadoutModule::IsInside(const TVector2& position) const {
416  const TVector2 positionRotated = TransformToModuleCoordinates(position);
417 
418  return (positionRotated.X() >= 0 && positionRotated.X() <= fSize.X() && positionRotated.Y() >= 0 &&
419  positionRotated.Y() <= fSize.Y());
420 }
421 
426 Bool_t TRestDetectorReadoutModule::IsInsideChannel(Int_t channel, const TVector2& position) {
427  const TVector2 pos = TransformToModuleCoordinates(position);
428  for (int idx = 0; idx < GetChannel(channel)->GetNumberOfPixels(); idx++) {
429  if (GetChannel(channel)->GetPixel(idx)->IsInside(pos)) {
430  return true;
431  }
432  }
433  return false;
434 }
435 
440 Bool_t TRestDetectorReadoutModule::IsInsidePixel(Int_t channel, Int_t pixel, const TVector2& position) {
441  if (channel < 0 || pixel < 0) {
442  return false;
443  }
444 
445  const TVector2 pos = TransformToModuleCoordinates(position);
446  if (GetChannel(channel)->GetPixel(pixel)->IsInside(pos)) {
447  return true;
448  }
449  return false;
450 }
451 
458 TVector2 TRestDetectorReadoutModule::GetDistanceToModule(const TVector2& position) {
459  TVector2 newPos = TransformToModuleCoordinates(position);
460 
461  Double_t dx = 0, dy = 0;
462  if (newPos.X() < 0) {
463  dx = -newPos.X();
464  } else if (fSize.X() - newPos.X() < 0) {
465  dx = fSize.X() - newPos.X();
466  }
467  if (newPos.Y() < 0) {
468  dy = -newPos.Y();
469  } else if (fSize.Y() - newPos.Y() < 0) {
470  dy = fSize.Y() - newPos.Y();
471  }
472 
473  return {dx, dy};
474 }
479 TVector2 TRestDetectorReadoutModule::GetPixelOrigin(Int_t channel, Int_t pixel) {
480  return GetPixelVertex(channel, pixel, 0);
481 }
482 
490 TVector2 TRestDetectorReadoutModule::GetPixelVertex(Int_t channel, Int_t pixel, Int_t vertex) {
491  TVector2 pixPosition = GetChannel(channel)->GetPixel(pixel)->GetVertex(vertex);
492 
493  pixPosition = pixPosition.Rotate(fRotation);
494  pixPosition = pixPosition + fOrigin;
495  return pixPosition;
496 }
497 
505 TVector2 TRestDetectorReadoutModule::GetPixelCenter(Int_t channel, Int_t pixel) {
506  TVector2 pixCenter = GetChannel(channel)->GetPixel(pixel)->GetCenter();
507 
508  pixCenter = pixCenter.Rotate(fRotation);
509  pixCenter = pixCenter + fOrigin;
510  return pixCenter;
511 }
512 
520 Bool_t TRestDetectorReadoutModule::GetPixelTriangle(Int_t channel, Int_t pixel) {
521  Bool_t type = GetChannel(channel)->GetPixel(pixel)->GetTriangle();
522 
523  return type;
524 }
525 
527  return GetPixelVertex(pix, 0);
528 }
529 
531  TVector2 pixPosition = pix->GetVertex(vertex);
532  pixPosition = pixPosition.Rotate(fRotation);
533  pixPosition = pixPosition + fOrigin;
534  return pixPosition;
535 }
536 
538  TVector2 corner1(GetPixelVertex(pix, 0));
539  TVector2 corner2(GetPixelVertex(pix, 2));
540  TVector2 center = (corner1 + corner2) / 2.;
541  return center;
542 }
543 
545  return pix->GetTriangle();
546 }
547 
556  TVector2 vertex(0, 0);
557  const TVector2& origin = fOrigin;
558 
559  if (n % 4 == 0)
560  return origin;
561  else if (n % 4 == 1) {
562  vertex.Set(fSize.X(), 0);
563  vertex = vertex.Rotate(fRotation);
564 
565  vertex = vertex + origin;
566  } else if (n % 4 == 2) {
567  vertex.Set(fSize.X(), fSize.Y());
568  vertex = vertex.Rotate(fRotation);
569 
570  vertex = vertex + origin;
571  } else if (n % 4 == 3) {
572  vertex.Set(0, fSize.Y());
573  vertex = vertex.Rotate(fRotation);
574 
575  vertex = vertex + origin;
576  }
577  return vertex;
578 }
579 
584  for (int i = 0; i < channel.GetNumberOfPixels(); i++) {
585  // TODO we expect here that the user will only do pixel rotations between 0
586  // and 90 degrees, we must force that on pixel definition or fix it here
587  Double_t oX = channel.GetPixel(i)->GetVertex(3).X();
588  Double_t oY = channel.GetPixel(i)->GetVertex(3).Y();
589  Double_t sX = channel.GetPixel(i)->GetVertex(1).X();
590  Double_t sY = channel.GetPixel(i)->GetVertex(1).Y();
591 
592  if (oX + fTolerance < 0 || oY + fTolerance < 0 || sX - fTolerance > fSize.X() ||
593  sY - fTolerance > fSize.Y()) {
594  if (showWarnings) {
595  cout << "REST Warning (AddChannel) pixel outside the module boundaries" << endl;
596  cout << "Channel: " << fReadoutChannel.size() << ", Pixel : " << i << endl;
597  cout << "Pixel origin = (" << oX << " , " << oY << ")" << endl;
598  cout << "Pixel size = (" << sX << " , " << sY << ")" << endl;
599  cout << "Module size = (" << fSize.X() << " , " << fSize.Y() << ")" << endl;
600  }
601  }
602  }
603 
604  fReadoutChannel.emplace_back(channel);
605  auto& lastChannel = fReadoutChannel.back();
606  // if the channel has no name or type, we set the module name and type
607  if (lastChannel.GetName().empty()) {
608  lastChannel.SetName(fName);
609  }
610  if (lastChannel.GetType().empty()) {
611  lastChannel.SetType(fType);
612  }
613 }
614 
619 
623 void TRestDetectorReadoutModule::Print(Int_t DetailLevel) {
624  if (DetailLevel >= 0) {
625  RESTMetadata << "-- Readout module : " << GetModuleID() << RESTendl;
626  RESTMetadata << "----------------------------------------------------------------" << RESTendl;
627  RESTMetadata << "-- Decoding File: " << fDecodingFile << RESTendl;
628  RESTMetadata << "Decoding was defined : " << (fDecoding ? "Yes" : "No") << RESTendl;
629  RESTMetadata << "-- First DAQ Channel: " << fFirstDaqChannel << RESTendl;
630  RESTMetadata << "-- Number of mapping nodes: " << fMappingNodes << RESTendl;
631  RESTMetadata << "-- Origin position : X = " << fOrigin.X() << " mm "
632  << " Y : " << fOrigin.Y() << " mm" << RESTendl;
633  RESTMetadata << "-- Size : X = " << fSize.X() << " Y : " << fSize.Y() << RESTendl;
634  RESTMetadata << "-- Rotation : " << fRotation * units("degrees") << " degrees" << RESTendl;
635  RESTMetadata << "-- Total channels : " << GetNumberOfChannels() << RESTendl;
636  RESTMetadata << "-- Tolerance : " << fTolerance << RESTendl;
637  RESTMetadata << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << RESTendl;
638 
639  for (size_t n = 0; n < GetNumberOfChannels(); n++) {
640  fReadoutChannel[n].Print(DetailLevel - 1);
641  }
642  }
643 }
TRestDetectorReadoutPixel * GetPixel(int n)
Returns a pointer to the pixel n by index.
Int_t GetNumberOfPixels()
Returns the total number of pixels inside the readout channel.
TRestDetectorReadoutModule()
Default TRestDetectorReadoutModule constructor.
void AddChannel(TRestDetectorReadoutChannel &channel)
Adds a new channel to the module.
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 GetPixelCenter(Int_t channel, Int_t pixel)
Returns the center pixel position for a given channel and pixel indexes.
void Initialize()
TRestDetectorReadoutModule initialization.
void DoReadoutMapping()
Starts the readout mapping initialization. This process is computationally expensive but it greatly o...
void SetDecodingFile(const std::string &decodingFile)
Set the decoding file in the readout module.
TVector2 GetPixelOrigin(Int_t channel, Int_t pixel)
Returns the pixel origin (left-bottom) position for a given channel and pixel indexes.
Bool_t GetPixelTriangle(Int_t channel, Int_t pixel)
Returns the pixel type for a given channel and pixel indexes.
Bool_t IsInside(const TVector2 &position) const
Determines if the position x,y relative to the readout plane are inside this readout module.
Int_t FindChannel(const TVector2 &position)
Returns the channel index corresponding to the absolute coordinates (absX, absY), but relative to the...
Bool_t IsInsideChannel(Int_t channel, const TVector2 &position)
Determines if the position TVector2 pos is found in any of the pixels of the readout channel index 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.
TVector2 GetVertex(int n) const
Returns the coordinates of the specified vertex index n. The physical coordinates relative to the rea...
Bool_t IsDaqIDInside(Int_t daqID)
Determines if a given daqID number is in the range of the module.
void SetMinMaxDaqIDs()
Initializes the max and min values for the daq channel number.
virtual ~TRestDetectorReadoutModule()
Default TRestDetectorReadoutModule destructor.
void Print(Int_t DetailLevel=0)
Prints the module details and channels if fullDetail is enabled.
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.
Bool_t GetTriangle() const
Returns true if the pixel is a triangle.
TVector2 GetVertex(int n) const
Returns the specified pixel vertex position.
static bool fileExists(const std::string &filename)
Returns true if the file (or directory) with path filename exists.
Definition: TRestTools.cxx:728
Int_t GetChar(std::string hint="Press a KEY to continue ...")
Helps to pause the program, printing a message before pausing.