File indexing completed on 2025-01-18 09:15:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include "DD4hep/DetFactoryHelper.h"
0014 #include "GeometryHelpers.h"
0015 #include <XML/Helper.h>
0016 #include <algorithm>
0017 #include <iostream>
0018 #include <math.h>
0019 #include <tuple>
0020
0021 using namespace dd4hep;
0022 using Point = ROOT::Math::XYPoint;
0023
0024 std::tuple<Volume, Position> build_module(const Detector& desc, const xml::Component& mod_x,
0025 SensitiveDetector& sens);
0026
0027
0028 template <class XmlComp> Position get_xml_xyz(const XmlComp& comp, dd4hep::xml::Strng_t name) {
0029 Position pos(0., 0., 0.);
0030 if (comp.hasChild(name)) {
0031 auto child = comp.child(name);
0032 pos.SetX(dd4hep::getAttrOrDefault<double>(child, _Unicode(x), 0.));
0033 pos.SetY(dd4hep::getAttrOrDefault<double>(child, _Unicode(y), 0.));
0034 pos.SetZ(dd4hep::getAttrOrDefault<double>(child, _Unicode(z), 0.));
0035 }
0036 return pos;
0037 }
0038
0039
0040 static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDetector sens) {
0041 xml::DetElement detElem = handle;
0042 std::string detName = detElem.nameStr();
0043 int detID = detElem.id();
0044 DetElement det(detName, detID);
0045 sens.setType("calorimeter");
0046 auto dim = detElem.dimensions();
0047 auto rmin = dim.rmin();
0048 auto rmax = dim.rmax();
0049 auto length = dim.length();
0050 auto phimin = dd4hep::getAttrOrDefault<double>(dim, _Unicode(phimin), 0.);
0051 auto phimax = dd4hep::getAttrOrDefault<double>(dim, _Unicode(phimax), 2. * M_PI);
0052
0053 Tube envShape(rmin, rmax, length / 2., phimin, phimax);
0054 Volume env(detName + "_envelope", envShape, desc.material("Air"));
0055 env.setVisAttributes(desc.visAttributes(detElem.visStr()));
0056
0057
0058 auto [modVol, modSize] = build_module(desc, detElem.child(_Unicode(module)), sens);
0059 double modSizeR = std::sqrt(modSize.x() * modSize.x() + modSize.y() * modSize.y());
0060 double assembly_rwidth = modSizeR * 2.;
0061 int nas = int((rmax - rmin) / assembly_rwidth) + 1;
0062 std::vector<Assembly> assemblies;
0063
0064 const double block_offset = -0.5 * (length - modSize.z());
0065 for (int i = 0; i < nas; ++i) {
0066 Assembly assembly(detName + Form("_ring%d", i + 1));
0067 auto assemblyPV = env.placeVolume(assembly, Position{0., 0., block_offset});
0068 assemblyPV.addPhysVolID("ring", i + 1);
0069 assemblies.emplace_back(std::move(assembly));
0070 }
0071
0072
0073 int modid = 1;
0074 for (int ix = 0; ix < int(2. * rmax / modSize.x()) + 1; ++ix) {
0075 double mx = modSize.x() * ix - rmax;
0076 for (int iy = 0; iy < int(2. * rmax / modSize.y()) + 1; ++iy) {
0077 double my = modSize.y() * iy - rmax;
0078 double mr = std::sqrt(mx * mx + my * my);
0079 if (mr - modSizeR >= rmin && mr + modSizeR <= rmax) {
0080 int ias = int((mr - rmin) / assembly_rwidth);
0081 auto& assembly = assemblies[ias];
0082 auto modPV = assembly.placeVolume(modVol, Position(mx, my, 0.));
0083 modPV.addPhysVolID("module", modid++);
0084 }
0085 }
0086 }
0087
0088 desc.add(Constant(detName + "_NModules", std::to_string(modid - 1)));
0089
0090 for (auto& assembly : assemblies) {
0091 assembly.ptr()->Voxelize("");
0092 }
0093
0094
0095 auto pos = get_xml_xyz(detElem, _Unicode(position));
0096 auto rot = get_xml_xyz(detElem, _Unicode(rotation));
0097 Volume motherVol = desc.pickMotherVolume(det);
0098 Transform3D tr =
0099 Translation3D(pos.x(), pos.y(), pos.z()) * RotationZYX(rot.z(), rot.y(), rot.x());
0100 PlacedVolume envPV = motherVol.placeVolume(env, tr);
0101 envPV.addPhysVolID("system", detID);
0102 det.setPlacement(envPV);
0103 return det;
0104 }
0105
0106
0107 std::tuple<Volume, Position> build_module(const Detector& desc, const xml::Component& mod_x,
0108 SensitiveDetector& sens) {
0109 auto sx = mod_x.attr<double>(_Unicode(sizex));
0110 auto sy = mod_x.attr<double>(_Unicode(sizey));
0111 auto sz = mod_x.attr<double>(_Unicode(sizez));
0112
0113 Box modShape(sx / 2., sy / 2., sz / 2.);
0114 auto modMat = desc.material(mod_x.attr<std::string>(_Unicode(material)));
0115 Volume modVol("module_vol", modShape, modMat);
0116 if (mod_x.hasAttr(_Unicode(vis))) {
0117 modVol.setVisAttributes(desc.visAttributes(mod_x.attr<std::string>(_Unicode(vis))));
0118 }
0119
0120 if (mod_x.hasChild(_Unicode(fiber))) {
0121 auto fiber_x = mod_x.child(_Unicode(fiber));
0122 auto fr = fiber_x.attr<double>(_Unicode(radius));
0123 auto fsx = fiber_x.attr<double>(_Unicode(spacex));
0124 auto fsy = fiber_x.attr<double>(_Unicode(spacey));
0125 auto foff = dd4hep::getAttrOrDefault<double>(fiber_x, _Unicode(offset), 0.5 * mm);
0126 auto fiberMat = desc.material(fiber_x.attr<std::string>(_Unicode(material)));
0127 Tube fiberShape(0., fr, sz / 2.);
0128 Volume fiberVol("fiber_vol", fiberShape, fiberMat);
0129 fiberVol.setSensitiveDetector(sens);
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147 double fside = 2. / std::sqrt(3.) * fr;
0148 double fdistx = 2. * fside + fsx;
0149 double fdisty = 2. * fr + fsy;
0150
0151
0152 int nx = int(sx / (2. * fr)) + 1;
0153 int ny = int(sy / (2. * fr)) + 1;
0154
0155
0156
0157
0158 double y0 = (foff + fside);
0159 int nfibers = 0;
0160 for (int iy = 0; iy < ny; ++iy) {
0161 double y = y0 + fdisty * iy;
0162
0163 if ((sy - y) < y0) {
0164 break;
0165 }
0166 double x0 = (iy % 2) ? (foff + fside) : (foff + fside + fdistx / 2.);
0167 for (int ix = 0; ix < nx; ++ix) {
0168 double x = x0 + fdistx * ix;
0169
0170 if ((sx - x) < x0) {
0171 break;
0172 }
0173 auto fiberPV =
0174 modVol.placeVolume(fiberVol, nfibers++, Position{x - sx / 2., y - sy / 2., 0});
0175
0176 fiberPV.addPhysVolID("fiber_x", ix + 1).addPhysVolID("fiber_y", iy + 1);
0177 }
0178 }
0179
0180 } else {
0181 modVol.setSensitiveDetector(sens);
0182 }
0183
0184 return std::make_tuple(modVol, Position{sx, sy, sz});
0185 }
0186
0187 DECLARE_DETELEMENT(epic_ScFiCalorimeter, create_detector)