Project
Loading...
Searching...
No Matches
MatLayerCylSet.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
13
16
17#ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version
18#include "GPUCommonLogger.h"
19#include <TFile.h>
20#include <TGeoManager.h>
22#include <tbb/blocked_range.h>
23#include <tbb/enumerable_thread_specific.h>
24#include <tbb/global_control.h>
25#include <tbb/parallel_for.h>
26#include <algorithm>
27#include <chrono>
28#include <cstdlib>
29#include <vector>
30//#define _DBG_LOC_ // for local debugging only
31
32#endif // !GPUCA_ALIGPUCODE
33#undef NDEBUG
34using namespace o2::base;
35
37
38#ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version
39
40//________________________________________________________________________________
41void MatLayerCylSet::addLayer(float rmin, float rmax, float zmax, float dz, float drphi)
42{
43 // add new layer checking for overlaps
45 assert(rmin < rmax && zmax > 0 && dz > 0 && drphi > 0);
47 int nlr = getNLayers();
48 if (!nlr) {
49 // book local storage
50 auto sz = sizeof(MatLayerCylSetLayout);
53 mFlatBufferSize = sz;
54 //--------------????
55 get()->mRMin = 1.e99;
56 get()->mRMax = 0.;
57 }
58
59 for (int il = 0; il < nlr; il++) {
60 const auto& lr = getLayer(il);
61 if (lr.getRMax() > rmin && rmax > lr.getRMin()) {
62 LOG(fatal) << "new layer overlaps with layer " << il;
63 }
64 }
65 auto* oldLayers = o2::gpu::FlatObject::resizeArray(get()->mLayers, nlr, nlr + 1);
66 // dynamyc buffers of old layers were used in new ones, detach them
67 for (int i = nlr; i--;) {
68 oldLayers[i].clearInternalBufferPtr();
69 }
70 delete[] oldLayers;
71 get()->mLayers[nlr].initSegmentation(rmin, rmax, zmax, dz, drphi);
72 get()->mNLayers++;
73 get()->mRMin = get()->mRMin > rmin ? rmin : get()->mRMin;
74 get()->mRMax = get()->mRMax < rmax ? rmax : get()->mRMax;
75 get()->mZMax = get()->mZMax < zmax ? zmax : get()->mZMax;
76 get()->mRMin2 = get()->mRMin * get()->mRMin;
77 get()->mRMax2 = get()->mRMax * get()->mRMax;
78}
79
80//________________________________________________________________________________
82{
84 const char* env = std::getenv("NTHREADS_MATBUD");
85 if (!env) {
86 return 1;
87 }
88 int n = std::atoi(env);
89 if (n < 1) {
90 LOG(warning) << "Ignoring invalid NTHREADS_MATBUD=" << env;
91 return 1;
92 }
93 return n;
94}
95
96//________________________________________________________________________________
97void MatLayerCylSet::populateFromTGeo(int ntrPerCell, int nThreads)
98{
101 assert(mConstructionMask == InProgress);
102
103 int nlr = getNLayers();
104 if (!nlr) {
105 LOG(error) << "The LUT is not yet initialized";
106 return;
107 }
108 if (get()->mR2Intervals) {
109 LOG(error) << "The LUT is already populated";
110 return;
111 }
112
113 if (nThreads < 0) {
114 nThreads = getNThreadsFromEnv();
115 }
116
117 using Clock = std::chrono::steady_clock;
118 auto seconds = [](Clock::time_point a, Clock::time_point b) {
119 return std::chrono::duration<double>(b - a).count();
120 };
121
122 if (nThreads <= 1) {
123 for (int i = 0; i < nlr; i++) {
124 LOG(info) << "Populating with " << ntrPerCell << " trials Lr " << i;
125 get()->mLayers[i].print();
126 }
127 const auto tFillStart = Clock::now();
128 for (int i = 0; i < nlr; i++) {
129 get()->mLayers[i].populateFromTGeo(ntrPerCell);
130 }
131 const auto tFillEnd = Clock::now();
133 LOG(info) << "LUT fill: 1 thread, cells " << seconds(tFillStart, tFillEnd) << " s";
134 return;
135 }
136
137 // Cells of all layers form one flat index range so that the load is balanced across
138 // threads even though layers differ a lot in cell count. layerOffsets[i] is the first
139 // flat index of layer i; a binary search maps a flat index back to (layer, iz, iphi).
140 std::vector<size_t> layerOffsets(nlr + 1, 0);
141 for (int i = 0; i < nlr; i++) {
142 LOG(info) << "Queuing " << ntrPerCell << " trials Lr " << i;
143 get()->mLayers[i].print();
144 const auto& lr = get()->mLayers[i];
145 layerOffsets[i + 1] = layerOffsets[i] + size_t(lr.getNZBins()) * lr.getNPhiBins();
146 }
147 const size_t totalCells = layerOffsets[nlr];
148
149 const auto tSetupStart = Clock::now();
150
151 // TGeo has to be told that several threads will navigate it, and each thread needs its own
152 // navigator. SetMaxThreads() is one-way -- TGeoManager has no API to return to
153 // single-threaded mode -- so we do not pretend to restore it; that is harmless because
154 // meanMaterialBudget() decides whether to lock from its own argument, not from this global.
155 // The navigators we book are ours, though, so those we do give back.
156 gGeoManager->SetMaxThreads(nThreads);
157
158 tbb::enumerable_thread_specific<TGeoNavigator*> threadNavigators(
159 []() { return gGeoManager->AddNavigator(); });
160
161 const auto tFillStart = Clock::now();
162 {
163 tbb::global_control threadControl(tbb::global_control::max_allowed_parallelism, nThreads);
164 tbb::parallel_for(tbb::blocked_range<size_t>(0, totalCells),
165 [this, ntrPerCell, &layerOffsets, &threadNavigators](const tbb::blocked_range<size_t>& range) {
166 TGeoNavigator* nav = threadNavigators.local();
167 for (size_t idx = range.begin(); idx != range.end(); ++idx) {
168 auto it = std::upper_bound(layerOffsets.begin(), layerOffsets.end(), idx);
169 const int layerIdx = int(std::distance(layerOffsets.begin(), it)) - 1;
170 const size_t cellInLayer = idx - layerOffsets[layerIdx];
171 auto& layer = this->get()->mLayers[layerIdx];
172 const int nphi = layer.getNPhiBins();
173 layer.populateFromTGeo(int(cellInLayer % nphi), int(cellInLayer / nphi), ntrPerCell, nav);
174 }
175 });
176 }
177
178 const auto tFillEnd = Clock::now();
179
180 for (TGeoNavigator* nav : threadNavigators) {
181 gGeoManager->RemoveNavigator(nav);
182 }
183
185 const auto tEnd = Clock::now();
186
187 // Reported separately because only the middle term scales: the setup walks every volume
188 // in the geometry (TGeoManager::SetMaxThreads) and the teardown is serial by nature.
189 LOG(info) << "LUT fill: " << nThreads << " threads, setup " << seconds(tSetupStart, tFillStart)
190 << " s, cells " << seconds(tFillStart, tFillEnd)
191 << " s, finalize " << seconds(tFillEnd, tEnd) << " s";
192}
193
194//________________________________________________________________________________
196{
197 // build layer search structures
198 assert(mConstructionMask == InProgress);
199 int nlr = getNLayers();
200 int nR2Int = 2 * (nlr + 1);
201 o2::gpu::FlatObject::resizeArray(get()->mR2Intervals, 0, nR2Int);
202 o2::gpu::FlatObject::resizeArray(get()->mInterval2LrID, 0, nR2Int);
203 get()->mR2Intervals[0] = get()->mRMin2;
204 get()->mR2Intervals[1] = get()->mRMax2;
205 get()->mInterval2LrID[0] = 0;
206 auto& nRIntervals = get()->mNRIntervals;
207 nRIntervals = 1;
208
209 for (int i = 1; i < nlr; i++) {
210 const auto& lr = getLayer(i);
211 if (o2::math_utils::sqrt(lr.getRMin2()) > o2::math_utils::sqrt(get()->mR2Intervals[nRIntervals] + Ray::Tiny)) {
212 // register gap
213 get()->mInterval2LrID[nRIntervals] = -1;
214 get()->mR2Intervals[++nRIntervals] = lr.getRMin2();
215 }
216 get()->mInterval2LrID[nRIntervals] = i;
217 get()->mR2Intervals[++nRIntervals] = lr.getRMax2();
218 }
219 delete[] o2::gpu::FlatObject::resizeArray(get()->mInterval2LrID, nR2Int, nRIntervals); // rebook with precise size
220 delete[] o2::gpu::FlatObject::resizeArray(get()->mR2Intervals, nR2Int, ++nRIntervals); // rebook with precise size
221 //
222}
223
224//________________________________________________________________________________
225void MatLayerCylSet::dumpToTree(const std::string& outName) const
226{
228
229 o2::utils::TreeStreamRedirector dump(outName.data(), "recreate");
230 for (int i = 0; i < getNLayers(); i++) {
231 const auto& lr = getLayer(i);
232 float r = 0.5 * (lr.getRMin() + lr.getRMax());
233 // per cell dump
234 int nphib = lr.getNPhiBins();
235 for (int ip = 0; ip < nphib; ip++) {
236 float phi = 0.5 * (lr.getPhiBinMin(ip) + lr.getPhiBinMax(ip));
237 float sn, cs;
238 int ips = lr.phiBin2Slice(ip);
239 char merge = 0; // not mergeable
240 if (ip + 1 < nphib) {
241 int ips1 = lr.phiBin2Slice(ip + 1);
242 merge = ips == ips1 ? -1 : lr.canMergePhiSlices(ips, ips1); // -1 for already merged
243 } else {
244 merge = -2; // last one
245 }
246 o2::math_utils::sincos(phi, sn, cs);
247 float x = r * cs, y = r * sn;
248 for (int iz = 0; iz < lr.getNZBins(); iz++) {
249 float z = 0.5 * (lr.getZBinMin(iz) + lr.getZBinMax(iz));
250 auto cell = lr.getCellPhiBin(ip, iz);
251 dump << "cell"
252 << "ilr=" << i << "r=" << r << "phi=" << phi << "x=" << x << "y=" << y << "z=" << z << "ip=" << ip << "ips=" << ips << "iz=" << iz
253 << "mrgnxt=" << merge << "val=" << cell << "\n";
254 }
255 }
256 //
257 // statistics per layer
258 MatCell mean, rms;
259 lr.getMeanRMS(mean, rms);
260 dump << "lay"
261 << "ilr=" << i << "r=" << r << "mean=" << mean << "rms=" << rms << "\n";
262 }
263}
264
265//________________________________________________________________________________
266void MatLayerCylSet::writeToFile(const std::string& outFName)
267{
269
270 TFile outf(outFName.data(), "recreate");
271 if (outf.IsZombie()) {
272 return;
273 }
274 outf.WriteObjectAny(this, Class(), "ccdb_object");
275 outf.Close();
276}
277
279{
281 LOG(info) << "Layer voxel already initialized; Aborting";
282 return;
283 }
284 LOG(info) << "Initializing voxel layer lookup";
285 // do some check if voxels are dimensioned correctly
286 if (LayerRMax < get()->mRMax) {
287 LOG(fatal) << "Cannot initialized layer voxel lookup due to dimension problem (fix constants in MatLayerCylSet.h)";
288 }
289 for (int voxel = 0; voxel < NumVoxels; ++voxel) {
290 // check the 2 extremes of this voxel "covering"
291 const auto lowerR = voxel * VoxelRDelta;
292 const auto upperR = lowerR + VoxelRDelta;
293 const auto lowerSegment = searchSegment(lowerR * lowerR);
294 const auto upperSegment = searchSegment(upperR * upperR);
295 mLayerVoxelLU[2 * voxel] = lowerSegment;
296 mLayerVoxelLU[2 * voxel + 1] = upperSegment;
297 }
299}
300
301//________________________________________________________________________________
302MatLayerCylSet* MatLayerCylSet::loadFromFile(const std::string& inpFName)
303{
304 TFile inpf(inpFName.data());
305 if (inpf.IsZombie()) {
306 LOG(error) << "Failed to open input file " << inpFName;
307 return nullptr;
308 }
309 MatLayerCylSet* mb = reinterpret_cast<MatLayerCylSet*>(inpf.GetObjectChecked("ccdb_object", Class()));
310 if (!mb && !(mb = reinterpret_cast<MatLayerCylSet*>(inpf.GetObjectChecked("MatBud", Class())))) { // for old objects
311 LOG(error) << "Failed to load mat.LUT from " << inpFName;
312 return nullptr;
313 }
314 auto rptr = rectifyPtrFromFile(mb);
315 return rptr;
316}
317
318//________________________________________________________________________________
320{
321 // rectify object loaded from file
322 if (ptr && !ptr->get()) {
323 ptr->fixPointers();
324 }
325 ptr->initLayerVoxelLU();
326 return ptr;
327}
328
329//________________________________________________________________________________
331{
332 // merge similar (whose relative budget does not differ within maxRelDiff) phi slices
333 assert(mConstructionMask == InProgress);
334 for (int i = getNLayers(); i--;) {
335 get()->mLayers[i].optimizePhiSlices(maxRelDiff);
336 }
337 // flatten(); // RS: TODO
338}
339
340//________________________________________________________________________________
342{
344 if (!get()) {
345 printf("Not initialized yet\n");
346 return;
347 }
349 LOG(warning) << "Object is not yet flattened";
350 }
351 for (int i = 0; i < getNLayers(); i++) {
352 printf("#%3d | ", i);
354 }
355 printf("%.2f < R < %.2f %d layers with total size %.2f MB\n", getRMin(), getRMax(), getNLayers(),
356 float(getFlatBufferSize()) / 1024 / 1024);
357}
358
359//________________________________________________________________________________
360void MatLayerCylSet::scaleLayersByID(int lrFrom, int lrTo, float factor, bool _x2x0, bool _rho)
361{
362 lrFrom = std::max(0, std::min(lrFrom, get()->mNLayers - 1));
363 lrTo = std::max(0, std::min(lrTo, get()->mNLayers - 1));
364 int dir = lrFrom >= lrTo ? -1 : 1;
365 lrTo += dir;
366 for (int i = lrFrom; i != lrTo; i += dir) {
367 get()->mLayers[i].scale(factor, _x2x0, _rho);
368 }
369}
370
371//________________________________________________________________________________
372void MatLayerCylSet::scaleLayersByR(float rFrom, float rTo, float factor, bool _x2x0, bool _rho)
373{
374 if (rFrom > rTo) {
375 std::swap(rFrom, rTo);
376 }
377 Ray ray(std::max(getRMin(), rFrom), 0., 0., std::min(getRMax(), rTo), 0., 0.);
378 short lmin, lmax;
379 if (!getLayersRange(ray, lmin, lmax)) {
380 LOGP(warn, "No layers found for {} < r < {}", rFrom, rTo);
381 return;
382 }
383 scaleLayersByID(lmin, lmax, factor, _x2x0, _rho);
384}
385
386#endif
387
388#ifndef GPUCA_GPUCODE
389//________________________________________________________________________________
391{
392 std::size_t sz = alignSize(sizeof(MatLayerCylSetLayout), getBufferAlignmentBytes()); // hold data members
393
394 sz = alignSize(sz + get()->mNLayers * sizeof(MatLayerCyl), MatLayerCyl::getClassAlignmentBytes());
395 sz = alignSize(sz + (get()->mNRIntervals + 1) * sizeof(float), getBufferAlignmentBytes());
396 sz = alignSize(sz + get()->mNRIntervals * sizeof(int), getBufferAlignmentBytes());
397
398 for (int i = 0; i < getNLayers(); i++) {
400 }
401 return sz;
402}
403#endif // ! GPUCA_GPUCODE
404
405//_________________________________________________________________________________________________
406GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, float x1, float y1, float z1) const
407{
408 // get material budget traversed on the line between point0 and point1
409 MatBudget rval;
410 Ray ray(x0, y0, z0, x1, y1, z1);
411 short lmin, lmax; // get innermost and outermost relevant layer
412 if (ray.isTooShort() || !getLayersRange(ray, lmin, lmax)) {
413 rval.length = ray.getDist();
414 return rval;
415 }
416 short lrID = lmax;
417 while (lrID >= lmin) { // go from outside to inside
418 const auto& lr = getLayer(lrID);
419 int nphiSlices = lr.getNPhiSlices();
420 int nc = ray.crossLayer(lr); // determines how many crossings this ray has with this tubular layer
421 for (int ic = nc; ic--;) {
422 float cross1, cross2;
423 ray.getCrossParams(ic, cross1, cross2); // tmax,tmin of crossing the layer
424
425 auto phi0 = ray.getPhi(cross1), phi1 = ray.getPhi(cross2), dPhi = phi0 - phi1;
426 auto phiID = lr.getPhiSliceID(phi0), phiIDLast = lr.getPhiSliceID(phi1);
427 // account for eventual wrapping around 0
428 if (dPhi > 0.f) {
429 if (dPhi > o2::constants::math::PI) { // wraps around phi=0
430 phiIDLast += nphiSlices;
431 }
432 } else {
433 if (dPhi < -o2::constants::math::PI) { // wraps around phi=0
434 phiID += nphiSlices;
435 }
436 }
437
438 int stepPhiID = phiID > phiIDLast ? -1 : 1;
439 bool checkMorePhi = true;
440 auto tStartPhi = cross1, tEndPhi = 0.f;
441 do {
442 // get the path in the current phi slice
443 if (phiID == phiIDLast) {
444 tEndPhi = cross2;
445 checkMorePhi = false;
446 } else { // last phi slice still not reached
447 tEndPhi = ray.crossRadial(lr, (stepPhiID > 0 ? phiID + 1 : phiID) % nphiSlices);
448 if (tEndPhi == Ray::InvalidT) {
449 break; // ray parallel to radial line, abandon check for phi bin change
450 }
451 const auto tMarginPhi = 1.e-6f + 1.e-5f * (cross1 - cross2);
452 // if (!(tEndPhi >= cross2 - tMarginPhi) | !(tEndPhi <= cross1 + tMarginPhi)) { // use non-short-circuit | to reject eventual NANs
453 if (tEndPhi < cross2 - tMarginPhi || tEndPhi > cross1 + tMarginPhi) {
454 tEndPhi = cross2;
455 checkMorePhi = false;
456 }
457 }
458 auto zID = lr.getZBinID(ray.getZ(tStartPhi));
459 auto zIDLast = lr.getZBinID(ray.getZ(tEndPhi));
460 // check if Zbins are crossed
461
462#ifdef _DBG_LOC_
463 printf("-- Zdiff (%3d : %3d) mode: t: %+e %+e\n", zID, zIDLast, tStartPhi, tEndPhi);
464#endif
465
466 if (zID != zIDLast) {
467 auto stepZID = zID < zIDLast ? 1 : -1;
468 bool checkMoreZ = true;
469 auto tStartZ = tStartPhi, tEndZ = 0.f;
470 do {
471 if (zID == zIDLast) {
472 tEndZ = tEndPhi;
473 checkMoreZ = false;
474 } else {
475 tEndZ = ray.crossZ(lr.getZBinMin(stepZID > 0 ? zID + 1 : zID));
476 if (tEndZ == Ray::InvalidT) { // track normal to Z axis, abandon Zbin change test
477 break;
478 }
479 }
480 // account materials of this step
481 float step = tEndZ > tStartZ ? tEndZ - tStartZ : tStartZ - tEndZ; // the real step is ray.getDist(tEnd-tStart), will rescale all later
482 const auto& cell = lr.getCell(phiID % nphiSlices, zID);
483 rval.meanRho += cell.meanRho * step;
484 rval.meanX2X0 += cell.meanX2X0 * step;
485 rval.length += step;
486
487#ifdef _DBG_LOC_
488 float pos0[3] = {ray.getPos(tStartZ, 0), ray.getPos(tStartZ, 1), ray.getPos(tStartZ, 2)};
489 float pos1[3] = {ray.getPos(tEndZ, 0), ray.getPos(tEndZ, 1), ray.getPos(tEndZ, 2)};
490 printf(
491 "Lr#%3d / cross#%d : account %f<t<%f at phiSlice %d | Zbin: %3d (%3d) |[%+e %+e +%e]:[%+e %+e %+e] "
492 "Step: %.3e StrpCor: %.3e\n",
493 lrID, ic, tEndZ, tStartZ, phiID % nphiSlices, zID, zIDLast,
494 pos0[0], pos0[1], pos0[2], pos1[0], pos1[1], pos1[2], step, ray.getDist(step));
495#endif
496
497 tStartZ = tEndZ;
498 zID += stepZID;
499 } while (checkMoreZ);
500 } else {
501 float step = tEndPhi > tStartPhi ? tEndPhi - tStartPhi : tStartPhi - tEndPhi; // the real step is |ray.getDist(tEnd-tStart)|, will rescale all later
502 const auto& cell = lr.getCell(phiID % nphiSlices, zID);
503 rval.meanRho += cell.meanRho * step;
504 rval.meanX2X0 += cell.meanX2X0 * step;
505 rval.length += step;
506
507#ifdef _DBG_LOC_
508 float pos0[3] = {ray.getPos(tStartPhi, 0), ray.getPos(tStartPhi, 1), ray.getPos(tStartPhi, 2)};
509 float pos1[3] = {ray.getPos(tEndPhi, 0), ray.getPos(tEndPhi, 1), ray.getPos(tEndPhi, 2)};
510 printf(
511 "Lr#%3d / cross#%d : account %f<t<%f at phiSlice %d | Zbin: %3d ----- |[%+e %+e +%e]:[%+e %+e %+e]"
512 "Step: %.3e StrpCor: %.3e\n",
513 lrID, ic, tEndPhi, tStartPhi, phiID % nphiSlices, zID,
514 pos0[0], pos0[1], pos0[2], pos1[0], pos1[1], pos1[2], step, ray.getDist(step));
515#endif
516 }
517 //
518 tStartPhi = tEndPhi;
519 phiID += stepPhiID;
520
521 } while (checkMorePhi);
522 }
523 lrID--;
524 } // loop over layers
525
526 if (rval.length != 0.f) {
527 rval.meanRho /= rval.length; // average
528 rval.meanX2X0 *= ray.getDist(); // normalize
529 }
530 rval.length = ray.getDist();
531
532#ifdef _DBG_LOC_
533 printf("<rho> = %e, x2X0 = %e | step = %e\n", rval.meanRho, rval.meanX2X0, rval.length);
534#endif
535 return rval;
536}
537
538//_________________________________________________________________________________________________
539GPUd() bool MatLayerCylSet::getLayersRange(const Ray& ray, short& lmin, short& lmax) const
540{
541 // get range of layers corresponding to rmin/rmax
542 //
543 lmin = lmax = -1;
544 float rmin2, rmax2;
545 ray.getMinMaxR2(rmin2, rmax2);
546
547 if (rmin2 >= getRMax2() || rmax2 <= getRMin2()) {
548 return false;
549 }
550 int lmxInt, lmnInt;
551 if (!mInitializedLayerVoxelLU) {
552 lmxInt = rmax2 < getRMax2() ? searchSegment(rmax2, 0) : get()->mNRIntervals - 2;
553 lmnInt = rmin2 >= getRMin2() ? searchSegment(rmin2, 0, lmxInt + 1) : 0;
554 } else {
555 lmxInt = rmax2 < getRMax2() ? searchLayerFast(rmax2, 0) : get()->mNRIntervals - 2;
556 lmnInt = rmin2 >= getRMin2() ? searchLayerFast(rmin2, 0, lmxInt + 1) : 0;
557 }
558
559 const auto* interval2LrID = get()->mInterval2LrID;
560 lmax = interval2LrID[lmxInt];
561 lmin = interval2LrID[lmnInt];
562 // make sure lmnInt and/or lmxInt are not in the gap
563 if (lmax < 0) {
564 lmax = interval2LrID[lmxInt - 1]; // rmax2 is in the gap, take highest layer below rmax2
565 }
566 if (lmin < 0) {
567 lmin = interval2LrID[lmnInt + 1]; // rmin2 is in the gap, take lowest layer above rmin2
568 }
569 return lmin <= lmax; // valid if both are not in the same gap
570}
571
572GPUd() int MatLayerCylSet::searchLayerFast(float r2, int low, int high) const
573{
574 // we can avoid the sqrt .. at the cost of more memory in the lookup
575 const auto index = 2 * int(o2::gpu::CAMath::Sqrt(r2) * InvVoxelRDelta);
576 const auto layersfirst = mLayerVoxelLU[index];
577 const auto layerslast = mLayerVoxelLU[index + 1];
578 if (layersfirst != layerslast) {
579 // this means the voxel is undecided and we revert to search
580 return searchSegment(r2, layersfirst, layerslast + 1);
581 }
582 return layersfirst;
583}
584
585GPUd() int MatLayerCylSet::searchSegment(float val, int low, int high) const
586{
588 if (low < 0) {
589 low = 0;
590 }
591 if (high < 0) {
592 high = get()->mNRIntervals;
593 }
594 int mid = (low + high) >> 1;
595 const auto* r2Intervals = get()->mR2Intervals;
596 while (mid != low) {
597 if (val < r2Intervals[mid]) {
598 high = mid;
599 } else {
600 low = mid;
601 }
602 mid = (low + high) >> 1;
603 }
604
605 return mid;
606}
607
608#ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version
609
611{
612 // make object flat: move all content to single internally allocated buffer
613 assert(mConstructionMask == InProgress);
614
615 int sz = estimateFlatBufferSize();
616 // create new internal buffer with total size and copy data
619 mFlatBufferSize = sz;
620 int nLr = getNLayers();
621
622 auto offs = alignSize(sizeof(MatLayerCylSetLayout), getBufferAlignmentBytes()); // account for the alignment
623 // move array of layer pointers to the flat array
624 auto* oldLayers = o2::gpu::FlatObject::resizeArray(get()->mLayers, nLr, nLr, (MatLayerCyl*)(mFlatBufferPtr + offs));
625 // dynamyc buffers of old layers were used in new ones, detach them
626 for (int i = nLr; i--;) {
627 oldLayers[i].clearInternalBufferPtr();
628 }
629 delete[] oldLayers;
630 offs = alignSize(offs + nLr * sizeof(MatLayerCyl), MatLayerCyl::getClassAlignmentBytes()); // account for the alignment
631
632 // move array of R2 boundaries to the flat array
633 delete[] o2::gpu::FlatObject::resizeArray(get()->mR2Intervals, nLr + 1, nLr + 1, (float*)(mFlatBufferPtr + offs));
634 offs = alignSize(offs + (nLr + 1) * sizeof(float), getBufferAlignmentBytes()); // account for the alignment
635
636 // move array of R2 boundaries to the flat array
637 delete[] o2::gpu::FlatObject::resizeArray(get()->mInterval2LrID, nLr, nLr, (int*)(mFlatBufferPtr + offs));
638 offs = alignSize(offs + nLr * sizeof(int), getBufferAlignmentBytes()); // account for the alignment
639
640 for (int il = 0; il < nLr; il++) {
641 MatLayerCyl& lr = get()->mLayers[il];
642 lr.flatten(mFlatBufferPtr + offs);
643 offs = alignSize(offs + lr.getFlatBufferSize(), getBufferAlignmentBytes()); // account for the alignment
644 }
646}
647
648//______________________________________________
649void MatLayerCylSet::moveBufferTo(char* newFlatBufferPtr)
650{
652 flatObject::moveBufferTo(newFlatBufferPtr);
654}
655#endif // !GPUCA_ALIGPUCODE
656
657#ifndef GPUCA_GPUCODE
658//______________________________________________
659void MatLayerCylSet::setFutureBufferAddress(char* futureFlatBufferPtr)
660{
663 fixPointers(mFlatBufferPtr, futureFlatBufferPtr, false); // flag that futureFlatBufferPtr is not valid yet
664 flatObject::setFutureBufferAddress(futureFlatBufferPtr);
665}
666
667//______________________________________________
668void MatLayerCylSet::setActualBufferAddress(char* actualFlatBufferPtr)
669{
672 fixPointers(actualFlatBufferPtr);
673}
674//______________________________________________
675void MatLayerCylSet::cloneFromObject(const MatLayerCylSet& obj, char* newFlatBufferPtr)
676{
678 flatObject::cloneFromObject(obj, newFlatBufferPtr);
680}
681
682//______________________________________________
683void MatLayerCylSet::fixPointers(char* newBasePtr)
684{
685 // fix pointers on the internal structure of the flat buffer after retrieving it from the file
686 if (newBasePtr) {
687 mFlatBufferPtr = newBasePtr; // used to impose external pointer
688 } else {
689 mFlatBufferPtr = mFlatBufferContainer; // impose pointer after reading from file
690 }
691 auto offs = alignSize(sizeof(MatLayerCylSetLayout), getBufferAlignmentBytes()); // account for the alignment
692 char* newPtr = mFlatBufferPtr + offs; // correct pointer on MatLayerCyl*
693 char* oldPtr = reinterpret_cast<char*>(get()->mLayers); // old pointer read from the file
694 fixPointers(oldPtr, newPtr);
695}
696
697//______________________________________________
698void MatLayerCylSet::fixPointers(char* oldPtr, char* newPtr, bool newPtrValid)
699{
700 // fix pointers on the internal structure of the flat buffer after retrieving it from the file
701 auto* layPtr = get()->mLayers;
702 get()->mLayers = flatObject::relocatePointer(oldPtr, newPtr, get()->mLayers);
703 get()->mR2Intervals = flatObject::relocatePointer(oldPtr, newPtr, get()->mR2Intervals);
704 get()->mInterval2LrID = flatObject::relocatePointer(oldPtr, newPtr, get()->mInterval2LrID);
705 if (newPtrValid) {
706 layPtr = get()->mLayers;
707 }
708 for (int i = 0; i < getNLayers(); i++) {
709 layPtr[i].setFlatPointer(flatObject::relocatePointer(oldPtr, newPtr, layPtr[i].getFlatBufferPtr()));
710 layPtr[i].fixPointers(oldPtr, newPtr);
711 }
712}
713#endif // !GPUCA_GPUCODE
714
715#ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version
716
717MatLayerCylSet* MatLayerCylSet::extractCopy(float rmin, float rmax, float tolerance, const MatLayerCylSet* addTo) const
718{
719 // extract layers in the covering rmin-rmax range. If addTo is provided, simply substitute its layers by those from this
720 if (addTo && addTo->getNLayers() != getNLayers()) {
721 LOGP(fatal, "addTo has {} layers, this has {}", addTo->getNLayers(), getNLayers());
722 }
723 Ray ray(std::max(getRMin(), rmin), 0., 0., std::min(getRMax(), rmax), 0., 0.);
724 short lmin, lmax;
725 if (!getLayersRange(ray, lmin, lmax)) {
726 LOGP(warn, "No layers found for {} < r < {}", rmin, rmax);
727 return nullptr;
728 }
729 LOGP(info, "Will extract layers {}:{} (out of {} layers) for {} < r < {}", lmin, lmax, getNLayers(), rmin, rmax);
730 MatLayerCylSet* copy = new MatLayerCylSet();
731 int lrCount = 0, lrCounOld = 0, lrCountTot = 0;
732 auto addLr = [copy, &lrCountTot](const MatLayerCyl& lr) {
733 float drphi = lr.getDPhi() * (lr.getRMin() + lr.getRMax()) / 2. * 0.999;
734 copy->addLayer(lr.getRMin(), lr.getRMax(), lr.getZMax(), lr.getDZ(), drphi);
735 auto& lrNew = copy->getLayer(lrCountTot++);
736 for (int iz = 0; iz < lrNew.getNZBins(); iz++) {
737 for (int ip = 0; ip < lrNew.getNPhiBins(); ip++) {
738 lrNew.getCellPhiBin(ip, iz).set(lr.getCellPhiBin(ip, iz));
739 }
740 }
741 };
742 if (addTo) {
743 for (int il = 0; il < lmin; il++) {
744 addLr(addTo->getLayer(il));
745 lrCounOld++;
746 }
747 }
748 for (int il = lmin; il <= lmax; il++) {
749 addLr(getLayer(il));
750 lrCount++;
751 }
752 if (addTo) {
753 for (int il = lmax + 1; il < getNLayers(); il++) {
754 addLr(addTo->getLayer(il));
755 lrCounOld++;
756 }
757 }
758 copy->finalizeStructures();
759 copy->optimizePhiSlices(tolerance);
760 copy->flatten();
761 LOGP(info, "Added layers {}:{} for {}<r<{} {}", lmin, lmax, rmin, rmax, fmt::format(", {} layers were transferred from additional set", lrCounOld));
762 return copy;
763}
764
765#endif
int32_t i
#define GPUd()
Declarations for the wrapper for the set of cylindrical material layers.
useful math constants
TBranch * ptr
void merge(Options const &options)
void setActualBufferAddress(char *actualFlatBufferPtr)
static constexpr size_t getBufferAlignmentBytes()
Gives minimal alignment in bytes required for the flat buffer.
void addLayer(float rmin, float rmax, float zmax, float dz, float drphi)
void optimizePhiSlices(float maxRelDiff=0.05)
void cloneFromObject(const MatLayerCylSet &obj, char *newFlatBufferPtr)
MatLayerCyl & getLayer(int i)
static MatLayerCylSet * loadFromFile(const std::string &inpFName="matbud.root")
static constexpr float VoxelRDelta
uint16_t mLayerVoxelLU[2 *NumVoxels]
MatLayerCylSet * extractCopy(float rmin, float rmax, float tol=1e-3, const MatLayerCylSet *toAdd=nullptr) const
static constexpr int NumVoxels
void print(bool data=false) const
bool mInitializedLayerVoxelLU
helper structure to lookup a layer based on known radius (static dimension for easy copy to GPU)
void scaleLayersByR(float rFrom, float rTo, float factor, bool _x2x0=true, bool _rho=true)
void populateFromTGeo(int ntrPerCel=10, int nThreads=-1)
void moveBufferTo(char *newFlatBufferPtr)
std::size_t estimateFlatBufferSize() const
GPUCA_ALIGPUCODE.
void dumpToTree(const std::string &outName="matbudTree.root") const
static MatLayerCylSet * rectifyPtrFromFile(MatLayerCylSet *ptr)
void setFutureBufferAddress(char *futureFlatBufferPtr)
static constexpr float LayerRMax
void scaleLayersByID(int lrFrom, int lrTo, float factor, bool _x2x0=true, bool _rho=true)
void fixPointers(char *newPtr=nullptr)
void writeToFile(const std::string &outFName="matbud.root")
static constexpr size_t getClassAlignmentBytes()
Gives minimal alignment in bytes required for the class object.
void print(bool data=false) const
void flatten(char *newPtr)
MatCell & getCellPhiBin(int iphi, int iz)
Definition MatLayerCyl.h:98
static constexpr float InvalidT
Definition Ray.h:46
static constexpr float Tiny
Definition Ray.h:47
void setFutureBufferAddress(char *futureFlatBufferPtr)
Definition FlatObject.h:569
uint32_t mConstructionMask
mask for constructed object members, first two bytes are used by this class
Definition FlatObject.h:321
int32_t mFlatBufferSize
size of the flat buffer
Definition FlatObject.h:320
char * mFlatBufferContainer
Definition FlatObject.h:322
static T * relocatePointer(const char *oldBase, char *newBase, const T *ptr)
Relocates a pointer inside a buffer to the new buffer address.
Definition FlatObject.h:283
void moveBufferTo(char *newBufferPtr)
Definition FlatObject.h:408
static constexpr size_t alignSize(size_t sizeBytes, size_t alignmentBytes)
_______________ Generic utilities _______________________________________________
Definition FlatObject.h:275
T * resizeArray(T *&ptr, int32_t oldSize, int32_t newSize, T *newPtr=nullptr)
Definition FlatObject.h:135
void cloneFromObject(const FlatObject &obj, char *newFlatBufferPtr)
Definition FlatObject.h:385
@ InProgress
construction started: temporary memory is reserved
Definition FlatObject.h:317
@ Constructed
the object is constructed, temporary memory is released
Definition FlatObject.h:316
void dump(const std::string what, DPMAP m, int verbose)
Definition dcs-ccdb.cxx:79
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint GLfloat GLfloat GLfloat GLfloat y1
Definition glcorearb.h:5034
GLuint GLfloat GLfloat GLfloat x1
Definition glcorearb.h:5034
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLenum GLint * range
Definition glcorearb.h:1899
GLboolean * data
Definition glcorearb.h:298
GLuint GLfloat x0
Definition glcorearb.h:5034
GLuint GLfloat * val
Definition glcorearb.h:1582
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLboolean r
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLuint GLfloat GLfloat y0
Definition glcorearb.h:5034
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
constexpr float PI
auto get(const std::byte *buffer, size_t=0)
Definition DataHeader.h:454
float length
length in material
Definition MatCell.h:55
float meanRho
mean density, g/cm^3
Definition MatCell.h:30
float meanX2X0
fraction of radiaton lenght
Definition MatCell.h:31
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"