Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:15:55

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2023 Aranya Giri, Simon Gardner
0003 
0004 /* Date : 12/12/2023
0005 W Scifi (EM Calorimeter) Pair Spectrometer */
0006 
0007 #include "DD4hep/DetFactoryHelper.h"
0008 #include <XML/Helper.h>
0009 #include <algorithm>
0010 #include <iostream>
0011 #include <tuple>
0012 #include <TVector3.h>
0013 
0014 using namespace std;
0015 using namespace dd4hep;
0016 
0017 // Definition of function to build the modules
0018 static tuple<Volume, Position> build_specScFiCAL_module(const Detector& description,
0019                                                         const xml::Component& mod_x,
0020                                                         SensitiveDetector& sens);
0021 
0022 // Driver Function
0023 static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) {
0024   sens.setType("calorimeter");
0025 
0026   xml_det_t x_det  = e;
0027   xml_comp_t x_mod = x_det.child(_Unicode(module));
0028   string det_name  = x_det.nameStr();
0029   int det_ID       = x_det.id();
0030 
0031   Material Air = description.material("Air");
0032 
0033   // Create main detector element to be returned at the end
0034   DetElement det(det_name, det_ID);
0035 
0036   // Mother volume
0037   Volume motherVol = description.pickMotherVolume(det);
0038 
0039   // Detector assembly
0040   Assembly assembly(det_name);
0041   assembly.setVisAttributes(description.visAttributes(x_det.attr<std::string>(_Unicode(vis))));
0042 
0043   double detSizeXY  = getAttrOrDefault(x_det, _Unicode(sizeXY), 180 * mm);
0044   double detSizeZ   = getAttrOrDefault(x_det, _Unicode(sizeZ), 180 * mm);
0045   int nmod_perlayer = getAttrOrDefault(x_det, _Unicode(nmod_perlayer), 3);
0046   int nlayer        = getAttrOrDefault(x_det, _Unicode(nlayer), 20);
0047 
0048   // Global detector position and resolution
0049   xml_comp_t pos = x_det.position();
0050   xml_comp_t rot = x_det.rotation();
0051 
0052   //function for module definition
0053   auto [modVol, modSize] = build_specScFiCAL_module(description, x_mod, sens);
0054 
0055   //layer definition before rotation
0056   xml_comp_t x_layer = x_det.child(_Unicode(layer));
0057 
0058   double laySizeX       = getAttrOrDefault(x_layer, _Unicode(sizeX), 1.0 * cm);
0059   double laySizeY       = getAttrOrDefault(x_layer, _Unicode(sizeY), 1.0 * cm);
0060   double laySizeZ       = getAttrOrDefault(x_layer, _Unicode(sizeZ), 1.0 * cm);
0061   double layerCoatSizeX = getAttrOrDefault(x_layer, _Unicode(coatSizeX), 1.0 * cm);
0062   double layerCoatSizeY = getAttrOrDefault(x_layer, _Unicode(coatSizeY), 1.0 * cm);
0063 
0064   Material layMat = description.material(x_layer.attr<std::string>(_Unicode(material)));
0065 
0066   Box layerBox(laySizeX / 2.0, laySizeY / 2.0, laySizeZ / 2.0);
0067   Volume layerVol("layer", layerBox, layMat);
0068   layerVol.setVisAttributes(description.visAttributes(x_det.attr<std::string>(_Unicode(vis))));
0069 
0070   // Position of first module, layer from center of CAL
0071   double mod_pos0   = -(detSizeXY / 2.0) + (modSize.x() / 2.0) + layerCoatSizeX;
0072   double layer_pos0 = -(detSizeZ / 2.0) + (modSize.y() / 2.0) + layerCoatSizeY;
0073 
0074   //Fill uncoated layer with modules
0075   for (int mod_id = 0; mod_id < nmod_perlayer; mod_id++) {
0076 
0077     //Build // to z-axis, then rotate
0078     double mod_pos_z = 0.0 * cm;
0079     double mod_pos_y = 0.0 * cm;
0080     double mod_pos_x = mod_id * modSize.x() + mod_pos0;
0081 
0082     PlacedVolume modPV = layerVol.placeVolume(modVol, Position(mod_pos_x, mod_pos_y, mod_pos_z));
0083     modPV.addPhysVolID("module", mod_id);
0084   } //imod-loop close
0085 
0086   //sector definition
0087   Box sectorBox(detSizeXY / 2, detSizeXY / 2, detSizeZ / 2);
0088   Volume sectorVol(det_name + "_sector", sectorBox, Air);
0089   sectorVol.setVisAttributes(description.visAttributes(x_mod.attr<std::string>(_Unicode(vis))));
0090 
0091   //Fill sector with layers (coated)
0092   for (int layer_id = 0; layer_id < nlayer; layer_id++) {
0093 
0094     double lay_pos_z = -layer_id * (modSize.y() + 2.0 * layerCoatSizeY) - layer_pos0;
0095     double lay_pos_y = 0.0 * cm;
0096     double lay_pos_x = 0.0 * cm;
0097     int orientation  = layer_id % 2 == 0;
0098 
0099     //rotation
0100     RotationZYX lay_rot = RotationZYX(0, 0, -90.0 * degree);
0101     if (orientation)
0102       lay_rot *= RotationY(-90.0 * degree);
0103 
0104     PlacedVolume layPV = sectorVol.placeVolume(
0105         layerVol, Transform3D(lay_rot, Position(lay_pos_x, lay_pos_y, lay_pos_z)));
0106     layPV.addPhysVolID("layer", layer_id);
0107   } //layer_id-loop close
0108 
0109   // loop over sectors(top, bottom)
0110   for (xml_coll_t si(x_det, _Unicode(sector)); si; si++) {
0111 
0112     xml_comp_t x_sector(si);
0113     int sector_id      = x_sector.id();
0114     xml_comp_t sec_pos = x_sector.position();
0115     xml_comp_t sec_rot = x_sector.rotation();
0116 
0117     PlacedVolume secPV = assembly.placeVolume(
0118         sectorVol, Transform3D(RotationZYX(sec_rot.z(), sec_rot.y(), sec_rot.x()),
0119                                Position(sec_pos.x(), sec_pos.y(), sec_pos.z())));
0120     secPV.addPhysVolID("sector", sector_id);
0121   } // sectors
0122 
0123   // Place assembly into mother volume.  Assembly is centered at origin
0124   PlacedVolume detPV =
0125       motherVol.placeVolume(assembly, Transform3D(RotationZYX(rot.z(), rot.y(), rot.x()),
0126                                                   Position(pos.x(), pos.y(), pos.z())));
0127   detPV.addPhysVolID("system", det_ID);
0128   // Connect to system ID
0129   det.setPlacement(detPV);
0130 
0131   return det;
0132 } //Driver class close
0133 
0134 static tuple<Volume, Position> build_specScFiCAL_module(const Detector& description,
0135                                                         const xml::Component& mod_x,
0136                                                         SensitiveDetector& sens) {
0137 
0138   //--------------------Module Setup---------------------------------------------------------------------
0139   double sx = mod_x.attr<double>(_Unicode(sizex));
0140   double sy = mod_x.attr<double>(_Unicode(sizey));
0141   double sz = mod_x.attr<double>(_Unicode(sizez));
0142 
0143   Position modSize(sx, sy, sz);
0144 
0145   Box modShape(modSize.x() / 2.0, modSize.y() / 2.0, modSize.z() / 2.0);
0146   auto modMat = description.material(mod_x.attr<std::string>(_Unicode(material)));
0147   Volume modVol("module_vol", modShape, modMat);
0148 
0149   modVol.setVisAttributes(description.visAttributes(mod_x.attr<std::string>(_Unicode(vis))));
0150 
0151   //--------------------------Block of fibers in a module------------------------------------------------------
0152 
0153   //block fibers
0154   auto fiber_block = mod_x.child(_Unicode(block));
0155 
0156   auto fb_sx      = fiber_block.attr<double>(_Unicode(sizeX));
0157   auto fb_sy      = fiber_block.attr<double>(_Unicode(sizeY));
0158   auto fb_sz      = fiber_block.attr<double>(_Unicode(sizeZ));
0159   auto fb_SpaceXY = fiber_block.attr<double>(_Unicode(SpaceXY));
0160 
0161   Position fbSize(fb_sx, fb_sy, fb_sz);
0162 
0163   //fibers
0164   auto fiber_tube = mod_x.child(_Unicode(fiber));
0165 
0166   auto fr  = fiber_tube.attr<double>(_Unicode(radius));
0167   auto fsx = fiber_tube.attr<double>(_Unicode(spacex));
0168   auto fsy = fiber_tube.attr<double>(_Unicode(spacey));
0169 
0170   //fiber block description and placement in module
0171   Box fbShape(fbSize.x() / 2.0, fbSize.y() / 2.0, fbSize.z() / 2.0);
0172   Volume fbVol("fiberblock_volume", fbShape, modMat);
0173   fbVol.setVisAttributes(
0174       description.visAttributes(mod_x.attr<std::string>(_Unicode(vis)))); //same as module
0175 
0176   int num_fbX = int(modSize.x() / (fbSize.x() + 2.0 * fb_SpaceXY));
0177   int num_fbY = int(modSize.y() / (fbSize.y() + 2.0 * fb_SpaceXY));
0178 
0179   double fb_xpos0 = -(modSize.x() / 2.0) + (fbSize.x() / 2.0) + fb_SpaceXY;
0180   double fb_ypos0 = -(modSize.y() / 2.0) + (fbSize.y() / 2.0) + fb_SpaceXY;
0181   int nblock      = 0;
0182 
0183   for (int iy = 0; iy < num_fbY; iy++) {
0184     for (int ix = 0; ix < num_fbX; ix++) {
0185       double fb_pos_x = fb_xpos0 + ix * (fbSize.x() + 2.0 * fb_SpaceXY); //mm
0186       double fb_pos_y = fb_ypos0 + iy * (fbSize.y() + 2.0 * fb_SpaceXY); //mm
0187       double fb_pos_z = 0 * mm;
0188 
0189       auto fbPV = modVol.placeVolume(fbVol, nblock, Position{fb_pos_x, fb_pos_y, fb_pos_z});
0190       fbPV.addPhysVolID("block", nblock++);
0191     }
0192   }
0193 
0194   //fiber placement and description in blocks
0195   auto fiberMat = description.material(fiber_tube.attr<std::string>(_Unicode(material)));
0196   Tube fiberShape(0., fr, fbSize.z() / 2.0);
0197   Volume fiberVol("fiber_vol", fiberShape, fiberMat);
0198   fiberVol.setVisAttributes(description.visAttributes(fiber_tube.attr<std::string>(_Unicode(vis))));
0199   fiberVol.setSensitiveDetector(sens);
0200 
0201   int num_fX = int(fbSize.x() / (2 * fr + 2.0 * fsx));
0202   int num_fY = int(fbSize.y() / (2 * fr + 2.0 * fsy));
0203 
0204   double fiber_xpos0 = -(fbSize.x() / 2.0) + fr + fsx;
0205   double fiber_ypos0 = -(fbSize.y() / 2.0) + fr + fsy;
0206   int nfibers        = 0;
0207 
0208   //Fiber Holder
0209   auto fiberholder_x = mod_x.child(_Unicode(fiberholder));
0210   double fh_dz       = 0.25 * mm; //thickness of fiber holder
0211 
0212   double fh_outerbox_y = 2.0 * fr + 2.0 * fsy;
0213   double fh_outerbox_x = 2.0 * fr + 2.0 * fsx;
0214   Box fh_outerbox(fh_outerbox_x / 2.0, fh_outerbox_y / 2.0, fh_dz / 2.0);
0215 
0216   double fh_innerbox_y = 2.0 * fr;
0217   double fh_innerbox_x = 2.0 * fr;
0218   Box fh_innerbox(fh_innerbox_x / 2.0, fh_innerbox_y / 2.0, fh_dz / 2.0);
0219 
0220   SubtractionSolid fiberholder_solid(fh_outerbox, fh_innerbox, Position(0.0, 0.0, 0.0));
0221   auto fiberholderMat = description.material(fiberholder_x.attr<std::string>(_Unicode(material)));
0222   Volume fiberholderVol("fiberholder_vol", fiberholder_solid, fiberholderMat);
0223   fiberholderVol.setVisAttributes(
0224       description.visAttributes(fiberholder_x.attr<std::string>(_Unicode(vis))));
0225 
0226   int nfh = 0;
0227 
0228   //placement of fibers and fiberholder
0229   for (int iy = 0; iy < num_fY; iy++) {
0230     for (int ix = 0; ix < num_fX; ix++) {
0231 
0232       double fiber_pos_x = fiber_xpos0 + ix * (2.0 * fr + 2.0 * fsx); //mm
0233       double fiber_pos_y = fiber_ypos0 + iy * (2.0 * fr + 2.0 * fsy); //mm
0234       double fiber_pos_z = 0 * mm;                                    //mm
0235 
0236       //placement of fiber
0237       auto fiberPV =
0238           fbVol.placeVolume(fiberVol, nfibers++, Position{fiber_pos_x, fiber_pos_y, fiber_pos_z});
0239       fiberPV.addPhysVolID("fiber_x", ix + 1).addPhysVolID("fiber_y", iy + 1);
0240 
0241       //placement of fiber holder 6.6*cm apart c-to-c
0242       int num_holders  = 6; // which means 4 regions
0243       double fh_pos_z0 = -1 * (fbSize.z() / 2.0) + (fh_dz / 2.0);
0244 
0245       for (int iz = 0; iz < num_holders; iz++) {
0246         double fh_pos_z = fh_pos_z0 + iz * ((fbSize.z() - fh_dz) / (num_holders - 1));
0247         fbVol.placeVolume(fiberholderVol, nfh++, Position{fiber_pos_x, fiber_pos_y, fh_pos_z});
0248       } //iz close
0249 
0250     } //ix close
0251   } //iy close
0252 
0253   return make_tuple(modVol, modSize);
0254 
0255 } // build_specScifiCAL_module function close
0256 
0257 DECLARE_DETELEMENT(EcalLumiSpecWScFi, create_detector)