Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-10-20 22:54:41

0001 #include <DetectorDescription/Core/interface/DDMaterial.h>
0002 #include <DetectorDescription/Core/interface/DDPartSelection.h>
0003 #include <DetectorDescription/Core/interface/DDSolid.h>
0004 #include <DetectorDescription/Core/interface/DDSolidShapes.h>
0005 #include <DetectorDescription/Core/interface/DDSpecifics.h>
0006 #include <DetectorDescription/OfflineDBLoader/interface/DDCoreToDDXMLOutput.h>
0007 #include "DetectorDescription/Core/interface/DDRotationMatrix.h"
0008 #include "DetectorDescription/Core/interface/DDTranslation.h"
0009 #include "DetectorDescription/Core/interface/DDName.h"
0010 #include "DetectorDescription/Core/interface/DDPosData.h"
0011 #include "DetectorDescription/Core/interface/DDTransform.h"
0012 #include "DetectorDescription/Core/interface/DDValue.h"
0013 #include "DetectorDescription/Core/interface/DDValuePair.h"
0014 
0015 #include "DetectorDescription/DDCMS/interface/DDSolidShapes.h"
0016 #include "DetectorDescription/DDCMS/interface/DDNamespace.h"
0017 
0018 #include "DataFormats/Math/interface/GeantUnits.h"
0019 #include "DataFormats/Math/interface/Rounding.h"
0020 #include "FWCore/Utilities/interface/Exception.h"
0021 #include "Math/GenVector/Cartesian3D.h"
0022 #include "Math/GenVector/DisplacementVector3D.h"
0023 #include "Math/GenVector/Rotation3D.h"
0024 
0025 #include "DD4hep/Filter.h"
0026 #include "DD4hep/Shapes.h"
0027 
0028 #include "TGeoMedium.h"
0029 
0030 #include <cstddef>
0031 #include <iomanip>
0032 #include <vector>
0033 
0034 using namespace geant_units::operators;
0035 
0036 template <class NumType>
0037 static inline constexpr NumType convertGPerCcToMgPerCc(NumType gPerCc)  // g/cm^3 -> mg/cm^3
0038 {
0039   return (gPerCc * 1000.);
0040 }
0041 
0042 static constexpr double tol0 = 1.e-11;        // Tiny values to be considered equal to 0
0043 static constexpr double reflectTol = 1.0e-3;  // Tolerance for recognizing reflections; Geant4-compatible
0044 
0045 namespace cms::rotation_utils {
0046   /* For debugging 
0047   static double determinant(const dd4hep::Rotation3D &rot) {
0048     double xx, xy, xz, yx, yy, yz, zx, zy, zz;
0049     rot.GetComponents(xx, xy, xz, yx, yy, yz, zx, zy, zz); 
0050     double term1 = xx * (yy * zz - yz * zy);
0051     double term2 = yx * (xy * zz - xz * zy);
0052     double term3 = zx * (xy * yz - yy * xz);
0053     return (term1 - term2 + term3);
0054   }
0055   */
0056 
0057   static const std::string identityHash(
0058       "1.00000000.00000000.00000000.00000001.00000000.00000000.00000000.00000001.0000000");
0059 
0060   static void addRotWithNewName(cms::DDNamespace& ns, std::string& name, const dd4hep::Rotation3D& rot) {
0061     const dd4hep::Rotation3D& rot2 = rot;
0062     name = name + "_DdNoNa";  // Name used by old DD to indicate an unnamed rotation
0063     ns.addRotation(name, rot2);
0064   }
0065 
0066   static void addRotWithNewName(cms::DDNamespace& ns, std::string& name, const Double_t* rot) {
0067     using namespace cms_rounding;
0068     dd4hep::Rotation3D rot2(roundIfNear0(rot[0], tol0),
0069                             roundIfNear0(rot[1], tol0),
0070                             roundIfNear0(rot[2], tol0),
0071                             roundIfNear0(rot[3], tol0),
0072                             roundIfNear0(rot[4], tol0),
0073                             roundIfNear0(rot[5], tol0),
0074                             roundIfNear0(rot[6], tol0),
0075                             roundIfNear0(rot[7], tol0),
0076                             roundIfNear0(rot[8], tol0));
0077     addRotWithNewName(ns, name, rot2);
0078   }
0079 
0080   template <typename T>
0081   static const std::string& rotName(const T& rot, const cms::DDParsingContext& context) {
0082     std::string hashVal = rotHash(rot);
0083     auto rotNameIter = context.rotRevMap.find(hashVal);
0084     if (rotNameIter != context.rotRevMap.end()) {
0085       return (rotNameIter->second);
0086     }
0087     static const std::string nullStr{"NULL"};
0088     return (nullStr);
0089   }
0090 
0091 }  // namespace cms::rotation_utils
0092 
0093 std::string DDCoreToDDXMLOutput::trimShapeName(const std::string& solidName) {
0094   size_t trimPt = solidName.find("_shape_0x");
0095   if (trimPt != std::string::npos)
0096     return (solidName.substr(0, trimPt));
0097   return (solidName);
0098 }
0099 
0100 void DDCoreToDDXMLOutput::solid(const dd4hep::Solid& solid, const cms::DDParsingContext& context, std::ostream& xos) {
0101   cms::DDSolidShape shape = cms::dd::value(cms::DDSolidShapeMap, std::string(solid.title()));
0102   switch (shape) {
0103     case cms::DDSolidShape::ddunion:
0104     case cms::DDSolidShape::ddsubtraction:
0105     case cms::DDSolidShape::ddintersection: {
0106       dd4hep::BooleanSolid rs(solid);
0107       if (shape == cms::DDSolidShape::ddunion) {
0108         xos << "<UnionSolid ";
0109       } else if (shape == cms::DDSolidShape::ddsubtraction) {
0110         xos << "<SubtractionSolid ";
0111       } else if (shape == cms::DDSolidShape::ddintersection) {
0112         xos << "<IntersectionSolid ";
0113       }
0114       xos << "name=\"" << trimShapeName(solid.name()) << "\">" << std::endl;
0115       xos << "<rSolid name=\"" << trimShapeName(rs.leftShape().name()) << "\"/>" << std::endl;
0116       xos << "<rSolid name=\"" << trimShapeName(rs.rightShape().name()) << "\"/>" << std::endl;
0117       const Double_t* trans = rs.rightMatrix()->GetTranslation();
0118       xos << "<Translation x=\"" << trans[0] << "*mm\"";
0119       xos << " y=\"" << trans[1] << "*mm\"";
0120       xos << " z=\"" << trans[2] << "*mm\"";
0121       xos << "/>" << std::endl;
0122       auto rot = rs.rightMatrix()->GetRotationMatrix();
0123       // The identity rotation can be omitted.
0124       if (cms::rotation_utils::rotHash(rot) != cms::rotation_utils::identityHash) {
0125         std::string rotNameStr = cms::rotation_utils::rotName(rot, context);
0126         xos << "<rRotation name=\"" << rotNameStr << "\"/>" << std::endl;
0127       }
0128       if (shape == cms::DDSolidShape::ddunion) {
0129         xos << "</UnionSolid>" << std::endl;
0130       } else if (shape == cms::DDSolidShape::ddsubtraction) {
0131         xos << "</SubtractionSolid>" << std::endl;
0132       } else if (shape == cms::DDSolidShape::ddintersection) {
0133         xos << "</IntersectionSolid>" << std::endl;
0134       }
0135       break;
0136     }
0137     case cms::DDSolidShape::ddbox: {
0138       dd4hep::Box rs(solid);
0139       xos << "<Box name=\"" << trimShapeName(rs.name()) << "\""
0140           << " dx=\"" << rs.x() << "*mm\""
0141           << " dy=\"" << rs.y() << "*mm\""
0142           << " dz=\"" << rs.z() << "*mm\"/>" << std::endl;
0143       break;
0144     }
0145     case cms::DDSolidShape::ddtubs: {
0146       dd4hep::Tube rs(solid);
0147       double startPhi = convertRadToDeg(rs.startPhi());
0148       if (startPhi > 180. && startPhi <= 360.)
0149         startPhi -= 360.;
0150       // Convert large positive angles to small negative ones
0151       // to match how they are usually defined
0152 
0153       xos << "<Tubs name=\"" << trimShapeName(rs.name()) << "\""
0154           << " rMin=\"" << rs.rMin() << "*mm\""
0155           << " rMax=\"" << rs.rMax() << "*mm\""
0156           << " dz=\"" << rs.dZ() << "*mm\""
0157           << " startPhi=\"" << startPhi << "*deg\""
0158           << " deltaPhi=\"" << convertRadToDeg(rs.endPhi() - rs.startPhi()) << "*deg\"/>" << std::endl;
0159       break;
0160     }
0161     case cms::DDSolidShape::ddtrd1: {
0162       dd4hep::Trd1 rs(solid);
0163       xos << "<Trd1 name=\"" << trimShapeName(rs.name()) << "\""
0164           << " dz=\"" << rs.dZ() << "*mm\""
0165           << " dy1=\"" << rs.dY() << "*mm\""
0166           << " dy2=\"" << rs.dY() << "*mm\""
0167           << " dx1=\"" << rs.dX1() << "*mm\""
0168           << " dx2=\"" << rs.dX2() << "*mm\"/>" << std::endl;
0169       break;
0170     }
0171     case cms::DDSolidShape::ddtrd2: {
0172       dd4hep::Trd2 rs(solid);
0173       xos << "<Trd1 name=\"" << trimShapeName(rs.name()) << "\""
0174           << " dz=\"" << rs.dZ() << "*mm\""
0175           << " dy1=\"" << rs.dY1() << "*mm\""
0176           << " dy2=\"" << rs.dY2() << "*mm\""
0177           << " dx1=\"" << rs.dX1() << "*mm\""
0178           << " dx2=\"" << rs.dX2() << "*mm\"/>" << std::endl;
0179       break;
0180     }
0181     case cms::DDSolidShape::ddtrap: {
0182       dd4hep::Trap rs(solid);
0183       xos << std::setprecision(8);
0184       // Precision of 8 is needed to prevent complaints from Native Geant4 10.7 about
0185       // small deviations from planarity of trapezoid faces.
0186 
0187       xos << "<Trapezoid name=\"" << trimShapeName(rs.name()) << "\""
0188           << " dz=\"" << rs.dZ() << "*mm\""
0189           << " theta=\"" << convertRadToDeg(rs.theta()) << "*deg\""
0190           << " phi=\"" << convertRadToDeg(rs.phi()) << "*deg\""
0191           << " h1=\"" << rs.high1() << "*mm\""
0192           << " bl1=\"" << rs.bottomLow1() << "*mm\""
0193           << " tl1=\"" << rs.topLow1() << "*mm\""
0194           << " alp1=\"" << convertRadToDeg(rs.alpha1()) << "*deg\""
0195           << " h2=\"" << rs.high2() << "*mm\""
0196           << " bl2=\"" << rs.bottomLow2() << "*mm\""
0197           << " tl2=\"" << rs.topLow2() << "*mm\""
0198           << " alp2=\"" << convertRadToDeg(rs.alpha2()) << "*deg\"/>" << std::endl;
0199       xos << std::setprecision(5);
0200       // Before CMSSW_12_1_0_pre5, all solids, including Trapezoids, had precision of 5.
0201       // In tests With Native Geant4 10.7, this precision caused complaints, as explained above.
0202       // To minimize changes, the precision was increased only for Trapezoids.
0203       // In future, when there is an opportunity to revise the geometry, it might be
0204       // desirable to use precision of 8 for all solids for consistency.
0205       break;
0206     }
0207     case cms::DDSolidShape::ddcons: {
0208       dd4hep::ConeSegment rs(solid);
0209       double startPhi = convertRadToDeg(rs.startPhi());
0210       if (startPhi > 180. && startPhi <= 360.)
0211         startPhi -= 360.;
0212       // Convert large positive angles to small negative ones
0213       // to match how they are usually defined
0214       //
0215       xos << "<Cone name=\"" << trimShapeName(rs.name()) << "\""
0216           << " dz=\"" << rs.dZ() << "*mm\""
0217           << " rMin1=\"" << rs.rMin1() << "*mm\""
0218           << " rMax1=\"" << rs.rMax1() << "*mm\""
0219           << " rMin2=\"" << rs.rMin2() << "*mm\""
0220           << " rMax2=\"" << rs.rMax2() << "*mm\""
0221           << " startPhi=\"" << startPhi << "*deg\""
0222           << " deltaPhi=\"" << convertRadToDeg(rs.endPhi() - rs.startPhi()) << "*deg\"/>" << std::endl;
0223       break;
0224     }
0225     case cms::DDSolidShape::ddpolycone: {
0226       //   <Polycone name="OCMS" startPhi="0*deg" deltaPhi="360*deg" >
0227       //    <ZSection z="-[CMSZ1]"  rMin="[Rmin]"  rMax="[CMSR2]" />
0228       //    <ZSection z="-[HallZ]"  rMin="[Rmin]"  rMax="[CMSR2]" />
0229       //    <ZSection z="-[HallZ]"  rMin="[Rmin]"  rMax="[HallR]" />
0230       //    <ZSection z="[HallZ]"   rMin="[Rmin]"  rMax="[HallR]" />
0231       //    <ZSection z="[HallZ]"   rMin="[Rmin]"  rMax="[CMSR2]" />
0232       //    <ZSection z="[CMSZ1]"   rMin="[Rmin]"  rMax="[CMSR2]" />
0233       dd4hep::Polycone rs(solid);
0234       xos << "<Polycone name=\"" << trimShapeName(rs.name()) << "\""
0235           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0236           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\">" << std::endl;
0237       const std::vector<double>& zV(rs.zPlaneZ());
0238       const std::vector<double>& rMinV(rs.zPlaneRmin());
0239       const std::vector<double>& rMaxV(rs.zPlaneRmax());
0240       for (size_t i = 0; i < zV.size(); ++i) {
0241         xos << "<ZSection z=\"" << zV[i] << "*mm\""
0242             << " rMin=\"" << rMinV[i] << "*mm\""
0243             << " rMax=\"" << rMaxV[i] << "*mm\"/>" << std::endl;
0244       }
0245       xos << "</Polycone>" << std::endl;
0246       break;
0247     }
0248     case cms::DDSolidShape::ddpolyhedra: {
0249       dd4hep::Polyhedra rs(solid);
0250       xos << "<Polyhedra name=\"" << trimShapeName(rs.name()) << "\""
0251           << " numSide=\"" << rs.numEdges() << "\""
0252           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0253           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\">" << std::endl;
0254       const std::vector<double>& zV(rs.zPlaneZ());
0255       const std::vector<double>& rMinV(rs.zPlaneRmin());
0256       const std::vector<double>& rMaxV(rs.zPlaneRmax());
0257       for (size_t i = 0; i < zV.size(); ++i) {
0258         xos << "<ZSection z=\"" << zV[i] << "*mm\""
0259             << " rMin=\"" << rMinV[i] << "*mm\""
0260             << " rMax=\"" << rMaxV[i] << "*mm\"/>" << std::endl;
0261       }
0262       xos << "</Polyhedra>" << std::endl;
0263       break;
0264     }
0265     case cms::DDSolidShape::ddtrunctubs: {
0266       dd4hep::TruncatedTube rs(solid);
0267       xos << "<TruncTubs name=\"" << trimShapeName(rs.name()) << "\""
0268           << " zHalf=\"" << rs.dZ() << "*mm\""
0269           << " rMin=\"" << rs.rMin() << "*mm\""
0270           << " rMax=\"" << rs.rMax() << "*mm\""
0271           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0272           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\""
0273           << " cutAtStart=\"" << rs.cutAtStart() << "*mm\""
0274           << " cutAtDelta=\"" << rs.cutAtDelta() << "*mm\""
0275           << " cutInside=\"" << (rs.cutInside() ? "true" : "false") << "\"/>" << std::endl;
0276       break;
0277     }
0278     case cms::DDSolidShape::ddtorus: {
0279       dd4hep::Torus rs(solid);
0280       xos << "<Torus name=\"" << trimShapeName(rs.name()) << "\""
0281           << " innerRadius=\"" << rs.rMin() << "*mm\""
0282           << " outerRadius=\"" << rs.rMax() << "*mm\""
0283           << " torusRadius=\"" << rs.r() << "*mm\""
0284           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0285           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\"/>" << std::endl;
0286       break;
0287     }
0288     case cms::DDSolidShape::ddellipticaltube: {
0289       dd4hep::EllipticalTube rs(solid);
0290       xos << "<EllipticalTube name=\"" << trimShapeName(rs.name()) << "\""
0291           << " xSemiAxis=\"" << rs.a() << "*mm\""
0292           << " ySemiAxis=\"" << rs.b() << "*mm\""
0293           << " zHeight=\"" << rs.dZ() << "*mm\"/>" << std::endl;
0294       break;
0295     }
0296     case cms::DDSolidShape::ddcuttubs: {
0297       dd4hep::CutTube rs(solid);
0298       const std::vector<double>& pLowNorm(rs.lowNormal());
0299       const std::vector<double>& pHighNorm(rs.highNormal());
0300 
0301       xos << "<CutTubs name=\"" << trimShapeName(solid.name()) << "\""
0302           << " dz=\"" << rs.dZ() << "*mm\""
0303           << " rMin=\"" << rs.rMin() << "*mm\""
0304           << " rMax=\"" << rs.rMax() << "*mm\""
0305           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0306           << " deltaPhi=\"" << convertRadToDeg(rs.endPhi() - rs.startPhi()) << "*deg\""
0307           << " lx=\"" << pLowNorm[0] << "\""
0308           << " ly=\"" << pLowNorm[1] << "\""
0309           << " lz=\"" << pLowNorm[2] << "\""
0310           << " tx=\"" << pHighNorm[0] << "\""
0311           << " ty=\"" << pHighNorm[1] << "\""
0312           << " tz=\"" << pHighNorm[2] << "\"/>" << std::endl;
0313       break;
0314     }
0315     case cms::DDSolidShape::ddextrudedpolygon: {
0316       dd4hep::ExtrudedPolygon rs(solid);
0317       std::vector<double> x = rs.x();
0318       std::vector<double> y = rs.y();
0319       std::vector<double> z = rs.z();
0320       std::vector<double> zx = rs.zx();
0321       std::vector<double> zy = rs.zy();
0322       std::vector<double> zs = rs.zscale();
0323 
0324       xos << "<ExtrudedPolygon name=\"" << trimShapeName(rs.name()) << "\"";
0325       for (unsigned int i = 0; i < x.size(); ++i)
0326         xos << " <XYPoint x=\"" << x[i] << "*mm\" y=\"" << y[i] << "*mm\"/>\n";
0327       for (unsigned int k = 0; k < z.size(); ++k)
0328         xos << " <ZXYSection z=\"" << z[k] << "*mm\" x=\"" << zx[k] << "*mm\" y=\"" << zy[k] << "*mm scale=" << zs[k]
0329             << "*mm\"/>\n";
0330       xos << "</ExtrudedPolygon>\n";
0331       break;
0332     }
0333     case cms::DDSolidShape::dd_not_init:
0334     default:
0335       throw cms::Exception("DDException")
0336           << "DDCoreToDDXMLOutput::solid " << solid.name() << ", shape ID = " << static_cast<int>(shape)
0337           << ", solid title = " << solid.title();
0338       break;
0339   }
0340 }
0341 
0342 void DDCoreToDDXMLOutput::solid(const DDSolid& solid, std::ostream& xos) {
0343   switch (solid.shape()) {
0344     case DDSolidShape::ddunion:
0345     case DDSolidShape::ddsubtraction:
0346     case DDSolidShape::ddintersection: {
0347       DDBooleanSolid rs(solid);
0348       if (solid.shape() == DDSolidShape::ddunion) {
0349         xos << "<UnionSolid ";
0350       } else if (solid.shape() == DDSolidShape::ddsubtraction) {
0351         xos << "<SubtractionSolid ";
0352       } else if (solid.shape() == DDSolidShape::ddintersection) {
0353         xos << "<IntersectionSolid ";
0354       }
0355       xos << "name=\"" << rs.toString() << "\">" << std::endl;
0356       // if translation is == identity there are no parameters.
0357       // if there is no rotation the name will be ":"
0358       xos << "<rSolid name=\"" << rs.solidA().toString() << "\"/>" << std::endl;
0359       xos << "<rSolid name=\"" << rs.solidB().toString() << "\"/>" << std::endl;
0360       xos << "<Translation x=\"" << rs.translation().X() << "*mm\"";
0361       xos << " y=\"" << rs.translation().Y() << "*mm\"";
0362       xos << " z=\"" << rs.translation().Z() << "*mm\"";
0363       xos << "/>" << std::endl;
0364       std::string rotName = rs.rotation().toString();
0365       if (rotName == ":") {
0366         rotName = "gen:ID";
0367       }
0368       xos << "<rRotation name=\"" << rs.rotation().toString() << "\"/>" << std::endl;
0369       if (solid.shape() == DDSolidShape::ddunion) {
0370         xos << "</UnionSolid>" << std::endl;
0371       } else if (solid.shape() == DDSolidShape::ddsubtraction) {
0372         xos << "</SubtractionSolid>" << std::endl;
0373       } else if (solid.shape() == DDSolidShape::ddintersection) {
0374         xos << "</IntersectionSolid>" << std::endl;
0375       }
0376       break;
0377     }
0378     case DDSolidShape::ddbox: {
0379       //    <Box name="box1" dx="10*cm" dy="10*cm" dz="10*cm"/>
0380       DDBox rs(solid);
0381       xos << "<Box name=\"" << rs.toString() << "\""  //<< rs.toString() << "\"" //
0382           << " dx=\"" << rs.halfX() << "*mm\""
0383           << " dy=\"" << rs.halfY() << "*mm\""
0384           << " dz=\"" << rs.halfZ() << "*mm\"/>" << std::endl;
0385       break;
0386     }
0387     case DDSolidShape::ddtubs: {
0388       //      <Tubs name="TrackerSupportTubeNomex"         rMin="[SupportTubeR1]+[Tol]"
0389       //            rMax="[SupportTubeR2]-[Tol]"           dz="[SupportTubeL]"
0390       //            startPhi="0*deg"                       deltaPhi="360*deg"/>
0391       DDTubs rs(solid);
0392       xos << "<Tubs name=\"" << rs.toString() << "\""
0393           << " rMin=\"" << rs.rIn() << "*mm\""
0394           << " rMax=\"" << rs.rOut() << "*mm\""
0395           << " dz=\"" << rs.zhalf() << "*mm\""
0396           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0397           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\"/>" << std::endl;
0398       break;
0399     }
0400     case DDSolidShape::ddtrap: {
0401       //    <Trapezoid name="UpL_CSC_for_TotemT1_Plane_2_5_7" dz="[PCB_Epoxy_Thick_3P]/2."
0402       //      alp1="-[Up_Signal_Side_alpL_3P]" alp2="-[Up_Signal_Side_alpL_3P]"
0403       //     bl1="[Max_Base_Signal_SideL_3P]/2." tl1="[Up_Min_Base_Signal_SideL_3P]/2." h1="[Up_Height_Signal_SideL_3P]/2."
0404       //     h2="[Up_Height_Signal_SideL_3P]/2." bl2="[Max_Base_Signal_SideL_3P]/2." tl2="[Up_Min_Base_Signal_SideL_3P]/2."/>
0405       DDTrap rs(solid);
0406       xos << "<Trapezoid name=\"" << rs.toString() << "\""
0407           << " dz=\"" << rs.halfZ() << "*mm\""
0408           << " theta=\"" << convertRadToDeg(rs.theta()) << "*deg\""
0409           << " phi=\"" << convertRadToDeg(rs.phi()) << "*deg\""
0410           << " h1=\"" << rs.y1() << "*mm\""
0411           << " bl1=\"" << rs.x1() << "*mm\""
0412           << " tl1=\"" << rs.x2() << "*mm\""
0413           << " alp1=\"" << convertRadToDeg(rs.alpha1()) << "*deg\""
0414           << " h2=\"" << rs.y2() << "*mm\""
0415           << " bl2=\"" << rs.x3() << "*mm\""
0416           << " tl2=\"" << rs.x4() << "*mm\""
0417           << " alp2=\"" << convertRadToDeg(rs.alpha2()) << "*deg\"/>" << std::endl;
0418       break;
0419     }
0420     case DDSolidShape::ddcons: {
0421       DDCons rs(solid);
0422       xos << "<Cone name=\"" << rs.toString() << "\""
0423           << " dz=\"" << rs.zhalf() << "*mm\""
0424           << " rMin1=\"" << rs.rInMinusZ() << "*mm\""
0425           << " rMax1=\"" << rs.rOutMinusZ() << "*mm\""
0426           << " rMin2=\"" << rs.rInPlusZ() << "*mm\""
0427           << " rMax2=\"" << rs.rOutPlusZ() << "*mm\""
0428           << " startPhi=\"" << convertRadToDeg(rs.phiFrom()) << "*deg\""
0429           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\"/>" << std::endl;
0430       break;
0431     }
0432     case DDSolidShape::ddpolycone_rz: {
0433       DDPolycone rs(solid);
0434       xos << "<Polycone name=\"" << rs.toString() << "\""
0435           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0436           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\">" << std::endl;
0437       const std::vector<double>& zV(rs.zVec());
0438       const std::vector<double>& rV(rs.rVec());
0439       for (size_t i = 0; i < zV.size(); ++i) {
0440         xos << "<RZPoint r=\"" << rV[i] << "*mm\""
0441             << " z=\"" << zV[i] << "*mm\"/>" << std::endl;
0442       }
0443       xos << "</Polycone>" << std::endl;
0444       break;
0445     }
0446     case DDSolidShape::ddpolyhedra_rz: {
0447       DDPolyhedra rs(solid);
0448       xos << "<Polyhedra name=\"" << rs.toString() << "\""
0449           << " numSide=\"" << rs.sides() << "\""
0450           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0451           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\">" << std::endl;
0452       const std::vector<double>& zV(rs.zVec());
0453       const std::vector<double>& rV(rs.rVec());
0454       for (size_t i = 0; i < zV.size(); ++i) {
0455         xos << "<RZPoint r=\"" << rV[i] << "*mm\""
0456             << " z=\"" << zV[i] << "*mm\"/>" << std::endl;
0457       }
0458       xos << "</Polyhedra>" << std::endl;
0459       break;
0460     }
0461     case DDSolidShape::ddpolycone_rrz: {
0462       //   <Polycone name="OCMS" startPhi="0*deg" deltaPhi="360*deg" >
0463       //    <ZSection z="-[CMSZ1]"  rMin="[Rmin]"  rMax="[CMSR2]" />
0464       //    <ZSection z="-[HallZ]"  rMin="[Rmin]"  rMax="[CMSR2]" />
0465       //    <ZSection z="-[HallZ]"  rMin="[Rmin]"  rMax="[HallR]" />
0466       //    <ZSection z="[HallZ]"   rMin="[Rmin]"  rMax="[HallR]" />
0467       //    <ZSection z="[HallZ]"   rMin="[Rmin]"  rMax="[CMSR2]" />
0468       //    <ZSection z="[CMSZ1]"   rMin="[Rmin]"  rMax="[CMSR2]" />
0469       DDPolycone rs(solid);
0470       xos << "<Polycone name=\"" << rs.toString() << "\""
0471           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0472           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\">" << std::endl;
0473       const std::vector<double>& zV(rs.zVec());
0474       const std::vector<double>& rMinV(rs.rMinVec());
0475       const std::vector<double>& rMaxV(rs.rMaxVec());
0476       for (size_t i = 0; i < zV.size(); ++i) {
0477         xos << "<ZSection z=\"" << zV[i] << "*mm\""
0478             << " rMin=\"" << rMinV[i] << "*mm\""
0479             << " rMax=\"" << rMaxV[i] << "*mm\"/>" << std::endl;
0480       }
0481       xos << "</Polycone>" << std::endl;
0482       break;
0483     }
0484     case DDSolidShape::ddpolyhedra_rrz: {
0485       DDPolyhedra rs(solid);
0486       xos << "<Polyhedra name=\"" << rs.toString() << "\""
0487           << " numSide=\"" << rs.sides() << "\""
0488           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0489           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\">" << std::endl;
0490       const std::vector<double>& zV(rs.zVec());
0491       const std::vector<double>& rMinV(rs.rMinVec());
0492       const std::vector<double>& rMaxV(rs.rMaxVec());
0493       for (size_t i = 0; i < zV.size(); ++i) {
0494         xos << "<ZSection z=\"" << zV[i] << "*mm\""
0495             << " rMin=\"" << rMinV[i] << "*mm\""
0496             << " rMax=\"" << rMaxV[i] << "*mm\"/>" << std::endl;
0497       }
0498       xos << "</Polyhedra>" << std::endl;
0499       break;
0500     }
0501     case DDSolidShape::ddpseudotrap: {
0502       // <PseudoTrap name="YE3_b" dx1="0.395967*m" dx2="1.86356*m" dy1="0.130*m" dy2="0.130*m" dz="2.73857*m" radius="-1.5300*m" atMinusZ="true"/>
0503       DDPseudoTrap rs(solid);
0504       xos << "<PseudoTrap name=\"" << rs.toString() << "\""
0505           << " dx1=\"" << rs.x1() << "*mm\""
0506           << " dx2=\"" << rs.x2() << "*mm\""
0507           << " dy1=\"" << rs.y1() << "*mm\""
0508           << " dy2=\"" << rs.y2() << "*mm\""
0509           << " dz=\"" << rs.halfZ() << "*mm\""
0510           << " radius=\"" << rs.radius() << "*mm\""
0511           << " atMinusZ=\"" << (rs.atMinusZ() ? "true" : "false") << "\"/>" << std::endl;
0512       break;
0513     }
0514     case DDSolidShape::ddtrunctubs: {
0515       // <TruncTubs name="trunctubs1" zHalf="50*cm" rMin="20*cm" rMax="40*cm"
0516       //                              startPhi="0*deg" deltaPhi="90*deg"
0517       //                              cutAtStart="25*cm" cutAtDelta="35*cm"/>
0518       DDTruncTubs rs(solid);
0519       xos << "<TruncTubs name=\"" << rs.toString() << "\""
0520           << " zHalf=\"" << rs.zHalf() << "*mm\""
0521           << " rMin=\"" << rs.rIn() << "*mm\""
0522           << " rMax=\"" << rs.rOut() << "*mm\""
0523           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0524           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\""
0525           << " cutAtStart=\"" << rs.cutAtStart() << "*mm\""
0526           << " cutAtDelta=\"" << rs.cutAtDelta() << "*mm\""
0527           << " cutInside=\"" << (rs.cutInside() ? "true" : "false") << "\"/>" << std::endl;
0528       break;
0529     }
0530     case DDSolidShape::ddshapeless: {
0531       DDShapelessSolid rs(solid);
0532       xos << "<ShapelessSolid name=\"" << rs.toString() << "\"/>" << std::endl;
0533       break;
0534     }
0535     case DDSolidShape::ddtorus: {
0536       // <Torus name="torus" innerRadius="7.5*cm" outerRadius="10*cm"
0537       //                     torusRadius="30*cm" startPhi="0*deg" deltaPhi="360*deg"/>
0538       DDTorus rs(solid);
0539       xos << "<Torus name=\"" << rs.toString() << "\""
0540           << " innerRadius=\"" << rs.rMin() << "*mm\""
0541           << " outerRadius=\"" << rs.rMax() << "*mm\""
0542           << " torusRadius=\"" << rs.rTorus() << "*mm\""
0543           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0544           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\"/>" << std::endl;
0545       break;
0546     }
0547     case DDSolidShape::ddellipticaltube: {
0548       // <EllipticalTube name="CMSWall"  xSemiAxis="[cavernData:CMSWallEDX]"
0549       //                                 ySemiAxis="[cavernData:CMSWallEDY]"
0550       //                                 zHeight="[cms:HallZ]"/>
0551       DDEllipticalTube rs(solid);
0552       xos << "<EllipticalTube name=\"" << rs.toString() << "\""
0553           << " xSemiAxis=\"" << rs.xSemiAxis() << "*mm\""
0554           << " ySemiAxis=\"" << rs.ySemiAxis() << "*mm\""
0555           << " zHeight=\"" << rs.zHeight() << "*mm\"/>" << std::endl;
0556       break;
0557     }
0558     case DDSolidShape::ddcuttubs: {
0559       //      <Tubs name="TrackerSupportTubeNomex"         rMin="[SupportTubeR1]+[Tol]"
0560       //            rMax="[SupportTubeR2]-[Tol]"           dz="[SupportTubeL]"
0561       //            startPhi="0*deg"                       deltaPhi="360*deg"/>
0562       DDCutTubs rs(solid);
0563       const std::array<double, 3>& pLowNorm(rs.lowNorm());
0564       const std::array<double, 3>& pHighNorm(rs.highNorm());
0565 
0566       xos << "<CutTubs name=\"" << rs.toString() << "\""
0567           << " dz=\"" << rs.zhalf() << "*mm\""
0568           << " rMin=\"" << rs.rIn() << "*mm\""
0569           << " rMax=\"" << rs.rOut() << "*mm\""
0570           << " startPhi=\"" << convertRadToDeg(rs.startPhi()) << "*deg\""
0571           << " deltaPhi=\"" << convertRadToDeg(rs.deltaPhi()) << "*deg\""
0572           << " lx=\"" << pLowNorm[0] << "\""
0573           << " ly=\"" << pLowNorm[1] << "\""
0574           << " lz=\"" << pLowNorm[2] << "\""
0575           << " tx=\"" << pHighNorm[0] << "\""
0576           << " ty=\"" << pHighNorm[1] << "\""
0577           << " tz=\"" << pHighNorm[2] << "\"/>" << std::endl;
0578       break;
0579     }
0580     case DDSolidShape::ddextrudedpolygon: {
0581       DDExtrudedPolygon rs(solid);
0582       std::vector<double> x = rs.xVec();
0583       std::vector<double> y = rs.yVec();
0584       std::vector<double> z = rs.zVec();
0585       std::vector<double> zx = rs.zxVec();
0586       std::vector<double> zy = rs.zyVec();
0587       std::vector<double> zs = rs.zscaleVec();
0588 
0589       xos << "<ExtrudedPolygon name=\"" << rs.toString() << "\"";
0590       for (unsigned int i = 0; i < x.size(); ++i)
0591         xos << " <XYPoint x=\"" << x[i] << "*mm\" y=\"" << y[i] << "*mm\"/>\n";
0592       for (unsigned int k = 0; k < z.size(); ++k)
0593         xos << " <ZXYSection z=\"" << z[k] << "*mm\" x=\"" << zx[k] << "*mm\" y=\"" << zy[k] << "*mm scale=" << zs[k]
0594             << "*mm\"/>\n";
0595       xos << "</ExtrudedPolygon>\n";
0596       break;
0597     }
0598     case DDSolidShape::dd_not_init:
0599     default:
0600       throw cms::Exception("DDException")
0601           << "DDCoreToDDXMLOutput::solid(...) " << solid.name() << " either not inited or no such solid.";
0602       break;
0603   }
0604 }
0605 
0606 void DDCoreToDDXMLOutput::material(const DDMaterial& material, std::ostream& xos) {
0607   int noc = material.noOfConstituents();
0608   if (noc == 0) {
0609     xos << "<ElementaryMaterial name=\"" << material.toString() << "\""
0610         << " density=\"" << std::scientific << std::setprecision(5) << convertUnitsTo(1._mg_per_cm3, material.density())
0611         << "*mg/cm3\""
0612         << " atomicWeight=\"" << std::fixed << convertUnitsTo(1._g_per_mole, material.a()) << "*g/mole\""
0613         << std::setprecision(0) << std::fixed << " atomicNumber=\"" << material.z() << "\"/>" << std::endl;
0614   } else {
0615     xos << "<CompositeMaterial name=\"" << material.toString() << "\""
0616         << " density=\"" << std::scientific << std::setprecision(5) << convertUnitsTo(1._mg_per_cm3, material.density())
0617         << "*mg/cm3\""
0618         << " method=\"mixture by weight\">" << std::endl;
0619 
0620     int j = 0;
0621     for (; j < noc; ++j) {
0622       xos << "<MaterialFraction fraction=\"" << std::fixed << std::setprecision(9) << material.constituent(j).second
0623           << "\">" << std::endl;
0624       xos << "<rMaterial name=\"" << material.constituent(j).first.name() << "\"/>" << std::endl;
0625       xos << "</MaterialFraction>" << std::endl;
0626     }
0627     xos << "</CompositeMaterial>" << std::endl;
0628   }
0629 }
0630 
0631 void DDCoreToDDXMLOutput::material(const std::string& matName,
0632                                    double density,
0633                                    const std::vector<cms::DDParsingContext::CompositeMaterial>& matRefs,
0634                                    std::ostream& xos) {
0635   xos << "<CompositeMaterial name=\"" << matName << "\""
0636       << " density=\"" << std::scientific << std::setprecision(5) << convertGPerCcToMgPerCc(density) << "*mg/cm3\""
0637       << " method=\"mixture by weight\">" << std::endl;
0638 
0639   for (auto compIter = matRefs.begin(); compIter != matRefs.end(); ++compIter) {
0640     xos << "<MaterialFraction fraction=\"" << std::fixed << std::setprecision(9) << compIter->fraction << "\">"
0641         << std::endl;
0642     xos << "<rMaterial name=\"" << compIter->name << "\"/>" << std::endl;
0643     xos << "</MaterialFraction>" << std::endl;
0644   }
0645   xos << "</CompositeMaterial>" << std::endl;
0646 }
0647 
0648 void DDCoreToDDXMLOutput::element(const TGeoMaterial* material, std::ostream& xos) {
0649   int noc = material->GetNelements();
0650   if (noc == 1) {
0651     TGeoElement* elem = material->GetElement();
0652     std::string nameLowerCase(elem->GetTitle());
0653     // Leave first letter capitalized
0654     for (size_t index = 1; index < nameLowerCase.size(); ++index) {
0655       nameLowerCase[index] = tolower(nameLowerCase[index]);
0656     }
0657     std::string trimName(dd4hep::dd::noNamespace(material->GetName()));
0658 
0659     // Element title contains element name in all uppercase.
0660     // Convert to lowercase and check that material name matches element name.
0661     // Hydrogen is used for vacuum materials. Phosphorus is called "Phosphor"
0662     // Boron is a special case because there are two isotopes defined: "Bor 10" and "Bor 11".
0663     if (trimName == nameLowerCase || nameLowerCase == "Hydrogen" || nameLowerCase == "Phosphorus" ||
0664         (nameLowerCase == "Boron" && trimName.compare(0, 3, "Bor") == 0)) {
0665       xos << "<ElementaryMaterial name=\"" << material->GetName() << "\""
0666           << " density=\"" << std::scientific << std::setprecision(5) << convertGPerCcToMgPerCc(material->GetDensity())
0667           << "*mg/cm3\""
0668           << " atomicWeight=\"" << std::fixed << material->GetA() << "*g/mole\"" << std::setprecision(0) << std::fixed
0669           << " atomicNumber=\"" << material->GetZ() << "\"/>" << std::endl;
0670     }
0671   }
0672 }
0673 
0674 void DDCoreToDDXMLOutput::rotation(const DDRotation& rotation, std::ostream& xos, const std::string& rotn) {
0675   DD3Vector x, y, z;
0676   rotation.rotation().GetComponents(x, y, z);
0677   double a, b, c;
0678   x.GetCoordinates(a, b, c);
0679   x.SetCoordinates(
0680       cms_rounding::roundIfNear0(a, tol0), cms_rounding::roundIfNear0(b, tol0), cms_rounding::roundIfNear0(c, tol0));
0681   y.GetCoordinates(a, b, c);
0682   y.SetCoordinates(
0683       cms_rounding::roundIfNear0(a, tol0), cms_rounding::roundIfNear0(b, tol0), cms_rounding::roundIfNear0(c, tol0));
0684   z.GetCoordinates(a, b, c);
0685   z.SetCoordinates(
0686       cms_rounding::roundIfNear0(a, tol0), cms_rounding::roundIfNear0(b, tol0), cms_rounding::roundIfNear0(c, tol0));
0687   double check = (x.Cross(y)).Dot(z);  // in case of a LEFT-handed orthogonal system
0688                                        // this must be -1
0689   bool reflection((1. - check) > reflectTol);
0690   std::string rotName = rotation.toString();
0691   if (rotName == ":") {
0692     if (!rotn.empty()) {
0693       rotName = rotn;
0694       std::cout << "about to try to make a new DDRotation... should fail!" << std::endl;
0695       DDRotation rot(DDName(rotn), std::make_unique<DDRotationMatrix>(rotation.rotation()));
0696       std::cout << "new rotation: " << rot << std::endl;
0697     } else {
0698       std::cout << "WARNING: MAKING AN UNNAMED ROTATION" << std::endl;
0699     }
0700   }
0701   if (!reflection) {
0702     xos << "<Rotation ";
0703   } else {
0704     xos << "<ReflectionRotation ";
0705   }
0706   using namespace cms_rounding;
0707   xos << "name=\"" << rotName << "\""
0708       << " phiX=\"" << roundIfNear0(convertRadToDeg(x.phi()), tol0) << "*deg\""
0709       << " thetaX=\"" << roundIfNear0(convertRadToDeg(x.theta()), tol0) << "*deg\""
0710       << " phiY=\"" << roundIfNear0(convertRadToDeg(y.phi()), tol0) << "*deg\""
0711       << " thetaY=\"" << roundIfNear0(convertRadToDeg(y.theta()), tol0) << "*deg\""
0712       << " phiZ=\"" << roundIfNear0(convertRadToDeg(z.phi()), tol0) << "*deg\""
0713       << " thetaZ=\"" << roundIfNear0(convertRadToDeg(z.theta()), tol0) << "*deg\"/>" << std::endl;
0714 }
0715 
0716 void DDCoreToDDXMLOutput::rotation(const dd4hep::Rotation3D& rotation,
0717                                    std::ostream& xos,
0718                                    const cms::DDParsingContext& context,
0719                                    const std::string& rotn) {
0720   ROOT::Math::XYZVector x, y, z;
0721   rotation.GetComponents(x, y, z);
0722   double a, b, c;
0723   x.GetCoordinates(a, b, c);
0724   x.SetCoordinates(
0725       cms_rounding::roundIfNear0(a, tol0), cms_rounding::roundIfNear0(b, tol0), cms_rounding::roundIfNear0(c, tol0));
0726   y.GetCoordinates(a, b, c);
0727   y.SetCoordinates(
0728       cms_rounding::roundIfNear0(a, tol0), cms_rounding::roundIfNear0(b, tol0), cms_rounding::roundIfNear0(c, tol0));
0729   z.GetCoordinates(a, b, c);
0730   z.SetCoordinates(
0731       cms_rounding::roundIfNear0(a, tol0), cms_rounding::roundIfNear0(b, tol0), cms_rounding::roundIfNear0(c, tol0));
0732   double check = (x.Cross(y)).Dot(z);  // in case of a LEFT-handed orthogonal system
0733                                        // this must be -1
0734   bool reflection((1. - check) > reflectTol);
0735   if (!reflection) {
0736     xos << "<Rotation ";
0737   } else {
0738     xos << "<ReflectionRotation ";
0739   }
0740   using namespace cms_rounding;
0741   xos << "name=\"" << rotn << "\""
0742       << " phiX=\"" << roundIfNear0(convertRadToDeg(x.phi()), tol0) << "*deg\""
0743       << " thetaX=\"" << roundIfNear0(convertRadToDeg(x.theta()), tol0) << "*deg\""
0744       << " phiY=\"" << roundIfNear0(convertRadToDeg(y.phi()), tol0) << "*deg\""
0745       << " thetaY=\"" << roundIfNear0(convertRadToDeg(y.theta()), tol0) << "*deg\""
0746       << " phiZ=\"" << roundIfNear0(convertRadToDeg(z.phi()), tol0) << "*deg\""
0747       << " thetaZ=\"" << roundIfNear0(convertRadToDeg(z.theta()), tol0) << "*deg\"/>" << std::endl;
0748 }
0749 
0750 void DDCoreToDDXMLOutput::logicalPart(const DDLogicalPart& lp, std::ostream& xos) {
0751   xos << "<LogicalPart name=\"" << lp.toString() << "\">" << std::endl;
0752   xos << "<rSolid name=\"" << lp.solid().toString() << "\"/>" << std::endl;
0753   xos << "<rMaterial name=\"" << lp.material().toString() << "\"/>" << std::endl;
0754   xos << "</LogicalPart>" << std::endl;
0755 }
0756 
0757 void DDCoreToDDXMLOutput::logicalPart(const std::string& asName, std::ostream& xos) {
0758   xos << "<LogicalPart name=\"" << asName << "\">" << std::endl;
0759   xos << "<rSolid name=\"" << asName << "\"/>" << std::endl;
0760   xos << "<rMaterial name=\"materials:Air\"/>" << std::endl;
0761   xos << "</LogicalPart>" << std::endl;
0762 }
0763 
0764 void DDCoreToDDXMLOutput::logicalPart(const TGeoVolume& lp, std::ostream& xos) {
0765   xos << "<LogicalPart name=\"" << lp.GetName() << "\">" << std::endl;
0766   auto solid = lp.GetShape();
0767   if (solid != nullptr) {
0768     xos << "<rSolid name=\"" << trimShapeName(solid->GetName()) << "\"/>" << std::endl;
0769   }
0770   auto material = lp.GetMaterial();
0771   if (material != nullptr) {
0772     xos << "<rMaterial name=\"" << material->GetName() << "\"/>" << std::endl;
0773   }
0774   xos << "</LogicalPart>" << std::endl;
0775 }
0776 
0777 void DDCoreToDDXMLOutput::position(const TGeoVolume& parent,
0778                                    const TGeoNode& child,
0779                                    const std::string& childVolName,
0780                                    cms::DDParsingContext& context,
0781                                    std::ostream& xos) {
0782   xos << "<PosPart copyNumber=\"" << child.GetNumber() << "\">" << std::endl;
0783   xos << "<rParent name=\"" << parent.GetName() << "\"/>" << std::endl;
0784   xos << "<rChild name=\"" << childVolName << "\"/>" << std::endl;
0785 
0786   const auto matrix = child.GetMatrix();
0787   if (matrix != nullptr && !matrix->IsIdentity()) {
0788     auto rot = matrix->GetRotationMatrix();
0789     if (cms::rotation_utils::rotHash(rot) != cms::rotation_utils::identityHash) {
0790       std::string rotNameStr = cms::rotation_utils::rotName(rot, context);
0791       if (rotNameStr == "NULL") {
0792         rotNameStr = child.GetName();  // Phys vol name
0793         rotNameStr += parent.GetName();
0794         cms::DDNamespace nameSpace(context);
0795         cms::rotation_utils::addRotWithNewName(nameSpace, rotNameStr, rot);
0796       }
0797       xos << "<rRotation name=\"" << rotNameStr << "\"/>" << std::endl;
0798     }
0799   }
0800   auto trans = matrix->GetTranslation();
0801   using namespace cms_rounding;
0802   xos << "<Translation x=\"" << roundIfNear0(trans[0]) << "*mm\"";
0803   xos << " y=\"" << roundIfNear0(trans[1]) << "*mm\"";
0804   xos << " z=\"" << roundIfNear0(trans[2]) << "*mm\"";
0805   xos << "/>" << std::endl;
0806   xos << "</PosPart>" << std::endl;
0807 }
0808 
0809 void DDCoreToDDXMLOutput::position(const DDLogicalPart& parent,
0810                                    const DDLogicalPart& child,
0811                                    DDPosData* edgeToChild,
0812                                    int& rotNameSeed,
0813                                    std::ostream& xos) {
0814   std::string rotName = edgeToChild->ddrot().toString();
0815   DDRotationMatrix myIDENT;
0816 
0817   xos << "<PosPart copyNumber=\"" << edgeToChild->copyno() << "\">" << std::endl;
0818   xos << "<rParent name=\"" << parent.toString() << "\"/>" << std::endl;
0819   xos << "<rChild name=\"" << child.toString() << "\"/>" << std::endl;
0820   if ((edgeToChild->ddrot().rotation()) != myIDENT) {
0821     if (rotName == ":") {
0822       rotation(edgeToChild->ddrot(), xos);
0823     } else {
0824       xos << "<rRotation name=\"" << rotName << "\"/>" << std::endl;
0825     }
0826   }  // else let default Rotation matrix be created?
0827   using namespace cms_rounding;
0828   xos << "<Translation x=\"" << roundIfNear0(edgeToChild->translation().x()) << "*mm\""
0829       << " y=\"" << roundIfNear0(edgeToChild->translation().y()) << "*mm\""
0830       << " z=\"" << roundIfNear0(edgeToChild->translation().z()) << "*mm\"/>" << std::endl;
0831   xos << "</PosPart>" << std::endl;
0832 }
0833 
0834 void DDCoreToDDXMLOutput::specpar(const DDSpecifics& sp, std::ostream& xos) {
0835   xos << "<SpecPar name=\"" << sp.toString() << "\" eval=\"false\">" << std::endl;
0836 
0837   // ========...  all the selection strings out as strings by using the DDPartSelection's std::ostream function...
0838   for (const auto& psit : sp.selection()) {
0839     xos << "<PartSelector path=\"" << psit << "\"/>" << std::endl;
0840   }
0841 
0842   // =========  ... and iterate over all DDValues...
0843   for (const auto& vit : sp.specifics()) {
0844     const DDValue& v = vit.second;
0845     size_t s = v.size();
0846     size_t i = 0;
0847     // ============  ... all actual values with the same name
0848     const std::vector<std::string>& strvec = v.strings();
0849     if (v.isEvaluated()) {
0850       for (; i < s; ++i) {
0851         xos << "<Parameter name=\"" << v.name() << "\""
0852             << " value=\"" << v[i] << "\""
0853             << " eval=\"true\"/>" << std::endl;
0854       }
0855     } else {
0856       for (; i < s; ++i) {
0857         xos << "<Parameter name=\"" << v.name() << "\""
0858             << " value=\"" << strvec[i] << "\""
0859             << " eval=\"false\"/>" << std::endl;
0860       }
0861     }
0862   }
0863   xos << "</SpecPar>" << std::endl;
0864 }
0865 
0866 void DDCoreToDDXMLOutput::specpar(const std::string& name, const dd4hep::SpecPar& specPar, std::ostream& xos) {
0867   xos << "<SpecPar name=\"" << name << "\" eval=\"false\">" << std::endl;
0868 
0869   for (const auto& psit : specPar.paths) {
0870     xos << "<PartSelector path=\"" << psit << "\"/>" << std::endl;
0871   }
0872 
0873   for (const auto& vit : specPar.spars) {
0874     for (const auto& sit : vit.second) {
0875       xos << "<Parameter name=\"" << vit.first << "\""
0876           << " value=\"" << sit << "\""
0877           << " eval=\"false\"/>" << std::endl;
0878     }
0879   }
0880   for (const auto& vit : specPar.numpars) {
0881     for (const auto& sit : vit.second) {
0882       xos << "<Parameter name=\"" << vit.first << "\""
0883           << " value=\"" << sit << "\""
0884           << " eval=\"true\"/>" << std::endl;
0885     }
0886   }
0887   xos << "</SpecPar>" << std::endl;
0888 }
0889 
0890 void DDCoreToDDXMLOutput::specpar(const std::pair<DDsvalues_type, std::set<const DDPartSelection*>>& pssv,
0891                                   std::ostream& xos) {
0892   static const std::string madeName("specparname");
0893   static int numspecpars(0);
0894   std::ostringstream ostr;
0895   ostr << numspecpars++;
0896   std::string spname = madeName + ostr.str();
0897   xos << "<SpecPar name=\"" << spname << "\" eval=\"false\">" << std::endl;
0898   for (const auto& psit : pssv.second) {
0899     xos << "<PartSelector path=\"" << *psit << "\"/>" << std::endl;
0900   }
0901 
0902   // =========  ... and iterate over all DDValues...
0903   for (const auto& vit : pssv.first) {
0904     const DDValue& v = vit.second;
0905     size_t s = v.size();
0906     size_t i = 0;
0907     // ============  ... all actual values with the same name
0908     const std::vector<std::string>& strvec = v.strings();
0909     if (v.isEvaluated()) {
0910       for (; i < s; ++i) {
0911         xos << "<Parameter name=\"" << v.name() << "\""
0912             << " value=\"" << v[i] << "\""
0913             << " eval=\"true\"/>" << std::endl;
0914       }
0915     } else {
0916       for (; i < s; ++i) {
0917         xos << "<Parameter name=\"" << v.name() << "\""
0918             << " value=\"" << strvec[i] << "\""
0919             << " eval=\"false\"/>" << std::endl;
0920       }
0921     }
0922   }
0923 
0924   xos << "</SpecPar>" << std::endl;
0925 }