Skip to content

Commit f74b291

Browse files
committed
Add splitting of stave in case of strict inner cutoff
1 parent 03bf67c commit f74b291

2 files changed

Lines changed: 116 additions & 73 deletions

File tree

Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/FT3Module.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,13 @@ class FT3Module
7070

7171
// Helper functions
7272
void fill_stave(PosNegPositionTypes& y_positions, double Rin, double Rout,
73-
double x_left, unsigned kSensorStack, double tolerance_inner,
74-
double tolerance_outer, PositionRangeType y_range);
73+
double x_left, unsigned kSensorStack, PositionRangeType y_range,
74+
std::pair<double, double>& absAllowedYRange);
7575
void addStaveVolume(
7676
TGeoVolume* motherVolume, std::string volumeName, int direction,
77-
unsigned* volume_count, double staveLength, double tolerance_inner,
78-
double tolerance_outer, double Rin, double Rout,
77+
unsigned* volume_count, double staveLength,
78+
std::array<std::array<double, 3>, 4> staveTriangles,
79+
std::pair<double, double>& absAllowedYRange,
7980
double x_mid, double y_mid, double z_stave_shift_abs);
8081
void addDetectorVolume(
8182
TGeoVolume* motherVolume, std::string volumeName, int color, unsigned* volume_count,

Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx

Lines changed: 111 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -150,22 +150,14 @@ std::pair<double, double> calculate_y_range(
150150
* for positive and negative y respectively
151151
*/
152152
void FT3Module::fill_stave(PosNegPositionTypes& y_positions, double Rin, double Rout,
153-
double x_left, unsigned kSensorStack, double tolerance_inner,
154-
double tolerance_outer, PositionRangeType y_ranges)
153+
double x_left, unsigned kSensorStack, PositionRangeType y_ranges,
154+
std::pair<double, double>& absAllowedYRange)
155155
{
156156
// start with upper half of the stave, then mirror to the bottom half
157-
double x_right = x_left + Constants::sensor2x1_width;
158157
// add the height of kSensorStack sensors + the gaps in between them
159158
double sensorStackHeight = Constants::getStackHeight(kSensorStack);
160159
double sensorAbsStackYShift = sensorStackHeight + Constants::stackGap;
161160

162-
std::pair<double, double> absAllowedYRange =
163-
calculate_y_range(x_left, x_right, Rin, Rout);
164-
165-
// shift allowed range by tolerance. Note that this sum can be negative, but
166-
// that is not a problem, it just means that we can always place sensors over the edge
167-
absAllowedYRange.first += tolerance_inner;
168-
absAllowedYRange.second -= tolerance_outer;
169161
// in case a big tolerance is given, cut on the given range instead
170162
double max_sensor_y_abs = std::min(absAllowedYRange.second, y_ranges.first.second);
171163

@@ -209,14 +201,14 @@ void FT3Module::fill_stave(PosNegPositionTypes& y_positions, double Rin, double
209201
}
210202

211203
/*
212-
* This function creates a carbon fibre volume for the stave,
213-
* onto which the sensor and its support will be glued.
204+
* Create the vertices of the triangles that make up the stave cross section
205+
*
206+
* Each array of 3 corresponds to x or z values of the 3 triangle vertices,
207+
* and the outer array corresponds to which triangle:
208+
*
209+
* [x_outer, z_outer, x_inner, z_inner], each of which has three values
214210
*/
215-
void FT3Module::addStaveVolume(
216-
TGeoVolume* motherVolume, std::string volumeName, int direction,
217-
unsigned* volume_count, double staveLength, double tolerance_inner,
218-
double tolerance_outer, double Rin, double Rout,
219-
double x_mid, double y_mid, double z_stave_shift_abs)
211+
std::array<std::array<double, 3>, 4> buildStaveTriangle(int direction)
220212
{
221213
// Set some constants for readability
222214
double d = Constants::effectiveCarbonThickness_Stave;
@@ -234,7 +226,7 @@ void FT3Module::addStaveVolume(
234226
* 4. Translate the volume to the given position (arguments)
235227
*
236228
*/
237-
double xv_inner[3], xv_outer[3], zv_inner[3], zv_outer[3];
229+
std::array<double, 3> xv_inner, xv_outer, zv_inner, zv_outer;
238230
// calculate the coordinates of the triangle vertices
239231
// Top/bottom vertex (apex)
240232
xv_outer[0] = 0;
@@ -263,46 +255,68 @@ void FT3Module::addStaveVolume(
263255
zv_inner[2] = zv_inner[1];
264256
xv_inner[2] = -xv_inner[1];
265257

258+
return {xv_outer, zv_outer, xv_inner, zv_inner};
259+
}
260+
261+
/*
262+
* This function creates a carbon fibre volume for the stave,
263+
* onto which the sensor and its support will be glued.
264+
*/
265+
void FT3Module::addStaveVolume(
266+
TGeoVolume* motherVolume, std::string volumeName, int direction,
267+
unsigned* volume_count, double staveLength,
268+
std::array<std::array<double, 3>, 4> staveTriangles,
269+
std::pair<double, double>& absAllowedYRange,
270+
double x_mid, double y_mid, double z_stave_shift_abs)
271+
{
272+
// The allowed y range is assumed to be non-negative.
273+
if (absAllowedYRange.first < 0 || absAllowedYRange.second < 0 ||
274+
absAllowedYRange.first >= absAllowedYRange.second) {
275+
LOG(error) << "Invalid allowed y range in addStaveVolume(): ("
276+
<< absAllowedYRange.first << ", " << absAllowedYRange.second
277+
<< "). Both values must be non-negative and the first "
278+
<< "value must be less than the second value.";
279+
return;
280+
}
281+
// Set the lower and upper y values of the stave:
282+
double y_lower = y_mid - staveLength / 2;
283+
double y_upper = y_mid + staveLength / 2;
284+
bool splitStave = false;
285+
if (y_lower > 0) { // This stave is fully above x-axis
286+
y_lower = std::max(y_lower, absAllowedYRange.first);
287+
y_upper = std::min(y_upper, absAllowedYRange.second);
288+
} else if (y_upper < 0) { // stave entirely below x-axis
289+
y_lower = std::max(y_lower, -absAllowedYRange.second);
290+
y_upper = std::min(y_upper, -absAllowedYRange.first);
291+
} else { // Full range stave that goes across x-axis
292+
// Here we might have to cut the stave up into two pieces
293+
if (absAllowedYRange.first > 0) {
294+
// There is a minimum inner value --> Split stave
295+
splitStave = true;
296+
y_lower = absAllowedYRange.first;
297+
} else {
298+
// regular stave, use full length, but don't forget outer cut
299+
y_lower = std::max(y_lower, -absAllowedYRange.second);
300+
}
301+
y_upper = std::min(y_upper, absAllowedYRange.second);
302+
}
303+
double staveLengthToUse = y_upper - y_lower;
266304
/*
267305
* create the extruded volumes from z=0 (later y=0 after rotation) to stave length
268306
* and not from midpoint - staveLength/2 to midpoint + staveLength/2, translate later
269307
*
270308
* Note also that we first need to check if the length is allowed given the inner
271309
* and outer radius of the layer.
272310
*/
273-
double x_left = x_mid - Constants::single_sensor_width;
274-
double x_right = x_mid + Constants::single_sensor_width;
275-
std::pair<double, double> absAllowedYRange =
276-
calculate_y_range(x_left, x_right, Rin, Rout);
277-
278-
// shift allowed range by tolerance. Note that this sum can be negative, but
279-
// that is not a problem, it just means that we can always place staves over the edge
280-
absAllowedYRange.first += tolerance_inner;
281-
absAllowedYRange.second -= tolerance_outer;
282-
283-
double maxStaveLength = absAllowedYRange.second - absAllowedYRange.first;
284-
double staveLengthToUse = std::min(staveLength, maxStaveLength);
285-
if (staveLengthToUse <= 0) {
286-
LOG(warning) << "Stave " << volumeName << " has non-positive length after applying "
287-
<< "tolerance, skipping stave. Max allowed length: " << maxStaveLength
288-
<< " tolerance inner: " << tolerance_inner
289-
<< " tolerance outer: " << tolerance_outer;
290-
return;
291-
}
292-
double staveLengthDiff = staveLength - staveLengthToUse;
293-
if (staveLengthDiff > 0) { // had to cut it, hence y_mid must move too
294-
y_mid = absAllowedYRange.first + staveLengthToUse / 2;
295-
}
296-
297311
TGeoXtru* staveFull = new TGeoXtru(2);
298312
staveFull->SetName(( volumeName + "_Xtru_outer").c_str());
299-
staveFull->DefinePolygon(3, xv_outer, zv_outer);
313+
staveFull->DefinePolygon(3, staveTriangles[0].data(), staveTriangles[1].data());
300314
staveFull->DefineSection(0, 0);
301315
staveFull->DefineSection(1, staveLengthToUse);
302316

303317
TGeoXtru* staveInner = new TGeoXtru(2);
304318
staveInner->SetName(( volumeName + "_Xtru_inner").c_str());
305-
staveInner->DefinePolygon(3, xv_inner, zv_inner);
319+
staveInner->DefinePolygon(3, staveTriangles[2].data(), staveTriangles[3].data());
306320
staveInner->DefineSection(0, 0);
307321
staveInner->DefineSection(1, staveLengthToUse);
308322

@@ -323,14 +337,29 @@ void FT3Module::addStaveVolume(
323337
* We still need to shift it in z to get the right staggered layout.
324338
* This means moving the staves that must be shifted in the opposite
325339
* direction they are facing: up for direction 1, and down for direction 0.
340+
*
341+
* Unlike a regular node placement, we have to put the stave at its
342+
* starting point in y, not the midpoint. Hence, if we have the mirror,
343+
* the starting point is the upper y value, since that is the bottom
344+
* of the mirrored stave -- by the outer radius
326345
*/
327346
double z_shift = (direction == 1) ? z_stave_shift_abs : -z_stave_shift_abs;
328347
TGeoCombiTrans* combiTrans =
329-
new TGeoCombiTrans(x_mid, y_mid - staveLengthToUse / 2, z_shift, rot);
348+
new TGeoCombiTrans(x_mid, y_lower, z_shift, rot);
330349
motherVolume->AddNode(staveVolume,
331350
*volume_count,
332351
combiTrans);
333352
(*volume_count)++;
353+
354+
// if the stave needs to be split, reuse the same volume on opposite side
355+
if (splitStave) {
356+
TGeoCombiTrans* combiTransSplit =
357+
new TGeoCombiTrans(x_mid, -y_upper, z_shift, rot);
358+
motherVolume->AddNode(staveVolume,
359+
*volume_count,
360+
combiTransSplit);
361+
(*volume_count)++;
362+
}
334363
}
335364

336365
/*
@@ -520,6 +549,8 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction
520549
// initialise all y_positions, vector over all staves/columns
521550
std::vector<PosNegPositionTypes> y_positionsPosNeg;
522551
unsigned volume_count = 0; // give each subvolume a unique ID
552+
// stave triangle cross sections are the same for every stave (direction based)
553+
std::array<std::array<double, 3>, 4> staveTriangles = buildStaveTriangle(direction);
523554
// Create the stave volumes and fill the y positions where to put sensors on the stave
524555
for (unsigned i_stave = 0; i_stave < Constants::x_midpoints.size(); i_stave++) {
525556
y_positionsPosNeg.emplace_back(PosNegPositionTypes{PositionTypes{}, PositionTypes{}});
@@ -552,18 +583,6 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction
552583
tolerance_outer = 0.;
553584
}
554585

555-
// Get whether the stave is shifted backward or not
556-
double z_stave_shift_abs = Constants::staveOnFront[i_stave] ? 0 : Constants::z_offsetStave;
557-
// now create the stave volume
558-
std::string stave_volume_name =
559-
"Stave_" + std::to_string(i_stave) + "_" + std::to_string(layerNumber) +
560-
"_" + std::to_string(direction);
561-
addStaveVolume(
562-
motherVolume, stave_volume_name, direction, &volume_count,
563-
Constants::y_lengths[i_stave], tolerance_inner, tolerance_outer,
564-
Rin, Rout, Constants::x_midpoints[i_stave],
565-
y_midpoint, mZ + z_stave_shift_abs
566-
);
567586
/*
568587
* There are three cases in which we want to mirror the stave around the x-axis,
569588
* which correspond to the stave not going fully from + to - Rout in y.
@@ -575,28 +594,51 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction
575594
*/
576595
double x_left = Constants::x_midpoints[i_stave] - Constants::sensor2x1_width / 2;
577596
double x_right = x_left + Constants::sensor2x1_width;
578-
bool mirrorStaveAroundXAxis = false;
579-
if (tolerance_inner >= 0) {
580-
double x_innermost = std::min(std::abs(x_left), std::abs(x_right));
581-
mirrorStaveAroundXAxis = (x_innermost < Rin);
582-
} else { // Have negative tolerance, so can place staves as wished
583-
mirrorStaveAroundXAxis = (y_midpoint > Rin);
597+
std::pair<double, double> absAllowedYRange =
598+
calculate_y_range(x_left, x_right, Rin, Rout);
599+
600+
/*
601+
* Shift allowed range by tolerance. Note that both values in the range must
602+
* be non-negative, and if the inner is not, then set it to 0. This just means
603+
* that there is no lower limit. The upper limit must however be larger than 0,
604+
* if it is not, then skip this stave and give a warning.
605+
*/
606+
absAllowedYRange.first += tolerance_inner;
607+
absAllowedYRange.second -= tolerance_outer;
608+
609+
if (absAllowedYRange.first < 0) {
610+
absAllowedYRange.first = 0;
584611
}
612+
if (absAllowedYRange.second <= 0) {
613+
LOG(warning) << "For stave " << i_stave << " in layer " << layerNumber
614+
<< " with direction " << direction << ": no space to place sensors after applying tolerances, skipping stave.";
615+
continue;
616+
}
617+
618+
// Get whether the stave is shifted backward or not before creating
619+
double z_stave_shift_abs = Constants::staveOnFront[i_stave] ? 0 : Constants::z_offsetStave;
620+
std::string stave_volume_name =
621+
"Stave_" + std::to_string(i_stave) + "_" + std::to_string(layerNumber) +
622+
"_" + std::to_string(direction);
623+
addStaveVolume(
624+
motherVolume, stave_volume_name, direction, &volume_count,
625+
Constants::y_lengths[i_stave], staveTriangles, absAllowedYRange,
626+
Constants::x_midpoints[i_stave], y_midpoint, mZ + z_stave_shift_abs
627+
);
585628
// Now create the mirrored stave
586-
if (mirrorStaveAroundXAxis) {
629+
if (mirrorStaveAroundX) {
587630
addStaveVolume(
588631
motherVolume, stave_volume_name + "_mirrored", direction, &volume_count,
589-
Constants::y_lengths[i_stave], tolerance_inner, tolerance_outer,
590-
Rin, Rout, Constants::x_midpoints[i_stave],
591-
-y_midpoint, mZ + z_stave_shift_abs
632+
Constants::y_lengths[i_stave], staveTriangles, absAllowedYRange,
633+
Constants::x_midpoints[i_stave], -y_midpoint, mZ + z_stave_shift_abs
592634
);
593635
}
594636

595637
// now add the sensor positions on the stave
596638
for (unsigned i_kSens = 0; i_kSens < Constants::kSensorsPerStack.size(); i_kSens++) {
597639
fill_stave(y_positionsPosNeg.back(), Rin, Rout, x_left,
598-
Constants::kSensorsPerStack[i_kSens], tolerance_inner,
599-
tolerance_outer, y_ranges);
640+
Constants::kSensorsPerStack[i_kSens], y_ranges,
641+
absAllowedYRange);
600642
}
601643
}
602644

0 commit comments

Comments
 (0)