Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:15:53

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   BarrelHCAL.placeVolume(
0259       barrel_csector_vol, 0,
0260       Transform3D(RotationZ(sec_rot_angle * dd4hep::deg) * RotationY(180.0 * dd4hep::deg),
0261                   Translation3D(0, 0, 0)));
0262   BarrelHCAL.placeVolume(barrel_csector_vol, 1,
0263                          Transform3D(RotationY(180.0 * dd4hep::deg), Translation3D(0, 0, 0)));
0264   BarrelHCAL.placeVolume(
0265       barrel_csector_vol, 2,
0266       Transform3D(RotationZ(-sec_rot_angle * dd4hep::deg) * RotationY(180.0 * dd4hep::deg),
0267                   Translation3D(0, 0, 0)));
0268   BarrelHCAL.placeVolume(barrel_er_vol, 0,
0269                          Transform3D(RotationY(180.0 * dd4hep::deg), Translation3D(0, 0, 0)));
0270   BarrelHCAL.placeVolume(barrel_er_vol, 1,
0271                          Transform3D(RotationY(0.0 * dd4hep::deg), Translation3D(0, 0, 0)));
0272 
0273   // Loop over the tile solids, create them and add them to the detector volume
0274 
0275   Volume Tile[12];
0276   Volume ChimneyTile[4];
0277 
0278   for (int j = 1; j < 17; j++) {
0279 
0280     std::string gdmlname;
0281     std::string solid_name;
0282 
0283     if (j < 13) {
0284 
0285       // standard tiles
0286 
0287       gdmlname   = _toString(j, "tile%d_gdmlfile");
0288       solid_name = _toString(j, "OuterHCalTile%02d");
0289 
0290     } else {
0291 
0292       // chimney tiles
0293 
0294       gdmlname   = _toString(j - 4, "ctile%d_gdmlfile");
0295       solid_name = _toString(j - 4, "OuterHCalChimneyTile%02d");
0296     }
0297 
0298     // tile shape gdml file info
0299     xml_comp_t x_det_tgdmlfile = x_det.child(gdmlname);
0300 
0301     std::string tgdml_file = getAttrOrDefault<std::string>(x_det_tgdmlfile, _Unicode(file), " ");
0302     ;
0303     std::string tgdml_material =
0304         getAttrOrDefault<std::string>(x_det_tgdmlfile, _Unicode(material), " ");
0305     std::string tgdml_url   = getAttrOrDefault<std::string>(x_det_tgdmlfile, _Unicode(url), " ");
0306     std::string tgdml_cache = getAttrOrDefault<std::string>(x_det_tgdmlfile, _Unicode(cache), " ");
0307 
0308     EnsureFileFromURLExists(tgdml_url, tgdml_file, tgdml_cache);
0309     if (!fs::exists(fs::path(tgdml_file))) {
0310       printout(ERROR, "BarrelHCalCalorimeter_geo", "file " + tgdml_file + " does not exist");
0311       printout(ERROR, "BarrelHCalCalorimeter_geo",
0312                "use a FileLoader plugin before the field element");
0313       std::_Exit(EXIT_FAILURE);
0314     }
0315 
0316     Volume solidVolume = parser.GDMLReadFile(tgdml_file.c_str());
0317     if (!solidVolume.isValid()) {
0318       printout(WARNING, "BarrelHCalCalorimeter_geo", "%s", tgdml_file.c_str());
0319       printout(WARNING, "BarrelHCalCalorimeter_geo", "solidVolume invalid, GDML parser failed!");
0320       std::_Exit(EXIT_FAILURE);
0321     }
0322     solidVolume.import();
0323     solidVolume.setVisAttributes(description, x_det.visStr());
0324     TessellatedSolid volume_solid = solidVolume.solid();
0325     volume_solid->CloseShape(true, true, true); // tesselated solid not closed by import!
0326     Material tile_material = description.material(tgdml_material.c_str());
0327     solidVolume.setMaterial(tile_material);
0328 
0329     solidVolume.setSensitiveDetector(sens);
0330 
0331     // For tiles we build an assembly to get the full array of tiles
0332     // Offsets and rotation are to properly orient the tiles in the assembly.
0333 
0334     if (solid_name.size() > 0) {
0335 
0336       std::string type = solid_name.substr(0, solid_name.size() - 2);
0337 
0338       if (type == "OuterHCalTile" || type == "OuterHCalChimneyTile") {
0339 
0340         std::string stnum = solid_name.substr(solid_name.size() - 2, solid_name.size());
0341         int tnum          = atoi(stnum.c_str()) - 1;
0342 
0343         // Tile numbers are indexed by the center (eta=0) out, we want them starting zero at one end.
0344 
0345         if (type == "OuterHCalTile") {
0346 
0347           Tile[11 - tnum] = solidVolume;
0348 
0349         } else if ((tnum > 7) && (type == "OuterHCalChimneyTile")) {
0350 
0351           ChimneyTile[11 - tnum] = solidVolume;
0352         }
0353 
0354       } else
0355         printout(WARNING, "BarrelHCalCalorimeter", "invalid solid_name, not a tile type?");
0356 
0357     } else
0358       printout(WARNING, "BarrelHCalCalorimeter", "solid_name.size() invalid! ");
0359   }
0360 
0361   // Place the tiles into the calorimeter volume
0362 
0363   double increment_angle  = (360.0 / 320.0) * dd4hep::deg;
0364   double increment_offset = -10.01 * increment_angle;
0365 
0366   DetElement tile_det("eta0 phi0", det_id);
0367   sens.setType("calorimeter");
0368 
0369   for (int i_eta = 0; i_eta < 12; i_eta++) { // eta ring
0370 
0371     int tnum = 11 - i_eta;
0372 
0373     for (int i_phi = 0; i_phi < 320; i_phi++) { // phi index
0374 
0375       if (i_eta > 3) {
0376 
0377         // ordinary sector tiles
0378 
0379         PlacedVolume phv1 = BarrelHCAL.placeVolume(
0380             Tile[i_eta], i_phi + i_eta * 320,
0381             RotationZ(i_phi * increment_angle + increment_offset) *
0382                 Transform3D(
0383                     RotationY(90.0 * dd4hep::deg),
0384                     Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0385                 RotationX(-tilePlaneRotate * dd4hep::deg) *
0386                 Transform3D(
0387                     RotationY(180.0 * dd4hep::deg),
0388                     Translation3D(-(xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0389                                   yposTile[tnum] * dd4hep::mm, -zposTile[tnum] * dd4hep::mm)));
0390 
0391         phv1.addPhysVolID("eta", i_eta).addPhysVolID("phi", i_phi);
0392         DetElement sd1 = tile_det.clone(_toString(i_eta, "eta%d ") + _toString(i_phi, "phi%d"));
0393         sd1.setPlacement(phv1);
0394         sdet.add(sd1);
0395 
0396         PlacedVolume phv0 = BarrelHCAL.placeVolume(
0397             Tile[i_eta], i_phi + (12 + tnum) * 320,
0398             RotationZ(i_phi * increment_angle + increment_offset) *
0399                 Transform3D(
0400                     RotationY(90.0 * dd4hep::deg),
0401                     Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0402                 RotationX(-tilePlaneRotate * dd4hep::deg) *
0403                 Translation3D((xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0404                               yposTile[tnum] * dd4hep::mm, zposTile[tnum] * dd4hep::mm));
0405 
0406         phv0.addPhysVolID("eta", (12 + tnum)).addPhysVolID("phi", i_phi);
0407         DetElement sd0 =
0408             tile_det.clone(_toString((12 + tnum), "eta%d ") + _toString(i_phi, "phi%d"));
0409         sd0.setPlacement(phv0);
0410         sdet.add(sd0);
0411 
0412       } else {
0413 
0414         // first three sectors are chimney sectors
0415 
0416         if (i_phi > 29) {
0417 
0418           // ordinary sector tiles
0419 
0420           PlacedVolume phv1 = BarrelHCAL.placeVolume(
0421               Tile[i_eta], i_phi + i_eta * 320,
0422               RotationZ(i_phi * increment_angle + increment_offset) *
0423                   Transform3D(
0424                       RotationY(90.0 * dd4hep::deg),
0425                       Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0426                   RotationX(-tilePlaneRotate * dd4hep::deg) *
0427                   Translation3D((xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0428                                 yposTile[tnum] * dd4hep::mm, zposTile[tnum] * dd4hep::mm));
0429 
0430           phv1.addPhysVolID("eta", i_eta).addPhysVolID("phi", i_phi);
0431           DetElement sd1 = tile_det.clone(_toString(i_eta, "eta%d ") + _toString(i_phi, "phi%d"));
0432           sd1.setPlacement(phv1);
0433           sdet.add(sd1);
0434 
0435           PlacedVolume phv0 = BarrelHCAL.placeVolume(
0436               Tile[i_eta], i_phi + (12 + tnum) * 320,
0437               RotationZ(i_phi * increment_angle + increment_offset) *
0438                   Transform3D(
0439                       RotationY(90.0 * dd4hep::deg),
0440                       Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0441                   RotationX(-tilePlaneRotate * dd4hep::deg) *
0442                   Transform3D(
0443                       RotationY(180.0 * dd4hep::deg),
0444                       Translation3D(-(xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0445                                     yposTile[tnum] * dd4hep::mm, -zposTile[tnum] * dd4hep::mm)));
0446 
0447           phv0.addPhysVolID("eta", (12 + tnum)).addPhysVolID("phi", i_phi);
0448           DetElement sd0 =
0449               tile_det.clone(_toString((12 + tnum), "eta%d ") + _toString(i_phi, "phi%d"));
0450           sd0.setPlacement(phv0);
0451           sdet.add(sd0);
0452 
0453         } else {
0454 
0455           // chimney sector tile
0456 
0457           PlacedVolume phv1 = BarrelHCAL.placeVolume(
0458               ChimneyTile[i_eta], i_phi + (12 + tnum) * 320,
0459               RotationZ(i_phi * increment_angle + increment_offset) *
0460                   Transform3D(
0461                       RotationY(90.0 * dd4hep::deg),
0462                       Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0463                   RotationX(-tilePlaneRotate * dd4hep::deg) *
0464                   Translation3D((xposChimneyTileS[tnum - 8] + (tnum + 1) * tile_tolerance) *
0465                                     dd4hep::mm,
0466                                 yposChimneyTileS[tnum - 8] * dd4hep::mm,
0467                                 zposChimneyTileS[tnum - 8] * dd4hep::mm));
0468 
0469           phv1.addPhysVolID("eta", (12 + tnum)).addPhysVolID("phi", i_phi);
0470           DetElement sd1 =
0471               tile_det.clone(_toString((12 + tnum), "eta%d ") + _toString(i_phi, "phi%d"));
0472           sd1.setPlacement(phv1);
0473           sdet.add(sd1);
0474 
0475           PlacedVolume phv0 = BarrelHCAL.placeVolume(
0476               Tile[i_eta], i_phi + i_eta * 320,
0477               RotationZ(i_phi * increment_angle + increment_offset) *
0478                   Transform3D(
0479                       RotationY(90.0 * dd4hep::deg),
0480                       Translation3D(xposOuter[0] * dd4hep::mm, yposOuter[0] * dd4hep::mm, 0.0)) *
0481                   RotationX(-tilePlaneRotate * dd4hep::deg) *
0482                   Translation3D((xposTile[tnum] + (tnum + 1) * tile_tolerance) * dd4hep::mm,
0483                                 yposTile[tnum] * dd4hep::mm, zposTile[tnum] * dd4hep::mm));
0484 
0485           phv0.addPhysVolID("eta", i_eta).addPhysVolID("phi", i_phi);
0486           DetElement sd0 = tile_det.clone(_toString(i_eta, "eta%d ") + _toString(i_phi, "phi%d"));
0487           sd0.setPlacement(phv0);
0488           sdet.add(sd0);
0489         }
0490       }
0491     }
0492   }
0493 
0494   // Place the detector into the envelope
0495 
0496   envelope.placeVolume(BarrelHCAL, 0, Transform3D(RotationZ(0.0), Translation3D(0, 0, 0)));
0497 
0498   std::string env_vis =
0499       getAttrOrDefault<std::string>(x_det, _Unicode(env_vis), "HcalBarrelEnvelopeVis");
0500   envelope.setAttributes(description, x_det.regionStr(), x_det.limitsStr(), env_vis);
0501   return sdet;
0502 }
0503 
0504 DECLARE_DETELEMENT(epic_HcalBarrelGDML, create_detector)