CbmRoot
Loading...
Searching...
No Matches
KfMaterialMap.cxx
Go to the documentation of this file.
1/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergey Gorbunov, Sergei Zharko [committer] */
4
5#include "KfMaterialMap.h"
6
8#include "KfSimd.h"
9
10#include <cmath>
11#include <iomanip>
12#include <sstream>
13#include <vector>
14
15#include <fmt/format.h>
16
19
20// ---------------------------------------------------------------------------------------------------------------------
21//
22MaterialMap::MaterialMap(int nBins, float xyMax, float zRef, float zMin, float zMax)
23 : fNbins(nBins)
24 , fXYmax(xyMax)
25 , fFactor(0.5 * fNbins / fXYmax)
26 , fZref(zRef)
27 , fZmin(zMin)
28 , fZmax(zMax)
29{
30 this->CheckConsistency();
31 fTable.resize(fNbins * fNbins);
32}
33
34// ---------------------------------------------------------------------------------------------------------------------
35//
36MaterialMap::MaterialMap(MaterialMap&& other) noexcept { this->Swap(other); }
37
38// ---------------------------------------------------------------------------------------------------------------------
39//
41{
42 if (this != &other) {
43 MaterialMap tmp(std::move(other));
44 this->Swap(tmp);
45 }
46 return *this;
47}
48
49// ---------------------------------------------------------------------------------------------------------------------
50//
51void MaterialMap::Add(const MaterialMap& other, float zTarg)
52{
53 // The function allows to add a material layer either from the left or from the right to the station
54 // NOTE: A symmetry of x-y is assumed
55 constexpr int nRays{3}; // Number of rays in a bin in a dimension
56 const bool bRadialRays{!std::isnan(zTarg)}; // Are rays radial (true, coming from target) or parallel (false)?
57 const auto scaleFactor{bRadialRays ? ((other.fZref - zTarg) / (this->fZref - zTarg)) : 1.F};
58 const auto binSize{2.F * scaleFactor * this->fXYmax / this->fNbins}; // Size of each bin dimension [cm]
59 const auto stepSize{binSize / static_cast<float>(nRays)}; // Step between two neighboring rays [cm]
60
61 // The coordinates of the first ray intersection with the other material layer [cm]
62 float yBinOther{-this->fXYmax * scaleFactor + stepSize * 0.5F};
63
64 // Loop over bins of the active (this)
65 for (int iBinY{0}; iBinY < this->fNbins; ++iBinY) {
66 float xBinOther{-this->fXYmax * scaleFactor + stepSize * 0.5F};
67 for (int iBinX{0}; iBinX < this->fNbins; ++iBinX) {
68 // Collect material using ray shooting
69 float avgThickness{0}; // Collected average thickness
70 for (int iRayY{0}; iRayY < nRays; ++iRayY) {
71 for (int iRayX{0}; iRayX < nRays; ++iRayX) {
72 avgThickness += other.GetThicknessX0(xBinOther + iRayX * stepSize, yBinOther + iRayY * stepSize);
73 }
74 }
75 this->fTable[iBinX + this->fNbins * iBinY] += (avgThickness / (nRays * nRays));
76 xBinOther += binSize;
77 }
78 yBinOther += binSize;
79 }
80 this->fZmin = std::min(this->fZmin, other.fZmin);
81 this->fZmax = std::max(this->fZmax, other.fZmax);
82}
83
84// ---------------------------------------------------------------------------------------------------------------------
85//
86int MaterialMap::GetBin(float x, float y) const
87{
88 int i{static_cast<int>((x + fXYmax) * fFactor)};
89 int j{static_cast<int>((y + fXYmax) * fFactor)};
90 if (i < 0 || j < 0 || i >= fNbins || j >= fNbins) {
91 return -1;
92 }
93 return i + j * fNbins;
94}
95
96// ---------------------------------------------------------------------------------------------------------------------
97//
98void MaterialMap::Rebin(int nGroups)
99{
100 if (nGroups < 1 && nGroups > fNbins) {
101 int nGroupsSet{nGroups};
102 nGroups = std::clamp(nGroups, 1, fNbins);
103 LOG(warn) << "kf::MaterialMap::Rebin(): incorrect input parameter nGroups = " << nGroupsSet << " is set to "
104 << nGroups;
105 }
106
107 int nBinsNew = static_cast<int>(static_cast<bool>(fNbins % nGroups)) + fNbins / nGroups;
108 std::vector<float> table(nBinsNew * nBinsNew);
109 for (int iX{0}; iX < nBinsNew; ++iX) {
110 for (int iY{0}; iY < nBinsNew; ++iY) {
111 float value{0.F};
112 int nEntries{0};
113 int iOldXmin{iX * nGroups};
114 int iOldXmax{std::max((iX + 1) * nGroups, fNbins)};
115 int iOldYmin{iY * nGroups};
116 int iOldYmax{std::max((iY + 1) * nGroups, fNbins)};
117 for (int iOldX{iOldXmin}; iOldX < iOldXmax; ++iOldX) {
118 for (int iOldY{iOldYmin}; iOldY < iOldYmax; ++iOldY) {
119 value += fTable[iOldX + fNbins * iOldY];
120 ++nEntries;
121 }
122 }
123 table[iX + nBinsNew * iY] = value / nEntries;
124 }
125 }
126 fTable = std::move(table);
127 fFactor = fFactor / fNbins * nBinsNew;
128 fNbins = nBinsNew;
129}
130
131// ---------------------------------------------------------------------------------------------------------------------
132//
133void MaterialMap::Swap(MaterialMap& other) noexcept
134{
135 std::swap(fNbins, other.fNbins);
136 std::swap(fXYmax, other.fXYmax);
137 std::swap(fFactor, other.fFactor);
138 std::swap(fZref, other.fZref);
139 std::swap(fZmin, other.fZmin);
140 std::swap(fZmax, other.fZmax);
141 std::swap(fTable, other.fTable); // Probably can cause segmentation violation (did not understand)
142}
143
144// ---------------------------------------------------------------------------------------------------------------------
145//
146std::string MaterialMap::ToString(int indentLevel, int verbose) const
147{
148 using fmt::format;
149 using std::setw;
150 std::stringstream msg;
151 if (verbose > 0) {
152 constexpr char indentCh = '\t';
153 std::string indent(indentLevel, indentCh);
154 msg << format("zRef = {:<12} cm, range [{:<12}, {:<12}] cm, nBins = {:<8}, XYmax = {:<12} cm", fZref, fZmin, fZmax,
155 fNbins, fXYmax);
156 if (verbose > 1) {
157 msg << indent << indentCh << "\nContent(rebinned to 10 bins):\n";
158 msg.precision(3);
159 auto mapTmp{*this};
160 mapTmp.Rebin(fNbins / 10);
161 msg << indent << indentCh << setw(15) << "y [cm] \\ x [cm]" << ' ';
162 for (int iX{0}; iX < mapTmp.fNbins; ++iX) {
163 float xRef{-mapTmp.fXYmax + (mapTmp.fXYmax * (2 * iX + 1)) / mapTmp.fNbins};
164 msg << setw(10) << xRef << ' ';
165 }
166 msg << '\n';
167 for (int iY{0}; iY < mapTmp.fNbins; ++iY) {
168 float yRef{-mapTmp.fXYmax + (mapTmp.fXYmax * (2 * iY + 1)) / mapTmp.fNbins};
169 msg << indent << indentCh << setw(15) << yRef << ' ';
170 for (int iX{0}; iX < mapTmp.fNbins; ++iX) {
171 msg << setw(10) << mapTmp.fTable[iX + mapTmp.fNbins * iY] << ' ';
172 }
173 msg << '\n';
174 }
175 }
176 }
177 return msg.str();
178}
179
180// ---------------------------------------------------------------------------------------------------------------------
181//
183{
184 if (fNbins < 1) {
185 std::stringstream aStream;
186 aStream << "MaterialMap: object cannot be initialized with non-positive nBins = " << fNbins;
187 throw std::logic_error(aStream.str());
188 }
189
190 if (fXYmax < 0.) {
191 std::stringstream aStream;
192 aStream << "MaterialMap: object cannot be initialized with non-positive XYmax = " << fXYmax << " [cm]";
193 throw std::logic_error(aStream.str());
194 }
195
196 if (!((fZmin <= fZref) && (fZref <= fZmax))) {
197 std::stringstream aStream;
198 aStream << "MaterialMap: object cannot be initialized with inconsistent Z: min " << fZmin << " ref " << fZref
199 << " max " << fZmax << " [cm]";
200 throw std::logic_error(aStream.str());
201 }
202}
Implementation selection for the SIMD utilities (VS or pseudo)
A map of station thickness in units of radiation length (X0) to the specific point in XY plane.
std::vector< float > fTable
Material budget table.
void Rebin(int factor)
Reduces number of bins by a given factor.
MaterialMap & operator=(const MaterialMap &other)=default
Copy assignment operator.
float fFactor
Util. var. for the conversion of point coordinates to row/column id.
int fNbins
Number of rows (== N columns) in the material budget table.
float fXYmax
Size of the station in x and y dimensions [cm].
float fZmax
Minimal Z of the collected material [cm].
float fZref
Reference Z of the collected material [cm].
MaterialMap()=default
Default constructor.
int GetBin(float x, float y) const
Gets bin index for (x,y). Returns -1 when outside of the map.
I GetThicknessX0(const I &x, const I &y) const
Gets material thickness in units of radiational length X0.
float fZmin
Minimal Z of the collected material [cm].
void Swap(MaterialMap &other) noexcept
Swap method.
void Add(const MaterialMap &other, float zTarg=defs::Undef< float >)
Adds material layer.
std::string ToString(int indentLevel=0, int verbose=1) const
String representation of the object.
void CheckConsistency() const
Checks the object consistency.