@@ -150,22 +150,14 @@ std::pair<double, double> calculate_y_range(
150150 * for positive and negative y respectively
151151 */
152152void 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