Skip to content

Commit 40a43e2

Browse files
committed
ALICE3-TRK: setting basis for digitization code - definition of a simple segmentation, adding methods to deal with the curved VD layers, adding chip response based on ITS2 and ITS3 codes, adding useful codes for parameters, digit containers, etc.
1 parent 12fcd79 commit 40a43e2

File tree

12 files changed

+1352
-21
lines changed

12 files changed

+1352
-21
lines changed

Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
o2_add_library(TRKBase
1313
SOURCES src/GeometryTGeo.cxx
1414
src/TRKBaseParam.cxx
15+
src/SegmentationChip.cxx
1516
PUBLIC_LINK_LIBRARIES O2::DetectorsBase)
1617

1718
o2_target_root_dictionary(TRKBase
1819
HEADERS include/TRKBase/GeometryTGeo.h
19-
include/TRKBase/TRKBaseParam.h)
20+
include/TRKBase/TRKBaseParam.h
21+
include/TRKBase/SegmentationChip.h)
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
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.
11+
12+
/// \file SegmentationChip.h
13+
/// \brief Definition of the SegmentationChipclass
14+
15+
#ifndef ALICEO2_TRK_SEGMENTATIONCHIP_H_
16+
#define ALICEO2_TRK_SEGMENTATIONCHIP_H_
17+
18+
#include <type_traits>
19+
#include <fairlogger/Logger.h>
20+
21+
#include "MathUtils/Cartesian.h"
22+
#include "TRKBase/Specs.h"
23+
24+
namespace o2::trk
25+
{
26+
27+
/// Segmentation and response for TRK chips in ALICE3 upgrade
28+
/// This is a work-in-progress code derived from the ITS2 and ITS3 segmentations.
29+
class SegmentationChip
30+
{
31+
// This class defines the segmenation of the TRK chips in the ALICE3 upgrade. We define
32+
// two coordinate systems, one width x,z detector local coordianates (cm) and
33+
// the more natural row,col layout: Also all the transformation between these
34+
// two. The class provides the transformation from the stave/layer/disk to TGeo
35+
// coordinates.
36+
// For the curved VD layers there exist three coordinate systems and one is transient.
37+
// 1. The global (curved) coordinate system. The chip's center of coordinate system is
38+
// defined at the the mid-point of the detector.
39+
// 2. The flat coordinate system. This is the tube segment projected onto a flat
40+
// surface. In the projection we implicitly assume that the inner and outer
41+
// stretch does not depend on the radius.
42+
// 3. The detector coordinate system. Defined by the row and column segmentation
43+
// defined at the upper edge in the flat coord.
44+
// For the flat ML and OT layers, there exist two coordinate systems:
45+
// 1. The global (flat) coordinate system. The chip's center of coordinate system is
46+
// defined at the the mid-point of the detector.
47+
// 2. The detector coordinate system. Defined by the row and column segmentation
48+
// TODO: add segmentation for VD disks
49+
50+
public:
51+
constexpr SegmentationChip() = default;
52+
~SegmentationChip() = default;
53+
constexpr SegmentationChip(const SegmentationChip&) = default;
54+
constexpr SegmentationChip(SegmentationChip&&) = delete;
55+
constexpr SegmentationChip& operator=(const SegmentationChip&) = default;
56+
constexpr SegmentationChip& operator=(SegmentationChip&&) = delete;
57+
58+
static constexpr float PitchColVD{constants::VD::petal::layer::pitchZ};
59+
static constexpr float PitchRowVD{constants::VD::petal::layer::pitchX};
60+
61+
static constexpr float PitchColML{constants::moduleMLOT::chip::pitchZ};
62+
static constexpr float PitchRowML{constants::moduleMLOT::chip::pitchX};
63+
64+
static constexpr float PitchColOT{constants::moduleMLOT::chip::pitchZ};
65+
static constexpr float PitchRowOT{constants::moduleMLOT::chip::pitchX};
66+
67+
static constexpr float SensorLayerThicknessVD = {constants::VD::petal::layer::totalThickness}; // physical thickness of sensitive part = 30 um
68+
static constexpr float SensorLayerThicknessML = {constants::moduleMLOT::chip::totalThickness}; // physical thickness of sensitive part = 100 um
69+
static constexpr float SensorLayerThicknessOT = {constants::moduleMLOT::chip::totalThickness}; // physical thickness of sensitive part = 100 um
70+
71+
static constexpr float SiliconTickness = constants::silicon::thickness; // effective thickness of sensitive part
72+
73+
static constexpr std::array<double, constants::VD::petal::nLayers> radiiVD = constants::VD::petal::layer::radii;
74+
75+
/// Transformation from Geant detector centered local coordinates (cm) to
76+
/// Pixel cell numbers iRow and iCol.
77+
/// Returns kTRUE if point x,z is inside sensitive volume, kFALSE otherwise.
78+
/// A value of -1 for iRow or iCol indicates that this point is outside of the
79+
/// detector segmentation as defined.
80+
/// \param float x Detector local coordinate x in cm with respect to
81+
/// the center of the sensitive volume.
82+
/// \param float z Detector local coordinate z in cm with respect to
83+
/// the center of the sensitive volulme.
84+
/// \param int iRow Detector x cell coordinate. Has the range 0 <= iRow < mNumberOfRows
85+
/// \param int iCol Detector z cell coordinate. Has the range 0 <= iCol < mNumberOfColumns
86+
/// \param int subDetID Sub-detector ID (0 for VD, 1 for ML/OT)
87+
/// \param int layer Layer number (0 to 2 for VD, 0 to 7 for ML/OT)
88+
/// \param int disk Disk number (0 to 5 for VD)
89+
static bool globalToDetector(float xRow, float zCol, int& iRow, int& iCol, int subDetID, int layer, int disk) noexcept
90+
{
91+
if (!isValidGlob(xRow, zCol, subDetID, layer)) {
92+
LOGP(info, "Global coordinates not valid: row = {} cm, col = {} cm", xRow, zCol);
93+
return false;
94+
}
95+
96+
globalToDetectorUnchecked(xRow, zCol, iRow, iCol, subDetID, layer, disk);
97+
98+
if (!isValidDet(iRow, iCol, subDetID, layer)) {
99+
iRow = iCol = -1;
100+
LOGP(info, "Detector coordinates not valid: iRow = {}, iCol = {}", iRow, iCol);
101+
return false;
102+
}
103+
return true;
104+
};
105+
/// same but w/o check for row/column range
106+
static void globalToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol, int subDetID, int layer, int disk) noexcept
107+
{
108+
// convert to row/col w/o over/underflow check
109+
float pitchRow(0), pitchCol(0);
110+
float maxWidth(0), maxLength(0);
111+
112+
if (subDetID == 0) {
113+
pitchRow = PitchRowVD;
114+
pitchCol = PitchColVD;
115+
maxWidth = constants::VD::petal::layer::width[layer];
116+
maxLength = constants::VD::petal::layer::length;
117+
// TODO: change this to use the layer and disk
118+
} else if (subDetID == 1 && layer <= 3) { // ML
119+
pitchRow = PitchRowML;
120+
pitchCol = PitchColML;
121+
maxWidth = constants::ML::width;
122+
maxLength = constants::ML::length;
123+
} else if (subDetID == 1 && layer >= 4) { // OT
124+
pitchRow = PitchRowOT;
125+
pitchCol = PitchColOT;
126+
maxWidth = constants::OT::width;
127+
maxLength = constants::OT::length;
128+
}
129+
// convert to row/col
130+
iRow = static_cast<int>(std::floor((maxWidth / 2 - xRow) / pitchRow));
131+
iCol = static_cast<int>(std::floor((zCol + maxLength / 2) / pitchCol));
132+
};
133+
134+
// Check global coordinates (cm) validity.
135+
static constexpr bool isValidGlob(float x, float z, int subDetID, int layer) noexcept
136+
{
137+
float maxWidth(0), maxLength(0);
138+
if (subDetID == 0) {
139+
maxWidth = constants::VD::petal::layer::width[layer];
140+
maxLength = constants::VD::petal::layer::length;
141+
// TODO: change this to use the layer and disk
142+
} else if (subDetID == 1 && layer <= 3) { // ML
143+
maxWidth = constants::ML::width;
144+
maxLength = constants::ML::length;
145+
} else if (subDetID == 1 && layer >= 4) { // OT
146+
maxWidth = constants::OT::width;
147+
maxLength = constants::OT::length;
148+
}
149+
return (-maxWidth / 2 < x && x < maxWidth / 2 && -maxLength / 2 < z && z < maxLength / 2);
150+
}
151+
152+
// Check detector coordinates validity.
153+
static constexpr bool isValidDet(float row, float col, int subDetID, int layer) noexcept
154+
{
155+
// Check if the row and column are within the valid range
156+
int nRows(0), nCols(0);
157+
if (subDetID == 0) {
158+
nRows = constants::VD::petal::layer::nRows[layer];
159+
nCols = constants::VD::petal::layer::nCols;
160+
// TODO: change this to use the layer and disk
161+
} else if (subDetID == 1 && layer <= 3) { // ML
162+
nRows = constants::ML::nRows;
163+
nCols = constants::ML::nCols;
164+
} else if (subDetID == 1 && layer >= 4) { // OT
165+
nRows = constants::OT::nRows;
166+
nCols = constants::OT::nCols;
167+
}
168+
return (row >= 0 && row < static_cast<float>(nRows) &&
169+
col >= 0 && col < static_cast<float>(nCols));
170+
}
171+
172+
/// Transformation from Detector cell coordinates to Geant detector centered
173+
/// local coordinates (cm)
174+
/// \param int iRow Detector x cell coordinate.
175+
/// \param int iCol Detector z cell coordinate.
176+
/// \param float x Detector local coordinate x in cm with respect to the
177+
/// center of the sensitive volume.
178+
/// \param float z Detector local coordinate z in cm with respect to the
179+
/// center of the sensitive volume.
180+
/// If iRow and or iCol is outside of the segmentation range a value of -0.5*Dx()
181+
/// or -0.5*Dz() is returned.
182+
/// \param int subDetID Sub-detector ID (0 for VD, 1 for ML/OT)
183+
/// \param int layer Layer number (0 to 2 for VD, 0 to 7 for ML/OT)
184+
/// \param int disk Disk number (0 to 5 for VD)
185+
static constexpr bool detectorToGlobal(int iRow, int iCol, float& xRow, float& zCol, int subDetID, int layer, int disk) noexcept
186+
{
187+
if (!isValidDet(xRow, zCol, subDetID, layer)) {
188+
LOGP(debug, "Detector coordinates not valid: iRow = {}, iCol = {}", iRow, iCol);
189+
return false;
190+
}
191+
detectorToGlobalUnchecked(iRow, iCol, xRow, zCol, subDetID, layer, disk);
192+
193+
if (!isValidGlob(xRow, zCol, subDetID, layer)) {
194+
LOGP(debug, "Global coordinates not valid: row = {} cm, col = {} cm", xRow, zCol);
195+
return false;
196+
}
197+
return true;
198+
};
199+
200+
// Same as detectorToGlobal w.o. checks.
201+
// We position ourself in the middle of the pixel.
202+
static void detectorToGlobalUnchecked(int& row, int& col, float xRow, float zCol, int subDetID, int layer, int disk) noexcept
203+
{
204+
if (subDetID == 0) {
205+
xRow = -(row + 0.5f) * PitchRowVD + constants::VD::petal::layer::width[layer] / 2;
206+
zCol = (col + 0.5f) * PitchColVD - constants::VD::petal::layer::length / 2;
207+
} else if (subDetID == 1 && layer <= 3) { // ML
208+
xRow = -(row + 0.5f) * PitchRowML + constants::ML::width / 2;
209+
zCol = (col + 0.5f) * PitchColML - constants::ML::length / 2;
210+
} else if (subDetID == 1 && layer >= 4) { // OT
211+
xRow = -(row + 0.5f) * PitchRowOT + constants::OT::width / 2;
212+
zCol = (col + 0.5f) * PitchColOT - constants::OT::length / 2;
213+
}
214+
}
215+
216+
/// Transformation from the curved surface to a flat surface.
217+
/// Additionally a shift in the flat coordinates must be applied because
218+
/// the center of the TGeoShap when projected will be higher than the
219+
/// physical thickness of the chip. Thus we shift the projected center
220+
/// down by this difference to align the coordinate systems.
221+
/// \param layer VD layer number
222+
/// \param xCurved Detector local curved coordinate x in cm with respect to
223+
/// the center of the sensitive volume.
224+
/// \param yCurved Detector local curved coordinate y in cm with respect to
225+
/// the center of the sensitive volume.
226+
/// \return math_utils::Vector2D<float>: x and y represent the detector local flat coordinates x and y
227+
// in cm with respect to the center of the sensitive volume.
228+
229+
static math_utils::Vector2D<float> curvedToFlat(const int layer, const float xCurved, const float yCurved) noexcept
230+
{
231+
// Align the flat surface with the curved survace of the original chip (and account for metal stack, TODO)
232+
float dist = std::hypot(xCurved, yCurved);
233+
float phi = std::atan2(yCurved, xCurved);
234+
235+
// the y position is in the silicon volume however we need the chip volume (silicon+metalstack)
236+
// this is accounted by a y shift
237+
float xFlat = -constants::VD::petal::layer::radii[layer] * phi; /// this is equal to the circumference segment covered between y=0 and the phi angle
238+
float yFlat = dist - constants::VD::petal::layer::radii[layer];
239+
return math_utils::Vector2D<float>(xFlat, yFlat);
240+
}
241+
242+
/// Transformation from the flat surface to a curved surface
243+
/// It works only if the detector is not rototraslated.
244+
/// \param layer VD layer number
245+
/// \param xFlat Detector local flat coordinate x in cm with respect to
246+
/// the center of the sensitive volume.
247+
/// \param yFlat Detector local flat coordinate y in cm with respect to
248+
/// the center of the sensitive volume.
249+
/// \return math_utils::Vector2D<float>: x and y represent the detector local curved coordinates x and y
250+
// in cm with respect to the center of the sensitive volume.
251+
static constexpr math_utils::Vector2D<float> flatToCurved(int layer, float xFlat, float yFlat) noexcept
252+
{
253+
// Revert the curvedToFlat transformation
254+
float dist = yFlat + constants::VD::petal::layer::radii[layer];
255+
float phi = -xFlat / constants::VD::petal::layer::radii[layer];
256+
// the y position is in the chip volume however we need the silicon volume
257+
// this is accounted by a -y shift
258+
float xCurved = dist * std::cos(phi);
259+
float yCurved = dist * std::sin(phi);
260+
return math_utils::Vector2D<float>(xCurved, yCurved);
261+
}
262+
};
263+
264+
} // namespace o2::trk
265+
266+
#endif
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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.
11+
12+
/// \file Specs.h
13+
/// \brief specs of the ALICE3 TRK
14+
15+
#ifndef O2_ALICE_TRK_SPECS
16+
#define O2_ALICE_TRK_SPECS
17+
18+
#include <array>
19+
#include <math.h>
20+
// This is a temporary version with the specs for the ALICE3 TRK
21+
// This files defines the design specifications of the chips for VD, ML, OT.
22+
// Each TGeoShape has the following properties
23+
// length: dimension in z-axis
24+
// width: dimension in xy-axes
25+
// color: for visulisation
26+
namespace o2::trk::constants
27+
{
28+
// Default unit of TGeo = cm
29+
constexpr double cm{1};
30+
constexpr double mu{1e-4};
31+
constexpr double mm{1e-1};
32+
33+
// namespace metalstack /// still to be defined
34+
// {
35+
// constexpr double thickness{5 * mu}; // physical thickness of the copper metal stack
36+
// }
37+
38+
namespace VD // TODO: add a primitive segmentation with more granularity wrt 1/4 layer = 1 chip
39+
{
40+
namespace petal
41+
{
42+
constexpr int nLayers{3}; // number of layers in each VD petal
43+
constexpr int nDisks{6}; // number of disks in each VD petal
44+
namespace layer
45+
{
46+
constexpr double pitchX{10 * mu}; // pitch of the row
47+
constexpr double pitchZ{10 * mu}; // pitch of the column
48+
constexpr double totalThickness{30 * mu}; // total thickness of the chip
49+
constexpr std::array<double, nLayers> radii{0.5 * cm, 1.2 * cm, 2.5 * cm}; // width of the quarter of layer in cm
50+
constexpr std::array<double, nLayers> width{radii[0] * 2 * M_PI / 4, radii[1] * 2 * M_PI / 4, radii[2] * 2 * M_PI / 4}; // width of the quarter of layer in cm
51+
constexpr double length{50 * cm}; // length of the layer
52+
constexpr int nCols{static_cast<int>(length / pitchZ)}; // number of columns in the chip
53+
constexpr std::array<int, nLayers> nRows{static_cast<int>(width[0] / pitchX), static_cast<int>(width[1] / pitchX), static_cast<int>(width[2] / pitchX)}; // number of rows in the chip
54+
55+
} // namespace layer
56+
namespace disk
57+
{ //// TODO: to be filled
58+
constexpr double radiusIn{0.5 * cm};
59+
constexpr double radiusOut{2.5 * cm};
60+
} // namespace disk
61+
} // namespace petal
62+
} // namespace VD
63+
64+
namespace moduleMLOT /// same for ML and OT for the moment
65+
{ /// TODO: account for different modules in case of change
66+
namespace chip
67+
{
68+
constexpr double width{25 * mm}; // width of the chip
69+
constexpr double length{32 * mm}; // length of the chip
70+
constexpr double pitchX{50 * mu}; // pitch of the row
71+
constexpr double pitchZ{50 * mu}; // pitch of the column
72+
constexpr int nRows{static_cast<int>(width / pitchX)}; // number of columns in the chip
73+
constexpr int nCold{static_cast<int>(length / pitchZ)}; // number of rows in the chipù
74+
constexpr double totalThickness{100 * mu}; // total thickness of the chip
75+
/// Set to 0 for the moment, to be adjusted with the actual design of the chip if needed
76+
static constexpr float PassiveEdgeReadOut = 0.f; // width of the readout edge (Passive bottom)
77+
static constexpr float PassiveEdgeTop = 0.f; // Passive area on top
78+
static constexpr float PassiveEdgeSide = 0.f; // width of Passive area on left/right of the sensor
79+
} // namespace chip
80+
namespace gaps
81+
{
82+
constexpr double interChips{0.2 * mm}; // gap between the chips
83+
constexpr double outerEdgeLongSide{1 * mm}; // gap between the chips and the outer edges (long side)
84+
constexpr double outerEdgeShortSide{0.1 * mm}; // gap between the chips and the outer edges (short side)
85+
} // namespace gaps
86+
constexpr double width{chip::width * 2 + gaps::interChips + 2 * gaps::outerEdgeLongSide}; // width of the module
87+
constexpr double length{chip::length * 4 + 3 * gaps::interChips + 2 * gaps::outerEdgeShortSide}; // length of the module
88+
constexpr int nRows{static_cast<int>(width / chip::pitchX)}; // number of columns in the module
89+
constexpr int nCold{static_cast<int>(length / chip::pitchZ)}; // number of rows in the module
90+
} // namespace moduleMLOT
91+
92+
namespace ML
93+
{
94+
constexpr double width{constants::moduleMLOT::width * 1}; // width of the stave
95+
constexpr double length{constants::moduleMLOT::length * 10}; // length of the stave
96+
constexpr int nRows{static_cast<int>(width / constants::moduleMLOT::chip::pitchX)}; // number of rows in the stave
97+
constexpr int nCols{static_cast<int>(length / constants::moduleMLOT::chip::pitchZ)}; // number of columns in the stave
98+
} // namespace ML
99+
100+
namespace OT
101+
{
102+
constexpr double width{moduleMLOT::width * 2}; // width of the stave
103+
constexpr double length{moduleMLOT::length * 20}; // length of the stave
104+
constexpr int nRows{static_cast<int>(width / moduleMLOT::chip::pitchX)}; // number of rows in the stave
105+
constexpr int nCols{static_cast<int>(length / moduleMLOT::chip::pitchZ)}; // number of columns in the stave
106+
} // namespace OT
107+
108+
namespace silicon
109+
{
110+
constexpr double thickness{10 * mu}; // thickness of active material
111+
} // namespace silicon
112+
} // namespace o2::trk::constants
113+
114+
#endif

0 commit comments

Comments
 (0)