CbmRoot
Loading...
Searching...
No Matches
CbmRichGeoHandler.cxx
Go to the documentation of this file.
1/* Copyright (C) 2015-2025 GSI/JINR-LIT, Darmstadt/Dubna
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Semen Lebedev, Martin Beyer, Adrian Amatus Weber, Andrey Lebedev [committer], Florian Uhlig */
4
13
14#include "CbmRichGeoHandler.h"
15
16#include "CbmRichAddress.h"
17#include "CbmRichDetectorData.h" // for CbmRichPmtData, CbmRichPixelData
18
19#include <Logger.h>
20
21#include <TGeoBBox.h>
22#include <TGeoManager.h>
23#include <TGeoMatrix.h>
24#include <TGeoNode.h>
25#include <TGeoVolume.h>
26#include <TRandom.h>
27
28#include <string>
29#include <tuple>
30
32{
33 // Temporary map storing local x and y coordinates of pixels in its PMT volume
34 std::map<Int_t, std::tuple<Double_t, Double_t>> localPixelCoord{};
35
36 fPixelPathToAddress.clear();
37 fPixelAddressToData.clear();
38 fPixelAddresses.clear();
39
40 fPmtPathToId.clear();
41 fPmtIdToData.clear();
42 fPmtIds.clear();
43
44 Int_t currentPixelAddress{0};
45 Int_t currentPmtId{0};
46
47 // Get MAPMT dimensions
48 Double_t pmtHeight{5.2};
49 Double_t pmtWidth{5.2};
50 TGeoVolume* pmtVolume = gGeoManager->FindVolumeFast("pmt");
51 if (!pmtVolume) pmtVolume = gGeoManager->FindVolumeFast("pmt_vol_0");
52 if (pmtVolume) {
53 auto shape = static_cast<const TGeoBBox*>(pmtVolume->GetShape());
54 if (shape) {
55 pmtHeight = 2. * shape->GetDY();
56 pmtWidth = 2. * shape->GetDX();
57 }
58 }
59
60 const TString pixelNameStr{"pmt_pixel"}; // MAPMT pixel search string
61
62 TGeoIterator geoIterator{gGeoManager->GetTopNode()->GetVolume()};
63 geoIterator.SetTopName("/cave_1");
64 geoIterator.Reset();
65 TGeoNode* curNode{nullptr};
66 while ((curNode = geoIterator())) {
67 if (!TString(curNode->GetVolume()->GetName()).Contains(pixelNameStr)) continue;
68
69 const TGeoMatrix* curMatrix = geoIterator.GetCurrentMatrix();
70 const Double_t* curNodeTr = curMatrix->GetTranslation();
71 const TGeoMatrix* localMatrix = curNode->GetMatrix(); // local transformation of pixel in MAPMT volume
72
73 TString nodePath{};
74 geoIterator.GetPath(nodePath);
75
76 // Check if this is a fallback version < v25
77 // for deriving the pixel address from the node path
78 auto vPos = nodePath.Index("rich_v");
79 if (vPos != TString::kNPOS) {
80 auto versionStr = std::string(nodePath.Data() + vPos + 6, 2);
81 int version = std::stoi(versionStr);
82 fFallback = version < 25;
83 }
84
85 const std::string path = std::string(nodePath.Data());
86 auto pmtInd = path.find_last_of('/');
87 if (std::string::npos == pmtInd) continue;
88 std::string pmtPath = path.substr(0, pmtInd + 1);
89
90 // Derive pixel address and pmt Id from node path
91 auto setup = GetDetectorSetup(nodePath);
92 switch (setup) {
93 case CbmRichGeoSetup::Rich: // RICH detector
94 if (fFallback) {
95 currentPixelAddress++;
96 break;
97 }
98 if (CreateAddressRich(path, currentPixelAddress, currentPmtId)) {
99 LOG(error) << "CbmRichGeoHandler::Init: CbmRichGeoHandler::CreateAddressRich failed!";
100 }
101 break;
102 case CbmRichGeoSetup::MiniRich: // mRICH detector
103 if (CreateAddressMiniRich(path, currentPixelAddress, currentPmtId)) {
104 LOG(error) << "CbmRichGeoHandler::Init: CbmRichGeoHandler::CreateAddressMiniRich failed!";
105 continue;
106 }
107 break;
108 default: LOG(error) << "ERROR: Could not identify Detector setup!"; break;
109 }
110
111 // Create mappings, PixelData and PmtData
112 fPixelPathToAddress.insert(std::pair<std::string, Int_t>(path, currentPixelAddress));
113 auto pixelData = std::make_unique<CbmRichPixelData>();
114 pixelData->fX = curNodeTr[0];
115 pixelData->fY = curNodeTr[1];
116 pixelData->fZ = curNodeTr[2];
117 pixelData->fAddress = currentPixelAddress;
118 localPixelCoord[currentPixelAddress] =
119 std::make_tuple(localMatrix->GetTranslation()[0], localMatrix->GetTranslation()[1]);
120 fPixelAddresses.push_back(currentPixelAddress);
121
122 if (fPmtPathToId.count(pmtPath) == 0) {
123 if (fFallback && setup == CbmRichGeoSetup::Rich) currentPmtId++;
124 fPmtPathToId.insert(std::pair<std::string, Int_t>(pmtPath, currentPmtId));
125 auto pmtData = std::make_unique<CbmRichPmtData>();
126 pmtData->fId = currentPmtId;
127 pmtData->fPixelAddresses.push_back(pixelData->fAddress);
128 pmtData->fHeight = pmtHeight;
129 pmtData->fWidth = pmtWidth;
130 pixelData->fPmtId = pmtData->fId;
131
132 fPmtIds.push_back(pmtData->fId);
133 fPmtIdToData.insert(std::make_pair(pmtData->fId, std::move(pmtData)));
134 }
135 else {
136 Int_t pmtId = fPmtPathToId[pmtPath];
137 auto pmtData = fPmtIdToData[pmtId].get();
138 if (!pmtData || pmtId != pmtData->fId) LOG(error) << "(!pmtData || pmtId != pmtData->fId) ";
139 pmtData->fPixelAddresses.push_back(pixelData->fAddress);
140 pixelData->fPmtId = pmtData->fId;
141 if (pmtData->fPixelAddresses.size() > 64) {
142 LOG(info) << "size:" << pmtData->fPixelAddresses.size() << " pmtData->fId:" << pmtData->fId
143 << " pmtPath:" << pmtPath << std::endl
144 << " path:" << path;
145 }
146 }
147
148 fPixelAddressToData.insert(std::make_pair(pixelData->fAddress, std::move(pixelData)));
149 }
150
151 // Calculate Pmt center as center of gravity of 64 pixels
152 for (const auto& pmt : fPmtIdToData) {
153 auto pmtData = pmt.second.get();
154 pmtData->fX = 0.;
155 pmtData->fY = 0.;
156 pmtData->fZ = 0.;
157 for (int pixelId : pmtData->fPixelAddresses) {
158 auto pixelData = fPixelAddressToData[pixelId].get();
159 if (!pixelData) continue;
160 pmtData->fX += pixelData->fX;
161 pmtData->fY += pixelData->fY;
162 pmtData->fZ += pixelData->fZ;
163 }
164 Double_t nPixels = static_cast<Double_t>(pmtData->fPixelAddresses.size());
165 pmtData->fX /= nPixels;
166 pmtData->fY /= nPixels;
167 pmtData->fZ /= nPixels;
168 }
169
170 // Calculate CbmRichPixelData.fPixelId for each pixel by sorting x and y translation inside PMT volume
171 for (const auto& pmt : fPmtIdToData) {
172 auto pmtData = pmt.second.get();
173 std::vector<std::tuple<CbmRichPixelData*, Double_t, Double_t>> pixelsInPmt{};
174 for (int pixelAddress : pmtData->fPixelAddresses) {
175 auto pixelData = fPixelAddressToData[pixelAddress].get();
176 if (!pixelData) continue;
177 pixelsInPmt.emplace_back(std::make_tuple(pixelData, std::get<0>(localPixelCoord[pixelAddress]),
178 std::get<1>(localPixelCoord[pixelAddress])));
179 }
180
181 std::sort(
182 pixelsInPmt.begin(), pixelsInPmt.end(),
183 [](std::tuple<CbmRichPixelData*, Double_t, Double_t> a, std::tuple<CbmRichPixelData*, Double_t, Double_t> b) {
184 return (std::get<2>(a) > std::get<2>(b))
185 || ((std::abs(std::get<2>(a) - std::get<2>(b)) <= 0.3) && (std::get<1>(a) < std::get<1>(b)));
186 // First sort by y (up to down) coordinate, then by x (left to right) coordinate
187 // stop sorting by y when y coordinate difference is less than 0.3 (to start sorting by x when y is the "same")
188 // needed because edge/corner pixels are slightly larger
189 });
190
191 if (pixelsInPmt.size() != 64) {
192 LOG(error) << "ERROR: Calculating local pixel indices failed, number of pixels in PMT is not 64. "
193 << pmtData->ToString();
194 }
195 for (std::size_t i = 0; i < pixelsInPmt.size(); i++) {
196 std::get<0>(pixelsInPmt[i])->fPixelId = static_cast<Int_t>(i);
197 }
198 }
199
200 localPixelCoord.clear();
201
202 LOG(info) << "CbmRichGeoHandler is initialized";
203 LOG(info) << "fPixelPathToAddress.size() = " << fPixelPathToAddress.size();
204 LOG(info) << "fPixelAddressToData.size() = " << fPixelAddressToData.size();
205
206 LOG(info) << "fPmtPathToId.size() = " << fPmtPathToId.size();
207 LOG(info) << "fPmtIdToData.size() = " << fPmtIdToData.size();
208}
209
211{
212 return fPixelPathToAddress.count(path) ? fPixelPathToAddress[path] : -1;
213}
214
216{
217 if (fPixelAddressToData.count(address) == 0) {
218 LOG(fatal) << "CbmRichGeoHandler::GetPixelDataByAddress: Pixel with address " << address << " not found.";
219 return nullptr;
220 }
221 return fPixelAddressToData[address].get();
222}
223
225
227{
228 return fPmtIdToData.count(id) ? fPmtIdToData[id].get() : nullptr;
229}
230
231std::vector<Int_t> CbmRichGeoHandler::GetNeighbourPixels(Int_t address, Int_t n, Bool_t horizontal, Bool_t vertical,
232 Bool_t diagonal)
233{
234 std::vector<Int_t> neighbourPixels{};
235 if (n == 0) return neighbourPixels;
236 CbmRichPixelData* addressPixelData = GetPixelDataByAddress(address);
237 Int_t indX = addressPixelData->fPixelId % 8;
238 Int_t indY = addressPixelData->fPixelId / 8;
239 std::vector<Int_t> pmtPixelAddresses = GetPmtDataById(addressPixelData->fPmtId)->fPixelAddresses;
240 for (const auto& iAddr : pmtPixelAddresses) {
241 if (iAddr == address) continue;
242 CbmRichPixelData* iPixelData = GetPixelDataByAddress(iAddr);
243 Int_t iIndX = iPixelData->fPixelId % 8;
244 Int_t iIndY = iPixelData->fPixelId / 8;
245 if (horizontal && !vertical && !diagonal && n == 1) { // direct horizontal neighbours
246 if (abs(iIndX - indX) == 1 && abs(iIndY - indY) == 0) neighbourPixels.push_back(iAddr);
247 }
248 else if (vertical && !horizontal && !diagonal && n == 1) { // direct vertical neighbours
249 if (abs(iIndX - indX) == 0 && abs(iIndY - indY) == 1) neighbourPixels.push_back(iAddr);
250 }
251 else if (!horizontal && !vertical && diagonal && n == 1) { // diagonal neighbours
252 if ((abs(iIndX - indX) == 1) && (abs(iIndY - indY) == 1)) neighbourPixels.push_back(iAddr);
253 }
254 else if (horizontal && vertical && !diagonal && n == 1) { // direct horizontal and vertical neighbours
255 if ((abs(iIndX - indX) + abs(iIndY - indY)) == 1) neighbourPixels.push_back(iAddr);
256 }
257 else if (horizontal && vertical && diagonal) { // all neighbours in (2N+1)*(2N+1) grid
258 if ((abs(iIndX - indX) <= n) && (abs(iIndY - indY) <= n)) neighbourPixels.push_back(iAddr);
259 }
260 else {
261 LOG(error) << "ERROR: Unrecogniced option in CbmRichGeoHandler::GetNeighbourPixels " << std::endl
262 << " n = " << n << " horizontal = " << horizontal << " vertical = " << vertical
263 << " diagonal = " << diagonal;
264 }
265 }
266 return neighbourPixels;
267}
268
269Int_t CbmRichGeoHandler::CreateAddressRich(const std::string& nodePath, Int_t& channelAddr, Int_t& pmtId)
270{
271 // Example path for RICH v25
272 // /cave_1/rich_v25a_0/rich_cont_1/rich_gas_1/camera_cont_1/camera_strip_1/camera_module_7/pmt_1/pmt_pixel_corner_1
273 // Indexing starts from 1 in geo paths, decrease by 1 for creating the RichAddress
274
275 auto pmtPixelInd = nodePath.find_last_of('/');
276 if (std::string::npos == pmtPixelInd) return 1;
277
278 // "/pmt_pixel_*_[1-64]" -> Pixel number [0, 63]
279 auto pixelUnderscore = nodePath.find_last_of('_');
280 if (std::string::npos == pixelUnderscore) return 1;
281 uint32_t pixelId = std::stoul(nodePath.substr(pixelUnderscore + 1)) - 1;
282
283 // "/pmt_[1-6]" -> Pmt number [0, 5] in backplane
284 auto pmtContInd = nodePath.rfind('/', pmtPixelInd - 1);
285 uint32_t pmt = std::stoul(nodePath.substr(pmtContInd + 5, pmtPixelInd - pmtContInd - 5)) - 1;
286 if (std::string::npos == pmtContInd) return 1;
287
288 // "/camera_module_[1-7]" -> Backplane number [0, 6]
289 auto backplaneInd = nodePath.rfind('/', pmtContInd - 1);
290 uint32_t backplane = std::stoul(nodePath.substr(backplaneInd + 15, pmtContInd - backplaneInd - 15)) - 1;
291 if (std::string::npos == backplaneInd) return 1;
292
293 // "/camera_strip_[1-14]" -> Strip number [0, 13]
294 auto stripInd = nodePath.rfind('/', backplaneInd - 1);
295 uint32_t strip = std::stoul(nodePath.substr(stripInd + 14, backplaneInd - stripInd - 14)) - 1;
296 if (std::string::npos == stripInd) return 1;
297
298 // "/camera_cont_[1-2]" -> Camera number [0: upper, 1: lower camera]
299 auto cameraInd = nodePath.rfind('/', stripInd - 1);
300 uint32_t camera = std::stoul(nodePath.substr(cameraInd + 13, stripInd - cameraInd - 13)) - 1;
301 if (std::string::npos == cameraInd) return 1;
302
303 channelAddr = CbmRichAddress::GetAddress(camera, strip, backplane, pmt, pixelId);
304 pmtId = CbmRichAddress::GetMotherAddress(channelAddr, 4);
305
306 return 0;
307}
308
309Int_t CbmRichGeoHandler::CreateAddressMiniRich(const std::string& nodePath, Int_t& channelAddr, Int_t& pmtId)
310{
311 auto pmtInd = nodePath.find_last_of('/');
312 if (std::string::npos == pmtInd) return 1;
313
314 Int_t channel = static_cast<Int_t>(std::stoul(nodePath.substr(pmtInd + 11))); // cut away "pmt_pixel_"
315 Int_t posAtPmt = channel / 100;
316 channel = channel % 100;
317
318 auto pmtVolInd = nodePath.rfind('/', pmtInd - 1);
319 if (std::string::npos == pmtVolInd) return 1;
320 Int_t pmtPosBP = static_cast<Int_t>(
321 std::stoul(nodePath.substr(pmtVolInd + 11,
322 pmtInd - pmtVolInd - 11))); // cut away "/pmt_vol_*_" ; position on BP
323
324 auto bpInd = nodePath.rfind('/', pmtVolInd - 1);
325 if (std::string::npos == bpInd) return 1;
326 Int_t posBP = static_cast<Int_t>(
327 std::stoul(nodePath.substr(bpInd + 14,
328 pmtVolInd - bpInd - 14))); // cut away "/pmt_cont_vol_" ; position on BP
329
330 Int_t x = (posBP / 10) + ((((pmtPosBP - 1) / 3) + 1) % 2);
331 Int_t y = (posBP % 10) + (2 - ((pmtPosBP - 1) % 3));
332
333 Int_t DiRICH_Add = ((7 & 0xF) << 12) + ((x & 0xF) << 8) + ((y & 0xF) << 4) + (posAtPmt & 0xF);
334 Int_t pixelUID = ((DiRICH_Add << 16) | (channel & 0x00FF));
335 Int_t pmtUID = ((x & 0xF) << 4) + (y & 0xF);
336
337 channelAddr = pixelUID;
338 pmtId = pmtUID;
339
340 return 0;
341}
int Int_t
bool Bool_t
Int_t CreateAddressRich(const std::string &nodePath, Int_t &channelAddr, Int_t &pmtId)
Create channel address & pmt Id from node path for RICH.
std::vector< Int_t > fPmtIds
CbmRichGeoSetup GetDetectorSetup(const TString &nodePath)
Identify detector setup (RICH or mRICH) by node path.
CbmRichPmtData * GetPmtDataById(Int_t id)
Int_t CreateAddressMiniRich(const std::string &nodePath, Int_t &channelAddr, Int_t &pmtId)
Create channel address & pmt Id from node path for mRICH.
std::vector< Int_t > GetNeighbourPixels(Int_t address, Int_t N, Bool_t horizontal=true, Bool_t vertical=true, Bool_t diagonal=true)
Return the addresses of the neighbour pixels.
Int_t GetPixelAddressByPath(const std::string &path)
void Init()
Initialize maps.
CbmRichPixelData * GetPixelDataByAddress(Int_t address)
std::vector< Int_t > fPixelAddresses
std::map< Int_t, std::unique_ptr< CbmRichPmtData > > fPmtIdToData
std::map< std::string, Int_t > fPmtPathToId
std::map< std::string, Int_t > fPixelPathToAddress
std::map< Int_t, std::unique_ptr< CbmRichPixelData > > fPixelAddressToData
std::vector< Int_t > fPixelAddresses
int32_t GetMotherAddress(int32_t address, int32_t level)
Construct the address of an element from the address of a descendant element.
int32_t GetAddress(uint32_t camera=0, uint32_t strip=0, uint32_t backplane=0, uint32_t pmt=0, uint32_t pixel=0, uint32_t version=kCurrentVersion)
Construct address.