Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:14:31

0001 #include "DD4hep/DetFactoryHelper.h"
0002 #include "DetectorDescription/DDCMS/interface/DDPlugins.h"
0003 #include "DetectorDescription/DDCMS/interface/BenchmarkGrd.h"
0004 #include "DetectorDescription/DDCMS/interface/DDutils.h"
0005 #include "DataFormats/Math/interface/angle_units.h"
0006 // Header files for endcap supercrystal geometry
0007 #include "Geometry/EcalCommonData/interface/DDEcalEndcapTrapX.h"
0008 #include <CLHEP/Geometry/Transform3D.h>
0009 
0010 #include <string>
0011 #include <vector>
0012 
0013 using namespace angle_units::operators;
0014 
0015 //#define EDM_ML_DEBUG
0016 
0017 namespace {
0018   struct Endcap {
0019     std::string mat;
0020     double zOff;
0021 
0022     std::string quaName;
0023     std::string quaMat;
0024 
0025     std::string crysMat;
0026     std::string wallMat;
0027 
0028     double crysLength;
0029     double crysRear;
0030     double crysFront;
0031     double sCELength;
0032     double sCERear;
0033     double sCEFront;
0034     double sCALength;
0035     double sCARear;
0036     double sCAFront;
0037     double sCAWall;
0038     double sCHLength;
0039     double sCHSide;
0040 
0041     double nSCTypes;
0042     std::vector<double> vecEESCProf;
0043     double nColumns;
0044     std::vector<double> vecEEShape;
0045     double nSCCutaway;
0046     std::vector<double> vecEESCCutaway;
0047     double nSCquad;
0048     std::vector<double> vecEESCCtrs;
0049     double nCRSC;
0050     std::vector<double> vecEECRCtrs;
0051 
0052     std::array<double, 3> cutParms;
0053     std::string cutBoxName;
0054 
0055     std::string envName;
0056     std::string alvName;
0057     std::string intName;
0058     std::string cryName;
0059 
0060     DDTranslation cryFCtr[5][5];
0061     DDTranslation cryRCtr[5][5];
0062     DDTranslation scrFCtr[10][10];
0063     DDTranslation scrRCtr[10][10];
0064 
0065     double pFHalf;
0066     double pFFifth;
0067     double pF45;
0068 
0069     std::vector<double> vecEESCLims;
0070 
0071     double iLength;
0072     double iXYOff;
0073     double cryZOff;
0074     double zFront;
0075   };
0076 
0077   const DDRotationMatrix& myrot(cms::DDNamespace& ns, const std::string& nam, const DDRotationMatrix& r) {
0078     ns.addRotation(nam, r);
0079     return ns.rotation(ns.prepend(nam));
0080   }
0081 
0082   std::string_view mynamespace(std::string_view input) {
0083     std::string_view v = input;
0084     auto trim_pos = v.find(':');
0085     if (trim_pos != v.npos)
0086       v.remove_suffix(v.size() - (trim_pos + 1));
0087     return v;
0088   }
0089 
0090   void placeEFRYn00(dd4hep::Volume& eeSCALog,
0091                     const dd4hep::Volume& eeCRLog,
0092                     int copyNum,
0093                     cms::DDNamespace& ns,
0094                     const std::string& rname,
0095                     DDEcalEndcapTrapX& crystal,
0096                     double cryZOff) {
0097     // The "EECrRoC1R1" rotation is too small. It is ignored by ROOT when the volume is placed. In order for the
0098     // volume to be placed with some rotation, the original rotation is increased by 1%, which is just enough for
0099     // the revised rotation to pass ROOT's check for a valid, non-identity rotation. It is hoped that such a small
0100     // change in a tiny rotaion will have no negative effects in the geometry.
0101     //
0102     // ROOT version where issue is observed: ROOT 6.22/09
0103     // TGeoRotation::CheckMatrix() is the method that checks rotations. When it determines a rotation is too
0104     // small, it sets the rotation to be ignored.
0105     // Original rotation angles: x = -7.045281e-07, y = 7.045385e-07, z = 0
0106     // Adjusted rotation angles: x = -7.115734e-07, y = 7.115839e-07, z = 0
0107 
0108     double xx, xy, xz, yx, yy, yz, zx, zy, zz;
0109     auto rotAdjusted = crystal.rotation();
0110     rotAdjusted.GetComponents(xx, xy, xz, yx, yy, yz, zx, zy, zz);
0111     double xtheta = atan2(zy, zz);
0112     double distyz = sqrt(zy * zy + zz * zz);
0113     double ytheta = atan2(-zx, distyz);
0114     double ztheta = atan2(yx, xx);
0115     LogDebug("EcalGeom") << "Original " << rname << " rotation angles: xtheta = " << std::setprecision(18) << xtheta
0116                          << ", distyz = " << distyz << ", ytheta = " << ytheta << ", ztheta = " << ztheta;
0117     double increase = 1.01;  // Increase rotation angle by 1%
0118     xtheta *= increase;
0119     ytheta *= increase;
0120     LogDebug("EcalGeom") << "Adjusted (+1%) " << rname << " rotation angles: xtheta = " << std::setprecision(18)
0121                          << xtheta << ", distyz = " << distyz << ", ytheta = " << ytheta << ", ztheta = " << ztheta;
0122     double xdiag = cos(xtheta), xoff = sin(xtheta);
0123     double ydiag = cos(ytheta), yoff = sin(ytheta);
0124     DDRotationMatrix xrot(1., 0., 0., 0., xdiag, -xoff, 0., xoff, xdiag);
0125     DDRotationMatrix yrot(ydiag, 0., yoff, 0., 1., 0., -yoff, 0., ydiag);
0126     rotAdjusted = yrot * xrot;
0127     eeSCALog.placeVolume(
0128         eeCRLog,
0129         copyNum,
0130         dd4hep::Transform3D(
0131             myrot(ns, rname, rotAdjusted),
0132             dd4hep::Position(crystal.centrePos().x(), crystal.centrePos().y(), crystal.centrePos().z() - cryZOff)));
0133   }
0134 
0135 }  // namespace
0136 
0137 static long algorithm(dd4hep::Detector& /* description */, cms::DDParsingContext& ctxt, xml_h e) {
0138   BenchmarkGrd counter("DDEcalEndcapAlgo");
0139   cms::DDNamespace ns(ctxt, e, true);
0140   cms::DDAlgoArguments args(ctxt, e);
0141 
0142   // TRICK!
0143   std::string myns{mynamespace(args.parentName()).data(), mynamespace(args.parentName()).size()};
0144 
0145   Endcap ee;
0146   ee.mat = args.str("EEMat");
0147   ee.zOff = args.dble("EEzOff");
0148 
0149   ee.quaName = args.str("EEQuaName");
0150   ee.quaMat = args.str("EEQuaMat");
0151   ee.crysMat = args.str("EECrysMat");
0152   ee.wallMat = args.str("EEWallMat");
0153   ee.crysLength = args.dble("EECrysLength");
0154   ee.crysRear = args.dble("EECrysRear");
0155   ee.crysFront = args.dble("EECrysFront");
0156   ee.sCELength = args.dble("EESCELength");
0157   ee.sCERear = args.dble("EESCERear");
0158   ee.sCEFront = args.dble("EESCEFront");
0159   ee.sCALength = args.dble("EESCALength");
0160   ee.sCARear = args.dble("EESCARear");
0161   ee.sCAFront = args.dble("EESCAFront");
0162   ee.sCAWall = args.dble("EESCAWall");
0163   ee.sCHLength = args.dble("EESCHLength");
0164   ee.sCHSide = args.dble("EESCHSide");
0165   ee.nSCTypes = args.dble("EEnSCTypes");
0166   ee.nColumns = args.dble("EEnColumns");
0167   ee.nSCCutaway = args.dble("EEnSCCutaway");
0168   ee.nSCquad = args.dble("EEnSCquad");
0169   ee.nCRSC = args.dble("EEnCRSC");
0170   ee.vecEESCProf = args.vecDble("EESCProf");
0171   ee.vecEEShape = args.vecDble("EEShape");
0172   ee.vecEESCCutaway = args.vecDble("EESCCutaway");
0173   ee.vecEESCCtrs = args.vecDble("EESCCtrs");
0174   ee.vecEECRCtrs = args.vecDble("EECRCtrs");
0175 
0176   ee.cutBoxName = args.str("EECutBoxName");
0177 
0178   ee.envName = args.str("EEEnvName");
0179   ee.alvName = args.str("EEAlvName");
0180   ee.intName = args.str("EEIntName");
0181   ee.cryName = args.str("EECryName");
0182 
0183   ee.pFHalf = args.dble("EEPFHalf");
0184   ee.pFFifth = args.dble("EEPFFifth");
0185   ee.pF45 = args.dble("EEPF45");
0186 
0187   ee.vecEESCLims = args.vecDble("EESCLims");
0188   ee.iLength = args.dble("EEiLength");
0189   ee.iXYOff = args.dble("EEiXYOff");
0190   ee.cryZOff = args.dble("EECryZOff");
0191   ee.zFront = args.dble("EEzFront");
0192 
0193   //  Position supercrystals in EE Quadrant
0194 
0195   //********************************* cutbox for trimming edge SCs
0196   const double cutWid(ee.sCERear / sqrt(2.));
0197   ee.cutParms[0] = cutWid;
0198   ee.cutParms[1] = cutWid;
0199   ee.cutParms[2] = ee.sCELength / sqrt(2.);
0200   dd4hep::Solid eeCutBox = dd4hep::Box(ee.cutBoxName, ee.cutParms[0], ee.cutParms[1], ee.cutParms[2]);
0201   //**************************************************************
0202 
0203   const double zFix(ee.zFront - 3172 * dd4hep::mm);  // fix for changing z offset
0204 
0205   //** fill supercrystal front and rear center positions from xml input
0206   for (unsigned int iC(0); iC != (unsigned int)ee.nSCquad; ++iC) {
0207     const unsigned int iOff(8 * iC);
0208     const unsigned int ix((unsigned int)ee.vecEESCCtrs[iOff + 0]);
0209     const unsigned int iy((unsigned int)ee.vecEESCCtrs[iOff + 1]);
0210 
0211     assert(ix > 0 && ix < 11 && iy > 0 && iy < 11);
0212 
0213     ee.scrFCtr[ix - 1][iy - 1] =
0214         DDTranslation(ee.vecEESCCtrs[iOff + 2], ee.vecEESCCtrs[iOff + 4], ee.vecEESCCtrs[iOff + 6] + zFix);
0215 
0216     ee.scrRCtr[ix - 1][iy - 1] =
0217         DDTranslation(ee.vecEESCCtrs[iOff + 3], ee.vecEESCCtrs[iOff + 5], ee.vecEESCCtrs[iOff + 7] + zFix);
0218   }
0219 
0220   //** fill crystal front and rear center positions from xml input
0221   for (unsigned int iC(0); iC != 25; ++iC) {
0222     const unsigned int iOff(8 * iC);
0223     const unsigned int ix((unsigned int)ee.vecEECRCtrs[iOff + 0]);
0224     const unsigned int iy((unsigned int)ee.vecEECRCtrs[iOff + 1]);
0225 
0226     assert(ix > 0 && ix < 6 && iy > 0 && iy < 6);
0227 
0228     ee.cryFCtr[ix - 1][iy - 1] =
0229         DDTranslation(ee.vecEECRCtrs[iOff + 2], ee.vecEECRCtrs[iOff + 4], ee.vecEECRCtrs[iOff + 6]);
0230 
0231     ee.cryRCtr[ix - 1][iy - 1] =
0232         DDTranslation(ee.vecEECRCtrs[iOff + 3], ee.vecEECRCtrs[iOff + 5], ee.vecEECRCtrs[iOff + 7]);
0233   }
0234 
0235   dd4hep::Solid eeCRSolid = dd4hep::Trap(ee.cryName,
0236                                          0.5 * ee.crysLength,
0237                                          atan((ee.crysRear - ee.crysFront) / (sqrt(2.) * ee.crysLength)),
0238                                          45._deg,
0239                                          0.5 * ee.crysFront,
0240                                          0.5 * ee.crysFront,
0241                                          0.5 * ee.crysFront,
0242                                          0._deg,
0243                                          0.5 * ee.crysRear,
0244                                          0.5 * ee.crysRear,
0245                                          0.5 * ee.crysRear,
0246                                          0._deg);
0247 #ifdef EDM_ML_DEBUG
0248   edm::LogVerbatim("EcalGeom") << eeCRSolid.name() << " Trap with parameters: " << cms::convert2mm(0.5 * ee.crysLength)
0249                                << ":" << (atan((ee.crysRear - ee.crysFront) / (sqrt(2.) * ee.crysLength))) << ":"
0250                                << 45._deg << ":" << cms::convert2mm(0.5 * ee.crysFront) << ":"
0251                                << cms::convert2mm(0.5 * ee.crysFront) << ":" << cms::convert2mm(0.5 * ee.crysFront)
0252                                << ":" << 0._deg << ":" << cms::convert2mm(0.5 * ee.crysRear) << ":"
0253                                << cms::convert2mm(0.5 * ee.crysRear) << ":" << cms::convert2mm(0.5 * ee.crysRear) << ":"
0254                                << 0._deg;
0255 #endif
0256   dd4hep::Volume eeCRLog = dd4hep::Volume(myns + ee.cryName, eeCRSolid, ns.material(ee.crysMat));
0257 
0258   for (unsigned int isc(0); isc < ee.nSCTypes; ++isc) {
0259     unsigned int iSCType = isc + 1;
0260     const std::string anum(std::to_string(iSCType));
0261     const double eFront(0.5 * ee.sCEFront);
0262     const double eRear(0.5 * ee.sCERear);
0263     const double eAng(atan((ee.sCERear - ee.sCEFront) / (sqrt(2.) * ee.sCELength)));
0264     const double ffived(45_deg);
0265     const double zerod(0_deg);
0266     std::string eeSCEnvName(1 == iSCType ? ee.envName + std::to_string(iSCType)
0267                                          : (ee.envName + std::to_string(iSCType) + "Tmp"));
0268     dd4hep::Solid eeSCEnv = ns.addSolidNS(
0269         eeSCEnvName,
0270         dd4hep::Trap(
0271             eeSCEnvName, 0.5 * ee.sCELength, eAng, ffived, eFront, eFront, eFront, zerod, eRear, eRear, eRear, zerod));
0272 #ifdef EDM_ML_DEBUG
0273     edm::LogVerbatim("EcalGeom") << eeSCEnv.name() << " Trap with parameters: " << cms::convert2mm(0.5 * ee.sCELength)
0274                                  << ":" << eAng << ":" << ffived << ":" << cms::convert2mm(eFront) << ":"
0275                                  << cms::convert2mm(eFront) << ":" << cms::convert2mm(eFront) << ":" << zerod << ":"
0276                                  << cms::convert2mm(eRear) << ":" << cms::convert2mm(eRear) << ":"
0277                                  << cms::convert2mm(eRear) << ":" << zerod;
0278 #endif
0279 
0280     const double aFront(0.5 * ee.sCAFront);
0281     const double aRear(0.5 * ee.sCARear);
0282     const double aAng(atan((ee.sCARear - ee.sCAFront) / (sqrt(2.) * ee.sCALength)));
0283     std::string eeSCAlvName(
0284         (1 == iSCType ? ee.alvName + std::to_string(iSCType) : (ee.alvName + std::to_string(iSCType) + "Tmp")));
0285     dd4hep::Solid eeSCAlv = ns.addSolidNS(
0286         eeSCAlvName,
0287         dd4hep::Trap(
0288             eeSCAlvName, 0.5 * ee.sCALength, aAng, ffived, aFront, aFront, aFront, zerod, aRear, aRear, aRear, zerod));
0289 #ifdef EDM_ML_DEBUG
0290     edm::LogVerbatim("EcalGeom") << eeSCAlv.name() << " Trap with parameters: " << cms::convert2mm(0.5 * ee.sCALength)
0291                                  << ":" << aAng << ":" << ffived << ":" << cms::convert2mm(aFront) << ":"
0292                                  << cms::convert2mm(aFront) << ":" << cms::convert2mm(aFront) << ":" << zerod << ":"
0293                                  << cms::convert2mm(aRear) << ":" << cms::convert2mm(aRear) << ":"
0294                                  << cms::convert2mm(aRear) << ":" << zerod;
0295 #endif
0296 
0297     const double dwall(ee.sCAWall);
0298     const double iFront(aFront - dwall);
0299     const double iRear(iFront);
0300     const double iLen(ee.iLength);
0301     std::string eeSCIntName(1 == iSCType ? ee.intName + std::to_string(iSCType)
0302                                          : (ee.intName + std::to_string(iSCType) + "Tmp"));
0303     dd4hep::Solid eeSCInt = ns.addSolidNS(eeSCIntName,
0304                                           dd4hep::Trap(eeSCIntName,
0305                                                        iLen / 2.,
0306                                                        atan((ee.sCARear - ee.sCAFront) / (sqrt(2.) * ee.sCALength)),
0307                                                        ffived,
0308                                                        iFront,
0309                                                        iFront,
0310                                                        iFront,
0311                                                        zerod,
0312                                                        iRear,
0313                                                        iRear,
0314                                                        iRear,
0315                                                        zerod));
0316 #ifdef EDM_ML_DEBUG
0317     edm::LogVerbatim("EcalGeom") << eeSCAlv.name() << " Trap with parameters: " << cms::convert2mm(iLen / 2.) << ":"
0318                                  << (atan((ee.sCARear - ee.sCAFront) / (sqrt(2.) * ee.sCALength))) << ":" << ffived
0319                                  << ":" << cms::convert2mm(iFront) << ":" << cms::convert2mm(iFront) << ":"
0320                                  << cms::convert2mm(iFront) << ":" << zerod << ":" << cms::convert2mm(iRear) << ":"
0321                                  << cms::convert2mm(iRear) << ":" << cms::convert2mm(iRear) << ":" << zerod;
0322 #endif
0323 
0324     const double dz(-0.5 * (ee.sCELength - ee.sCALength));
0325     const double dxy(0.5 * dz * (ee.sCERear - ee.sCEFront) / ee.sCELength);
0326     const double zIOff(-(ee.sCALength - iLen) / 2.);
0327     const double xyIOff(ee.iXYOff);
0328 
0329     dd4hep::Volume eeSCELog;
0330     dd4hep::Volume eeSCALog;
0331     dd4hep::Volume eeSCILog;
0332 
0333     if (1 == iSCType) {  // standard SC in this block
0334       eeSCELog =
0335           ns.addVolumeNS(dd4hep::Volume(myns + ee.envName + std::to_string(iSCType), eeSCEnv, ns.material(ee.mat)));
0336       eeSCALog = dd4hep::Volume(myns + ee.alvName + std::to_string(iSCType), eeSCAlv, ns.material(ee.wallMat));
0337       eeSCILog = dd4hep::Volume(myns + ee.intName + std::to_string(iSCType), eeSCInt, ns.material(ee.mat));
0338     } else {  // partial SCs this block: create subtraction volumes as appropriate
0339       const double half(ee.cutParms[0] - ee.pFHalf * ee.crysRear);
0340       const double fifth(ee.cutParms[0] + ee.pFFifth * ee.crysRear);
0341       const double fac(ee.pF45);
0342 
0343       const double zmm(0 * dd4hep::mm);
0344 
0345       DDTranslation cutTra(
0346           2 == iSCType ? DDTranslation(zmm, half, zmm)
0347                        : (3 == iSCType ? DDTranslation(half, zmm, zmm)
0348                                        : (4 == iSCType ? DDTranslation(zmm, -fifth, zmm)
0349                                                        : (5 == iSCType ? DDTranslation(-half * fac, -half * fac, zmm)
0350                                                                        : DDTranslation(-fifth, zmm, zmm)))));
0351 
0352       const CLHEP::HepRotationZ cutm(ffived);
0353 
0354       DDRotationMatrix cutRot(5 != iSCType ? DDRotationMatrix()
0355                                            : myrot(ns,
0356                                                    "EECry5Rot",
0357                                                    DDRotationMatrix(cutm.xx(),
0358                                                                     cutm.xy(),
0359                                                                     cutm.xz(),
0360                                                                     cutm.yx(),
0361                                                                     cutm.yy(),
0362                                                                     cutm.yz(),
0363                                                                     cutm.zx(),
0364                                                                     cutm.zy(),
0365                                                                     cutm.zz())));
0366 
0367       dd4hep::Solid eeCutEnv = dd4hep::SubtractionSolid(ee.envName + std::to_string(iSCType),
0368                                                         ns.solid(ee.envName + std::to_string(iSCType) + "Tmp"),
0369                                                         eeCutBox,
0370                                                         dd4hep::Transform3D(cutRot, cutTra));
0371 #ifdef EDM_ML_DEBUG
0372       edm::LogVerbatim("EcalGeom") << eeCutEnv.name() << " Subtracted by " << cms::convert2mm(ee.cutParms[0]) << ":"
0373                                    << cms::convert2mm(ee.cutParms[1]) << ":" << cms::convert2mm(ee.cutParms[2]);
0374 #endif
0375 
0376       const DDTranslation extra(dxy, dxy, dz);
0377 
0378       dd4hep::Solid eeCutAlv = dd4hep::SubtractionSolid(ee.alvName + std::to_string(iSCType),
0379                                                         ns.solid(ee.alvName + std::to_string(iSCType) + "Tmp"),
0380                                                         eeCutBox,
0381                                                         dd4hep::Transform3D(cutRot, cutTra - extra));
0382 #ifdef EDM_ML_DEBUG
0383       edm::LogVerbatim("EcalGeom") << eeCutAlv.name() << " Subtracted by " << cms::convert2mm(ee.cutParms[0]) << ":"
0384                                    << cms::convert2mm(ee.cutParms[1]) << ":" << cms::convert2mm(ee.cutParms[2]);
0385 #endif
0386 
0387       const double mySign(iSCType < 4 ? +1. : -1.);
0388 
0389       const DDTranslation extraI(xyIOff + mySign * 2 * dd4hep::mm, xyIOff + mySign * 2 * dd4hep::mm, zIOff);
0390 
0391       dd4hep::Solid eeCutInt = dd4hep::SubtractionSolid(ee.intName + std::to_string(iSCType),
0392                                                         ns.solid(ee.intName + std::to_string(iSCType) + "Tmp"),
0393                                                         eeCutBox,
0394                                                         dd4hep::Transform3D(cutRot, cutTra - extraI));
0395 #ifdef EDM_ML_DEBUG
0396       edm::LogVerbatim("EcalGeom") << eeCutInt.name() << " Subtracted by " << cms::convert2mm(ee.cutParms[0]) << ":"
0397                                    << cms::convert2mm(ee.cutParms[1]) << ":" << cms::convert2mm(ee.cutParms[2]);
0398 #endif
0399 
0400       eeSCELog =
0401           ns.addVolumeNS(dd4hep::Volume(myns + ee.envName + std::to_string(iSCType), eeCutEnv, ns.material(ee.mat)));
0402       eeSCALog = dd4hep::Volume(myns + ee.alvName + std::to_string(iSCType), eeCutAlv, ns.material(ee.wallMat));
0403       eeSCILog = dd4hep::Volume(myns + ee.intName + std::to_string(iSCType), eeCutInt, ns.material(ee.mat));
0404     }
0405     eeSCELog.placeVolume(eeSCALog, iSCType * 100 + 1, dd4hep::Position(dxy, dxy, dz));
0406     eeSCALog.placeVolume(eeSCILog, iSCType * 100 + 1, dd4hep::Position(xyIOff, xyIOff, zIOff));
0407 #ifdef EDM_ML_DEBUG
0408     edm::LogVerbatim("EEGeom") << eeSCALog.name() << " " << (iSCType * 100 + 1) << " in " << eeSCELog.name();
0409     edm::LogVerbatim("EEGeom") << eeSCILog.name() << " " << (iSCType * 100 + 1) << " in " << eeSCALog.name();
0410     edm::LogVerbatim("EcalGeom") << eeSCALog.name() << " " << (iSCType * 100 + 1) << " in " << eeSCELog.name()
0411                                  << " at (" << cms::convert2mm(dxy) << ", " << cms::convert2mm(dxy) << ", "
0412                                  << cms::convert2mm(dz) << ")";
0413     edm::LogVerbatim("EcalGeom") << eeSCILog.name() << " " << (iSCType * 100 + 1) << " in " << eeSCALog.name()
0414                                  << " at (" << cms::convert2mm(xyIOff) << ", " << cms::convert2mm(xyIOff) << ", "
0415                                  << cms::convert2mm(zIOff) << ")";
0416 #endif
0417     DDTranslation croffset(0., 0., 0.);
0418 
0419     // Position crystals within parent supercrystal interior volume
0420     static const unsigned int ncol(5);
0421 
0422     if (iSCType > 0 && iSCType <= ee.nSCTypes) {
0423       const unsigned int icoffset((iSCType - 1) * ncol - 1);
0424 
0425       // Loop over columns of SC
0426       for (unsigned int icol(1); icol <= ncol; ++icol) {
0427         // Get column limits for this SC type from xml input
0428         const int ncrcol((int)ee.vecEESCProf[icoffset + icol]);
0429 
0430         const int imin(0 < ncrcol ? 1 : (0 > ncrcol ? ncol + ncrcol + 1 : 0));
0431         const int imax(0 < ncrcol ? ncrcol : (0 > ncrcol ? ncol : 0));
0432 
0433         if (imax > 0) {
0434           // Loop over crystals in this row
0435           for (int irow(imin); irow <= imax; ++irow) {
0436             // Create crystal as a DDEcalEndcapTrapX object and calculate rotation and
0437             // translation required to position it in the SC.
0438             DDEcalEndcapTrapX crystal(1, ee.crysFront, ee.crysRear, ee.crysLength);
0439 
0440             crystal.moveto(ee.cryFCtr[icol - 1][irow - 1], ee.cryRCtr[icol - 1][irow - 1]);
0441 
0442             std::string rname("EECrRoC" + std::to_string(icol) + "R" + std::to_string(irow));
0443 
0444             if (rname == "EECrRoC1R1") {
0445               // The "EECrRoC1R1" rotation is too small and would be ignored by ROOT. It needs to be
0446               // increased by 1% to take effect. See placeEFRYn00 for more details.
0447 
0448               placeEFRYn00(
0449                   eeSCALog, eeCRLog, 100 * iSCType + 10 * (icol - 1) + (irow - 1), ns, rname, crystal, ee.cryZOff);
0450             } else
0451               eeSCALog.placeVolume(eeCRLog,
0452                                    100 * iSCType + 10 * (icol - 1) + (irow - 1),
0453                                    dd4hep::Transform3D(myrot(ns, rname, crystal.rotation()),
0454                                                        dd4hep::Position(crystal.centrePos().x(),
0455                                                                         crystal.centrePos().y(),
0456                                                                         crystal.centrePos().z() - ee.cryZOff)));
0457 #ifdef EDM_ML_DEBUG
0458             edm::LogVerbatim("EEGeom") << eeCRLog.name() << " " << (100 * iSCType + 10 * (icol - 1) + (irow - 1))
0459                                        << " in " << eeSCALog.name();
0460             edm::LogVerbatim("EcalGeom") << eeCRLog.name() << " " << (100 * iSCType + 10 * (icol - 1) + (irow - 1))
0461                                          << " in " << eeSCALog.name() << " at ("
0462                                          << cms::convert2mm(crystal.centrePos().x()) << ", "
0463                                          << cms::convert2mm(crystal.centrePos().y()) << ", "
0464                                          << cms::convert2mm((crystal.centrePos().z() - ee.cryZOff)) << ")";
0465 #endif
0466           }
0467         }
0468       }
0469     }
0470   }
0471 
0472   //** Loop over endcap columns
0473   for (int icol = 1; icol <= int(ee.nColumns); icol++) {
0474     //**  Loop over SCs in column, using limits from xml input
0475     for (int irow = int(ee.vecEEShape[2 * icol - 2]); irow <= int(ee.vecEEShape[2 * icol - 1]); ++irow) {
0476       if (ee.vecEESCLims[0] <= icol && ee.vecEESCLims[1] >= icol && ee.vecEESCLims[2] <= irow &&
0477           ee.vecEESCLims[3] >= irow) {
0478         // Find SC type (complete or partial) for this location
0479         unsigned int isctype = 1;
0480 
0481         for (unsigned int ii = 0; ii < (unsigned int)(ee.nSCCutaway); ++ii) {
0482           if ((ee.vecEESCCutaway[3 * ii] == icol) && (ee.vecEESCCutaway[3 * ii + 1] == irow)) {
0483             isctype = int(ee.vecEESCCutaway[3 * ii + 2]);
0484           }
0485         }
0486 
0487         // Create SC as a DDEcalEndcapTrapX object and calculate rotation and
0488         // translation required to position it in the endcap.
0489         DDEcalEndcapTrapX scrys(1, ee.sCEFront, ee.sCERear, ee.sCELength);
0490         scrys.moveto(ee.scrFCtr[icol - 1][irow - 1], ee.scrRCtr[icol - 1][irow - 1]);
0491         scrys.translate(DDTranslation(0., 0., -ee.zOff));
0492 
0493         std::string rname(ee.envName + std::to_string(isctype) + std::to_string(icol) + "R" + std::to_string(irow));
0494         // Position SC in endcap
0495         dd4hep::Volume quaLog = ns.volume(ee.quaName);
0496         dd4hep::Volume childEnvLog = ns.volume(myns + ee.envName + std::to_string(isctype));
0497         quaLog.placeVolume(childEnvLog,
0498                            100 * isctype + 10 * (icol - 1) + (irow - 1),
0499                            dd4hep::Transform3D(scrys.rotation(), scrys.centrePos()));
0500 #ifdef EDM_ML_DEBUG
0501         edm::LogVerbatim("EEGeom") << childEnvLog.name() << " " << (100 * isctype + 10 * (icol - 1) + (irow - 1))
0502                                    << " in " << quaLog.name();
0503         edm::LogVerbatim("EcalGeom") << childEnvLog.name() << " " << (100 * isctype + 10 * (icol - 1) + (irow - 1))
0504                                      << " in " << quaLog.name() << " at (" << cms::convert2mm(scrys.centrePos().x())
0505                                      << ", " << cms::convert2mm(scrys.centrePos().y()) << ", "
0506                                      << cms::convert2mm(scrys.centrePos().z()) << ")";
0507 #endif
0508       }
0509     }
0510   }
0511 
0512   return 1;
0513 }
0514 
0515 DECLARE_DDCMS_DETELEMENT(DDCMS_ecal_DDEcalEndcapAlgo, algorithm)