Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-17 08:29:23

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2023 Sebouh J. Paul
0003 
0004 //==========================================================================
0005 //  Implementation of SiPM-on-tile Zero-Degree Calorimeter
0006 //--------------------------------------------------------------------------
0007 //  Author: Sebouh J. Paul (UCR)
0008 //==========================================================================
0009 
0010 #include "DD4hep/DetFactoryHelper.h"
0011 #include <XML/Helper.h>
0012 #include <XML/Layering.h>
0013 #include <XML/Utilities.h>
0014 
0015 using namespace dd4hep;
0016 
0017 static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens) {
0018   xml_det_t detElem   = handle;
0019   std::string detName = detElem.nameStr();
0020   int detID           = detElem.id();
0021 
0022   xml_dim_t dim = detElem.dimensions();
0023   double width  = dim.x(); // Size along x-axis
0024   double height = dim.y(); // Size along y-axis
0025   double length = dim.z(); // Size along z-axis
0026 
0027   xml_comp_t abs_dims    = detElem.child("absorber_dimensions");
0028   double absorber_width  = abs_dims.attr<double>("width");
0029   double absorber_height = abs_dims.attr<double>("height");
0030 
0031   xml_comp_t scint_layout = detElem.child("scintillator_layout");
0032   int nrows_even          = scint_layout.attr<int>("nrows_even_layers");
0033   int nrows_odd           = scint_layout.attr<int>("nrows_odd_layers");
0034   int ncols_even          = scint_layout.attr<int>("ncols_even_layers");
0035   int ncols_odd           = scint_layout.attr<int>("ncols_odd_layers");
0036 
0037   double tile = scint_layout.attr<double>("tile_side_length");
0038 
0039   xml_dim_t pos = detElem.position(); // Position in global coordinates
0040   xml_dim_t rot = detElem.rotation();
0041 
0042   Material air = desc.material("Air");
0043 
0044   // Defining envelope
0045   Box envelope(width / 2.0, height / 2.0, length / 2.0);
0046 
0047   // Defining envelope volume
0048   Volume envelopeVol(detName, envelope, air);
0049   // Setting envelope attributes
0050   envelopeVol.setAttributes(desc, detElem.regionStr(), detElem.limitsStr(), detElem.visStr());
0051 
0052   PlacedVolume pv;
0053 
0054   double z_distance_traversed = 0.;
0055 
0056   int layer_num = 1;
0057 
0058   // Looping through all the different layer sections
0059   for (xml_coll_t c(detElem, _U(layer)); c; ++c) {
0060     xml_comp_t x_layer     = c;
0061     int repeat             = x_layer.repeat();
0062     double layer_thickness = x_layer.thickness();
0063 
0064     // Looping through the number of repeated layers in each section
0065     for (int i = 0; i < repeat; i++) {
0066       std::string layer_name = detName + _toString(layer_num, "_layer%d");
0067 
0068       Box layer(width / 2., height / 2., layer_thickness / 2.);
0069 
0070       Volume layer_vol(layer_name, layer, air);
0071 
0072       int slice_num  = 1;
0073       double slice_z = -layer_thickness / 2.; // Keeps track of slices' z locations in each layer
0074 
0075       // Looping over each layer's slices
0076       for (xml_coll_t l(x_layer, _U(slice)); l; ++l) {
0077         xml_comp_t x_slice     = l;
0078         double slice_thickness = x_slice.thickness();
0079         std::string slice_name = layer_name + _toString(slice_num, "slice%d");
0080         Material slice_mat     = desc.material(x_slice.materialStr());
0081         slice_z += slice_thickness / 2.; // Going to slice halfway point
0082 
0083         double slice_width, slice_height, slice_x, slice_y;
0084         if (x_slice.nameStr() == "ESRFoil_slice" or x_slice.nameStr() == "Scintillator_slice") {
0085           if (i % 2 == 0) {
0086             slice_width  = ncols_even * tile;
0087             slice_height = nrows_even * tile;
0088             slice_x      = tile / 4;
0089             slice_y      = -tile / 4;
0090           }
0091           if (i % 2 == 1) {
0092             slice_width  = ncols_odd * tile;
0093             slice_height = nrows_odd * tile;
0094             slice_x      = -tile / 4;
0095             slice_y      = -tile / 4;
0096           }
0097         } else { //absorber
0098           slice_width  = absorber_width;
0099           slice_height = absorber_height;
0100           slice_x      = 0;
0101           slice_y      = (-nrows_even / 2 + 1 / 4) * tile + absorber_height / 2;
0102         }
0103 
0104         Box slice(slice_width / 2., slice_height / 2., slice_thickness / 2.);
0105 
0106         Volume slice_vol(slice_name, slice, slice_mat);
0107 
0108         // Setting appropriate slices as sensitive
0109         if (x_slice.isSensitive()) {
0110           sens.setType("calorimeter");
0111           slice_vol.setSensitiveDetector(sens);
0112         }
0113 
0114         // Setting slice attributes
0115         slice_vol.setAttributes(desc, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr());
0116 
0117         // Placing slice within layer
0118         pv = layer_vol.placeVolume(
0119             slice_vol, Transform3D(RotationZYX(0, 0, 0), Position(slice_x, slice_y, slice_z)));
0120         pv.addPhysVolID("slice", slice_num);
0121         slice_z += slice_thickness / 2.;
0122         z_distance_traversed += slice_thickness;
0123         ++slice_num;
0124       }
0125 
0126       // Setting layer attributes
0127       layer_vol.setAttributes(desc, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr());
0128       // Placing each layer inside the envelope volume
0129       // -length/2. is front of detector in global coordinate system
0130       // + (z_distance_traversed - layer_thickness) goes to the front of each layer
0131       // + layer_thickness/2. places layer in correct spot
0132       // Example: After placement of slices in first layer, z_distance_traversed = layer_thickness
0133       //          Subtracting layer_thickness goes back to the front of the first slice (Now, z = -length/2)
0134       //          Adding layer_thickness/2. goes to half the first layer thickness (proper place to put layer)
0135       //          Each loop over repeat will increases z_distance_traversed by layer_thickness
0136       pv = envelopeVol.placeVolume(
0137           layer_vol, Transform3D(RotationZYX(0, 0, 0),
0138                                  Position(0., 0.,
0139                                           -length / 2. + (z_distance_traversed - layer_thickness) +
0140                                               layer_thickness / 2.)));
0141       pv.addPhysVolID("layer", layer_num);
0142       layer_num++;
0143     }
0144   }
0145 
0146   DetElement det(detName, detID);
0147   Volume motherVol = desc.pickMotherVolume(det);
0148 
0149   // apply any detector type flags set in XML
0150   dd4hep::xml::setDetectorTypeFlag(detElem, det);
0151 
0152   // Placing ZDC in world volume
0153   auto tr =
0154       Transform3D(RotationZYX(rot.z(), rot.y(), rot.x()), Position(pos.x(), pos.y(), pos.z()));
0155   PlacedVolume phv = motherVol.placeVolume(envelopeVol, tr);
0156   phv.addPhysVolID("system", detID);
0157   det.setPlacement(phv);
0158 
0159   return det;
0160 }
0161 DECLARE_DETELEMENT(ZeroDegreeCalorimeterSiPMonTile, createDetector)