ATLAS Offline Software
Loading...
Searching...
No Matches
MuonChamber.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "MuonGeoModel/Csc.h"
8#include "MuonGeoModel/Ded.h"
10#include "MuonGeoModel/Mdt.h"
13#include "MuonGeoModel/Rpc.h"
14#include "MuonGeoModel/Spacer.h"
17#include "MuonGeoModel/Tgc.h"
21//
34
35// just to check subtype, cutout:
39#include "MuonGeoModel/MYSQL.h"
42//
47//
48#include "GaudiKernel/SystemOfUnits.h"
49#include "GeoModelKernel/GeoBox.h"
50#include "GeoModelKernel/GeoDefinitions.h"
51#include "GeoModelKernel/GeoFullPhysVol.h"
52#include "GeoModelKernel/GeoIdentifierTag.h"
53#include "GeoModelKernel/GeoLogVol.h"
54#include "GeoModelKernel/GeoMaterial.h"
55#include "GeoModelKernel/GeoNameTag.h"
56#include "GeoModelKernel/GeoPhysVol.h"
57#include "GeoModelKernel/GeoSerialDenominator.h"
58#include "GeoModelKernel/GeoShapeIntersection.h"
59#include "GeoModelKernel/GeoShapeShift.h"
60#include "GeoModelKernel/GeoShapeSubtraction.h"
61#include "GeoModelKernel/GeoShapeUnion.h"
62#include "GeoModelKernel/GeoTransform.h"
63#include "GeoModelKernel/GeoTrd.h"
64#include "GeoModelKernel/GeoTube.h"
65
66#include <fstream>
67#include <iomanip>
68#include <vector>
69
70#define RPCON true
71#define useAssemblies false
72
73namespace {
74 // const maps holding the y/z translation for BIS RPCs (since they cannot be parsed by amdb)
75 const std::map<std::string, float> rpcYTrans = {
76 std::make_pair<std::string, float>("RPC26", -9.1), // big RPC7
77 std::make_pair<std::string, float>("RPC27", -9.1), // small RPC7
78 std::make_pair<std::string, float>("RPC28", -27.7), // big RPC8
79 std::make_pair<std::string, float>("RPC29", -8.8), // small RPC8
80 };
81 const std::map<std::string, float> rpcZTrans = {
82 std::make_pair<std::string, float>("RPC26", 3.22), // big RPC7
83 std::make_pair<std::string, float>("RPC27", 3.06), // small RPC7
84 std::make_pair<std::string, float>("RPC28", 3.11), // big RPC8
85 std::make_pair<std::string, float>("RPC29", 3.11), // small RPC8
86 };
87} // namespace
88
89namespace MuonGM {
90
91 // cutouts for BMS at eta=+-1 and phi=4 (RPC/DED/MDT) ok //16 tubes shorter + entire RPC and DED (of dbz1) narrower
92
94 DetectorElement(s->GetName()),
95 AthMessaging{"MuGM::MuonChamber"} {
96 width = s->GetWidth1();
97 longWidth = s->GetWidth2();
98 thickness = s->GetThickness(mysql);
99 length = s->GetLength();
100 m_station = s;
101
102 // CSL envelope is too small for its components - enlarge it slightly
103 std::string stname(m_station->GetName(), 0, 3);
104 if (stname == "CSL")
105 longWidth *= 1.015;
106
107 }
108
110 const MYSQL& mysql,
111 MuonDetectorManager *manager, int zi, int fi, bool is_mirrored, bool &isAssembly) {
112 ATH_MSG_VERBOSE( " Building a MuonChamber for m_station " << m_station->GetName() << " at zi, fi " << zi << " " << fi + 1 << " is_mirrored " << is_mirrored
113 << " is assembly = " << isAssembly );
114
115 std::string stname(m_station->GetName(), 0, 3);
116
117 double halfpitch = m_station->mdtHalfPitch(mysql);
118 const std::string stName = m_station->GetName();
119
120 const MdtIdHelper *mdt_id = manager->mdtIdHelper();
121 int stationType = mdt_id->stationNameIndex(stName.substr(0, 3));
122 bool is_barrel = (stName.compare(0, 1, "B") == 0);
123
124 std::string geometry_version = manager->geometryVersion();
125 double extratop = m_station->GetExtraTopThickness();
126 double extrabottom = m_station->GetExtraBottomThickness();
127 double totthick = thickness + extratop + extrabottom;
128
129 GeoTrd *maintrd;
130 maintrd = new GeoTrd(totthick / 2, totthick / 2, width / 2, longWidth / 2, length / 2);
131
132 if (length <= 0) {
133 ATH_MSG_ERROR( " Invalid length " << length << " for m_station " << m_station->GetName() << " fi/zi " << fi + 1 << "/" << zi );
134 }
135
136 ATH_MSG_VERBOSE( " MuonChamber size thick,w,lw,l " << totthick << ", " << width << ", " << longWidth << ", " << length );
137
138 const GeoShape *strd = nullptr;
139 double dx = 0.;
140 if ((extratop + extrabottom) != 0.) {
141 // sup on top & bottom
142 dx = extratop / 2. - extrabottom / 2.;
143
144 ATH_MSG_VERBOSE( " m_station name " << m_station->GetName() << " extra top, bottom, dx = " << extratop << " " << extrabottom );
145 strd = &((*maintrd) << GeoTrf::Translate3D(dx, 0., 0.));
146 } else {
147 strd = maintrd;
148 }
149
150 double amdbOrigine_along_length = m_station->getAmdbOrigine_along_length();
151 double amdbOrigine_along_thickness = m_station->getAmdbOrigine_along_thickness(mysql);
152
153 // Fix clash of EIS1 and CSS1. Cut out upper corner of CSS1 envelope (along long width)
154 if (stname == "CSS") {
155 StandardComponent *comp = nullptr;
156 double clen = 0;
157 double cthick = 0;
158 double cypos = 0;
159 double cxpos = 0;
160 for (int i = 0; i < m_station->GetNrOfComponents(); i++) {
161 comp = static_cast<StandardComponent *>(m_station->GetComponent(i));
162 if ((comp->name).compare(0, 3, "CSC") == 0) {
163 clen = comp->dy;
164 cthick = comp->GetThickness(mysql);
165 cypos = clen - comp->posy + 1.0 - length / 2.;
166 cxpos = -totthick / 2. + comp->posz + cthick / 2. + 0.1;
167 break;
168 }
169 }
170 GeoIntrusivePtr<GeoShape> box{new GeoBox(cthick / 2., longWidth / 2., (length - clen) / 2.)};
171 strd = &(strd->subtract((*box) << GeoTrf::Translate3D(cxpos, 0., cypos)));
172 }
173
174 if (m_enableFineClashFixing > 0) {
175 // Mother volume modifications for specific chambers
176
177 // Fix clashes of non-cutout BMS with BTWingRib
178 if ((stname == "BMS" && std::abs(zi) == 5) || (stname == "BMS" && std::abs(zi) == 1 && fi != 3)) {
179 StandardComponent *comp = nullptr;
180 double cutlen = 0.;
181 double cutthick = 0.;
182 double top_edge = 0.;
183 for (int i = m_station->GetNrOfComponents() - 2; i > -1; i--) {
184 comp = static_cast<StandardComponent *>(m_station->GetComponent(i));
185 top_edge = comp->posy + comp->dy;
186 cutlen = length - top_edge;
187 if ((comp->posy != 0 && cutlen > 0.1) || comp->dy > 0.75 * length) {
188 cutthick = comp->GetThickness(mysql) + 1.;
189 break;
190 }
191 }
192 GeoIntrusivePtr<GeoShape> box1{new GeoBox(cutthick / 2., (longWidth + 2.) / 2., cutlen)};
193 strd = &(strd->subtract((*box1) << GeoTrf::Translate3D((totthick - cutthick) / 2., 0., length / 2.)));
194 }
195 }
196
197 // Skip mother volume modifications for assembly volumes since they cannot cause clash
198 if (!isAssembly) {
199 bool testEIL = (stname == "EIL" && std::abs(zi) != 1 && (std::abs(zi) != 4 || fi == 0 || fi == 4));
200
201 if ((m_enableFineClashFixing && (stname == "BML" || stname == "BIL" || stname == "BOL" || stname == "BMS" || stname == "BIS" || stname == "BOS")) || testEIL) {
202 double root3 = 1.7320508;
203 StandardComponent *comp = nullptr;
204 double mdt_half_thick = -1.;
205 double mdt_pos = 0.;
206 double xtube1 = 0;
207 double xtube2 = 0;
208
209 int index = 0;
210 int mdt_index[4] = {0, 0, 0, 0};
211 for (int i = 0; i < m_station->GetNrOfComponents(); i++) {
212 comp = static_cast<StandardComponent *>(m_station->GetComponent(i));
213 if (comp->name.compare(0,3,"MDT") == 0) {
214 mdt_index[index] = i;
215 index += 1;
216 }
217 }
218
219 // Prepare boxes and cylinders for chamber volume mods
220 GeoIntrusivePtr<GeoShape> box{new GeoBox((totthick + 2.) / 2., (longWidth + 2.) / 2., halfpitch)};
221 GeoIntrusivePtr<const GeoShape> frontcyl{new GeoTube(0.0, halfpitch + 0.001, longWidth / 2.)};
222 frontcyl = &((*frontcyl) << GeoTrf::RotateX3D(90. * Gaudi::Units::deg));
223 GeoIntrusivePtr<const GeoShape> backcyl{new GeoTube(0.0, halfpitch - 0.001, (longWidth + 2.) / 2.)};
224 backcyl = &((*backcyl) << GeoTrf::RotateX3D(90. * Gaudi::Units::deg));
225
226 if (index > 0) {
227 // If chamber has MDTs, shorten length by halfpitch (remove what was added in DBReader.h)
228 strd = &(strd->subtract((*box) << GeoTrf::Translate3D(0., 0., length / 2.)));
229 double sign = 1.;
230 for (int i = 0; i < index; i++) {
231 comp = static_cast<StandardComponent *>(m_station->GetComponent(mdt_index[i]));
232 mdt_half_thick = comp->GetThickness(mysql) / 2.;
233 mdt_pos = -totthick / 2. + comp->posz + mdt_half_thick;
234 mdt_pos += amdbOrigine_along_thickness;
235 xtube1 = sign * (mdt_half_thick - (root3 + 1.) * halfpitch);
236 xtube2 = sign * (mdt_half_thick - (3 * root3 + 1.) * halfpitch);
237 strd = &(strd->add((*frontcyl) << GeoTrf::Translate3D(mdt_pos + xtube1, 0., length / 2. - halfpitch)));
238 strd = &(strd->subtract((*backcyl) << GeoTrf::Translate3D(mdt_pos + xtube1, 0., -length / 2.)));
239
240 if (stname == "BIL" || (stname == "BIS" && std::abs(zi) != 8) || testEIL) {
241 strd = &(strd->add((*frontcyl) << GeoTrf::Translate3D(mdt_pos + xtube2, 0., length / 2. - halfpitch)));
242 strd = &(strd->subtract((*backcyl) << GeoTrf::Translate3D(mdt_pos + xtube2, 0., -length / 2.)));
243 }
244
245 sign *= -1.;
246 }
247 }
248 if (stname != "EIL") {
249 if (zi < 0 && !is_mirrored)
250 strd = &((*strd) << GeoTrf::RotateX3D(180. * Gaudi::Units::deg));
251 }
252
253 } // fine clash fixing
254 } // !isAssembly
255
256 // This will allow the MDT tube structure to be mirrored w.r.t. the chamber at z>0
257 // and to correctly place any other component in the m_station
258 if (zi < 0 && !is_mirrored && stName[0] == 'B') {
259 if (m_station->hasMdts()) {
260 amdbOrigine_along_length += halfpitch;
261 }
262 }
263 ATH_MSG_VERBOSE( "amdb origine: in the length direction = " << amdbOrigine_along_length
264 << " in the thickness direction = " << amdbOrigine_along_thickness);
265
266 if (isAssembly) {
267 ATH_MSG_DEBUG( "Station " << stName << " at zi, fi " << zi << " " << fi + 1 << " will be described as Assembly" );
268 }
269
270 // for BOG in layout Q we will have to shorten CHV, CMI as these
271 // are not shortened in AMDB
272 // double lengthShiftCP = 0.;
273
274 // if this is a BOG, we want to make cutouts in the MOTHER VOLUME
275 if (stName.compare(0, 3, "BOG") == 0 && (manager->IncludeCutoutsBogFlag() || manager->IncludeCutoutsFlag())) {
276
277 ATH_MSG_VERBOSE( "amdb org: length= " << amdbOrigine_along_length << " thickness= " << amdbOrigine_along_thickness );
278
279 std::string statType = stName.substr(0, 3);
280 if (m_station->GetNrOfCutouts() > 0) {
281 ATH_MSG_DEBUG( "Station " << stName << " at zi, fi " << zi << " " << fi + 1 << " has components with cutouts " );
282 isAssembly = true;
283
284 // look for FIRST component with cutouts and loop over all of the cutouts:
285 bool foundCutouts = false;
286 for (int j = 0; j < m_station->GetNrOfComponents(); j++) {
287 StandardComponent *c = static_cast<StandardComponent *>(m_station->GetComponent(j));
288
289 if (!foundCutouts) {
290 for (int ii = 0; ii < m_station->GetNrOfCutouts(); ii++) {
291 Cutout *cut = m_station->GetCutout(ii);
292 // if this is a BOG in layout Q, set the CP param:
293 // (both cuts have same length so ok to reset it)
294 // also do here some tweaking to prevent undershoot
295 // of the cutouts wrt mother volume:
296 if (std::abs(cut->dx - 600.7) < 0.1) {
297 cut->dx = cut->dx + 10. * Gaudi::Units::mm;
298 cut->widthXs = cut->widthXs + 20. * Gaudi::Units::mm;
299 cut->widthXl = cut->widthXl + 20. * Gaudi::Units::mm;
300 }
301 if (std::abs(cut->dx + 600.7) < 0.1) {
302 cut->dx = cut->dx - 10. * Gaudi::Units::mm;
303 cut->widthXs = cut->widthXs + 20. * Gaudi::Units::mm;
304 cut->widthXl = cut->widthXl + 20. * Gaudi::Units::mm;
305 }
306 if (std::abs(cut->lengthY - 180.2) < 0.001) {
307 cut->lengthY = cut->lengthY + (0.010) * Gaudi::Units::mm;
308 }
309 if (std::abs(cut->dy - 1019.8) < 0.001) {
310 cut->dy = 1216.4185 - cut->lengthY;
311 }
312 // create the cutout with the full thickness of the STATION
313 cut->setThickness(totthick * 1.01); // extra to be sure
314 if ((cut->subtype == mysql.allocPosFindSubtype(std::string(statType), fi, zi)) && (cut->icut == mysql.allocPosFindCutout(std::string(statType), fi, zi)) &&
315 (cut->ijob == c->index)) {
316
317 foundCutouts = true;
318 }
319 } // Loop over cutouts
320 } // If no cutouts
321 } // Loop over components
322 }
323 } // end of special loop just for cutouts
324
325 // remove overlaps between end-cap and forward region of TGC stations,
326 // T[1-3]E1_station and T[1-3]F1_station
327 if (stName.compare(0, 1, "T") == 0 && stName.compare(2, 1, "E") == 0 && stName.compare(1, 1, "4") != 0) {
328 GeoTrd *strdoverlap = new GeoTrd(totthick / 4, totthick / 4, width / 2, longWidth / 2, 400. / 2);
329 strd = &(strd->subtract((*strdoverlap) << GeoTrf::Translate3D(-totthick / 4., 0., -length / 2 + 400. / 2.)));
330 }
331
332 const GeoMaterial *mtrd = nullptr;
333 if (useAssemblies || isAssembly) {
334 mtrd = matManager.getMaterial("special::Ether");
335 } else {
336 mtrd = matManager.getMaterial("std::Air");
337 }
338 GeoLogVol *ltrd = new GeoLogVol(std::string(stName) + "_Station", strd, mtrd);
339 PVLink ptrd = new GeoPhysVol(ltrd);
340
341 double ypos{0.}, zpos{0.}, xpos{0.}, irad{0.};
342 std::array<int, 2> ndbz{0, 0};
343
344 // Compute how many RPC modules there are in the m_station
345 int nDoubletR{0}, nRpc{0}, nTgc{0}, nCsc{0}, nMdt{0};
346 double previous_depth = 0.;
347 ATH_MSG_VERBOSE( " Station Name = " << stName << " fi/zi " << fi << "/" << zi << " defining the n. of DoubletR to " );
348
349 for (int j = 0; j < m_station->GetNrOfComponents(); j++) {
350 StandardComponent *d = static_cast<StandardComponent *>(m_station->GetComponent(j));
351 std::string_view cn = std::string_view(d->name).substr(0, 3);
352 if (cn == "RPC") {
353 nRpc++;
354 if (nRpc == 1)
355 nDoubletR++;
356 double depth = -thickness / 2. + d->posz + d->GetThickness(mysql) / 2.;
357 // std::cerr << " nRpc, nDoubletR, depth " << nRpc << " " << nDoubletR
358 // << " " << depth;
359 // BI RPC Chambers have one one doubletR
360 if (!(stname.compare(0, 2, "BI") == 0) && nDoubletR == 1 && nRpc > 1 && depth * previous_depth < 0)
361 nDoubletR++;
362 // std::cerr<<" updated to "<<nDoubletR<<std::endl;
363
364 previous_depth = depth;
365 }
366 if (cn == "CSC") {
367 nCsc++;
368 }
369 if (cn == "TGC") {
370 nTgc++;
371 }
372 if (cn == "MDT") {
373 nMdt++;
374 }
375 }
376 ATH_MSG_DEBUG( " " << nDoubletR<<" nMdt/Rpc/Tgc/Csc " << nMdt << "/" << nRpc << "/" << nTgc << "/" << nCsc );
377
378 // Get location and dimensions of long beams and pass them to cross beams
379 // in order to make holes
380 int numLB = -1;
381 double LBheight{0.}, LBwidth{0.}, LByShift{0.};
382 std::array<double, 2> LBpos{-1, -1};
383 for (int i = 0; i < m_station->GetNrOfComponents(); i++) {
384 StandardComponent *c = static_cast<StandardComponent *>(m_station->GetComponent(i));
385 std::string_view cname = std::string_view(c->name).substr(0, 2);
386 if (cname == "LB") {
387 const LBI *lb = dynamic_cast<const LBI *>(mysql.GetTechnology(c->name));
388 LByShift = lb->yShift;
389
390 numLB++;
391 LBpos[numLB] = c->posy + c->dy / 2.;
392 LBheight = lb->height;
393 LBwidth = c->dy;
394 }
395 if (numLB > 0)
396 break; // only 2 LBs per chamber
397 }
398
399 for (int i = 0; i < m_station->GetNrOfComponents(); i++) {
400 StandardComponent *c = static_cast<StandardComponent *>(m_station->GetComponent(i));
401 std::string_view cname = std::string_view(c->name).substr(0, 3);
402 if (cname == "CRO" || cname == "CMI" || cname == "CHV") {
403 CbmComponent *ccbm = static_cast<CbmComponent *>(c);
404 ccbm->lb_height = LBheight;
405 ccbm->lb_width = LBwidth;
406 ccbm->hole_pos1 = LBpos[0];
407 ccbm->hole_pos2 = LBpos[1];
408 }
409 }
410
411 // Look for the subtype of the CMI in the chamber to let LB know ...
412 std::string CMIcomponentNumber = "";
413 for (int j = 0; j < m_station->GetNrOfComponents(); j++) {
414 StandardComponent *d = static_cast<StandardComponent *>(m_station->GetComponent(j));
415 std::string_view cn = std::string_view(d->name).substr(0, 3);
416 if (cn == "CMI") {
417 CMIcomponentNumber = (d->name).substr(3, 2);
418 break;
419 }
420 }
421
422 for (int j = 0; j < m_station->GetNrOfComponents(); j++) {
423 StandardComponent *d = static_cast<StandardComponent *>(m_station->GetComponent(j));
424 std::string_view cn = std::string_view(d->name).substr(0, 2);
425 if (cn == "LB") {
426 LbiComponent *lbic = static_cast<LbiComponent *>(d);
427 if (lbic) {
428 lbic->associated_CMIsubtype = CMIcomponentNumber;
429 } else
430 ATH_MSG_ERROR( "MuonChamber :: cannot associate a CMI subtype to the LB component " );
431 }
432 }
433
434 // Build the MuonStation(readout-geometry) corresponding to this MuonChamber(raw-geometry)
435 MuonStation *mstat{nullptr};
436 if (stName.compare(0, 1, "B") == 0) {
437 mstat = new MuonStation(stName.substr(0, 3), width, totthick, length, longWidth, totthick, length, zi, fi + 1,
438 (zi < 0 && !is_mirrored));
439 } else {
440 mstat = new MuonStation(stName.substr(0, 3), width, length, totthick, longWidth, length, totthick, zi, fi + 1,
441 (zi < 0 && !is_mirrored));
442 }
443 mstat->setPhysVol(ptrd);
444 manager->addMuonStation(std::unique_ptr<MuonStation>(mstat));
445 ATH_MSG_DEBUG( " Building a MuonStation for this MuonChamber "
446 << m_station->GetName() << " at zi, fi " << zi << " " << fi + 1 << " is_mirrored " << is_mirrored);
447
448 // here the big loop over the components !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
449
450 for (int i = 0; i < m_station->GetNrOfComponents(); i++) {
451 StandardComponent *c = static_cast<StandardComponent *>(m_station->GetComponent(i));
452 ATH_MSG_VERBOSE( " Component index " << c->index << " in loop for " << stName << " " << stationType << " at zi, fi " << zi << " " << fi + 1 << " cName "
453 << c->name << " thickness " << c->GetThickness(mysql) << " length " << c->dy << " w, lw " << c->dx1 << " " << c->dx2 );
454 ATH_MSG_VERBOSE( " Component local (amdb) coords " << c->posx << " " << c->posy << " " << c->posz );
455
456 ypos = -thickness / 2. + c->posz + c->GetThickness(mysql) / 2.;
457 zpos = 0.;
458 xpos = 0.;
459
460 ypos = -thickness / 2. + (c->posz + amdbOrigine_along_thickness) + c->GetThickness(mysql) / 2.;
461 zpos = -length / 2. + amdbOrigine_along_length + c->posy + c->dy / 2.;
462 xpos = c->posx;
463
464 const std::string &techname = c->name;
465 std::string_view type = std::string_view(techname).substr(0, 3);
466
467 PVLink lv{}, lvd{}, lvs{}, lvo{};
468 GeoIntrusivePtr<GeoFullPhysVol> lvm{}, lvr{}, lvt{}, lvc{};
469
470 double BeamHeight{0.};
471
472 // Are there cutouts?
473 std::string statType = stName.substr(0, 3);
474 double cthickness = c->GetThickness(mysql);
475 int ncutouts = 0;
476 std::vector<Cutout *> vcutdef;
477 std::vector<std::unique_ptr<Cutout>> vcutdef_todel;
478 for (int ii = 0; ii < m_station->GetNrOfCutouts(); ii++) {
479 Cutout *cut = m_station->GetCutout(ii);
480 cut->setThickness(cthickness * 1.01); // extra thickness to be sure
481
482 if ((cut->subtype == mysql.allocPosFindSubtype(std::string(statType), fi, zi)) && (cut->icut == mysql.allocPosFindCutout(std::string(statType), fi, zi)) && (cut->ijob == c->index)) {
483
484 double tempdx = cut->dx;
485 double tempdy = cut->dy;
486 double templengthY = cut->lengthY;
487 cut->dx = 0.;
488 cut->dy = 0.;
489
490 if (stName.compare(0, 3, "BOG") == 0) {
491 // make the cutouts a bit longer
492 cut->lengthY = templengthY + 31.;
493 }
494
495 cut->dx = tempdx;
496 cut->dy = tempdy;
497
498 if (std::abs(cut->dead1) > 1. && techname == "MDT03")
499 cut->dy = cut->dy + 15.0 * cos(cut->dead1 * Gaudi::Units::deg);
500 // should compensate for the dy position defined in amdb at the bottom of the foam in ML 1 of EMS1,3 and BOS 6
501 // can be applied only for layout >=r.04.04 in rel 15.6.X.Y due to the frozen Tier0 policy
502
503 cut->lengthY = templengthY;
504 // in thickness, cutout will coincide with component
505 // not needed (DHW) double xposcut = 0.; // rel. to component thickness
506 // double yposcut = -xpos+cut->dx; // rel. to component width
507 // double zposcut = -zpos+cut->dy; // rel. to component length
508 // if (stName.substr(0,3)=="BOG")
509 // {
510 // move the extended cut region out a little
511 // if (cut->dy < 10.) zposcut = -zpos+cut->dy - 15.5;
512 // }
513 ncutouts++;
514 ATH_MSG_VERBOSE( "A new cutout for this component " );
515 ATH_MSG_VERBOSE( *cut );
516
517 // Corrected cutout values for BMS7, BMS14
518 if (stName.compare(0, 3, "BMS") == 0) {
519 if (fi == 3) { // stationPhi = 4
520 if (std::abs(zi) == 1) { // stationEta = +-1
521 double margin = 1.0; // make cutout a little bigger to avoid coincident boundaries
522
523 if (type == "RPC" || type == "DED") {
524 cut->widthXl += 2 * margin;
525 cut->widthXs += 2 * margin;
526 cut->dx += margin;
527 cut->lengthY += 2 * margin;
528
529 if (zi > 0)
530 cut->dy = -margin;
531 }
532 }
533
534 if (zi == -1) {
535 if (type == "MDT")
536 cut->dy = 0.;
537 }
538 }
539 }
540
541 // the following is a fine tuning ----- MUST CHECK for a better solution
542 if (stName.compare(0, 3,"BOS") == 0 && zi == -6 && type == "MDT") {
543 cut->dy = c->dy - cut->dy - cut->lengthY - halfpitch;
544 cut->dead1 = 30.; // why this is not 30. or -30. already ?????
545 if (techname == "MDT03")
546 cut->dy = cut->dy + 30.0; // *cos(cut->dead1*Gaudi::Units::deg);
547
548 ATH_MSG_VERBOSE( "Cut dead1 for BOS 6 on C side is " << cut->dead1 );
549
550 }
551
552 // this mirroring of the cutout is necessary only for barrel MDT chambers; for EC the cutout will be automatically mirrored
553 // this fix cannot be applied in 15.6.X.Y for layout < r.04.04 due to the frozen tier0 policy
554
555 if (type == "MDT" && (is_mirrored || zi < 0) && stName.compare(0, 1, "B") == 0) {
556 // MDT in chambers explicitly described at z<0 have to be
557 // rotated by 180deg to adj. tube staggering
558 // reverse the position (x amdb) of the cutout if the m_station is mirrored
559 Cutout *cutmirr = new Cutout(*cut);
560 cutmirr->dx = -cutmirr->dx;
561 // this way, after the rotation by 180 Gaudi::Units::deg, the cut will be at the same global phi
562 // it has for the m_station at z>0
563 vcutdef.push_back(cutmirr);
564 vcutdef_todel.emplace_back(cutmirr);
565 ATH_MSG_VERBOSE( "adding for application mirrored cut \n" << *cutmirr );
566
567 } else if (type == "RPC" || type == "DED") {
568 Cutout *cutRpcType = new Cutout(*cut);
569 // temporary for testing fixes to r.03.09
570 if (stName.compare(0, 3, "BMS") == 0 && zi == 4 && (c->index == 20 || c->index == 21 || c->index == 24 || c->index == 25)) {
571 cutRpcType->dy = 1102.5;
572 }
573
574 if (stName.compare(0, 3, "BOS") == 0 && zi == 6 && type == "DED")
575 cutRpcType->dy = 706.;
576
577 cutRpcType->dy = cutRpcType->dy - c->posy;
578 cutRpcType->dx = cutRpcType->dx - c->posx;
579
580 if (type == "RPC") {
581 RpcComponent *rp = static_cast<RpcComponent *>(c);
582 if (rp->iswap == -1) {
583 cutRpcType->dy = c->dy - (cutRpcType->dy + cutRpcType->lengthY);
584 }
585 }
586
587 ATH_MSG_VERBOSE( " Rpc or ded cutout redefined as follows \n" << *cutRpcType );
588 vcutdef.push_back(cutRpcType);
589 vcutdef_todel.emplace_back(cutRpcType);
590 } else if (type == "TGC") {
591 // In AMDB, y coordinates of cutout and component are given by
592 // radius from detector z-axis. To get standard y value of cutout,
593 // subtract radius of component from radius of cutout
594 Cutout *tgccut = new Cutout(*cut);
595 tgccut->dy -= c->posy; //
596
597 ATH_MSG_VERBOSE( " Tgc cutout redefined as follows \n" << *tgccut );
598 vcutdef.push_back(tgccut);
599 vcutdef_todel.emplace_back(tgccut);
600 } else {
601 vcutdef.push_back(cut);
602 }
603 }
604 } // Loop over cutouts in m_station
605
606 if (ncutouts > 0) {
607 ATH_MSG_DEBUG( c->name << " of station " << stName << " at fi/zi " << fi + 1 << "/" << zi << " has " << ncutouts << " cutouts " );
608
609 }
610 // define here the total transform that will be applied to component:
611 GeoTrf::Transform3D htcomponent(GeoTrf::Transform3D::Identity());
612 GeoTransform *xfcomponent{nullptr};
613 GeoAlignableTransform *xfaligncomponent{nullptr};
614 // for RPCs we need a vector of transforms for M28 geometry...
615
616 if (type == "CRO") {
617 if (stName.compare(0, 1, "B") != 0 && is_mirrored)
618 mstat->setxAmdbCRO(-xpos);
619 else
620 mstat->setxAmdbCRO(xpos);
621 }
622
623 if (type == "MDT") {
624 htcomponent = GeoTrf::TranslateX3D(ypos) * GeoTrf::TranslateZ3D(zpos) * GeoTrf::TranslateY3D(xpos);
625
626 if (zi < 0 && !is_mirrored && stName[0] == 'B') {
627 // this (rotation + shift of halfpitch) will mirror the tube structure w.r.t. the chamber at z>0
628 htcomponent = htcomponent * GeoTrf::RotateX3D(180. * Gaudi::Units::deg);
629 htcomponent = htcomponent * GeoTrf::TranslateZ3D(halfpitch);
630 }
631
632 // ss - 24-05-2006 I don't really understand if this is needed at all
633 // it was introduced by Isabel T.
634 if (zi < 0 && stName.compare(0, 3, "BOG") == 0 && is_mirrored) {
635 // htcomponent = htcomponent*GeoTrf::RotateX3D(180.*Gaudi::Units::deg);
636 // tubes OK but chambers wrong
637 // htcomponent = GeoTrf::RotateX3D(180.*Gaudi::Units::deg)*htcomponent;
638 // chambers OK but tubes wrong
639 htcomponent = GeoTrf::RotateX3D(180. * Gaudi::Units::deg) * htcomponent * GeoTrf::RotateX3D(180. * Gaudi::Units::deg); // turn chambers but go back for tubes
640 } // ss - 24-05-2006 I don't really understand if this is needed at all
641
642 xfaligncomponent = new GeoAlignableTransform(htcomponent);
643 std::string key =std::string( stName) + techname;
644
645 // for cutouts:
646 // MDT cutouts for BOS1,5, BMS7,14, (problem with BMS4,10), EMS, BMG and BIS MDT14
647 bool mdtCutoutFlag = ((stname == "BOS" && std::abs(zi) == 6) || stname == "BMG" || techname == "MDT14" || (stname == "BMS" && (std::abs(zi) == 1 && fi == 3)) ||
648 (stname == "EMS" && (std::abs(zi) == 1 || std::abs(zi) == 3)));
649 if (((manager->IncludeCutoutsFlag() && mdtCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) && zi >= 0) {
650 key += "p" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
651 } else if (((manager->IncludeCutoutsFlag() && mdtCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG")) == 0) && zi < 0) {
652 key += "m" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
653 }
654
655 GeoVPhysVol *fpv = m_FPVMAP->GetDetector(key);
656 if (fpv == nullptr) {
657 std::unique_ptr<Mdt> r = std::make_unique<Mdt>(mysql, c, stName + techname);
658 ATH_MSG_DEBUG( " Building an MDT for station " << key << " component name is " << c->name <<
659 " stName "<<stName<<" techName: "<<techname<< " manager->IncludeCutoutsFlag() "
660 << manager->IncludeCutoutsFlag() << " manager->IncludeCutoutsBogFlag() " << manager->IncludeCutoutsBogFlag() );
661
662
663 if ((manager->IncludeCutoutsFlag() && mdtCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) {
664 lvm = r->build(matManager, mysql, vcutdef);
665 } else {
666 lvm = r->build(matManager, mysql);
667 }
668 m_FPVMAP->StoreDetector(lvm, key);
669 } else {
670 GeoFullPhysVol *rfpv = static_cast<GeoFullPhysVol *>(fpv);
671 ATH_MSG_VERBOSE( " This MDT for station " << key << " component name is " << c->name << " already exists; clone it " );
672 lvm = rfpv->clone();
673 }
674
675 } else if (type == "SPA" && manager->MinimalGeoFlag() == 0) {
676 if (techname == "SPA01" && stName.compare(0, 1, "C") == 0) {
677 ATH_MSG_DEBUG( "Ficticious spacer SPA01 in CSC chamber - skip it " );
678 // ignore SPA 1 component of CSS/CSL chambers in R02.03 (it is there only for AMDB convenience,
679 // leaving the CSC envelop => global position of the m_station unchanged)
680 continue;
681 }
682
683 htcomponent = GeoTrf::TranslateX3D(ypos) * GeoTrf::TranslateZ3D(zpos);
684 xfcomponent = new GeoTransform(htcomponent);
685 std::string key = std::string(stName) + techname;
686 if ((manager->IncludeCutoutsFlag() || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) && zi >= 0) {
687 key += "p" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
688 } else if ((manager->IncludeCutoutsFlag() || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3,"BOG") == 0)) && zi < 0) {
689 key += "m" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
690 }
691
692 GeoVPhysVol *fpv = m_FPVMAP->GetDetector(key);
693 if (fpv == nullptr) {
694 std::unique_ptr<Spacer>r = std::make_unique<Spacer>(mysql, c);
695 ATH_MSG_DEBUG( " Building a SPA for m_station "<< key << " component name is " << c->name );
696 if (manager->IncludeCutoutsFlag() || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) {
697 lv = r->build(matManager, 1);
698 } else {
699 lv = r->build(matManager);
700 }
701 ATH_MSG_DEBUG( " Storing in FPVMAP with key " << key );
702 m_FPVMAP->StoreDetector(lv, key);
703 } else {
704 lv = fpv;
705 }
706 } else if ((type == "CHV" || type == "CRO" || type == "CMI" || type == "LB0" || type == "LBI") && manager->MinimalGeoFlag() == 0) {
707 std::unique_ptr<SpacerBeam> r = std::make_unique<SpacerBeam>(mysql, c);
708 BeamHeight = r->height;
709 ypos = c->posx;
710 double xpos = (c->posz + amdbOrigine_along_thickness) - thickness / 2. + BeamHeight / 2.;
711 if (type.compare(0, 2, "LB") == 0)
712 xpos -= LByShift;
713
714 double angle = 0.;
715 if (std::abs(c->excent) > 0.001) {
716 angle = atan((longWidth - width) / length / 2.);
717 if (c->excent < 0.)
718 angle = -angle;
719 }
720
721 // This is an attempt to provide some info to LB construction in order
722 // to avoid the clash of LB with CXx in the endcaps ...
723 if (type == "LB0") {
724 if (stName == "EML1" || stName == "EML6") {
725 if ((c->dx1 > width) && zpos < 0.) {
726 r->width = 0.98 * width;
727 }
728 if ((c->dx1 / longWidth) > 0.98 && zpos > 0.) {
729 double mywidth = 0.93 * longWidth;
730 r->width = mywidth;
731 }
732 }
733 }
734
735 if (type == "CMI" || type == "CHV" || type == "CRO") {
736 // Shorten CHV, CMI lengths to fit in BOL4 envelope
737 if (stname == "BOL" && zi == 1 && (fi + 1) == 3) {
738 r->length = length - halfpitch;
739 zpos = -halfpitch / 2.;
740 }
741 }
742
743 if (!is_mirrored) {
744 htcomponent = GeoTrf::Translate3D(xpos, ypos, zpos) * GeoTrf::RotateX3D(angle);
745 } else {
746 htcomponent = GeoTrf::Translate3D(xpos, -ypos, zpos) * GeoTrf::RotateX3D(-angle);
747 }
748 xfcomponent = new GeoTransform(htcomponent);
749
750 std::string key = stName + techname;
751 if ((manager->IncludeCutoutsFlag() || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) && zi >= 0) {
752 key += "p" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
753 } else if ((manager->IncludeCutoutsFlag() || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) && zi < 0) {
754 key += "m" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
755 }
756 // can have LB of different length in same m_station:
757 if (type.substr(0, 2) == "LB")
758 key += buildString(int(c->dx1), 0);
759
760 ATH_MSG_DEBUG( " Building a SpacerBeam for m_station "<< key << " component name is "<< c->name );
761 GeoVPhysVol *fpv = m_FPVMAP->GetDetector(key);
762 if (fpv == nullptr || (stName.compare(0, 3, "BOG") == 0 && type == "CMI")) {
763 if (stName.compare(0, 3, "BOG") == 0) {
764 ATH_MSG_VERBOSE( " Building a SpacerBeam for station " << key << " component name is " << c->name );
765 }
766 if (manager->IncludeCutoutsFlag() || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) {
767 lvo = r->build(matManager, 1, is_barrel);
768 } else {
769 lvo = r->build(matManager, is_barrel);
770 }
771 m_FPVMAP->StoreDetector(lvo, key);
772 // AMDB origin is in bottom centre of bottom cross-piece at
773 // end of bar.
774 // From centre, it is -height/2 in x, 0 in y, -length/2 in z
775 } else {
776 if (stName.compare(0, 3,"BOG") == 0)
777 ATH_MSG_VERBOSE( " This spacerbeam for station " << key << " component name is " << c->name << " already exists; re-use it " );
778 lvo = fpv;
779 }
780
781 } else if (type == "RPC") {
782 // position stuff needed for cutout, used to be below:
783 RpcComponent *rp = static_cast<RpcComponent *>(c);
784 int ndivy = rp->ndivy;
785 int ndivz = rp->ndivz;
786
787 if (ndivz != 1 || ndivy != 1) {
788 ATH_MSG_ERROR( " RPC segmentation z,y " << ndivz << " " << ndivy );
789 }
790
791 double xpos = c->posx;
792 // implement really the mirror symmetry
793 if (is_mirrored)
794 xpos = -xpos;
795
796 ATH_MSG_VERBOSE( " In station " << stName << " with " << nDoubletR << " doubletR,"
797 << " RPC " << (c->name).substr(3, 2) << " has swap flag = " << rp->iswap << " ypos, zpos " << ypos << " " << zpos << " " );
798
799 htcomponent = GeoTrf::TranslateX3D(ypos) * GeoTrf::TranslateY3D(xpos) * GeoTrf::TranslateZ3D(zpos);
800 if (rp->iswap == -1) { // this is like amdb iswap
801 htcomponent = htcomponent * GeoTrf::RotateY3D(180 * Gaudi::Units::deg);
802 }
803 xfaligncomponent = new GeoAlignableTransform(htcomponent);
804
805 // end of position stuff
806
807 bool rpcCutoutFlag = (stname == "BOS" && std::abs(zi) == 6) || (stname == "BMS" && (std::abs(zi) == 2 || std::abs(zi) == 4 || std::abs(zi) == 6)) ||
808 (stname == "BMS" && std::abs(zi) == 1 && fi == 3);
809 std::string key = stName + techname;
810 if (((manager->IncludeCutoutsFlag() && rpcCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) && zi >= 0) {
811 key += "p" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0) + "_" +
812 buildString(vcutdef.size(), 0) + "_" + buildString(rp->iswap, 0);
813 } else if (((manager->IncludeCutoutsFlag() && rpcCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) && zi < 0) {
814 key += "m" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0) + "_" +
815 buildString(vcutdef.size(), 0) + "_" + buildString(rp->iswap, 0);
816 }
817 PVLink fpv = m_FPVMAP->GetDetector(key);
818 if (fpv == nullptr) {
819 std::unique_ptr<Rpc> r = std::make_unique<Rpc>(mysql, c);
820 r->setLogVolName(std::string(stName) + techname);
821 if (stName.find("BI") != std::string::npos) {
822 std::map<std::string, float>::const_iterator yItr = rpcYTrans.find(techname);
823 if (yItr != rpcYTrans.end())
824 r->y_translation = yItr->second;
825 std::map<std::string, float>::const_iterator zItr = rpcZTrans.find(techname);
826 if (zItr != rpcZTrans.end())
827 r->z_translation = zItr->second;
828 }
829
830 if ((manager->IncludeCutoutsFlag() && rpcCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) {
831 lvr = r->build(matManager, mysql, manager->MinimalGeoFlag(), 1, vcutdef);
832 } else {
833 lvr = r->build(matManager, mysql, manager->MinimalGeoFlag());
834 }
835
836 m_FPVMAP->StoreDetector(lvr, key);
837 } else {
838 auto rfpv = dynamic_pointer_cast<GeoFullPhysVol>(fpv);
839 lvr = rfpv->clone();
840 }
841
842 } else if (type == "DED" && manager->MinimalGeoFlag() == 0) {
843 double xpos = c->posx;
844 if (is_mirrored)
845 xpos = -xpos;
846 htcomponent = GeoTrf::TranslateX3D(ypos) * GeoTrf::TranslateY3D(xpos) * GeoTrf::TranslateZ3D(zpos);
847
848 xfcomponent = new GeoTransform(htcomponent);
849
850 bool dedCutoutFlag = (stname == "BOS" && std::abs(zi) == 6) || (stname == "BMS" && (std::abs(zi) == 2 || std::abs(zi) == 4 || std::abs(zi) == 6)) ||
851 (stname == "BMS" && std::abs(zi) == 1 && fi == 3);
852 std::string key = std::string(stName) + techname;
853 if (((manager->IncludeCutoutsFlag() && dedCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3,"BOG") == 0)) && zi >= 0) {
854 key += "p" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0) + "_" +
855 buildString(vcutdef.size(), 0);
856 } else if (((manager->IncludeCutoutsFlag() && dedCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) && zi < 0) {
857 key += "m" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0) + "_" +
858 buildString(vcutdef.size(), 0);
859 }
860 key += buildString(int(c->dy), 0) + "_" + buildString(int(c->dx1), 0);
861 PVLink fpv = m_FPVMAP->GetDetector(key);
862
863 if (fpv == nullptr) {
864 std::unique_ptr<Ded> r = std::make_unique<Ded>(mysql, c);
865 ATH_MSG_VERBOSE( " Building a DED for station " << key << " component name is " << c->name );
866 if ((manager->IncludeCutoutsFlag() && dedCutoutFlag) || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3, "BOG") == 0)) {
867 lvd = r->build(matManager, mysql, 1, vcutdef);
868 } else {
869 lvd = r->build(matManager, mysql);
870 }
871
872 m_FPVMAP->StoreDetector(lvd, key);
873 } else {
874 lvd = fpv;
875 ATH_MSG_VERBOSE( " Re-using DED for station " << key << " component name is " << c->name );
876 }
877
878 } else if (type == "SUP" && manager->MinimalGeoFlag() == 0) {
879 ypos = -thickness / 2. + c->posz;
880 double zpos = -length / 2. + c->posy + c->dy / 2. - SupComponent::zAMDB0(mysql, *c);
881 ypos = ypos - SupComponent::xAMDB0(mysql, *c);
882 double xpos = c->posx - SupComponent::yAMDB0(mysql, *c);
883
884 htcomponent = GeoTrf::TranslateX3D(ypos) * GeoTrf::TranslateY3D(xpos) * GeoTrf::TranslateZ3D(zpos);
885 std::string key = std::string(stName) + techname;
886 if ((manager->IncludeCutoutsFlag() || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3,"BOG") == 0)) && zi >= 0) {
887 key += "p" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
888 } else if ((manager->IncludeCutoutsFlag() || (manager->IncludeCutoutsBogFlag() && stName.compare(0, 3,"BOG") == 0)) && zi < 0) {
889 key += "m" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
890 }
891
892 GeoVPhysVol *fpv = m_FPVMAP->GetDetector(key);
893 if (fpv == nullptr) {
894 m_FPVMAP->StoreDetector(lvs, key);
895 } else {
896 lvs = fpv;
897 }
898
899 } else if (type == "TGC") {
900 TgcComponent *tg = static_cast<TgcComponent *>(m_station->GetComponent(i));
901 TgcComponent *tgInner = static_cast<TgcComponent *>(m_station->GetComponent(0));
902 irad = tgInner->posy;
903 TgcComponent *tgOuter = static_cast<TgcComponent *>(m_station->GetComponent(m_station->GetNrOfComponents() - 1));
904 double orad = tgOuter->posy + tgOuter->dy;
905 double start = -(orad - irad) / 2. + (tg->posy - irad) + tg->dy / 2;
906 double xstart = -thickness / 2. + tg->GetThickness(mysql) / 2.;
907 htcomponent = GeoTrf::TranslateX3D(xstart + tg->posz) * GeoTrf::TranslateZ3D(start);
908 xfaligncomponent = new GeoAlignableTransform(htcomponent);
909
910 // Define key for this TGC component
911 std::string key = std::string(stName) + techname;
912 if (manager->IncludeCutoutsFlag()) {
913 if (mysql.allocPosFindCutout(statType, fi, zi) > 0) {
914 // If there is a cutout for this chamber, give it a special key
915 if (zi >= 0) {
916 key += "p" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
917 } else if (zi < 0) {
918 key += "m" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
919 }
920 }
921 }
922
923 char chswidth[32];
924 sprintf(chswidth, "%i", static_cast<int>(10 * c->dx1));
925 key += chswidth;
926
927 GeoVPhysVol *fpv = m_FPVMAP->GetDetector(key);
928 if (fpv == nullptr) {
929 std::unique_ptr<Tgc> t = std::make_unique<Tgc>(mysql, c);
930 t->setLogVolName(std::string(stName) + techname);
931 if (manager->IncludeCutoutsFlag()) {
932 lvt = t->build(matManager, mysql, manager->MinimalGeoFlag(), 1, vcutdef);
933 } else {
934 lvt = t->build(matManager, mysql, manager->MinimalGeoFlag());
935 }
936 m_FPVMAP->StoreDetector(lvt, key);
937 } else {
938 GeoFullPhysVol *rfpv = static_cast<GeoFullPhysVol *>(fpv);
939 lvt = rfpv->clone();
940 }
941
942 } else if (type == "CSC") {
943 htcomponent = GeoTrf::TranslateX3D(ypos) * GeoTrf::TranslateZ3D(zpos);
944 xfaligncomponent = new GeoAlignableTransform(htcomponent);
945 // Here define the key for this CSC component
946 std::string key = std::string(stName) + techname;
947 if (manager->IncludeCutoutsFlag() && zi >= 0) {
948 key += "p" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
949 } else if (manager->IncludeCutoutsFlag() && zi < 0) {
950 key += "m" + buildString(mysql.allocPosFindSubtype(statType, fi, zi), 0) + "_" + buildString(mysql.allocPosFindCutout(statType, fi, zi), 0);
951 }
952
953 GeoVPhysVol *fpv = m_FPVMAP->GetDetector(key);
954 if (fpv == nullptr) {
955 std::unique_ptr<Csc> t = std::make_unique<Csc>(mysql, c);
956 t->setLogVolName(std::string(stName) + techname);
957
958 if (manager->IncludeCutoutsFlag()) {
959 lvc = t->build(matManager, mysql, manager->MinimalGeoFlag(), 1, vcutdef);
960 } else {
961 lvc = t->build(matManager, mysql, manager->MinimalGeoFlag());
962 }
963
964 m_FPVMAP->StoreDetector(lvc, key);
965 } else {
966 GeoFullPhysVol *rfpv = static_cast<GeoFullPhysVol *>(fpv);
967 lvc = rfpv->clone();
968 }
969
970 } else {
971 if (type != "MDT" && type != "RPC" && type != "TGC" && type != "SUP" && type != "DED" && type != "SPA" && type != "CHV" && type != "CRO" && type != "CMI" &&
972 type != "LB0" && type != "LBI") {
973 ATH_MSG_INFO( "Unknown component " << type );
974 }
975 }
976
977 // Place components in chamber envelope
978 if (lvm && manager->mdtIdHelper()) {
979 int stationEta = zi;
980 int stationPhi = fi + 1;
981 int ml = 1;
982 int tubel = 1;
983 int tube = 1;
984 if (ypos > 5.)
985 ml = 2; // Need >5 instead of >0 because BIS78 is not perfectly centered
986 std::string stag = "ml[" + MuonGM::buildString(ml, 0) + "]" + techname + "component";
987
988 GeoNameTag *nm = new GeoNameTag(stag);
989 ptrd->add(new GeoIdentifierTag(c->index));
990 ptrd->add(nm);
991
992 xfaligncomponent->setDelta(GeoTrf::Transform3D::Identity());
993 // delete xfcomponent;
994 ptrd->add(xfaligncomponent);
995 ptrd->add(lvm);
996 const MdtIdHelper *mdt_id = manager->mdtIdHelper();
997 std::unique_ptr<MdtReadoutElement> det = std::make_unique<MdtReadoutElement>(lvm, stName, manager);
998 Position ip = mysql.GetStationPosition(stName.substr(0, 3), fi, zi);
999 setMdtReadoutGeom(mysql, det.get(), static_cast<MdtComponent *>(c), ip);
1000 det->setHasCutouts(ncutouts > 0);
1001 det->setNMdtInStation(nMdt);
1002 Identifier id = mdt_id->channelID(stationType, stationEta, stationPhi, ml, tubel, tube);
1003 det->setIdentifier(id);
1004 det->setMultilayer(ml);
1005 det->setParentMuonStation(mstat);
1006 det->geoInitDone();
1007
1008 if (ml == 1) {
1009 // set fixed point for MDT deformations: s0,z0,t0 for the point at lowest t,z (z,y amdb) and s=x=0
1010 mstat->setBlineFixedPointInAmdbLRS(c->posx, c->posy, c->posz);
1011 } else {
1013 if (c->posy < b0.y())
1014 mstat->setBlineFixedPointInAmdbLRS(b0.x(), c->posy, b0.z());
1015 }
1016
1017 int jobIndex = c->index;
1018
1019 mstat->addMuonReadoutElementWithAlTransf(det.get(), xfaligncomponent, jobIndex);
1020 ATH_MSG_DEBUG( std::string(stName + techname) << " trying to build a MDT Id from stType/eta/phi/ml/tl/t " << stationType << "/" << stationEta << "/"
1021 << stationPhi << "/" << ml << "/" << tubel << "/" << tube << endmsg << " Copy number is " << c->index << " tagName " << stag );
1022
1023
1024 manager->addMdtReadoutElement(std::move(det));
1025 }
1026
1027 if (lvc && manager->cscIdHelper()) {
1028 CscComponent *cs = static_cast<CscComponent *>(m_station->GetComponent(i));
1029 int stationEta = zi;
1030 int stationPhi = fi + 1;
1031 int chamberLayer = 1;
1032 if (ypos > 0.)
1033 chamberLayer = 2;
1034 std::string stag = "cl[" + MuonGM::buildString(chamberLayer, 0) + "]" + techname + "component";
1035 GeoNameTag *nm = new GeoNameTag(stag);
1036 ptrd->add(new GeoIdentifierTag(c->index));
1037 ptrd->add(nm);
1038
1039 xfaligncomponent->setDelta(GeoTrf::Transform3D::Identity());
1040 // delete xfcomponent;
1041 ptrd->add(xfaligncomponent);
1042 ptrd->add(lvc);
1043
1044 std::unique_ptr<CscReadoutElement> det = std::make_unique<CscReadoutElement>(lvc, stName, manager);
1045 Position ip = mysql.GetStationPosition(stName.substr(0, 3), fi, zi);
1046 setCscReadoutGeom(mysql, det.get(), cs, ip);
1047
1048 const CscIdHelper *csc_id = manager->cscIdHelper();
1049 det->setHasCutouts(ncutouts > 0);
1050 Identifier id = csc_id->channelID(stationType, stationEta, stationPhi, chamberLayer, 1, 0, 1);
1051 det->setIdentifier(id);
1052 det->setChamberLayer(chamberLayer);
1053 det->setParentMuonStation(mstat);
1054
1055 int jobIndex = c->index;
1056 // mstat->addMuonReadoutElement(det,jobIndex);
1057 mstat->addMuonReadoutElementWithAlTransf(det.get(), xfaligncomponent, jobIndex);
1058 ATH_MSG_DEBUG( stName << techname << " trying to build a CSC Id from stType/eta/phi/ml " << stationType << "/" << stationEta << "/"
1059 << stationPhi << "/" << chamberLayer << "/ and /1/0/1" << endmsg << " Copy number is " << c->index << " tagName " << stag );
1060
1061 // set alignment parameters for the wire layers
1062 manager->addCscReadoutElement(std::move(det));
1063 }
1064
1065 if (lvt && manager->tgcIdHelper()) {
1066 ATH_MSG_DEBUG( " Adding a TGC chamber to the tree zi,fi, is_mirrored " << zi << " " << fi + 1 << " " << is_mirrored );
1067
1068 TgcComponent *tg = static_cast<TgcComponent *>(m_station->GetComponent(i));
1069 ATH_MSG_VERBOSE( "There's a TGC named " << techname << " of thickness " << tg->GetThickness(mysql) );
1070
1071 const TgcIdHelper *tgc_id = manager->tgcIdHelper();
1072 int stationEta = 0;
1073 stationEta = tg->index;
1074 if (zi < 0)
1075 stationEta = -stationEta;
1076 int stationPhi = 0;
1077 stationPhi = MuonGM::stationPhiTGC(stName, fi + 1, zi);
1078 int ttag = 1000 * stationPhi + tg->index;
1079 std::string stag = "stPhiJob[" + MuonGM::buildString(ttag, 0) + "]" + techname + "tgccomponent";
1080 GeoNameTag *nm = new GeoNameTag(stag);
1081 int geoid = 0;
1082 if (useAssemblies || isAssembly) {
1083 geoid = c->index;
1084 } else {
1085 if (zi < 0)
1086 ttag = -ttag;
1087 geoid = ttag;
1088 }
1089 ptrd->add(new GeoIdentifierTag(geoid));
1090 ptrd->add(nm);
1091
1092 xfaligncomponent->setDelta(GeoTrf::Transform3D::Identity());
1093
1094 // delete xfcomponent;
1095 ptrd->add(xfaligncomponent);
1096 ptrd->add(lvt);
1097
1098 std::unique_ptr<TgcReadoutElement> det = std::make_unique<TgcReadoutElement>(lvt, stName, manager);
1099 Position ip = mysql.GetStationPosition(stName.substr(0, 3), fi, zi);
1100 setTgcReadoutGeom(mysql, det.get(), tg, ip, stName);
1101 det->setHasCutouts(ncutouts > 0);
1102 Identifier id = tgc_id->channelID(stationType, stationEta, stationPhi, 1, false, 1);
1103 det->setIdentifier(id);
1104 det->setParentMuonStation(mstat);
1105
1106 int jobIndex = c->index;
1107
1108 mstat->addMuonReadoutElementWithAlTransf(det.get(), xfaligncomponent, jobIndex);
1109
1110 ATH_MSG_DEBUG( stName << techname << " trying to build a TGC Id from stType/eta/phi " << stationType << "/" << stationEta << "/" << stationPhi
1111 << "/ and /1/0/1" << endmsg << " Copy number is " << geoid << " tagName = " << stag );
1112 manager->addTgcReadoutElement(std::move(det));
1113 }
1114
1115 if (lvr && RPCON && manager->rpcIdHelper()) {
1116 RpcComponent *rp = static_cast<RpcComponent *>(c);
1117 int ndivy = rp->ndivy;
1118 int ndivz = rp->ndivz;
1119
1120 if (ndivz != 1 || ndivy != 1) {
1121 ATH_MSG_ERROR( " RPC segmentation z,y " << ndivz << " " << ndivy );
1122 }
1123
1124 double zpos = -length / 2. + c->posy + c->dy / 2.;
1125 double xpos = c->posx;
1126
1127 // implement really the mirror symmetry
1128 if (is_mirrored)
1129 xpos = -xpos;
1130 // ... putting back to here!
1131
1132 const RpcIdHelper *rpc_id = manager->rpcIdHelper();
1133 int stationEta = zi;
1134 int stationPhi = fi + 1;
1135 int doubletR = 1;
1136 int doubletZ = 1;
1137
1138 if (nRpc > 1 && nDoubletR == 2 && ypos > 0.)
1139 doubletR = 2;
1140 ndbz[doubletR - 1]++;
1141
1142 // the BI RPCs are 3-gap RPCs mounted inside of the BI (s)MDTs
1143 if (stname.find("BI") != std::string::npos) {
1144 if (stname.find("BIS") != std::string::npos) {
1145 // for BIS78, there is a second RPC doubletZ at amdb-y (MuonGeoModel-z)=144mm inside the station
1146 if (std::abs(stationEta)>= 7){
1147 ATH_MSG_DEBUG("BIS78 station eta: "<<stationEta<<" phi: "<<stationPhi<<" dR: "<<doubletR<<" dZ:"<< doubletZ <<" rp: "<<rp->posz);
1148 }
1149 if (std::abs(stationEta) >= 7 && rp->posz > 80)
1150 doubletZ = 2;
1151 else
1152 doubletZ = 1;
1153 } else {
1154 // for BIL/BIM/BIR, we have 10 RPCs put on 6 MDT stations, thus, need to exploit doubletZ as additional variable on top of stationEta
1155 // only for BIL, there are sometimes 2 RPCs per 1 MDT station, namely for stationEta 1,3,4,6
1156 if (stname.find("BIL") != std::string::npos && std::abs(stationEta) < 7 && std::abs(stationEta) != 2 && std::abs(stationEta) != 5) {
1157 if (rp->posy > 1)
1158 doubletZ = 2; // put the chamber with positive amdb-z to doubletZ=2
1159 } else
1160 doubletZ = 1;
1161 }
1162 } else {
1163 if (zi <= 0 && !is_mirrored) {
1164 if (zpos < -100 * Gaudi::Units::mm)
1165 doubletZ = 2;
1166 } else {
1167 if (zpos > 100 * Gaudi::Units::mm)
1168 doubletZ = 2;
1169 }
1170 }
1171
1172 // BMS (BOG) RPCs can have |xpos|=950 (|xpos|=350)
1173 if (std::abs(xpos) > 100. * Gaudi::Units::mm) {
1174 if (ndbz[doubletR - 1] > 2) {
1175 doubletZ = 3;
1176 }
1177 ndbz[doubletR - 1]--;
1178 }
1179
1180 int dbphi = 1;
1181
1182 // this special patch is needed for BMS in the ribs where xpos is ~950mm;
1183 // the theshold to 100mm (too low) caused a bug
1184 // in BOG at eta +/-4 and stationEta 7 (not 6) ==>> 28 Jan 2016 raising the threshold to 400.mm
1185 // doublet phi not aware of pos. in space !!!
1186 if (xpos > 400. * Gaudi::Units::mm)
1187 dbphi = 2;
1188
1189 int doubletPhi = dbphi;
1190 // doublet phi aware of pos. in space !!!
1191 if (zi < 0 && is_mirrored && doubletZ == 3) {
1192 doubletPhi++;
1193 if (doubletPhi > 2)
1194 doubletPhi = 1;
1195 } else if (zi < 0 && is_mirrored && doubletZ == 2 && doubletR == 1 && stName == "BMS6") {
1196 doubletPhi++;
1197 if (doubletPhi > 2)
1198 doubletPhi = 1;
1199 }
1200 // never defined fields: set to the lower limit
1201 int gasGap = 1;
1202 int measuresPhi = 0;
1203 int strip = 1;
1204
1205 int geoid = 0;
1206 std::string stag;
1207 int tag = doubletZ + doubletR * 100 + dbphi * 1000;
1208 if (rp->iswap == -1)
1209 tag = -1 * tag;
1210 stag = "SwapdbPdbRdbZ[" + MuonGM::buildString(tag, 0) + "]" + techname + "rpccomponent";
1211 if (useAssemblies || isAssembly) {
1212 geoid = c->index;
1213 } else {
1214 int tag = rp->index + doubletR * 100 + dbphi * 1000;
1215 if (rp->iswap == -1)
1216 tag = -1 * tag;
1217 geoid = tag;
1218 }
1219
1220 GeoNameTag *nm = new GeoNameTag(stag);
1221 ptrd->add(new GeoIdentifierTag(geoid));
1222 ptrd->add(nm);
1223
1224 xfaligncomponent->setDelta(GeoTrf::Transform3D::Identity());
1225 // delete xfcomponent;
1226 ptrd->add(xfaligncomponent);
1227 ptrd->add(lvr);
1228
1229 std::unique_ptr<RpcReadoutElement> det = std::make_unique<RpcReadoutElement>(lvr, stName, zi, fi + 1, is_mirrored, manager);
1230 Position ip = mysql.GetStationPosition(stName.substr(0, 3), fi, zi);
1231 setRpcReadoutGeom(mysql, det.get(), rp, ip);
1232 Identifier id = rpc_id->channelID(stationType, stationEta, stationPhi, doubletR, doubletZ, doubletPhi, gasGap, measuresPhi, strip);
1233 det->setIdentifier(id);
1234 det->setHasCutouts(ncutouts > 0);
1235 det->setDoubletR(doubletR);
1236 det->setDoubletZ(doubletZ);
1237 det->setDoubletPhi(doubletPhi);
1238
1239 ATH_MSG_DEBUG( stName << techname << " trying to build a RPC Id from stType/eta/phi/dbR/dbZ/dbP " << stationType << "/" << stationEta << "/"
1240 << stationPhi << "/" << doubletR << "/" << doubletZ << "/" << doubletPhi << "///" << gasGap << "/" << measuresPhi << "/" << strip << endmsg
1241 << " Copy number " << geoid << " tagName= " << stag );
1242 det->setParentMuonStation(mstat);
1243
1244 int jobIndex = c->index;
1245
1246 mstat->addMuonReadoutElementWithAlTransf(det.get(), xfaligncomponent, jobIndex);
1247
1248
1249 if (stName.find("BI") != std::string::npos) {
1250 std::map<std::string, float>::const_iterator yItr = rpcYTrans.find(techname);
1251 if (yItr != rpcYTrans.end())
1252 det->setYTranslation(yItr->second);
1253 std::map<std::string, float>::const_iterator zItr = rpcZTrans.find(techname);
1254 if (zItr != rpcZTrans.end())
1255 det->setZTranslation(zItr->second);
1256 }
1257
1258 det->fillCache(); // fill temporary cache (global position on known yet)
1259 det->initDesign();
1260 det->clearCache(); // clear temporary cache
1261 manager->addRpcReadoutElement(std::move(det));
1262 } // if (lvr && RPCON && manager->rpcIdHelper()) {
1263
1264 if (lvs && RPCON) {
1265 std::string cname = c->name;
1266 ATH_MSG_VERBOSE( " yes, the component is a SupComponent named " << cname );
1267 GeoNameTag *nm = new GeoNameTag(stName + "_stName " + techname + " supcomponent");
1268 ptrd->add(new GeoIdentifierTag(c->index));
1269 ptrd->add(nm);
1270 ptrd->add(xfcomponent);
1271 ATH_MSG_VERBOSE( " register x" );
1272 ATH_MSG_VERBOSE( " register y" );
1273 ATH_MSG_VERBOSE( " register z" );
1274
1275 ptrd->add(lvs);
1276 ATH_MSG_VERBOSE( " register lvs" );
1277 }
1278
1279 if (lvd && RPCON) {
1280 GeoNameTag *nm = new GeoNameTag(stName + "_stName " + techname + " dedcomponent");
1281 ptrd->add(new GeoIdentifierTag(c->index));
1282 ptrd->add(nm);
1283
1284 ptrd->add(xfcomponent);
1285 ptrd->add(lvd);
1286 }
1287
1288 if (lvo) {
1289 // translate from AMDB chamber coordinates:
1290 // (move chamber origin and swap axes around)
1291 // D-line gives AMDB coords of AMDB component origin
1292 // we need MuonGM coords of MuonGM component origin...
1293 // take off length/2, thickness/2 to get to AMDB chamber org
1294 // then put back GetLength()/2, GetThickness()/2 to get to
1295 // component org.
1296 GeoNameTag *nm = new GeoNameTag(stName + "_stName " + techname + " component");
1297 ptrd->add(new GeoIdentifierTag(c->index));
1298 ptrd->add(nm);
1299
1300 ptrd->add(xfcomponent);
1301 ptrd->add(lvo);
1302 }
1303
1304 if (lv) {
1305 GeoNameTag *nm = new GeoNameTag(stName + "_stName " + techname + " component");
1306 ptrd->add(new GeoIdentifierTag(c->index));
1307 ptrd->add(nm);
1308 ptrd->add(xfcomponent);
1309 ptrd->add(lv);
1310 }
1311
1312 } // End big loop over components
1314
1315 return ptrd;
1316 }
1317
1319 CscReadoutElement *re, const CscComponent *cc, const Position &ip) {
1320
1321 re->m_Ssize = cc->dx1;
1322 re->m_LongSsize = cc->dx2;
1323 re->m_Rsize = cc->dy;
1324 re->m_LongRsize = cc->dy;
1325 re->m_Zsize = cc->GetThickness(mysql);
1326 re->m_LongZsize = cc->GetThickness(mysql);
1327 re->m_RlengthUpToMaxWidth = cc->maxwdy;
1328 re->m_excent = cc->excent;
1329
1330 // Csc features specific to this readout element
1331 std::string tname = cc->name;
1332 re->setTechnologyName(tname);
1333
1334 if (ip.isAssigned) {
1335 re->setStationS(ip.shift);
1336 } else {
1337 ATH_MSG_ERROR( " MuonChamber::setCscReadoutGeom: position not found " );
1338 assert(0);
1339 }
1340
1341 const CSC *thisc = dynamic_cast<const CSC*>(mysql.GetTechnology(tname));
1342 re->m_anodecathode_distance = thisc->anocathodist;
1343 re->m_ngasgaps = thisc->numOfLayers;
1344 re->m_nstriplayers = thisc->numOfLayers;
1345 re->m_nwirelayers = thisc->numOfLayers;
1346 re->m_roxacellwidth = thisc->roxacellwith;
1347 re->m_nEtastripsperlayer = thisc->nEtastrips;
1348 re->m_nPhistripsperlayer = thisc->nPhistrips;
1349 re->m_Etastrippitch = thisc->cathreadoutpitch;
1350 re->m_Phistrippitch = thisc->phireadoutpitch;
1351 re->m_Etastripwidth = re->m_Etastrippitch;
1352 re->m_Phistripwidth = re->m_Phistrippitch;
1353 }
1354
1356 MdtReadoutElement *re, const MdtComponent *cc, const Position &ip) {
1357
1358 re->m_Ssize = cc->dx1;
1359 re->m_LongSsize = cc->dx2;
1360
1361 if (re->m_inBarrel) {
1362 re->m_Rsize = cc->GetThickness(mysql);
1363 re->m_LongRsize = cc->GetThickness(mysql);
1364 re->m_Zsize = cc->dy;
1365 re->m_LongZsize = cc->dy;
1366 } else {
1367 re->m_Rsize = cc->dy;
1368 re->m_LongRsize = cc->dy;
1369 re->m_Zsize = cc->GetThickness(mysql);
1370 re->m_LongZsize = cc->GetThickness(mysql);
1371 }
1372
1373 re->m_cutoutShift = cc->cutoutTubeXShift;
1374 re->m_tubelenStepSize = cc->tubelenStepSize;
1375
1376 if (ip.isAssigned) {
1377 re->setStationS(ip.shift);
1378 } else {
1379 ATH_MSG_ERROR( " MuonChamber::setMdtReadoutGeom: position not found " );
1380 assert(0);
1381 }
1382
1383 std::string tname = cc->name;
1384 re->setTechnologyName(tname);
1385 const MDT *thism = dynamic_cast<const MDT*>(mysql.GetTechnology(tname));
1386 re->m_nlayers = thism->numOfLayers;
1387 re->m_tubepitch = thism->pitch;
1388 re->m_tubelayerpitch = thism->y[1] - thism->y[0];
1389 re->m_endpluglength = thism->tubeEndPlugLength;
1390 re->m_deadlength = cc->deadx; // thism->tubeDeadLength;
1391 re->m_innerRadius = thism->innerRadius;
1392 re->m_tubeWallThickness = thism->tubeWallThickness;
1393
1394 if (re->m_inBarrel) {
1395 re->m_ntubesperlayer = int(re->m_Zsize / re->m_tubepitch);
1396 re->m_nsteps = 1; // all tubes have the same length
1397 re->m_ntubesinastep = re->m_ntubesperlayer;
1398 re->m_tubelength[0] = re->m_Ssize;
1399 } else {
1400 re->m_ntubesperlayer = int(re->m_Rsize / re->m_tubepitch);
1401 re->m_nsteps = int(re->m_Rsize / re->m_tubelenStepSize);
1402 re->m_ntubesinastep = int(re->m_tubelenStepSize / re->m_tubepitch);
1403 re->m_tubelength[0] = re->m_Ssize;
1404 double diff = (re->m_LongSsize - re->m_Ssize) * (re->m_LongRsize - re->m_tubepitch / 2.) / re->m_LongRsize;
1405 for (int is = 0; is < re->m_nsteps; ++is) {
1406 double len = re->m_Ssize + is * diff / re->m_nsteps;
1407 re->m_tubelength[is] = len;
1408 }
1409 }
1410
1411 for (int tl = 0; tl < re->m_nlayers; ++tl) {
1412 re->m_firstwire_x[tl] = thism->x[tl];
1413 re->m_firstwire_y[tl] = thism->y[tl];
1414 }
1415 }
1416
1419 const RpcComponent *cc,
1420 const Position &ip) {
1421 re->m_Ssize = cc->dx1;
1422 re->m_LongSsize = cc->dx2;
1423 re->m_Rsize = cc->GetThickness(mysql);
1424 re->m_LongRsize = cc->GetThickness(mysql);
1425 re->m_Zsize = cc->dy;
1426 re->m_LongZsize = cc->dy;
1427
1428 re->m_hasDEDontop = true;
1429 if (cc->iswap == -1)
1430 re->m_hasDEDontop = false;
1431
1432 if (ip.isAssigned) {
1433 re->setStationS(ip.shift);
1434 } else {
1435 ATH_MSG_ERROR( " MuonChamber::setRpcReadoutGeom: position not found " );
1436 assert(0);
1437 }
1438
1439 std::string tname = cc->name;
1440 re->setTechnologyName(tname);
1441 const RPC *thisr = dynamic_cast<const RPC*>(mysql.GetTechnology(tname));
1442 re->m_nphigasgaps = thisr->NGasGaps_in_s;
1443 re->m_gasgapssize = re->m_Ssize / re->m_nphigasgaps - 2. * thisr->bakeliteframesize;
1444 re->m_gasgapzsize = re->m_Zsize - 2. * thisr->bakeliteframesize;
1445 re->m_nphistrippanels = thisr->NstripPanels_in_s;
1446 re->m_phistrippitch = thisr->stripPitchS;
1447 re->m_etastrippitch = thisr->stripPitchZ;
1448
1449 if (re->getStationName().find("BI") != std::string::npos) {
1450 re->setNumberOfLayers(3); // all BI RPCs always have 3 gas gaps
1451
1452 }
1453 const RPC* genericRpc = dynamic_cast<const RPC*>(mysql.GetATechnology("RPC0"));
1454
1455 if (re->numberOfLayers() == 3) {
1456 constexpr double rpc3GapLayerThickness = 11.8; // gas vol. + ( bakelite + graphite + PET )x2
1457 for (int gasGap =1 ; gasGap <= re->numberOfLayers(); ++gasGap) {
1460 re->m_gasGap_xPos[gasGap -1] = (gasGap - 2) * rpc3GapLayerThickness - 0.74;
1461 }
1462 } else {
1463 re->m_gasGap_xPos[0] = -re->m_Rsize / 2. + thisr->externalSupPanelThickness + genericRpc->stripPanelThickness
1464 + genericRpc->GasGapThickness / 2;
1465 re->m_gasGap_xPos[1] = re->m_gasGap_xPos[0] + genericRpc->rpcLayerThickness +
1466 genericRpc->centralSupPanelThickness;
1467 if (!re->m_hasDEDontop) {
1468 std::swap(re->m_gasGap_xPos[0], re->m_gasGap_xPos[1]);
1469 }
1470 }
1471
1472 re->m_phistripwidth = re->m_phistrippitch - genericRpc->stripSeparation;
1473 re->m_etastripwidth = re->m_etastrippitch - genericRpc->stripSeparation;
1474 re->m_nphistripsperpanel = int((re->m_Ssize / re->m_nphistrippanels) / re->m_phistrippitch);
1475 if (re->getStationName().compare(0, 3, "BME") != 0) {
1476 re->m_nphistripsperpanel-=(re->m_nphistripsperpanel % 8) ;
1477 }
1478 re->m_netastripsperpanel = int((re->m_Zsize) / re->m_etastrippitch);
1479 re->m_netastripsperpanel -= (re->m_netastripsperpanel % 8);
1480
1481 re->m_phipaneldead = re->m_Ssize / re->m_nphistrippanels -
1482 re->m_nphistripsperpanel * re->m_phistrippitch +
1483 genericRpc->stripSeparation;
1484 re->m_phipaneldead = re->m_phipaneldead / 2.;
1485 re->m_etapaneldead = re->m_Zsize - re->m_netastripsperpanel * re->m_etastrippitch + genericRpc->stripSeparation;
1486 re->m_etapaneldead = re->m_etapaneldead / 2.;
1487 re->m_phistriplength = re->m_LongZsize;
1488 re->m_etastriplength = re->m_LongSsize / re->m_nphistrippanels;
1489
1490 re->m_first_phistrip_s[0] = -re->m_Ssize / 2. + re->m_phipaneldead + re->m_phistripwidth / 2.;
1491 if (re->m_nphistrippanels == 2) {
1492 re->m_first_phistrip_s[1] = re->m_phipaneldead + re->m_phistripwidth / 2.;
1493 }
1494
1495 double offset = 0.;
1496 re->m_phistrip_z = -re->m_Zsize / 2. + offset + re->m_phistriplength / 2.;
1497
1498 // first strip position on each eta panel
1499 re->m_first_etastrip_z = -re->m_Zsize / 2. + re->m_etapaneldead + re->m_etastripwidth / 2.;
1500 re->m_etastrip_s[0] = -re->m_Ssize / 2. + offset + re->m_etastriplength / 2.;
1501 if (re->m_nphistrippanels == 2) {
1502 re->m_etastrip_s[1] = re->m_Ssize / 2. - offset - re->m_etastriplength / 2.;
1503 }
1504 }
1505
1508 const TgcComponent *cc,
1509 const Position &ip,
1510 const std::string& stName) {
1511
1512 re->setSsize(cc->dx1);
1513 re->setLongSsize(cc->dx2);
1514 re->setRsize(cc->dy);
1515 re->setLongRsize(cc->dy);
1516 re->setZsize(cc->GetThickness(mysql));
1517 re->setLongZsize(cc->GetThickness(mysql));
1518
1519 const TGC *genericTgc = dynamic_cast<const TGC*>(mysql.GetATechnology("TGC0"));
1520 re->setFrameThickness(genericTgc->frame_h,
1521 genericTgc->frame_ab);
1522
1523
1524 const std::string &tname = cc->name;
1525 int tname_index = MuonGM::strtoint(tname, 3, 2);
1526 re->setTechnologyName(tname);
1527
1528 if (ip.isAssigned) {
1529 re->setStationS(ip.shift);
1530 } else {
1531 throw std::runtime_error(" MuonChamberLite::setTgcReadoutGeom position not found ");
1532 }
1533
1534 char index[2];
1535 sprintf(index, "%i", cc->index);
1536
1537 re->setReadOutName(stName.substr(0, 4) + '_' + index);
1538 re->setReadOutParams(mysql.GetTgcRPars(tname_index));
1539
1540 const TGC *thist = dynamic_cast<const TGC*>(mysql.GetTechnology(tname));
1541 const std::size_t ncomp = (thist->materials).size();
1542
1543 unsigned int gasGap{0};
1544 for (std::size_t i = 0; i < ncomp; ++i) {
1545 double newpos = -re->getZsize() / 2. + thist->positions[i] + thist->tck[i] / 2.;
1546 if ( thist->materials[i].find("TGCGas") != std::string::npos) {
1547 re->setPlaneZ(newpos, ++gasGap);
1548 }
1549 }
1550 }
1551
1552 void MuonChamber::print() const {
1553 ATH_MSG_INFO( "MuonChamber " << name << " :" );
1554 }
1556 void MuonChamber::setFPVMAP(FPVMAP *fpvmap) { m_FPVMAP = fpvmap; }
1557
1558
1559} // namespace MuonGM
const boost::regex re(r_e)
#define endmsg
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
ReadCards * rp
#define RPCON
#define useAssemblies
void diff(const Jet &rJet1, const Jet &rJet2, std::map< std::string, double > varDiff)
Difference between jets - Non-Class function required by trigger.
Definition Jet.cxx:631
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
int sign(int a)
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
Identifier channelID(int stationName, int stationEta, int stationPhi, int chamberLayer, int wireLayer, int measuresPhi, int strip) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int tubeLayer, int tube) const
double roxacellwith
double phireadoutpitch
double cathreadoutpitch
double anocathodist
double dy
Definition Cutout.h:24
double lengthY
Definition Cutout.h:27
double dx
Definition Cutout.h:23
DetectorElement(const std::string &n)
std::string associated_CMIsubtype
double tubeEndPlugLength
double tubeWallThickness
double innerRadius
std::array< double, 4 > y
std::array< double, 4 > x
Position GetStationPosition(const std::string &nameType, int fi, int zi) const
Definition MYSQL.cxx:71
Technology * GetTechnology(const std::string &name)
Definition MYSQL.cxx:105
const Technology * GetATechnology(const std::string &name) const
Definition MYSQL.cxx:162
int allocPosFindCutout(const std::string &statType, int fi, int zi) const
Definition MYSQL.cxx:201
GeoModel::TransientConstSharedPtr< TgcReadoutParams > GetTgcRPars(const std::string &name) const
Definition MYSQL.cxx:88
int allocPosFindSubtype(const std::string &statType, int fi, int zi) const
Definition MYSQL.cxx:196
void setMdtReadoutGeom(const MYSQL &mysql, MdtReadoutElement *re, const MdtComponent *cc, const Position &p)
GeoVPhysVol * build(StoredMaterialManager &matManager, const MYSQL &mysql, MuonDetectorManager *manager, int ieta, int iphi, bool is_mirrored, bool &isAssembly)
void setCscReadoutGeom(const MYSQL &mysql, CscReadoutElement *re, const CscComponent *cc, const Position &p)
void setFPVMAP(FPVMAP *fpvmap)
virtual void print() const override
void setRpcReadoutGeom(const MYSQL &mysql, RpcReadoutElement *re, const RpcComponent *cc, const Position &p)
void setTgcReadoutGeom(const MYSQL &mysql, TgcReadoutElement *re, const TgcComponent *cc, const Position &p, const std::string &statname)
MuonChamber(const MYSQL &mysql, Station *s)
void setFineClashFixingFlag(int value)
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
void setBlineFixedPointInAmdbLRS(double s0, double z0, double t0)
void updateBlineFixedPointInAmdbLRS()
void setxAmdbCRO(double xpos)
const Amg::Vector3D & getBlineFixedPointInAmdbLRS() const
void addMuonReadoutElementWithAlTransf(MuonReadoutElement *a, GeoAlignableTransform *ptrsf, int jobIndex)
void setPhysVol(const PVLink &vol)
double GasGapThickness
double stripPitchZ
double bakeliteframesize
double stripPanelThickness
double stripSeparation
double centralSupPanelThickness
double externalSupPanelThickness
double stripPitchS
double rpcLayerThickness
An RpcReadoutElement corresponds to a single RPC module; therefore typicaly a barrel muon station con...
double GetThickness(const MYSQL &mysql) const
static double zAMDB0(const MYSQL &mysql, const StandardComponent &c)
static double yAMDB0(const MYSQL &mysql, const StandardComponent &c)
static double xAMDB0(const MYSQL &mysql, const StandardComponent &c)
std::vector< std::string > materials
std::vector< double > tck
std::vector< double > positions
A TgcReadoutElement corresponds to a single TGC chamber; therefore typically a TGC station contains s...
int stationNameIndex(const std::string &name) const
Identifier channelID(int stationName, int stationEta, int stationPhi, int doubletR, int doubletZ, int doubletPhi, int gasGap, int measuresPhi, int strip) const
This class holds one or more material managers and makes them storeable, under StoreGate.
virtual const GeoMaterial * getMaterial(const std::string &name)=0
Identifier channelID(int stationName, int stationEta, int stationPhi, int gasGap, int isStrip, int channel) const
std::string depth
tag string for intendation
Definition fastadd.cxx:46
int lb
Definition globals.cxx:23
int r
Definition globals.cxx:22
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the Athena extensions are properly loaded.
Definition GeoMuonHits.h:27
std::string buildString(int i, int ncha)
int stationPhiTGC(std::string_view stName, int fi, int zi_input)
Converts the AMDB phi index to the Identifier phi Index.
int strtoint(std::string_view str, unsigned int istart, unsigned int length)
Definition TgcBase.h:6
Definition index.py:1
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)