diff --git a/compact/ecal_barrel_interlayers.xml b/compact/ecal_barrel_interlayers.xml index a0d3b727e6ca81ff9d7e182a8e6cdbb6d718aace..fbdf6ebedc9e3a03577ba575451dcd8c379502b8 100644 --- a/compact/ecal_barrel_interlayers.xml +++ b/compact/ecal_barrel_interlayers.xml @@ -1,8 +1,9 @@ <lccdd> <display> - <vis name="EcalBarrelEnvelope_vis" alpha="0.9" r="0.99" g="0.5" b="0" showDaughters="true" visible="false" /> - <vis name="EcalBarrelStave_vis" alpha="0.9" r="0.99" g="0.5" b="0" showDaughters="true" visible="false" /> + <vis name="EcalBarrelEnvelope_vis" alpha="0.9" r="0.99" g="0.5" b="0" showDaughters="true" visible="false" /> + <vis name="EcalBarrelStave_vis" alpha="0.9" r="0.99" g="0.5" b="0" showDaughters="true" visible="false" /> + <vis name="EcalBarrelFiberLayer_vis" alpha="0.9" r="0.1" g="0.5" b="0.5" showDaughters="false" visible="true" /> </display> <define> <comment> @@ -85,7 +86,6 @@ <dimensions numsides="EcalBarrel_ModRepeat" rmin="EcalBarrel_rmin" z="EcalBarrel_length"/> - <staves vis="EcalBarrelStave_vis"/> <layer repeat="EcalBarrelImagingLayers_num" vis="AnlBlue" space_between="EcalBarrel_ScFiLayerThickness + EcalBarrel_SpaceBetween" space_before="0.*cm"> @@ -115,18 +115,16 @@ rmin="EcalBarrel_rmin" z="EcalBarrel_length"/> <staves vis="EcalBarrelStave_vis"> - <support inside="true" material="Steel235" vis="AnlOrange" - thickness="EcalBarrel_Support_thickness" - n_beams="3" grid_size="25.0*cm" > + <support material="Steel235" vis="AnlOrange" n_beams="3" grid_size="25.0*cm" + thickness="EcalBarrel_Support_thickness" beam_thickness="EcalBarrel_Support_thickness/4" > </support> </staves> <layer repeat="EcalBarrelImagingLayers_num-1" vis="AnlBlue" space_between="EcalBarrel_ImagingLayerThickness + EcalBarrel_SpaceBetween" space_before="EcalBarrel_ImagingLayerThickness + EcalBarrel_SpaceBetween/2."> - <slice material="Lead" thickness="EcalBarrel_RadiatorThickness" vis="EcalBarrelFibersVis"> + <slice material="Lead" thickness="EcalBarrel_RadiatorThickness" vis="EcalBarrelFiberLayer_vis"> <fiber material="PlasticScint" sensitive="yes" - vis="EcalBarrelFiberVis" radius="EcalBarrel_FiberRadius" spacing_x="EcalBarrel_FiberXSpacing" spacing_z="EcalBarrel_FiberZSpacing"/> @@ -138,14 +136,12 @@ space_before="EcalBarrel_ImagingLayerThickness + EcalBarrel_SpaceBetween"> <slice material="Lead" thickness="EcalBarrel_FiberLayerThickness/EcalBarrel_FiberChunkLayers_num" - vis="EcalBarrelFiberLayerVis"> + vis="EcalBarrelFiberLayer_vis"> <fiber material="PlasticScint" sensitive="yes" - vis="EcalBarrelFiberVis" radius="EcalBarrel_FiberRadius" spacing_x="EcalBarrel_FiberXSpacing" - spacing_z="EcalBarrel_FiberZSpacing"> - </fiber> + spacing_z="EcalBarrel_FiberZSpacing"/> </slice> </layer> </detector> diff --git a/src/BarrelCalorimeterInterlayers_geo.cpp b/src/BarrelCalorimeterInterlayers_geo.cpp index 2ea9133a6a6ca55b5f9fb5ea9189cde0bf6b517f..cd5270ead5699067d5f9200647326df7dc0eae97 100644 --- a/src/BarrelCalorimeterInterlayers_geo.cpp +++ b/src/BarrelCalorimeterInterlayers_geo.cpp @@ -3,9 +3,13 @@ // Assembly is used as the envelope so two different detectors can be interlayered with each other // // -// Implementation of the Sci Fiber geometry: M. Żurek 06/19/2021 -// Support interlayers between multiple detectors: C. Peng 07/09/2021 - +// 06/19/2021: Implementation of the Sci Fiber geometry. M. Żurek +// 07/09/2021: Support interlayers between multiple detectors. C. Peng +// 07/23/2021: Add assemblies as mother volumes of fibers to reduce the number of daughter volumes. C. Peng, M. Żurek +// Reference: TGeo performance issue with large number of daughter volumes +// https://indico.cern.ch/event/967418/contributions/4075358/attachments/2128099/3583278/201009_shKo_dd4hep.pdf +// 07/24/2021: Changed support implementation to avoid too many uses of boolean geometries. DAWN view seems to have +// issue dealing with it. C. Peng #include "DD4hep/DetFactoryHelper.h" #include "XML/Layering.h" @@ -17,13 +21,17 @@ using namespace dd4hep; using namespace dd4hep::detail; typedef ROOT::Math::XYPoint Point; -// headers for helper functions, defined in BarrelCalorimeterHybrid_geo +// fiber placement helpers, defined in BarrelCalorimeterHybrid_geo vector<vector<Point>> fiberPositions(double radius, double x_spacing, double z_spacing, double x, double z, double phi, double spacing_tol = 1e-2); std::pair<int, int> getNdivisions(double x, double z, double dx, double dz); vector<tuple<int, Point, Point, Point, Point>> gridPoints(int div_x, int div_z, double x, double z, double phi); -void buildFibers(Detector& desc, SensitiveDetector sens, Volume &s_vol, xml_comp_t x_fiber, - std::tuple<double, double, double, double> dimensions); + +// geometry helpers +void buildFibers(Detector& desc, SensitiveDetector &sens, Volume &mother, xml_comp_t x_fiber, + const std::tuple<double, double, double, double> &dimensions); +void buildSupport(Detector& desc, Volume &mother, xml_comp_t x_support, + const std::tuple<double, double, double, double> &dimensions); // barrel ecal layers contained in an assembly @@ -33,7 +41,6 @@ static Ref_t create_detector(Detector& desc, xml_h e, SensitiveDetector sens) { Material air = desc.air(); int det_id = x_det.id(); string det_name = x_det.nameStr(); - xml_comp_t x_staves = x_det.staves(); double offset = x_det.attr<double>(_Unicode(offset)); xml_comp_t x_dim = x_det.dimensions(); int nsides = x_dim.numsides(); @@ -150,75 +157,22 @@ static Ref_t create_detector(Detector& desc, xml_h e, SensitiveDetector sens) { sdet.add(sd); } - Solid support_frame_s; // optional stave support - if (x_staves.hasChild("support")) { - xml_comp_t x_support = x_staves.child(_U(support)); - double support_thickness = getAttrOrDefault(x_support, _U(thickness), 5.0 * cm); - double trd_x1_support = (2 * std::tan(hphi) * l_pos_z + support_thickness)/2; - // is the support on the inside surface? - bool is_inside_support = getAttrOrDefault<bool>(x_support, _Unicode(inside), true); - double trd_x1 = std::tan(hphi) * inner_r; - double trd_x2 = std::tan(hphi) * (l_pos_z + support_thickness); - double trd_y1 = x_dim.z()/2.; - - // number of "beams" running the length of the stave. - int n_beams = getAttrOrDefault<int>(x_support, _Unicode(n_beams), 3); - double beam_thickness = support_thickness / 4.0; // maybe a parameter later... - trd_x1_support = (2 * std::tan(hphi) * (l_pos_z + beam_thickness)) / 2.; - double grid_size = getAttrOrDefault(x_support, _Unicode(grid_size), 25.0 * cm); - double beam_width = 2.0 * trd_x1_support / (n_beams + 1); // quick hack to make some gap between T beams - - double cross_beam_thickness = support_thickness/4.0; - //double trd_x1_support = (2 * std::tan(hphi) * (inner_r + beam_thickness)) / 2.; - double trd_x2_support = trd_x2; - - int n_cross_supports = std::floor((trd_y1-cross_beam_thickness)/grid_size); - - Box beam_vert_s(beam_thickness / 2.0 , trd_y1, support_thickness / 2.0 ); - Box beam_hori_s(beam_width / 2.0, trd_y1, beam_thickness / 2.0); - UnionSolid T_beam_s(beam_vert_s, beam_hori_s, Position(0, 0, -support_thickness / 2.0 + beam_thickness / 2.0)); - - // cross supports - Trapezoid trd_support(trd_x1_support,trd_x2_support, - beam_thickness / 2.0, beam_thickness / 2.0, - support_thickness / 2.0 - cross_beam_thickness/2.0); - UnionSolid support_array_start_s(T_beam_s,trd_support,Position(0,0,cross_beam_thickness/2.0)); - for (int isup = 0; isup < n_cross_supports; isup++) { - support_array_start_s = UnionSolid(support_array_start_s, trd_support, - Position(0, -1.0 * isup * grid_size, cross_beam_thickness/2.0)); - support_array_start_s = UnionSolid(support_array_start_s, trd_support, - Position(0, 1.0 * isup * grid_size, cross_beam_thickness/2.0)); + if (x_det.hasChild(_U(staves))) { + xml_comp_t x_staves = x_det.staves(); + mod_vol.setVisAttributes(desc.visAttributes(x_staves.visStr())); + if (x_staves.hasChild(_U(support))) { + buildSupport(desc, mod_vol, x_staves.child(_U(support)), {inner_r, l_pos_z, x_dim.z(), hphi}); } - support_array_start_s = - UnionSolid(support_array_start_s, beam_hori_s, - Position(-1.8 * 0.5*(trd_x1+trd_x2_support) / n_beams, 0, -support_thickness / 2.0 + beam_thickness / 2.0)); - support_array_start_s = - UnionSolid(support_array_start_s, beam_hori_s, - Position(1.8 * 0.5*(trd_x1+trd_x2_support) / n_beams, 0, -support_thickness / 2.0 + beam_thickness / 2.0)); - support_array_start_s = - UnionSolid(support_array_start_s, beam_vert_s, Position(-1.8 * 0.5*(trd_x1+trd_x2_support) / n_beams, 0, 0)); - support_array_start_s = - UnionSolid(support_array_start_s, beam_vert_s, Position(1.8 * 0.5*(trd_x1+trd_x2_support) / n_beams, 0, 0)); - - support_frame_s = support_array_start_s; - - Material support_mat = desc.material(x_support.materialStr()); - Volume support_vol("support_frame_v", support_frame_s, support_mat); - support_vol.setVisAttributes(desc,x_support.visStr()); - - // figure out how to best place - auto pv = mod_vol.placeVolume(support_vol, Position(0.0, 0.0, l_pos_z + support_thickness / 2.0)); } - //l_pos_z += support_thickness; // Set envelope volume attributes. envelope.setAttributes(desc, x_det.regionStr(), x_det.limitsStr(), x_det.visStr()); return sdet; } -void buildFibers(Detector& desc, SensitiveDetector sens, Volume &s_vol, xml_comp_t x_fiber, - std::tuple<double, double, double, double> dimensions) +void buildFibers(Detector& desc, SensitiveDetector &sens, Volume &s_vol, xml_comp_t x_fiber, + const std::tuple<double, double, double, double> &dimensions) { auto [s_trd_x1, s_thick, s_length, hphi] = dimensions; double f_radius = getAttrOrDefault(x_fiber, _U(radius), 0.1 * cm); @@ -258,7 +212,7 @@ void buildFibers(Detector& desc, SensitiveDetector sens, Volume &s_vol, xml_comp // Check to which grid fiber belongs to for (auto &poly_vtx : grid_vtx) { if (p.y() != l_pos_y) { - std::cerr << Form("Expected the same y position from a same line: %.2f, but got %.f", l_pos_y, p.y()) + std::cerr << Form("Expected the same y position from a same line: %.2f, but got %.2f", l_pos_y, p.y()) << std::endl; continue; } @@ -289,11 +243,96 @@ void buildFibers(Detector& desc, SensitiveDetector sens, Volume &s_vol, xml_comp PlacedVolume fiber_phv = lfibers.placeVolume(f_vol, Position(p.x(), 0., 0.)); fiber_phv.addPhysVolID(f_id_grid, f_grid_id + 1).addPhysVolID(f_id_fiber, f_id + 1); } + lfibers.ptr()->Voxelize(""); Transform3D l_tr(RotationZYX(0,0,M_PI*0.5),Position(0., 0, l_pos_y)); s_vol.placeVolume(lfibers, l_tr); } } +// DAWN view seems to have some issue with overlapping solids even if they were unions +// The support is now built without overlapping +void buildSupport(Detector& desc, Volume &mod_vol, xml_comp_t x_support, + const std::tuple<double, double, double, double> &dimensions) +{ + auto [inner_r, l_pos_z, stave_length, hphi] = dimensions; + + double support_thickness = getAttrOrDefault(x_support, _Unicode(thickness), 5. * cm); + double beam_thickness = getAttrOrDefault(x_support, _Unicode(beam_thickness), support_thickness/4.); + // sanity check + if (beam_thickness > support_thickness/3.) { + std::cerr << Form("beam_thickness (%.2f) cannot be greater than support_thickness/3 (%.2f), shrink it to fit", + beam_thickness, support_thickness/3.) << std::endl; + beam_thickness = support_thickness/3.; + } + double trd_x1_support = std::tan(hphi) * l_pos_z; + double trd_x2_support = std::tan(hphi) * (l_pos_z + support_thickness); + double trd_y = stave_length / 2.; + Assembly env_vol ("support_envelope"); + + double grid_size = getAttrOrDefault(x_support, _Unicode(grid_size), 25. * cm); + int n_cross_supports = std::floor(trd_y - beam_thickness)/grid_size; + // number of "beams" running the length of the stave. + // @TODO make it configurable + int n_beams = getAttrOrDefault(x_support, _Unicode(n_beams), 3);; + double beam_width = 2. * trd_x1_support / (n_beams + 1); // quick hack to make some gap between T beams + double beam_gap = getAttrOrDefault(x_support, _Unicode(beam_gap), 3.*cm); + + // build H-shape beam + double beam_space_x = beam_width + beam_gap; + double beam_space_z = support_thickness - beam_thickness; + double cross_thickness = support_thickness - 2.*beam_thickness; + double beam_pos_z = -beam_thickness / 2.; + double beam_center_z = support_thickness / 2. + beam_pos_z; + + Box beam_vert_s(beam_thickness / 2. , trd_y, cross_thickness / 2.); + Box beam_hori_s(beam_width / 2., trd_y, beam_thickness / 2.); + UnionSolid T_beam_s(beam_hori_s, beam_vert_s, Position(0., 0., beam_space_z / 2.)); + UnionSolid H_beam_s(T_beam_s, beam_hori_s, Position(0., 0., support_thickness - beam_thickness)); + Volume H_beam_vol("H_beam", H_beam_s, desc.material(x_support.materialStr())); + H_beam_vol.setVisAttributes(desc, x_support.visStr()); + // place H beams first + double beam_start_x = - (n_beams - 1) * (beam_width + beam_gap) / 2.; + for (int i = 0; i < n_beams; ++i) { + Position beam_pos(beam_start_x + i * (beam_width + beam_gap), 0., - support_thickness / 2. - beam_pos_z); + env_vol.placeVolume(H_beam_vol, beam_pos); + } + + // place central crossing beams that connects the H beams + double cross_x = beam_space_x - beam_thickness; + Box cross_s(cross_x / 2., beam_thickness / 2., cross_thickness / 2.); + Volume cross_vol("cross_center_beam", cross_s, desc.material(x_support.materialStr())); + cross_vol.setVisAttributes(desc, x_support.visStr()); + for (int i = 0; i < n_beams - 1; ++i) { + env_vol.placeVolume(cross_vol, Position(beam_start_x + beam_space_x * (i + 0.5), 0., 0.)); + for (int j = 1; j < n_cross_supports; j++) { + env_vol.placeVolume(cross_vol, Position(beam_start_x + beam_space_x * (i + 0.5), -j * grid_size, 0.)); + env_vol.placeVolume(cross_vol, Position(beam_start_x + beam_space_x * (i + 0.5), j * grid_size, 0.)); + } + } + + // place edge crossing beams that connects the neighbour support + // @TODO: connection part is still using boolean volumes, maybe problematic to DAWN + double cross_edge_x = trd_x1_support + beam_start_x - beam_thickness / 2.; + double cross_trd_x1 = cross_edge_x + std::tan(hphi) * beam_thickness; + double cross_trd_x2 = cross_trd_x1 + 2.* std::tan(hphi) * cross_thickness; + double edge_pos_x = beam_start_x - beam_thickness / 2. - cross_trd_x1 / 2.; + Trapezoid cross_s2_trd (cross_trd_x1 / 2., cross_trd_x2 / 2., + beam_thickness / 2., beam_thickness / 2., cross_thickness / 2.); + Box cross_s2_box ((cross_trd_x2 - cross_trd_x1)/2., beam_thickness / 2., cross_thickness / 2.); + SubtractionSolid cross_s2(cross_s2_trd, cross_s2_box, Position((cross_trd_x1 + cross_trd_x2) / 4., 0., 0.)); + Volume cross_vol2("cross_edge_beam", cross_s2, desc.material(x_support.materialStr())); + cross_vol2.setVisAttributes(desc, x_support.visStr()); + env_vol.placeVolume(cross_vol2, Position(edge_pos_x, 0., 0.)); + env_vol.placeVolume(cross_vol2, Transform3D(Translation3D(-edge_pos_x, 0., 0.) * RotationZ(M_PI))); + for (int j = 1; j < n_cross_supports; j++) { + env_vol.placeVolume(cross_vol2, Position(edge_pos_x, -j * grid_size, 0.)); + env_vol.placeVolume(cross_vol2, Position(edge_pos_x, j * grid_size, 0.)); + env_vol.placeVolume(cross_vol2, Transform3D(Translation3D(-edge_pos_x, -j * grid_size, 0.) * RotationZ(M_PI))); + env_vol.placeVolume(cross_vol2, Transform3D(Translation3D(-edge_pos_x, j * grid_size, 0.) * RotationZ(M_PI))); + } + + mod_vol.placeVolume(env_vol, Position(0.0, 0.0, l_pos_z + support_thickness/2.)); +} + DECLARE_DETELEMENT(athena_EcalBarrelInterlayers, create_detector) -// DECLARE_DETELEMENT(athena_EcalBarrelInterlayers, create_detector)