ATLAS Offline Software
Loading...
Searching...
No Matches
EMECAccordionConstruction.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2024-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// EMECAccordionConstruction
6// Construct internal structure of the EMEC Inner and Outer Wheels
7
8// Revision history:
9// 24-Jan-2024 Evgueni Tcherniaev: Initial version
10
11#include <cmath>
12#include <iostream>
13
15
16#include "GeoModelKernel/GeoElement.h"
17#include "GeoModelKernel/GeoMaterial.h"
18#include "GeoModelKernel/GeoFullPhysVol.h"
19#include "GeoModelKernel/GeoPhysVol.h"
20#include "GeoModelKernel/GeoVPhysVol.h"
21#include "GeoModelKernel/GeoLogVol.h"
22#include "GeoModelKernel/GeoBox.h"
23#include "GeoModelKernel/GeoCons.h"
24#include "GeoModelKernel/GeoPcon.h"
25#include "GeoModelKernel/GeoGenericTrap.h"
26#include "GeoModelKernel/GeoNameTag.h"
27#include "GeoModelKernel/GeoTransform.h"
28#include "GeoModelKernel/GeoIdentifierTag.h"
29#include "GeoModelKernel/Units.h"
30
34
36#include "GaudiKernel/MsgStream.h"
37#include "GaudiKernel/ISvcLocator.h"
38#include "GaudiKernel/PhysicalConstants.h"
39#include "GaudiKernel/StatusCode.h"
43
44#define SI GeoModelKernelUnits
45
47//
48// Set parameters for accordion structure construction
49//
51{
52 ISvcLocator *svcLocator = Gaudi::svcLocator();
53 SmartIF<StoreGateSvc> detStore{svcLocator->service("DetectorStore")};
54 if(!detStore.isValid()) {
55 throw std::runtime_error("Error in EndcapCryostatConstruction, cannot access DetectorStore");
56 }
57
58 // Get GeoModelSvc and RDBAccessSvc
59
60 SmartIF<IRDBAccessSvc> rdbAccess{svcLocator->service("RDBAccessSvc")};
61 if(!rdbAccess.isValid()){
62 throw std::runtime_error("EMECConstruction: cannot locate RDBAccessSvc!");
63 }
64
65 SmartIF<IGeoModelSvc> geoModelSvc{svcLocator->service("GeoModelSvc")};
66 if(!geoModelSvc.isValid()) {
67 throw std::runtime_error("EMECAccordionConstruction: cannot locate GeoModelSvc!");
68 }
69
70 DecodeVersionKey larVersionKey(geoModelSvc, "LAr");
71 IRDBRecordset_ptr DB_EmecGeometry = rdbAccess->getRecordsetPtr("EmecGeometry", larVersionKey.tag(), larVersionKey.node());
72 if(DB_EmecGeometry->size() == 0){
73 DB_EmecGeometry = rdbAccess->getRecordsetPtr("EmecGeometry", "EmecGeometry-00");
74 }
75
76 IRDBRecordset_ptr emecWheelParameters = rdbAccess->getRecordsetPtr("EmecWheelParameters", larVersionKey.tag(), larVersionKey.node());
77 if(emecWheelParameters->size() == 0){
78 emecWheelParameters = rdbAccess->getRecordsetPtr("EmecWheelParameters", "EmecWheelParameters-00");
79 }
80
81
82 IRDBRecordset_ptr emecMagicNumbers = rdbAccess->getRecordsetPtr("EmecMagicNumbers", larVersionKey.tag(), larVersionKey.node());
83 if(emecMagicNumbers->size() == 0){
84 emecMagicNumbers = rdbAccess->getRecordsetPtr("EmecMagicNumbers", "EmecMagicNumbers-00");
85 }
86
87 IRDBRecordset_ptr coldContraction = rdbAccess->getRecordsetPtr("ColdContraction", larVersionKey.tag(), larVersionKey.node());
88 if(coldContraction->size() == 0){
89 coldContraction = rdbAccess->getRecordsetPtr("ColdContraction", "ColdContraction-00");
90 }
91
92 IRDBRecordset_ptr emecFan = rdbAccess->getRecordsetPtr("EmecFan", larVersionKey.tag(), larVersionKey.node());
93 if(emecFan->size() == 0){
94 emecFan = rdbAccess->getRecordsetPtr("EmecFan", "EmecFan-00");
95 }
96
97
98 // Inner wheel accordion wave parameters
99 m_innerNoAbsorbes = (*emecWheelParameters)[0]->getInt("NABS"); // 256
100 m_innerNoElectrodes = (*emecWheelParameters)[0]->getInt("NABS"); // 256
101 m_innerNoWaves = (*emecWheelParameters)[0]->getInt("NACC"); // 6
102
103 m_innerLipWidth = (*emecMagicNumbers)[0]->getDouble("STRAIGHTSTARTSECTION") * SI::mm; // 2 mm
104 m_innerWaveZoneWidth = (*emecMagicNumbers)[0]->getDouble("ACTIVELENGTH") * SI::mm; // 510 mm
109
110 // Check values
111 if (m_innerNoAbsorbes != 256) {
112 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setWheelParameters: wrong number of absorbers. (NABS = " + std::to_string( m_innerNoAbsorbes) + ") for Inner Wheel, expected 256!");
113 }
114 if (m_innerNoWaves != 6) {
115 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setWheelParameters: wrong number of waves. (NACC = " + std::to_string( m_innerNoAbsorbes ) + ") for Inner Wheel, expected 6!");
116 }
117 if (m_innerLipWidth != 2 * SI::mm) {
118 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setWheelParameters: wrong width of absorber lips. (STRAIGHTSTARTSECTION = " + std::to_string( m_innerNoAbsorbes/SI::mm) + "), expected 2 mm!" );
119 }
120 if (m_innerWaveZoneWidth != 510 * SI::mm) {
121 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setWheelParameters: wrong width of absorber active zone. (ACTIVELENGTH = " + std::to_string(m_innerWaveZoneWidth/SI::mm) + "), expected 510 mm!");
122 }
123
124 // Outer wheel accordion wave parameters
125 m_outerNoAbsorbes = (*emecWheelParameters)[1]->getInt("NABS"); // 768
126 m_outerNoElectrodes = (*emecWheelParameters)[1]->getInt("NABS"); // 768
127 m_outerNoWaves = (*emecWheelParameters)[1]->getInt("NACC"); // 9
128
135
136 // Check values
137 if (m_outerNoAbsorbes != 768) {
138 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setWheelParameters: wrong number of absorbers. (NABS = " + std::to_string (m_outerNoAbsorbes) + ") for Outer Wheel, expected 768!");
139 }
140 if (m_outerNoWaves != 9) {
141 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setWheelParameters: wrong number of waves. (NACC = " + std::to_string(m_outerNoAbsorbes) + ") for Outer Wheel, expected 9!" );
142 }
143
144 // Inner wheel thiknesses
145 m_innerLeadThickness = (*emecFan)[0]->getDouble("LEADTHICKNESSINNER") * SI::mm; // 2.2 mm
146 m_innerSteelThickness = (*emecFan)[0]->getDouble("STEELTHICKNESS") * SI::mm; // 0.2 mm
147 m_innerGlueThickness = (*emecFan)[0]->getDouble("GLUETHICKNESS") * SI::mm; // 0.1 mm (TRD: 0.15 mm)
148 m_innerElectrodeThickness = (*emecFan)[0]->getDouble("ELECTRODETOTALTHICKNESS") * SI::mm; // 0.275 mm
149
150 // Outer wheel thiknesses
151 m_outerLeadThickness = (*emecFan)[0]->getDouble("LEADTHICKNESSOUTER") * SI::mm; // 1.69 mm (TRD: 1.7 mm)
155
156 // E.T. notes:
157 // 1. In LArCustomShapeExtensionSolid.cxx the contraction factor was equal to 0.991, here 0.997
158 // 2. There is a discrepancy between specified thickness of glue (0.1 mm) and its value in TDR (0.15 mm)
159 // 3. There is a discrepancy between specified thickness of lead in the outer wheel (1.69 mm) and its value in TDR (1.7 mm)
160 // 4. Application of the contraction factor to the thicknesses (?) is under question
161 // 5. Materials are specified at room temperature (?) instead of LAr temperature
162 // 6. Iron (?) is used instead of Steel in absorbers
163 //
164 // for more information see:
165 // https://indico.cern.ch/event/1236615/contributions/5313135/attachments/2610372/4509836/2023.03.13-EMEC_discrepancies.pdf
166
167 // Contraction factor
168 m_kContraction = (*coldContraction)[0]->getDouble("ABSORBERCONTRACTION"); // 0.997, in LArCustomShapeExtensionSolid.cxx was 0.991
169
170 // Applying contraction factor to thicknesses (?)
175
180
181 // 1./eleInvContraction = 0.99639
182 double eleInvContraction = (*coldContraction)[0]->getDouble("ELECTRODEINVCONTRACTION"); // 1.0036256
183 m_innerElectrodeThickness /= eleInvContraction;
184 m_outerElectrodeThickness /= eleInvContraction;
185}
186
188//
189// Set pointer to Inner Wheeel envelope
190//
192{
193 m_innerWheel = innerWheel;
194 const GeoShape* shape = innerWheel->getLogVol()->getShape();
195 if (shape->type() != "Pcon") {
196 throw std::runtime_error( "LArGeo::EMECAccordionConstruction::setInnerWheel: unexpected shape type '"+ shape->type() + "', expected 'Pcon'!");
197 }
198 const GeoPcon* pcon = static_cast<const GeoPcon*>(shape);
199 auto nplanes = pcon->getNPlanes();
200 if (nplanes != 2) {
201 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setInnerWheel: wrong number of Z planes '" + std::to_string(nplanes) + "', expected '2'!");
202 }
203 for (unsigned int i = 0; i < nplanes; ++i)
204 {
205 m_zWheelInner[i] = pcon->getZPlane(i);
206 m_rMinInner[i] = pcon->getRMinPlane(i);
207 m_rMaxInner[i] = pcon->getRMaxPlane(i);
208 }
209 // Set Inner Wheel base name
210 m_nameInnerWheel = innerWheel->getLogVol()->getName();
211}
212
214//
215// Set pointer to Outer Wheeel envelope
216//
218{
219 m_outerWheel = outerWheel;
220 const GeoShape* shape = outerWheel->getLogVol()->getShape();
221 if (shape->type() != "Pcon") {
222 throw std::runtime_error( "LArGeo::EMECAccordionConstruction::setOuterWheel: unexpected shape type '"+ shape->type() + "', expected 'Pcon'!");
223
224 }
225 const GeoPcon* pcon = static_cast<const GeoPcon*>(shape);
226 auto nplanes = pcon->getNPlanes();
227 if (nplanes != 3) {
228 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setOuterWheel: wrong number of Z planes" + std::to_string(nplanes) + "', expected '3'!" );
229 }
230 for (unsigned int i = 0; i < nplanes; ++i)
231 {
232 m_zWheelOuter[i] = pcon->getZPlane(i);
233 m_rMinOuter[i] = pcon->getRMinPlane(i);
234 m_rMaxOuter[i] = pcon->getRMaxPlane(i);
235 }
236 // Set Outer Wheel base name
237 m_nameOuterWheel = outerWheel->getLogVol()->getName();
238}
239
241//
242// Set Inner wheel slices: (lip)(quater_wave)(11 half_waves)(quater_wave)(lip)
243//
245{
246 if (!m_innerWheel)
247 {
248 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setInnerWheelSlices: Inner Wheel volume is not set!" );
249 }
250 // Compute slices
255
259 for (int i = 3; i < s_innerNoBlades - 1; ++i)
260 {
262 }
265 for (int i = 0; i < s_innerNoBlades + 1; ++i)
266 {
269 }
270}
271
273//
274// Set Outer wheel slices (lip)(quater_wave)(15_half_waves)(quater_wave)(lip)
275//
277{
278 if (!m_outerWheel)
279 {
280 throw std::runtime_error( "LArGeo::EMECAccordionConstruction::setOuterWheelSlices: Outer Wheel volume is not set!");
281 }
282 // Compute slices
289
293 for (int i = 3; i < s_outerNoBlades - 1; ++i)
294 {
296 }
299 for (int i = 0; i < s_outerNoBlades + 1; ++i)
300 {
303 if (m_outerWheelRmax[i] > m_rMaxOuter[2]) m_outerWheelRmax[i] = m_rMaxOuter[2]; // 2034 mm starting from i = 3
304 }
305}
306
308//
309// Set material
310//
311void
313 const GeoMaterial* material)
314{
315 if (name == "LiquidArgon") m_materialLiquidArgon = material;
316 else if (name == "Kapton") m_materialKapton = material;
317 else if (name == "Lead" ) m_materialLead = material;
318 else if (name == "Steel" ) m_materialSteel = material;
319 else if (name == "Glue" ) m_materialGlue = material;
320 else
321 {
322 throw std::runtime_error("LArGeo::EMECAccordionConstruction::setMaterial: unexpected material name '" + name + "'!");
323 }
324}
325
327//
328// Get Inner absorber data from technical information
329//
330void
332 double& llip1, double& ylip1,
333 double& llip2, double& ylip2) const
334{
335 // Points taken from technical drawing
336 GeoTwoVector A[14+1] = {}; // A[0] is not used
337 A[1] = GeoTwoVector( 1.700, 1019.908) * SI::mm;
338 A[2] = GeoTwoVector( 36.595, 1022.643) * SI::mm;
339 A[3] = GeoTwoVector(110.351, 1024.416) * SI::mm;
340 A[4] = GeoTwoVector(184.545, 1020.841) * SI::mm;
341 A[5] = GeoTwoVector(258.785, 1011.865) * SI::mm;
342 A[6] = GeoTwoVector(332.678, 997.463) * SI::mm;
343 A[7] = GeoTwoVector(405.824, 977.640) * SI::mm;
344 A[8] = GeoTwoVector(477.824, 952.430) * SI::mm;
345 A[9] = GeoTwoVector(548.280, 921.895) * SI::mm;
346 A[10] = GeoTwoVector(616.797, 886.130) * SI::mm;
347 A[11] = GeoTwoVector(682.985, 845.257) * SI::mm;
348 A[12] = GeoTwoVector(746.463, 799.426) * SI::mm;
349 A[13] = GeoTwoVector(806.859, 748.819) * SI::mm;
350 A[14] = GeoTwoVector(835.788, 723.065) * SI::mm;
351
352 GeoTwoVector B[14+1] = {}; // B[0] is not used
353 B[1] = GeoTwoVector( 1.132, 710.702) * SI::mm;
354 B[2] = GeoTwoVector( 25.476, 711.930) * SI::mm;
355 B[3] = GeoTwoVector( 76.670, 711.749) * SI::mm;
356 B[4] = GeoTwoVector(127.967, 707.873) * SI::mm;
357 B[5] = GeoTwoVector(179.099, 700.288) * SI::mm;
358 B[6] = GeoTwoVector(229.797, 688.988) * SI::mm;
359 B[7] = GeoTwoVector(279.791, 674.025) * SI::mm;
360 B[8] = GeoTwoVector(328.814, 655.414) * SI::mm;
361 B[9] = GeoTwoVector(376.600, 633.227) * SI::mm;
362 B[10] = GeoTwoVector(422.886, 607.546) * SI::mm;
363 B[11] = GeoTwoVector(467.418, 578.473) * SI::mm;
364 B[12] = GeoTwoVector(509.946, 546.127) * SI::mm;
365 B[13] = GeoTwoVector(550.228, 510.649) * SI::mm;
366 B[14] = GeoTwoVector(568.629, 492.593) * SI::mm;
367
368 GeoTwoVector C[4+1] = {}; // C[0] is not used
369 C[1] = GeoTwoVector( -1.754, 978.281) * SI::mm;
370 C[2] = GeoTwoVector( 1.668, 978.279) * SI::mm;
371 C[3] = GeoTwoVector(803.643, 696.378) * SI::mm;
372 C[4] = GeoTwoVector(805.917, 693.745) * SI::mm;
373
374 GeoTwoVector D[4+1] = {}; // D[0] is not used
375 D[1] = GeoTwoVector( -1.894, 786.281) * SI::mm;
376 D[2] = GeoTwoVector( 1.186, 786.279) * SI::mm;
377 D[3] = GeoTwoVector(610.986, 529.319) * SI::mm;
378 D[4] = GeoTwoVector(613.041, 526.940) * SI::mm;
379
380 // Compute angle between rays
381 int k1 = 2, k2 = 13; // take rays 2 and 13
382 double cosa = A[k1].dot(A[k2])/(A[k1].norm()*A[k2].norm());
383 double ang = std::acos(cosa)/(k2 - k1);
384
385 // Compute bottom and top width of the accordion blade
386 double rmin = B[1].norm();
387 double rmax = A[14].norm();
388 wmin = 2.*rmin*std::sin(ang/2.);
389 wmax = 2.*rmax*std::sin(ang/2.);
390
391 // Compute length and position of the first lip
392 llip1 = (C[2] - D[2]).norm();
393 ylip1 = (D[2] - B[1]).norm() + llip1/2.;
394
395 // Compute length and position of the last lip
396 llip2 = (C[3] - D[3]).norm();
397 ylip2 = (D[3] - B[14]).norm() + llip2/2.;
398}
399
401//
402// Get Outer absorber data from technical information
403//
404void
406 double& llip1, double& ylip1,
407 double& llip2, double& ylip2) const
408{
409 // Points taken from technical drawing
410 GeoTwoVector A[20+1] = {}; // A[0] is not used
411 A[1] = GeoTwoVector( 1.773, 3438.343) * SI::mm;
412 A[2] = GeoTwoVector( 26.515, 3445.688) * SI::mm;
413 A[3] = GeoTwoVector( 79.893, 3460.218) * SI::mm;
414 A[4] = GeoTwoVector(133.523, 3468.701) * SI::mm;
415 A[5] = GeoTwoVector(186.888, 3466.236) * SI::mm;
416 A[6] = GeoTwoVector(240.209, 3462.949) * SI::mm;
417 A[7] = GeoTwoVector(293.473, 3458.842) * SI::mm;
418 A[8] = GeoTwoVector(346.668, 3453.916) * SI::mm;
419 A[9] = GeoTwoVector(399.780, 3448.172) * SI::mm;
420 A[10] = GeoTwoVector(452.798, 3441.612) * SI::mm;
421 A[11] = GeoTwoVector(505.708, 3434.236) * SI::mm;
422 A[12] = GeoTwoVector(558.499, 3426.047) * SI::mm;
423 A[13] = GeoTwoVector(611.157, 3417.046) * SI::mm;
424 A[14] = GeoTwoVector(663.670, 3407.236) * SI::mm;
425 A[15] = GeoTwoVector(716.027, 3396.619) * SI::mm;
426 A[16] = GeoTwoVector(768.214, 3385.198) * SI::mm;
427 A[17] = GeoTwoVector(820.219, 3372.975) * SI::mm;
428 A[18] = GeoTwoVector(872.029, 3359.953) * SI::mm;
429 A[19] = GeoTwoVector(923.633, 3346.135) * SI::mm;
430 A[20] = GeoTwoVector(947.625, 3339.413) * SI::mm;
431
432 GeoTwoVector B[20+1] = {}; // B[0] is not used
433 B[1] = GeoTwoVector( 0.810, 2046.995) * SI::mm;
434 B[2] = GeoTwoVector( 15.769, 2049.165) * SI::mm;
435 B[3] = GeoTwoVector( 47.410, 2053.375) * SI::mm;
436 B[4] = GeoTwoVector( 79.185, 2057.095) * SI::mm;
437 B[5] = GeoTwoVector(111.086, 2060.323) * SI::mm;
438 B[6] = GeoTwoVector(143.105, 2063.055) * SI::mm;
439 B[7] = GeoTwoVector(175.234, 2065.288) * SI::mm;
440 B[8] = GeoTwoVector(207.466, 2067.020) * SI::mm;
441 B[9] = GeoTwoVector(239.792, 2068.248) * SI::mm;
442 B[10] = GeoTwoVector(272.205, 2068.969) * SI::mm;
443 B[11] = GeoTwoVector(304.697, 2069.181) * SI::mm;
444 B[12] = GeoTwoVector(337.260, 2068.883) * SI::mm;
445 B[13] = GeoTwoVector(369.885, 2068.071) * SI::mm;
446 B[14] = GeoTwoVector(402.566, 2066.744) * SI::mm;
447 B[15] = GeoTwoVector(435.293, 2064.899) * SI::mm;
448 B[16] = GeoTwoVector(468.058, 2062.536) * SI::mm;
449 B[17] = GeoTwoVector(500.853, 2059.653) * SI::mm;
450 B[18] = GeoTwoVector(533.670, 2056.247) * SI::mm;
451 B[19] = GeoTwoVector(566.501, 2052.318) * SI::mm;
452 B[20] = GeoTwoVector(582.048, 2050.271) * SI::mm;
453
454 GeoTwoVector C[4+1] = {}; // C[0] is not used
455 C[1] = GeoTwoVector( -1.682, 3416.858) * SI::mm;
456 C[2] = GeoTwoVector( 1.756, 3416.858) * SI::mm;
457 C[3] = GeoTwoVector(932.782, 3287.070) * SI::mm;
458 C[3] = GeoTwoVector(936.090, 3286.130) * SI::mm;
459
460 GeoTwoVector D[4+1] = {}; // D[0] is not used
461 D[1] = GeoTwoVector( -1.975, 2088.411) * SI::mm;
462 D[2] = GeoTwoVector( 0.839, 2088.410) * SI::mm;
463 D[3] = GeoTwoVector(593.526, 2090.743) * SI::mm;
464 D[4] = GeoTwoVector(596.271, 2089.963) * SI::mm;
465
466 // Compute angle between rays
467 int k1 = 4, k2 = 19; // take rays 4 and 19
468 double cosa = A[k1].dot(A[k2])/(A[k1].norm()*A[k2].norm());
469 double ang = std::acos(cosa)/(k2 - k1);
470
471 // Compute bottom and top width of the accordion blade
472 double rmin = B[1].norm();
473 double rmax = A[19].norm(); // A[19] has slightly bigger radius than A[20]
474 wmin = 2.*rmin*std::sin(ang/2.);
475 wmax = 2.*rmax*std::sin(ang/2.);
476
477 // Compute length and position of the first lip
478 llip1 = (C[2] - D[2]).norm();
479 ylip1 = (D[2] - B[1]).norm() + llip1/2.;
480
481 // Compute length and position of the last lip
482 llip2 = (C[3] - D[3]).norm();
483 ylip2 = (D[3] - B[20]).norm() + llip2/2.;
484}
485
487//
488// Compute uncut Blade corners
489//
490void
491LArGeo::EMECAccordionConstruction::getBladeCorners(double wmin, double wmax, double thickness,
492 double rmin, double rmax, double zdel,
493 GeoThreeVector corners[8]) const
494{
495 double z = zdel/2.;
496
497 double xmin = std::sqrt(wmin*wmin - zdel*zdel)/2.;
498 double dxmin = (thickness/2.)*(wmin/zdel);
499 double ymin = rmin;
500
501 double xmax = std::sqrt(wmax*wmax - zdel*zdel)/2.;
502 double dxmax = (thickness/2.)*(wmax/zdel);
503 double xtmp = (xmax + dxmax);
504 double ymax = std::sqrt(rmax*rmax - xtmp*xtmp);
505
506 corners[0] = GeoThreeVector(-xmin + dxmin, ymin, -z);
507 corners[1] = GeoThreeVector(-xmin - dxmin, ymin, -z);
508 corners[2] = GeoThreeVector(-xmax - dxmax, ymax, -z);
509 corners[3] = GeoThreeVector(-xmax + dxmax, ymax, -z);
510
511 corners[4] = GeoThreeVector(+xmin + dxmin, ymin, +z);
512 corners[5] = GeoThreeVector(+xmin - dxmin, ymin, +z);
513 corners[6] = GeoThreeVector(+xmax - dxmax, ymax, +z);
514 corners[7] = GeoThreeVector(+xmax + dxmax, ymax, +z);
515}
516
518//
519// Compute cut plane for bottom of Blade
520//
523 double zmax, double rmax) const
524{
525 GeoThreeVector pmin(0, rmin, zmin);
526 GeoThreeVector pmax(0, rmax, zmax);
527 GeoThreeVector v = (pmax - pmin).normalized();
528
530 plane.m_n = GeoThreeVector(0., -v.z(), v.y());
531 plane.m_d = -plane.m_n.dot(pmin);
532 return plane;
533}
534
536//
537// Compute cut plane for top of Blade
538//
541 double zmax, double rmax,
542 const GeoThreeVector corners[8]) const
543{
544 GeoThreeVector pbot(std::min(corners[0].x(), corners[1].x()), corners[0].y(), 0);
545 GeoThreeVector ptop(std::min(corners[2].x(), corners[3].x()), corners[3].y(), 0);
546
547 GeoThreeVector v = (ptop - pbot).normalized();
548 double d = v.x()*pbot.y() - v.y()*pbot.x();
549 double r = ptop.norm();
550 double l = std::sqrt(r*r - d*d);
551 double wmin = std::sqrt(rmin*rmin - d*d);
552 double wmax = std::sqrt(rmax*rmax - d*d);
553 double ymin = ptop.y() - v.y()*(l - wmin);
554 double ymax = ptop.y() - v.y()*(l - wmax);
555
556 GeoThreeVector pmin(0, ymin, zmin);
557 GeoThreeVector pmax(0, ymax, zmax);
558 v = (pmax - pmin).normalized();
559
561 plane.m_n = GeoThreeVector(0., -v.z(), v.y());
562 plane.m_d = -plane.m_n.dot(pmin);
563 return plane;
564}
565
567//
568// Find intersection of line segment with plane
569//
572 const GeoThreeVector& p2,
574{
575 double d1 = plane.m_n.dot(p1) + plane.m_d;
576 double d2 = plane.m_n.dot(p2) + plane.m_d;
577 return (d2*p1 - d1*p2)/(d2 - d1);
578}
579
581//
582// Cut Blade and construct solid
583// icase = 1 - first quater-wave, negative inclination
584// icase = 2 - half-wave, positive inclination
585// icase = 3 - half-wave, negative inclination
586// icase = 4 - last quater-wave, positive inclination
587//
588GeoShape*
590 const GeoThreeVector corners[8], double xscale,
591 double pz1, double pr1min, double pr1max,
592 double pz2, double pr2min, double pr2max) const
593{
594 double z1 = pz1, r1min = pr1min, r1max = pr1max;
595 double z2 = pz2, r2min = pr2min, r2max = pr2max;
596 if (icase == 1) // First quater-wave blade
597 {
598 z1 -= (z2 - z1);
599 r1min -= (r2min - r1min);
600 r1max -= (r2max - r1max);
601 }
602 if (icase == 4) // Last quater-wave blade
603 {
604 z2 += (z2 - z1);
605 r2min += (r2min - r1min);
606 r2max += (r2max - r1max);
607 }
608
609 // Prepare Blade for cutting
610 std::vector<GeoThreeVector> v3(8);
611 double kx = (icase == 2) ? 1 : -1; // set inclination
612
613 // Move Blade to required position
614 for (int i = 0; i < 8; ++i)
615 {
616 v3[i] = GeoThreeVector(kx*corners[i].x(), corners[i].y(), corners[i].z() + (z1 + z2)/2.);
617 }
618
619 // Change order vertices in case of negative inclination
620 if (kx < 0)
621 {
622 std::swap(v3[0],v3[1]);
623 std::swap(v3[2],v3[3]);
624 std::swap(v3[4],v3[5]);
625 std::swap(v3[6],v3[7]);
626 }
627
628 // Cut Blade by bottom plane
629 LArGeo::EMECAccordionConstruction::CutPlane botPlane = getBottomCutPlane(z1, r1min, z2, r2min);
630 v3[0] = IntersectionPoint(v3[0], v3[3], botPlane);
631 v3[1] = IntersectionPoint(v3[1], v3[2], botPlane);
632 v3[4] = IntersectionPoint(v3[4], v3[7], botPlane);
633 v3[5] = IntersectionPoint(v3[5], v3[6], botPlane);
634
635 // Cut Blade by top plane
636 LArGeo::EMECAccordionConstruction::CutPlane topPlane = getTopCutPlane(z1, r1max, z2, r2max, corners);
637 v3[3] = IntersectionPoint(v3[0], v3[3], topPlane);
638 v3[2] = IntersectionPoint(v3[1], v3[2], topPlane);
639 v3[7] = IntersectionPoint(v3[4], v3[7], topPlane);
640 v3[6] = IntersectionPoint(v3[5], v3[6], topPlane);
641
642 if (icase == 1) // First quater-wave blade
643 {
644 v3[0] = (v3[0] + v3[4])/2.;
645 v3[1] = (v3[1] + v3[5])/2.;
646 v3[2] = (v3[2] + v3[6])/2.;
647 v3[3] = (v3[3] + v3[7])/2.;
648 }
649
650 if (icase == 4) // Last quater-wave blade
651 {
652 v3[4] = (v3[0] + v3[4])/2.;
653 v3[5] = (v3[1] + v3[5])/2.;
654 v3[6] = (v3[2] + v3[6])/2.;
655 v3[7] = (v3[3] + v3[7])/2.;
656 }
657
658 // Construct GenericTrap solid
659 //
660 // +--------Z
661 // |
662 // | 3 +----------+ 7
663 // | 0 +------|---+ 4 |
664 // X | 2 +----------+ 6
665 // 1 +----------+ 5
666 //
667 std::vector<GeoTwoVector> v2(8);
668 for (int i = 0; i < 8; i += 2)
669 {
670 double xmid = (v3[i + 1].x() + v3[i].x())/2.;
671 double xdel = (v3[i + 1].x() - v3[i].x())*xscale/2.;
672 v2[i + 0] = GeoTwoVector(xmid - xdel, v3[i + 0].y());
673 v2[i + 1] = GeoTwoVector(xmid + xdel, v3[i + 1].y());
674 }
675 return new GeoGenericTrap((pz2 - pz1)/2., v2);
676}
677
679//
680// Construct Slices in Inner Wheel, set offsets
681//
683{
684 std::string name;
685 GeoShape* solid;
686 for (int islice = 0; islice < s_innerNoBlades; ++islice)
687 {
688 name = m_nameInnerWheel + m_nameSlice + m_nameSuffix[islice];
689 double dz = 0.5*(m_innerWheelZ[islice+1] - m_innerWheelZ[islice]);
690 solid = new GeoCons(m_innerWheelRmin[islice], m_innerWheelRmin[islice+1],
691 m_innerWheelRmax[islice], m_innerWheelRmax[islice+1],
692 dz, 0.*SI::deg, 360.*SI::deg);
693 m_innerSlice[islice] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialLiquidArgon));
694 m_innerSliceOffset[islice] = GeoThreeVector(0., 0., m_innerWheelZ[islice] + dz);
695 }
696}
697
699//
700// Construct Slices in Outer Wheel, set offsets
701//
703{
704 std::string name;
705 GeoShape* solid;
706 for (int islice = 0; islice < s_outerNoBlades; ++islice)
707 {
708 name = m_nameOuterWheel + m_nameSlice + m_nameSuffix[islice];
709 double dz = 0.5*(m_outerWheelZ[islice+1] - m_outerWheelZ[islice]);
710 solid = new GeoCons(m_outerWheelRmin[islice], m_outerWheelRmin[islice+1],
711 m_outerWheelRmax[islice], m_outerWheelRmax[islice+1],
712 dz, 0.*SI::deg, 360.*SI::deg);
713 m_outerSlice[islice] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialLiquidArgon));
714 m_outerSliceOffset[islice] = GeoThreeVector(0., 0., m_outerWheelZ[islice] + dz);
715 }
716}
717
719//
720// Construct Lips of Absorbers and Electrodes for Inner Wheel
721// Set offsets
722//
723void
725 double innerLipPosition1,
726 double innerLipLength2,
727 double innerLipPosition2)
728{
729 double dx, dy, dz, xoffset, yoffset, zoffset;
730 std::string name;
731 GeoShape* solid;
732
733 // Contruct logical volumes for 1st lip
734 int iblade = 0;
736 dy = 0.5*innerLipLength1;
737 dz = 0.5*m_innerLipWidth;
739 solid = new GeoBox(dx, dy, dz);
740 m_innerAbsorber[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialSteel));
741
742 name = m_nameInnerWheel + m_nameGlue + m_nameSuffix[iblade];
743 solid = new GeoBox(dx*m_innerGlueRatio, dy, dz);
744 m_innerGlue[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialGlue));
745
746 name = m_nameInnerWheel + m_nameLead + m_nameSuffix[iblade];
747 solid = new GeoBox(dx*m_innerLeadRatio, dy, dz);
748 m_innerLead[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialLead));
749
752 solid = new GeoBox(dx, dy, dz);
753 m_innerElectrode[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialKapton));
754
755 // Set offsets
756 xoffset = 0.;
757 yoffset = m_innerWheelRmin[1] + innerLipPosition1;
758 zoffset = m_innerWheelZmin + dz;
759 m_innerAbsorberOffset[iblade] = GeoThreeVector(xoffset, yoffset, zoffset);
760 m_innerElectrodeOffset[iblade] = GeoThreeVector(xoffset, yoffset, zoffset);
761
762 // Contruct logical volumes for 2nd lip
763 iblade = s_innerNoBlades - 1;
765 dy = 0.5*innerLipLength2;
766 dz = 0.5*m_innerLipWidth;
768 solid = new GeoBox(dx, dy, dz);
769 m_innerAbsorber[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialSteel));
770
771 name = m_nameInnerWheel + m_nameGlue + m_nameSuffix[iblade];
772 solid = new GeoBox(dx*m_innerGlueRatio, dy, dz);
773 m_innerGlue[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialGlue));
774
775 name = m_nameInnerWheel + m_nameLead + m_nameSuffix[iblade];
776 solid = new GeoBox(dx*m_innerLeadRatio, dy, dz);
777 m_innerLead[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialLead));
778
781 solid = new GeoBox(dx, dy, dz);
782 m_innerElectrode[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialKapton));
783
784 // Set offsets
785 xoffset = 0.;
786 yoffset = m_innerWheelRmin[s_innerNoBlades - 1] + innerLipPosition2;
787 zoffset = m_innerWheelZmax - dz;
788 m_innerAbsorberOffset[iblade] = GeoThreeVector(xoffset, yoffset, zoffset);
789 m_innerElectrodeOffset[iblade] = GeoThreeVector(xoffset, yoffset, zoffset);
790}
791
793//
794// Construct Lips of Absorbers and Electrodes for Outer Wheel
795// Set offsets
796//
798 double outerLipPosition1,
799 double outerLipLength2,
800 double outerLipPosition2)
801{
802 double dx, dy, dz, xoffset, yoffset, zoffset;
803 std::string name;
804 GeoShape* solid;
805
806 // Contruct logical volumes for 1st lip
807 int iblade = 0;
809 dy = 0.5*outerLipLength1;
810 dz = 0.5*m_outerLipWidth;
812 solid = new GeoBox(dx, dy, dz);
813 m_outerAbsorber[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialSteel));
814
815 name = m_nameOuterWheel + m_nameGlue + m_nameSuffix[iblade];
816 solid = new GeoBox(dx*m_outerGlueRatio, dy, dz);
817 m_outerGlue[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialGlue));
818
819 name = m_nameOuterWheel + m_nameLead + m_nameSuffix[iblade];
820 solid = new GeoBox(dx*m_outerLeadRatio, dy, dz);
821 m_outerLead[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialLead));
822
825 solid = new GeoBox(dx, dy, dz);
826 m_outerElectrode[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialKapton));
827
828 // Set offsets
829 xoffset = 0.;
830 yoffset = m_outerWheelRmin[1] + outerLipPosition1;
831 zoffset = m_outerWheelZmin + dz;
832 m_outerAbsorberOffset[iblade] = GeoThreeVector(xoffset, yoffset, zoffset);
833 m_outerElectrodeOffset[iblade] = GeoThreeVector(xoffset, yoffset, zoffset);
834
835 // Contruct logical volumes for 2nd lip
836 iblade = s_outerNoBlades - 1;
838 dy = 0.5*outerLipLength2;
839 dz = 0.5*m_outerLipWidth;
841 solid = new GeoBox(dx, dy, dz);
842 m_outerAbsorber[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialSteel));
843
844 name = m_nameOuterWheel + m_nameGlue + m_nameSuffix[iblade];
845 solid = new GeoBox(dx*m_outerGlueRatio, dy, dz);
846 m_outerGlue[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialGlue));
847
848 name = m_nameOuterWheel + m_nameLead + m_nameSuffix[iblade];
849 solid = new GeoBox(dx*m_outerLeadRatio, dy, dz);
850 m_outerLead[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialLead));
851
854 solid = new GeoBox(dx, dy, dz);
855 m_outerElectrode[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialKapton));
856
857 // Set offsets
858 xoffset = 0.;
859 yoffset = m_outerWheelRmin[s_outerNoBlades -1] + outerLipPosition2;
860 zoffset = m_outerWheelZmax - dz;
861 m_outerAbsorberOffset[iblade] = GeoThreeVector(xoffset, yoffset, zoffset);
862 m_outerElectrodeOffset[iblade] = GeoThreeVector(xoffset, yoffset, zoffset);
863}
864
866//
867// Construct Blades of Absorbers and Electrodes for Inner Wheel
868// Set offsets
869//
870void
872 const GeoThreeVector innerElectrodeCorners[8])
873{
874 std::string name;
875 GeoShape* solid;
876
877 for (int iblade = 1; iblade < s_innerNoBlades - 1; ++iblade)
878 {
879 int icase = (iblade%2 == 0) ? 2 : 3; // positive/negative inclination
880 if (iblade == 1) icase = 1; // first quater-wave
881 if (iblade == s_innerNoBlades - 2) icase = 4; // last quater-wave
882
883 double z1 = m_innerWheelZ[iblade];
884 double r1min = m_innerWheelRmin[iblade];
885 double r1max = m_innerWheelRmax[iblade];
886 double z2 = m_innerWheelZ[iblade + 1];
887 double r2min = m_innerWheelRmin[iblade + 1];
888 double r2max = m_innerWheelRmax[iblade + 1];
889
890 // Construct volumes for Absorber, Glue, Lead and Electrode
892 solid = constructBlade(icase, innerCorners, 1., z1, r1min, r1max, z2, r2min, r2max);
893 m_innerAbsorber[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialSteel));
894
895 name = m_nameInnerWheel + m_nameGlue + m_nameSuffix[iblade];
896 solid = constructBlade(icase, innerCorners, m_innerGlueRatio, z1, r1min, r1max, z2, r2min, r2max);
897 m_innerGlue[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialGlue));
898
899 name = m_nameInnerWheel + m_nameLead + m_nameSuffix[iblade];
900 solid = constructBlade(icase, innerCorners, m_innerLeadRatio, z1, r1min, r1max, z2, r2min, r2max);
901 m_innerLead[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialLead));
902
904 solid = constructBlade(icase, innerElectrodeCorners, 1., z1, r1min, r1max, z2, r2min, r2max);
905 m_innerElectrode[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialKapton));
906
907 // Set offsets
908 m_innerAbsorberOffset[iblade] = GeoThreeVector(0., 0., (z1 + z2)/2.);
909 m_innerElectrodeOffset[iblade] = GeoThreeVector(0., 0., (z1 + z2)/2.);
910 }
911}
912
914//
915// Construct Blades of Absorbers and Electrodes for Outer Wheel
916// Set offsets
917//
918void
920 const GeoThreeVector outerElectrodeCorners[8])
921{
922 std::string name;
923 GeoShape* solid;
924
925 for (int iblade = 1; iblade < s_outerNoBlades - 1; ++iblade)
926 {
927 int icase = (iblade%2 == 0) ? 2 : 3; // positive/negative inclination
928 if (iblade == 1) icase = 1; // first quater-wave
929 if (iblade == s_outerNoBlades - 2) icase = 4; // last quater-wave
930
931 double z1 = m_outerWheelZ[iblade];
932 double r1min = m_outerWheelRmin[iblade];
933 double r1max = m_outerWheelRmax[iblade];
934 double z2 = m_outerWheelZ[iblade + 1];
935 double r2min = m_outerWheelRmin[iblade + 1];
936 double r2max = m_outerWheelRmax[iblade + 1];
937
938 // Construct volumes for Absorber, Glue, Lead and Electrode
940 solid = constructBlade(icase, outerCorners, 1., z1, r1min, r1max, z2, r2min, r2max);
941 m_outerAbsorber[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialSteel));
942
943 name = m_nameOuterWheel + m_nameGlue + m_nameSuffix[iblade];
944 solid = constructBlade(icase, outerCorners, m_outerGlueRatio, z1, r1min, r1max, z2, r2min, r2max);
945 m_outerGlue[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialGlue));
946
947 name = m_nameOuterWheel + m_nameLead + m_nameSuffix[iblade];
948 solid = constructBlade(icase, outerCorners, m_outerLeadRatio, z1, r1min, r1max, z2, r2min, r2max);
949 m_outerLead[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialLead));
950
951 // Construct solid for Electrode
953 solid = constructBlade(icase, outerElectrodeCorners, 1., z1, r1min, r1max, z2, r2min, r2max);
954 m_outerElectrode[iblade] = new GeoPhysVol(new GeoLogVol(name, solid, m_materialKapton));
955
956 // Set offsets
957 m_outerAbsorberOffset[iblade] = GeoThreeVector(0., 0., (z1 + z2)/2.);
958 m_outerElectrodeOffset[iblade] = GeoThreeVector(0., 0., (z1 + z2)/2.);
959 }
960}
961
963//
964// Place Glue and Lead into Inner Wheel Absorbers
965//
967{
968 for (int iblade = 0; iblade < s_innerNoBlades; ++iblade)
969 {
970 m_innerGlue[iblade]->add(m_innerLead[iblade]);
971 m_innerAbsorber[iblade]->add(m_innerGlue[iblade]);
972 }
973}
974
976//
977// Place Glue and Lead into Outer Wheel Absorbers
978//
980{
981 for (int iblade = 0; iblade < s_outerNoBlades; ++iblade)
982 {
983 m_outerGlue[iblade]->add(m_outerLead[iblade]);
984 m_outerAbsorber[iblade]->add(m_outerGlue[iblade]);
985 }
986}
987
989//
990// Place Slices in Inner Wheel, if needed
991//
993{
994 if (!makeSlices) return;
995 for (int islice = 0; islice < s_innerNoBlades; ++islice)
996 {
997 double x = m_innerSliceOffset[islice].x();
998 double y = m_innerSliceOffset[islice].y();
999 double z = m_innerSliceOffset[islice].z();
1000 m_innerWheel->add(new GeoTransform(GeoTrf::Translate3D(x, y, z)));
1001 m_innerWheel->add(m_innerSlice[islice]);
1002 }
1003}
1004
1006//
1007// Place Slices in Outer Wheel, if needed
1008//
1010{
1011 if (!makeSlices) return;
1012 for (int islice = 0; islice < s_outerNoBlades; ++islice)
1013 {
1014 double x = m_outerSliceOffset[islice].x();
1015 double y = m_outerSliceOffset[islice].y();
1016 double z = m_outerSliceOffset[islice].z();
1017 m_outerWheel->add(new GeoTransform(GeoTrf::Translate3D(x, y, z)));
1018 m_outerWheel->add(m_outerSlice[islice]);
1019 }
1020}
1021
1023//
1024// Place Inner Wheel Electrodes and Absorbers
1025//
1026void
1028 bool makeSlices,
1029 bool makeSectors)
1030{
1031 int nphi = (makeSectors) ? m_innerNoElectrodes/innerNoSectors : m_innerNoElectrodes;
1032 double dphi = SI::twopi/m_innerNoElectrodes;
1033 GeoPhysVol* mother = nullptr;
1034
1035 // Place Electordes
1036 for (int iphi = 0; iphi < nphi; ++iphi)
1037 {
1038 GeoTrf::RotateZ3D rotation(dphi*iphi - SI::halfpi);
1039 int copyNo = iphi + 1;
1040 for (int iblade = 0; iblade < s_innerNoBlades; ++iblade)
1041 {
1042 if (makeSlices) mother = m_innerSlice[iblade];
1043 if (makeSectors) mother = m_innerSector[iblade];
1044 if (makeSlices || makeSectors)
1045 {
1046 double x = m_innerElectrodeOffset[iblade].x();
1047 double y = m_innerElectrodeOffset[iblade].y();
1048 double z = 0;
1049 GeoTrf::Translate3D translation(x, y, z);
1050 mother->add(new GeoIdentifierTag(copyNo));
1051 mother->add(new GeoTransform(rotation*translation));
1052 mother->add(m_innerElectrode[iblade]);
1053 }
1054 else
1055 {
1056 double x = m_innerElectrodeOffset[iblade].x();
1057 double y = m_innerElectrodeOffset[iblade].y();
1058 double z = m_innerElectrodeOffset[iblade].z();
1059 GeoTrf::Translate3D translation(x, y, z);
1060 m_innerWheel->add(new GeoIdentifierTag(copyNo));
1061 m_innerWheel->add(new GeoTransform(rotation*translation));
1062 m_innerWheel->add(m_innerElectrode[iblade]);
1063 }
1064 }
1065 }
1066
1067 // Place Absorbers
1068 for (int iphi = 0; iphi < nphi; ++iphi)
1069 {
1070 GeoTrf::RotateZ3D rotation(dphi*(iphi+0.5) - SI::halfpi);
1071 int copyNo = iphi + 1;
1072 for (int iblade = 0; iblade < s_innerNoBlades; ++iblade)
1073 {
1074 if (makeSlices) mother = m_innerSlice[iblade];
1075 if (makeSectors) mother = m_innerSector[iblade];
1076 if (makeSlices || makeSectors)
1077 {
1078 double x = m_innerAbsorberOffset[iblade].x();
1079 double y = m_innerAbsorberOffset[iblade].y();
1080 double z = 0;
1081 GeoTrf::Translate3D translation(x, y, z);
1082 mother->add(new GeoIdentifierTag(copyNo));
1083 mother->add(new GeoTransform(rotation*translation));
1084 mother->add(m_innerAbsorber[iblade]);
1085 }
1086 else
1087 {
1088 double x = m_innerAbsorberOffset[iblade].x();
1089 double y = m_innerAbsorberOffset[iblade].y();
1090 double z = m_innerAbsorberOffset[iblade].z();
1091 GeoTrf::Translate3D translation(x, y, z);
1092 m_innerWheel->add(new GeoIdentifierTag(copyNo));
1093 m_innerWheel->add(new GeoTransform(rotation*translation));
1094 m_innerWheel->add(m_innerAbsorber[iblade]);
1095 }
1096 }
1097 }
1098}
1099
1101//
1102// Place Outer Wheel Electrodes and Absorbers
1103//
1104void
1106 bool makeSlices,
1107 bool makeSectors)
1108{
1109 int nphi = (makeSectors) ? m_outerNoElectrodes/outerNoSectors : m_outerNoElectrodes;
1110 double dphi = SI::twopi/m_outerNoElectrodes;
1111 GeoPhysVol* mother = nullptr;
1112
1113 // Place Electordes
1114 for (int iphi = 0; iphi < nphi; ++iphi)
1115 {
1116 GeoTrf::RotateZ3D rotation(dphi*iphi - SI::halfpi);
1117 int copyNo = iphi + 1;
1118 for (int iblade = 0; iblade < s_outerNoBlades; ++iblade)
1119 {
1120 if (makeSlices) mother = m_outerSlice[iblade];
1121 if (makeSectors) mother = m_outerSector[iblade];
1122 if (makeSlices || makeSectors)
1123 {
1124 double x = m_outerElectrodeOffset[iblade].x();
1125 double y = m_outerElectrodeOffset[iblade].y();
1126 double z = 0;
1127 GeoTrf::Translate3D translation(x, y, z);
1128 mother->add(new GeoIdentifierTag(copyNo));
1129 mother->add(new GeoTransform(rotation*translation));
1130 mother->add(m_outerElectrode[iblade]);
1131 }
1132 else
1133 {
1134 double x = m_outerElectrodeOffset[iblade].x();
1135 double y = m_outerElectrodeOffset[iblade].y();
1136 double z = m_outerElectrodeOffset[iblade].z();
1137 GeoTrf::Translate3D translation(x, y, z);
1138 m_outerWheel->add(new GeoIdentifierTag(copyNo));
1139 m_outerWheel->add(new GeoTransform(rotation*translation));
1140 m_outerWheel->add(m_outerElectrode[iblade]);
1141 }
1142 }
1143 }
1144
1145 // Place Absorbers
1146 for (int iphi = 0; iphi < nphi; ++iphi)
1147 {
1148 GeoTrf::RotateZ3D rotation(dphi*(iphi+0.5) - SI::halfpi);
1149 int copyNo = iphi + 1;
1150 for (int iblade = 0; iblade < s_outerNoBlades; ++iblade)
1151 {
1152 if (makeSlices) mother = m_outerSlice[iblade];
1153 if (makeSectors) mother = m_outerSector[iblade];
1154 if (makeSlices || makeSectors)
1155 {
1156 double x = m_outerAbsorberOffset[iblade].x();
1157 double y = m_outerAbsorberOffset[iblade].y();
1158 double z = 0;
1159 GeoTrf::Translate3D translation(x, y, z);
1160 mother->add(new GeoIdentifierTag(copyNo));
1161 mother->add(new GeoTransform(rotation*translation));
1162 mother->add(m_outerAbsorber[iblade]);
1163 }
1164 else
1165 {
1166 double x = m_outerAbsorberOffset[iblade].x();
1167 double y = m_outerAbsorberOffset[iblade].y();
1168 double z = m_outerAbsorberOffset[iblade].z();
1169 GeoTrf::Translate3D translation(x, y, z);
1170 m_outerWheel->add(new GeoIdentifierTag(copyNo));
1171 m_outerWheel->add(new GeoTransform(rotation*translation));
1172 m_outerWheel->add(m_outerAbsorber[iblade]);
1173 }
1174 }
1175 }
1176}
1177
1179//
1180// Construct EMEC Inner Wheel Accordion
1181//
1182void
1184{
1185 bool makeSectors = false;
1186 int innerNoSectors = 0;
1187
1188 // P R E L I M I N A R Y C A L C U L A T I O N S
1189 //
1190 setInnerWheelSlices(); // define thickness of slices in Inner Wheel
1191
1192 // Get enginneering data of absorbers
1193 double innerUncutBladeWidthMin, innerUncutBladeWidthMax;
1194 double innerLipLength1, innerLipPosition1;
1195 double innerLipLength2, innerLipPosition2;
1196 getInnerAbsorberData(innerUncutBladeWidthMin, innerUncutBladeWidthMax,
1197 innerLipLength1, innerLipPosition1,
1198 innerLipLength2, innerLipPosition2);
1199 innerUncutBladeWidthMin *= m_kContraction;
1200 innerUncutBladeWidthMax *= m_kContraction;
1201 innerLipLength1 *= m_kContraction;
1202 innerLipPosition1 *= m_kContraction;
1203 innerLipLength2 *= m_kContraction;
1204 innerLipPosition2 *= m_kContraction;
1205
1206 // C O M P U T E U N C U T B L A D E C O R N E R S
1207 //
1208 double wmin, wmax, thickness, rmin, rmax, zdel;
1209
1210 // Compute Inner Absorber Blade corners
1211 GeoThreeVector innerCorners[8];
1212 wmin = innerUncutBladeWidthMin;
1213 wmax = innerUncutBladeWidthMax;
1214 thickness = m_innerAbsorberThickness;
1215 rmin = m_innerWheelRmin[1];
1217 zdel = m_innerHalfWaveWidth; // slice width
1218 getBladeCorners(wmin, wmax, thickness, rmin, rmax, zdel, innerCorners);
1219
1220 // Compute Inner Electrode Blade corners
1221 GeoThreeVector innerElectrodeCorners[8];
1222 thickness = m_innerElectrodeThickness;
1223 getBladeCorners(wmin, wmax, thickness, rmin, rmax, zdel, innerElectrodeCorners);
1224
1225 // C O N S T R U C T L O G I C A L V O L U M E S
1226 //
1227 // Compute X-scale factors for glue and lead in absorbers
1228 // Needed for construction of corresponding volumes
1231
1232 // Construct Lips, set offsets for the case "no Slices, no Sectors"
1233 constructInnerLips(innerLipLength1, innerLipPosition1, innerLipLength2, innerLipPosition2);
1234
1235 // Construct Blades, set offsets for the case "no Slices, no Sectors"
1236 constructInnerBlades(innerCorners, innerElectrodeCorners);
1237
1238 // Construct Slices, set offsets
1240
1241 // Construct Sectors (disabled)
1242 // constructInnerSectors(innerNoSectors);
1243
1244 // C O N S T R U C T P H Y S I C A L V O L U M E S
1245 //
1246 placeInnerGlueAndLead(); // place Glue and Lead in Inner Wheel Absorbers
1247 placeInnerSlices(makeSlices); // place Slices, if needed
1248 // PlaceInnerSectors(innerNoSectors, makeSlices, makeSectors); // disabled
1249 placeInnerAccordion(innerNoSectors, makeSlices, makeSectors); // place Absorbers and Electrodes
1250}
1251
1253//
1254// Construct EMEC Inner Wheel Accordion
1255//
1256void
1258{
1259 bool makeSectors = false;
1260 int outerNoSectors = 0;
1261
1262 // P R E L I M I N A R Y C A L C U L A T I O N S
1263 //
1264 setOuterWheelSlices(); // define thickness of slices in Outer Wheel
1265
1266 // Get enginneering data of absorbers
1267 double outerUncutBladeWidthMin, outerUncutBladeWidthMax;
1268 double outerLipLength1, outerLipPosition1;
1269 double outerLipLength2, outerLipPosition2;
1270 getOuterAbsorberData(outerUncutBladeWidthMin, outerUncutBladeWidthMax,
1271 outerLipLength1, outerLipPosition1,
1272 outerLipLength2, outerLipPosition2);
1273 outerUncutBladeWidthMin *= m_kContraction;
1274 outerUncutBladeWidthMax *= m_kContraction;
1275 outerLipLength1 *= m_kContraction;
1276 outerLipPosition1 *= m_kContraction;
1277 outerLipLength2 *= m_kContraction;
1278 outerLipPosition2 *= m_kContraction;
1279
1280 // C O M P U T E U N C U T B L A D E C O R N E R S
1281 //
1282 double wmin, wmax, thickness, rmin, rmax, zdel;
1283
1284 // Compute Outer Absorber Blade corners
1285 GeoThreeVector outerCorners[8];
1286 wmin = outerUncutBladeWidthMin;
1287 wmax = outerUncutBladeWidthMax;
1288 thickness = m_outerAbsorberThickness;
1289 rmin = m_outerWheelRmin[1];
1291 zdel = m_outerHalfWaveWidth; // slice width
1292 getBladeCorners(wmin, wmax, thickness, rmin, rmax, zdel, outerCorners);
1293
1294 // Compute Outer Electrode Blade corners
1295 GeoThreeVector outerElectrodeCorners[8];
1296 thickness = m_outerElectrodeThickness;
1297 getBladeCorners(wmin, wmax, thickness, rmin, rmax, zdel, outerElectrodeCorners);
1298
1299 // C O N S T R U C T L O G I C A L V O L U M E S
1300 //
1301 // Compute X-scale factors for glue and lead in absorbers
1302 // Needed for construction of corresponding volumes
1305
1306 // Construct Lips, set offsets for the case "no Slices, no Sectors"
1307 constructOuterLips(outerLipLength1, outerLipPosition1, outerLipLength2, outerLipPosition2);
1308
1309 // Construct Blades, set offsets for the case "no Slices, no Sectors"
1310 constructOuterBlades(outerCorners, outerElectrodeCorners);
1311
1312 // Construct Slices, set offsets
1314
1315 // Construct Sectors (disabled)
1316 // constructOuterSectors(outerNoSectors);
1317
1318 // C O N S T R U C T P H Y S I C A L V O L U M E S
1319 //
1320 placeOuterGlueAndLead(); // place Glue and Lead in Outer Wheel Absorbers
1321 placeOuterSlices(makeSlices); // place Slices, if needed
1322 // PlaceOuterSectors(outerNoSectors, makeSlices, makeSectors); // disabled
1323 placeOuterAccordion(outerNoSectors, makeSlices, makeSectors); // place Absorbers and Electrodes
1324}
1325
Declaration of EMECAccordionConstruction class.
GeoTrf::Vector3D GeoThreeVector
GeoTrf::Vector2D GeoTwoVector
Definition of the abstract IRDBAccessSvc interface.
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of the abstract IRDBRecord interface.
Definition of the abstract IRDBRecordset interface.
static std::map< double, LArWheelSliceSolid * > solid
#define y
#define x
#define z
This is a helper class to query the version tags from GeoModelSvc and determine the appropriate tag a...
const std::string & tag() const
Return version tag.
const std::string & node() const
Return the version node.
virtual unsigned int size() const =0
void constructInnerLips(double innerLipLength1, double innerLipPosition1, double innerLipLength2, double innerLipPosition2)
void constructInnerWheelStructure(bool makeSlices=true)
std::array< GeoPhysVol *, s_innerNoBlades > m_innerElectrode
GeoShape * constructBlade(int icase, const GeoThreeVector corners[8], double xscale, double pz1, double pr1min, double pr1max, double pz2, double pr2min, double pr2max) const
std::array< double, s_outerNoBlades+1 > m_outerWheelRmin
std::array< GeoPhysVol *, s_innerNoBlades > m_innerSector
std::array< GeoPhysVol *, s_outerNoBlades > m_outerGlue
void getBladeCorners(double wmin, double wmax, double thickness, double rmin, double rmax, double zdel, GeoThreeVector corners[8]) const
std::array< double, s_innerNoBlades+1 > m_innerWheelRmax
void constructOuterLips(double outerLipLength1, double outerLipPosition1, double outerLipLength2, double outerLipPosition2)
std::array< GeoThreeVector, s_outerNoBlades > m_outerAbsorberOffset
void getOuterAbsorberData(double &wmin, double &wmax, double &llip1, double &ylip1, double &llip2, double &ylip2) const
std::array< double, s_innerNoBlades+1 > m_innerWheelRmin
void placeOuterAccordion(int outerNoSectors, bool makeSlices, bool makeSectors)
std::array< GeoThreeVector, s_innerNoBlades > m_innerAbsorberOffset
GeoThreeVector IntersectionPoint(const GeoThreeVector &p1, const GeoThreeVector &p2, const CutPlane &plane) const
void constructOuterBlades(const GeoThreeVector outerCorners[8], const GeoThreeVector outerElectrodeCorners[8])
std::array< GeoPhysVol *, s_innerNoBlades > m_innerSlice
std::array< GeoPhysVol *, s_innerNoBlades > m_innerGlue
void getInnerAbsorberData(double &wmin, double &wmax, double &llip1, double &ylip1, double &llip2, double &ylip2) const
std::array< double, s_outerNoBlades+1 > m_outerWheelZ
std::array< GeoPhysVol *, s_outerNoBlades > m_outerSector
std::string m_nameSuffix[s_outerNoBlades]
std::array< GeoThreeVector, s_innerNoBlades > m_innerSliceOffset
void setInnerWheel(GeoFullPhysVol *innerWheel)
std::array< GeoThreeVector, s_innerNoBlades > m_innerElectrodeOffset
std::array< GeoPhysVol *, s_outerNoBlades > m_outerLead
void setOuterWheel(GeoFullPhysVol *outerWheel)
std::array< GeoPhysVol *, s_outerNoBlades > m_outerSlice
std::array< GeoPhysVol *, s_innerNoBlades > m_innerLead
std::array< GeoThreeVector, s_outerNoBlades > m_outerElectrodeOffset
CutPlane getTopCutPlane(double zmin, double rmin, double zmax, double rmax, const GeoThreeVector corners[8]) const
std::array< GeoPhysVol *, s_outerNoBlades > m_outerAbsorber
std::array< GeoThreeVector, s_outerNoBlades > m_outerSliceOffset
std::array< GeoPhysVol *, s_innerNoBlades > m_innerAbsorber
void placeInnerAccordion(int innerNoSectors, bool makeSlices, bool makeSectors)
std::array< GeoPhysVol *, s_outerNoBlades > m_outerElectrode
void setMaterial(const std::string &name, const GeoMaterial *material)
void constructOuterWheelStructure(bool makeSlices=true)
void constructInnerBlades(const GeoThreeVector innerCorners[8], const GeoThreeVector innerElectrodeCorners[8])
CutPlane getBottomCutPlane(double zmin, double rmin, double zmax, double rmax) const
std::array< double, s_innerNoBlades+1 > m_innerWheelZ
std::array< double, s_outerNoBlades+1 > m_outerWheelRmax
int r
Definition globals.cxx:22
struct color C
double xmax
Definition listroot.cxx:61
double ymin
Definition listroot.cxx:63
double xmin
Definition listroot.cxx:60
double ymax
Definition listroot.cxx:64
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
hold the test vectors and ease the comparison