Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2023 Friederike Bock
0003 
0004 //==========================================================================
0005 //  Implementation of longitudinally separated forward calorimeter
0006 //--------------------------------------------------------------------------
0007 //  Author: Friederike Bock (ORNL)
0008 //==========================================================================
0009 
0010 #include "DD4hep/DetFactoryHelper.h"
0011 #include "DD4hep/Printout.h"
0012 #include "DD4hep/Shapes.h"
0013 #include "DDRec/DetectorData.h"
0014 #include "DDRec/Surface.h"
0015 #include <XML/Helper.h>
0016 #include "XML/Layering.h"
0017 #include "XML/Utilities.h"
0018 using namespace dd4hep;
0019 
0020 struct moduleParamsStrct {
0021   moduleParamsStrct()
0022       : mod_BIwidth(0.)
0023       , mod_BIheight(0.)
0024       , mod_SWThick(0.)
0025       , mod_TWThick(0.)
0026       , mod_MPThick(0.)
0027       , mod_FWThick(0.)
0028       , mod_BWThick(0.)
0029       , mod_width(0.)
0030       , mod_height(0.)
0031       , mod_notchDepth(0.)
0032       , mod_notchHeight(0.)
0033       , mod_foilThick(0.)
0034       , mod_pcbLength(0.)
0035       , mod_pcbThick(0.)
0036       , mod_pcbWidth(0.)
0037       , mod_visStr("")
0038       , mod_regStr("")
0039       , mod_limStr("") {}
0040   moduleParamsStrct(double BIwidth, double BIheight, double SWThick, double TWThick, double MPThick,
0041                     double FWThick, double BWThick, double width, double height, double notchDepth,
0042                     double notchHeight, double foilThick, double pcbLegth, double pcbThick,
0043                     double pcbWidth, std::string visStr, std::string regStr, std::string limStr) {
0044     mod_BIwidth     = BIwidth;
0045     mod_BIheight    = BIheight;
0046     mod_SWThick     = SWThick;
0047     mod_TWThick     = TWThick;
0048     mod_MPThick     = MPThick;
0049     mod_FWThick     = FWThick;
0050     mod_BWThick     = BWThick;
0051     mod_width       = width;
0052     mod_height      = height;
0053     mod_notchDepth  = notchDepth;
0054     mod_notchHeight = notchHeight;
0055     mod_foilThick   = foilThick;
0056     mod_pcbLength   = pcbLegth;
0057     mod_pcbThick    = pcbThick;
0058     mod_pcbWidth    = pcbWidth;
0059     mod_visStr      = visStr;
0060     mod_regStr      = regStr;
0061     mod_limStr      = limStr;
0062   }
0063   double mod_BIwidth     = 0.;
0064   double mod_BIheight    = 0.;
0065   double mod_SWThick     = 0.;
0066   double mod_TWThick     = 0.;
0067   double mod_MPThick     = 0.;
0068   double mod_FWThick     = 0.;
0069   double mod_BWThick     = 0.;
0070   double mod_width       = 0.;
0071   double mod_height      = 0.;
0072   double mod_notchDepth  = 0.;
0073   double mod_notchHeight = 0.;
0074   double mod_foilThick   = 0.;
0075   double mod_pcbLength   = 0.;
0076   double mod_pcbThick    = 0.;
0077   double mod_pcbWidth    = 0.;
0078   std::string mod_visStr = "";
0079   std::string mod_regStr = "";
0080   std::string mod_limStr = "";
0081 };
0082 
0083 struct sliceParamsStrct {
0084   sliceParamsStrct()
0085       : layer_ID(0)
0086       , slice_ID(0)
0087       , slice_partID(0)
0088       , slice_thick(0.)
0089       , slice_offset(0.)
0090       , slice_readoutLayer(0)
0091       , slice_matStr("")
0092       , slice_visStr("")
0093       , slice_regStr("")
0094       , slice_limStr("") {}
0095   sliceParamsStrct(int l_ID, int sl_ID, int sl_partID, double sl_thick, double sl_off, int l_rl,
0096                    std::string sl_matStr, std::string sl_visStr, std::string sl_regStr,
0097                    std::string sl_limStr) {
0098     layer_ID           = l_ID;
0099     slice_ID           = sl_ID;
0100     slice_partID       = sl_partID;
0101     slice_thick        = sl_thick;
0102     slice_offset       = sl_off;
0103     slice_readoutLayer = l_rl;
0104     slice_matStr       = sl_matStr;
0105     slice_visStr       = sl_visStr;
0106     slice_regStr       = sl_regStr;
0107     slice_limStr       = sl_limStr;
0108   }
0109   int layer_ID             = 0;
0110   int slice_ID             = 0;
0111   int slice_partID         = 0;
0112   double slice_thick       = 0.;
0113   double slice_offset      = 0.;
0114   int slice_readoutLayer   = 0;
0115   std::string slice_matStr = "";
0116   std::string slice_visStr = "";
0117   std::string slice_regStr = "";
0118   std::string slice_limStr = "";
0119 };
0120 
0121 //************************************************************************************************************
0122 //************************** Assembly for absorber plates  ***************************************************
0123 //************************************************************************************************************
0124 Volume createAbsorberPlate(Detector& desc, std::string basename, double h_mod, double w_mod,
0125                            double t_mod_tp, double t_mod_sp, double t_slice, double w_notch,
0126                            double h_notch, Material slice_mat, std::string region,
0127                            std::string limit, std::string vis, bool renderComp) {
0128 
0129   double w_plate = (w_mod / 2 - t_mod_sp) * 2;
0130   double l_A     = -w_plate / 2;
0131   double l_B     = -(w_plate / 2 - w_notch);
0132   double r_A     = w_plate / 2;
0133   // 0      1     2     3     4
0134   const std::vector<double> xCoord = {l_A, r_A, r_A, l_A, l_A,
0135                                       // 5     6     7
0136                                       l_B, l_B, l_A};
0137   // 0      1     2     3      4
0138 
0139   double topA = h_mod / 2 - t_mod_tp;
0140   double topB = h_notch / 2;
0141   double botA = -(h_mod / 2 - t_mod_tp);
0142   double botB = -(h_notch / 2);
0143   // 0     1       2      3       4
0144   const std::vector<double> yCoord = {topA, topA, botA, botA, botB,
0145                                       // 5       6       7      8       9
0146                                       botB, topB, topB};
0147 
0148   const std::vector<double> zStep      = {-t_slice / 2, t_slice / 2};
0149   const std::vector<double> zStepX     = {0., 0.};
0150   const std::vector<double> zStepY     = {0., 0.};
0151   const std::vector<double> zStepScale = {1., 1.};
0152 
0153   ExtrudedPolygon absplate = ExtrudedPolygon(xCoord, yCoord, zStep, zStepX, zStepY, zStepScale);
0154 
0155   Volume absplate_vol(basename, absplate, slice_mat);
0156   // Setting slice attributes
0157   if (renderComp) {
0158     absplate_vol.setAttributes(desc, region, limit, vis);
0159   } else {
0160     absplate_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0161   }
0162 
0163   return absplate_vol;
0164 }
0165 
0166 //************************************************************************************************************
0167 //************************** Filler plate i.e. air & kapton & PCB & ESR
0168 //************************************************************************************************************
0169 Volume createFillerPlate(Detector& desc, std::string basename, double h_mod, double w_mod,
0170                          double t_mod_tp, double t_mod_sp, double t_slice, double w_notch,
0171                          Material slice_mat, std::string region, std::string limit, std::string vis,
0172                          bool renderComp) {
0173   double w_plate = w_mod - 2 * t_mod_sp - w_notch;
0174   double h_plate = h_mod - 2 * t_mod_tp;
0175 
0176   Box filler(w_plate / 2., h_plate / 2., t_slice / 2.);
0177   Volume filler_vol(basename, filler, slice_mat);
0178   // Setting slice attributes
0179   if (renderComp) {
0180     filler_vol.setAttributes(desc, region, limit, vis);
0181   } else {
0182     filler_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0183   }
0184 
0185   return filler_vol;
0186 }
0187 
0188 //************************************************************************************************************
0189 //************************** single scintillator plate for tower *********************************************
0190 //************************************************************************************************************
0191 Volume createScintillatorTower(Detector& desc, std::string basename, double w_tow, double h_tow,
0192                                double t_slice, Material slice_mat, std::string region,
0193                                std::string limit, std::string vis, SensitiveDetector sens,
0194                                bool renderComp) {
0195 
0196   Box scintplate(w_tow / 2., h_tow / 2., t_slice / 2.);
0197   Volume slice_vol(basename, scintplate, slice_mat);
0198   // Setting appropriate slices as sensitive
0199   sens.setType("calorimeter");
0200   slice_vol.setSensitiveDetector(sens);
0201   // Setting slice attributes
0202   if (renderComp) {
0203     slice_vol.setAttributes(desc, region, limit, vis);
0204   } else {
0205     slice_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0206   }
0207   return slice_vol;
0208 }
0209 
0210 //************************************************************************************************************
0211 //************************** create scintillator plate with separations for 8M *******************************
0212 //************************************************************************************************************
0213 Assembly createScintillatorPlateEightM(Detector& desc, std::string basename,
0214                                        //                                         int modID,
0215                                        int layerID, double h_mod, double w_mod, double t_mod_tp,
0216                                        double t_mod_sp, double t_slice, double w_notch,
0217                                        double t_foil, Material slice_mat, int roLayer,
0218                                        std::string region, std::string limit, std::string vis,
0219                                        SensitiveDetector sens, bool renderComp) {
0220   // Tower placement in 8M module
0221   //======================================================================
0222   //||              ||              ||                ||                ||
0223   //||      0       ||      1       ||        2       ||        3       ||
0224   //||              ||              ||                ||                ||
0225   //======================================================================
0226   //||              ||              ||                ||                ||
0227   //||      4       ||      5       ||        6       ||        7       ||
0228   //||              ||              ||                ||                ||
0229   //======================================================================
0230   Assembly modScintAssembly(basename);
0231   double w_plate = w_mod - w_notch - 2 * t_mod_sp - 2 * t_foil;
0232   double h_plate = h_mod - 2 * t_mod_tp - 2 * t_foil;
0233   double w_tow   = (w_plate - 6 * t_foil) / 4;
0234   double h_tow   = (h_plate - 2 * t_foil) / 2;
0235 
0236   // placement volumes
0237   PlacedVolume pvm;
0238 
0239   // foil separations                     // 0              1                   2                   3                   4
0240   const std::vector<double> xCoordTi = {
0241       -(w_plate / 2.), -(w_tow + 3 * t_foil), -(w_tow + 3 * t_foil), -(w_tow + 1 * t_foil),
0242       -(w_tow + 1 * t_foil),
0243       // 5              6                   7                   8                   9
0244       -t_foil, -t_foil, t_foil, t_foil, w_tow + 1 * t_foil,
0245       // 10             11                  12                  13                  14
0246       w_tow + 1 * t_foil, w_tow + 3 * t_foil, w_tow + 3 * t_foil, w_plate / 2., w_plate / 2.,
0247       // 15             16                  17                  18                  19
0248       w_tow + 3 * t_foil, w_tow + 3 * t_foil, w_tow + 1 * t_foil, w_tow + 1 * t_foil, t_foil,
0249       // 20             21                  22                  23                  24
0250       t_foil, -t_foil, -t_foil, -(w_tow + 1 * t_foil), -(w_tow + 1 * t_foil),
0251       // 25             26                  27
0252       -(w_tow + 3 * t_foil), -(w_tow + 3 * t_foil), -(w_plate / 2.)};
0253   // 0              1                   2                   3                   4
0254   const std::vector<double> yCoordTi = {
0255       t_foil, t_foil, (h_plate / 2.), (h_plate / 2.), t_foil,
0256       // 5              6                   7                   8                   9
0257       t_foil, (h_plate / 2.), (h_plate / 2.), t_foil, t_foil,
0258       // 10             11                  12                  13                  14
0259       (h_plate / 2.), (h_plate / 2.), t_foil, t_foil, -t_foil,
0260       // 15             16                  17                  18                  19
0261       -t_foil, -(h_plate / 2.), -(h_plate / 2.), -t_foil, -t_foil,
0262       // 20             21                  22                  23                  24
0263       -(h_plate / 2.), -(h_plate / 2.), -t_foil, -t_foil, -(h_plate / 2.),
0264       // 25             26                  27
0265       -(h_plate / 2.), -t_foil, -t_foil};
0266 
0267   const std::vector<double> zStepTi      = {-t_slice / 2, t_slice / 2};
0268   const std::vector<double> zStepXTi     = {0., 0.};
0269   const std::vector<double> zStepYTi     = {0., 0.};
0270   const std::vector<double> zStepScaleTi = {1., 1.};
0271 
0272   ExtrudedPolygon foilgrid =
0273       ExtrudedPolygon(xCoordTi, yCoordTi, zStepTi, zStepXTi, zStepYTi, zStepScaleTi);
0274   Box foil_t((w_plate + 2 * t_foil) / 2., t_foil / 2., t_slice / 2.);
0275   Box foil_s(t_foil / 2., h_plate / 2., t_slice / 2.);
0276   Volume foilgrid_vol(basename + "_ESRFoil_" + _toString(layerID, "_layer_%d"), foilgrid,
0277                       slice_mat);
0278   Volume foil_t_vol(basename + "_ESRFoilT_" + _toString(layerID, "_layer_%d"), foil_t, slice_mat);
0279   Volume foil_b_vol(basename + "_ESRFoilB_" + _toString(layerID, "_layer_%d"), foil_t, slice_mat);
0280   Volume foil_l_vol(basename + "_ESRFoilL_" + _toString(layerID, "_layer_%d"), foil_s, slice_mat);
0281   Volume foil_r_vol(basename + "_ESRFoilR_" + _toString(layerID, "_layer_%d"), foil_s, slice_mat);
0282   // Setting slice attributes
0283   if (renderComp) {
0284     foilgrid_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0285     foil_t_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0286     foil_b_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0287     foil_l_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0288     foil_r_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0289   } else {
0290     foilgrid_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0291     foil_t_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0292     foil_b_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0293     foil_l_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0294     foil_r_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0295   }
0296   pvm = modScintAssembly.placeVolume(foilgrid_vol, Position(0, 0, 0));
0297   pvm = modScintAssembly.placeVolume(foil_t_vol, Position(0, 1.5 * t_foil + h_tow, 0));
0298   pvm = modScintAssembly.placeVolume(foil_b_vol, Position(0, -(1.5 * t_foil + h_tow), 0));
0299   pvm = modScintAssembly.placeVolume(foil_l_vol, Position(-(3.5 * t_foil + 2 * w_tow), 0, 0));
0300   pvm = modScintAssembly.placeVolume(foil_r_vol, Position((3.5 * t_foil + 2 * w_tow), 0, 0));
0301 
0302   // 8M module placement of scintillator for tower
0303   double rotZ[8] = {0, 0, 0, 0, 0, 0, 0, 0};
0304   double rotY[8] = {0, 0, 0, 0, 0, 0, 0, 0};
0305   double rotX[8] = {0, 0, 0, 0, 0, 0, 0, 0};
0306   double posX[8] = {(w_tow * 1.5 + 3 * t_foil), (w_tow * 0.5 + t_foil),
0307                     -(w_tow * 0.5 + t_foil),    -(w_tow * 1.5 + 3 * t_foil),
0308                     (w_tow * 1.5 + 3 * t_foil), (w_tow * 0.5 + t_foil),
0309                     -(w_tow * 0.5 + t_foil),    -(w_tow * 1.5 + 3 * t_foil)};
0310   double posY[8] = {0.5 * (h_tow) + t_foil,    0.5 * (h_tow) + t_foil,    0.5 * (h_tow) + t_foil,
0311                     0.5 * (h_tow) + t_foil,    -(0.5 * (h_tow) + t_foil), -(0.5 * (h_tow) + t_foil),
0312                     -(0.5 * (h_tow) + t_foil), -(0.5 * (h_tow) + t_foil)};
0313   double posZ[8] = {0, 0, 0, 0, 0, 0, 0, 0};
0314   int towerx     = 0;
0315   int towery     = 0;
0316 
0317   // loop over all towers within same module
0318   for (int i = 0; i < 8; i++) {
0319     // printout(DEBUG, "LFHCAL_geo", basename + _toString(i, "_tower_%d") + "\t" + _toString(modID) + "\t" + _toString(i) + "\t" + _toString(layerID));
0320     Volume modScintTowerAss =
0321         createScintillatorTower(desc, basename + _toString(i, "_tower_%d"), w_tow, h_tow, t_slice,
0322                                 slice_mat, region, limit, vis, sens, renderComp);
0323     pvm = modScintAssembly.placeVolume(
0324         modScintTowerAss,
0325         Transform3D(RotationZYX(rotZ[i], rotY[i], rotX[i]), Position(posX[i], posY[i], posZ[i])));
0326     towerx = i % 4;
0327     towery = 0;
0328     if (i > 3)
0329       towery = 1;
0330     pvm.addPhysVolID("towerx", towerx)
0331         .addPhysVolID("towery", towery)
0332         .addPhysVolID("layerz", layerID)
0333         .addPhysVolID("passive", 0)
0334         .addPhysVolID("rlayerz", roLayer);
0335   }
0336   return modScintAssembly;
0337 }
0338 
0339 //************************************************************************************************************
0340 //************************** create scintillator plate with separations for 4M *******************************
0341 //************************************************************************************************************
0342 Assembly createScintillatorPlateFourM(Detector& desc, std::string basename,
0343                                       //                                         int modID,
0344                                       int layerID, double h_mod, double w_mod, double t_mod_tp,
0345                                       double t_mod_sp, double t_slice, double w_notch,
0346                                       double t_foil, Material slice_mat, int roLayer,
0347                                       std::string region, std::string limit, std::string vis,
0348                                       SensitiveDetector sens, bool renderComp) {
0349   // Tower placement in 4M module
0350   //--------------------------------
0351   //|              ||              |
0352   //|      0       ||      1       |
0353   //|              ||              |
0354   //|==============================|
0355   //|              ||              |
0356   //|      2       ||      3       |
0357   //|              ||              |
0358   //--------------------------------
0359   Assembly modScintAssembly(basename);
0360 
0361   double w_plate = w_mod - w_notch - 2 * t_mod_sp - 2 * t_foil;
0362   double h_plate = h_mod - 2 * t_mod_tp - 2 * t_foil;
0363   double w_tow   = (w_plate - 2 * t_foil) / 2;
0364   double h_tow   = (h_plate - 2 * t_foil) / 2;
0365 
0366   // placement volumes
0367   PlacedVolume pvm;
0368 
0369   // foil separations
0370   // 0            1             2             3               4
0371   const std::vector<double> xCoordTi = {
0372       -(w_plate / 2.), -t_foil, -t_foil, t_foil, t_foil,
0373       // 5            6             7             8               9
0374       w_plate / 2., w_plate / 2., t_foil, t_foil, -t_foil,
0375       // 10           11
0376       -t_foil, -(w_plate / 2.)};
0377   // 0            1             2             3               4
0378   const std::vector<double> yCoordTi = {
0379       t_foil,
0380       t_foil,
0381       (h_plate / 2.),
0382       (h_plate / 2.),
0383       t_foil,
0384       // 5            6             7             8               9
0385       t_foil,
0386       -t_foil,
0387       -t_foil,
0388       -(h_plate / 2.),
0389       -(h_plate / 2.),
0390       // 10           11
0391       -t_foil,
0392       -t_foil,
0393   };
0394 
0395   const std::vector<double> zStepTi      = {-t_slice / 2, t_slice / 2};
0396   const std::vector<double> zStepXTi     = {0., 0.};
0397   const std::vector<double> zStepYTi     = {0., 0.};
0398   const std::vector<double> zStepScaleTi = {1., 1.};
0399 
0400   ExtrudedPolygon foilgrid =
0401       ExtrudedPolygon(xCoordTi, yCoordTi, zStepTi, zStepXTi, zStepYTi, zStepScaleTi);
0402   Box foil_t((w_plate + 2 * t_foil) / 2., t_foil / 2., t_slice / 2.);
0403   Box foil_s(t_foil / 2., h_plate / 2., t_slice / 2.);
0404   Volume foilgrid_vol(basename + "_ESRFoil_" + _toString(layerID, "_layer_%d"), foilgrid,
0405                       slice_mat);
0406   Volume foil_t_vol(basename + "_ESRFoilT_" + _toString(layerID, "_layer_%d"), foil_t, slice_mat);
0407   Volume foil_b_vol(basename + "_ESRFoilB_" + _toString(layerID, "_layer_%d"), foil_t, slice_mat);
0408   Volume foil_l_vol(basename + "_ESRFoilL_" + _toString(layerID, "_layer_%d"), foil_s, slice_mat);
0409   Volume foil_r_vol(basename + "_ESRFoilR_" + _toString(layerID, "_layer_%d"), foil_s, slice_mat);
0410   // Setting slice attributes
0411   if (renderComp) {
0412     foilgrid_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0413     foil_t_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0414     foil_b_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0415     foil_l_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0416     foil_r_vol.setAttributes(desc, region, limit, "LFHCALLayerSepVis");
0417   } else {
0418     foilgrid_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0419     foil_t_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0420     foil_b_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0421     foil_l_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0422     foil_r_vol.setAttributes(desc, region, limit, "InvisibleNoDaughters");
0423   }
0424   pvm = modScintAssembly.placeVolume(foilgrid_vol, Position(0, 0, 0));
0425   pvm = modScintAssembly.placeVolume(foil_t_vol, Position(0, 1.5 * t_foil + h_tow, 0));
0426   pvm = modScintAssembly.placeVolume(foil_b_vol, Position(0, -(1.5 * t_foil + h_tow), 0));
0427   pvm = modScintAssembly.placeVolume(foil_l_vol, Position(-(1.5 * t_foil + w_tow), 0, 0));
0428   pvm = modScintAssembly.placeVolume(foil_r_vol, Position((1.5 * t_foil + w_tow), 0, 0));
0429 
0430   // 4M module placement of scintillator for tower
0431   double rotZ[4] = {0, 0, 0, 0};
0432   double rotY[4] = {0, 0, 0, 0};
0433   double rotX[4] = {0, 0, 0, 0};
0434   double posX[4] = {(w_tow * 0.5 + t_foil), -(w_tow * 0.5 + t_foil), (w_tow * 0.5 + t_foil),
0435                     -(w_tow * 0.5 + t_foil)};
0436   double posY[4] = {0.5 * (h_tow) + t_foil, 0.5 * (h_tow) + t_foil, -(0.5 * (h_tow) + t_foil),
0437                     -(0.5 * (h_tow) + t_foil)};
0438   double posZ[4] = {0, 0, 0, 0};
0439   int towerx     = 0;
0440   int towery     = 0;
0441   // loop over all towers within same module
0442 
0443   for (int i = 0; i < 4; i++) {
0444     // printout(DEBUG, "LFHCAL_geo", basename + _toString(i, "_tower_%d") + "\t" + _toString(modID) + "\t" + _toString(i) + "\t" + _toString(layerID));
0445     Volume modScintTowerAss =
0446         createScintillatorTower(desc, basename + _toString(i, "_tower_%d"), w_tow, h_tow, t_slice,
0447                                 slice_mat, region, limit, vis, sens, renderComp);
0448     pvm = modScintAssembly.placeVolume(
0449         modScintTowerAss,
0450         Transform3D(RotationZYX(rotZ[i], rotY[i], rotX[i]), Position(posX[i], posY[i], posZ[i])));
0451     towerx = i % 2;
0452     towery = 0;
0453     if (i > 1)
0454       towery = 1;
0455     pvm.addPhysVolID("towerx", towerx)
0456         .addPhysVolID("towery", towery)
0457         .addPhysVolID("layerz", layerID)
0458         .addPhysVolID("passive", 0)
0459         .addPhysVolID("rlayerz", roLayer);
0460   }
0461   return modScintAssembly;
0462 }
0463 
0464 //************************************************************************************************************
0465 //************************** create 8M module assembly  ******************************************************
0466 //************************************************************************************************************
0467 Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
0468                           std::vector<sliceParamsStrct> sl_params,
0469                           //                               int modID,
0470                           double length, SensitiveDetector sens, bool renderComp, bool allSen) {
0471   std::string baseName = "LFHCAL_8M";
0472 
0473   // assembly definition
0474   Box modBox(mod_params.mod_width / 2., mod_params.mod_height / 2., length / 2.);
0475   Volume vol_mod(baseName, modBox, desc.material("Air"));
0476   vol_mod.setVisAttributes(desc.visAttributes(mod_params.mod_visStr.data()));
0477 
0478   // placement operator
0479   PlacedVolume pvm;
0480   // ********************************************************************************
0481   // Casing definition
0482   // ********************************************************************************
0483   // geom definition 8M module casing
0484   Box MountingPlate(mod_params.mod_width / 2., mod_params.mod_height / 2.,
0485                     mod_params.mod_MPThick / 2.);
0486   Box modFrontPlate(mod_params.mod_width / 2., mod_params.mod_height / 2.,
0487                     mod_params.mod_FWThick / 2.);
0488   Box modSidePlateL(
0489       mod_params.mod_SWThick / 2., mod_params.mod_height / 2.,
0490       (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.);
0491   Box modSidePlateR(
0492       mod_params.mod_SWThick / 2., mod_params.mod_height / 2.,
0493       (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.);
0494   Box modTopPlate(
0495       (mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., mod_params.mod_TWThick / 2.,
0496       (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.);
0497   Box modBottomPlate(
0498       (mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., mod_params.mod_TWThick / 2.,
0499       (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.);
0500   Box modBackCutOut(mod_params.mod_BIwidth / 2., mod_params.mod_BIheight / 2.,
0501                     mod_params.mod_BWThick / 2.);
0502   Box modBackPlateFull(mod_params.mod_width / 2., mod_params.mod_height / 2.,
0503                        mod_params.mod_BWThick / 2.);
0504   SubtractionSolid modBackPlate(modBackPlateFull, modBackCutOut);
0505 
0506   // volume definition 8M module casing
0507   Volume vol_mountingPlate(baseName + "_MountingPlate", MountingPlate, desc.material("Steel235"));
0508   Volume vol_modFrontPlate(baseName + "_FrontPlate", modFrontPlate, desc.material("Steel235"));
0509   Volume vol_modBackPlate(baseName + "_BackPlate", modBackPlate, desc.material("Steel235"));
0510   Volume vol_modSidePlateL(baseName + "_LeftSidePlate", modSidePlateL, desc.material("Steel235"));
0511   Volume vol_modSidePlateR(baseName + "_RightSidePlate", modSidePlateR, desc.material("Steel235"));
0512   Volume vol_modTopPlate(baseName + "_TopPlate", modTopPlate, desc.material("Steel235"));
0513   Volume vol_modBottomPlate(baseName + "_BottomPlate", modBottomPlate, desc.material("Steel235"));
0514 
0515   if (allSen) {
0516     sens.setType("calorimeter");
0517     vol_mountingPlate.setSensitiveDetector(sens);
0518     vol_modFrontPlate.setSensitiveDetector(sens);
0519     vol_modBackPlate.setSensitiveDetector(sens);
0520     vol_modSidePlateL.setSensitiveDetector(sens);
0521     vol_modSidePlateR.setSensitiveDetector(sens);
0522     vol_modTopPlate.setSensitiveDetector(sens);
0523     vol_modBottomPlate.setSensitiveDetector(sens);
0524   }
0525 
0526   if (renderComp) {
0527     vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0528                                     // mod_params.mod_visStr);
0529                                     "LFHCALLayerTungstenVis");
0530     vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0531                                     // mod_params.mod_visStr);
0532                                     "LFHCALLayerSteelVis");
0533     vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0534                                    //  mod_params.mod_visStr);
0535                                    "LFHCALLayerSteelVis");
0536     vol_modSidePlateL.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0537                                     mod_params.mod_visStr);
0538     vol_modSidePlateR.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0539                                     mod_params.mod_visStr);
0540     vol_modTopPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0541                                   // mod_params.mod_visStr);
0542                                   "LFHCALLayerSteelVis");
0543     vol_modBottomPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0544                                      //  mod_params.mod_visStr);
0545                                      "LFHCALLayerSteelVis");
0546   } else {
0547     vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0548                                     "InvisibleNoDaughters");
0549     vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0550                                     "InvisibleNoDaughters");
0551     vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0552                                    "InvisibleNoDaughters");
0553     vol_modSidePlateL.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0554                                     "InvisibleNoDaughters");
0555     vol_modSidePlateR.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0556                                     "InvisibleNoDaughters");
0557     vol_modTopPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0558                                   "InvisibleNoDaughters");
0559     vol_modBottomPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0560                                      "InvisibleNoDaughters");
0561   }
0562 
0563   // ********************************************************************************
0564   // long PCB
0565   // ********************************************************************************
0566   Box modPCB(mod_params.mod_pcbThick / 2., mod_params.mod_pcbWidth / 2.,
0567              (mod_params.mod_pcbLength) / 2.);
0568   Volume vol_modPCB(baseName + "_PCB", modPCB, desc.material("Fr4"));
0569   if (renderComp) {
0570     vol_modPCB.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, "LFHCALModPCB");
0571   } else {
0572     vol_modPCB.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0573                              "InvisibleNoDaughters");
0574   }
0575 
0576   int layer_num  = 0;
0577   double slice_z = -length / 2 + mod_params.mod_MPThick +
0578                    mod_params.mod_FWThick; // Keeps track of layers' local z locations
0579   // Looping through the number of repeated layers & slices in each section
0580   for (int i = 0; i < (int)sl_params.size(); i++) {
0581     slice_z += sl_params[i].slice_offset +
0582                sl_params[i].slice_thick / 2.; // Going to halfway point in layer
0583     layer_num = sl_params[i].layer_ID;
0584     //*************************************************
0585     // absorber plates
0586     //*************************************************
0587     Material slice_mat = desc.material(sl_params[i].slice_matStr);
0588     if (sl_params[i].slice_partID == 1) {
0589       Volume modAbsAssembly = createAbsorberPlate(
0590           desc, baseName + "_Abs" + _toString(sl_params[i].layer_ID, "_layer_%d"),
0591           mod_params.mod_height, mod_params.mod_width, mod_params.mod_TWThick,
0592           mod_params.mod_SWThick, sl_params[i].slice_thick, mod_params.mod_notchDepth,
0593           mod_params.mod_notchHeight, slice_mat, sl_params[i].slice_regStr,
0594           sl_params[i].slice_limStr, sl_params[i].slice_visStr, renderComp);
0595       // Placing slice within layer
0596       if (allSen)
0597         modAbsAssembly.setSensitiveDetector(sens);
0598       pvm = vol_mod.placeVolume(modAbsAssembly,
0599                                 Transform3D(RotationZYX(0, 0, 0), Position(0., 0., slice_z)));
0600       if (allSen)
0601         pvm.addPhysVolID("towerx", 0)
0602             .addPhysVolID("towery", 0)
0603             .addPhysVolID("rlayerz", sl_params[i].slice_readoutLayer)
0604             .addPhysVolID("layerz", layer_num)
0605             .addPhysVolID("passive", 1);
0606       //*************************************************
0607       // air & kapton & PCB & ESR
0608       //*************************************************
0609     } else if (sl_params[i].slice_partID == 2) {
0610       Volume modFillAssembly =
0611           createFillerPlate(desc,
0612                             baseName + "_Fill" + _toString(sl_params[i].layer_ID, "_layer_%d") +
0613                                 _toString(sl_params[i].slice_ID, "slice_%d"),
0614                             mod_params.mod_height, mod_params.mod_width, mod_params.mod_TWThick,
0615                             mod_params.mod_SWThick, sl_params[i].slice_thick,
0616                             mod_params.mod_notchDepth, slice_mat, sl_params[i].slice_regStr,
0617                             sl_params[i].slice_limStr, sl_params[i].slice_visStr, renderComp);
0618       // Placing slice within layer
0619       if (allSen)
0620         modFillAssembly.setSensitiveDetector(sens);
0621       pvm = vol_mod.placeVolume(
0622           modFillAssembly, Transform3D(RotationZYX(0, 0, 0),
0623                                        Position((mod_params.mod_notchDepth) / 2., 0., slice_z)));
0624       if (allSen)
0625         pvm.addPhysVolID("towerx", 1)
0626             .addPhysVolID("towery", 0)
0627             .addPhysVolID("rlayerz", sl_params[i].slice_readoutLayer)
0628             .addPhysVolID("layerz", layer_num)
0629             .addPhysVolID("passive", 1);
0630       //*************************************************
0631       // scintillator
0632       //*************************************************
0633     } else {
0634       Assembly modScintAssembly = createScintillatorPlateEightM(
0635           desc, baseName + "_ScintAssembly" + _toString(sl_params[i].layer_ID, "_layer_%d"),
0636           layer_num, mod_params.mod_height, mod_params.mod_width, mod_params.mod_TWThick,
0637           mod_params.mod_SWThick, sl_params[i].slice_thick, mod_params.mod_notchDepth,
0638           mod_params.mod_foilThick, slice_mat, sl_params[i].slice_readoutLayer,
0639           sl_params[i].slice_regStr, sl_params[i].slice_limStr, sl_params[i].slice_visStr, sens,
0640           renderComp);
0641       // Placing slice within layer
0642       pvm = vol_mod.placeVolume(
0643           modScintAssembly, Transform3D(RotationZYX(0, 0, 0),
0644                                         Position((mod_params.mod_notchDepth) / 2., 0, slice_z)));
0645     }
0646     slice_z += sl_params[i].slice_thick / 2.;
0647   }
0648 
0649   // placement 8M module casing
0650   pvm = vol_mod.placeVolume(vol_mountingPlate,
0651                             Position(0, 0, -(length - mod_params.mod_MPThick) / 2.));
0652   pvm = vol_mod.placeVolume(
0653       vol_modFrontPlate,
0654       Position(0, 0, -(length - mod_params.mod_FWThick) / 2. + mod_params.mod_MPThick));
0655   if (allSen)
0656     pvm.addPhysVolID("towerx", 2)
0657         .addPhysVolID("towery", 0)
0658         .addPhysVolID("layerz", 0)
0659         .addPhysVolID("passive", 1);
0660   pvm =
0661       vol_mod.placeVolume(vol_modBackPlate, Position(0, 0, (length - mod_params.mod_BWThick) / 2.));
0662   if (allSen)
0663     pvm.addPhysVolID("towerx", 2)
0664         .addPhysVolID("towery", 0)
0665         .addPhysVolID("layerz", layer_num)
0666         .addPhysVolID("passive", 1);
0667   pvm = vol_mod.placeVolume(
0668       vol_modSidePlateL,
0669       Position(-(mod_params.mod_width - mod_params.mod_SWThick) / 2., 0,
0670                (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2));
0671   if (allSen)
0672     pvm.addPhysVolID("towerx", 3)
0673         .addPhysVolID("towery", 0)
0674         .addPhysVolID("layerz", 0)
0675         .addPhysVolID("passive", 1);
0676   pvm = vol_mod.placeVolume(
0677       vol_modSidePlateR,
0678       Position((mod_params.mod_width - mod_params.mod_SWThick) / 2., 0,
0679                (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2));
0680   if (allSen)
0681     pvm.addPhysVolID("towerx", 0)
0682         .addPhysVolID("towery", 1)
0683         .addPhysVolID("layerz", 0)
0684         .addPhysVolID("passive", 1);
0685   pvm = vol_mod.placeVolume(
0686       vol_modTopPlate,
0687       Position(0, (mod_params.mod_height - mod_params.mod_TWThick) / 2.,
0688                (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2));
0689   if (allSen)
0690     pvm.addPhysVolID("towerx", 1)
0691         .addPhysVolID("towery", 1)
0692         .addPhysVolID("layerz", 0)
0693         .addPhysVolID("passive", 1);
0694   pvm = vol_mod.placeVolume(
0695       vol_modBottomPlate,
0696       Position(0, -(mod_params.mod_height - mod_params.mod_TWThick) / 2.,
0697                (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2));
0698   if (allSen)
0699     pvm.addPhysVolID("towerx", 2)
0700         .addPhysVolID("towery", 1)
0701         .addPhysVolID("layerz", 0)
0702         .addPhysVolID("passive", 1);
0703 
0704   double lengthA =
0705       length - mod_params.mod_FWThick - mod_params.mod_MPThick + mod_params.mod_BWThick / 2;
0706   double z_offSetPCB =
0707       (mod_params.mod_FWThick + mod_params.mod_MPThick + mod_params.mod_BWThick) / 2 -
0708       (lengthA - mod_params.mod_pcbLength) / 2.;
0709 
0710   pvm = vol_mod.placeVolume(
0711       vol_modPCB,
0712       Position(-(mod_params.mod_width - 2 * mod_params.mod_SWThick - mod_params.mod_notchDepth) /
0713                    2.,
0714                0, z_offSetPCB));
0715 
0716   return vol_mod;
0717 }
0718 
0719 //************************************************************************************************************
0720 //************************** create 8M module assembly  ******************************************************
0721 //************************************************************************************************************
0722 Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params,
0723                          std::vector<sliceParamsStrct> sl_params,
0724                          //                               int modID,
0725                          double length, SensitiveDetector sens, bool renderComp, bool allSen) {
0726 
0727   std::string baseName = "LFHCAL_4M";
0728 
0729   // assembly definition
0730   Box modBox(mod_params.mod_width / 2., mod_params.mod_height / 2., length / 2.);
0731   Volume vol_mod(baseName, modBox, desc.material("Air"));
0732   printout(DEBUG, "LFHCAL_geo", "visualization string module: " + mod_params.mod_visStr);
0733   vol_mod.setVisAttributes(desc.visAttributes(mod_params.mod_visStr.data()));
0734 
0735   // placement operator
0736   PlacedVolume pvm;
0737   // ********************************************************************************
0738   // Casing definition
0739   // ********************************************************************************
0740   // geom definition 8M module casing
0741   Box MountingPlate(mod_params.mod_width / 2., mod_params.mod_height / 2.,
0742                     mod_params.mod_MPThick / 2.);
0743   Box modFrontPlate(mod_params.mod_width / 2., mod_params.mod_height / 2.,
0744                     mod_params.mod_FWThick / 2.);
0745   Box modSidePlateL(
0746       mod_params.mod_SWThick / 2., mod_params.mod_height / 2.,
0747       (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.);
0748   Box modSidePlateR(
0749       mod_params.mod_SWThick / 2., mod_params.mod_height / 2.,
0750       (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.);
0751   Box modTopPlate(
0752       (mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., mod_params.mod_TWThick / 2.,
0753       (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.);
0754   Box modBottomPlate(
0755       (mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., mod_params.mod_TWThick / 2.,
0756       (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.);
0757   Box modBackCutOut(mod_params.mod_BIwidth / 2., mod_params.mod_BIheight / 2.,
0758                     mod_params.mod_BWThick / 2.);
0759   Box modBackPlateFull(mod_params.mod_width / 2., mod_params.mod_height / 2.,
0760                        mod_params.mod_BWThick / 2.);
0761   SubtractionSolid modBackPlate(modBackPlateFull, modBackCutOut);
0762 
0763   // volume definition 8M module casing
0764   Volume vol_mountingPlate(baseName + "_MountingPlate", MountingPlate, desc.material("Steel235"));
0765   Volume vol_modFrontPlate(baseName + "_FrontPlate", modFrontPlate, desc.material("Steel235"));
0766   Volume vol_modBackPlate(baseName + "_BackPlate", modBackPlate, desc.material("Steel235"));
0767   Volume vol_modSidePlateL(baseName + "_LeftSidePlate", modSidePlateL, desc.material("Steel235"));
0768   Volume vol_modSidePlateR(baseName + "_RightSidePlate", modSidePlateR, desc.material("Steel235"));
0769   Volume vol_modTopPlate(baseName + "_TopPlate", modTopPlate, desc.material("Steel235"));
0770   Volume vol_modBottomPlate(baseName + "_BottomPlate", modBottomPlate, desc.material("Steel235"));
0771 
0772   if (allSen) {
0773     sens.setType("calorimeter");
0774     vol_mountingPlate.setSensitiveDetector(sens);
0775     vol_modFrontPlate.setSensitiveDetector(sens);
0776     vol_modBackPlate.setSensitiveDetector(sens);
0777     vol_modSidePlateL.setSensitiveDetector(sens);
0778     vol_modSidePlateR.setSensitiveDetector(sens);
0779     vol_modTopPlate.setSensitiveDetector(sens);
0780     vol_modBottomPlate.setSensitiveDetector(sens);
0781   }
0782 
0783   if (renderComp) {
0784     vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0785                                     // mod_params.mod_visStr);
0786                                     "LFHCALLayerTungstenVis");
0787     vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0788                                     // mod_params.mod_visStr);
0789                                     "LFHCALLayerSteelVis");
0790     vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0791                                    // mod_params.mod_visStr);
0792                                    "LFHCALLayerSteelVis");
0793     vol_modSidePlateL.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0794                                     mod_params.mod_visStr);
0795     vol_modSidePlateR.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0796                                     mod_params.mod_visStr);
0797     vol_modTopPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0798                                   // mod_params.mod_visStr);
0799                                   "LFHCALLayerSteelVis");
0800     vol_modBottomPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0801                                      // mod_params.mod_visStr);
0802                                      "LFHCALLayerSteelVis");
0803   } else {
0804     vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0805                                     "InvisibleNoDaughters");
0806     vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0807                                     "InvisibleNoDaughters");
0808     vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0809                                    "InvisibleNoDaughters");
0810     vol_modSidePlateL.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0811                                     "InvisibleNoDaughters");
0812     vol_modSidePlateR.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0813                                     "InvisibleNoDaughters");
0814     vol_modTopPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0815                                   "InvisibleNoDaughters");
0816     vol_modBottomPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0817                                      "InvisibleNoDaughters");
0818   }
0819 
0820   // ********************************************************************************
0821   // long PCB
0822   // ********************************************************************************
0823   Box modPCB(mod_params.mod_pcbThick / 2., mod_params.mod_pcbWidth / 2.,
0824              (mod_params.mod_pcbLength) / 2.);
0825   Volume vol_modPCB(baseName + "_PCB", modPCB, desc.material("Fr4"));
0826   if (renderComp) {
0827     vol_modPCB.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, "LFHCALModPCB");
0828   } else {
0829     vol_modPCB.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
0830                              "InvisibleNoDaughters");
0831   }
0832 
0833   int layer_num  = 0;
0834   double slice_z = -length / 2 + mod_params.mod_MPThick +
0835                    mod_params.mod_FWThick; // Keeps track of layers' local z locations
0836 
0837   // Looping through the number of repeated layers & slices in each section
0838   for (int i = 0; i < (int)sl_params.size(); i++) {
0839     slice_z += sl_params[i].slice_offset +
0840                sl_params[i].slice_thick / 2.; // Going to halfway point in layer
0841     layer_num = sl_params[i].layer_ID;
0842     //*************************************************
0843     // absorber plates
0844     //*************************************************
0845     Material slice_mat = desc.material(sl_params[i].slice_matStr);
0846     if (sl_params[i].slice_partID == 1) {
0847       Volume modAbsAssembly = createAbsorberPlate(
0848           desc, baseName + "_Abs" + _toString(sl_params[i].layer_ID, "_layer_%d"),
0849           mod_params.mod_height, mod_params.mod_width, mod_params.mod_TWThick,
0850           mod_params.mod_SWThick, sl_params[i].slice_thick, mod_params.mod_notchDepth,
0851           mod_params.mod_notchHeight, slice_mat, sl_params[i].slice_regStr,
0852           sl_params[i].slice_limStr, sl_params[i].slice_visStr, renderComp);
0853       // Placing slice within layer
0854       if (allSen)
0855         modAbsAssembly.setSensitiveDetector(sens);
0856       pvm = vol_mod.placeVolume(modAbsAssembly,
0857                                 Transform3D(RotationZYX(0, 0, 0), Position(0., 0., slice_z)));
0858       if (allSen)
0859         pvm.addPhysVolID("towerx", 0)
0860             .addPhysVolID("towery", 0)
0861             .addPhysVolID("rlayerz", sl_params[i].slice_readoutLayer)
0862             .addPhysVolID("layerz", layer_num)
0863             .addPhysVolID("passive", 1);
0864       //*************************************************
0865       // air & kapton & PCB & ESR
0866       //*************************************************
0867     } else if (sl_params[i].slice_partID == 2) {
0868       Volume modFillAssembly =
0869           createFillerPlate(desc,
0870                             baseName + "_Fill" + _toString(sl_params[i].layer_ID, "_layer_%d") +
0871                                 _toString(sl_params[i].slice_ID, "slice_%d"),
0872                             mod_params.mod_height, mod_params.mod_width, mod_params.mod_TWThick,
0873                             mod_params.mod_SWThick, sl_params[i].slice_thick,
0874                             mod_params.mod_notchDepth, slice_mat, sl_params[i].slice_regStr,
0875                             sl_params[i].slice_limStr, sl_params[i].slice_visStr, renderComp);
0876       // Placing slice within layer
0877       if (allSen)
0878         modFillAssembly.setSensitiveDetector(sens);
0879       pvm = vol_mod.placeVolume(
0880           modFillAssembly, Transform3D(RotationZYX(0, 0, 0),
0881                                        Position((mod_params.mod_notchDepth) / 2., 0., slice_z)));
0882       if (allSen)
0883         pvm.addPhysVolID("towerx", 1)
0884             .addPhysVolID("towery", 0)
0885             .addPhysVolID("rlayerz", sl_params[i].slice_readoutLayer)
0886             .addPhysVolID("layerz", layer_num)
0887             .addPhysVolID("passive", 1);
0888       //*************************************************
0889       // scintillator
0890       //*************************************************
0891     } else {
0892       Assembly modScintAssembly = createScintillatorPlateFourM(
0893           desc, baseName + "_ScintAssembly" + _toString(sl_params[i].layer_ID, "_layer_%d"),
0894           layer_num, mod_params.mod_height, mod_params.mod_width, mod_params.mod_TWThick,
0895           mod_params.mod_SWThick, sl_params[i].slice_thick, mod_params.mod_notchDepth,
0896           mod_params.mod_foilThick, slice_mat, sl_params[i].slice_readoutLayer,
0897           sl_params[i].slice_regStr, sl_params[i].slice_limStr, sl_params[i].slice_visStr, sens,
0898           renderComp);
0899       // Placing slice within layer
0900       pvm = vol_mod.placeVolume(
0901           modScintAssembly, Transform3D(RotationZYX(0, 0, 0),
0902                                         Position((mod_params.mod_notchDepth) / 2., 0, slice_z)));
0903     }
0904     slice_z += sl_params[i].slice_thick / 2.;
0905   }
0906 
0907   // placement 4M module casing
0908   pvm = vol_mod.placeVolume(vol_mountingPlate,
0909                             Position(0, 0, -(length - mod_params.mod_MPThick) / 2.));
0910   pvm = vol_mod.placeVolume(
0911       vol_modFrontPlate,
0912       Position(0, 0, -(length - mod_params.mod_FWThick) / 2. + mod_params.mod_MPThick));
0913   if (allSen)
0914     pvm.addPhysVolID("towerx", 2)
0915         .addPhysVolID("towery", 0)
0916         .addPhysVolID("layerz", 0)
0917         .addPhysVolID("passive", 1);
0918   pvm =
0919       vol_mod.placeVolume(vol_modBackPlate, Position(0, 0, (length - mod_params.mod_BWThick) / 2.));
0920   if (allSen)
0921     pvm.addPhysVolID("towerx", 2)
0922         .addPhysVolID("towery", 0)
0923         .addPhysVolID("layerz", layer_num)
0924         .addPhysVolID("passive", 1);
0925   pvm = vol_mod.placeVolume(
0926       vol_modSidePlateL,
0927       Position(-(mod_params.mod_width - mod_params.mod_SWThick) / 2., 0,
0928                (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2));
0929   if (allSen)
0930     pvm.addPhysVolID("towerx", 3)
0931         .addPhysVolID("towery", 0)
0932         .addPhysVolID("layerz", 0)
0933         .addPhysVolID("passive", 1);
0934   pvm = vol_mod.placeVolume(
0935       vol_modSidePlateR,
0936       Position((mod_params.mod_width - mod_params.mod_SWThick) / 2., 0,
0937                (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2));
0938   if (allSen)
0939     pvm.addPhysVolID("towerx", 0)
0940         .addPhysVolID("towery", 1)
0941         .addPhysVolID("layerz", 0)
0942         .addPhysVolID("passive", 1);
0943   pvm = vol_mod.placeVolume(
0944       vol_modTopPlate,
0945       Position(0, (mod_params.mod_height - mod_params.mod_TWThick) / 2.,
0946                (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2));
0947   if (allSen)
0948     pvm.addPhysVolID("towerx", 1)
0949         .addPhysVolID("towery", 1)
0950         .addPhysVolID("layerz", 0)
0951         .addPhysVolID("passive", 1);
0952   pvm = vol_mod.placeVolume(
0953       vol_modBottomPlate,
0954       Position(0, -(mod_params.mod_height - mod_params.mod_TWThick) / 2.,
0955                (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2));
0956   if (allSen)
0957     pvm.addPhysVolID("towerx", 2)
0958         .addPhysVolID("towery", 1)
0959         .addPhysVolID("layerz", 0)
0960         .addPhysVolID("passive", 1);
0961 
0962   double lengthA =
0963       length - mod_params.mod_FWThick - mod_params.mod_MPThick + mod_params.mod_BWThick / 2;
0964   double z_offSetPCB =
0965       (mod_params.mod_FWThick + mod_params.mod_MPThick + mod_params.mod_BWThick) / 2 -
0966       (lengthA - mod_params.mod_pcbLength) / 2.;
0967 
0968   pvm = vol_mod.placeVolume(
0969       vol_modPCB,
0970       Position(-(mod_params.mod_width - 2 * mod_params.mod_SWThick - mod_params.mod_notchDepth) /
0971                    2.,
0972                0, z_offSetPCB));
0973   return vol_mod;
0974 }
0975 
0976 //********************************************************************************************
0977 //*                                                                                          *
0978 //*                              Create detector                                             *
0979 //==============================  MAIN FUNCTION  =============================================
0980 //*                                                                                          *
0981 //********************************************************************************************
0982 static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens) {
0983   // global detector variables
0984   xml_det_t detElem   = handle;
0985   std::string detName = detElem.nameStr();
0986   int detID           = detElem.id();
0987 
0988   // general detector dimensions
0989   xml_dim_t dim = detElem.dimensions();
0990   double length = dim.z(); // Size along z-axis
0991 
0992   // general detector position
0993   xml_dim_t pos = detElem.position();
0994   printout(DEBUG, "LFHCAL_geo",
0995            "global LFHCal position " + _toString(pos.x()) + "\t" + _toString(pos.y()) + "\t" +
0996                _toString(pos.z()));
0997 
0998   // envelope volume
0999   xml_comp_t x_env = detElem.child(_Unicode(envelope));
1000   Tube rmaxtube(0, dim.rmax(), dim.z() / 2);
1001   Box beampipe(dim.x() / 2, dim.y() / 2, dim.z() / 2);
1002   Solid env = SubtractionSolid(rmaxtube, beampipe, Position(dim.x0(), 0, 0));
1003   Volume env_vol(detName + "_env", env, desc.material(x_env.materialStr()));
1004 
1005   bool renderComponents = getAttrOrDefault(detElem, _Unicode(renderComponents), 0.);
1006   bool allSensitive     = getAttrOrDefault(detElem, _Unicode(allSensitive), 0.);
1007   if (renderComponents) {
1008     printout(DEBUG, "LFHCAL_geo", "enabled visualization");
1009   } else {
1010     printout(DEBUG, "LFHCAL_geo", "switchted off visualization");
1011   }
1012 
1013   // 8M module specific loading
1014   xml_comp_t eightM_xml   = detElem.child(_Unicode(eightmodule));
1015   xml_dim_t eightMmod_dim = eightM_xml.dimensions();
1016   moduleParamsStrct eightM_params(
1017       getAttrOrDefault(eightMmod_dim, _Unicode(widthBackInner), 0.),
1018       getAttrOrDefault(eightMmod_dim, _Unicode(heightBackInner), 0.),
1019       getAttrOrDefault(eightMmod_dim, _Unicode(widthSideWall), 0.),
1020       getAttrOrDefault(eightMmod_dim, _Unicode(widthTopWall), 0.),
1021       getAttrOrDefault(eightMmod_dim, _Unicode(thicknessMountingPlate), 0.),
1022       getAttrOrDefault(eightMmod_dim, _Unicode(thicknessFrontWall), 0.),
1023       getAttrOrDefault(eightMmod_dim, _Unicode(thicknessBackWall), 0.),
1024       getAttrOrDefault(eightMmod_dim, _Unicode(width), 0.),
1025       getAttrOrDefault(eightMmod_dim, _Unicode(height), 0.),
1026       getAttrOrDefault(eightMmod_dim, _Unicode(notchDepth), 0.),
1027       getAttrOrDefault(eightMmod_dim, _Unicode(notchHeight), 0.),
1028       getAttrOrDefault(eightMmod_dim, _Unicode(foilThick), 0.),
1029       getAttrOrDefault(eightMmod_dim, _Unicode(pcbLength), 0.),
1030       getAttrOrDefault(eightMmod_dim, _Unicode(pcbThick), 0.),
1031       getAttrOrDefault(eightMmod_dim, _Unicode(pcbWidth), 0.), eightM_xml.visStr(),
1032       eightM_xml.regionStr(), eightM_xml.limitsStr());
1033 
1034   // 4M module specific loading
1035   xml_comp_t fourM_xml   = detElem.child(_Unicode(fourmodule));
1036   xml_dim_t fourMmod_dim = fourM_xml.dimensions();
1037   moduleParamsStrct fourM_params(
1038       getAttrOrDefault(fourMmod_dim, _Unicode(widthBackInner), 0.),
1039       getAttrOrDefault(fourMmod_dim, _Unicode(heightBackInner), 0.),
1040       getAttrOrDefault(fourMmod_dim, _Unicode(widthSideWall), 0.),
1041       getAttrOrDefault(fourMmod_dim, _Unicode(widthTopWall), 0.),
1042       getAttrOrDefault(fourMmod_dim, _Unicode(thicknessMountingPlate), 0.),
1043       getAttrOrDefault(fourMmod_dim, _Unicode(thicknessFrontWall), 0.),
1044       getAttrOrDefault(fourMmod_dim, _Unicode(thicknessBackWall), 0.),
1045       getAttrOrDefault(fourMmod_dim, _Unicode(width), 0.),
1046       getAttrOrDefault(fourMmod_dim, _Unicode(height), 0.),
1047       getAttrOrDefault(fourMmod_dim, _Unicode(notchDepth), 0.),
1048       getAttrOrDefault(fourMmod_dim, _Unicode(notchHeight), 0.),
1049       getAttrOrDefault(fourMmod_dim, _Unicode(foilThick), 0.),
1050       getAttrOrDefault(fourMmod_dim, _Unicode(pcbLength), 0.),
1051       getAttrOrDefault(fourMmod_dim, _Unicode(pcbThick), 0.),
1052       getAttrOrDefault(fourMmod_dim, _Unicode(pcbWidth), 0.), fourM_xml.visStr(),
1053       fourM_xml.regionStr(), fourM_xml.limitsStr());
1054 
1055   std::vector<sliceParamsStrct> slice_Params;
1056   int layer_num  = 0;
1057   int readLayerC = 0;
1058   for (xml_coll_t c(detElem, _U(layer)); c; ++c) {
1059     xml_comp_t x_layer = c;
1060     int repeat         = x_layer.repeat();
1061     int readlayer      = getAttrOrDefault(x_layer, _Unicode(readoutlayer), 0.);
1062     if (readLayerC != readlayer) {
1063       readLayerC = readlayer;
1064       layer_num  = 0;
1065     }
1066     // Looping through the number of repeated layers in each section
1067     for (int i = 0; i < repeat; i++) {
1068       int slice_num = 0;
1069 
1070       // Looping over each layer's slices
1071       for (xml_coll_t l(x_layer, _U(slice)); l; ++l) {
1072         xml_comp_t x_slice = l;
1073         sliceParamsStrct slice_param(layer_num, slice_num, getAttrOrDefault(l, _Unicode(type), 0.),
1074                                      x_slice.thickness(), getAttrOrDefault(l, _Unicode(offset), 0.),
1075                                      readlayer, x_slice.materialStr(), x_slice.visStr(),
1076                                      x_slice.regionStr(), x_slice.limitsStr());
1077         slice_Params.push_back(slice_param);
1078         ++slice_num;
1079       }
1080       layer_num++;
1081     }
1082   }
1083 
1084   // create mother volume
1085   DetElement det(detName, detID);
1086   Assembly assembly(detName);
1087   PlacedVolume phv;
1088 
1089   int moduleIDx = -1;
1090   int moduleIDy = -1;
1091 
1092   struct position {
1093     double x, y, z;
1094   };
1095 
1096   std::vector<position> pos8M;
1097 
1098   xml_coll_t eightMPos(detElem, _Unicode(eightmodulepositions));
1099   for (xml_coll_t position_i(eightMPos, _U(position)); position_i; ++position_i) {
1100     xml_comp_t position_comp = position_i;
1101     if (!getAttrOrDefault(position_comp, _Unicode(if), true)) {
1102       printout(DEBUG, "LFHCAL_geo", "skipping x = %.1f cm, y = %.1f cm", position_comp.x(),
1103                position_comp.y());
1104       continue;
1105     }
1106     pos8M.push_back({position_comp.x(), position_comp.y(), position_comp.z()});
1107   }
1108 
1109   // create 8M modules
1110   Volume eightMassembly = createEightMModule(desc, eightM_params, slice_Params, length, sens,
1111                                              renderComponents, allSensitive);
1112   for (int e = 0; e < (int)pos8M.size(); e++) {
1113     if (e % 20 == 0)
1114       printout(DEBUG, "LFHCAL_geo",
1115                "LFHCAL placing 8M module: " + _toString(e) + "/" + _toString((int)pos8M.size()) +
1116                    "\t" + _toString(pos8M[e].x) + "\t" + _toString(pos8M[e].y) + "\t" +
1117                    _toString(pos8M[e].z));
1118     if (moduleIDx < 0 || moduleIDy < 0) {
1119       printout(DEBUG, "LFHCAL_geo",
1120                "LFHCAL WRONG ID FOR 8M module: " + _toString(e) + "/" +
1121                    _toString((int)pos8M.size()) + "\t" + _toString(moduleIDx) + "\t" +
1122                    _toString(moduleIDy));
1123     }
1124     moduleIDx = ((pos8M[e].x + 270) / 10);
1125     moduleIDy = ((pos8M[e].y + 265) / 10);
1126 
1127     // Placing modules in world volume
1128     auto tr8M = Transform3D(Position(-pos8M[e].x, -pos8M[e].y, pos8M[e].z));
1129     phv       = assembly.placeVolume(eightMassembly, tr8M);
1130     phv.addPhysVolID("moduleIDx", moduleIDx)
1131         .addPhysVolID("moduleIDy", moduleIDy)
1132         .addPhysVolID("moduletype", 0);
1133   }
1134 
1135   std::vector<position> pos4M;
1136 
1137   xml_coll_t fourMPos(detElem, _Unicode(fourmodulepositions));
1138   for (xml_coll_t position_i(fourMPos, _U(position)); position_i; ++position_i) {
1139     xml_comp_t position_comp = position_i;
1140     if (!getAttrOrDefault(position_comp, _Unicode(if), true)) {
1141       printout(DEBUG, "LFHCAL_geo", "skipping x = %.1f cm, y = %.1f cm", position_comp.x(),
1142                position_comp.y());
1143       continue;
1144     }
1145     pos4M.push_back({position_comp.x(), position_comp.y(), position_comp.z()});
1146   }
1147 
1148   // create 4M modules
1149   Volume fourMassembly = createFourMModule(desc, fourM_params, slice_Params, length, sens,
1150                                            renderComponents, allSensitive);
1151   for (int f = 0; f < (int)pos4M.size(); f++) {
1152     if (f % 20 == 0)
1153       printout(DEBUG, "LFHCAL_geo",
1154                "LFHCAL placing 4M module: " + _toString(f) + "/" + _toString((int)pos4M.size()) +
1155                    "\t" + _toString(pos4M[f].x) + "\t" + _toString(pos4M[f].y) + "\t" +
1156                    _toString(pos4M[f].z));
1157 
1158     moduleIDx = ((pos4M[f].x + 265) / 10);
1159     moduleIDy = ((pos4M[f].y + 265) / 10);
1160     if (moduleIDx < 0 || moduleIDy < 0) {
1161       printout(DEBUG, "LFHCAL_geo",
1162                "LFHCAL WRONG ID FOR 4M module: " + _toString(f) + "/" +
1163                    _toString((int)pos4M.size()) + "\t" + _toString(moduleIDx) + "\t" +
1164                    _toString(moduleIDy));
1165     }
1166     auto tr4M = Transform3D(Position(-pos4M[f].x, -pos4M[f].y, pos4M[f].z));
1167     phv       = assembly.placeVolume(fourMassembly, tr4M);
1168     phv.addPhysVolID("moduleIDx", moduleIDx)
1169         .addPhysVolID("moduleIDy", moduleIDy)
1170         .addPhysVolID("moduletype", 1);
1171   }
1172 
1173   Volume motherVol = desc.pickMotherVolume(det);
1174   phv              = env_vol.placeVolume(assembly);
1175   phv              = motherVol.placeVolume(env_vol,
1176                                            Transform3D(Position(pos.x(), pos.y(), pos.z() + length / 2.)));
1177   phv.addPhysVolID("system", detID);
1178   det.setPlacement(phv);
1179 
1180   return det;
1181 }
1182 DECLARE_DETELEMENT(epic_LFHCAL, createDetector)