Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 09:29:45

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2022 John Lajoie
0003 
0004 //==========================================================================
0005 //  AIDA Detector description implementation
0006 //--------------------------------------------------------------------------
0007 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0008 // All rights reserved.
0009 //
0010 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0011 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0012 //
0013 // Author     : M.Frank
0014 //
0015 //==========================================================================
0016 //
0017 // Specialized generic detector constructor
0018 //
0019 //==========================================================================
0020 #include "DD4hep/DetFactoryHelper.h"
0021 #include "DD4hep/Printout.h"
0022 #include "XML/Layering.h"
0023 
0024 #include "TVector3.h"
0025 #include "TGDMLParse.h"
0026 #include "FileLoaderHelper.h"
0027 
0028 using namespace std;
0029 using namespace dd4hep;
0030 using namespace dd4hep::detail;
0031 
0032 static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) {
0033 
0034   // printout(WARNING, "BarrelHCalCalorimeter", "called create_detector ");
0035 
0036   xml_det_t x_det = e;
0037   int det_id      = x_det.id();
0038   string det_name = x_det.nameStr();
0039   Material air    = description.air();
0040 
0041   DetElement sdet(det_name, det_id);
0042   Volume motherVol = description.pickMotherVolume(sdet);
0043 
0044   // Create envelope to hold HCAL barrel
0045 
0046   double rmin1   = x_det.rmin1();
0047   double rmin2   = x_det.rmin2();
0048   double rmax    = x_det.rmax();
0049   double length1 = x_det.z1();
0050   double length2 = x_det.z2();
0051 
0052   // 5mm buffer on inner radius to acount for comb angle/tilt
0053   // (allows the combs to be added in later)
0054   std::vector<double> rmins = {rmin2 - 0.5 * cm, rmin2 - 0.5 * cm, rmin1 - 1.5 * cm,
0055                                rmin1 - 1.5 * cm, rmin2 - 0.5 * cm, rmin2 - 0.5 * cm};
0056   // 1cm buffer on outer radius to acount for comb angle/tilt
0057   // (allows the combs to be added in later)
0058   std::vector<double> rmaxs = {rmax + 1.0 * cm, rmax + 1.0 * cm, rmax + 1.0 * cm,
0059                                rmax + 1.0 * cm, rmax + 1.0 * cm, rmax + 1.0 * cm};
0060   // leave room for dogbones at the ends (not part of det table)
0061   std::vector<double> zs = {
0062       -length2 / 2. - 8.2 * cm, -length1 / 2., -length1 / 2., length1 / 2., length1 / 2.,
0063       length2 / 2. + 8.2 * cm};
0064 
0065   // printout(WARNING, "BarrelHCalCalorimeter", "%f %f %f %f %f", rmin1, rmin2, rmax, length1/2., length2/2.);
0066 
0067   Polycone ptube(0.0, 2.0 * M_PI, rmins, rmaxs, zs);
0068   Volume envelope(det_name, ptube, air);
0069 
0070   PlacedVolume env_phv = motherVol.placeVolume(envelope);
0071   env_phv.addPhysVolID("system", det_id);
0072   sdet.setPlacement(env_phv);
0073 
0074   xml_comp_t det_define = x_det.child("define");
0075 
0076   // Pick up the constants
0077 
0078   double tilePlaneRotate = 0.0;
0079   double tile_tolerance  = 0.2; // Tile tolerance in mm to avoid overlaps
0080 
0081   // Sector steel tessellated shape gdml file info
0082   xml_comp_t x_det_sec_gdmlfile = x_det.child("sec_gdmlfile");
0083   std::string sec_gdml_file =
0084       getAttrOrDefault<std::string>(x_det_sec_gdmlfile, _Unicode(file), " ");
0085   ;
0086   std::string sec_gdml_material =
0087       getAttrOrDefault<std::string>(x_det_sec_gdmlfile, _Unicode(material), " ");
0088   std::string sec_gdml_url = getAttrOrDefault<std::string>(x_det_sec_gdmlfile, _Unicode(url), " ");
0089   std::string sec_gdml_cache =
0090       getAttrOrDefault<std::string>(x_det_sec_gdmlfile, _Unicode(cache), " ");
0091 
0092   xml_comp_t x_det_csec_gdmlfile = x_det.child("csec_gdmlfile");
0093   std::string csec_gdml_file =
0094       getAttrOrDefault<std::string>(x_det_csec_gdmlfile, _Unicode(file), " ");
0095   ;
0096   std::string csec_gdml_material =
0097       getAttrOrDefault<std::string>(x_det_csec_gdmlfile, _Unicode(material), " ");
0098   std::string csec_gdml_url =
0099       getAttrOrDefault<std::string>(x_det_csec_gdmlfile, _Unicode(url), " ");
0100   std::string csec_gdml_cache =
0101       getAttrOrDefault<std::string>(x_det_csec_gdmlfile, _Unicode(cache), " ");
0102 
0103   xml_comp_t x_det_er_gdmlfile = x_det.child("er_gdmlfile");
0104   std::string er_gdml_file = getAttrOrDefault<std::string>(x_det_er_gdmlfile, _Unicode(file), " ");
0105   ;
0106   std::string er_gdml_material =
0107       getAttrOrDefault<std::string>(x_det_er_gdmlfile, _Unicode(material), " ");
0108   std::string er_gdml_url = getAttrOrDefault<std::string>(x_det_er_gdmlfile, _Unicode(url), " ");
0109   std::string er_gdml_cache =
0110       getAttrOrDefault<std::string>(x_det_er_gdmlfile, _Unicode(cache), " ");
0111 
0112   // Loop over the defines section and pick up the tile offsets, ref location and angles
0113 
0114   for (xml_coll_t i(det_define, _Unicode(constant)); i; ++i) {
0115     xml_comp_t x_const = i;
0116 
0117     std::string const_name = getAttrOrDefault<std::string>(x_const, _Unicode(name), " ");
0118 
0119     if (const_name == "tilePlaneRotate") {
0120       std::string const_value = getAttrOrDefault<std::string>(x_const, _Unicode(value), " ");
0121       tilePlaneRotate         = atof(const_value.c_str());
0122     } else
0123       printout(WARNING, "BarrelHCalCalorimeter", "unrecognized <constant> data!");
0124   }
0125 
0126   std::vector<double> xposOuter;
0127   std::vector<double> yposOuter;
0128 
0129   std::vector<double> xposTile;
0130   std::vector<double> yposTile;
0131   std::vector<double> zposTile;
0132 
0133   std::vector<double> xposChimneyTileS;
0134   std::vector<double> yposChimneyTileS;
0135   std::vector<double> zposChimneyTileS;
0136 
0137   for (xml_coll_t i(det_define, _Unicode(matrix)); i; ++i) {
0138     xml_comp_t x_mtrx = i;
0139 
0140     std::string mtrx_name   = getAttrOrDefault<std::string>(x_mtrx, _Unicode(name), " ");
0141     std::string mtrx_values = getAttrOrDefault<std::string>(x_mtrx, _Unicode(values), " ");
0142 
0143     std::vector<double>* aptr = NULL;
0144 
0145     if (mtrx_name == "xposOuter")
0146       aptr = &xposOuter;
0147     else if (mtrx_name == "yposOuter")
0148       aptr = &yposOuter;
0149     else if (mtrx_name == "xposTile")
0150       aptr = &xposTile;
0151     else if (mtrx_name == "yposTile")
0152       aptr = &yposTile;
0153     else if (mtrx_name == "zposTile")
0154       aptr = &zposTile;
0155     else if (mtrx_name == "xposChimneyTileS")
0156       aptr = &xposChimneyTileS;
0157     else if (mtrx_name == "yposChimneyTileS")
0158       aptr = &yposChimneyTileS;
0159     else if (mtrx_name == "zposChimneyTileS")
0160       aptr = &zposChimneyTileS;
0161     else {
0162       printout(WARNING, "BarrelHCalCalorimeter", "unknown <matrix> data!");
0163       continue;
0164     }
0165 
0166     std::string delimiter = " ";
0167     size_t pos            = 0;
0168     std::string token;
0169     while ((pos = mtrx_values.find(delimiter)) != std::string::npos) {
0170       token = mtrx_values.substr(0, pos);
0171       aptr->push_back(atof(token.c_str()));
0172       mtrx_values.erase(0, pos + delimiter.length());
0173     }
0174     aptr->push_back(atof(mtrx_values.c_str()));
0175   }
0176 
0177   // Read in the barrel structure GDML file
0178   // three structures - normal sector, chimney sector, and end rings
0179   Assembly BarrelHCAL("BarrelHCAL");
0180   TGDMLParse parser;
0181 
0182   // sector
0183   EnsureFileFromURLExists(sec_gdml_url, sec_gdml_file, sec_gdml_cache);
0184   if (!fs::exists(fs::path(sec_gdml_file))) {
0185     printout(ERROR, "BarrelHCalCalorimeter_geo", "file " + sec_gdml_file + " does not exist");
0186     printout(ERROR, "BarrelHCalCalorimeter_geo",
0187              "use a FileLoader plugin before the field element");
0188     std::_Exit(EXIT_FAILURE);
0189   }
0190 
0191   Volume barrel_sector_vol = parser.GDMLReadFile(sec_gdml_file.c_str());
0192   if (!barrel_sector_vol.isValid()) {
0193     printout(WARNING, "BarrelHCalCalorimeter", "%s", sec_gdml_file.c_str());
0194     printout(WARNING, "BarrelHCalCalorimeter", "barrel_sector_vol invalid, GDML parser failed!");
0195     std::_Exit(EXIT_FAILURE);
0196   }
0197   barrel_sector_vol.import();
0198   barrel_sector_vol.setVisAttributes(description, x_det.visStr());
0199   TessellatedSolid barrel_sector_solid = barrel_sector_vol.solid();
0200   barrel_sector_solid->CloseShape(true, true, true); // tesselated solid not closed by import!
0201   Material sector_material = description.material(sec_gdml_material.c_str());
0202   barrel_sector_vol.setMaterial(sector_material);
0203 
0204   // chimney sector
0205   EnsureFileFromURLExists(csec_gdml_url, csec_gdml_file, csec_gdml_cache);
0206   if (!fs::exists(fs::path(csec_gdml_file))) {
0207     printout(ERROR, "BarrelHCalCalorimeter_geo", "file " + csec_gdml_file + " does not exist");
0208     printout(ERROR, "BarrelHCalCalorimeter_geo",
0209              "use a FileLoader plugin before the field element");
0210     std::_Exit(EXIT_FAILURE);
0211   }
0212 
0213   Volume barrel_csector_vol = parser.GDMLReadFile(csec_gdml_file.c_str());
0214   if (!barrel_csector_vol.isValid()) {
0215     printout(WARNING, "BarrelHCalCalorimeter", "%s", csec_gdml_file.c_str());
0216     printout(WARNING, "BarrelHCalCalorimeter", "barrel_csector_vol invalid, GDML parser failed!");
0217     std::_Exit(EXIT_FAILURE);
0218   }
0219   barrel_csector_vol.import();
0220   barrel_csector_vol.setVisAttributes(description, x_det.visStr());
0221   TessellatedSolid barrel_csector_solid = barrel_csector_vol.solid();
0222   barrel_csector_solid->CloseShape(true, true, true); // tesselated solid not closed by import!
0223   Material csector_material = description.material(csec_gdml_material.c_str());
0224   barrel_csector_vol.setMaterial(csector_material);
0225 
0226   // end ring
0227   EnsureFileFromURLExists(er_gdml_url, er_gdml_file, er_gdml_cache);
0228   if (!fs::exists(fs::path(er_gdml_file))) {
0229     printout(ERROR, "BarrelHCalCalorimeter_geo", "file " + er_gdml_file + " does not exist");
0230     printout(ERROR, "BarrelHCalCalorimeter_geo",
0231              "use a FileLoader plugin before the field element");
0232     std::_Exit(EXIT_FAILURE);
0233   }
0234 
0235   Volume barrel_er_vol = parser.GDMLReadFile(er_gdml_file.c_str());
0236   if (!barrel_er_vol.isValid()) {
0237     printout(WARNING, "BarrelHCalCalorimeter", "%s", er_gdml_file.c_str());
0238     printout(WARNING, "BarrelHCalCalorimeter", "barrel_er_vol invalid, GDML parser failed!");
0239     std::_Exit(EXIT_FAILURE);
0240   }
0241   barrel_er_vol.import();
0242   barrel_er_vol.setVisAttributes(description, x_det.visStr());
0243   TessellatedSolid barrel_er_solid = barrel_er_vol.solid();
0244   barrel_er_solid->CloseShape(true, true, true); // tesselated solid not closed by import!
0245   Material er_material = description.material(er_gdml_material.c_str());
0246   barrel_er_vol.setMaterial(er_material);
0247 
0248   // Place steel in envelope
0249 
0250   double sec_rot_angle = 360.0 / 32.0;
0251 
0252   for (int k = 0; k < 29; k++) {
0253     BarrelHCAL.placeVolume(
0254         barrel_sector_vol, k,
0255         Transform3D(RotationZ(-k * sec_rot_angle * dd4hep::deg) * RotationY(180.0 * dd4hep::deg),
0256                     Translation3D(0, 0, 0)));
0257   }
0258 
0259   BarrelHCAL.placeVolume(
0260       barrel_csector_vol, 0,
0261       Transform3D(RotationZ(sec_rot_angle * dd4hep::deg) * RotationY(180.0 * dd4hep::deg),
0262                   Translation3D(0, 0, 0)));
0263 
0264   BarrelHCAL.placeVolume(barrel_csector_vol, 1,
0265                          Transform3D(RotationY(180.0 * dd4hep::deg), Translation3D(0, 0, 0)));
0266 
0267   BarrelHCAL.placeVolume(
0268       barrel_csector_vol, 2,
0269       Transform3D(RotationZ(-sec_rot_angle * dd4hep::deg) * RotationY(180.0 * dd4hep::deg),
0270                   Translation3D(0, 0, 0)));
0271 
0272   BarrelHCAL.placeVolume(barrel_er_vol, 0,
0273                          Transform3D(RotationY(180.0 * dd4hep::deg), Translation3D(0, 0, 0)));
0274 
0275   BarrelHCAL.placeVolume(barrel_er_vol, 1,
0276                          Transform3D(RotationY(0.0 * dd4hep::deg), Translation3D(0, 0, 0)));
0277 
0278   // Loop over the tile solids, create them and add them to the detector volume
0279 
0280   Volume Tile[12];
0281   Volume ChimneyTile[4];
0282 
0283   for (int j = 1; j < 17; j++) {
0284 
0285     std::string gdmlname;
0286     std::string solid_name;
0287 
0288     if (j < 13) {
0289 
0290       // standard tiles
0291 
0292       gdmlname   = _toString(j, "tile%d_gdmlfile");
0293       solid_name = _toString(j, "OuterHCalTile%02d");
0294 
0295     } else {
0296 
0297       // chimney tiles
0298 
0299       gdmlname   = _toString(j - 4, "ctile%d_gdmlfile");
0300       solid_name = _toString(j - 4, "OuterHCalChimneyTile%02d");
0301     }
0302 
0303     // tile shape gdml file info
0304     xml_comp_t x_det_tgdmlfile = x_det.child(gdmlname);
0305 
0306     std::string tgdml_file = getAttrOrDefault<std::string>(x_det_tgdmlfile, _Unicode(file), " ");
0307     ;
0308     std::string tgdml_material =
0309         getAttrOrDefault<std::string>(x_det_tgdmlfile, _Unicode(material), " ");
0310     std::string tgdml_url   = getAttrOrDefault<std::string>(x_det_tgdmlfile, _Unicode(url), " ");
0311     std::string tgdml_cache = getAttrOrDefault<std::string>(x_det_tgdmlfile, _Unicode(cache), " ");
0312 
0313     EnsureFileFromURLExists(tgdml_url, tgdml_file, tgdml_cache);
0314     if (!fs::exists(fs::path(tgdml_file))) {
0315       printout(ERROR, "BarrelHCalCalorimeter_geo", "file " + tgdml_file + " does not exist");
0316       printout(ERROR, "BarrelHCalCalorimeter_geo",
0317                "use a FileLoader plugin before the field element");
0318       std::_Exit(EXIT_FAILURE);
0319     }
0320 
0321     Volume solidVolume = parser.GDMLReadFile(tgdml_file.c_str());
0322     if (!solidVolume.isValid()) {
0323       printout(WARNING, "BarrelHCalCalorimeter_geo", "%s", tgdml_file.c_str());
0324       printout(WARNING, "BarrelHCalCalorimeter_geo", "solidVolume invalid, GDML parser failed!");
0325       std::_Exit(EXIT_FAILURE);
0326     }
0327     solidVolume.import();
0328     solidVolume.setVisAttributes(description, x_det.visStr());
0329     TessellatedSolid volume_solid = solidVolume.solid();
0330     volume_solid->CloseShape(true, true, true); // tesselated solid not closed by import!
0331     Material tile_material = description.material(tgdml_material.c_str());
0332     solidVolume.setMaterial(tile_material);
0333 
0334     solidVolume.setSensitiveDetector(sens);
0335 
0336     // For tiles we build an assembly to get the full array of tiles
0337     // Offsets and rotation are to properly orient the tiles in the assembly.
0338 
0339     if (solid_name.size() > 0) {
0340 
0341       std::string type = solid_name.substr(0, solid_name.size() - 2);
0342 
0343       if (type == "OuterHCalTile" || type == "OuterHCalChimneyTile") {
0344 
0345         std::string stnum = solid_name.substr(solid_name.size() - 2, solid_name.size());
0346         int tnum          = atoi(stnum.c_str()) - 1;
0347 
0348         // Tile numbers are indexed by the center (eta=0) out, we want them starting zero at one end.
0349 
0350         if (type == "OuterHCalTile") {
0351 
0352           Tile[11 - tnum] = solidVolume;
0353 
0354         } else if ((tnum > 7) && (type == "OuterHCalChimneyTile")) {
0355 
0356           ChimneyTile[11 - tnum] = solidVolume;
0357         }
0358 
0359       } else
0360         printout(WARNING, "BarrelHCalCalorimeter", "invalid solid_name, not a tile type?");
0361 
0362     } else
0363       printout(WARNING, "BarrelHCalCalorimeter", "solid_name.size() invalid! ");
0364   }
0365 
0366   // Place the tiles into the calorimeter volume
0367 
0368   double increment_angle  = (360.0 / 320.0) * dd4hep::deg;
0369   double increment_offset = -10.01 * increment_angle;
0370 
0371   DetElement tile_det("eta0 phi0", det_id);
0372   sens.setType("calorimeter");
0373 
0374   for (int i_eta = 0; i_eta < 12; i_eta++) { // eta ring
0375 
0376     int tnum = 11 - i_eta;
0377 
0378     for (int i_phi = 0; i_phi < 320; i_phi++) { // phi index
0379 
0380       if (i_eta > 3) {
0381 
0382         // ordinary sector tiles
0383 
0384         PlacedVolume phv1 = BarrelHCAL.placeVolume(
0385             Tile[i_eta], i_phi + i_eta * 320,
0386             RotationZ(i_phi * increment_angle + increment_offset) *
0387                 Transform3D(
0388                     RotationY(90.0 * dd4hep::deg),
0389                     Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0390                 RotationX(-tilePlaneRotate * dd4hep::deg) *
0391                 Transform3D(
0392                     RotationY(180.0 * dd4hep::deg),
0393                     Translation3D(-(xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0394                                   yposTile[tnum] * dd4hep::mm, -zposTile[tnum] * dd4hep::mm)));
0395 
0396         phv1.addPhysVolID("eta", i_eta).addPhysVolID("phi", i_phi);
0397         DetElement sd1 = tile_det.clone(_toString(i_eta, "eta%d ") + _toString(i_phi, "phi%d"));
0398         sd1.setPlacement(phv1);
0399         sdet.add(sd1);
0400 
0401         PlacedVolume phv0 = BarrelHCAL.placeVolume(
0402             Tile[i_eta], i_phi + (12 + tnum) * 320,
0403             RotationZ(i_phi * increment_angle + increment_offset) *
0404                 Transform3D(
0405                     RotationY(90.0 * dd4hep::deg),
0406                     Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0407                 RotationX(-tilePlaneRotate * dd4hep::deg) *
0408                 Translation3D((xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0409                               yposTile[tnum] * dd4hep::mm, zposTile[tnum] * dd4hep::mm));
0410 
0411         phv0.addPhysVolID("eta", (12 + tnum)).addPhysVolID("phi", i_phi);
0412         DetElement sd0 =
0413             tile_det.clone(_toString((12 + tnum), "eta%d ") + _toString(i_phi, "phi%d"));
0414         sd0.setPlacement(phv0);
0415         sdet.add(sd0);
0416 
0417       } else {
0418 
0419         // first three sectors are chimney sectors
0420 
0421         if (i_phi > 29) {
0422 
0423           // ordinary sector tiles
0424 
0425           PlacedVolume phv1 = BarrelHCAL.placeVolume(
0426               Tile[i_eta], i_phi + i_eta * 320,
0427               RotationZ(i_phi * increment_angle + increment_offset) *
0428                   Transform3D(
0429                       RotationY(90.0 * dd4hep::deg),
0430                       Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0431                   RotationX(-tilePlaneRotate * dd4hep::deg) *
0432                   Translation3D(-(xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0433                                 yposTile[tnum] * dd4hep::mm, -zposTile[tnum] * dd4hep::mm));
0434 
0435           phv1.addPhysVolID("eta", i_eta).addPhysVolID("phi", i_phi);
0436           DetElement sd1 = tile_det.clone(_toString(i_eta, "eta%d ") + _toString(i_phi, "phi%d"));
0437           sd1.setPlacement(phv1);
0438           sdet.add(sd1);
0439 
0440           PlacedVolume phv0 = BarrelHCAL.placeVolume(
0441               Tile[i_eta], i_phi + (12 + tnum) * 320,
0442               RotationZ(i_phi * increment_angle + increment_offset) *
0443                   Transform3D(
0444                       RotationY(90.0 * dd4hep::deg),
0445                       Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0446                   RotationX(-tilePlaneRotate * dd4hep::deg) *
0447                   Transform3D(
0448                       RotationY(180.0 * dd4hep::deg),
0449                       Translation3D((xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0450                                     yposTile[tnum] * dd4hep::mm, zposTile[tnum] * dd4hep::mm)));
0451 
0452           phv0.addPhysVolID("eta", (12 + tnum)).addPhysVolID("phi", i_phi);
0453           DetElement sd0 =
0454               tile_det.clone(_toString((12 + tnum), "eta%d ") + _toString(i_phi, "phi%d"));
0455           sd0.setPlacement(phv0);
0456           sdet.add(sd0);
0457 
0458         } else {
0459 
0460           // chimney sector tile
0461 
0462           PlacedVolume phv1 = BarrelHCAL.placeVolume(
0463               ChimneyTile[i_eta], i_phi + (12 + tnum) * 320,
0464               RotationZ(i_phi * increment_angle + increment_offset) *
0465                   Transform3D(
0466                       RotationY(90.0 * dd4hep::deg),
0467                       Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0468                   RotationX(-tilePlaneRotate * dd4hep::deg) *
0469                   Translation3D((xposChimneyTileS[tnum - 8] + (tnum + 1) * tile_tolerance) *
0470                                     dd4hep::mm,
0471                                 yposChimneyTileS[tnum - 8] * dd4hep::mm,
0472                                 zposChimneyTileS[tnum - 8] * dd4hep::mm));
0473 
0474           phv1.addPhysVolID("eta", (12 + tnum)).addPhysVolID("phi", i_phi);
0475           DetElement sd1 =
0476               tile_det.clone(_toString((12 + tnum), "eta%d ") + _toString(i_phi, "phi%d"));
0477           sd1.setPlacement(phv1);
0478           sdet.add(sd1);
0479 
0480           PlacedVolume phv0 = BarrelHCAL.placeVolume(
0481               Tile[i_eta], i_phi + i_eta * 320,
0482               RotationZ(i_phi * increment_angle + increment_offset) *
0483                   Transform3D(
0484                       RotationY(90.0 * dd4hep::deg),
0485                       Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0486                   RotationX(-tilePlaneRotate * dd4hep::deg) *
0487                   Translation3D(-(xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0488                                 yposTile[tnum] * dd4hep::mm, -zposTile[tnum] * dd4hep::mm));
0489 
0490           phv0.addPhysVolID("eta", i_eta).addPhysVolID("phi", i_phi);
0491           DetElement sd0 = tile_det.clone(_toString(i_eta, "eta%d ") + _toString(i_phi, "phi%d"));
0492           sd0.setPlacement(phv0);
0493           sdet.add(sd0);
0494         }
0495       }
0496     }
0497   }
0498 
0499   // Place the detector into the envelope
0500 
0501   envelope.placeVolume(BarrelHCAL, 0, Transform3D(RotationZ(0.0), Translation3D(0, 0, 0)));
0502 
0503   std::string env_vis =
0504       getAttrOrDefault<std::string>(x_det, _Unicode(env_vis), "HcalBarrelEnvelopeVis");
0505   envelope.setAttributes(description, x_det.regionStr(), x_det.limitsStr(), env_vis);
0506   return sdet;
0507 }
0508 
0509 DECLARE_DETELEMENT(epic_HcalBarrelGDML, create_detector)