ATLAS Offline Software
Loading...
Searching...
No Matches
MuonGeometryWriter.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 "JiveXML/DataType.h"
7
9#include "GaudiKernel/IToolSvc.h"
10#include "GaudiKernel/MsgStream.h"
11
15
16#include "GeoModelKernel/GeoVolumeCursor.h"
17#include "GeoModelKernel/GeoVDetectorManager.h"
19#include "GeoModelKernel/GeoTubs.h"
20#include "GeoModelKernel/GeoTrd.h"
21#include "GeoModelKernel/GeoShapeShift.h"
22
24
25#include <fstream>
26
27namespace JiveXML {
28
29 const double MuonGeometryWriter::m_smallAngle = 0.05;
30 const double MuonGeometryWriter::m_smallDistance = 100.;
31
33
34 ATH_MSG_DEBUG( "writeGeometry()" );
35
36 std::ofstream outputFile("AMuonGeometry.xml");
37 writeHeader(outputFile);
38
39 if ( detStore()->retrieve(m_muon_manager).isFailure() ) {
40 ATH_MSG_ERROR( "Could not retrieve MuonGM::MuonDetectorManager" );
42 return StatusCode::FAILURE;
43 } else {
44 writeStations(outputFile);
45 }
46
47 processNSW(outputFile);
48
49 writeFooter(outputFile);
50 outputFile.close();
51
52 return StatusCode::SUCCESS;
53 }
54
55 void MuonGeometryWriter::writeHeader(std::ofstream &out) const {
56
57 out << "<?xml version=\"1.0\"?>" << std::endl
58 << "<!DOCTYPE AMuonGeometry [" << std::endl
59 << "<!ELEMENT AMuonGeometry (ABox | ATBx | ATrd)*>" << std::endl
60 << "<!ELEMENT ABox EMPTY >" << std::endl
61 << "<!ATTLIST ABox" << std::endl
62 << " n CDATA #REQUIRED" << std::endl
63 << " zi CDATA #REQUIRED" << std::endl
64 << " zo CDATA #REQUIRED" << std::endl
65 << " ri CDATA #REQUIRED" << std::endl
66 << " ro CDATA #REQUIRED" << std::endl
67 << " w CDATA #REQUIRED" << std::endl
68 << " eta CDATA #REQUIRED" << std::endl
69 << " phi CDATA #REQUIRED" << std::endl
70 << " dphi CDATA \"0\"" << std::endl
71 << " sh CDATA \"0\"" << std::endl
72 << " RPCi CDATA \"0\"" << std::endl
73 << " RPCo CDATA \"0\">" << std::endl
74 << "<!ELEMENT ATBx EMPTY >" << std::endl
75 << "<!ATTLIST ATBx" << std::endl
76 << " n CDATA #REQUIRED" << std::endl
77 << " zi CDATA #REQUIRED" << std::endl
78 << " zo CDATA #REQUIRED" << std::endl
79 << " ri CDATA #REQUIRED" << std::endl
80 << " ro CDATA #REQUIRED" << std::endl
81 << " w CDATA #REQUIRED" << std::endl
82 << " eta CDATA #REQUIRED" << std::endl
83 << " phi CDATA #REQUIRED" << std::endl
84 << " sh CDATA \"0\"" << std::endl
85 << " dphi CDATA \"0\"" << std::endl
86 << " RPCi CDATA \"0\"" << std::endl
87 << " RPCo CDATA \"0\"" << std::endl
88 << " zis CDATA #REQUIRED" << std::endl
89 << " zos CDATA #REQUIRED" << std::endl
90 << " ws CDATA #REQUIRED" << std::endl
91 << " or CDATA \"0\">" << std::endl
92 << "<!ELEMENT ATrd EMPTY >" << std::endl
93 << "<!ATTLIST ATrd" << std::endl
94 << " n CDATA #REQUIRED" << std::endl
95 << " zi CDATA #REQUIRED" << std::endl
96 << " zo CDATA #REQUIRED" << std::endl
97 << " ri CDATA #REQUIRED" << std::endl
98 << " ro CDATA #REQUIRED" << std::endl
99 << " wi CDATA #REQUIRED" << std::endl
100 << " wo CDATA #REQUIRED" << std::endl
101 << " eta CDATA #REQUIRED" << std::endl
102 << " phi CDATA #REQUIRED" << std::endl
103 << " dphi CDATA \"0\"" << std::endl
104 << " sh CDATA \"0\"" << std::endl
105 << " a CDATA \"0\">" << std::endl
106 << "]>" << std::endl
107 << "<AMuonGeometry>" << std::endl;
108 }
109
110 void MuonGeometryWriter::writeStations(std::ofstream &out) const {
111
112 // While we retrieve the MdtIdHelper, we use the functionality provided by its parent class MuonIdHelper
113 // this is not MDT specific and any of the other IdHelpers would have worked as well.
114 const MdtIdHelper *mdtIdHelper = m_muon_manager->mdtIdHelper();
115 int snMax = mdtIdHelper->stationNameIndexMax();
116
117 ATH_MSG_DEBUG( " Station types: " << snMax );
118
119 // Loop over all station types.
120 for (int sn=0; sn<=snMax; sn++) {
121 std::string stationName = mdtIdHelper->stationNameString(sn);
122 // some stationNames no longer exist
123 if (!stationName.compare(MuonIdHelper::BAD_NAME)) continue;
124
125 // Determine the type of chamber from the stationName string.
126 std::string stationTech;
127 switch(stationName[0]) {
128 case 'B':
129 case 'E':
130 stationTech = "MDT";
131 break;
132 case 'C':
133 stationTech = "CSC";
134 break;
135 case 'T':
136 stationTech = "TGC";
137 break;
138 default:
139 stationTech = "???";
140 break;
141 }
142
143 // The TGCs contain several stations in one sector. As this would create several stations with the same
144 // identifier, people apparently chose to let the phi index of the stations continue up to 3 or even 6
145 // times the "real" maximum value. We need to determine this maximum value in order to calculate the real
146 // phi index.
147 int maxPhi;
148 if (stationTech == "TGC") {
149 if (stationName[2] == 'E' && stationName[1] != '4') {
150 maxPhi = 48;
151 } else {
152 maxPhi = 24;
153 }
154 } else {
155 maxPhi = 8;
156 }
157
158 // Loop over all eta values.
159 for (int eta=-16; eta<=16; eta++) {
160 std::vector<const MuonGM::MuonStation *> *stations = new std::vector<const MuonGM::MuonStation *>;
161
162 // And loop over all possible phi values.
163 for (int phi=maxPhi; phi>0; phi--) {
164
165 // Try to retrieve the station, it might not exist, but this seems to be the most
166 // reliable way to find out.
167 const MuonGM::MuonStation *station = m_muon_manager->getMuonStation(stationName, eta, phi);
168
169 // If station != 0, the station exists and we add it to our vector.
170 if (station) stations->push_back(station);
171 }
172
173 // While there are stations that haven't been written to XML, stay in this loop.
174 while (stations->size() > 0) {
175
176 // Take the parameters of a station and store them in the variables with the "1" suffix.
177 const MuonGM::MuonStation *station1 = *(stations->end()-1);
178
179 HepGeom::Point3D<double> pos1 = getPosition(station1, maxPhi);
180 int phi1 = station1->getPhiIndex();
181 double dphi1 = getDeltaPhi(pos1, maxPhi);
182 double shift1 = getShift(pos1, dphi1);
183 double alpha1 = getAlpha(Amg::EigenTransformToCLHEP(station1->getTransform()));
184
185 // Now determine the dimensions of a station of this station.
186 double signed_dz = station1->Zsize()/2.;
187 if (pos1.z()<0) signed_dz *= -1;
188 double zi1 = pos1.z() - signed_dz; // inner z
189 double zo1 = pos1.z() + signed_dz; // outer z
190 double ri1 = pos1.perp() - station1->Rsize()/2.; // inner r
191 double ro1 = pos1.perp() + station1->Rsize()/2.; // outer r
192 double wi1 = station1->Ssize(); // width at inner r
193 double wo1 = station1->LongSsize(); // width at outer r
194
195 // Create the string containing the phi sectors this station is in.
196 std::string phiString = DataType(phi1).toString();
197
198 // Remove this station from the to-be-processed list.
199 stations->erase(stations->end()-1, stations->end());
200
201 // Now loop over the other stations and see if any of them have the same parameters. Do
202 // this in reverse order to allow the current station to be erased from the vector.
203 std::vector<const MuonGM::MuonStation *>::iterator it;
204 for (it=stations->end()-1; it>=stations->begin(); --it) {
205 HepGeom::Point3D<double> pos2 = getPosition(*it, maxPhi);
206 int phi2 = (*it)->getPhiIndex();
207 double dphi2 = getDeltaPhi(pos2, maxPhi);
208 double shift2 = getShift(pos2, dphi2);
209 double alpha2 = getAlpha(Amg::EigenTransformToCLHEP((*it)->getTransform()));
210
211 double signed_dz2 = (*it)->Zsize()/2.;
212 if (pos2.z()<0) signed_dz2 *= -1;
213 double zi2 = pos2.z() - signed_dz2; // inner z
214 double zo2 = pos2.z() + signed_dz2; // outer z
215 double ri2 = pos2.perp() - (*it)->Rsize()/2.; // inner r
216 double ro2 = pos2.perp() + (*it)->Rsize()/2.; // outer r
217 double wi2 = (*it)->Ssize(); // width at inner r
218 double wo2 = (*it)->LongSsize(); // width at outer r
219
220 // If the parameters are indeed the same (within reasonable limits), then we
221 // can simply add this chamber to the sectors attribute of the first one.
222 if (pos1.distance(pos2) < m_smallDistance
223 && equalAngle(dphi1, dphi2)
224 && equalLength(shift1, shift2)
225 && equalAngle(alpha1, alpha2)
226 && equalLength(zi1, zi2)
227 && equalLength(zo1, zo2)
228 && equalLength(ri1, ri2)
229 && equalLength(ro1, ro2)
230 && equalLength(wi1, wi2)
231 && equalLength(wo1, wo2)) {
232
233 // Add the station to the phi sector string and remove it from the
234 // to-be-processed list.
235 phiString += " " + DataType(phi2).toString();
236
237 stations->erase(it, it+1);
238 }
239 }
240
241 // From here onwards we need to treat barrel chambers and endcap chambers differently.
242 if (stationName[0] == 'B') {
243
244 // Barrel chambers can have inner and/or outer RPCs.
245 // Let's take a default of 0. (no RPCs).
246 double rpci = 0.;
247 double rpco = 0.;
248
249 // Determine the thickness of the RPC layer on this station.
250 if (stationName[1] == 'M') {
251 // Middle (BM*) stations have RPCs on both sides.
252 rpci = rpco = 15.;
253 } else if (stationName[1] == 'O') {
254 // Outer (BO*) stations have RPCs on one side.
255 if (stationName[2] == 'S') {
256 // On the side facing the IP for small sectors (BOS).
257 rpci = 15.;
258 } else {
259 // On the outside for large sectors (BOL, BOF, BOG, BOH).
260 rpco = 15.;
261 }
262 } else if (stationName[1] == 'I' && eta==7 && wi1>1800) {
263 // Run3 BIS7/8 stations have RPCs on the inner side and they are wider than the Run2 BIS7 and BIS8 stations.
264 rpci = 4.;
265 }
266
267 // Barrel chambers are written as <ABox> elements.
268 out << "<ABox n=\"" << stationTech << "_" << stationName << "\""
269 << " zi=\"" << zi1/10. << "\"" << " zo=\"" << zo1/10. << "\""
270 << " ri=\"" << ri1/10. << "\"" << " ro=\"" << ro1/10. << "\""
271 << " w=\"" << wi1/10. << "\""
272 << " eta=\"" << eta << "\""
273 << " phi=\"" << phiString << "\"";
274
275 // A rotation with respect to the large sector.
276 if (std::abs(dphi1) > m_smallAngle)
277 out << " dphi=\"" << 180/M_PI * dphi1 << "\"";
278
279 // A shift perpendicular to r in the xy-plane.
280 if (std::abs(shift1) > m_smallDistance)
281 out << " sh=\"" << shift1/10. << "\"";
282
283 // RPCs.
284 if (rpci > 0.)
285 out << " RPCi=\"" << rpci << "\"";
286 if (rpco > 0.)
287 out << " RPCo=\"" << rpco << "\"";
288 out << " />" << std::endl;
289
290 } else {
291
292 // Endcap chambers are written as <ATrd> elements, parameters are similar to <ABox>.
293 writeATrd(out, stationTech, stationName, zi1, zo1, ri1, ro1, wi1, wo1, eta, phiString, dphi1, shift1, alpha1);
294 }
295 }
296
297 delete stations;
298 }
299 }
300 }
301
302 HepGeom::Point3D<double> MuonGeometryWriter::getPosition(const MuonGM::MuonStation *station, int maxPhi) const {
303
304 // Take the position of the station.
305 HepGeom::Point3D<double> pos = Amg::EigenTransformToCLHEP(station->getTransform()) * HepGeom::Point3D<double>(0., 0., 0.);
306
307 double phi = 2.*M_PI * ((double) station->getPhiIndex()-1.) / maxPhi;
308
309 // Rotate it to sector 1.
310 //return HepGeom::RotateZ3D((1-phi) * M_PI/4.) * pos;
311 return HepGeom::RotateZ3D(-phi) * pos;
312 }
313
314 double MuonGeometryWriter::getDeltaPhi(const HepGeom::Point3D<double> &pos, int maxPhi) const {
315
316 if (maxPhi > 8) {
317 // For TGCs there is no shift, so we can just return the angle.
318 return pos.phi();
319 } else if (std::abs(pos.phi() - M_PI/8.) < M_PI/16.) {
320 // For the others, rotate to the next sector if it's reasonably close to pi/8.
321 // Any further deviation will be put in as a shift.
322 return M_PI/8.;
323 } else {
324 // No rotation at all.
325 return 0.;
326 }
327 }
328
329 double MuonGeometryWriter::getAlpha(const HepGeom::Transform3D &trans) const {
330
331 // Extract the rotation from the transformation.
332 CLHEP::HepRotation rot = trans.getRotation();
333
334 // The theta component is what we're interested in.
335 return M_PI/2. - rot.getTheta();
336 }
337
338 double MuonGeometryWriter::getShift(const HepGeom::Point3D<double> &pos, double dphi) const {
339
340 HepGeom::Point3D<double> rotpos;
341
342 // First we remove the shift caused by the rotation over dphi.
343 if (std::abs(dphi) < m_smallAngle) {
344 rotpos = pos;
345 } else {
346 rotpos = HepGeom::RotateZ3D(-dphi) * pos;
347 }
348
349 // Then we return what is left as the shift.
350 if (std::abs(rotpos.y()) < m_smallDistance) {
351 return 0.;
352 } else {
353 return rotpos.y();
354 }
355 }
356
357 void MuonGeometryWriter::writeFooter(std::ofstream &out) const {
358
359 out << "</AMuonGeometry>" << std::endl;
360
361 }
362
363 void MuonGeometryWriter::writeATrd(std::ofstream &out,
364 const std::string& stationTech, const std::string& stationName,
365 double zi, double zo, double ri, double ro, double wi, double wo,
366 int eta, const std::string& phiString,
367 double dphi, double shift, double alpha) const {
368
369 out << "<ATrd n=\"" << stationTech << "_" << stationName << std::abs(eta) << "\""
370 << " zi=\"" << zi/10. << "\"" << " zo=\"" << zo/10. << "\""
371 << " ri=\"" << ri/10. << "\"" << " ro=\"" << ro/10. << "\""
372 << " wi=\"" << wi/10. << "\"" << " wo=\"" << wo/10. << "\""
373 << " eta=\"" << eta << "\""
374 << " phi=\"" << phiString << "\"";
375
376 // A rotation with respect to the large sector.
377 if (std::abs(dphi) > m_smallAngle)
378 out << " dphi=\"" << 180/M_PI * dphi << "\"";
379
380 // A shift perpendicular to r in the xy-plane.
381 if (std::abs(shift) > m_smallDistance)
382 out << " sh=\"" << shift/10. << "\"";
383
384 // A tilt in the rz-plane, for the CSCs.
385 if (std::abs(alpha) > m_smallAngle)
386 out << " a=\"" << 180/M_PI * alpha << "\"";
387
388 out << " />" << std::endl;
389
390
391 }
392
393 void MuonGeometryWriter::processNSW(std::ofstream &out) {
394
395 int maxPhi = 8;
396
397 // Check if NSW exists in the GeoModel tree, and process it if exists
398 const GeoModelExperiment * theExpt = nullptr;
399 if (detStore()->retrieve(theExpt, "ATLAS").isFailure()) {
400 ATH_MSG_ERROR( "Could not retrieve the ATLAS GeoModelExperiment from detector store" );
401 return;
402 }
403
404 PVConstLink world(theExpt->getPhysVol());
405 GeoVolumeCursor av(world);
406 while (!av.atEnd()) {
407 if ( av.getName()=="Muon") {
408 GeoVolumeCursor pv(av.getVolume());
409 while (!pv.atEnd()) { // Loop over Muon stations
410 if (pv.getVolume()->getLogVol()->getName()=="NewSmallWheel") {
411 ATH_MSG_INFO( "Found New Small Wheel geometry." );
412 GeoVolumeCursor pvnsw(pv.getVolume());
413
414 while (!pvnsw.atEnd()){
415 std::string stationName = pvnsw.getVolume()->getLogVol()->getName();
416
417 // Process MicroMegas chambers
418 if (stationName=="NSW_MM"){
419 ATH_MSG_DEBUG( "Processing NSW micromegas chambers." );
420
421 GeoVolumeCursor pvnswsub(pvnsw.getVolume());
422 bool newChamber = true;
423 std::string phiString = "";
424 std::string phiString_mirrorEta = "";
425 double dphi=0, shift=0, zi=0, zo=0, ri=0, ro=0, wi=0, wo=0;
426 std::string chamberName="";
427 HepGeom::Point3D<double> pos_rot;
428
429 while (!pvnswsub.atEnd()){
430 if (((pvnswsub.getVolume()->getLogVol())->getShape())->typeID() == GeoTrd::getClassTypeID() ) { // MicroMega
431
432 if (newChamber){
433
434 int phiIndex;
435 readNSWMMPars(&pvnswsub, maxPhi, chamberName, pos_rot, zi, zo, ri, ro, wi, wo, dphi, shift, phiIndex);
436 phiString = DataType(phiIndex).toString();
437
438 newChamber = false;
439 pvnswsub.next();
440 } // end of processing the first chamber
441
442 else{
443 std::string chamberName2;
444 HepGeom::Point3D<double> pos_rot2;
445 double zi2, zo2, ri2, ro2, wi2, wo2, dphi2, shift2;
446 int phiIndex2;
447 readNSWMMPars(&pvnswsub, maxPhi, chamberName2, pos_rot2, zi2, zo2, ri2, ro2, wi2, wo2, dphi2, shift2, phiIndex2);
448
449 if (chamberName != chamberName2
450 || !equalAngle(dphi, dphi2)
451 || !equalLength(shift, shift2)
452 || !equalLength(ri, ri2)
453 || !equalLength(ro, ro2)
454 || !equalLength(wi, wi2)
455 || !equalLength(wo, wo2)) {
456 // This is a different chamber.
457 // Reset the new chamber flag so that it can be processed as a new chamber in the next loop
458 newChamber = true;
459 }
460 else if (pos_rot.distance(pos_rot2) < m_smallDistance
461 && equalLength(zi, zi2)
462 && equalLength(zo, zo2)
463 ) {
464 // same chamber in different phi sector, add it to the existing phi index list
465 std::string stationPhi = DataType(phiIndex2).toString();
466 if (phiString.find(stationPhi) == std::string::npos) phiString += " " + stationPhi;
467 pvnswsub.next();
468 }
469 else if (pos_rot.distance(HepGeom::Point3D<double>(pos_rot2.x(), pos_rot2.y(), -pos_rot2.z())) < m_smallDistance
470 && equalLength(zi, -zi2)
471 && equalLength(zo, -zo2)
472 ) {
473 // same chamber in oppposite eta region, add it to a separate phi index list
474 std::string stationPhi = DataType(phiIndex2).toString();
475 if (phiString_mirrorEta.find(stationPhi) == std::string::npos){
476 if (not phiString_mirrorEta.empty()) phiString_mirrorEta += " ";
477 phiString_mirrorEta += stationPhi;
478 }
479 pvnswsub.next();
480 }
481 else {
482 // This is a different chamber.
483 // Reset the new chamber flag so that it can be processed as a new chamber in the next loop
484 newChamber = true;
485 }
486
487 } // end of processing another chamber and comparing it to the first chamber
488
489
490 if (phiString!="" && (newChamber || pvnswsub.atEnd())){
491 // if the next chamber is a different chamber, or this is the last chamber, write the geometry to output
492 ATH_MSG_DEBUG( "Writing " << chamberName );
493
494 std::string stationTech = "MM";
495 std::string stationName = "MM"+chamberName.substr(7,1); // MMS: small sector. MML: large sector
496 int eta = std::stoi(chamberName.substr(8,1));
497 writeATrd(out, stationTech, stationName, zi, zo, ri, ro, wi, wo, eta, phiString, dphi, shift, 0);
498 if (phiString_mirrorEta!="") {
499 writeATrd(out, stationTech, stationName, -zi, -zo, ri, ro, wi, wo, -eta, phiString_mirrorEta, dphi, shift, 0);
500 }
501
502 phiString = ""; // reset for new chambers
503 phiString_mirrorEta = ""; // reset for new chambers
504 }
505 }
506 else { // not MicroMegas; Move to the next chamber
507 pvnswsub.next();
508 }
509
510 }
511 }
512
513 // Process sTGC chambers
514 else if (stationName=="NSW_sTGC"){
515
516 ATH_MSG_DEBUG( "Processing NSW sTGC chambers." );
517
518 GeoVolumeCursor pvnswsub(pvnsw.getVolume());
519 bool newChamber = true;
520 std::string phiString = "";
521 std::string phiString_mirrorEta = "";
522 int nvtx=0;
523 double dz=0, dphi=0, shift=0;
524 std::string chamberName="";
525 HepGeom::Point3D<double> pos_rot;
526 const GeoSimplePolygonBrep* theBrep = nullptr;
527
528 while (!pvnswsub.atEnd()){
529 if (((pvnswsub.getVolume()->getLogVol())->getShape())->typeID() == GeoShapeShift::getClassTypeID() ) {// sTGC
530
531
532 if (newChamber){
533
534 int phiIndex;
535 readNSWSTGCPars(&pvnswsub, maxPhi, chamberName, pos_rot, theBrep, nvtx, dz, dphi, shift, phiIndex);
536 phiString = DataType(phiIndex).toString();
537
538 newChamber = false;
539 pvnswsub.next();
540 } // end of processing the first chamber
541
542 else{
543
544 std::string chamberName2;
545 HepGeom::Point3D<double> pos_rot2;
546 const GeoSimplePolygonBrep* theBrep2;
547 int nvtx2, phiIndex2;
548 double dz2, dphi2, shift2;
549 readNSWSTGCPars(&pvnswsub, maxPhi, chamberName2, pos_rot2, theBrep2, nvtx2, dz2, dphi2, shift2, phiIndex2);
550
551 // Check if it is the same shape as the first chamber
552 bool isSameShape = true;
553 if (nvtx == nvtx2 && equalLength(dz, dz2) ) { // Same Nvtx and thickness. Check vertices coordinates.
554 for (int i=0; i<nvtx; ++i){
555 if ( !equalLength(theBrep->getXVertex(i), theBrep2->getXVertex(i))
556 || !equalLength(theBrep->getYVertex(i), theBrep2->getYVertex(i)) )
557 {
558 isSameShape = false;
559 }
560 }
561 }
562 else { // Different Nvtx or thickness
563 isSameShape = false;
564 }
565
566 // Check if it has the same name, offset and shape as the first chamber
567 if (chamberName != chamberName2
568 || !equalAngle(dphi, dphi2)
569 || !equalLength(shift, shift2)
570 || !isSameShape)
571 {
572 // This is a different chamber.
573 // Reset the new chamber flag so that it can be processed as a new chamber in the next loop
574 newChamber = true;
575 }
576 // check chamber position
577 else if (pos_rot.distance(pos_rot2) < m_smallDistance) {
578 // same chamber in different phi sector, add it to the existing phi index list
579 std::string stationPhi = DataType(phiIndex2).toString();
580 if (phiString.find(stationPhi) == std::string::npos) phiString += " " + stationPhi;
581 pvnswsub.next();
582 }
583 else if (pos_rot.distance(HepGeom::Point3D<double>(pos_rot2.x(), pos_rot2.y(), -pos_rot2.z())) < m_smallDistance) {
584 // same chamber in oppposite eta region, add it to a separate phi index list
585 std::string stationPhi = DataType(phiIndex2).toString();
586 if (phiString_mirrorEta.find(stationPhi) == std::string::npos) {
587 if (not phiString_mirrorEta.empty()) phiString_mirrorEta += " ";
588 phiString_mirrorEta += stationPhi;
589 }
590 pvnswsub.next();
591 }
592 else {
593 // This is a different chamber.
594 // Reset the new chamber flag so that it can be processed as a new chamber in the next loop
595 newChamber = true;
596 }
597 } // end of processing another chamber and comparing it to the first chamber
598
599
600 if (phiString!="" && (newChamber || pvnswsub.atEnd())){
601 // if the next chamber is a different chamber, or this is the last chamber, write the geometry to output
602 ATH_MSG_DEBUG( "Writing " << chamberName );
603
604 std::string stationTech = "STGC";
605 std::string stationName = "ST"+chamberName.substr(8,1); // STS: small sector. STL: large sector
606 int eta = std::stoi(chamberName.substr(9,1));
607 double signed_dz = dz;
608 if (pos_rot.z()<0) dz *= -1;
609 double zi = pos_rot.z() - signed_dz;
610 double zo = pos_rot.z() + signed_dz;
611 double rho = pos_rot.perp();
612 double ri, ro, wi, wo;
613
614 if (nvtx==4){ // write as a single ATrd
615 // vtx1-----vtx0 (outer)
616 // \ /
617 // vtx2--vtx3 (inner)
618 const int vtxList[] = {0, 1, 2, 3};
619 readBrepAsATrd(theBrep, rho, vtxList, ri, ro, wi, wo);
620 writeATrd(out, stationTech, stationName, zi, zo, ri, ro, wi, wo, eta, phiString, dphi, shift, 0);
621 if (phiString_mirrorEta!="") {
622 writeATrd(out, stationTech, stationName, -zi, -zo, ri, ro, wi, wo, -eta, phiString_mirrorEta, dphi, shift, 0);
623 }
624 }
625
626 else if (nvtx==6){ // print as two ATrds
627 // vtx1-----vtx0 (outer)
628 // | |
629 // vtx2 vtx5
630 // \ /
631 // vtx3--vtx4 (inner)
632
633 // First ATrd (inner part): vertex 2, 3, 4, 5
634 const int vtxList1[] = {5, 2, 3, 4};
635 readBrepAsATrd(theBrep, rho, vtxList1, ri, ro, wi, wo);
636 writeATrd(out, stationTech, stationName, zi, zo, ri, ro, wi, wo, eta, phiString, dphi, shift, 0);
637 if (phiString_mirrorEta!="") {
638 writeATrd(out, stationTech, stationName, -zi, -zo, ri, ro, wi, wo, -eta, phiString_mirrorEta, dphi, shift, 0);
639 }
640
641 // Second ATrd (outter part): vertex 0, 1, 2, 5
642 const int vtxList2[] = {0, 1, 2, 5};
643 readBrepAsATrd(theBrep, rho, vtxList2, ri, ro, wi, wo);
644 writeATrd(out, stationTech, stationName, zi, zo, ri, ro, wi, wo, eta, phiString, dphi, shift, 0);
645 if (phiString_mirrorEta!="") {
646 writeATrd(out, stationTech, stationName, -zi, -zo, ri, ro, wi, wo, -eta, phiString_mirrorEta, dphi, shift, 0);
647 }
648
649 }
650
651 else{
652 ATH_MSG_ERROR( "Shape not supported by GeometryJiveXML: polygon shape with "<<nvtx <<" verticies in NSW sTGC." );
653 }
654 phiString = ""; // reset for new chambers
655 phiString_mirrorEta = ""; // reset for new chambers
656 }
657
658 }
659 else { // not sTGC; Move to the next chamber
660 pvnswsub.next();
661 }
662
663 }
664 }
665 pvnsw.next();
666 }
667 return; // Done with NSW. Skip other subdetectors
668 }
669
670 pv.next();
671 }
672 }
673 av.next(); // increment volume cursor.
674 }
675 }
676
677 int MuonGeometryWriter::getPhiIndex(double phi, int maxPhi) const {
678 if (phi<0) phi += 2.*M_PI;
679 int phiIndex = std::round(phi * maxPhi / (2.*M_PI) - 0.1) + 1;
680 return phiIndex;
681 }
682
683 HepGeom::Point3D<double> MuonGeometryWriter::getPositionNSW(Amg::Vector3D pos, int maxPhi) const {
684 // get phi index of the sector
685 int phiIndex = getPhiIndex(pos.phi(), maxPhi);
686 // calculate phi of the sector center
687 double sectorPhi = 2.*M_PI * ((double) phiIndex-1.) / maxPhi;
688 // rotate to first sector
689 HepGeom::Point3D<double> pos_rot = HepGeom::RotateZ3D(-sectorPhi) * HepGeom::Point3D<double>(pos.x(), pos.y(), pos.z());
690
691 return pos_rot;
692 }
693
694 void MuonGeometryWriter::readNSWMMPars(const GeoVolumeCursor *pv, int maxPhi, std::string& chamberName, HepGeom::Point3D<double>& pos_rot,
695 double& zi, double& zo, double& ri, double& ro, double& wi, double& wo, double& dphi, double& shift, int& phiIndex) const {
696
697 chamberName = pv->getVolume()->getLogVol()->getName();
698 const GeoTrd* theTrd = dynamic_cast<const GeoTrd*> ((pv->getVolume()->getLogVol())->getShape());
699 Amg::Vector3D pos = pv->getTransform().translation();
700
701 pos_rot = getPositionNSW(pos, maxPhi);
702 dphi = getDeltaPhi(pos_rot, maxPhi);
703 shift = getShift(pos_rot, dphi);
704 double signed_dz = theTrd->getXHalfLength1();
705 if (pos_rot.z()<0) signed_dz *= -1;
706
707 zi = pos_rot.z() - signed_dz;
708 zo = pos_rot.z() + signed_dz;
709 ri = pos_rot.perp() - theTrd->getZHalfLength();
710 ro = pos_rot.perp() + theTrd->getZHalfLength();
711 wi = 2.0 * theTrd->getYHalfLength1();
712 wo = 2.0 * theTrd->getYHalfLength2();
713
714 phiIndex = getPhiIndex(pos.phi(), maxPhi);
715
716 return;
717 }
718
719 void MuonGeometryWriter::readNSWSTGCPars(const GeoVolumeCursor *pv, int maxPhi,
720 std::string& chamberName, HepGeom::Point3D<double>& pos_rot, const GeoSimplePolygonBrep*& theBrep,
721 int& nvtx, double& dz, double& dphi, double& shift, int& phiIndex) const {
722
723 chamberName = pv->getVolume()->getLogVol()->getName();
724
725 const GeoShapeShift* theShift = dynamic_cast<const GeoShapeShift*> ((pv->getVolume()->getLogVol())->getShape());
726 theBrep = dynamic_cast<const GeoSimplePolygonBrep*> (theShift->getOp());
727 nvtx = theBrep->getNVertices();
728 dz = theBrep->getDZ();
729
730 Amg::Vector3D pos = pv->getTransform().translation();
731 pos_rot = getPositionNSW(pos, maxPhi);
732 dphi = getDeltaPhi(pos_rot, maxPhi);
733 shift = getShift(pos_rot, dphi);
734
735 phiIndex = getPhiIndex(pos.phi(), maxPhi);
736
737 return;
738 }
739
740 void MuonGeometryWriter::readBrepAsATrd(const GeoSimplePolygonBrep* theBrep, double rho, const int *vtx,
741 double& ri, double& ro, double& wi, double& wo) const {
742 // vtx1-----vtx0 (outer)
743 // \ /
744 // vtx2--vtx3 (inner)
745 ri = rho + theBrep->getYVertex(vtx[3]);
746 ro = rho + theBrep->getYVertex(vtx[0]);
747 wi = theBrep->getXVertex(vtx[3]) - theBrep->getXVertex(vtx[2]);
748 wo = theBrep->getXVertex(vtx[0]) - theBrep->getXVertex(vtx[1]);
749 return;
750 }
751
752 bool MuonGeometryWriter::equalAngle(double a, double b) const {
753 return std::abs(a - b) < m_smallAngle;
754 }
755
756 bool MuonGeometryWriter::equalLength(double a, double b) const {
757 return std::abs(a - b) < m_smallDistance;
758 }
759
760}
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
OFFLINE_FRAGMENTS_NAMESPACE::PointerType DataType
static Double_t a
const ServiceHandle< StoreGateSvc > & detStore() const
GeoPhysVol * getPhysVol()
Destructor.
void readNSWMMPars(const GeoVolumeCursor *pv, int maxPhi, std::string &chamberName, HepGeom::Point3D< double > &pos_rot, double &zi, double &zo, double &ri, double &ro, double &wi, double &wo, double &dphi, double &shift, int &phiIndex) const
Reads the geometry parameters of a NSW Micromegas chamber.
void writeStations(std::ofstream &out) const
Retrieves all stations from GeoModel and writes the corresponding XML elements to a stream.
HepGeom::Point3D< double > getPositionNSW(Amg::Vector3D pos, int maxPhi) const
Returns the global position of the NSW station, rotated to sector 1.
static const double m_smallAngle
Maximum deviation from the reference value before the station is considered different.
bool equalLength(double a, double b) const
Compares two coordinates or lenghts.
void processNSW(std::ofstream &out)
process the geometry of New Small Wheel
void writeFooter(std::ofstream &out) const
Writes the footer of the XML file to a stream.
void writeHeader(std::ofstream &out) const
Writes the header of the XML file to a stream.
HepGeom::Point3D< double > getPosition(const MuonGM::MuonStation *station, int maxPhi) const
Returns the global position of the station, rotated to sector 1.
double getDeltaPhi(const HepGeom::Point3D< double > &pos, int maxPhi) const
Returns the rotation of the station with respect to the center of the sector.
double getShift(const HepGeom::Point3D< double > &pos, double dphi) const
Returns the shift of the station with respect to the center of the sector.
void readBrepAsATrd(const GeoSimplePolygonBrep *theBrep, double rho, const int *vtx, double &ri, double &ro, double &wi, double &wo) const
Takes four vetecies of a GeoSimplePolygonBrep to form a trapezoid shape and reads the parameters of t...
void readNSWSTGCPars(const GeoVolumeCursor *pv, int maxPhi, std::string &chamberName, HepGeom::Point3D< double > &pos_rot, const GeoSimplePolygonBrep *&theBrep, int &nvtx, double &dz, double &dphi, double &shift, int &phiIndex) const
Reads the geometry parameters of a NSW sTGC chamber.
int getPhiIndex(double phi, int maxPhi) const
Returns phi index of the sector.
static const double m_smallDistance
void writeATrd(std::ofstream &out, const std::string &stationTech, const std::string &stationName, double zi, double zo, double ri, double ro, double wi, double wo, int eta, const std::string &phiString, double dphi, double shift, double alpha) const
Writes a trapezoid station in XML to a stream.
bool equalAngle(double a, double b) const
Compares two angles.
const MuonGM::MuonDetectorManager * m_muon_manager
Pointer to the muon detector manager (GeoModel)
virtual StatusCode writeGeometry()
Writes the geometry of the ATLAS muon spectrometer to an XML file for use with Atlantis.
double getAlpha(const HepGeom::Transform3D &trans) const
Returns the forward tilt angle of a station (for CSCs).
double Zsize() const
double LongSsize() const
int getPhiIndex() const
a la AMDB
double Ssize() const
Amg::Transform3D getTransform() const
double Rsize() const
static const std::string BAD_NAME
int stationNameIndexMax() const
const std::string & stationNameString(const int &index) const
HepGeom::Transform3D EigenTransformToCLHEP(const Amg::Transform3D &eigenTransf)
Converts an Eigen-based Amg::Transform3D into a CLHEP-based HepGeom::Transform3D.
Eigen::Matrix< double, 3, 1 > Vector3D
This header is shared inbetween the C-style server thread and the C++ Athena ServerSvc.