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