Skip to content

Commit

Permalink
Added a modified version of the Generic Cal Endcap without cutout
Browse files Browse the repository at this point in the history
  • Loading branch information
bartosik-hep authored and tmadlener committed Jun 11, 2024
1 parent 3042e58 commit 8e54df1
Showing 1 changed file with 253 additions and 0 deletions.
253 changes: 253 additions & 0 deletions detector/calorimeter/GenericCalEndcap_o2_v01_geo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
//====================================================================
// Modified Generic Endcap Driver for the CLIC detector
//--------------------------------------------------------------------
//
// Author : N.Nikiforou
// Adapted from PolyhedraBarrel Calorimeter by M. Frank
// Note: This driver supports conical inner shape in the endcap controlled by rmin and rmin2
//
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "XML/Layering.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
#include "DDSegmentation/Segmentation.h"


using namespace std;

using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::Layering;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::Cone;
using dd4hep::PolyhedraRegular;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::RotationZYX;
using dd4hep::Segmentation;
using dd4hep::SensitiveDetector;
using dd4hep::SubtractionSolid;
using dd4hep::Transform3D;
using dd4hep::Volume;
using dd4hep::_toString;

using dd4hep::rec::LayeredCalorimeterData;

// workaround for DD4hep v00-14 (and older)
#ifndef DD4HEP_VERSION_GE
#define DD4HEP_VERSION_GE(a,b) 0
#endif

static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) {
xml_det_t x_det = e;
int det_id = x_det.id();
string det_name = x_det.nameStr();
DetElement sdet (det_name,det_id);

// --- create an envelope volume and position it into the world ---------------------

Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, e , sdet ) ;
dd4hep::xml::setDetectorTypeFlag( e, sdet ) ;

if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;

//-----------------------------------------------------------------------------------

xml_dim_t dim = x_det.dimensions();
Material air = theDetector.air();
int nsides_inner = dim.nsides_inner();
int nsides_outer = dim.nsides_outer();
double rmin = dim.rmin();
double rmax = dim.rmax(); /// FIXME: IS THIS RIGHT?
double zmin = dim.zmin();
// Second internal radius for the conical cutout
double rmin2 = dim.hasAttr(_U(rmin2)) ? dim.rmin2() : rmin;

Layering layering(x_det);
double totalThickness = layering.totalThickness();
int n_layers = layering.layers().size();
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();

std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID
double cell_sizeX = cellSizeVector[0];
double cell_sizeY = cellSizeVector[1];


PolyhedraRegular polyVolume(nsides_outer,0,rmax,totalThickness);
Volume endcapVol("endcap",polyVolume,air);


if(rmin2 != rmin){
Cone cutoutPolyVolume(totalThickness/1.99, 0,rmin, 0,rmin2);
endcapVol=Volume("endcap", SubtractionSolid(polyVolume, cutoutPolyVolume, Position(0,0,0)), air);

}


DetElement endcapA(sdet,"endcap",det_id);
Ref_t(endcapA)->SetName((det_name+"_A").c_str());

int layer_num = 0;
int layerType = 0;
double layerZ = -totalThickness/2;

//Create caloData object to extend driver with data required for reconstruction
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
caloData->inner_symmetry = nsides_inner;
caloData->outer_symmetry = nsides_outer;

/** NOTE: phi0=0 means lower face flat parallel to experimental floor
* This is achieved by rotating the modules with respect to the envelope
* which is assumed to be a Polyhedron and has its axes rotated with respect
* to the world by 180/nsides. In any other case (e.g. if you want to have
* a tip of the calorimeter touching the ground) this value needs to be computed
*/

caloData->inner_phi0 = 0.;
caloData->outer_phi0 = 0.;
caloData->gap0 = 0.; //FIXME
caloData->gap1 = 0.; //FIXME
caloData->gap2 = 0.; //FIXME


