Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-13 08:27:12

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2022 Sakib Rahman, Whitney Armstrong
0003 
0004 #include <vector>
0005 #include <functional>
0006 
0007 #include "DD4hep/DetFactoryHelper.h"
0008 #include "DD4hep/OpticalSurfaces.h"
0009 #include "DD4hep/Printout.h"
0010 #include "DDRec/DetectorData.h"
0011 #include "DDRec/Surface.h"
0012 #include "Math/Point2D.h"
0013 #include <XML/Helper.h>
0014 #include <XML/Utilities.h>
0015 
0016 //////////////////////////////////////////////////
0017 // Far Forward B0 Electromagnetic Calorimeter
0018 //////////////////////////////////////////////////
0019 
0020 using std::make_tuple;
0021 using std::map;
0022 using std::string;
0023 using std::tuple;
0024 using std::vector;
0025 using namespace dd4hep;
0026 
0027 static tuple<Volume, Position> build_module(Detector& desc, xml_coll_t& plm,
0028                                             SensitiveDetector& sens);
0029 static tuple<int, int> add_individuals(
0030     std::function<tuple<Volume, Position>(Detector&, xml_coll_t&, SensitiveDetector&)> build_module,
0031     Detector& desc, Assembly& env, xml_coll_t& plm, SensitiveDetector& sens, int sid);
0032 
0033 static Ref_t createDetector(Detector& desc, xml_h e, SensitiveDetector sens) {
0034   xml_det_t x_det = e;
0035   string detName  = x_det.nameStr();
0036   int detID       = x_det.id();
0037   DetElement det(detName, detID);
0038   sens.setType("calorimeter");
0039 
0040   // apply any detector type flags set in XML
0041   dd4hep::xml::setDetectorTypeFlag(x_det, det);
0042 
0043   // assembly
0044   Assembly detVol(detName);
0045 
0046   xml_dim_t pos = x_det.position();
0047   xml_dim_t rot = x_det.rotation();
0048 
0049   // module placement
0050   xml_comp_t plm = x_det.child(_Unicode(placements));
0051   map<int, int> sectorModuleNumbers;
0052   auto addModuleNumbers = [&sectorModuleNumbers](int sector, int nmod) {
0053     auto it = sectorModuleNumbers.find(sector);
0054     if (it != sectorModuleNumbers.end()) {
0055       it->second += nmod;
0056     } else {
0057       sectorModuleNumbers[sector] = nmod;
0058     }
0059   };
0060 
0061   int sector_id = 1;
0062 
0063   for (xml_coll_t mod(plm, _Unicode(individuals)); mod; ++mod) {
0064     auto [sector, nmod] = add_individuals(build_module, desc, detVol, mod, sens, sector_id++);
0065     addModuleNumbers(sector, nmod);
0066   }
0067 
0068   // position and rotation of parent volume
0069   Volume motherVol = desc.pickMotherVolume(det);
0070   Transform3D tr(RotationZYX(rot.z(), rot.y(), rot.x()), Position(pos.x(), pos.y(), pos.z()));
0071   PlacedVolume detPV = motherVol.placeVolume(detVol, tr);
0072   detPV.addPhysVolID("system", detID);
0073   det.setPlacement(detPV);
0074   return det;
0075 }
0076 
0077 // helper function to build module with or w/o wrapper
0078 static tuple<Volume, Position> build_module(Detector& desc, xml::Collection_t& plm,
0079                                             SensitiveDetector& sens) {
0080   auto mod = plm.child(_Unicode(module));
0081   auto sx  = mod.attr<double>(_Unicode(sizex));
0082   auto sy  = mod.attr<double>(_Unicode(sizey));
0083   auto sz  = mod.attr<double>(_Unicode(sizez));
0084   Box modShape(sx / 2., sy / 2., sz / 2.);
0085   auto modMat = desc.material(mod.attr<string>(_Unicode(material)));
0086   Volume modVol("module_vol", modShape, modMat);
0087   modVol.setSensitiveDetector(sens);
0088   modVol.setVisAttributes(desc.visAttributes(mod.attr<string>(_Unicode(vis))));
0089 
0090   // no wrapper
0091   if (!plm.hasChild(_Unicode(wrapper))) {
0092     return make_tuple(modVol, Position{sx, sy, sz});
0093     // build wrapper
0094   } else {
0095     auto wrp       = plm.child(_Unicode(wrapper));
0096     auto thickness = wrp.attr<double>(_Unicode(thickness));
0097     if (thickness < 1e-12 * mm) {
0098       return make_tuple(modVol, Position{sx, sy, sz});
0099     }
0100     auto wrpMat = desc.material(wrp.attr<string>(_Unicode(material)));
0101     Box wrpShape((sx + thickness) / 2., (sy + thickness) / 2., sz / 2.);
0102     Volume wrpVol("wrapper_vol", wrpShape, wrpMat);
0103     wrpVol.placeVolume(modVol, Position(0., 0., 0.));
0104     wrpVol.setVisAttributes(desc.visAttributes(wrp.attr<string>(_Unicode(vis))));
0105     return make_tuple(wrpVol, Position{sx + thickness, sy + thickness, sz});
0106   }
0107 }
0108 
0109 // place modules, id must be provided
0110 static tuple<int, int> add_individuals(
0111     std::function<tuple<Volume, Position>(Detector&, xml_coll_t&, SensitiveDetector&)> build_module,
0112     Detector& desc, Assembly& env, xml_coll_t& plm, SensitiveDetector& sens, int sid) {
0113   auto [modVol, modSize] = build_module(desc, plm, sens);
0114   int sector_id          = dd4hep::getAttrOrDefault<int>(plm, _Unicode(sector), sid);
0115   int nmodules           = 0;
0116   for (xml_coll_t pl(plm, _Unicode(placement)); pl; ++pl) {
0117     Position pos(dd4hep::getAttrOrDefault<double>(pl, _Unicode(x), 0.),
0118                  dd4hep::getAttrOrDefault<double>(pl, _Unicode(y), 0.),
0119                  dd4hep::getAttrOrDefault<double>(pl, _Unicode(z), 0.));
0120     Position rot(dd4hep::getAttrOrDefault<double>(pl, _Unicode(rotx), 0.),
0121                  dd4hep::getAttrOrDefault<double>(pl, _Unicode(roty), 0.),
0122                  dd4hep::getAttrOrDefault<double>(pl, _Unicode(rotz), 0.));
0123     auto mid = pl.attr<int>(_Unicode(id));
0124     Transform3D tr =
0125         Translation3D(pos.x(), pos.y(), pos.z()) * RotationZYX(rot.z(), rot.y(), rot.x());
0126     auto modPV = env.placeVolume(modVol, tr);
0127     modPV.addPhysVolID("sector", sector_id).addPhysVolID("module", mid);
0128     nmodules++;
0129   }
0130 
0131   return {sector_id, nmodules};
0132 }
0133 
0134 DECLARE_DETELEMENT(B0_ECAL, createDetector)