From b4e815b397e3370f23c709f0fdbe1bab40c4ba03 Mon Sep 17 00:00:00 2001 From: Chao Peng <cpeng@anl.gov> Date: Mon, 12 Jul 2021 04:48:47 +0000 Subject: [PATCH] Interlayer barrel ecal --- athena.xml | 33 +- bin/make_dawn_views | 14 +- compact/definitions.xml | 4 +- compact/ecal.xml | 15 - compact/ecal_barrel_interlayers.xml | 158 +++++++++ src/BarrelCalorimeterInterlayers_geo.cpp | 397 +++++++++++++++++++++++ 6 files changed, 585 insertions(+), 36 deletions(-) delete mode 100644 compact/ecal.xml create mode 100644 compact/ecal_barrel_interlayers.xml create mode 100644 src/BarrelCalorimeterInterlayers_geo.cpp diff --git a/athena.xml b/athena.xml index 25eff83a..d54c46d6 100644 --- a/athena.xml +++ b/athena.xml @@ -1,5 +1,5 @@ -<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0" - xmlns:xs="http://www.w3.org/2001/XMLSchema" +<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0" + xmlns:xs="http://www.w3.org/2001/XMLSchema" xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd"> <!-- Some information about detector --> @@ -8,7 +8,7 @@ url="https://eicweb.phy.anl.gov/EIC/detectors/athena.git" status="development" version="v1 2021-03-16"> - <comment>Athena Detector</comment> + <comment>Athena Detector</comment> </info> <define> @@ -112,15 +112,15 @@ <include ref="ip6/beampipe.xml"/> <detectors> - <detector id="VertexBarrelSubAssembly_ID" - name="VertexBarrelSubAssembly" - type="DD4hep_SubdetectorAssembly" + <detector id="VertexBarrelSubAssembly_ID" + name="VertexBarrelSubAssembly" + type="DD4hep_SubdetectorAssembly" vis="TrackerSubAssemblyVis"> <composite name="VertexBarrel" /> </detector> - <detector id="VertexEndcapSubAssembly_ID" - name="VertexEndcapSubAssembly" - type="DD4hep_SubdetectorAssembly" + <detector id="VertexEndcapSubAssembly_ID" + name="VertexEndcapSubAssembly" + type="DD4hep_SubdetectorAssembly" vis="TrackerSubAssemblyVis"> <composite name="VertexEndcapN" /> <composite name="VertexEndcapP" /> @@ -142,7 +142,7 @@ <composite name="TrackerEndcapP_Outer"/> <composite name="TrackerEndcapN_Outer"/> </detector> - + <detector id="TOFSubAssembly_ID" name="TOFSubAssembly" type="DD4hep_SubdetectorAssembly" @@ -188,14 +188,21 @@ <include ref="compact/central_tracker.xml"/> <include ref="compact/tof_barrel.xml"/> - + <!--include ref="compact/rwell_tracker_barrel.xml"/--> <include ref="compact/cb_DIRC.xml"/> <!-- When changing magnet, also select dimensions in definitions.xml. --> <include ref="compact/solenoid.xml"/> - <include ref="compact/ecal.xml"/> + <include ref="compact/ci_ecal.xml"/> + <!--<include ref="compact/ci_ecal_shashlik.xml"/>--> + <!--<include ref="compact/ce_ecal.xml"/>--> + <include ref="compact/ce_ecal_crystal_glass.xml"/> + <!-- <include ref="compact/ecal_barrel.xml"/> --> + <!-- <include ref="compact/ecal_barrel_hybrid.xml"/> --> + <include ref="compact/ecal_barrel_interlayers.xml"/> + <include ref="compact/hcal.xml"/> <!--include ref="compact/ce_GEM.xml"/--> <!--include ref="compact/gem_tracker_endcap.xml"/--> @@ -213,7 +220,7 @@ <include ref="compact/mm_tracker_barrel.xml"/> <include ref="compact/cb_VTX_Barrel.xml"/> --> - + <readouts> </readouts> diff --git a/bin/make_dawn_views b/bin/make_dawn_views index fe13723b..ea438d27 100755 --- a/bin/make_dawn_views +++ b/bin/make_dawn_views @@ -104,13 +104,13 @@ if [ "${DETECTOR_ONLY}" -eq "1" ] ; then -o derp.root -n 1 \ --ui csh --vis -b -m macro/dawn_picture.mac & -sleep 10 -echo "sleeping 20 secs .. " -sleep 10 -echo "sleeping 10 secs " -sleep 5 -echo "sleeping 5 secs " -sleep 5 +timeout=200 +while [ $timeout -ge 0 ] && [ ! -f "g4_0000.prim" ] +do + echo "terminating in $timeout secs ..." + sleep 5 + ((timeout=timeout-5)) +done kill %1 else diff --git a/compact/definitions.xml b/compact/definitions.xml index ac42e8b4..27d5db26 100644 --- a/compact/definitions.xml +++ b/compact/definitions.xml @@ -180,8 +180,9 @@ EndcapP subassembly ID: 102 EndcapN subassembly ID: 103 Crystal subassembly ID: 104 + Barrel2 subassembly ID: 105 - Unused IDs: 105-109 + Unused IDs: 106-109 </comment> <constant name="ECalSubAssembly_ID" value="100"/> @@ -189,6 +190,7 @@ <constant name="ECalEndcapP_ID" value="102"/> <constant name="ECalEndcapN_ID" value="103"/> <constant name="CrystalEndcap_ID" value="104"/> + <constant name="ECalBarrel2_ID" value="105"/> <comment> ===================================== diff --git a/compact/ecal.xml b/compact/ecal.xml deleted file mode 100644 index 60704e6c..00000000 --- a/compact/ecal.xml +++ /dev/null @@ -1,15 +0,0 @@ -<lccdd> - - <comment>barrel ecal</comment> - <!-- <include ref="ecal_barrel.xml"/> --> - <include ref="ecal_barrel_hybrid.xml"/> - - <comment>electron endcap ecal</comment> - <!--<include ref="ce_ecal.xml"/>--> - <include ref="ce_ecal_crystal_glass.xml"/> - - <comment>hadron endcap ecal</comment> - <include ref="ci_ecal.xml"/> - <!--<include ref="ci_ecal_shashlik.xml"/>--> - -</lccdd> diff --git a/compact/ecal_barrel_interlayers.xml b/compact/ecal_barrel_interlayers.xml new file mode 100644 index 00000000..8d1c6910 --- /dev/null +++ b/compact/ecal_barrel_interlayers.xml @@ -0,0 +1,158 @@ +<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" /> + </display> + <define> + <comment> + --------------------------------------- + EM Calorimeter Parameters with AstroPix + --------------------------------------- + </comment> + <constant name="EcalBarrel_Support_thickness" value="5*cm"/> + <constant name="EcalBarrel_SiliconThickness" value="500*um"/> + <constant name="EcalBarrel_ElectronicsThickness" value="150*um"/> + <constant name="EcalBarrel_CopperThickness" value="100*um"/> + <constant name="EcalBarrel_KaptonThickness" value="200*um"/> + <constant name="EcalBarrel_EpoxyThickness" value="100*um"/> + <constant name="EcalBarrel_CarbonThickness" value="0.5*mm"/> + <constant name="EcalBarrel_CarbonSpacerWidth" value="4*mm"/> + <constant name="EcalBarrel_LayerSpacing" value="10.0*mm"/> + <constant name="EcalBarrel_FiberRadius" value="0.5*mm"/> + <constant name="EcalBarrel_FiberXSpacing" value="1.34*mm"/> + <constant name="EcalBarrel_FiberZSpacing" value="1.22*mm"/> + <constant name="EcalBarrel_SpaceBetween" value="1*mm"/> + <comment> + For Pb/SiFi (GlueX): X0 ~ 1.45 cm + For W/SiFi (sPHENIX): X0 ~ 0.7 cm (but different fiber orientation) + </comment> + <constant name="EcalBarrel_RadiatorThickness" value="EcalBarrel_FiberZSpacing*12"/> + <constant name="EcalBarrel_ModRepeat" value="CaloSides"/> + <constant name="EcalBarrel_ModLength" value="0.5*m"/> + <constant name="EcalBarrel_ModWidth" value="0.5*m"/> + <constant name="EcalBarrel_AvailThickness" value="EcalBarrel_TotalThickness-EcalBarrel_Support_thickness"/> + <constant name="EcalBarrel_ImagingLayerThickness" + value="EcalBarrel_SiliconThickness + + EcalBarrel_ElectronicsThickness + + EcalBarrel_CopperThickness + + EcalBarrel_KaptonThickness + + EcalBarrel_EpoxyThickness + + EcalBarrel_CarbonThickness + + EcalBarrel_LayerSpacing"/> + + <constant name="EcalBarrelImagingLayers_nMax" value="6"/> + <constant name="EcalBarrelImagingLayers_num" + value="min(EcalBarrelImagingLayers_nMax, + floor(EcalBarrel_AvailThickness/ + (EcalBarrel_ImagingLayerThickness+EcalBarrel_RadiatorThickness+EcalBarrel_SpaceBetween)))"/> + <constant name="EcalBarrel_FiberLayerThickness_max" + value="max(0, EcalBarrel_AvailThickness- + (EcalBarrelImagingLayers_num*EcalBarrel_ImagingLayerThickness))"/> + <constant name="EcalBarrel_FiberLayerThickness" + value="min(EcalBarrel_FiberLayerThickness_max, EcalBarrel_FiberZSpacing*12*15)"/> + </define> + + <limits> + </limits> + + <regions> + </regions> + + <display> + </display> + + <detectors> + + <comment> + --------------------------------------- + Imaging Layers of Barrel EM Calorimeter + --------------------------------------- + Silicon (Astropix) readout layers for imaging 3d showers + </comment> + <detector + id="ECalBarrel_ID" + name="EcalBarrelImaging" + type="athena_EcalBarrelInterlayers" + readout="EcalBarrelHits" + calorimeterType="EM_BARREL" + vis="EcalBarrelEnvelope_vis" + offset="EcalBarrel_offset"> + <dimensions numsides="EcalBarrel_ModRepeat" + rmin="EcalBarrel_rmin" + z="EcalBarrel_length"/> + <staves vis="EcalBarrelStave_vis"/> + <layer repeat="EcalBarrelImagingLayers_num" vis="AnlBlue" + space_between="EcalBarrel_RadiatorThickness + EcalBarrel_SpaceBetween" + space_before="0.*cm"> + <slice material="Silicon" thickness="EcalBarrel_SiliconThickness" sensitive="yes" limits="cal_limits" vis="AnlGray"/> + <slice material="Silicon" thickness="EcalBarrel_ElectronicsThickness" vis="AnlGold"/> + <slice material="Copper" thickness="EcalBarrel_CopperThickness" vis="AnlGray"/> + <slice material="Kapton" thickness="EcalBarrel_KaptonThickness" vis="AnlGold"/> + <slice material="Epoxy" thickness="EcalBarrel_EpoxyThickness" vis="AnlGray"/> + <slice material="CarbonFiber" thickness="EcalBarrel_CarbonThickness" vis="AnlGold"/> + <slice material="Air" thickness="EcalBarrel_LayerSpacing " vis="AnlGold"/> + </layer> + </detector> + + <comment> + --------------------------------------- + Pb/ScFi Layers of Barrel EM Calorimeter + --------------------------------------- + </comment> + <detector + id="ECalBarrel2_ID" + name="EcalBarrelScFi" + type="athena_EcalBarrelInterlayers" + readout="EcalBarrelScFiHits" + calorimeterType="EM_BARREL" + vis="EcalBarrelEnvelope_vis" + offset="EcalBarrel_offset"> + <dimensions numsides="EcalBarrel_ModRepeat" + 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> + </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"> + <fiber material="PlasticScint" + sensitive="yes" + vis="EcalBarrelFiberVis" + radius="EcalBarrel_FiberRadius" + spacing_x="EcalBarrel_FiberXSpacing" + spacing_z="EcalBarrel_FiberZSpacing"/> + </slice> + </layer> + <layer repeat="1" vis="AnlBlue" + space_before="EcalBarrel_ImagingLayerThickness + EcalBarrel_SpaceBetween"> + <slice material="Lead" thickness="EcalBarrel_FiberLayerThickness" vis="EcalBarrelFiberLayerVis"> + <fiber material="PlasticScint" + sensitive="yes" + vis="EcalBarrelFiberVis" + radius="EcalBarrel_FiberRadius" + spacing_x="EcalBarrel_FiberXSpacing" + spacing_z="EcalBarrel_FiberZSpacing"> + </fiber> + </slice> + </layer> + </detector> + </detectors> + + <readouts> + <readout name="EcalBarrelHits"> + <segmentation type="CartesianGridXY" grid_size_x="0.5 * mm" grid_size_y="0.5 * mm"/> + <id>system:8,module:8,layer:8,slice:8,x:32:-16,y:-16</id> + </readout> + <readout name="EcalBarrelScFiHits"> + <segmentation type="NoSegmentation"/> + <id>system:8,module:8,layer:8,slice:8,grid:16,fiber:16</id> + </readout> + </readouts> + +</lccdd> diff --git a/src/BarrelCalorimeterInterlayers_geo.cpp b/src/BarrelCalorimeterInterlayers_geo.cpp new file mode 100644 index 00000000..ec888447 --- /dev/null +++ b/src/BarrelCalorimeterInterlayers_geo.cpp @@ -0,0 +1,397 @@ +// Detector plugin to support a hybrid central barrel calorimeter +// The detector consists of interlayers of Pb/ScFi (segmentation in global r, phi) and W/Si (segmentation in local x, y) +// 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 + + +#include "DD4hep/DetFactoryHelper.h" +#include "XML/Layering.h" +#include "Math/Point2D.h" +#include "TGeoPolygon.h" + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::detail; + +typedef ROOT::Math::XYPoint Point; +// headers for helper functions +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); + + +// barrel ecal layers contained in an assembly +static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) { + Layering layering (e); + xml_det_t x_det = e; + Material air = description.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(); + double inner_r = x_dim.rmin(); + double dphi = (2*M_PI/nsides); + double hphi = dphi/2; + + DetElement sdet (det_name, det_id); + Volume motherVol = description.pickMotherVolume(sdet); + + Assembly envelope (det_name); + Transform3D tr = Translation3D(0, 0, offset) * RotationZ(hphi); + PlacedVolume env_phv = motherVol.placeVolume(envelope, tr); + sens.setType("calorimeter"); + + env_phv.addPhysVolID("system",det_id); + sdet.setPlacement(env_phv); + + // build a single stave + DetElement stave_det("stave0", det_id); + Assembly mod_vol("stave"); + + // keep tracking of the total thickness + double l_pos_z = inner_r; + { // ===== buildBarrelStave(description, sens, module_volume) ===== + // Parameters for computing the layer X dimension: + double tan_hphi = std::tan(hphi); + double l_dim_y = x_dim.z()/2.; + + // Loop over the sets of layer elements in the detector. + int l_num = 1; + for(xml_coll_t li(x_det, _U(layer)); li; ++li) { + xml_comp_t x_layer = li; + int repeat = x_layer.repeat(); + double l_space_between = dd4hep::getAttrOrDefault(x_layer, _Unicode(space_between), 0.); + double l_space_before = dd4hep::getAttrOrDefault(x_layer, _Unicode(space_before), 0.); + l_pos_z += l_space_before; + // Loop over number of repeats for this layer. + for (int j = 0; j < repeat; j++) { + string l_name = Form("layer%d", l_num); + double l_thickness = layering.layer(l_num - 1)->thickness(); // Layer's thickness. + double l_dim_x = tan_hphi* l_pos_z; + l_pos_z += l_thickness; + + Position l_pos(0, 0, l_pos_z - l_thickness/2.); // Position of the layer. + double l_trd_x1 = l_dim_x; + double l_trd_x2 = l_dim_x + l_thickness*tan_hphi; + double l_trd_y1 = l_dim_y; + double l_trd_y2 = l_trd_y1; + double l_trd_z = l_thickness/2; + Trapezoid l_shape(l_trd_x1, l_trd_x2, l_trd_y1, l_trd_y2, l_trd_z); + Volume l_vol(l_name, l_shape, air); + DetElement layer(stave_det, l_name, det_id); + + // Loop over the sublayers or slices for this layer. + int s_num = 1; + double s_pos_z = -(l_thickness / 2.); + for(xml_coll_t si(x_layer,_U(slice)); si; ++si) { + xml_comp_t x_slice = si; + string s_name = Form("slice%d", s_num); + double s_thick = x_slice.thickness(); + double s_trd_x1 = l_dim_x + (s_pos_z + l_thickness/2)*tan_hphi; + double s_trd_x2 = l_dim_x + (s_pos_z + l_thickness/2 + s_thick)*tan_hphi; + double s_trd_y1 = l_trd_y1; + double s_trd_y2 = s_trd_y1; + double s_trd_z = s_thick/2.; + Trapezoid s_shape(s_trd_x1, s_trd_x2, s_trd_y1, s_trd_y2, s_trd_z); + Volume s_vol(s_name, s_shape, description.material(x_slice.materialStr())); + DetElement slice(layer, s_name, det_id); + + // build fibers + if (x_slice.hasChild("fiber")) { + xml_comp_t x_fiber = x_slice.child(_Unicode(fiber)); + double f_radius = getAttrOrDefault(x_fiber, _U(radius), 0.1 * cm); + double f_spacing_x = getAttrOrDefault(x_fiber, _Unicode(spacing_x), 0.122 * cm); + double f_spacing_z = getAttrOrDefault(x_fiber, _Unicode(spacing_z), 0.134 * cm); + std::string f_id_grid = getAttrOrDefault(x_fiber, _Unicode(identifier_grid), "grid"); + std::string f_id_fiber = getAttrOrDefault(x_fiber, _Unicode(identifier_fiber), "fiber"); + + // Calculate fiber positions inside the slice + vector<Point> f_pos = _fiberPositions(f_radius, f_spacing_x, f_spacing_z, s_trd_x1, s_thick, hphi); + // Sort fiber IDs fo better organization + sort(f_pos.begin(), f_pos.end(), + [](const Point &p1, const Point &p2) { + if (p1.y() == p2.y()) { return p1.x() < p2.x(); } + return p1.y() < p2.y(); + }); + + Tube f_tube(0, f_radius, l_dim_y); + + // Set up the readout grid for the fiber layers + // Trapezoid is divided into segments with equal dz and equal number of divisions in x + // Every segment is a polygon that can be attached later to the lightguide + // The grid size is assumed to be ~2x2 cm (starting values). This is to be larger than + // SiPM chip (for GlueX 13mmx13mm: 4x4 grid 3mmx3mm with 3600 50×50 μm pixels each) + // See, e.g., https://arxiv.org/abs/1801.03088 Fig. 2d + + // Calculate number of divisions + auto grid_div = _getNdivisions(s_trd_x1, s_thick, 2.0*cm, 2.0*cm); + // Calculate polygonal grid coordinates (vertices) + auto grid_vtx = _gridPoints(grid_div.first, grid_div.second, s_trd_x1, s_thick, hphi); + + vector<int> f_id_count(grid_div.first*grid_div.second, 0); + for (auto &p : f_pos) { + int f_grid_id = -1; + int f_id = -1; + // Check to which grid fiber belongs to + for (auto &poly_vtx : grid_vtx) { + auto [grid_id, vtx_a, vtx_b, vtx_c, vtx_d] = poly_vtx; + double poly_x[4] = {vtx_a.x(), vtx_b.x(), vtx_c.x(), vtx_d.x()}; + double poly_y[4] = {vtx_a.y(), vtx_b.y(), vtx_c.y(), vtx_d.y()}; + double f_xy[2] = {p.x(), p.y()}; + + TGeoPolygon poly(4); + poly.SetXY(poly_x,poly_y); + poly.FinishPolygon(); + + if(poly.Contains(f_xy)) { + f_grid_id = grid_id; + f_id = f_id_count[grid_id]; + f_id_count[grid_id]++; + } + } + + string f_name = "fiber" + to_string(f_grid_id) + "_" + to_string(f_id); + Volume f_vol(f_name, f_tube, description.material(x_fiber.materialStr())); + DetElement fiber(slice, f_name, det_id); + if ( x_fiber.isSensitive() ) { + f_vol.setSensitiveDetector(sens); + } + fiber.setAttributes(description,f_vol,x_fiber.regionStr(),x_fiber.limitsStr(),x_fiber.visStr()); + + // Fiber placement + Transform3D f_tr(RotationZYX(0,0,M_PI*0.5),Position(p.x(), 0 ,p.y())); + PlacedVolume fiber_phv = s_vol.placeVolume(f_vol, f_tr); + fiber_phv.addPhysVolID(f_id_grid, f_grid_id + 1).addPhysVolID(f_id_fiber, f_id + 1); + fiber.setPlacement(fiber_phv); + } + } + + + if ( x_slice.isSensitive() ) { + s_vol.setSensitiveDetector(sens); + } + s_vol.setAttributes(description, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr()); + + // Slice placement. + PlacedVolume slice_phv = l_vol.placeVolume(s_vol, Position(0, 0, s_pos_z + s_thick/2)); + slice_phv.addPhysVolID("slice", s_num); + slice.setPlacement(slice_phv); + // Increment Z position of slice. + s_pos_z += s_thick; + ++s_num; + } + + // Set region, limitset, and vis of layer. + l_vol.setAttributes(description, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr()); + + PlacedVolume layer_phv = mod_vol.placeVolume(l_vol, l_pos); + layer_phv.addPhysVolID("layer", l_num); + layer.setPlacement(layer_phv); + // Increment to next layer Z position. Do not add space_between for the last layer + if (j < repeat - 1) { + l_pos_z += l_space_between; + } + ++l_num; + } + } + } + // Phi start for a stave. + double phi = M_PI / nsides; + // Create nsides staves. + for (int i = 0; i < nsides; i++, phi -= dphi) { // i is module number + // Compute the stave position + Transform3D tr(RotationZYX(0, phi, M_PI*0.5), Translation3D(0, 0, 0)); + PlacedVolume pv = envelope.placeVolume(mod_vol, tr); + pv.addPhysVolID("module", i + 1); + DetElement sd = (i == 0) ? stave_det : stave_det.clone(Form("stave%d", i)); + sd.setPlacement(pv); + 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)); + } + 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 = description.material(x_support.materialStr()); + Volume support_vol("support_frame_v", support_frame_s, support_mat); + support_vol.setVisAttributes(description,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(description, x_det.regionStr(), x_det.limitsStr(), x_det.visStr()); + return sdet; +} + + +DECLARE_DETELEMENT(athena_EcalBarrelInterlayers, create_detector) +// DECLARE_DETELEMENT(athena_EcalBarrelInterlayers, create_detector) + + +// ----------------------------------------------------------------------------- +// helper functions +// ----------------------------------------------------------------------------- +// Fill fiber lattice into trapezoid starting from position (0,0) in x-z coordinate system +vector<Point> _fiberPositions(double radius, double x_spacing, double z_spacing, + double x, double z, double phi, double spacing_tol) { + // z_spacing - distance between fiber layers in z + // x_spacing - distance between fiber centers in x + // x - half-length of the shorter (bottom) base of the trapezoid + // z - height of the trapezoid + // phi - angle between z and trapezoid arm + + vector<Point> positions; + int z_layers = floor((z/2-radius-spacing_tol)/z_spacing); // number of layers that fit in z/2 + + double z_pos = 0.; + double x_pos = 0.; + + for(int l = -z_layers; l < z_layers+1; l++) { + + z_pos = l*z_spacing; + double x_max = x + (z/2. + z_pos)*tan(phi) - spacing_tol; // calculate max x at particular z_pos + (l % 2 == 0) ? x_pos = 0. : x_pos = x_spacing/2; // account for spacing/2 shift + + while(x_pos < (x_max - radius)) { + positions.push_back(Point(x_pos,z_pos)); + if(x_pos != 0.) positions.push_back(Point(-x_pos,z_pos)); // using symmetry around x=0 + x_pos += x_spacing; + } + } + + return positions; +} + +// Calculate number of divisions for the readout grid for the fiber layers +std::pair<int, int> _getNdivisions(double x, double z, double dx, double dz){ + // x and z defined as in vector<Point> fiberPositions + // dx, dz - size of the grid in x and z we want to get close to with the polygons + // See also descripltion when the function is called + + double SiPMsize = 13.0*mm; + double grid_min = SiPMsize + 3.0*mm; + + if(dz < grid_min) { + dz = grid_min; + } + + if(dx < grid_min) { + dx = grid_min; + } + + int nfit_cells_z = floor(z/dz); + int n_cells_z = nfit_cells_z; + + if(nfit_cells_z == 0) n_cells_z++; + + int nfit_cells_x = floor((2*x)/dx); + int n_cells_x = nfit_cells_x; + + if(nfit_cells_x == 0) n_cells_x++; + + return std::make_pair(n_cells_x, n_cells_z); + +} + +// Calculate dimensions of the polygonal grid in the cartesian coordinate system x-z +vector< tuple<int, Point, Point, Point, Point> > _gridPoints(int div_x, int div_z, double x, double z, double phi) { + // x, z and phi defined as in vector<Point> fiberPositions + // div_x, div_z - number of divisions in x and z + double dz = z/div_z; + + std::vector<std::tuple<int, Point, Point, Point, Point>> points; + + for(int iz = 0; iz < div_z + 1; iz++){ + for(int ix = 0; ix < div_x + 1; ix++){ + double A_z = -z/2 + iz*dz; + double B_z = -z/2 + (iz+1)*dz; + + double len_x_for_z = 2*(x+iz*dz*tan(phi)); + double len_x_for_z_plus_1 = 2*(x + (iz+1)*dz*tan(phi)); + + double dx_for_z = len_x_for_z/div_x; + double dx_for_z_plus_1 = len_x_for_z_plus_1/div_x; + + double A_x = -len_x_for_z/2. + ix*dx_for_z; + double B_x = -len_x_for_z_plus_1/2. + ix*dx_for_z_plus_1; + + double C_z = B_z; + double D_z = A_z; + double C_x = B_x + dx_for_z_plus_1; + double D_x = A_x + dx_for_z; + + int id = ix + div_x * iz; + + auto A = Point(A_x, A_z); + auto B = Point(B_x, B_z); + auto C = Point(C_x, C_z); + auto D = Point(D_x, D_z); + + // vertex points filled in the clock-wise direction + points.push_back(make_tuple(id, A, B, C, D)); + + } + } + + return points; + +} + -- GitLab