/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = rmin ;
caloData->extent[1] = rmax ; ///FIXME: CHECK WHAT IS NEEDED (EXSCRIBED?)
caloData->extent[2] = zmin ;
caloData->extent[3] = zmin + totalThickness;

endcapVol.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());

for(xml_coll_t c(x_det,_U(layer)); c; ++c) {
xml_comp_t x_layer = c;
double layer_thick = layering.layer(layer_num)->thickness();
string layer_type_name = _toString(layerType,"layerType%d");
int layer_repeat = x_layer.repeat();
double layer_rmin = x_layer.rmin();

std::cout<<"Number of layers in group "<<layerType<<" : "<<layer_repeat<<std::endl;

Volume layer_vol(layer_type_name,PolyhedraRegular(nsides_outer,layer_rmin,rmax,layer_thick),air);

int slice_num = 0;
double sliceZ = -layer_thick/2;

//Create a caloLayer struct for thiss layer type to store copies of in the parent struct
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;

double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;

for(xml_coll_t s(x_layer,_U(slice)); s; ++s) {
xml_comp_t x_slice = s;
string slice_name = _toString(slice_num,"slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
Volume slice_vol(slice_name,PolyhedraRegular(nsides_outer,layer_rmin,rmax,slice_thickness),slice_material);

slice_vol.setVisAttributes(theDetector.visAttributes(x_slice.visStr()));
sliceZ += slice_thickness/2;
layer_vol.placeVolume(slice_vol,Position(0,0,sliceZ));

nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;

if ( x_slice.isSensitive() ) {
sens.setType("calorimeter");
slice_vol.setSensitiveDetector(sens);

#if DD4HEP_VERSION_GE( 0, 15 )
//Store "inner" quantities
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
//Store scintillator thickness
caloLayer.sensitive_thickness = slice_thickness;
#endif
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
}

nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;

sliceZ += slice_thickness/2;
slice_num++;
}

#if DD4HEP_VERSION_GE( 0, 15 )
//Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
#endif
layer_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr()));


if ( layer_repeat <= 0 ) throw std::runtime_error(x_det.nameStr()+"> Invalid repeat value");

for(int j=0; j<layer_repeat; ++j) {
string phys_lay = _toString(layer_num,"layer%d");

//The rest of the data is constant; only the distance needs to be updated
//Store the position up to the inner face of the layer
caloLayer.distance = zmin + totalThickness/2 + layerZ;
//Push back a copy to the caloData structure
caloData->layers.push_back( caloLayer );

layerZ += layer_thick/2;
DetElement layer_elt(endcapA, phys_lay, layer_num);
PlacedVolume pv = endcapVol.placeVolume(layer_vol,Position(0,0,layerZ));
pv.addPhysVolID("layer", layer_num);
layer_elt.setPlacement(pv);

layerZ += layer_thick/2;
++layer_num;
}
++layerType;
}

double z_pos = zmin+totalThickness/2;
PlacedVolume pv;
// Reflect it.

DetElement endcapB = endcapA.clone(det_name+"_B",x_det.id());

//Removed rotations to align with envelope
//NOTE: If the envelope is not a polyhedron (eg. if you use a tube)
//you may need to rotate so the axes match

pv = envelope.placeVolume(endcapVol,Transform3D(RotationZYX(0,0,0),
Position(0,0,z_pos)));
pv.addPhysVolID("side", 1);
endcapA.setPlacement(pv);

//Removed rotations
pv = envelope.placeVolume(endcapVol,Transform3D(RotationZYX(0,M_PI,0),
Position(0,0,-z_pos)));
pv.addPhysVolID("side", 2);
endcapB.setPlacement(pv);

sdet.add(endcapB);

sdet.addExtension< LayeredCalorimeterData >( caloData ) ;

return sdet;

}

DECLARE_DETELEMENT(GenericCalEndcap_o2_v01,create_detector)

0 comments on commit 8e54df1

Please sign in to comment.