ATLAS Offline Software
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 
27 namespace 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");
38 
39  if ( detStore()->retrieve(m_muon_manager).isFailure() ) {
40  ATH_MSG_ERROR( "Could not retrieve MuonGM::MuonDetectorManager" );
41  m_muon_manager = 0;
42  return StatusCode::FAILURE;
43  } else {
45  }
46 
48 
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.
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 
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 }
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
JiveXML::MuonGeometryWriter::processNSW
void processNSW(std::ofstream &out)
process the geometry of New Small Wheel
Definition: MuonGeometryWriter.cxx:393
DataType.h
GeoModelExperiment::getPhysVol
GeoPhysVol * getPhysVol()
Destructor.
Definition: GeoModelExperiment.cxx:21
add-xsec-uncert-quadrature-N.alpha
alpha
Definition: add-xsec-uncert-quadrature-N.py:110
JiveXML::MuonGeometryWriter::m_smallAngle
static const double m_smallAngle
Maximum deviation from the reference value before the station is considered different.
Definition: MuonGeometryWriter.h:173
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
JiveXML::MuonGeometryWriter::readBrepAsATrd
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...
Definition: MuonGeometryWriter.cxx:740
dumpTgcDigiDeadChambers.stationName
dictionary stationName
Definition: dumpTgcDigiDeadChambers.py:30
JiveXML::MuonGeometryWriter::getPhiIndex
int getPhiIndex(double phi, int maxPhi) const
Returns phi index of the sector.
Definition: MuonGeometryWriter.cxx:677
MuonGM::MuonStation::getTransform
Amg::Transform3D getTransform() const
Definition: MuonStation.h:180
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
DataType
OFFLINE_FRAGMENTS_NAMESPACE::PointerType DataType
Definition: RoIBResultByteStreamTool.cxx:25
skel.it
it
Definition: skel.GENtoEVGEN.py:407
JiveXML::MuonGeometryWriter::readNSWSTGCPars
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.
Definition: MuonGeometryWriter.cxx:719
GeoModelExperiment
Definition: GeoModelExperiment.h:32
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:70
M_PI
#define M_PI
Definition: ActiveFraction.h:11
JiveXML::MuonGeometryWriter::getPosition
HepGeom::Point3D< double > getPosition(const MuonGM::MuonStation *station, int maxPhi) const
Returns the global position of the station, rotated to sector 1.
Definition: MuonGeometryWriter.cxx:302
MuonIdHelper::stationNameIndexMax
int stationNameIndexMax() const
Definition: MuonIdHelper.cxx:824
JiveXML::MuonGeometryWriter::getPositionNSW
HepGeom::Point3D< double > getPositionNSW(Amg::Vector3D pos, int maxPhi) const
Returns the global position of the NSW station, rotated to sector 1.
Definition: MuonGeometryWriter.cxx:683
AthCommonDataStore< AthCommonMsg< AlgTool > >::detStore
const ServiceHandle< StoreGateSvc > & detStore() const
The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:95
MuonGeometryWriter.h
GeoModelExperiment.h
compareGeometries.outputFile
string outputFile
Definition: compareGeometries.py:25
MuonGM::MuonStation::Ssize
double Ssize() const
Definition: MuonStation.h:185
MuonGM::MuonStation::getPhiIndex
int getPhiIndex() const
a la AMDB
Definition: MuonStation.h:173
MuonGM::MuonStation::Zsize
double Zsize() const
Definition: MuonStation.h:186
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
MuonGM::MuonStation::Rsize
double Rsize() const
Definition: MuonStation.h:184
lumiFormat.i
int i
Definition: lumiFormat.py:85
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
MuonGM::MuonStation
Definition: MuonStation.h:51
MdtIdHelper
Definition: MdtIdHelper.h:61
MdtIdHelper.h
MuonGM::MuonDetectorManager::mdtIdHelper
const MdtIdHelper * mdtIdHelper() const
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/MuonDetectorManager.h:232
xAOD::double
double
Definition: CompositeParticle_v1.cxx:159
JiveXML
This header is shared inbetween the C-style server thread and the C++ Athena ServerSvc.
Definition: BadLArRetriever.cxx:22
CLHEPtoEigenConverter.h
MuonIdHelper::stationNameString
const std::string & stationNameString(const int &index) const
Definition: MuonIdHelper.cxx:858
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:76
JiveXML::MuonGeometryWriter::writeGeometry
virtual StatusCode writeGeometry()
Writes the geometry of the ATLAS muon spectrometer to an XML file for use with Atlantis.
Definition: MuonGeometryWriter.cxx:32
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
JiveXML::MuonGeometryWriter::m_smallDistance
static const double m_smallDistance
Definition: MuonGeometryWriter.h:173
JiveXML::MuonGeometryWriter::writeFooter
void writeFooter(std::ofstream &out) const
Writes the footer of the XML file to a stream.
Definition: MuonGeometryWriter.cxx:357
MuonDetectorManager.h
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
eflowRec::phiIndex
unsigned int phiIndex(float phi, float binsize)
calculate phi index for a given phi
Definition: EtaPhiLUT.cxx:23
MuonGM::MuonDetectorManager::getMuonStation
const MuonStation * getMuonStation(const std::string &stName, int eta, int phi) const
Definition: MuonDetDescr/MuonReadoutGeometry/src/MuonDetectorManager.cxx:139
JiveXML::MuonGeometryWriter::equalLength
bool equalLength(double a, double b) const
Compares two coordinates or lenghts.
Definition: MuonGeometryWriter.cxx:756
JiveXML::MuonGeometryWriter::readNSWMMPars
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.
Definition: MuonGeometryWriter.cxx:694
a
TList * a
Definition: liststreamerinfos.cxx:10
Amg::EigenTransformToCLHEP
HepGeom::Transform3D EigenTransformToCLHEP(const Amg::Transform3D &eigenTransf)
Converts an Eigen-based Amg::Transform3D into a CLHEP-based HepGeom::Transform3D.
Definition: CLHEPtoEigenConverter.h:120
JiveXML::MuonGeometryWriter::getShift
double getShift(const HepGeom::Point3D< double > &pos, double dphi) const
Returns the shift of the station with respect to the center of the sector.
Definition: MuonGeometryWriter.cxx:338
JiveXML::MuonGeometryWriter::writeATrd
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.
Definition: MuonGeometryWriter.cxx:363
python.changerun.pv
pv
Definition: changerun.py:79
JiveXML::MuonGeometryWriter::m_muon_manager
const MuonGM::MuonDetectorManager * m_muon_manager
Pointer to the muon detector manager (GeoModel)
Definition: MuonGeometryWriter.h:170
JiveXML::MuonGeometryWriter::getAlpha
double getAlpha(const HepGeom::Transform3D &trans) const
Returns the forward tilt angle of a station (for CSCs).
Definition: MuonGeometryWriter.cxx:329
JiveXML::MuonGeometryWriter::writeHeader
void writeHeader(std::ofstream &out) const
Writes the header of the XML file to a stream.
Definition: MuonGeometryWriter.cxx:55
JiveXML::MuonGeometryWriter::equalAngle
bool equalAngle(double a, double b) const
Compares two angles.
Definition: MuonGeometryWriter.cxx:752
MuonStation.h
StoreGateSvc.h
MuonGM::MuonStation::LongSsize
double LongSsize() const
Definition: MuonStation.h:188
fitman.rho
rho
Definition: fitman.py:532
JiveXML::MuonGeometryWriter::getDeltaPhi
double getDeltaPhi(const HepGeom::Point3D< double > &pos, int maxPhi) const
Returns the rotation of the station with respect to the center of the sector.
Definition: MuonGeometryWriter.cxx:314
JiveXML::MuonGeometryWriter::writeStations
void writeStations(std::ofstream &out) const
Retrieves all stations from GeoModel and writes the corresponding XML elements to a stream.
Definition: MuonGeometryWriter.cxx:110
MuonIdHelper::BAD_NAME
static const std::string BAD_NAME
Definition: MuonIdHelper.h:224