Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • maxt/CEPCSW
  • zyjonah/CEPCSW
  • wanjw03/CEPCSW
  • yudian2002/CEPCSW
  • starr136a/CEPCSW
  • fucd/CEPCSW
  • shuohan/CEPCSW
  • glliu/CEPCSW
  • zhangjinxian/CEPCSW_20250110
  • zhangyz/CEPCSW
  • shuxian/CEPCSW
  • lihp29/CEPCSW
  • zhangkl/CEPCSW
  • laipz/CEPCSW
  • lizhihao/CEPCSW
  • yudian2002/cepcsw-otk-endcap-update-01
  • xuchj7/CEPCSW
  • wuchonghao9612/CEPCSW
  • chenye/CEPCSW
  • zhangxm/CEPCSW
  • mengwq/CEPCSW
  • yudian2002/cepcsw-geo-upgrade-v-2
  • fangwx/CEPCSW
  • yudian2002/cepcsw-geo-upgrade
  • jiangxj/CEPCSW
  • yudian2002/cepcsw-otk-end-cap-development
  • guolei/CEPCSW
  • chenbp/CEPCSW
  • dhb112358/CEPCSW
  • tangyb/CEPCSW
  • luhc/CEPCSW
  • songwz/cepcsw-tdr
  • yudian2002/cepcsw-ote-development
  • yudian2002/cepcsw-otb-development
  • dudejing/CEPCSW
  • shexin/CEPCSW
  • sunwy/CEPCSW
  • 1810337/CEPCSW
  • cepcsw/CEPCSW
  • tyzhang/CEPCSW
  • fucd/CEPCSW1
  • xiaolin.wang/CEPCSW
  • wangchu/CEPCSW
  • 201840277/CEPCSW
  • zhaog/CEPCSW
  • shihy/cepcsw-dose
  • myliu/CEPCSW
  • thinking/CEPCSW
  • lihn/CEPCSW
  • 221840222/CEPCSW
  • gongjd1119/CEPCSW
  • tanggy/CEPCSW
  • lintao/CEPCSW
  • guofangyi/cepcsw-release
  • shihy/CEPCSW
  • 1365447033/CEPCSW
  • lizhan/CEPCSW
  • shixin/CEPCSW
  • cepc/CEPCSW
59 results
Show changes
Showing
with 4267 additions and 41 deletions
<define>
<constant name="Yoke_cells_size" value="30*mm"/>
<constant name="Yoke_barrel_inner_radius" value="Yoke_inner_radius"/>
<constant name="Hcal_Yoke_plug_gap" value="45*mm"/>
</define>
......
......@@ -395,7 +395,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
// end of slabs aligned to inner face of support plate in next stave (not the outer surface)
// double Y = (module_thickness/2.) / sin(M_PI/4.);
// double Y = (module_thickness_noSupport/2.) / sin(2.*M_PI/nsides);
double Y = (module_thickness/2.) / sin(2.*M_PI/nsides);
double Y = -(module_thickness/2.) / sin(2.*M_PI/nsides);
// stave numbering from 1->8
// stave = 1 is in +ve x direction
......@@ -422,7 +422,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
for (int imodule = 0; imodule < Ecal_barrel_z_modules; imodule++) {
int module_id = imodule+1;
Transform3D tr( RotationZYX( 0 , phirot, M_PI/2.), // magic rotation!
Transform3D tr( RotationZYX( M_PI , phirot, M_PI/2.), // magic rotation!
Translation3D(
( X*cos(phirot2)-Y*sin(phirot2) ) ,
( X*sin(phirot2)+Y*cos(phirot2) ) ,
......
......@@ -207,7 +207,8 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
caloData->extent[2] = EcalEndcapRing_min_z ;
caloData->extent[3] = EcalEndcapRing_max_z ;
cout << " Z: " << EcalEndcapRing_min_z << " -> " << EcalEndcapRing_max_z << endl;
cout << " R: " << EcalEndcapRing_inner_radius << " -> " << EcalEndcapRing_outer_radius << endl;
//====================================================================
//
// general calculated parameters
......
//====================================================================
// SHcalRpc01 - Implementation from ILCSoft's Mokka version
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDSegmentation/TiledLayerGridXY.h"
#include "DDRec/Surface.h"
#include "DDRec/DetectorData.h"
#include "XML/Utilities.h"
using namespace std;
using dd4hep::Ref_t;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::Segmentation;
using dd4hep::Readout;
using dd4hep::Material;
using dd4hep::Volume;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationZYX;
using dd4hep::RotationZ;
using dd4hep::Transform3D;
using dd4hep::Box;
using dd4hep::Tube;
using dd4hep::PolyhedraRegular;
using dd4hep::SubtractionSolid;
using dd4hep::_toString;
using dd4hep::pi;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of SHcalRpc01 detector, ported from Mokka driver SHcalRpc01.cc
*
* Mokka History:
* - first implementation from ILCSoft
* - http://cepcgit.ihep.ac.cn/cepcsoft/MokkaC
*/
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
cout << "--------------------------" << endl;
cout << "creating SHcalRpc01_Barrel" << endl;
cout << "--------------------------" << endl;
xml_det_t x_det = element;
string name = x_det.nameStr();
int det_id = x_det.id();
DetElement det(name, det_id);
Volume envelope = dd4hep::xml::createPlacedEnvelope(theDetector, element , det ) ;
dd4hep::xml::setDetectorTypeFlag(element, det) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return det ;
xml_comp_t x_staves = x_det.staves();
string Hcal_radiator_material = x_staves.materialStr();
Material stavesMaterial = theDetector.material(Hcal_radiator_material);
Material air = theDetector.air();
sens.setType("calorimeter");
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
dd4hep::DDSegmentation::TiledLayerGridXY* tiledSeg = dynamic_cast<dd4hep::DDSegmentation::TiledLayerGridXY*> (seg.segmentation());
assert(tiledSeg && "no TiledLayerGridXY found" );
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0);
double cell_sizeX = cellSizeVector[0];
double cell_sizeZ = cellSizeVector[1];
double Hcal_inner_radius = theDetector.constant<double>("Hcal_inner_radius");
double Hcal_outer_radius_set = theDetector.constant<double>("Hcal_outer_radius");
double Hcal_half_length = theDetector.constant<double>("Hcal_half_length");
int Hcal_inner_symmetry = theDetector.constant<int>("Hcal_inner_symmetry");
int Hcal_outer_symmetry = 0;
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Hcal_modules_gap = theDetector.constant<double>("Hcal_modules_gap");
double Ecal_outer_radius = theDetector.constant<double>("Ecal_outer_radius");
int Hcal_barrel_number_modules = theDetector.constant<int>("Hcal_barrel_number_modules");
double hPrime = Ecal_outer_radius + theDetector.constant<double>("Hcal_Ecal_gap");
Hcal_inner_radius = hPrime / cos(pi/8.);
double Hcal_normal_dim_z = (2*Hcal_half_length - (Hcal_barrel_number_modules-1)*Hcal_modules_gap)/Hcal_barrel_number_modules;
xml_coll_t c(x_det,_U(layer));
xml_comp_t x_layer = c;
int Hcal_nlayers = x_layer.repeat();
double Hcal_radiator_thickness = 0;
double layerThickness = 0.0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
layerThickness += x_slice.thickness();
if(x_slice.materialStr()==Hcal_radiator_material) Hcal_radiator_thickness = x_slice.thickness();
}
cout << " cell size xy = " << cell_sizeX << " cell size z = " << cell_sizeZ << endl;
cout << " layer_thickness (from slices) = " << layerThickness << " and radiator_thickness = " << Hcal_radiator_thickness << endl;
double Hcal_chamber_thickness = layerThickness - Hcal_radiator_thickness;
int MinNumCellsInTransvPlane = theDetector.constant<int>("Hcal_MinNumCellsInTransvPlane");
double RPC_EdgeWidth = theDetector.constant<double>("Hcal_gas_edge_width");
double RPCGazInletInnerRadius = theDetector.constant<double>("Hcal_gasInlet_inner_radius");
double RPCGazInletOuterRadius = theDetector.constant<double>("Hcal_gasInlet_outer_radius");
double RPCGazInletLength = theDetector.constant<double>("Hcal_gasInlet_length");
double RPC_PadSeparation = theDetector.constant<double>("Hcal_pad_separation");
double Hcal_spacer_thickness = theDetector.constant<double>("Hcal_spacer_thickness");
double Hcal_spacer_separation = theDetector.constant<double>("Hcal_spacer_separation");
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
caloData->inner_symmetry = Hcal_inner_symmetry ;
caloData->outer_symmetry = Hcal_outer_symmetry ;
caloData->phi0 = 0 ; // fg: also hardcoded below
// general calculated parameters
double AngleRatio=0.76536686;//"k"
double d_InnerOctoSize=AngleRatio*Hcal_inner_radius;//"d"
double LMin = 2*RPC_EdgeWidth+cell_sizeX*MinNumCellsInTransvPlane+(MinNumCellsInTransvPlane+1)*RPC_PadSeparation;
double Ynl = 0.5*d_InnerOctoSize - Hcal_nlayers*layerThickness;
double Hcal_outer_radius = sqrt((LMin-Ynl)*(LMin-Ynl) + (hPrime + Hcal_nlayers*layerThickness)*(hPrime + Hcal_nlayers*layerThickness));
if(Hcal_outer_radius!=Hcal_outer_radius_set){
cout << "calculated Hcal_outer_radius != input, will impact HcalEndcap and HcalEndcapRing. Hcal_outer_radius = " << Hcal_outer_radius
<< " but set as " << Hcal_outer_radius_set << " difference = " << Hcal_outer_radius-Hcal_outer_radius_set << endl;
}
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in cm.
caloData->extent[0] = Hcal_inner_radius ;
caloData->extent[1] = Hcal_outer_radius ;
caloData->extent[2] = 0. ; // Barrel zmin is "0" by default.
caloData->extent[3] = Hcal_half_length ;
double Hcal_total_dim_y = Hcal_outer_radius - hPrime;
// the y_dim1_for_z kept as the original value in TDR
double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z - 2 *(Hcal_lateral_plate_thickness);
//int N_cells_z = static_cast <int> ( (Hcal_regular_chamber_dim_z - 2*RPC_EdgeWidth - RPC_PadSeparation) / (Hcal_cell_dim_x + RPC_PadSeparation) );
// Hcal_cell_dim_z=(Hcal_regular_chamber_dim_z-RPC_PadSeparation )/N_cells_z
// - RPC_PadSeparation;
Tube solidCaloTube(0, Hcal_outer_radius, Hcal_half_length);
PolyhedraRegular solidOctogon(8, 0, hPrime, 4*Hcal_half_length);
RotationZYX rotOctogon(dd4hep::twopi/16,0,0);
SubtractionSolid solidCalo(solidCaloTube, solidOctogon, rotOctogon);
Volume logicCalo(name+"_radiator", solidCalo, stavesMaterial);
logicCalo.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
PlacedVolume calo_pv = envelope.placeVolume(logicCalo, Position(0,0,0));
DetElement calo(det, "envelope", det_id);
calo.setPlacement(calo_pv);
if(tiledSeg) tiledSeg->setOffsetY(-(Hcal_regular_chamber_dim_z/2.-RPC_EdgeWidth)+0.5*cell_sizeZ);
for(int layer_id=1; layer_id<=Hcal_nlayers; layer_id++){
double yn = sqrt(Hcal_outer_radius*Hcal_outer_radius - (hPrime + layer_id*layerThickness)*(hPrime + layer_id*layerThickness));
double Yn = 0.5*d_InnerOctoSize - layer_id*layerThickness;
double halfX = Hcal_chamber_thickness/2.;
double halfY = (yn+Yn)/2.;
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeZ;
//double halfZ = Hcal_normal_dim_z / 2.;
double halfZ = Hcal_regular_chamber_dim_z / 2.;
double localXPos = hPrime + Hcal_radiator_thickness + Hcal_chamber_thickness/2. + (layer_id-1)*layerThickness;
double localYPos = -Yn + 0.5*(Yn + yn);
Box chamberSolid(halfY, halfZ, halfX);
string chamberLogical_name = name+_toString(layer_id,"_layer%d");
Volume chamberLogical(chamberLogical_name, chamberSolid, air);
chamberLogical.setAttributes(theDetector, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr());
if(tiledSeg) tiledSeg->setLayerOffsetX((-(halfY-RPC_EdgeWidth)+0.5*cell_sizeX)*2/cell_sizeX);
string layer_name = name+_toString(layer_id,"_layer%d");
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
nRadiationLengths = Hcal_radiator_thickness/(stavesMaterial.radLength());
nInteractionLengths = Hcal_radiator_thickness/(stavesMaterial.intLength());
double slice_pos_z = -halfX;
int slice_number = 0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
if(x_slice.materialStr()==Hcal_radiator_material) continue;
string slice_name = layer_name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
if(layer_id==1) cout<<" Layer_slice: "<< slice_name<<" slice_thickness: "<< slice_thickness<< endl;
slice_pos_z += slice_thickness/2.;
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// Slice volume & box
Box sliceSolid(halfY, halfZ, slice_thickness/2.);
Volume sliceVol(slice_name, sliceSolid, slice_material);
if ( x_slice.isSensitive() ) {
sliceVol.setSensitiveDetector(sens);
if(RPC_EdgeWidth>0){
double RPC_GazInlet_In_Z = halfZ - RPC_EdgeWidth - RPCGazInletOuterRadius;
double RPC_GazInlet_In_Y = halfY - RPC_EdgeWidth/2;
double RPC_GazInlet_Out_Z = -RPC_GazInlet_In_Z;
double RPC_GazInlet_Out_Y = RPC_GazInlet_In_Y;
string mateialName = x_slice.attr<string>(_Unicode(edge_material));
Material edge_material = theDetector.material(mateialName);
Box solidRPCEdge1(halfY, halfZ, slice_thickness/2.);
Box solidRPCEdge2(halfY-RPC_EdgeWidth, halfZ-RPC_EdgeWidth, slice_thickness/2.);
SubtractionSolid solidRPCEdge(solidRPCEdge1, solidRPCEdge2, Position(0,0,0));
Volume logicRPCEdge(slice_name+"_edge", solidRPCEdge, edge_material);
logicRPCEdge.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
sliceVol.placeVolume(logicRPCEdge);
RotationZYX rotGaz(0, pi/2., 0);
Tube solidRPCGazInlet(RPCGazInletInnerRadius,RPCGazInletOuterRadius,RPC_EdgeWidth/*RPCGazInletLength*//2);
Volume logicRPCGazInlet(slice_name+"_GazInlet", solidRPCGazInlet, edge_material);
logicRPCGazInlet.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
logicRPCEdge.placeVolume(logicRPCGazInlet, Transform3D(rotGaz, Position(RPC_GazInlet_In_Y,RPC_GazInlet_In_Z, 0)));
logicRPCEdge.placeVolume(logicRPCGazInlet, Transform3D(rotGaz, Position(RPC_GazInlet_Out_Y,RPC_GazInlet_Out_Z, 0)));
Tube solidRPCGazInsideInlet(0,RPCGazInletInnerRadius,RPC_EdgeWidth/*RPCGazInletLength*//2);
Volume logicRPCGazInsideInlet(slice_name+"_GazInsideInlet", solidRPCGazInsideInlet, slice_material);
logicRPCGazInsideInlet.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),"SeeThrough");
logicRPCEdge.placeVolume(logicRPCGazInsideInlet, Transform3D(rotGaz, Position(RPC_GazInlet_In_Y,RPC_GazInlet_In_Z, 0)));
logicRPCEdge.placeVolume(logicRPCGazInsideInlet, Transform3D(rotGaz,Position(RPC_GazInlet_Out_Y,RPC_GazInlet_Out_Z, 0)));
}
if(Hcal_spacer_thickness>0){
Tube solidRPCSpacer(0,Hcal_spacer_thickness/2,slice_thickness/2);
Material space_material = theDetector.material(x_slice.attr<string>(_Unicode(spacer_material)));
Volume logicRPCSpacer(slice_name+"_spacer", solidRPCSpacer, space_material);
logicRPCSpacer.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
RotationZYX rotSpacer(0, 0, 0);
double gap_hZ = halfZ-RPC_EdgeWidth;
double gap_hY = halfY-RPC_EdgeWidth;
int y_number_of_separations = (int)(2*gap_hY/Hcal_spacer_separation);
int z_number_of_separations = (int)(2*gap_hZ/Hcal_spacer_separation);
double y_lateral_space = (2*gap_hY - y_number_of_separations*Hcal_spacer_separation)/2;
double z_lateral_space = (2*gap_hZ - z_number_of_separations*Hcal_spacer_separation)/2;
if(y_lateral_space < Hcal_spacer_thickness/2.){
y_number_of_separations = (int)((2*gap_hY-Hcal_spacer_thickness)/Hcal_spacer_separation);
y_lateral_space = (2*gap_hY - y_number_of_separations*Hcal_spacer_separation)/2;
}
if(z_lateral_space < Hcal_spacer_thickness/2.){
z_number_of_separations = (int)((2*gap_hZ-Hcal_spacer_thickness)/Hcal_spacer_separation);
z_lateral_space = (2*gap_hZ - z_number_of_separations*Hcal_spacer_separation)/2;
}
for(int y_counter = 0; y_counter <=y_number_of_separations; y_counter++){
double SpacerY = gap_hY - y_lateral_space - y_counter*Hcal_spacer_separation;
for(int z_counter = 0; z_counter <=z_number_of_separations; z_counter++){
double SpacerZ = gap_hZ - z_lateral_space - z_counter*Hcal_spacer_separation;
PlacedVolume space_pv = sliceVol.placeVolume(logicRPCSpacer, Transform3D(rotSpacer, Position(SpacerY,SpacerZ,0)));
}
}
}
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
if(layer_id==1) cout<<"Hcal_Barrel: inner_thickness= "<<thickness_sum<<endl;
//Store readout gasgap thickness
caloLayer.sensitive_thickness = slice_thickness;
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),"SeeThrough");
}
else{
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
}
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// slice PlacedVolume
PlacedVolume slice_phv = chamberLogical.placeVolume(sliceVol,Position(0,0,slice_pos_z));
if ( x_slice.isSensitive() ) {
int slice_id = (layer_id > Hcal_nlayers)? 1:-1;
slice_phv.addPhysVolID("layer",layer_id).addPhysVolID("slice",slice_id);
}
DetElement sliceDetE(layer_name,_toString(slice_number,"slice%d"),x_det.id());
sliceDetE.setPlacement(slice_phv);
// Increment x position for next slice.
slice_pos_z += slice_thickness/2.;
// Increment slice number.
++slice_number;
}
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
if(layer_id==1) cout << "Hcal_Barrel: outer_thickness= " << thickness_sum << endl;
double chamber_y_offset = -(-Hcal_total_dim_y/2. + (layer_id-1)*layerThickness + layerThickness/2.);
caloLayer.distance = Hcal_inner_radius + Hcal_total_dim_y/2.0 + chamber_y_offset ;
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
double stave_phi_offset, module_z_offset;
stave_phi_offset = pi*0.5;
for(int stave_id = 1; stave_id <= 8; stave_id++){
double phirot = stave_phi_offset+(stave_id-1)*pi/4.;
RotationZYX rot(pi/2, pi/2, 0); //phirot);
RotationZ rotZ(phirot);
RotationZYX rotAll = rotZ*rot;
RotationZYX rotInverse(phirot, 0, 0);
for(int module_id = 1; module_id <= Hcal_barrel_number_modules; module_id++){
module_z_offset = - Hcal_half_length + Hcal_normal_dim_z/2. + (module_id-1)*(Hcal_normal_dim_z+Hcal_modules_gap);
Position localPos(localXPos,localYPos,module_z_offset);
Position newPos = rotInverse*localPos;
Transform3D tran3D(rotAll, newPos);
PlacedVolume pv = logicCalo.placeVolume(chamberLogical, tran3D);
pv.addPhysVolID("stave",stave_id).addPhysVolID("module",module_id).addPhysVolID("layer",layer_id);
DetElement layer(calo, name+_toString(stave_id,"_stave%d")+_toString(module_id,"_module%d")+_toString(layer_id,"_layer%d"), det_id);
layer.setPlacement(pv);
}
}
}
det.addExtension< LayeredCalorimeterData >( caloData ) ;
return det;
}
DECLARE_DETELEMENT(SHcalRpc01_Barrel, create_detector)
//====================================================================
// SHcalRpc01 - Implementation from ILCSoft's Mokka version
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDRec/Surface.h"
#include "DDRec/DetectorData.h"
#include "XML/Utilities.h"
using namespace std;
using dd4hep::Ref_t;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::Segmentation;
using dd4hep::Readout;
using dd4hep::Material;
using dd4hep::Volume;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationZYX;
using dd4hep::Transform3D;
using dd4hep::Box;
using dd4hep::Tube;
using dd4hep::PolyhedraRegular;
using dd4hep::SubtractionSolid;
using dd4hep::IntersectionSolid;
using dd4hep::_toString;
using dd4hep::pi;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of SHcalRpc01 detector, ported from Mokka driver SHcalRpc01.cc
*
* Mokka History:
* - first implementation from ILCSoft
* - http://cepcgit.ihep.ac.cn/cepcsoft/MokkaC
*/
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
cout << "------------------------------" << endl;
cout << "creating SHcalRpc01_EndcapRing" << endl;
cout << "------------------------------" << endl;
xml_det_t x_det = element;
string name = x_det.nameStr();
int det_id = x_det.id();
DetElement det(name, det_id) ;
xml_comp_t x_staves = x_det.staves();
string Hcal_radiator_material = x_staves.materialStr();
Material stavesMaterial = theDetector.material(Hcal_radiator_material);
Material air = theDetector.air();
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , det ) ;
dd4hep::xml::setDetectorTypeFlag( element, det ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return det ;
sens.setType("calorimeter");
DetElement module(det,"module0",det_id);
DetElement layer(module, "stave_layer", det_id);
DetElement slice(layer, "slice", det_id);
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0);
double cell_sizeX = cellSizeVector[0];
double cell_sizeY = cellSizeVector[1];
double Hcal_outer_radius = theDetector.constant<double>("Hcal_outer_radius");
int Hcal_endcap_outer_symmetry = theDetector.constant<int>("Hcal_endcap_outer_symmetry");
double Hcal_stave_gaps = theDetector.constant<double>("Hcal_stave_gaps");
int Hcal_nlayers = theDetector.constant<int>("Hcal_endcap_nlayers");
double Hcal_start_z = theDetector.constant<double>("Hcal_endcap_zmin");
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Ecal_endcap_zmin = theDetector.constant<double>("Ecal_endcap_zmin");
double Hcal_endcap_ecal_gap = theDetector.constant<double>("Hcal_endcap_ecal_gap");
double Ecal_endcap_outer_radius = theDetector.constant<double>("EcalEndcap_outer_radius");
double Hcal_radial_ring_inner_gap = theDetector.constant<double>("Hcal_radial_ring_inner_gap");
xml_coll_t c(x_det,_U(layer));
xml_comp_t x_layer = c;
double Hcal_radiator_thickness = 0;
double layerThickness = 0.0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
layerThickness += x_slice.thickness();
if(x_slice.materialStr()==Hcal_radiator_material) Hcal_radiator_thickness = x_slice.thickness();
}
cout << " layer_thickness (from slices) = " << layerThickness << " and radiator_thickness = " << Hcal_radiator_thickness << endl;
double Hcal_chamber_thickness = layerThickness - Hcal_radiator_thickness;
int numSide = Hcal_endcap_outer_symmetry;
double Hcal_endcap_rmax = Hcal_outer_radius * cos(pi/numSide);
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
caloData->inner_symmetry = numSide;
caloData->outer_symmetry = numSide;
caloData->phi0 = 0;
double start_z = Ecal_endcap_zmin;
double SpaceForLayers = Hcal_start_z - Hcal_endcap_ecal_gap - Ecal_endcap_zmin - 2*Hcal_lateral_plate_thickness;
int MaxNumberOfLayers = (int)(SpaceForLayers / (Hcal_chamber_thickness + Hcal_radiator_thickness));
double stop_z = start_z + MaxNumberOfLayers*layerThickness + 2*Hcal_lateral_plate_thickness;
double pRMax = Hcal_endcap_rmax;
double pDz = (stop_z - start_z)/2.;
double pRMin = Ecal_endcap_outer_radius + Hcal_radial_ring_inner_gap;
cout << "Rings will have " << MaxNumberOfLayers << " layers." << endl;
cout << " Z: " << start_z << " -> " << stop_z << endl;
cout << " R: " << pRMin << " -> " << pRMax << endl;
caloData->extent[0] = pRMin;
caloData->extent[1] = pRMax;
caloData->extent[2] = start_z;
caloData->extent[3] = stop_z;
PolyhedraRegular EndCapRingSolidPoly(numSide, -pi/numSide, pRMin, pRMax, 2*pDz);
Volume EndCapRingLogical(name+"_radiator", EndCapRingSolidPoly, stavesMaterial);
EndCapRingLogical.setAttributes(theDetector,x_staves.regionStr(),x_staves.limitsStr(),x_staves.visStr());
int number_of_chambers = Hcal_nlayers;
if(MaxNumberOfLayers < number_of_chambers) number_of_chambers = MaxNumberOfLayers;
double rInner = pRMin + Hcal_lateral_plate_thickness;
double rOuter = pRMax - Hcal_lateral_plate_thickness;
PolyhedraRegular EndCapRingChamberPoly(numSide, -pi/numSide, rInner, rOuter, Hcal_chamber_thickness);
Box IntersectionStaveBox(rOuter/2., rOuter/2., Hcal_chamber_thickness/2);
Position IntersectPos(rOuter/2. + Hcal_stave_gaps/2., rOuter/2. + Hcal_stave_gaps/2., 0.);
IntersectionSolid EndCapRingStaveSolid(EndCapRingChamberPoly, IntersectionStaveBox, IntersectPos);
Volume EndCapRingChamberLogical(name+"_chamber", EndCapRingStaveSolid, air);
EndCapRingChamberLogical.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
double nRadiationLengthsInside=0.;
double nInteractionLengthsInside=0.;
double inner_thickness=0;
double sensitive_thickness=0;
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
double slice_pos_z = -Hcal_chamber_thickness/2.;
int slice_number = 0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
string slice_name = name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
cout<<" Layer_slice: " << slice_name << " slice_thickness: " << slice_thickness<< endl;
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
if(x_slice.materialStr()==Hcal_radiator_material) continue;
slice_pos_z += slice_thickness/2.;
PolyhedraRegular slicePoly(numSide, -pi/numSide, rInner, rOuter, slice_thickness);
IntersectionSolid sliceStaveSolid(slicePoly, IntersectionStaveBox, IntersectPos);
Volume sliceVol(name + _toString(slice_number,"_slice%d"), sliceStaveSolid, slice_material);
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
if(x_slice.isSensitive()){
sliceVol.setSensitiveDetector(sens);
nRadiationLengthsInside = nRadiationLengths;
nInteractionLengthsInside = nInteractionLengths;
inner_thickness = thickness_sum;
sensitive_thickness = slice_thickness;
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;
// slice PlacedVolume
PlacedVolume slice_phv = EndCapRingChamberLogical.placeVolume(sliceVol,Position(0,0,slice_pos_z));
//DetElement slice(layer_name,_toString(slice_number,"slice%d"),x_det.id());
slice.setPlacement(slice_phv);
// Increment x position for next slice.
slice_pos_z += slice_thickness/2.;
// Increment slice number.
++slice_number;
}
// chamber placements
for(int stave_id = 1; stave_id <= 4; stave_id++){
double angle = -pi/2.*(stave_id-1);
RotationZYX lrot(angle,0,0);
for (int layer_id = 1; layer_id <= number_of_chambers; layer_id++){
double Zoff = -pDz + (layer_id-1)*layerThickness + Hcal_radiator_thickness + Hcal_chamber_thickness/2.;
Position l_pos(0., 0., Zoff);
Position l_new = lrot*l_pos;
Transform3D ltran3D(lrot,l_new);
PlacedVolume layer_phv = EndCapRingLogical.placeVolume(EndCapRingChamberLogical, ltran3D);
layer_phv.addPhysVolID("layer",layer_id);
layer_phv.addPhysVolID("stave",stave_id);
//string l_name = _toString(layer_id,"layer%d");
//string stave_name = _toString(stave_id,"stave%d");
//DetElement layer(module_det, l_name+stave_name, det_id);
layer.setPlacement(layer_phv);
if(stave_id==1&&layer_id==1){
cout << "Hcal_EndcapRing: inner_thickness= " << inner_thickness << endl;
cout << "Hcal_EndcapRing: outer_thickness= " << thickness_sum << endl;
}
if(stave_id==1){//only one needed, according to wenxingfang's
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;
caloLayer.inner_nRadiationLengths = nRadiationLengthsInside;
caloLayer.inner_nInteractionLengths = nInteractionLengthsInside;
caloLayer.inner_thickness = inner_thickness;
caloLayer.sensitive_thickness = sensitive_thickness;
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
caloLayer.distance = start_z + (layer_id-1)*layerThickness;
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
}
}
}
// Placements
double endcap_z_offset = start_z + pDz;
for(int side = 0; side <= 1; side++){
int module_id = (side==0) ? 6 : 0;
double this_module_z_offset = (side==0) ? endcap_z_offset : -endcap_z_offset;
// use reflect volume for z<0, therefore, same rotation
// segmentation violation happen if EndCapRingLogical.reflect(), back to rotate Y
// double this_module_rotY = (side==0) ? 0.0 : 0.0;
double this_module_rotY = (side==0) ? 0.0 : pi;
//double this_module_rotZ = (side==0) ? pi/8. : pi/8;
RotationZYX rot(0,this_module_rotY,0);
Transform3D tran3D(rot,Position(0,0,this_module_z_offset));
PlacedVolume module_phv;
//if(side==0) module_phv = envelope.placeVolume(EndCapRingLogical, tran3D);
//else module_phv = envelope.placeVolume(EndCapRingLogical.reflect(), tran3D);
module_phv = envelope.placeVolume(EndCapRingLogical, tran3D);
module_phv.addPhysVolID("module", module_id);
//DetElement sd = (module_id==0) ? module_det : module_det.clone(_toString(side,"module%d"));
module.setPlacement(module_phv);
}
det.addExtension<LayeredCalorimeterData>(caloData) ;
return det;
}
DECLARE_DETELEMENT(SHcalRpc01_EndcapRing, create_detector)
//====================================================================
// SHcalRpc01 - Implementation from ILCSoft's Mokka version
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDRec/Surface.h"
#include "DDRec/DetectorData.h"
#include "XML/Utilities.h"
using namespace std;
using dd4hep::Ref_t;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::Segmentation;
using dd4hep::Readout;
using dd4hep::Material;
using dd4hep::Volume;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationZYX;
using dd4hep::Transform3D;
using dd4hep::Box;
using dd4hep::Tube;
using dd4hep::PolyhedraRegular;
using dd4hep::SubtractionSolid;
using dd4hep::IntersectionSolid;
using dd4hep::_toString;
using dd4hep::pi;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of SHcalRpc01 detector, ported from Mokka driver SHcalRpc01.cc
*
* Mokka History:
* - first implementation from ILCSoft
* - http://cepcgit.ihep.ac.cn/cepcsoft/MokkaC
*/
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
cout << "--------------------------" << endl;
cout << "creating SHcalRpc01_Endcap" << endl;
cout << "--------------------------" << endl;
xml_det_t x_det = element;
string name = x_det.nameStr();
int det_id = x_det.id();
DetElement det(name, det_id) ;
xml_comp_t x_staves = x_det.staves();
string Hcal_radiator_material = x_staves.materialStr();
Material stavesMaterial = theDetector.material(Hcal_radiator_material);
Material air = theDetector.air();
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , det ) ;
dd4hep::xml::setDetectorTypeFlag( element, det ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return det ;
sens.setType("calorimeter");
DetElement module(det,"module0",det_id);
DetElement layer(module, "stave_layer", det_id);
DetElement slice(layer, "slice", det_id);
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0);
double cell_sizeX = cellSizeVector[0];
double cell_sizeY = cellSizeVector[1];
//double Hcal_inner_radius = theDetector.constant<double>("Hcal_inner_radius");
double Hcal_outer_radius = theDetector.constant<double>("Hcal_outer_radius");
//double Hcal_half_length = theDetector.constant<double>("Hcal_half_length");
int Hcal_endcap_outer_symmetry = theDetector.constant<int>("Hcal_endcap_outer_symmetry");
//double Hcal_cells_size = theDetector.constant<double>("Hcal_cells_size");
double Hcal_stave_gaps = theDetector.constant<double>("Hcal_stave_gaps");
int Hcal_nlayers = theDetector.constant<int>("Hcal_endcap_nlayers");
double Hcal_start_z = theDetector.constant<double>("Hcal_endcap_zmin");
double Hcal_end_z = theDetector.constant<double>("HcalEndcap_max_z");
double Hcal_back_plate_thickness = theDetector.constant<double>("Hcal_back_plate_thickness");
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Hcal_endcap_center_box_size = theDetector.constant<double>("Hcal_endcap_center_box_size");
xml_coll_t c(x_det,_U(layer));
xml_comp_t x_layer = c;
double Hcal_radiator_thickness = 0;
double layerThickness = 0.0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
layerThickness += x_slice.thickness();
if(x_slice.materialStr()==Hcal_radiator_material) Hcal_radiator_thickness = x_slice.thickness();
}
cout << " layer_thickness (from slices) = " << layerThickness << " and radiator_thickness = " << Hcal_radiator_thickness << endl;
double Hcal_chamber_thickness = layerThickness - Hcal_radiator_thickness;
int numSide = Hcal_endcap_outer_symmetry;
double Hcal_endcap_thickness = Hcal_nlayers*layerThickness + Hcal_back_plate_thickness;
double Hcal_endcap_rmax = Hcal_outer_radius * cos(pi/numSide);
cout << " module thickness = " << Hcal_endcap_thickness << endl;
if(Hcal_end_z!=Hcal_start_z+Hcal_endcap_thickness){
cout << "Hcal_end_z input != Hcal_start_z + Hcal_endcap_thickness: " << "Hcal_end_z=" << Hcal_end_z
<< " but Hcal_start_z=" << Hcal_start_z << " and calculate as " << Hcal_start_z+Hcal_endcap_thickness << endl;
}
LayeredCalorimeterData* caloData = new LayeredCalorimeterData;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout;
caloData->inner_symmetry = 4;
caloData->outer_symmetry = Hcal_endcap_outer_symmetry;
caloData->phi0 = 0;
caloData->extent[0] = Hcal_endcap_center_box_size/2.;
caloData->extent[1] = Hcal_outer_radius;
caloData->extent[2] = Hcal_start_z;
caloData->extent[3] = Hcal_start_z+Hcal_endcap_thickness;
double pRMax = Hcal_endcap_rmax;
double pDz = Hcal_endcap_thickness/2.;
double pRMin = Hcal_endcap_center_box_size/2.;
PolyhedraRegular EndCapSolidPoly(numSide, -pi/numSide, 0., pRMax, 2*pDz);
Box hcalECInnerHole(pRMin, pRMin, pDz);
SubtractionSolid solidHCalEC(EndCapSolidPoly,hcalECInnerHole);
Volume EndCapLogical(name+"_radiator", solidHCalEC, stavesMaterial);
EndCapLogical.setAttributes(theDetector,x_staves.regionStr(),x_staves.limitsStr(),x_staves.visStr());
int number_of_chambers = Hcal_nlayers;
int possible_number_of_chambers = (int) (floor(abs(Hcal_endcap_thickness-Hcal_back_plate_thickness) / (Hcal_chamber_thickness + Hcal_radiator_thickness)));
if(possible_number_of_chambers < number_of_chambers) number_of_chambers = possible_number_of_chambers;
double rInner = 0.;
double rOuter= Hcal_endcap_rmax - Hcal_lateral_plate_thickness;
PolyhedraRegular EndCapChamberPoly(numSide, -pi/numSide, rInner, rOuter, Hcal_chamber_thickness);
Box hcalECChamberInnerHole(pRMin + Hcal_lateral_plate_thickness, pRMin + Hcal_lateral_plate_thickness, Hcal_chamber_thickness/2);
SubtractionSolid EndCapChamberSolid(EndCapChamberPoly, hcalECChamberInnerHole);
Box IntersectionStaveBox(rOuter/2., rOuter/2., Hcal_chamber_thickness/2);
Position pos(rOuter/2. + Hcal_stave_gaps/2., rOuter/2. + Hcal_stave_gaps/2., 0.);
Position IntersectPos = pos;
IntersectionSolid EndCapStaveSolid(EndCapChamberSolid, IntersectionStaveBox, IntersectPos);
Volume EndCapChamberLogical(name+"_chamber", EndCapStaveSolid, air);
EndCapChamberLogical.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
double nRadiationLengthsInside=0.;
double nInteractionLengthsInside=0.;
double inner_thickness=0;
double sensitive_thickness=0;
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
double slice_pos_z = -Hcal_chamber_thickness/2.;
int slice_number = 0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
string slice_name = name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
cout<<" Layer_slice: " << slice_name << " slice_thickness: " << slice_thickness<< endl;
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
if(x_slice.materialStr()==Hcal_radiator_material) continue;
slice_pos_z += slice_thickness/2.;
PolyhedraRegular slicePoly(numSide, -pi/numSide, rInner, rOuter, slice_thickness);
SubtractionSolid sliceSolid(slicePoly, hcalECChamberInnerHole);
IntersectionSolid sliceStaveSolid(sliceSolid, IntersectionStaveBox, IntersectPos);
Volume sliceVol(name + _toString(slice_number,"_slice%d"), sliceStaveSolid, slice_material);
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
if(x_slice.isSensitive()){
sliceVol.setSensitiveDetector(sens);
nRadiationLengthsInside = nRadiationLengths;
nInteractionLengthsInside = nInteractionLengths;
inner_thickness = thickness_sum;
sensitive_thickness = slice_thickness;
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;
// slice PlacedVolume
PlacedVolume slice_phv = EndCapChamberLogical.placeVolume(sliceVol,Position(0,0,slice_pos_z));
//DetElement slice(layer_name,_toString(slice_number,"slice%d"),x_det.id());
slice.setPlacement(slice_phv);
// Increment x position for next slice.
slice_pos_z += slice_thickness/2.;
// Increment slice number.
++slice_number;
}
if(possible_number_of_chambers < number_of_chambers) number_of_chambers = possible_number_of_chambers;
// chamber placements
for(int stave_id = 1; stave_id <= 4; stave_id++){
double angle = -pi/2.*(stave_id-1);
//RotationZ lrotz(angle);
RotationZYX lrot(angle,0,0);
for (int layer_id = 1; layer_id <= number_of_chambers; layer_id++){
double Zoff = -Hcal_endcap_thickness/2. + (layer_id-1) *(Hcal_chamber_thickness + Hcal_radiator_thickness) + Hcal_radiator_thickness + Hcal_chamber_thickness/2.;
Position l_pos(0., 0., Zoff);
Position l_new = lrot*l_pos;
Transform3D ltran3D(lrot,l_new);
PlacedVolume layer_phv = EndCapLogical.placeVolume(EndCapChamberLogical, ltran3D);
layer_phv.addPhysVolID("layer",layer_id);
layer_phv.addPhysVolID("stave",stave_id);
//string l_name = _toString(layer_id,"layer%d");
//string stave_name = _toString(stave_id,"stave%d");
//DetElement layer(module_det, l_name+stave_name, det_id);
layer.setPlacement(layer_phv);
if(stave_id==1&&layer_id==1){
cout << "Hcal_Endcap: inner_thickness= " << inner_thickness << endl;
cout << "Hcal_Endcap: outer_thickness= " << thickness_sum << endl;
}
if(stave_id==1){// only for one stave is good. by wenxingfang
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;
caloLayer.inner_nRadiationLengths = nRadiationLengthsInside;
caloLayer.inner_nInteractionLengths = nInteractionLengthsInside;
caloLayer.inner_thickness = inner_thickness;
caloLayer.sensitive_thickness = sensitive_thickness;
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
caloLayer.distance = Hcal_start_z + (layer_id-1)*layerThickness;
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
}
}
}
// Placements
double endcap_z_offset = Hcal_start_z + Hcal_endcap_thickness/2.;
for(int side = 0; side <= 1; side++){
int module_id = (side==0) ? 6 : 0;
double this_module_z_offset = (side==0) ? endcap_z_offset : -endcap_z_offset;
// use reflect volume for z<0, therefore, same rotation
// segmentation violation happen if EndCapRingLogical.reflect(), back to rotate Y
// double this_module_rotY = (side==0) ? 0.0 : 0.0;
double this_module_rotY = (side==0) ? 0.0 : pi;
//double this_module_rotZ = (side==0) ? pi/8. : pi/8;
RotationZYX rot(0,this_module_rotY,0);
Transform3D tran3D(rot,Position(0,0,this_module_z_offset));
PlacedVolume module_phv;
//if(side==0) module_phv = envelope.placeVolume(EndCapRingLogical, tran3D);
//else module_phv = envelope.placeVolume(EndCapRingLogical.reflect(), tran3D);
module_phv = envelope.placeVolume(EndCapLogical, tran3D);
module_phv.addPhysVolID("module", module_id);
//DetElement sd = (module_id==0) ? module_det : module_det.clone(_toString(side,"module%d"));
module.setPlacement(module_phv);
}
det.addExtension<LayeredCalorimeterData>(caloData) ;
return det;
}
DECLARE_DETELEMENT(SHcalRpc01_Endcaps, create_detector)
//====================================================================
// SHcalRpc02 - update fixed 8 staves to optinal staves, FU Chengdong
// SHcalRpc01 - Implementation from ILCSoft's Mokka version
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDSegmentation/TiledLayerGridXY.h"
#include "DDRec/Surface.h"
#include "DDRec/DetectorData.h"
#include "XML/Utilities.h"
using namespace std;
using dd4hep::Ref_t;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::Segmentation;
using dd4hep::Readout;
using dd4hep::Material;
using dd4hep::Volume;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationZYX;
using dd4hep::RotationZ;
using dd4hep::Transform3D;
using dd4hep::Box;
using dd4hep::Tube;
using dd4hep::PolyhedraRegular;
using dd4hep::SubtractionSolid;
using dd4hep::_toString;
using dd4hep::pi;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of SHcalRpc01 detector, ported from Mokka driver SHcalRpc01.cc
*
* Mokka History:
* - first implementation from ILCSoft
* - http://cepcgit.ihep.ac.cn/cepcsoft/MokkaC
*/
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
cout << "--------------------------" << endl;
cout << "creating SHcalRpc01_Barrel" << endl;
cout << "--------------------------" << endl;
xml_det_t x_det = element;
string name = x_det.nameStr();
int det_id = x_det.id();
DetElement det(name, det_id);
Volume envelope = dd4hep::xml::createPlacedEnvelope(theDetector, element , det ) ;
envelope.setVisAttributes(theDetector, "GrayVis");
dd4hep::xml::setDetectorTypeFlag(element, det) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return det ;
xml_comp_t x_staves = x_det.staves();
string Hcal_radiator_material = x_staves.materialStr();
Material stavesMaterial = theDetector.material(Hcal_radiator_material);
Material air = theDetector.air();
sens.setType("calorimeter");
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
dd4hep::DDSegmentation::TiledLayerGridXY* tiledSeg = dynamic_cast<dd4hep::DDSegmentation::TiledLayerGridXY*> (seg.segmentation());
assert(tiledSeg && "no TiledLayerGridXY found" );
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0);
double cell_sizeX = cellSizeVector[0];
double cell_sizeZ = cellSizeVector[1];
double Hcal_inner_radius = theDetector.constant<double>("Hcal_inner_radius");
double Hcal_outer_radius_set = theDetector.constant<double>("Hcal_outer_radius");
double Hcal_half_length = theDetector.constant<double>("Hcal_half_length");
int Hcal_inner_symmetry = theDetector.constant<int>("Hcal_inner_symmetry");
int Hcal_outer_symmetry = 0;
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Hcal_modules_gap = theDetector.constant<double>("Hcal_modules_gap");
double Ecal_outer_radius = theDetector.constant<double>("Ecal_outer_radius");
int Hcal_barrel_number_modules = theDetector.constant<int>("Hcal_barrel_number_modules");
double hPrime = Ecal_outer_radius + theDetector.constant<double>("Hcal_Ecal_gap");
Hcal_inner_radius = hPrime / cos(pi/Hcal_inner_symmetry);
double Hcal_normal_dim_z = (2*Hcal_half_length - (Hcal_barrel_number_modules-1)*Hcal_modules_gap)/Hcal_barrel_number_modules;
xml_coll_t c(x_det,_U(layer));
xml_comp_t x_layer = c;
int Hcal_nlayers = x_layer.repeat();
double Hcal_radiator_thickness = 0;
double layerThickness = 0.0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
layerThickness += x_slice.thickness();
if(x_slice.materialStr()==Hcal_radiator_material) Hcal_radiator_thickness = x_slice.thickness();
}
cout << " inner symmetry = " << Hcal_inner_symmetry << endl;
cout << " Hcal_inner_radius = " << hPrime << endl;
cout << " cell size xy = " << cell_sizeX << " cell size z = " << cell_sizeZ << endl;
cout << " layer_thickness (from slices) = " << layerThickness << " and radiator_thickness = " << Hcal_radiator_thickness << endl;
double Hcal_chamber_thickness = layerThickness - Hcal_radiator_thickness;
int MinNumCellsInTransvPlane = theDetector.constant<int>("Hcal_MinNumCellsInTransvPlane");
double RPC_EdgeWidth = theDetector.constant<double>("Hcal_gas_edge_width");
double RPCGazInletInnerRadius = theDetector.constant<double>("Hcal_gasInlet_inner_radius");
double RPCGazInletOuterRadius = theDetector.constant<double>("Hcal_gasInlet_outer_radius");
double RPCGazInletLength = theDetector.constant<double>("Hcal_gasInlet_length");
double RPC_PadSeparation = theDetector.constant<double>("Hcal_pad_separation");
double Hcal_spacer_thickness = theDetector.constant<double>("Hcal_spacer_thickness");
double Hcal_spacer_separation = theDetector.constant<double>("Hcal_spacer_separation");
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
caloData->inner_symmetry = Hcal_inner_symmetry ;
caloData->outer_symmetry = Hcal_outer_symmetry ;
caloData->phi0 = 0 ; // fg: also hardcoded below
// general calculated parameters
double AngleRatio=tan(dd4hep::pi/Hcal_inner_symmetry);
double d_InnerOctoSize=2*AngleRatio*Hcal_inner_radius;//"d"
double LMin = 2*RPC_EdgeWidth+cell_sizeX*MinNumCellsInTransvPlane+(MinNumCellsInTransvPlane+1)*RPC_PadSeparation;
cout << "LMin=" << LMin << endl;
double Ynl = 0.5*d_InnerOctoSize - Hcal_nlayers*layerThickness/tan(dd4hep::twopi/Hcal_inner_symmetry);
double Hcal_outer_radius = sqrt((LMin-Ynl)*(LMin-Ynl) + (hPrime + Hcal_nlayers*layerThickness)*(hPrime + Hcal_nlayers*layerThickness));
if(Hcal_outer_radius!=Hcal_outer_radius_set){
cout << "calculated Hcal_outer_radius != input, will impact HcalEndcap and HcalEndcapRing. Hcal_outer_radius = " << Hcal_outer_radius
<< " but set as " << Hcal_outer_radius_set << " difference = " << Hcal_outer_radius-Hcal_outer_radius_set << endl;
cout << "if Coil put inside of Hcal, it is possible!" << endl;
}
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in cm.
caloData->extent[0] = Hcal_inner_radius ;
caloData->extent[1] = Hcal_outer_radius ;
caloData->extent[2] = 0. ; // Barrel zmin is "0" by default.
caloData->extent[3] = Hcal_half_length ;
double Hcal_total_dim_y = Hcal_outer_radius - hPrime;
// the y_dim1_for_z kept as the original value in TDR
double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z - 2 *(Hcal_lateral_plate_thickness);
//int N_cells_z = static_cast <int> ( (Hcal_regular_chamber_dim_z - 2*RPC_EdgeWidth - RPC_PadSeparation) / (Hcal_cell_dim_x + RPC_PadSeparation) );
// Hcal_cell_dim_z=(Hcal_regular_chamber_dim_z-RPC_PadSeparation )/N_cells_z
// - RPC_PadSeparation;
Tube solidCaloTube(0, Hcal_outer_radius, Hcal_half_length);
PolyhedraRegular solidOctogon(Hcal_inner_symmetry, 0, hPrime, 4*Hcal_half_length);
RotationZYX rotOctogon(dd4hep::twopi/2/Hcal_inner_symmetry,0,0);
SubtractionSolid solidCalo(solidCaloTube, solidOctogon, rotOctogon);
Volume logicCalo(name+"_radiator", solidCalo, stavesMaterial);
logicCalo.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
PlacedVolume calo_pv = envelope.placeVolume(logicCalo, Position(0,0,0));
DetElement calo(det, "envelope", det_id);
calo.setPlacement(calo_pv);
if(tiledSeg) tiledSeg->setOffsetY(-(Hcal_regular_chamber_dim_z/2.-RPC_EdgeWidth)+0.5*cell_sizeZ);
for(int layer_id=1; layer_id<=Hcal_nlayers; layer_id++){
double yn = sqrt(Hcal_outer_radius*Hcal_outer_radius - (hPrime + layer_id*layerThickness)*(hPrime + layer_id*layerThickness));
double Yn = 0.5*d_InnerOctoSize - layer_id*layerThickness/tan(dd4hep::twopi/Hcal_inner_symmetry);
double halfX = Hcal_chamber_thickness/2.;
double halfY = (yn+Yn)/2.;
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeZ;
//double halfZ = Hcal_normal_dim_z / 2.;
double halfZ = Hcal_regular_chamber_dim_z / 2.;
double localXPos = hPrime + Hcal_radiator_thickness + Hcal_chamber_thickness/2. + (layer_id-1)*layerThickness;
double localYPos = -Yn + 0.5*(Yn + yn);
Box chamberSolid(halfY, halfZ, halfX);
string chamberLogical_name = name+_toString(layer_id,"_layer%d");
Volume chamberLogical(chamberLogical_name, chamberSolid, air);
chamberLogical.setAttributes(theDetector, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr());
if(tiledSeg) tiledSeg->setLayerOffsetX((-(halfY-RPC_EdgeWidth)+0.5*cell_sizeX)*2/cell_sizeX);
string layer_name = name+_toString(layer_id,"_layer%d");
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
nRadiationLengths = Hcal_radiator_thickness/(stavesMaterial.radLength());
nInteractionLengths = Hcal_radiator_thickness/(stavesMaterial.intLength());
double slice_pos_z = -halfX;
int slice_number = 0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
if(x_slice.materialStr()==Hcal_radiator_material) continue;
string slice_name = layer_name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
if(layer_id==1) cout<<" Layer_slice: "<< slice_name<<" slice_thickness: "<< slice_thickness<< endl;
slice_pos_z += slice_thickness/2.;
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// Slice volume & box
Box sliceSolid(halfY, halfZ, slice_thickness/2.);
Volume sliceVol(slice_name, sliceSolid, slice_material);
if ( x_slice.isSensitive() ) {
sliceVol.setSensitiveDetector(sens);
if(RPC_EdgeWidth>0){
double RPC_GazInlet_In_Z = halfZ - RPC_EdgeWidth - RPCGazInletOuterRadius;
double RPC_GazInlet_In_Y = halfY - RPC_EdgeWidth/2;
double RPC_GazInlet_Out_Z = -RPC_GazInlet_In_Z;
double RPC_GazInlet_Out_Y = RPC_GazInlet_In_Y;
string mateialName = x_slice.attr<string>(_Unicode(edge_material));
Material edge_material = theDetector.material(mateialName);
Box solidRPCEdge1(halfY, halfZ, slice_thickness/2.);
Box solidRPCEdge2(halfY-RPC_EdgeWidth, halfZ-RPC_EdgeWidth, slice_thickness/2.);
SubtractionSolid solidRPCEdge(solidRPCEdge1, solidRPCEdge2, Position(0,0,0));
Volume logicRPCEdge(slice_name+"_edge", solidRPCEdge, edge_material);
logicRPCEdge.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
sliceVol.placeVolume(logicRPCEdge);
RotationZYX rotGaz(0, pi/2., 0);
Tube solidRPCGazInlet(RPCGazInletInnerRadius,RPCGazInletOuterRadius,RPC_EdgeWidth/*RPCGazInletLength*//2);
Volume logicRPCGazInlet(slice_name+"_GazInlet", solidRPCGazInlet, edge_material);
logicRPCGazInlet.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
logicRPCEdge.placeVolume(logicRPCGazInlet, Transform3D(rotGaz, Position(RPC_GazInlet_In_Y,RPC_GazInlet_In_Z, 0)));
logicRPCEdge.placeVolume(logicRPCGazInlet, Transform3D(rotGaz, Position(RPC_GazInlet_Out_Y,RPC_GazInlet_Out_Z, 0)));
Tube solidRPCGazInsideInlet(0,RPCGazInletInnerRadius,RPC_EdgeWidth/*RPCGazInletLength*//2);
Volume logicRPCGazInsideInlet(slice_name+"_GazInsideInlet", solidRPCGazInsideInlet, slice_material);
logicRPCGazInsideInlet.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),"SeeThrough");
logicRPCEdge.placeVolume(logicRPCGazInsideInlet, Transform3D(rotGaz, Position(RPC_GazInlet_In_Y,RPC_GazInlet_In_Z, 0)));
logicRPCEdge.placeVolume(logicRPCGazInsideInlet, Transform3D(rotGaz,Position(RPC_GazInlet_Out_Y,RPC_GazInlet_Out_Z, 0)));
}
if(Hcal_spacer_thickness>0){
Tube solidRPCSpacer(0,Hcal_spacer_thickness/2,slice_thickness/2);
Material space_material = theDetector.material(x_slice.attr<string>(_Unicode(spacer_material)));
Volume logicRPCSpacer(slice_name+"_spacer", solidRPCSpacer, space_material);
logicRPCSpacer.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
RotationZYX rotSpacer(0, 0, 0);
double gap_hZ = halfZ-RPC_EdgeWidth;
double gap_hY = halfY-RPC_EdgeWidth;
int y_number_of_separations = (int)(2*gap_hY/Hcal_spacer_separation);
int z_number_of_separations = (int)(2*gap_hZ/Hcal_spacer_separation);
double y_lateral_space = (2*gap_hY - y_number_of_separations*Hcal_spacer_separation)/2;
double z_lateral_space = (2*gap_hZ - z_number_of_separations*Hcal_spacer_separation)/2;
if(y_lateral_space < Hcal_spacer_thickness/2.){
y_number_of_separations = (int)((2*gap_hY-Hcal_spacer_thickness)/Hcal_spacer_separation);
y_lateral_space = (2*gap_hY - y_number_of_separations*Hcal_spacer_separation)/2;
}
if(z_lateral_space < Hcal_spacer_thickness/2.){
z_number_of_separations = (int)((2*gap_hZ-Hcal_spacer_thickness)/Hcal_spacer_separation);
z_lateral_space = (2*gap_hZ - z_number_of_separations*Hcal_spacer_separation)/2;
}
for(int y_counter = 0; y_counter <=y_number_of_separations; y_counter++){
double SpacerY = gap_hY - y_lateral_space - y_counter*Hcal_spacer_separation;
for(int z_counter = 0; z_counter <=z_number_of_separations; z_counter++){
double SpacerZ = gap_hZ - z_lateral_space - z_counter*Hcal_spacer_separation;
PlacedVolume space_pv = sliceVol.placeVolume(logicRPCSpacer, Transform3D(rotSpacer, Position(SpacerY,SpacerZ,0)));
}
}
}
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
if(layer_id==1) cout<<"Hcal_Barrel: inner_thickness= "<<thickness_sum<<endl;
//Store readout gasgap thickness
caloLayer.sensitive_thickness = slice_thickness;
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),"SeeThrough");
}
else{
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
}
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// slice PlacedVolume
PlacedVolume slice_phv = chamberLogical.placeVolume(sliceVol,Position(0,0,slice_pos_z));
if ( x_slice.isSensitive() ) {
int slice_id = (layer_id > Hcal_nlayers)? 1:-1;
slice_phv.addPhysVolID("layer",layer_id).addPhysVolID("slice",slice_id);
}
DetElement sliceDetE(layer_name,_toString(slice_number,"slice%d"),x_det.id());
sliceDetE.setPlacement(slice_phv);
// Increment x position for next slice.
slice_pos_z += slice_thickness/2.;
// Increment slice number.
++slice_number;
}
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
if(layer_id==1) cout << "Hcal_Barrel: outer_thickness= " << thickness_sum << endl;
double chamber_y_offset = -(-Hcal_total_dim_y/2. + (layer_id-1)*layerThickness + layerThickness/2.);
caloLayer.distance = Hcal_inner_radius + Hcal_total_dim_y/2.0 + chamber_y_offset ;
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
double stave_phi_offset, module_z_offset;
//stave_phi_offset = pi/Hcal_inner_symmetry;
stave_phi_offset = pi*0.5;
for(int stave_id = 1; stave_id <= Hcal_inner_symmetry; stave_id++){
double phirot = stave_phi_offset+(stave_id-1)*pi/Hcal_inner_symmetry*2;
RotationZYX rot(pi/2, pi/2, 0); //phirot);
RotationZ rotZ(phirot);
RotationZYX rotAll = rotZ*rot;
RotationZYX rotInverse(phirot, 0, 0);
for(int module_id = 1; module_id <= Hcal_barrel_number_modules; module_id++){
module_z_offset = - Hcal_half_length + Hcal_normal_dim_z/2. + (module_id-1)*(Hcal_normal_dim_z+Hcal_modules_gap);
Position localPos(localXPos,localYPos,module_z_offset);
Position newPos = rotInverse*localPos;
Transform3D tran3D(rotAll, newPos);
PlacedVolume pv = logicCalo.placeVolume(chamberLogical, tran3D);
pv.addPhysVolID("stave",stave_id).addPhysVolID("module",module_id);//.addPhysVolID("layer",layer_id);
DetElement layer(calo, name+_toString(stave_id,"_stave%d")+_toString(module_id,"_module%d")+_toString(layer_id,"_layer%d"), det_id);
layer.setPlacement(pv);
}
}
}
det.addExtension< LayeredCalorimeterData >( caloData ) ;
return det;
}
DECLARE_DETELEMENT(SHcalRpc02_Barrel, create_detector)
//====================================================================
// DD4hep Geometry driver for HcalBarrel
//--------------------------------------------------------------------
// S.Lu, DESY
// F. Gaede, DESY : v04 : prepare for multi segmentation
// 18.04.2017 - copied from SHcalSc04_Barrel_v01.cpp
// - add optional parameter <subsegmentation key="" value=""/>
// defines the segmentation to be used in reconstruction
//====================================================================
#include "DD4hep/Printout.h"
#include "DD4hep/DetFactoryHelper.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
#include "DDSegmentation/BitField64.h"
#include "DDSegmentation/TiledLayerGridXY.h"
#include "DDSegmentation/Segmentation.h"
#include "DDSegmentation/MultiSegmentation.h"
#include "LcgeoExceptions.h"
#include <iostream>
#include <vector>
using namespace std;
using dd4hep::_toString;
using dd4hep::Box;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::Detector;
using dd4hep::DetElement;
using dd4hep::IntersectionSolid;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::Rotation3D;
using dd4hep::RotationZ;
using dd4hep::RotationZYX;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Trapezoid;
using dd4hep::Tube;
using dd4hep::Volume;
using dd4hep::rec::LayeredCalorimeterData;
// After reading in all the necessary parameters.
// To check the radius range and the space for placing the total layers
static bool validateEnvelope(double rInner, double rOuter, double radiatorThickness, double layerThickness, int layerNumber, int nsymmetry)
{
bool Error = false;
bool Warning = false;
double spaceAllowed = rOuter * cos(M_PI / nsymmetry) - rInner;
double spaceNeeded = (radiatorThickness + layerThickness) * layerNumber;
double spaceToleranted = (radiatorThickness + layerThickness) * (layerNumber + 1);
double rOuterRecommaned = (rInner + spaceNeeded) / cos(M_PI / 16.);
int layerNumberRecommaned = floor((spaceAllowed) / (radiatorThickness + layerThickness));
if (spaceNeeded > spaceAllowed)
{
printout(dd4hep::ERROR, "SHcalSc04_Barrel_v04", " Layer number is more than it can be built! ");
Error = true;
}
else if (spaceToleranted < spaceAllowed)
{
printout(dd4hep::WARNING, "SHcalSc04_Barrel_v04", " Layer number is less than it is able to build!");
Warning = true;
}
else
{
printout(dd4hep::DEBUG, "SHcalSc04_Barrel_v04", " has been validated and start to build it.");
Error = false;
Warning = false;
}
if (Error)
{
cout << "\n ============> First Help Documentation <=============== \n"
<< " When you see this message, that means you are crashing the module. \n"
<< " Please take a cup of cafe, and think about what you want to do! \n"
<< " Here are few FirstAid# for you. Please read them carefully. \n"
<< " \n"
<< " ### FirstAid 1: ###\n"
<< " If you want to build HCAL within the rInner and rOuter range, \n"
<< " please reduce the layer number to " << layerNumberRecommaned << " \n"
<< " with the current layer thickness structure. \n"
<< " \n"
<< " You may redisgn the layer structure and thickness, too. \n"
<< " \n"
<< " ### FirstAid 2: ###\n"
<< " If you want to build HCAL with this layer number and the layer thickness, \n"
<< " you have to update rOuter to " << rOuterRecommaned * 10. << "*mm \n"
<< " and to inform other subdetector, you need this space for building your design. \n"
<< " \n"
<< " ### FirstAid 3: ###\n"
<< " Do you think that you are looking for another type of HCAL driver? \n"
<< " \n"
<< endl;
throw lcgeo::GeometryException("SHcalSc04_Barrel: Error: Layer number is more than it can be built!");
}
else if (Warning)
{
cout << "\n ============> First Help Documentation <=============== \n"
<< " When you see this warning message, that means you are changing the module. \n"
<< " Please take a cup of cafe, and think about what you want to do! \n"
<< " Here are few FirstAid# for you. Please read them carefully. \n"
<< " \n"
<< " ### FirstAid 1: ###\n"
<< " If you want to build HCAL within the rInner and rOuter range, \n"
<< " You could build the layer number up to " << layerNumberRecommaned << " \n"
<< " with the current layer thickness structure. \n"
<< " \n"
<< " You may redisgn the layer structure and thickness, too. \n"
<< " \n"
<< " ### FirstAid 2: ###\n"
<< " If you want to build HCAL with this layer number and the layer thickness, \n"
<< " you could reduce rOuter to " << rOuterRecommaned * 10. << "*mm \n"
<< " and to reduce the back plate thickness, which you may not need for placing layer. \n"
<< " \n"
<< " ### FirstAid 3: ###\n"
<< " Do you think that you are looking for another type of HCAL driver? \n"
<< " \n"
<< endl;
return Warning;
}
else
{
return true;
}
}
static Ref_t create_detector(Detector &theDetector, xml_h element, SensitiveDetector sens)
{
double boundarySafety = 0.0001;
xml_det_t x_det = element;
string det_name = x_det.nameStr();
int det_id = x_det.id();
DetElement sdet(det_name, det_id);
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope(theDetector, element, sdet);
dd4hep::xml::setDetectorTypeFlag(element, sdet);
if (theDetector.buildType() == BUILD_ENVELOPE)
return sdet;
//-----------------------------------------------------------------------------------
xml_comp_t x_staves = x_det.staves(); // absorber
Material stavesMaterial = theDetector.material(x_staves.materialStr());
Material air = theDetector.air();
PlacedVolume pv;
sens.setType("calorimeter");
//====================================================================
//
// Read all the constant from ILD_o1_v05.xml
// Use them to build HcalBarrel
//
//====================================================================
double Hcal_inner_radius = theDetector.constant<double>("Hcal_inner_radius");
double Hcal_outer_radius = theDetector.constant<double>("Hcal_outer_radius");
double Hcal_half_length = theDetector.constant<double>("Hcal_half_length");
int Hcal_inner_symmetry = theDetector.constant<int>("Hcal_inner_symmetry");
int Hcal_outer_symmetry = 0; // Fixed shape for Tube, and not allow to modify from compact xml
double Hcal_cell_size = theDetector.constant<double>("Hcal_cell_size");
double Hcal_cell_size_abnormal = theDetector.constant<double>("Hcal_cell_size_abnormal");
double Hcal_scintillator_air_gap = theDetector.constant<double>("Hcal_scintillator_air_gap");
double Hcal_scintillator_ESR_thickness = theDetector.constant<double>("Hcal_scintillator_ESR_thickness");
double Hcal_scintillator_thickness = theDetector.constant<double>("Hcal_scintillator_thickness");
double Hcal_radiator_thickness = theDetector.constant<double>("Hcal_radiator_thickness");
double Hcal_chamber_thickness = theDetector.constant<double>("Hcal_chamber_thickness");
double Hcal_back_plate_thickness = theDetector.constant<double>("Hcal_back_plate_thickness");
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Hcal_stave_gaps = theDetector.constant<double>("Hcal_stave_gaps");
// double Hcal_modules_gap = theDetector.constant<double>("Hcal_modules_gap");
double Hcal_middle_stave_gaps = theDetector.constant<double>("Hcal_middle_stave_gaps");
double Hcal_layer_air_gap = theDetector.constant<double>("Hcal_layer_air_gap");
// double Hcal_cells_size = theDetector.constant<double>("Hcal_cells_size");
int Hcal_nlayers = theDetector.constant<int>("Hcal_nlayers");
//=================================================================================
// if Hcal_outer_radius stands for the radius of circumcircle, comment next line
Hcal_outer_radius /= cos(M_PI / Hcal_inner_symmetry);
//=================================================================================
printout(dd4hep::INFO, "SHcalSc04_Barrel_v04", "Hcal_inner_radius : %e - Hcal_outer_radius %e ", Hcal_inner_radius, Hcal_outer_radius);
validateEnvelope(Hcal_inner_radius, Hcal_outer_radius, Hcal_radiator_thickness, Hcal_chamber_thickness, Hcal_nlayers, Hcal_inner_symmetry);
// fg: this is a bit tricky: we first have to check whether a multi segmentation is used and then, if so, we
// will check the <subsegmentation key="" value=""/> element, for which subsegmentation to use for filling the
// DDRec:LayeredCalorimeterData information.
// Additionally, we need to figure out if there is a TiledLayerGridXY instance defined -
// and in case, there is more than one defined, we need to pick the correct one specified via the
// <subsegmentation key="" value=""/> element.
// This involves a lot of casting: review the API in DD4hep !!
// check if we have a multi segmentation :
//========== fill data for reconstruction ============================
LayeredCalorimeterData *caloData = new LayeredCalorimeterData;
caloData->layoutType = LayeredCalorimeterData::BarrelLayout;
caloData->inner_symmetry = Hcal_inner_symmetry;
caloData->outer_symmetry = Hcal_outer_symmetry;
caloData->phi0 = 0; // fg: also hardcoded below
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = Hcal_inner_radius;
caloData->extent[1] = Hcal_outer_radius;
caloData->extent[2] = 0.; // Barrel zmin is "0" by default.
caloData->extent[3] = Hcal_half_length;
//====================================================================
//
// general calculated parameters
//
//====================================================================
double Hcal_total_dim_y = Hcal_nlayers * (Hcal_radiator_thickness + Hcal_chamber_thickness) + Hcal_back_plate_thickness;
// double Hcal_y_dim1_for_x = Hcal_outer_radius * cos(M_PI / Hcal_inner_symmetry) - Hcal_inner_radius;
double Hcal_bottom_dim_x = 2. * Hcal_inner_radius * tan(M_PI / Hcal_inner_symmetry) - Hcal_lateral_plate_thickness * 2 - Hcal_stave_gaps;
// double Hcal_normal_dim_z = (2 * Hcal_half_length - Hcal_modules_gap) / 2.;
double Hcal_normal_dim_z = Hcal_half_length;
// only the middle has the steel plate.
// double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z - Hcal_lateral_plate_thickness;
double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z;
// double Hcal_cell_dim_x = Hcal_cells_size;
// double Hcal_cell_dim_z = Hcal_regular_chamber_dim_z / floor (Hcal_regular_chamber_dim_z/Hcal_cell_dim_x);
// ========= Create Hcal Barrel stave ====================================
// It will be the volume for palcing the Hcal Barrel Chamber(i.e. Layers).
// Itself will be placed into the world volume.
// ==========================================================================
// stave modules shaper parameters
double BHX = (Hcal_bottom_dim_x + Hcal_lateral_plate_thickness * 2 + Hcal_stave_gaps) / 2.;
double THX = (Hcal_total_dim_y + Hcal_inner_radius) * tan(M_PI / Hcal_inner_symmetry);
double YXH = Hcal_total_dim_y / 2.;
// double DHZ = (Hcal_normal_dim_z - Hcal_lateral_plate_thickness) / 2.;
double DHZ = Hcal_normal_dim_z;
Trapezoid stave_shaper(THX, BHX, DHZ, DHZ, YXH);
Tube solidCaloTube(0, Hcal_outer_radius, DHZ + boundarySafety);
RotationZYX mrot(0, 0, M_PI / 2.);
Rotation3D mrot3D(mrot);
Position mxyzVec(0, 0, (Hcal_inner_radius + Hcal_total_dim_y / 2.));
Transform3D mtran3D(mrot3D, mxyzVec);
IntersectionSolid barrelModuleSolid(stave_shaper, solidCaloTube, mtran3D);
Volume EnvLogHcalModuleBarrel(det_name + "_module", barrelModuleSolid, stavesMaterial);
EnvLogHcalModuleBarrel.setAttributes(theDetector, x_staves.regionStr(), x_staves.limitsStr(), x_staves.visStr());
// stave modules lateral plate shaper parameters
// double BHX_LP = BHX;
// double THX_LP = THX;
// double YXH_LP = YXH;
// // build lateral palte here to simulate lateral plate in the middle of barrel.
// double DHZ_LP = Hcal_lateral_plate_thickness / 2.0;
// Trapezoid stave_shaper_LP(THX_LP, BHX_LP, DHZ_LP, DHZ_LP, YXH_LP);
// Tube solidCaloTube_LP(0, Hcal_outer_radius, DHZ_LP + boundarySafety);
// IntersectionSolid Module_lateral_plate(stave_shaper_LP, solidCaloTube_LP, mtran3D);
// Volume EnvLogHcalModuleBarrel_LP(det_name + "_Module_lateral_plate", Module_lateral_plate, stavesMaterial);
// EnvLogHcalModuleBarrel_LP.setAttributes(theDetector, x_det.regionStr(), x_det.limitsStr(), x_det.visStr());
#ifdef SHCALSC04_DEBUG
std::cout << " ==> Hcal_outer_radius: " << Hcal_outer_radius << std::endl;
#endif
//====================================================================
//
// Chambers in the HCAL BARREL
//
//====================================================================
// Build Layer Chamber fill with air, which include the tolarance space at the two side
// place the slice into the Layer Chamber
// Place the Layer Chamber into the Stave module
// place the Stave module into the asembly Volume
// place the module middle lateral plate into asembly Volume
double x_halflength; // dimension of an Hcal barrel layer on the x-axis
double y_halfheight; // dimension of an Hcal barrel layer on the y-axis
double z_halfwidth; // dimension of an Hcal barrel layer on the z-axis
x_halflength = 0.; // Each Layer the x_halflength has new value.
y_halfheight = Hcal_chamber_thickness / 2.;
z_halfwidth = Hcal_regular_chamber_dim_z;
double xOffset = 0.; // the x_halflength of a barrel layer is calculated as a
// barrel x-dimension plus (bottom barrel) or minus
//(top barrel) an x-offset, which depends on the angle M_PI/Hcal_inner_symmetry
double xShift = 0.; // Geant4 draws everything in the barrel related to the
// center of the bottom barrel, so we need to shift the layers to
// the left (or to the right) with the quantity xShift
// read sensitive cell parameters and create it
// xml_comp_t x_scintillator = x_det.solid();
// Material sensitiveMaterial = theDetector.material(x_scintillator.materialStr());
// xml_comp_t x_ESR = x_det.shape();
// Material ladderMaterial = theDetector.material(x_ESR.materialStr());
Volume cell_vol;
Volume scintillator_vol;
Volume cell_vol_abnormal;
Volume scintillator_vol_abnormal;
xml_comp_t x_layer_tmp(x_det.child(_U(layer)));
for (xml_coll_t k(x_layer_tmp, _U(slice)); k; ++k)
{
xml_comp_t x_slice = k;
if (x_slice.isSensitive())
{
// child elements: ladder and sensitive
xml_comp_t x_sensitive(x_slice.child(_U(sensitive)));
xml_comp_t x_ladder(x_slice.child(_U(ladder)));
Material sensitiveMaterial = theDetector.material(x_sensitive.materialStr());
Material ladderMaterial = theDetector.material(x_ladder.materialStr());
// Store scintillator thickness
double cell_thickness = Hcal_scintillator_thickness + 2 * Hcal_scintillator_ESR_thickness;
double cell_size = 2 * Hcal_scintillator_ESR_thickness + Hcal_cell_size;
// place sensitive cell into ESR cell
string cell_name = "cell";
string scintillator_name = cell_name + "_scintillator";
// create sensitive cell with ESR
Box cell_box(cell_size / 2., cell_size / 2., cell_thickness / 2.);
// string cell_name=
// Volume cell_vol_tmp(cell_name, cell_box, ladderMaterial);
cell_vol = Volume(cell_name, cell_box, ladderMaterial);
cell_vol.setAttributes(theDetector, x_ladder.regionStr(), x_ladder.limitsStr(), x_ladder.visStr());
Box scintillator_box(Hcal_cell_size / 2., Hcal_cell_size / 2., Hcal_scintillator_thickness / 2.);
// Volume scintillator_vol_tmp(scintillator_name, scintillator_box, sensitiveMaterial);
scintillator_vol = Volume(scintillator_name, scintillator_box, sensitiveMaterial);
scintillator_vol.setAttributes(theDetector, x_sensitive.regionStr(), x_sensitive.limitsStr(), x_sensitive.visStr());
scintillator_vol.setSensitiveDetector(sens);
cell_vol.placeVolume(scintillator_vol, Position(0., 0., 0.));
// cout << x_ladder.visStr() << " " << x_sensitive.visStr() << endl;
///////////////////////////////
// abnormal cell //
///////////////////////////////
double cell_size_abnormal = 2 * Hcal_scintillator_ESR_thickness + Hcal_cell_size_abnormal;
// place sensitive cell into ESR cell
string cell_name_abnormal = "cell_abnormal";
string scintillator_name_abnormal = cell_name_abnormal + "_scintillator_abnormal";
// create sensitive cell with ESR
Box cell_box_abnormal(cell_size_abnormal / 2., cell_size / 2., cell_thickness / 2.);
// string cell_name=
// Volume cell_vol_tmp_abnormal(cell_name_abnormal, cell_box_abnormal, ladderMaterial);
cell_vol_abnormal = Volume(cell_name_abnormal, cell_box_abnormal, ladderMaterial);
cell_vol_abnormal.setAttributes(theDetector, x_ladder.regionStr(), x_ladder.limitsStr(), x_ladder.visStr());
Box scintillator_box_abnormal(Hcal_cell_size_abnormal / 2., Hcal_cell_size / 2., Hcal_scintillator_thickness / 2.);
// Volume scintillator_vol_tmp_abnormal(scintillator_name_abnormal, scintillator_box_abnormal, sensitiveMaterial);
scintillator_vol_abnormal = Volume(scintillator_name_abnormal, scintillator_box_abnormal, sensitiveMaterial);
scintillator_vol_abnormal.setAttributes(theDetector, x_sensitive.regionStr(), x_sensitive.limitsStr(), x_sensitive.visStr());
scintillator_vol_abnormal.setSensitiveDetector(sens);
cell_vol_abnormal.placeVolume(scintillator_vol_abnormal, Position(0., 0., 0.));
}
}
// sensitive cell creating done
//-------------------- start loop over HCAL layers ----------------------
// int n_x_layer_1 = 0;
for (int layer_id = 1; layer_id <= (Hcal_nlayers); layer_id++)
{
double TanPiDiv8 = tan(M_PI / Hcal_inner_symmetry);
double x_total = 0.;
// double x_halfLength;
x_halflength = 0.;
// int layer_id = 0;
// if ((layer_id < Hcal_nlayers) || (layer_id > Hcal_nlayers && layer_id < (2 * Hcal_nlayers)))
// layer_id = layer_id % Hcal_nlayers;
// else if ((layer_id == Hcal_nlayers) || (layer_id == 2 * Hcal_nlayers))
// layer_id = Hcal_nlayers;
//---- bottom barrel------------------------------------------------------------
// if (layer_id * (Hcal_radiator_thickness + Hcal_chamber_thickness) < (Hcal_outer_radius * cos(M_PI / Hcal_inner_symmetry) - Hcal_inner_radius))
// {
xOffset = (layer_id * Hcal_radiator_thickness + (layer_id - 1) * Hcal_chamber_thickness) * TanPiDiv8;
x_total = Hcal_bottom_dim_x - Hcal_middle_stave_gaps + xOffset * 2;
x_halflength = x_total - 2 * Hcal_layer_air_gap;
// x_halfLength = x_halflength / 2.;
// }
// else
// { //----- top barrel -------------------------------------------------
// double y_layerID = layer_id * (Hcal_radiator_thickness + Hcal_chamber_thickness) + Hcal_inner_radius;
// double ro_layer = Hcal_outer_radius - Hcal_radiator_thickness;
// x_total = sqrt(ro_layer * ro_layer - y_layerID * y_layerID);
// x_halflength = x_total - Hcal_middle_stave_gaps;
// x_halfLength = x_halflength / 2.;
// xOffset = (layer_id * Hcal_radiator_thickness + (layer_id - 1) * Hcal_chamber_thickness - Hcal_y_dim1_for_x) / TanPiDiv8 + Hcal_chamber_thickness / TanPiDiv8;
// }
x_halflength = x_halflength / 2.;
LayeredCalorimeterData::Layer caloLayer;
caloLayer.cellSize0 = Hcal_cell_size;
caloLayer.cellSize1 = Hcal_cell_size;
//--------------------------------------------------------------------------------
// build chamber box, with the calculated dimensions
//-------------------------------------------------------------------------------
printout(dd4hep::DEBUG, "SHcalSc04_Barrel_v04", " \n Start to build layer chamber - layer_id: %d", layer_id);
printout(dd4hep::DEBUG, "SHcalSc04_Barrel_v04", " chamber x:y:z: %e:%e:%e", x_halflength * 2., z_halfwidth * 2., y_halfheight * 2.);
// check if x_halflength (scintillator length) is divisible with x_integerTileSize
Box ChamberSolid((x_halflength + Hcal_layer_air_gap), // x + air gaps at two side, do not need to build air gaps individualy.
z_halfwidth, // z attention!
y_halfheight); // y attention!
string ChamberLogical_name = det_name + _toString(layer_id, "_layer%d");
Volume ChamberLogical(ChamberLogical_name, ChamberSolid, air);
ChamberLogical.setAttributes(theDetector, x_layer_tmp.regionStr(), x_layer_tmp.limitsStr(), x_layer_tmp.visStr());
double layer_thickness = y_halfheight * 2.;
double nRadiationLengths = 0.;
double nInteractionLengths = 0.;
double thickness_sum = 0;
nRadiationLengths = Hcal_radiator_thickness / (stavesMaterial.radLength());
nInteractionLengths = Hcal_radiator_thickness / (stavesMaterial.intLength());
thickness_sum = Hcal_radiator_thickness;
//====================================================================
// Create Hcal Barrel Chamber without radiator
// Place into the Hcal Barrel stave, after each radiator
//====================================================================
xml_coll_t c(x_det, _U(layer));
xml_comp_t x_layer = c;
string layer_name = det_name + _toString(layer_id, "_layer%d");
// Create the slices (sublayers) within the Hcal Barrel Chamber.
double slice_pos_z = layer_thickness / 2.;
int slice_number = 0;
for (xml_coll_t k(x_layer, _U(slice)); k; ++k)
{
xml_comp_t x_slice = k;
string slice_name = layer_name + _toString(slice_number, "_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
DetElement slice(layer_name, _toString(slice_number, "slice%d"), x_det.id());
slice_pos_z -= slice_thickness / 2.;
// Slice volume & box
Volume slice_vol(slice_name, Box(x_halflength, z_halfwidth, slice_thickness / 2.), slice_material);
slice_vol.setAttributes(theDetector, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr());
nRadiationLengths += slice_thickness / (2. * slice_material.radLength());
nInteractionLengths += slice_thickness / (2. * slice_material.intLength());
thickness_sum += slice_thickness / 2;
if (x_slice.isSensitive())
{
// Store "inner" quantities
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
// Store scintillator thickness
caloLayer.sensitive_thickness = Hcal_scintillator_thickness;
double cell_size = 2 * Hcal_scintillator_ESR_thickness + Hcal_cell_size;
double cell_size_abnormal = 2 * Hcal_scintillator_ESR_thickness + Hcal_cell_size_abnormal;
double cell_x_offset = 0, cell_z_offset = 0, cell_y_offset = 0;
// place cell into slice one by one
double total_cell_size = cell_size + Hcal_scintillator_air_gap; // include air gap
double total_cell_size_abnormal = cell_size_abnormal + Hcal_scintillator_air_gap; // include air gap
int n_x = (2 * x_halflength) / total_cell_size;
int n_z = (2 * z_halfwidth) / total_cell_size;
int nx_abnormal = (2 * x_halflength - n_x * total_cell_size) / (total_cell_size_abnormal - total_cell_size);
n_x -= nx_abnormal;
// if(layer_id==1){n_x_layer_1=n_x;}
// else{
// n_x=(n_x-n_x_layer_1)/2;
// n_x=n_x*2+n_x_layer_1;
// }
for (int index_cell_z = 0; index_cell_z < n_z; index_cell_z++)
{
cell_x_offset = (n_x * total_cell_size + nx_abnormal * total_cell_size_abnormal) / 2.;
cell_z_offset = (n_z / 2. - index_cell_z - 0.5) * total_cell_size;
for (int index_cell_x = 0; index_cell_x < n_x; index_cell_x++)
{
cell_x_offset -= total_cell_size / 2.;
int cell_number = index_cell_x + 100 * index_cell_z;
string cell_name = slice_name + _toString(cell_number, "_cell%d");
string scintillator_name = cell_name + "_scintillator";
// cell_y_offset = slice_thickness / 2.;
PlacedVolume cell_phv = slice_vol.placeVolume(cell_vol, Position(cell_x_offset, cell_z_offset, cell_y_offset));
cell_phv.addPhysVolID("tile", cell_number);
DetElement cell(cell_name, _toString(cell_number, "cell%d"), cell_number);
cell.setPlacement(cell_phv);
cell_x_offset -= total_cell_size / 2.;
}
for (int index_cell_x = 0; index_cell_x < nx_abnormal; index_cell_x++)
{
cell_x_offset -= total_cell_size_abnormal / 2.;
int cell_number = index_cell_x + n_x + 100 * index_cell_z;
string cell_name = slice_name + _toString(cell_number, "_cell%d");
string scintillator_name = cell_name + "_scintillator";
// cell_y_offset = slice_thickness / 2.;
PlacedVolume cell_phv = slice_vol.placeVolume(cell_vol_abnormal, Position(cell_x_offset, cell_z_offset, cell_y_offset));
cell_phv.addPhysVolID("tile", cell_number);
DetElement cell(cell_name, _toString(cell_number, "cell%d"), cell_number);
cell.setPlacement(cell_phv);
cell_x_offset -= total_cell_size_abnormal / 2.;
}
}
//printf("layerID: %2d, x_length: %3.3lf, x_cell: %3.3lf, x_cell_abnormal: %3.3lf, x_dead: %3.3lf, z_length: %3.3lf,z_cell: %3.3lf, z_dead: %3.3lf,\n", layer_id, 2 * x_halflength, n_x * total_cell_size, nx_abnormal * total_cell_size_abnormal, 2 * x_halflength - n_x * total_cell_size - nx_abnormal * total_cell_size_abnormal, 2 * z_halfwidth, n_z * total_cell_size, 2 * z_halfwidth - n_z * total_cell_size);
// 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;
// Set region, limitset, and vis.
// slice_vol.setAttributes(theDetector, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr());
// slice PlacedVolume
PlacedVolume slice_phv = ChamberLogical.placeVolume(slice_vol, Position(0., 0., slice_pos_z));
slice_phv.addPhysVolID("layer", layer_id);
slice.setPlacement(slice_phv);
// Increment z position for next slice.
slice_pos_z -= slice_thickness / 2.;
// Increment slice number.
++slice_number;
}
// Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
//--------------------------- Chamber Placements -----------------------------------------
double chamber_x_offset, chamber_y_offset, chamber_z_offset;
chamber_x_offset = xShift;
chamber_z_offset = 0;
chamber_y_offset = -(-Hcal_total_dim_y / 2. + (layer_id - 1) * (Hcal_chamber_thickness + Hcal_radiator_thickness) + Hcal_radiator_thickness + Hcal_chamber_thickness / 2.);
pv = EnvLogHcalModuleBarrel.placeVolume(ChamberLogical,
Position(chamber_x_offset, chamber_z_offset, chamber_y_offset));
//-----------------------------------------------------------------------------------------
if (layer_id <= Hcal_nlayers)
{ // add the first set of layers to the reconstruction data
caloLayer.distance = Hcal_inner_radius + Hcal_total_dim_y / 2.0 - chamber_y_offset - caloLayer.inner_thickness;
// Will be added later at "DDMarlinPandora/DDGeometryCreator.cc:226" to get center of sensitive element
caloLayer.absorberThickness = Hcal_radiator_thickness;
caloData->layers.push_back(caloLayer);
}
//-----------------------------------------------------------------------------------------
} // end loop over HCAL nlayers;
//====================================================================
// Place HCAL Barrel stave module into the envelope
//====================================================================
double stave_phi_offset, module_z_offset = 0;
double Y = Hcal_inner_radius + Hcal_total_dim_y / 2.;
stave_phi_offset = M_PI / Hcal_inner_symmetry - M_PI / 2.;
//-------- start loop over HCAL BARREL staves ----------------------------
for (int stave_id = 1; stave_id <= Hcal_inner_symmetry; stave_id++)
{
double phirot = stave_phi_offset;
RotationZYX srot(0, phirot, M_PI * 0.5);
Rotation3D srot3D(srot);
// for (int module_id = 1; module_id <= 2; module_id++)
// {
Position sxyzVec(-Y * sin(phirot), Y * cos(phirot), module_z_offset);
Transform3D stran3D(srot3D, sxyzVec);
// Place Hcal Barrel volume into the envelope volume
pv = envelope.placeVolume(EnvLogHcalModuleBarrel, stran3D);
pv.addPhysVolID("stave", stave_id);
// pv.addPhysVolID("module", module_id);
pv.addPhysVolID("system", det_id);
// const int staveCounter = (stave_id - 1) * 2 + module_id - 1;
const int staveCounter = stave_id - 1;
DetElement stave(sdet, _toString(staveCounter, "stave%d"), staveCounter);
stave.setPlacement(pv);
// Position xyzVec_LP(-Y * sin(phirot), Y * cos(phirot), lateral_plate_z_offset);
// Transform3D tran3D_LP(srot3D, xyzVec_LP);
// pv = envelope.placeVolume(EnvLogHcalModuleBarrel_LP, tran3D_LP);
// module_z_offset = -module_z_offset;
// lateral_plate_z_offset = -lateral_plate_z_offset;
// }
stave_phi_offset -= M_PI * 2.0 / Hcal_inner_symmetry;
} //-------- end loop over HCAL BARREL staves ----------------------------
sdet.addExtension<LayeredCalorimeterData>(caloData);
return sdet;
}
DECLARE_DETELEMENT(SHcalSc04_Barrel_v04, create_detector)
//====================================================================
// AIDA Detector description implementation
// for LDC AHCAL Endcap
//--------------------------------------------------------------------
//
// Author : S.Lu
// F. Gaede, DESY : v01 : prepare for multi segmentation
// 18.04.2017 - copied from SHcalSc04_Barrel_v01.cpp
// - add optional parameter <subsegmentation key="" value=""/>
// defines the segmentation to be used in reconstruction
//
// Basic idea:
// 1. Create the Hcal Endcap module envelope (16 modules).
// Note: with default material Steel235.
//
// 2. Create the Hcal Endcap Chamber(i.e. Layer) for each module.
// Create the Layer with slices (Polystyrene,Cu,FR4,air).
// Place each slice into the chamber with the right position,
// And registry the IDs for slice
//
// 3. Place the same Layer into the endcap module envelope.
// It will be repeated repeat 48 times.
// And registry the IDs for layer, and endcapID.
//
// 4. Place the endcap module into the world volume,
// with the right position and rotation.
// And registry the IDs for stave,module and endcapID.
//
// 5. Customer material FR4 and Steel235 defined in materials.xml
//
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DetType.h"
#include "XML/Layering.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
#include "DDSegmentation/BitField64.h"
#include "DDSegmentation/Segmentation.h"
#include "DDSegmentation/MultiSegmentation.h"
#include "LcgeoExceptions.h"
using namespace std;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::BitField64;
using dd4hep::Box;
using dd4hep::DetElement;
using dd4hep::DetType;
using dd4hep::Detector;
using dd4hep::Layering;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::RotationX;
using dd4hep::Segmentation;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Translation3D;
using dd4hep::Volume;
using dd4hep::_toString;
using dd4hep::rec::LayeredCalorimeterData;
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
xml_det_t x_det = element;
Layering layering(x_det);
xml_dim_t dim = x_det.dimensions();
string det_name = x_det.nameStr();
Material air = theDetector.air();
Material stavesMaterial = theDetector.material(x_det.materialStr());
int numSides = dim.numsides();
int det_id = x_det.id();
DetElement sdet(det_name,det_id);
PlacedVolume pVol;
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ;
sdet.setTypeFlag( DetType::CALORIMETER | DetType::ENDCAP | DetType::HADRONIC ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
//-----------------------------------------------------------------------------------
sens.setType("calorimeter");
DetElement stave_det("module0stave0",det_id);
// The way to reaad constant from XML/Detector file.
double Hcal_radiator_thickness = theDetector.constant<double>("Hcal_radiator_thickness");
double Hcal_endcap_lateral_structure_thickness = theDetector.constant<double>("Hcal_endcap_lateral_structure_thickness");
double Hcal_endcap_layer_air_gap = theDetector.constant<double>("Hcal_endcap_layer_air_gap");
//double Hcal_cells_size = theDetector.constant<double>("Hcal_cells_size");
double HcalEndcap_inner_radius = theDetector.constant<double>("Hcal_endcap_inner_radius");
double HcalEndcap_outer_radius = theDetector.constant<double>("Hcal_endcap_outer_radius");
double HcalEndcap_min_z = theDetector.constant<double>("Hcal_endcap_zmin");
double HcalEndcap_max_z = theDetector.constant<double>("Hcal_endcap_zmax");
double Hcal_steel_cassette_thickness = theDetector.constant<double>("Hcal_steel_cassette_thickness");
double HcalServices_outer_FR4_thickness = theDetector.constant<double>("Hcal_services_outer_FR4_thickness");
double HcalServices_outer_Cu_thickness = theDetector.constant<double>("Hcal_services_outer_Cu_thickness");
double Hcal_endcap_services_module_width = theDetector.constant<double>("Hcal_endcap_services_module_width");
Material stainless_steel = theDetector.material("stainless_steel");
Material PCB = theDetector.material("PCB");
Material copper = theDetector.material("Cu");
std::cout <<"\n HcalEndcap_inner_radius = "
<<HcalEndcap_inner_radius/dd4hep::mm <<" mm"
<<"\n HcalEndcap_outer_radius = "
<<HcalEndcap_outer_radius/dd4hep::mm <<" mm"
<<"\n HcalEndcap_min_z = "
<<HcalEndcap_min_z/dd4hep::mm <<" mm"
<<"\n HcalEndcap_max_z = "
<<HcalEndcap_max_z/dd4hep::mm <<" mm"
<<std::endl;
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
BitField64 encoder = seg.decoder();
encoder.setValue(0) ;
// we first have to check whether a multi segmentation is used and then, if so, we
// will check the <subsegmentation key="" value=""/> element, for which subsegmentation to use for filling the
// DDRec:LayeredCalorimeterData information.
// check if we have a multi segmentation :
dd4hep::DDSegmentation::MultiSegmentation* multiSeg =
dynamic_cast< dd4hep::DDSegmentation::MultiSegmentation*>( seg.segmentation() ) ;
int sensitive_slice_number = -1 ;
if( multiSeg ){
try{
// check if we have an entry for the subsegmentation to be used
xml_comp_t segxml = x_det.child( _Unicode( subsegmentation ) ) ;
std::string keyStr = segxml.attr<std::string>( _Unicode(key) ) ;
int keyVal = segxml.attr<int>( _Unicode(value) ) ;
encoder[ keyStr ] = keyVal ;
// if we have a multisegmentation that uses the slice as key, we need to know for the
// computation of the layer parameters in LayeredCalorimeterData::Layer below
if( keyStr == "slice" ){
sensitive_slice_number = keyVal ;
}
} catch(const std::runtime_error &) {
throw lcgeo::GeometryException( "SHcalSc04_Endcaps_v01: Error: MultiSegmentation specified but no "
" <subsegmentation key="" value=""/> element defined for detector ! " ) ;
}
}
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
caloData->inner_symmetry = 4 ; // hard code cernter box hole
caloData->outer_symmetry = 0 ; // outer tube, or 8 for Octagun
caloData->phi0 = 0 ;
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = HcalEndcap_inner_radius ;
caloData->extent[1] = HcalEndcap_outer_radius ;
caloData->extent[2] = HcalEndcap_min_z ;
caloData->extent[3] = HcalEndcap_max_z ;
int endcapID = 0;
for(xml_coll_t c(x_det.child(_U(dimensions)),_U(dimensions)); c; ++c)
{
xml_comp_t l(c);
double dim_x = l.attr<double>(_Unicode(dim_x));
double dim_y = l.attr<double>(_Unicode(dim_y));
double dim_z = l.attr<double>(_Unicode(dim_z));
double pos_y = l.attr<double>(_Unicode(y_offset));
// Hcal Endcap module shape
double box_half_x= dim_x/2.0; // module width, all are same
double box_half_y= dim_y/2.0; // module length, changing
double box_half_z= dim_z/2.0; // total thickness, all are same
double x_offset = box_half_x*numSides-box_half_x*endcapID*2.0-box_half_x;
double y_offset = pos_y;
Box EndcapModule(box_half_x,box_half_y,box_half_z);
// define the name of each endcap Module
string envelopeVol_name = det_name+_toString(endcapID,"_EndcapModule%d");
Volume envelopeVol(envelopeVol_name,EndcapModule,stavesMaterial);
// Set envelope volume attributes.
envelopeVol.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
double FEE_half_x = box_half_x-Hcal_endcap_services_module_width/2.0;
double FEE_half_y = Hcal_endcap_services_module_width/2.0;
double FEE_half_z = box_half_z;
Box FEEBox(FEE_half_x,FEE_half_y,FEE_half_z);
Volume FEEModule("Hcal_endcap_FEE",FEEBox,air);
double FEELayer_thickness = Hcal_steel_cassette_thickness + HcalServices_outer_FR4_thickness + HcalServices_outer_Cu_thickness;
Box FEELayerBox(FEE_half_x,FEE_half_y,FEELayer_thickness/2.0);
Volume FEELayer("FEELayer",FEELayerBox,air);
Box FEELayerSteelBox(FEE_half_x,FEE_half_y,Hcal_steel_cassette_thickness/2.0);
Volume FEELayerSteel("FEELayerSteel",FEELayerSteelBox,stainless_steel);
pVol = FEELayer.placeVolume(FEELayerSteel,
Position(0,
0,
(-FEELayer_thickness/2.0
+Hcal_steel_cassette_thickness/2.0)));
Box FEELayerFR4Box(FEE_half_x,FEE_half_y,HcalServices_outer_FR4_thickness/2.0);
Volume FEELayerFR4("FEELayerFR4",FEELayerFR4Box,PCB);
pVol = FEELayer.placeVolume(FEELayerFR4,
Position(0,
0,
(-FEELayer_thickness/2.0+Hcal_steel_cassette_thickness
+HcalServices_outer_FR4_thickness/2.0)));
Box FEELayerCuBox(FEE_half_x,FEE_half_y,HcalServices_outer_Cu_thickness/2.0);
Volume FEELayerCu("FEELayerCu",FEELayerCuBox,copper);
pVol = FEELayer.placeVolume(FEELayerCu,
Position(0,
0,
(-FEELayer_thickness/2.0+Hcal_steel_cassette_thickness+HcalServices_outer_FR4_thickness +HcalServices_outer_Cu_thickness/2.0)));
// ========= Create Hcal Chamber (i.e. Layers) ==============================
// It will be the sub volume for placing the slices.
// Itself will be placed into the Hcal Endcap modules envelope.
// ==========================================================================
// create Layer (air) and place the slices (Polystyrene,Cu,FR4,air) into it.
// place the Layer into the Hcal Endcap Modules envelope (stavesMaterial).
// First Hcal Chamber position, start after first radiator
double layer_pos_z = - box_half_z + Hcal_radiator_thickness;
// Create Hcal Endcap Chamber without radiator
// Place into the Hcal Encap module envelope, after each radiator
int layer_num = 1;
for(xml_coll_t m(x_det,_U(layer)); m; ++m) {
xml_comp_t x_layer = m;
int repeat = x_layer.repeat(); // Get number of layers.
double layer_thickness = layering.layer(layer_num)->thickness();
string layer_name = envelopeVol_name+"_layer";
DetElement layer(stave_det,layer_name,det_id);
// Active Layer box & volume
double active_layer_dim_x = box_half_x - Hcal_endcap_lateral_structure_thickness - Hcal_endcap_layer_air_gap;
double active_layer_dim_y = box_half_y;
double active_layer_dim_z = layer_thickness/2.0;
// Build chamber including air gap
// The Layer will be filled with slices,
Volume layer_vol(layer_name, Box((active_layer_dim_x + Hcal_endcap_layer_air_gap),
active_layer_dim_y,active_layer_dim_z), air);
encoder["layer"] = layer_num ;
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions( encoder.getValue() );
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cellSizeVector[0];
caloLayer.cellSize1 = cellSizeVector[1];
// ========= Create sublayer slices =========================================
// Create and place the slices into Layer
// ==========================================================================
// Create the slices (sublayers) within the Hcal Chamber.
double slice_pos_z = -(layer_thickness / 2.0);
int slice_number = 0;
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
nRadiationLengths = Hcal_radiator_thickness/(stavesMaterial.radLength());
nInteractionLengths = Hcal_radiator_thickness/(stavesMaterial.intLength());
thickness_sum = Hcal_radiator_thickness;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
string slice_name = layer_name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
DetElement slice(layer,_toString(slice_number,"slice%d"),det_id);
slice_pos_z += slice_thickness / 2.0;
// Slice volume & box
Volume slice_vol(slice_name,Box(active_layer_dim_x,active_layer_dim_y,slice_thickness/2.0),slice_material);
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
if ( x_slice.isSensitive() ) {
slice_vol.setSensitiveDetector(sens);
// if we have a multisegmentation based on slices, we need to use the correct slice here
if ( sensitive_slice_number<0 || sensitive_slice_number == slice_number ) {
//Store "inner" quantities
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
//Store scintillator thickness
caloLayer.sensitive_thickness = slice_thickness;
//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;
// Set region, limitset, and vis.
slice_vol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
// slice PlacedVolume
PlacedVolume slice_phv = layer_vol.placeVolume(slice_vol,Position(0,0,slice_pos_z));
slice_phv.addPhysVolID("slice",slice_number);
slice.setPlacement(slice_phv);
// Increment Z position for next slice.
slice_pos_z += slice_thickness / 2.0;
// Increment slice number.
++slice_number;
}
// Set region, limitset, and vis.
layer_vol.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
//Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
// ========= Place the Layer (i.e. Chamber) =================================
// Place the Layer into the Hcal Endcap module envelope.
// with the right position and rotation.
// Registry the IDs (layer, stave, module).
// Place the same layer 48 times into Endcap module
// ==========================================================================
for (int j = 0; j < repeat; j++) {
// Layer position in y within the Endcap Modules.
layer_pos_z += layer_thickness / 2.0;
PlacedVolume layer_phv = envelopeVol.placeVolume(layer_vol,
Position(0,0,layer_pos_z));
// registry the ID of Layer, stave and module
layer_phv.addPhysVolID("layer",layer_num);
// then setPlacement for it.
layer.setPlacement(layer_phv);
pVol = FEEModule.placeVolume(FEELayer,
Position(0,0,layer_pos_z));
//-----------------------------------------------------------------------------------------
if ( caloData->layers.size() < (unsigned int)repeat ) {
caloLayer.distance = HcalEndcap_min_z + box_half_z + layer_pos_z
- caloLayer.inner_thickness ; // Will be added later at "DDMarlinPandora/DDGeometryCreator.cc:226" to get center of sensitive element
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
}
//-----------------------------------------------------------------------------------------
// ===== Prepare for next layer (i.e. next Chamber) =========================
// Prepare the chamber placement position and the chamber dimension
// ==========================================================================
// Increment the layer_pos_y
// Place Hcal Chamber after each radiator
layer_pos_z += layer_thickness / 2.0;
layer_pos_z += Hcal_radiator_thickness;
++layer_num;
}
}
// =========== Place Hcal Endcap envelope ===================================
// Finally place the Hcal Endcap envelope into the world volume.
// Registry the stave(up/down), module(left/right) and endcapID.
// ==========================================================================
// Acording to the number of staves and modules,
// Place the same Hcal Endcap module volume into the world volume
// with the right position and rotation.
for(int stave_num=0;stave_num<2;stave_num++){
double EndcapModule_pos_x = 0;
double EndcapModule_pos_y = 0;
double EndcapModule_pos_z = 0;
double rot_EM = 0;
double EndcapModule_center_pos_z = HcalEndcap_min_z + box_half_z;
double FEEModule_pos_x = 0;
double FEEModule_pos_y = 0;
double FEEModule_pos_z = 0;
double FEEModule_center_pos_z = HcalEndcap_min_z + box_half_z;
switch (stave_num)
{
case 0 :
EndcapModule_pos_x = x_offset;
EndcapModule_pos_y = y_offset;
FEEModule_pos_x = x_offset;
FEEModule_pos_y = y_offset + box_half_y + Hcal_endcap_services_module_width/2.0;
break;
case 1 :
EndcapModule_pos_x = -x_offset;
EndcapModule_pos_y = -y_offset;
FEEModule_pos_x = -x_offset;
FEEModule_pos_y = -y_offset - box_half_y - Hcal_endcap_services_module_width/2.0;
break;
}
for(int module_num=0;module_num<2;module_num++) {
int module_id = (module_num==0)? 0:6;
rot_EM = (module_id==0)?M_PI:0;
EndcapModule_pos_z = (module_id==0)? -EndcapModule_center_pos_z:EndcapModule_center_pos_z;
PlacedVolume env_phv = envelope.placeVolume(envelopeVol,
Transform3D(RotationX(rot_EM),
Translation3D(EndcapModule_pos_x,
EndcapModule_pos_y,
EndcapModule_pos_z)));
env_phv.addPhysVolID("tower",endcapID);
env_phv.addPhysVolID("stave",stave_num); // y: up /down
env_phv.addPhysVolID("module",module_id); // z: -/+ 0/6
env_phv.addPhysVolID("system",det_id);
FEEModule_pos_z = (module_id==0)? -FEEModule_center_pos_z:FEEModule_center_pos_z;
if (!(endcapID==0))
env_phv = envelope.placeVolume(FEEModule,
Transform3D(RotationX(rot_EM),
Translation3D(FEEModule_pos_x,
FEEModule_pos_y,
FEEModule_pos_z)));
DetElement sd = (module_num==0&&stave_num==0) ? stave_det : stave_det.clone(_toString(module_id,"module%d")+_toString(stave_num,"stave%d"));
sd.setPlacement(env_phv);
}
}
endcapID++;
}
sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
return sdet;
}
DECLARE_DETELEMENT(SHcalSc04_Endcaps_v01, create_detector)
//================================================================================
// Description — End-Cap AHCAL
//--------------------------------------------------------------------------------
// Author: Ji-Yuan CHEN (SJTU; jy_chen@sjtu.edu.cn)
//--------------------------------------------------------------------------------
//
// End-cap AHCAL with 40×40×3 mm³ scintillator tiles.
// Adding the dead materials (cassette, PCB and electronic components, ESR wrapper and steel absorber) and including the air gaps, the size of each cell becomes 40.3×40.3×27.2 mm³.
//
// The inner radius, end-cap thickness, unit size, etc. are directly read from XML file.
//
// Structure in a layer: Cassette → ESR → scintillator → ESR → PCB (including electronic components) → cassette → steel absorber.
//
// Default layout: The absorber is designed as a whole with some space left for the sensitive units (the cross-section is not a polygon); steel frame on the edges of each module; 16 modules (called 'staves' in this program), 48 layers; 72 rows in r direction, with uniform granularity. For a schematic diagram, see Page 3 of <https://indico.ihep.ac.cn/event/22010/contributions/153187/attachments/77666/96430/2024_0324_Calorimeter_Endcaps.pdf> (the design on the left; the numbers have been modified).
//================================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/Shapes.h"
#include "DD4hep/DetType.h"
#include "XML/Layering.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
#include "DDSegmentation/Segmentation.h"
#include <sstream>
#include <cassert>
using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::to_string;
#define MYDEBUG(x) cout << __FILE__ << ":" << __LINE__ << ": " << x << endl;
#define MYDEBUGVAL(x) cout << __FILE__ << ":" << __LINE__ << ": "<< #x << ": " << x << endl;
using dd4hep::Ref_t;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::pi;
using dd4hep::mm;
using dd4hep::Material;
using dd4hep::DetElement;
using dd4hep::Volume;
using dd4hep::PolyhedraRegular;
using dd4hep::Tube;
using dd4hep::UnionSolid;
using dd4hep::Trapezoid;
using dd4hep::Box;
using dd4hep::SubtractionSolid;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationX;
using dd4hep::_toString;
using dd4hep::Transform3D;
using dd4hep::RotationZ;
using dd4hep::RotationY;
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens)
{
xml_det_t x_det = e;
const string det_name = x_det.nameStr();
const string det_type = x_det.typeStr();
const int det_id = x_det.id();
MYDEBUGVAL(det_name)
MYDEBUGVAL(det_type)
MYDEBUGVAL(det_id)
// To prevent overlapping
const double boundary_safety = theDetector.constant<double>("boundary_safety");
// Global geometry
const double r_in = theDetector.constant<double>("hcalendcap_inner_radius");
const double r_out = theDetector.constant<double>("hcalendcap_outer_radius");
const double module_thickness = theDetector.constant<double>("hcalendcap_thickness");
const double pos_z = theDetector.constant<double>("hcalendcap_z");
const int Nmodules = theDetector.constant<int>("Nmodules");
const double angle = 2 * pi / Nmodules;
// Unit size
const double scintillator_xy = theDetector.constant<double>("scintillator_xy");
const double scintillator_z = theDetector.constant<double>("scintillator_z");
const double wrapped_scintillator_xy = theDetector.constant<double>("wrapped_scintillator_xy");
const double wrapped_scintillator_z = theDetector.constant<double>("wrapped_scintillator_z");
// Dead materials
const double cassette_thickness = theDetector.constant<double>("cassette_thickness");
const double esr_thickness = theDetector.constant<double>("esr_thickness"); // Wrapper
[[maybe_unused]] const double sipm_xy = theDetector.constant<double>("sipm_xy");
[[maybe_unused]] const double sipm_z = theDetector.constant<double>("sipm_z");
const double pcb_thickness = theDetector.constant<double>("pcb_thickness");
const double absorber_thickness = theDetector.constant<double>("absorber_thickness");
const double air_gap_xy = 0.5 * (wrapped_scintillator_xy - scintillator_xy) - esr_thickness;
[[maybe_unused]] const double air_gap_z = 0.5 * (wrapped_scintillator_z - scintillator_z) - esr_thickness;
// Odd-shaped cells
const int Nodd = theDetector.constant<int>("Nodd");
const double short_elongation_1 = theDetector.constant<double>("short_elongation_1");
const double short_elongation_2 = theDetector.constant<double>("short_elongation_2");
const double short_elongation_3 = theDetector.constant<double>("short_elongation_3");
const double short_elongation_4 = theDetector.constant<double>("short_elongation_4");
const double short_elongation_5 = theDetector.constant<double>("short_elongation_5");
const double elongation_angle_esr_out = wrapped_scintillator_xy * tan(0.5 * angle); // Elongation of the outer edge of ESR: long side - short side
const double elongation_angle_esr_in = (wrapped_scintillator_xy - esr_thickness / cos(0.5 * angle)) * tan(0.5 * angle); // Elongation of the inner edge of ESR: long side - short side
const double elongation_angle_sc = scintillator_xy * tan(0.5 * angle); // Elongation of the scintillator: long side - short side
const vector<double> short_elongation_esr_out = { short_elongation_1, short_elongation_2, short_elongation_3, short_elongation_4, short_elongation_5 };
assert(Nodd == short_elongation_esr_out.size());
vector<double> short_elongation_sc(short_elongation_esr_out.size()), long_elongation_sc(short_elongation_esr_out.size()), short_elongation_esr_in(short_elongation_esr_out.size()), long_elongation_esr_in(short_elongation_esr_out.size()), long_elongation_esr_out(short_elongation_esr_out.size());
for (int i = 0; i < Nodd; ++i)
{
short_elongation_sc.at(i) = short_elongation_esr_out.at(i) - (air_gap_xy + esr_thickness) / cos(0.5 * angle);
long_elongation_sc.at(i) = short_elongation_sc.at(i) + elongation_angle_sc;
short_elongation_esr_in.at(i) = short_elongation_esr_out.at(i) - esr_thickness / cos(0.5 * angle);
long_elongation_esr_in.at(i) = short_elongation_esr_in.at(i) + elongation_angle_esr_in;
long_elongation_esr_out.at(i) = short_elongation_esr_out.at(i) + elongation_angle_esr_out;
}
// Mechanical structure
const double inner_structure_thickness = theDetector.constant<double>("inner_structure_thickness");
[[maybe_unused]] const double outer_structure_width = theDetector.constant<double>("outer_structure_width");
[[maybe_unused]] const double outer_structure_thickness = theDetector.constant<double>("outer_structure_thickness");
const double frame_thickness = theDetector.constant<double>("frame_thickness");
const double layer_thickness = wrapped_scintillator_z + pcb_thickness + 2 * cassette_thickness + absorber_thickness + 5 * boundary_safety;
const double non_absorber_thickness = wrapped_scintillator_z + pcb_thickness + 3 * boundary_safety;
MYDEBUGVAL(layer_thickness)
// Module size
const double dim_in_frame = (r_in + inner_structure_thickness + frame_thickness) * tan(0.5 * angle);
const double dim_out_frame = r_out * sin(0.5 * angle);
const double dim_in = dim_in_frame - frame_thickness / cos(0.5 * angle);
const double dim_out = dim_out_frame - frame_thickness / cos(0.5 * angle);
const double height = r_out * cos(0.5 * angle) - r_in - inner_structure_thickness;
const double r0 = r_in + inner_structure_thickness + 0.5 * height; // Rotation radius for placing the modules
const int Nrows = (int) (height / (wrapped_scintillator_xy + boundary_safety));
const int Nlayers = (int) (module_thickness / layer_thickness);
int Ncells_phi;
MYDEBUGVAL(Nrows)
MYDEBUGVAL(Nlayers)
// Materials
Material mat_air(theDetector.material("Air"));
Material mat_PCB(theDetector.material("PCB"));
[[maybe_unused]] Material mat_SiPM(theDetector.material("G4_Si"));
Material mat_sensitive(theDetector.material( x_det.materialStr() ));
Material mat_ESR(theDetector.material("G4_ESR"));
Material mat_steel(theDetector.material("Steel235"));
// The detector and mother volumes (world)
DetElement AHCAL(det_name, det_id);
Volume motherVol = theDetector.pickMotherVolume(AHCAL);
// Create two tube-like envelopes to represent the end-cap volumes
// PolyhedraRegular envelope_side(Nmodules, 0.5 * angle, r_in + inner_structure_thickness, r_out, module_thickness);
Tube envelope_side(r_in, r_out, 0.5 * module_thickness);
UnionSolid envelope(envelope_side, envelope_side, Position(0, 0, 2 * pos_z));
Volume envelopeVol(det_name, envelope, mat_steel);
PlacedVolume envelopePlv = motherVol.placeVolume(envelopeVol, Position(0, 0, -pos_z));
envelopePlv.addPhysVolID("system", det_id);
envelopeVol.setVisAttributes(theDetector, "SeeThrough");
AHCAL.setPlacement(envelopePlv);
DetElement stave_det(AHCAL, "sector", det_id);
// Module (stave)
Trapezoid stave(dim_in, dim_out, 0.5 * module_thickness, 0.5 * module_thickness, 0.5 * height);
Volume stave_vol("stave_vol", stave, mat_steel);
stave_vol.setVisAttributes(theDetector, "BlueVis");
// Layer with only wrapped scintillators, electronic components and PCB
Trapezoid layer(dim_in, dim_out, 0.5 * non_absorber_thickness, 0.5 * non_absorber_thickness, 0.5 * height);
Volume layer_vol("layer_vol", layer, mat_steel);
layer_vol.setVisAttributes(theDetector, "SeeThrough");
// Scintillator, ESR, SiPM, PCB, cassette, and absorber
Box normal_scintillator(0.5 * scintillator_xy, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Volume scintillator("scintillator", normal_scintillator, mat_sensitive); // Order: phi → z → r
scintillator.setVisAttributes(theDetector, "SeeThrough");
scintillator.setSensitiveDetector(sens);
[[maybe_unused]] Volume sipm("SiPM", Box(0.5 * sipm_xy, 0.5 * sipm_xy, 0.5 * sipm_z), mat_SiPM);
sipm.setVisAttributes(theDetector, "CyanVis");
Box esr_out(0.5 * wrapped_scintillator_xy, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Box esr_in(0.5 * wrapped_scintillator_xy - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Volume esr("esr", SubtractionSolid(esr_out, esr_in, Position(0, 0, 0)), mat_ESR);
esr.setVisAttributes(theDetector, "SeeThrough");
// Odd-shaped scintillators
Trapezoid odd_add_0_scintillator(0, long_elongation_sc.at(0) - short_elongation_sc.at(0), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Trapezoid odd_add_45_scintillator(short_elongation_sc.at(1), long_elongation_sc.at(1), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Trapezoid odd_add_9_scintillator(short_elongation_sc.at(2), long_elongation_sc.at(2), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Trapezoid odd_add_14_scintillator(short_elongation_sc.at(3), long_elongation_sc.at(3), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Trapezoid odd_add_17_scintillator(short_elongation_sc.at(4), long_elongation_sc.at(4), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Box odd_scintillator_0_rect(0.5 * (scintillator_xy + short_elongation_sc.at(0)), 0.5 * scintillator_z, 0.5 * scintillator_xy);
Volume odd_0_scintillator("odd_0_scintillator", UnionSolid(odd_scintillator_0_rect, odd_add_0_scintillator, Position(0.5 * (scintillator_xy + short_elongation_sc.at(0)), 0, 0)), mat_sensitive);
odd_0_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_0_scintillator.setSensitiveDetector(sens);
Volume odd_45_scintillator("odd_45_scintillator", UnionSolid(normal_scintillator, odd_add_45_scintillator, Position(0.5 * scintillator_xy, 0, 0)), mat_sensitive);
odd_45_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_45_scintillator.setSensitiveDetector(sens);
Volume odd_9_scintillator("odd_9_scintillator", UnionSolid(normal_scintillator, odd_add_9_scintillator, Position(0.5 * scintillator_xy, 0, 0)), mat_sensitive);
odd_9_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_9_scintillator.setSensitiveDetector(sens);
Volume odd_14_scintillator("odd_14_scintillator", UnionSolid(normal_scintillator, odd_add_14_scintillator, Position(0.5 * scintillator_xy, 0, 0)), mat_sensitive);
odd_14_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_14_scintillator.setSensitiveDetector(sens);
Volume odd_17_scintillator("odd_17_scintillator", UnionSolid(normal_scintillator, odd_add_17_scintillator, Position(0.5 * scintillator_xy, 0, 0)), mat_sensitive);
odd_17_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_17_scintillator.setSensitiveDetector(sens);
// Odd-shaped ESR
// Outer edge
Trapezoid odd_add_0_esr_out(short_elongation_esr_out.at(0), long_elongation_esr_out.at(0), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Trapezoid odd_add_45_esr_out(short_elongation_esr_out.at(1), long_elongation_esr_out.at(1), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Trapezoid odd_add_9_esr_out(short_elongation_esr_out.at(2), long_elongation_esr_out.at(2), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Trapezoid odd_add_14_esr_out(short_elongation_esr_out.at(3), long_elongation_esr_out.at(3), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Trapezoid odd_add_17_esr_out(short_elongation_esr_out.at(4), long_elongation_esr_out.at(4), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
UnionSolid odd_0_esr_out(esr_out, odd_add_0_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_45_esr_out(esr_out, odd_add_45_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_9_esr_out(esr_out, odd_add_9_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_14_esr_out(esr_out, odd_add_14_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_17_esr_out(esr_out, odd_add_17_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
// Inner edge
Trapezoid odd_add_0_esr_in(0, long_elongation_esr_in.at(0) - short_elongation_esr_in.at(0), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Trapezoid odd_add_45_esr_in(short_elongation_esr_in.at(1), long_elongation_esr_in.at(1), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Trapezoid odd_add_9_esr_in(short_elongation_esr_in.at(2), long_elongation_esr_in.at(2), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Trapezoid odd_add_14_esr_in(short_elongation_esr_in.at(3), long_elongation_esr_in.at(3), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Trapezoid odd_add_17_esr_in(short_elongation_esr_in.at(4), long_elongation_esr_in.at(4), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Box odd_esr_in_0_rect(0.5 * (wrapped_scintillator_xy - 2 * esr_thickness + short_elongation_esr_in.at(0)), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
UnionSolid odd_0_esr_in(odd_esr_in_0_rect, odd_add_0_esr_in, Position(0.5 * (wrapped_scintillator_xy + short_elongation_esr_in.at(0)), 0, 0));
UnionSolid odd_45_esr_in(esr_in, odd_add_45_esr_in, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_9_esr_in(esr_in, odd_add_9_esr_in, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_14_esr_in(esr_in, odd_add_14_esr_in, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_17_esr_in(esr_in, odd_add_17_esr_in, Position(0.5 * wrapped_scintillator_xy, 0, 0));
// Odd-shaped ESR, from the subtraction of outer and inner frames
Volume odd_0_esr("odd_0_esr", SubtractionSolid(odd_0_esr_out, odd_0_esr_in, Position(0, 0, 0)), mat_ESR);
Volume odd_45_esr("odd_45_esr", SubtractionSolid(odd_45_esr_out, odd_45_esr_in, Position(0, 0, 0)), mat_ESR);
Volume odd_9_esr("odd_9_esr", SubtractionSolid(odd_9_esr_out, odd_9_esr_in, Position(0, 0, 0)), mat_ESR);
Volume odd_14_esr("odd_14_esr", SubtractionSolid(odd_14_esr_out, odd_14_esr_in, Position(0, 0, 0)), mat_ESR);
Volume odd_17_esr("odd_17_esr", SubtractionSolid(odd_17_esr_out, odd_17_esr_in, Position(0, 0, 0)), mat_ESR);
// Positions
const double scintillator_pos_z = -0.5 * non_absorber_thickness + boundary_safety + 0.5 * wrapped_scintillator_z;
const double esr_pos_z = scintillator_pos_z;
const double pcb_pos_z = esr_pos_z + 0.5 * wrapped_scintillator_z + boundary_safety + 0.5 * pcb_thickness;
// Loop for placing the units in a layer
for (int ir = 1; ir <= Nrows; ++ir)
{
const double layer_length = dim_in + (ir - 1) * wrapped_scintillator_xy * tan(0.5 * angle);
Ncells_phi = (int) (2 * layer_length / wrapped_scintillator_xy);
const double layer_phi = Ncells_phi * wrapped_scintillator_xy;
const double single_elongation = layer_length - 0.5 * layer_phi;
Volume slice("slice", Trapezoid(layer_length, layer_length + elongation_angle_esr_out, 0.5 * non_absorber_thickness, 0.5 * non_absorber_thickness, 0.5 * (wrapped_scintillator_xy + boundary_safety)), mat_air);
slice.setVisAttributes(theDetector, "SeeThrough");
string slicename = "Slice_" + to_string(ir);
DetElement sd(stave_det, slicename, det_id);
Volume slice_pcb("slice_pcb", Box(0.5 * layer_phi, 0.5 * pcb_thickness, 0.5 * wrapped_scintillator_xy), mat_PCB);
slice_pcb.setVisAttributes(theDetector, "SeeThrough");
PlacedVolume pcb_unit = slice.placeVolume(slice_pcb, Position(0, pcb_pos_z, 0));
pcb_unit.addPhysVolID("row", ir);
for (int iphi = 1; iphi <= Ncells_phi; ++iphi)
{
PlacedVolume scintillator_unit;
PlacedVolume esr_unit;
Position position_scintillator((-0.5 * (Ncells_phi + 1) + iphi) * wrapped_scintillator_xy, scintillator_pos_z, 0);
Position position_esr((-0.5 * (Ncells_phi + 1) + iphi) * wrapped_scintillator_xy, esr_pos_z, 0);
Transform3D transform_scintillator(RotationZ(pi), position_scintillator);
Transform3D transform_esr(RotationZ(pi), position_esr);
if (iphi == 1)
{
if (single_elongation >= short_elongation_esr_out.at(4))
{
scintillator_unit = slice.placeVolume(odd_17_scintillator, transform_scintillator);
esr_unit = slice.placeVolume(odd_17_esr, transform_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(3))
{
scintillator_unit = slice.placeVolume(odd_14_scintillator, transform_scintillator);
esr_unit = slice.placeVolume(odd_14_esr, transform_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(2))
{
scintillator_unit = slice.placeVolume(odd_9_scintillator, transform_scintillator);
esr_unit = slice.placeVolume(odd_9_esr, transform_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(1))
{
scintillator_unit = slice.placeVolume(odd_45_scintillator, transform_scintillator);
esr_unit = slice.placeVolume(odd_45_esr, transform_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(0))
{
scintillator_unit = slice.placeVolume(odd_0_scintillator, Transform3D(RotationZ(pi),
Position((-0.5 * (Ncells_phi + 1) + iphi) * wrapped_scintillator_xy - 0.5 * short_elongation_esr_in.at(0),
scintillator_pos_z,
0)));
esr_unit = slice.placeVolume(odd_0_esr, transform_esr);
}
}
else if (iphi == Ncells_phi)
{
if (single_elongation >= short_elongation_esr_out.at(4))
{
scintillator_unit = slice.placeVolume(odd_17_scintillator, position_scintillator);
esr_unit = slice.placeVolume(odd_17_esr, position_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(3))
{
scintillator_unit = slice.placeVolume(odd_14_scintillator, position_scintillator);
esr_unit = slice.placeVolume(odd_14_esr, position_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(2))
{
scintillator_unit = slice.placeVolume(odd_9_scintillator, position_scintillator);
esr_unit = slice.placeVolume(odd_9_esr, position_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(1))
{
scintillator_unit = slice.placeVolume(odd_45_scintillator, position_scintillator);
esr_unit = slice.placeVolume(odd_45_esr, position_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(0))
{
scintillator_unit = slice.placeVolume(odd_0_scintillator,
Position((-0.5 * (Ncells_phi + 1) + iphi) * wrapped_scintillator_xy + 0.5 * short_elongation_esr_in.at(0),
scintillator_pos_z,
0));
esr_unit = slice.placeVolume(odd_0_esr, position_esr);
}
}
else
{
scintillator_unit = slice.placeVolume(scintillator, position_scintillator);
esr_unit = slice.placeVolume(esr, position_esr);
}
scintillator_unit.addPhysVolID("row", ir).addPhysVolID("phi", iphi);
esr_unit.addPhysVolID("row", ir).addPhysVolID("phi", iphi);
string scintillator_name = "Scintillator_" + to_string(ir) + "_" + to_string(iphi);
DetElement unit(sd, scintillator_name, det_id);
unit.setPlacement(scintillator_unit);
}
PlacedVolume plv = layer_vol.placeVolume(slice, Position(0, 0, (-0.5 * (Nrows + 1) + ir) * (wrapped_scintillator_xy + boundary_safety)));
plv.addPhysVolID("row", ir);
sd.setPlacement(plv);
}
// Loop for placing the layers in a module
for (int ilayer = 1; ilayer <= Nlayers; ++ilayer)
{
PlacedVolume plv = stave_vol.placeVolume(layer_vol, Position(0, (ilayer - 1) * layer_thickness + cassette_thickness + 0.5 * non_absorber_thickness - 0.5 * module_thickness, 0));
plv.addPhysVolID("layer", ilayer);
DetElement sd(stave_det, _toString(ilayer, "layer_%3d"), det_id);
sd.setPlacement(plv);
}
// Loop for placing the modules
for (int i = 0; i < Nmodules; ++i)
{
const double m_rot = i * angle;
const double posx = -r0 * sin(m_rot);
const double posy = r0 * cos(m_rot);
Transform3D transform_neg(RotationZ(m_rot) * RotationX(-0.5 * pi), Position(posx, posy, 0));
Transform3D transform_pos(RotationZ(m_rot) * RotationY(pi) * RotationX(-0.5 * pi), Position(posx, posy, 2 * pos_z));
PlacedVolume plv_neg = envelopeVol.placeVolume(stave_vol, transform_neg);
PlacedVolume plv_pos = envelopeVol.placeVolume(stave_vol, transform_pos);
plv_neg.addPhysVolID("stave", i);
plv_pos.addPhysVolID("stave", i + Nmodules);
DetElement sd_neg(AHCAL, _toString(i, "sector%3d"), det_id);
DetElement sd_pos(AHCAL, _toString(i + Nmodules, "sector%3d"), det_id);
sd_neg.setPlacement(plv_neg);
sd_pos.setPlacement(plv_pos);
}
sens.setType("calorimeter");
MYDEBUG("create_detector FINISHED.");
return AHCAL;
}
DECLARE_DETELEMENT(SHcalSc04_Endcaps_v02, create_detector)
//====================================================================
// lcgeo - LC detector models in DD4hep
//--------------------------------------------------------------------
// DD4hep Geometry driver for YokeBarrel
// Ported from Mokka
//--------------------------------------------------------------------
// S.Lu, DESY
// $Id$
//====================================================================
// *********************************************************
// * Mokka *
// * -- A Detailed Geant 4 Simulation for the ILC -- *
// * *
// * polywww.in2p3.fr/geant4/tesla/www/mokka/mokka.html *
// *********************************************************
//
// $Id$
// $Name: $
//
// History:
// - first implementation P. Mora de Freitas (May 2001)
// - selectable symmetry, self-scaling, removed pole tips
// - Adrian Vogel, 2006-03-17
// - muon system plus
// instrumented pole tip back for TESLA models
// - Predrag Krstonosic , 2006-08-30
// - added barrelEndcapGap, gear parameters, made barrel
// and endcap same thickness, made plug insensitive,
// - F.Gaede, DESY 2008-10-04
//
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DetType.h"
#include "XML/Layering.h"
#include "TGeoTrd2.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
using namespace std;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::Box;
using dd4hep::DetElement;
using dd4hep::DetType;
using dd4hep::Detector;
using dd4hep::Layering;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::PolyhedraRegular;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::Rotation3D;
using dd4hep::RotationZYX;
using dd4hep::Segmentation;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Volume;
using dd4hep::_toString;
using dd4hep::rec::LayeredCalorimeterData;
#define VERBOSE 1
// 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 element, SensitiveDetector sens) {
static double tolerance = 0e0;
xml_det_t x_det = element;
string det_name = x_det.nameStr();
Layering layering (element);
xml_comp_t x_dim = x_det.dimensions();
int nsides = x_dim.numsides();
Material air = theDetector.air();
xml_comp_t x_staves = x_det.staves();
Material yokeMaterial = theDetector.material(x_staves.materialStr());
//unused: Material env_mat = theDetector.material(x_dim.materialStr());
xml_comp_t env_pos = x_det.position();
xml_comp_t env_rot = x_det.rotation();
Position pos(env_pos.x(),env_pos.y(),env_pos.z());
RotationZYX rotZYX(env_rot.z(),env_rot.y(),env_rot.x());
Transform3D tr(rotZYX,pos);
int det_id = x_det.id();
DetElement sdet (det_name,det_id);
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ;
dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
//-----------------------------------------------------------------------------------
sens.setType("calorimeter");
//====================================================================
//
// Read all the constant from ILD_o1_v05.xml
// Use them to build Yoke05Barrel
//
//====================================================================
double Yoke_barrel_inner_radius = theDetector.constant<double>("Yoke_barrel_inner_radius");
//double Yoke_thickness = theDetector.constant<double>("Yoke_thickness");
//double Yoke_Barrel_Half_Z = theDetector.constant<double>("Yoke_Barrel_Half_Z");
double Yoke_Z_start_endcaps = theDetector.constant<double>("Yoke_Z_start_endcaps");
//double Yoke_cells_size = theDetector.constant<double>("Yoke_cells_size");
//Database *db = new Database(env.GetDBName());
//db->exec("SELECT * FROM `yoke`;");
//db->getTuple();
////... Geometry parameters from the environment and from the database
//symmetry = db->fetchInt("symmetry");
//const G4double rInnerBarrel =
// env.GetParameterAsDouble("Yoke_barrel_inner_radius");
//const G4double rInnerEndcap =
// env.GetParameterAsDouble("Yoke_endcap_inner_radius");
//const G4double zStartEndcap =
// env.GetParameterAsDouble("Yoke_Z_start_endcaps");
//
//db->exec("SELECT * FROM `muon`;");
//db->getTuple();
//iron_thickness = db->fetchDouble("iron_thickness");
//G4double gap_thickness = db->fetchDouble("layer_thickness");
//number_of_layers = db->fetchInt("number_of_layers");
//G4double yokeBarrelEndcapGap = db->fetchInt("barrel_endcap_gap");
//G4double cell_dim_x = db->fetchDouble("cell_size");
//G4double cell_dim_z = db->fetchDouble("cell_size");
//G4double chamber_thickness = 10*mm;
double yokeBarrelEndcapGap = 2.5;// ?? theDetector.constant<double>("barrel_endcap_gap"); //25.0*mm
//====================================================================
//
// general calculated parameters
//
//====================================================================
//port from Mokka Yoke05, the following parameters used by Yoke05
int symmetry = nsides;
double rInnerBarrel = Yoke_barrel_inner_radius;
double zStartEndcap = Yoke_Z_start_endcaps; // has been updated to 4072.0*mm by driver SCoil02
//TODO: put all magic numbers into ILD_o1_v05.xml file.
double gap_thickness = 4.0;
double iron_thickness = 10.0; //10.0 cm
int number_of_layers = 10;
//... Barrel parameters:
//... tolerance 1 mm
double yokeBarrelThickness = gap_thickness
+ number_of_layers*(iron_thickness + gap_thickness)
+ 3*(5.6*iron_thickness + gap_thickness)
+ 0.1; // the tolerance 1 mm
double rOuterBarrel = rInnerBarrel + yokeBarrelThickness;
double z_halfBarrel = zStartEndcap - yokeBarrelEndcapGap;
// In this release the number of modules is fixed to 3
double Yoke_Barrel_module_dim_z = 2.0*(zStartEndcap-yokeBarrelEndcapGap)/3.0 ;
//double Yoke_cell_dim_x = Yoke_cells_size;
//double Yoke_cell_dim_z = Yoke_Barrel_module_dim_z / floor (Yoke_Barrel_module_dim_z/Yoke_cell_dim_x);
cout<<" Build the yoke within this dimension "<<endl;
cout << " ...Yoke db: symmetry " << symmetry <<endl;
cout << " ...Yoke db: rInnerBarrel " << rInnerBarrel <<endl;
cout << " ...Yoke db: zStartEndcap " << zStartEndcap <<endl;
cout << " ...Muon db: iron_thickness " << iron_thickness <<endl;
cout << " ...Muon db: gap_thickness " << gap_thickness <<endl;
cout << " ...Muon db: number_of_layers " << number_of_layers <<endl;
cout << " ...Muon par: yokeBarrelThickness " << yokeBarrelThickness <<endl;
cout << " ...Muon par: Barrel_half_z " << z_halfBarrel <<endl;
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];
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
caloData->inner_symmetry = symmetry ;
caloData->outer_symmetry = symmetry ;
caloData->phi0 = 0 ; // also hardcoded below
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = rInnerBarrel ;
caloData->extent[1] = rOuterBarrel ;
caloData->extent[2] = 0. ;
caloData->extent[3] = z_halfBarrel ;
// ========= Create Yoke Barrel module ====================================
PolyhedraRegular YokeBarrelSolid( symmetry, M_PI/2.0-M_PI/symmetry, rInnerBarrel, rOuterBarrel, Yoke_Barrel_module_dim_z);
Volume mod_vol(det_name+"_module", YokeBarrelSolid, yokeMaterial);
//Volume mod_vol(det_name+"_module", YokeBarrelSolid, air);
mod_vol.setVisAttributes(theDetector.visAttributes(x_det.visStr()));
//====================================================================
// Build chamber volume
//====================================================================
//double gap_thickness = db->fetchDouble("layer_thickness");
//-------------------- start loop over Yoke layers ----------------------
// Loop over the sets of layer elements in the detector.
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
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();
// Loop over number of repeats for this layer.
for (int i=0; i<repeat; i++) {
//if(i>11) continue;
string l_name = _toString(l_num,"layer%d");
//double l_thickness = layering.layer(l_num-1)->thickness(); // Layer's thickness.
double l_thickness = layering.layer(i)->thickness(); // Layer's thickness.
//double gap_thickness = l_thickness;
//double iron_thickness = 10.0; //10.0 cm
double radius_low = rInnerBarrel+ 0.05 + i*gap_thickness + i*iron_thickness;
//rInnerBarrel+ 0.5*mm + i*gap_thickness + i*iron_thickness;
//double radius_mid = radius_low+0.5*gap_thickness;
//double radius_sensitive = radius_mid;
if( i>=10 ) radius_low = rInnerBarrel + 0.05 + i*gap_thickness + (i+(i-10)*4.6)*iron_thickness;
//{ radius_low =
// rInnerBarrel + 0.5*mm + i*gap_thickness
// + (i+(i-10)*4.6)*iron_thickness;
//radius_mid = radius_low+0.5*gap_thickness;
//radius_sensitive = radius_mid;
//}
//... safety margines of 0.1 mm for x,y of chambers
//double dx = radius_low*tan(Angle2)-0.1*mm;
//double dy = (zStartEndcap-yokeBarrelEndcapGap)/3.0-0.1*mm;
double Angle2 = M_PI/symmetry;
double dx = radius_low*tan(Angle2)-0.01;
double dy = (zStartEndcap-yokeBarrelEndcapGap)/3.0-0.01;
//Box ChamberSolid(dx,gap_thickness/2.,dy);
//Volume ChamberLog("muonSci",ChamberSolid,air);
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;
Box ChamberSolid(dx,l_thickness/2.0, dy);
Volume ChamberLog(det_name+"_"+l_name,ChamberSolid,air);
DetElement layer(l_name, det_id);
ChamberLog.setVisAttributes(theDetector.visAttributes(x_layer.visStr()));
// Loop over the sublayers or slices for this layer.
int s_num = 1;
double s_pos_y = -(l_thickness / 2);
//--------------------------------------------------------------------------------
// Build Layer, Sensitive Scintilator in the middle, and Air tolorance at two sides
//--------------------------------------------------------------------------------
double radiator_thickness = 0.05; // Yoke05 Barrel: No radiator before first sensitive layer.
if ( i>0 ) radiator_thickness = gap_thickness + iron_thickness - l_thickness;
if ( i>=10 ) radiator_thickness = gap_thickness + 5.6*iron_thickness - l_thickness;
nRadiationLengths = radiator_thickness/(yokeMaterial.radLength());
nInteractionLengths = radiator_thickness/(yokeMaterial.intLength());
thickness_sum = radiator_thickness;
for(xml_coll_t si(x_layer,_U(slice)); si; ++si) {
xml_comp_t x_slice = si;
string s_name = _toString(s_num,"slice%d");
double s_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
s_pos_y += s_thickness/2.;
double slab_dim_x = dx-tolerance;
double slab_dim_y = s_thickness/2.;
double slab_dim_z = dy-tolerance;
Box s_box(slab_dim_x,slab_dim_y,slab_dim_z);
Volume s_vol(det_name+"_"+l_name+"_"+s_name,s_box,slice_material);
DetElement slice(layer,s_name,det_id);
nRadiationLengths += s_thickness/(2.*slice_material.radLength());
nInteractionLengths += s_thickness/(2.*slice_material.intLength());
thickness_sum += s_thickness/2;
if ( x_slice.isSensitive() ) {
s_vol.setSensitiveDetector(sens);
std::cout << " ...Barrel i, position: " << i << " " << radius_low + l_thickness/2.0 + s_pos_y << std::endl;
#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 = s_thickness;
#endif
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
}
nRadiationLengths += s_thickness/(2.*slice_material.radLength());
nInteractionLengths += s_thickness/(2.*slice_material.intLength());
thickness_sum += s_thickness/2;
// Set region, limitset, and vis.
s_vol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
Position s_pos(0,s_pos_y,0); // Position of the layer.
PlacedVolume s_phv = ChamberLog.placeVolume(s_vol,s_pos);
slice.setPlacement(s_phv);
// Increment x position for next slice.
s_pos_y += s_thickness/2.;
++s_num;
}
#if DD4HEP_VERSION_GE( 0, 15 )
//Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
#endif
++l_num;
double phirot = 0;
for(int j=0;j<symmetry;j++)
{
double Y = radius_low + l_thickness/2.0;
Position xyzVec(-Y*sin(phirot), Y*cos(phirot), 0);
RotationZYX rot(phirot,0,0);
Rotation3D rot3D(rot);
Transform3D tran3D(rot3D,xyzVec);
PlacedVolume layer_phv = mod_vol.placeVolume(ChamberLog,tran3D);
layer_phv.addPhysVolID("layer", l_num).addPhysVolID("stave",j+1);
string stave_name = _toString(j+1,"stave%d");
string stave_layer_name = stave_name+_toString(l_num,"layer%d");
DetElement stave(stave_layer_name,det_id);;
stave.setPlacement(layer_phv);
sdet.add(stave);
phirot -= M_PI/symmetry*2.0;
}
//-----------------------------------------------------------------------------------------
caloLayer.distance = radius_low - radiator_thickness ;
caloLayer.absorberThickness = radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
//-----------------------------------------------------------------------------------------
}
}
//====================================================================
// Place Yoke05 Barrel stave module into the world volume
//====================================================================
for (int module_id = 1; module_id < 4; module_id++)
{
double module_z_offset = (module_id-2) * Yoke_Barrel_module_dim_z;
Position mpos(0,0,module_z_offset);
PlacedVolume m_phv = envelope.placeVolume(mod_vol,mpos);
m_phv.addPhysVolID("module",module_id).addPhysVolID("system", det_id);
m_phv.addPhysVolID("tower", 1);// Not used
string m_name = _toString(module_id,"module%d");
DetElement sd (m_name,det_id);
sd.setPlacement(m_phv);
sdet.add(sd);
}
sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
return sdet;
}
DECLARE_DETELEMENT(Yoke05_Barrel,create_detector)
//====================================================================
// lcgeo - LC detector models in DD4hep
//--------------------------------------------------------------------
// DD4hep Geometry driver for YokeEndcaps
// Ported from Mokka
//--------------------------------------------------------------------
// S.Lu, DESY
// $Id$
//====================================================================
// *********************************************************
// * Mokka *
// * -- A Detailed Geant 4 Simulation for the ILC -- *
// * *
// * polywww.in2p3.fr/geant4/tesla/www/mokka/mokka.html *
// *********************************************************
//
// $Id$
// $Name: $
//
// History:
// - first implementation P. Mora de Freitas (May 2001)
// - selectable symmetry, self-scaling, removed pole tips
// - Adrian Vogel, 2006-03-17
// - muon system plus
// instrumented pole tip back for TESLA models
// - Predrag Krstonosic , 2006-08-30
// - added barrelEndcapGap, gear parameters, made barrel
// and endcap same thickness, made plug insensitive,
// - F.Gaede, DESY 2008-10-04
//
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DetType.h"
#include "XML/Layering.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
using namespace std;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::DetType;
using dd4hep::Detector;
using dd4hep::Layering;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::PolyhedraRegular;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::Rotation3D;
using dd4hep::RotationZYX;
using dd4hep::Segmentation;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Volume;
using dd4hep::_toString;
using dd4hep::rec::LayeredCalorimeterData;
#define VERBOSE 1
// 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 element, SensitiveDetector sens) {
double tolerance = 0.1;
xml_det_t x_det = element;
string det_name = x_det.nameStr();
Layering layering (element);
xml_comp_t x_dim = x_det.dimensions();
int nsides = x_dim.numsides();
Material air = theDetector.air();
//unused: Material vacuum = theDetector.vacuum();
Material yokeMaterial = theDetector.material(x_det.materialStr());;
int det_id = x_det.id();
DetElement sdet (det_name,det_id);
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ;
dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
//-----------------------------------------------------------------------------------
sens.setType("calorimeter");
//====================================================================
//
// Read all the constant from ILD_o1_v05.xml
// Use them to build Yoke05Endcaps
//
//====================================================================
double Yoke_barrel_inner_radius = theDetector.constant<double>("Yoke_barrel_inner_radius");
double Yoke_endcap_inner_radius = theDetector.constant<double>("Yoke_endcap_inner_radius");
double Yoke_Z_start_endcaps = theDetector.constant<double>("Yoke_Z_start_endcaps");
double HCAL_R_max = theDetector.constant<double>("Hcal_outer_radius");
//double Yoke_cells_size = theDetector.constant<double>("Yoke_cells_size");
double yokeBarrelEndcapGap = 2.5;// ?? theDetector.constant<double>("barrel_endcap_gap"); //25.0*mm
//====================================================================
//
// general calculated parameters
//
//====================================================================
//port from Mokka Yoke05, the following parameters used by Yoke05
int symmetry = nsides;
double rInnerBarrel = Yoke_barrel_inner_radius;
double zStartEndcap = Yoke_Z_start_endcaps; // has been updated to 4072.0*mm by driver SCoil02
//TODO: put all magic numbers into ILD_o1_v05.xml file.
double gap_thickness = 4.0;
double iron_thickness = 10.0; //10.0 cm
int number_of_layers = 10;
//... Barrel parameters:
//... tolerance 1 mm
double yokeBarrelThickness = gap_thickness
+ number_of_layers*(iron_thickness + gap_thickness)
+ 3*(5.6*iron_thickness + gap_thickness)
+ 0.1; // the tolerance 1 mm
double yokeEndcapThickness = number_of_layers*(iron_thickness + gap_thickness)
+ 2*(5.6*iron_thickness + gap_thickness); // + gap_thickness;
double rInnerEndcap = Yoke_endcap_inner_radius;
double rOuterEndcap = rInnerBarrel + yokeBarrelThickness;
double z_halfBarrel = zStartEndcap - yokeBarrelEndcapGap;
//Port from Mokka:
// Endcap Thickness has no tolerance
// But the placement should shift_middle by -0.05 (0.5*mm) later
double Yoke_Endcap_module_dim_z = yokeEndcapThickness;
//double Yoke_cell_dim_x = rOuterEndcap*2.0 / floor (rOuterEndcap*2.0/Yoke_cells_size);
//double Yoke_cell_dim_y = Yoke_cell_dim_x;
cout<<" Build the yoke within this dimension "<<endl;
cout << " ...Yoke db: symmetry " << symmetry <<endl;
cout << " ...Yoke db: rInnerEndcap " << rInnerEndcap <<endl;
cout << " ...Yoke db: rOuterEndcap " << rOuterEndcap <<endl;
cout << " ...Yoke db: zStartEndcap " << zStartEndcap <<endl;
cout << " ...Muon db: iron_thickness " << iron_thickness <<endl;
cout << " ...Muon db: gap_thickness " << gap_thickness <<endl;
cout << " ...Muon db: number_of_layers " << number_of_layers <<endl;
cout << " ...Muon par: yokeEndcapThickness " << yokeEndcapThickness <<endl;
cout << " ...Muon par: Barrel_half_z " << z_halfBarrel <<endl;
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];
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
caloData->inner_symmetry = symmetry ;
caloData->outer_symmetry = symmetry ;
caloData->phi0 = 0 ; // hardcoded
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = rInnerEndcap ;
caloData->extent[1] = rOuterEndcap ;
caloData->extent[2] = zStartEndcap ;
caloData->extent[3] = zStartEndcap + Yoke_Endcap_module_dim_z ;
PolyhedraRegular YokeEndcapSolid( symmetry, M_PI/symmetry, rInnerEndcap, rOuterEndcap, Yoke_Endcap_module_dim_z);
Volume mod_vol(det_name+"_module", YokeEndcapSolid, yokeMaterial);
mod_vol.setVisAttributes(theDetector.visAttributes(x_det.visStr()));
//====================================================================
// Build chamber volume
//====================================================================
//double gap_thickness = db->fetchDouble("layer_thickness");
//-------------------- start loop over Yoke layers ----------------------
// Loop over the sets of layer elements in the detector.
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
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();
// Loop over number of repeats for this layer.
for (int i=0; i<repeat; i++) {
//if(i>11) continue;
string l_name = _toString(l_num,"layer%d");
double l_thickness = layering.layer(i)->thickness(); // Layer's thickness.
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;
PolyhedraRegular ChamberSolid( symmetry, M_PI/symmetry, rInnerEndcap + tolerance, rOuterEndcap - tolerance, l_thickness);
Volume ChamberLog(det_name+"_"+l_name,ChamberSolid,air);
DetElement layer(l_name, det_id);
ChamberLog.setVisAttributes(theDetector.visAttributes(x_layer.visStr()));
// Loop over the sublayers or slices for this layer.
int s_num = 1;
double s_pos_z = -(l_thickness / 2);
double shift_middle = - yokeEndcapThickness/2 - 0.05 //-0.5*mm since PolyhedraRegular from -Yoke_Endcap_module_dim_z/2 to Yoke_Endcap_module_dim_z/2
+ iron_thickness*(i+1)
+ (i+0.5)*gap_thickness;
if( i>= 10){
shift_middle = - yokeEndcapThickness/2 - 0.05 //0.5*mm
+ iron_thickness*(i+1+(i-9)*4.6) + (i+0.5)*gap_thickness;
}
//--------------------------------------------------------------------------------
// Build Layer, Sensitive Scintilator in the middle, and Air tolorance at two sides
//--------------------------------------------------------------------------------
double radiator_thickness = -0.05 + 0.5*gap_thickness + iron_thickness - l_thickness/2.0 ;
if ( i>0 ) radiator_thickness = gap_thickness + iron_thickness - l_thickness ;
if ( i>=10 ) radiator_thickness = gap_thickness + 5.6*iron_thickness - l_thickness ;
nRadiationLengths = radiator_thickness/(yokeMaterial.radLength());
nInteractionLengths = radiator_thickness/(yokeMaterial.intLength());
thickness_sum = radiator_thickness;
for(xml_coll_t si(x_layer,_U(slice)); si; ++si) {
xml_comp_t x_slice = si;
string s_name = _toString(s_num,"slice%d");
double s_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
s_pos_z += s_thickness/2.;
PolyhedraRegular sliceSolid( symmetry, M_PI/symmetry, rInnerEndcap + tolerance + 0.01, rOuterEndcap - tolerance -0.01, s_thickness);
Volume s_vol(det_name+"_"+l_name+"_"+s_name,sliceSolid,slice_material);
DetElement slice(layer,s_name,det_id);
nRadiationLengths += s_thickness/(2.*slice_material.radLength());
nInteractionLengths += s_thickness/(2.*slice_material.intLength());
thickness_sum += s_thickness/2;
if ( x_slice.isSensitive() ) {
s_vol.setSensitiveDetector(sens);
cout << " ...Endcap i, position: " << i << " " << zStartEndcap + yokeEndcapThickness/2 + shift_middle + l_thickness/2.0 + s_pos_z << endl;
#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 = s_thickness;
#endif
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
}
nRadiationLengths += s_thickness/(2.*slice_material.radLength());
nInteractionLengths += s_thickness/(2.*slice_material.intLength());
thickness_sum += s_thickness/2;
// Set region, limitset, and vis.
s_vol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
Position s_pos(0,0,s_pos_z); // Position of the layer.
PlacedVolume s_phv = ChamberLog.placeVolume(s_vol,s_pos);
slice.setPlacement(s_phv);
// Increment x position for next slice.
s_pos_z += s_thickness/2.;
++s_num;
}
#if DD4HEP_VERSION_GE( 0, 15 )
//Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
#endif
++l_num;
Position xyzVec(0,0,shift_middle);
PlacedVolume layer_phv = mod_vol.placeVolume(ChamberLog,xyzVec);
layer_phv.addPhysVolID("layer", l_num);
//string stave_name = "stave1";
string stave_layer_name = "stave1"+_toString(l_num,"layer%d");
DetElement stave(stave_layer_name,det_id);;
stave.setPlacement(layer_phv);
sdet.add(stave);
//-----------------------------------------------------------------------------------------
caloLayer.distance = zStartEndcap + yokeEndcapThickness/2.0 + shift_middle
- caloLayer.inner_thickness ;
caloLayer.absorberThickness = radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
//-----------------------------------------------------------------------------------------
}
}
//====================================================================
// Check Yoke05 plug module
//====================================================================
bool build_plug = false;
double HCAL_z = theDetector.constant<double>("HcalEndcap_max_z");;
double HCAL_plug_gap = theDetector.constant<double>("Hcal_Yoke_plug_gap");
int Hcal_endcap_outer_symmetry = theDetector.constant<int>("Hcal_endcap_outer_symmetry");
double plug_thickness = zStartEndcap-HCAL_z-HCAL_plug_gap;
double rInnerPlug = Yoke_endcap_inner_radius;
double rOuterPlug = HCAL_R_max*cos(dd4hep::pi/16.) *cos(dd4hep::pi/Hcal_endcap_outer_symmetry);
double Yoke_Plug_module_dim_z = plug_thickness;
// Is there a space to build Yoke plug
if( Yoke_Plug_module_dim_z > 0 )
{
build_plug = true;
cout << " ...Plug par: build_plug is true, there is space to build yoke plug" <<endl;
cout << " ...Plug par: HCAL_half_z " << HCAL_z <<endl;
cout << " ...Plug par: HCAL_Plug_Gap " << HCAL_plug_gap <<endl;
cout << " ...Plug par: Plug Thickness " << plug_thickness <<endl;
cout << " ...Plug par: Plug Radius " << rOuterPlug <<endl;
}
//====================================================================
// Place Yoke05 Endcaps module into the world volume
//====================================================================
double zEndcap = zStartEndcap + yokeEndcapThickness/2.0 + 0.1; // Need 0.1 (1.0*mm) according to the Mokka Yoke05 driver.
double zPlug = zStartEndcap - plug_thickness/2.0 -0.05; // Need 0.05 (0.5*mm) according to the Mokka Yoke05 driver.
for(int module_num=0;module_num<2;module_num++) {
int module_id = ( module_num == 0 ) ? 0:6;
double this_module_z_offset = ( module_id == 0 ) ? - zEndcap : zEndcap;
double this_module_rotY = ( module_id == 0 ) ? M_PI:0;
Position xyzVec(0,0,this_module_z_offset);
RotationZYX rot(0,this_module_rotY,0);
Rotation3D rot3D(rot);
Transform3D tran3D(rot3D,xyzVec);
PlacedVolume pv = envelope.placeVolume(mod_vol,tran3D);
pv.addPhysVolID("module",module_id); // z: -/+ 0/6
string m_name = _toString(module_id,"module%d");
DetElement sd (m_name,det_id);
sd.setPlacement(pv);
sdet.add(sd);
//====================================================================
// If build_plug is true, Place the plug module into the world volume
//====================================================================
if(build_plug == true){
PolyhedraRegular YokePlugSolid( symmetry, M_PI/symmetry, rInnerPlug, rOuterPlug, Yoke_Plug_module_dim_z);
Volume plug_vol(det_name+"_plug", YokePlugSolid, yokeMaterial);
plug_vol.setVisAttributes(theDetector.visAttributes(x_det.visStr()));
double this_plug_z_offset = ( module_id == 0 ) ? - zPlug : zPlug;
Position plug_pos(0,0,this_plug_z_offset);
PlacedVolume plug_phv = envelope.placeVolume(plug_vol,plug_pos);
string plug_name = _toString(module_id,"plug%d");
DetElement plug (plug_name,det_id);
plug.setPlacement(plug_phv);
}
}
sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
return sdet;
}
DECLARE_DETELEMENT(Yoke05_Endcaps,create_detector)
//====================================================================
// DDSim - LC detector models in DD4hep
//--------------------------------------------------------------------
// F.Gaede, DESY
// $Id$
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDRec/Surface.h"
#include "XMLHandlerDB.h"
#include "XML/Utilities.h"
#include <cmath>
#include "DDRec/DetectorData.h"
//#include "GearWrapper.h"
using namespace std;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::Box;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::PolyhedraRegular;
using dd4hep::Position;
using dd4hep::Ref_t;
using dd4hep::RotationZYX;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Tube;
using dd4hep::Volume;
using dd4hep::xml::_toString;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of the coil, ported from Mokka drivers SCoil02.cc and Coil01.cc
*
* Mokka History:
* SCoil02.cc
* F.Gaede, DESY: based on SCoil01, with added parameters for the
* clearance to the yoke:
* Hcal_Coil_additional_gap : adjust the actual gap in r (Hcal_R_max allready defines a gap)
* Coil_Yoke_radial_clearance : -> defines inner r of yoke
* Coil_Yoke_lateral_clearance : -> defines zEndcap of yoke
* Coil00.cc
* - first implementation P. Mora de Freitas (may 01)
* - F.Gaede: write out parameters to GEAR (Oct 08)
* Coil00.cc:
* - V. Saveliev: replaced simple Al-tube with more detailed structure (cryostat, etc )
*
* @author: F.Gaede, DESY, Aug 2014
*/
static Ref_t create_element(Detector& theDetector, xml_h element, SensitiveDetector sens) {
//------------------------------------------
// See comments starting with '//**' for
// hints on porting issues
//------------------------------------------
xml_det_t x_det = element;
string name = x_det.nameStr();
DetElement coil( name, x_det.id() ) ;
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , coil ) ;
dd4hep::xml::setDetectorTypeFlag( element, coil ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return coil ;
//-----------------------------------------------------------------------------------
sens.setType("tracker");
PlacedVolume pv;
//######################################################################################################################################################################
// code ported from Coil02::construct() :
//##################################
cout << "\nBuilding Coil..." << endl;
xml_comp_t x_tube (x_det.child(_U(tube)));
double inner_radius = x_tube.rmin() ;
double outer_radius = x_tube.rmax() ;
double half_z = x_tube.dz() ;
cout << "\n... cryostat inner_radius " << inner_radius
<< "\n... cryostat outer_radius " << outer_radius
<< "\n... cryostat half_z " << half_z
<< endl;
double tCoil = outer_radius - inner_radius;
double zMandrel = half_z-197*dd4hep::mm;
double rInnerMain = 175./750.*tCoil;
double rOuterMain = 426./750.*tCoil;
double zCorrect = zMandrel/3;
double zMain = (zMandrel-zCorrect)*2/3;
double rInnerMandrel = rOuterMain;
double rOuterMandrel = 654./750.*tCoil;
double rInnerSci1 = 90*dd4hep::mm;
double rInnerSci2 = 105*dd4hep::mm;
double rInnerSci3 = -90*dd4hep::mm;
double rInnerSci4 = -105*dd4hep::mm;
double zReduceSci = 100*dd4hep::mm;
Material coilMaterial = theDetector.material( x_tube.materialStr() ) ;
//FG: for now fall back to a simple tube filled with Al
// the code below has to many hard coded numbers
// that need verification and then need to be converted
// to xml parameters ...
#define code_is_cleaned_up true
#if 0 //!code_is_cleaned_up
Tube coil_tube( x_tube.rmin(), x_tube.rmax(), x_tube.dz() );
Volume coil_vol( "coil_vol", coil_tube , coilMaterial );
pv = envelope.placeVolume( coil_vol ) ;
coil.setVisAttributes( theDetector, "BlueVis" , coil_vol );
cout << " ... for the time being simply use a tube of aluminum ..." << endl ;
//=========================================================================================================
#else
//... Coil Cryostat (Al, inside vacuum)
//... inner cylinder
Tube CoilEnvelopeSolid_1( inner_radius, 40.* dd4hep::mm + inner_radius , half_z ) ;
Volume CoilLogical_1( "CoilEnvelope_1", CoilEnvelopeSolid_1, coilMaterial ) ;
coil.setVisAttributes( theDetector, "ShellVis" , CoilLogical_1 );
pv = envelope.placeVolume( CoilLogical_1 ) ;
//... outer cylinder
Tube CoilEnvelopeSolid_2 ( -30*dd4hep::mm + outer_radius, outer_radius , half_z ) ;
Volume CoilLogical_2( "CoilEnvelope_2", CoilEnvelopeSolid_2, coilMaterial ) ;
coil.setVisAttributes( theDetector, "ShellVis" , CoilLogical_2 );
pv = envelope.placeVolume( CoilLogical_2 ) ;
//... side wall left
Tube CoilEnvelopeSolid_3( 40*dd4hep::mm + inner_radius, -30*dd4hep::mm + outer_radius, 25.* dd4hep::mm ) ;
Volume CoilLogical_3( "CoilEnvelope_3", CoilEnvelopeSolid_3, coilMaterial ) ;
coil.setVisAttributes( theDetector, "ShellVis" , CoilLogical_3 );
pv = envelope.placeVolume( CoilLogical_3 , Position( 0., 0., -25.*dd4hep::mm + half_z ) ) ;
//... side wall right
// Tube CoilEnvelopeSolid_4( 40*dd4hep::mm + inner_radius, -30*dd4hep::mm + outer_radius, 25.* dd4hep::mm ) ;
// Volume CoilLogical_4( "CoilEnvelope_4", CoilEnvelopeSolid_4, coilMaterial ) ;
// coil.setVisAttributes( theDetector, "BlueVis" , CoilLogical_4 );
// pv = envelope.placeVolume( CoilLogical_4 , Position( 0., 0., 25.*dd4hep::mm - half_z ) ) ;
//simply place the same volume again
pv = envelope.placeVolume( CoilLogical_3 , Position( 0., 0., 25.*dd4hep::mm - half_z ) ) ;
//... Coil modules
//... main coll module 1,2,3
Tube CoilMainSolid_1( rInnerMain + inner_radius, rOuterMain + inner_radius, zMain/2-0.*dd4hep::mm ) ;
Volume CoilMainLogical_1( "CoilMain_1" , CoilMainSolid_1, coilMaterial ) ;
coil.setVisAttributes( theDetector, "GreyVis" , CoilMainLogical_1 );
pv = envelope.placeVolume( CoilMainLogical_1 , Position( 0., 0., -zMain ) ) ;
pv = envelope.placeVolume( CoilMainLogical_1 , Position( 0., 0., 0. ) ) ;
pv = envelope.placeVolume( CoilMainLogical_1 , Position( 0., 0., zMain ) ) ;
Material aluminium = theDetector.material("G4_Al");
Material polystyrene = theDetector.material("G4_POLYSTYRENE");
//... corrected coil module 1,2
Tube CoilCorrectSolid_1(rInnerMain + inner_radius, rOuterMain + inner_radius, zCorrect/2);
Volume CoilCorrectLogical_1("CoilCorrect_1", CoilCorrectSolid_1, aluminium);
coil.setVisAttributes( theDetector, "BlueVis", CoilCorrectLogical_1);
pv = envelope.placeVolume(CoilCorrectLogical_1, Position(0., 0., -zMain*3/2-zCorrect/2));
pv = envelope.placeVolume(CoilCorrectLogical_1, Position(0., 0., zMain*3/2+zCorrect/2));
//... Coil mandrel
Tube CoilMandrelSolid(rInnerMandrel + inner_radius, rOuterMandrel + inner_radius, zMandrel);
Volume CoilMandrelLogical("CoilMandrel", CoilMandrelSolid, aluminium);
coil.setVisAttributes( theDetector, "GreenVis", CoilMandrelLogical);
pv = envelope.placeVolume(CoilMandrelLogical, Position(0., 0., 0.));
//... Coil sensitive detectors
int layer_id=1; //Put in the database!!!
// Threshold is 20%. mip = 200 keV/dd4hep::mm
const double sensitive_thickness = 10. *dd4hep::mm;
//theCoilSD = new TRKSD00("COIL", sensitive_thickness * 200 * keV * 0.01);
//RegisterSensitiveDetector(theCoilSD);
double rOuterSci1 = rInnerSci1 + sensitive_thickness;
double rOuterSci2 = rInnerSci2 + sensitive_thickness;
double rOuterSci3 = rInnerSci3 + sensitive_thickness;
double rOuterSci4 = rInnerSci4 + sensitive_thickness;
double halfZSci = half_z - zReduceSci;
//... Scintillator Detector layer 1
if((rOuterSci1+inner_radius)/cos(dd4hep::pi/24)<rInnerMain+inner_radius){
const double zPozBarrelArray_1 = halfZSci;
const double rInnerBarrelArray_1 = rInnerSci1+inner_radius;
const double rOuterBarrelArray_1 = rOuterSci1+inner_radius;
PolyhedraRegular CoilScintSolid_1(24, rInnerBarrelArray_1, rOuterBarrelArray_1, zPozBarrelArray_1*2);
Volume CoilScintLogical_1("CoilScint_1", CoilScintSolid_1, polystyrene);
coil.setVisAttributes( theDetector, "RedVis", CoilScintLogical_1);
CoilScintLogical_1.setSensitiveDetector(sens);
pv = envelope.placeVolume(CoilScintLogical_1, Position(0., 0., 0.));
pv.addPhysVolID("layer",layer_id);
}
layer_id++;
//... Scintillation Detector layer 2
if((rOuterSci2+inner_radius)/cos(dd4hep::pi/24)<rInnerMain+inner_radius){
const double zPozBarrelArray_2 = halfZSci;
const double rInnerBarrelArray_2 = rInnerSci2+inner_radius;
const double rOuterBarrelArray_2 = rOuterSci2+inner_radius;
PolyhedraRegular CoilScintSolid_2(24, rInnerBarrelArray_2, rOuterBarrelArray_2, zPozBarrelArray_2*2);
Volume CoilScintLogical_2("CoilScint_2", CoilScintSolid_2, polystyrene);
coil.setVisAttributes( theDetector, "RedVis", CoilScintLogical_2);
CoilScintLogical_2.setSensitiveDetector(sens);
pv = envelope.placeVolume(CoilScintLogical_2, Position(0., 0., 0.));
pv.addPhysVolID("layer",layer_id);
}
layer_id++;
//... Scint detector layer 3
if(rInnerSci3+outer_radius>rOuterMandrel+inner_radius){
const double zPozBarrelArray_3 = halfZSci;
const double rInnerBarrelArray_3 = rInnerSci3+outer_radius;
const double rOuterBarrelArray_3 = rOuterSci3+outer_radius;
PolyhedraRegular CoilScintSolid_3(24, rInnerBarrelArray_3, rOuterBarrelArray_3, zPozBarrelArray_3*2);
Volume CoilScintLogical_3("CoilScint_3", CoilScintSolid_3, polystyrene);
coil.setVisAttributes( theDetector, "RedVis", CoilScintLogical_3);
CoilScintLogical_3.setSensitiveDetector(sens);
pv = envelope.placeVolume(CoilScintLogical_3, Position(0., 0., 0.));
pv.addPhysVolID("layer",layer_id);
}
layer_id++;
//... Scintillation Detector layer 4
if(rInnerSci4+outer_radius>rOuterMandrel+inner_radius){
const double zPozBarrelArray_4 = halfZSci;
const double rInnerBarrelArray_4 = rInnerSci4+outer_radius;
const double rOuterBarrelArray_4 = rOuterSci4+outer_radius;
PolyhedraRegular CoilScintSolid_4(24, rInnerBarrelArray_4, rOuterBarrelArray_4, zPozBarrelArray_4*2);
Volume CoilScintLogical_4("CoilScint_4", CoilScintSolid_4, polystyrene);
coil.setVisAttributes( theDetector, "RedVis", CoilScintLogical_4);
CoilScintLogical_4.setSensitiveDetector(sens);
pv = envelope.placeVolume(CoilScintLogical_4, Position(0., 0., 0.));
pv.addPhysVolID("layer",layer_id);
}
#ifdef MOKKA_GEAR
//----------------------------------------------------
// MokkaGear
//----------------------------------------------------
MokkaGear* gearMgr = MokkaGear::getMgr() ;
gear::GearParametersImpl* gp = new gear::GearParametersImpl ;
//Inner Cylinder
gp->setDoubleVal("Coil_cryostat_inner_cyl_inner_radius",
inner_radius);
gp->setDoubleVal("Coil_cryostat_inner_cyl_outer_radius",
40.*dd4hep::mm+inner_radius);
gp->setDoubleVal("Coil_cryostat_inner_cyl_half_z", half_z);
gp->setStringVal("Coil_material_inner_cyl", "aluminium");
//Outer Cylinder
gp->setDoubleVal("Coil_cryostat_outer_cyl_inner_radius",
-30*dd4hep::mm+outer_radius);
gp->setDoubleVal("Coil_cryostat_outer_cyl_outer_radius",
outer_radius);
gp->setDoubleVal("Coil_cryostat_outer_cyl_half_z", half_z);
gp->setStringVal("Coil_material_outer_cyl", "aluminium");
//FG: add the parameters under the 'old' names as expected by the reconstruction:
gp->setDoubleVal("Coil_cryostat_inner_radius", inner_radius);
gp->setDoubleVal("Coil_cryostat_outer_radius", outer_radius);
gp->setDoubleVal("Coil_cryostat_half_z", half_z);
//Side wall left
gp->setDoubleVal("Coil_cryostat_side_l_inner_radius",
40*dd4hep::mm+inner_radius);
gp->setDoubleVal("Coil_cryostat_side_l_outer_radius",
-30*dd4hep::mm+outer_radius);
gp->setDoubleVal("Coil_cryostat_side_l_half_z", 25.*dd4hep::mm);
gp->setStringVal("Coil_material_side_l", "aluminium");
//Side wall right
gp->setDoubleVal("Coil_cryostat_side_r_inner_radius",
40*dd4hep::mm+inner_radius);
gp->setDoubleVal("Coil_cryostat_side_r_outer_radius",
-30*dd4hep::mm+outer_radius);
gp->setDoubleVal("Coil_cryostat_side_r_half_z", 25.*dd4hep::mm);
gp->setStringVal("Coil_material_side_r", "aluminium");
// Coil modules
gp->setDoubleVal("Coil_cryostat_modules_inner_radius",
rInnerMain+inner_radius);
gp->setDoubleVal("Coil_cryostat_modules_outer_radius",
rOuterMain+inner_radius);
gp->setDoubleVal("Coil_cryostat_modules_half_z", zMain/2-20.*dd4hep::mm);
gp->setStringVal("Coil_material_modules", "aluminium");
gp->setDoubleVal("Coil_cryostat_c_modules_inner_radius",
rInnerMain+inner_radius);
gp->setDoubleVal("Coil_cryostat_c_modules_outer_radius",
rOuterMain+inner_radius);
gp->setDoubleVal("Coil_cryostat_c_modules_half_z", zCorrect);
gp->setStringVal("Coil_material_c_modules", "aluminium");
//Coil mandrel
gp->setDoubleVal("Coil_cryostat_mandrel_inner_radius",
rInnerMandrel+inner_radius);
gp->setDoubleVal("Coil_cryostat_mandrel_outer_radius",
rOuterMandrel+inner_radius);
gp->setDoubleVal("Coil_cryostat_mandrel_half_z", zMandrel);
gp->setStringVal("Coil_material_mandrel", "aluminium");
//Sensitive detectors
gp->setDoubleVal("Coil_cryostat_scint1_inner_radius",
rInnerSci1+inner_radius);
gp->setDoubleVal("Coil_cryostat_scint1_outer_radius",
rOuterSci1+inner_radius);
gp->setDoubleVal("Coil_cryostat_scint1_zposin",
-zReduceSci+half_z);
gp->setDoubleVal("Coil_cryostat_scint1_zposend",
+zReduceSci+half_z);
gp->setStringVal("Coil_material_scint1", "polystyrene");
gp->setDoubleVal("Coil_cryostat_scint2_inner_radius",
rInnerSci2+inner_radius);
gp->setDoubleVal("Coil_cryostat_scint2_outer_radius",
rOuterSci2+inner_radius);
gp->setDoubleVal("Coil_cryostat_scint2_zposin",
-zReduceSci+half_z);
gp->setDoubleVal("Coil_cryostat_scint2_zposend",
+zReduceSci+half_z);
gp->setStringVal("Coil_material_scint2", "polystyrene");
gp->setDoubleVal("Coil_cryostat_scint3_inner_radius",
rInnerSci3+outer_radius);
gp->setDoubleVal("Coil_cryostat_scint3_outer_radius",
rOuterSci3+outer_radius);
gp->setDoubleVal("Coil_cryostat_scint3_zposin",
-zReduceSci+half_z);
gp->setDoubleVal("Coil_cryostat_scint3_zposend",
+zReduceSci+half_z);
gp->setStringVal("Coil_material_scint3", "polystyrene");
gp->setDoubleVal("Coil_cryostat_scint4_inner_radius",
rInnerSci4+outer_radius);
gp->setDoubleVal("Coil_cryostat_scint4_outer_radius",
rOuterSci4+outer_radius);
gp->setDoubleVal("Coil_cryostat_scint4_zposin",
-zReduceSci+half_z);
gp->setDoubleVal("Coil_cryostat_scint4_zposend",
+zReduceSci+half_z);
gp->setStringVal("Coil_material_scint4", "polystyrene");
gearMgr->setGearParameters("CoilParameters", gp);
#endif
cout << "Coil done.\n" << endl;
// //====== create the meassurement surface ===================
// Vector3D u,v,n ;
// if( faces_IP == 0 ){
// // will be rotated around z-axis later
// u.fill( 0. , -1. , 0. ) ;
// v.fill( 0. , 0. , 1. ) ;
// n.fill( -1. , 0. , 0. ) ;
// // implement 7 deg stereo angle
// u.fill( 0. , -cos( 3.5 * dd4hep::deg ) , -sin( 3.5 * dd4hep::deg ) ) ;
// v.fill( 0. , -sin( 3.5 * dd4hep::deg ) , cos( 3.5 * dd4hep::deg ) ) ;
// } else {
// u.fill( 0. , 1. , 0. ) ;
// v.fill( 0. , 0. , 1. ) ;
// n.fill( 1. , 0. , 0. ) ;
// // implement 7 deg stereo angle
// u.fill( 0. , cos( 3.5 * dd4hep::deg ) , sin( 3.5 * dd4hep::deg ) ) ;
// v.fill( 0. , -sin( 3.5 * dd4hep::deg ) , cos( 3.5 * dd4hep::deg ) ) ;
// }
// double inner_thick = sensitive_thickness / 2.0 ;
// double outer_thick = sensitive_thickness / 2.0 + support_thickness ; // support is on top
// VolPlane surf( sitSenLogical , SurfaceType(SurfaceType::Sensitive,SurfaceType::Measurement1D) ,inner_thick, outer_thick , u,v,n ) ; //,o ) ;
// // vector of sensor placements - needed for DetElements in ladder loop below
// std::vector<PlacedVolume> pvV( layer_geom.n_sensors_per_ladder ) ;
// //============================================================
#endif //code_is_cleaned_up
//=========================================================================================================
cout << "SCoil02 done.\n" << endl;
//######################################################################################################################################################################
//--------------------------------------
//coil.setVisAttributes( theDetector, x_det.visStr(), envelope );
//added coded by Thorben Quast
//the coil is modelled as a calorimeter layer to be consistent with the
//implementation of the solenoid (layers) of CLIC
LayeredCalorimeterData* coilData = new LayeredCalorimeterData;
//NN: Adding the rest of the data
coilData->inner_symmetry = 0;
coilData->outer_symmetry = 0;
coilData->layoutType = LayeredCalorimeterData::BarrelLayout ;
coilData->extent[0] = inner_radius ;
coilData->extent[1] = outer_radius;
coilData->extent[2] = 0. ;
coilData->extent[3] = half_z;
//NN: These probably need to be fixed and ced modified to read the extent, rather than the layer
LayeredCalorimeterData::Layer coilLayer;
coilLayer.distance = inner_radius;
coilLayer.inner_thickness = ( outer_radius - inner_radius ) / 2. ;
coilLayer.outer_thickness = coilLayer.inner_thickness ;
coilLayer.cellSize0 = 0; //equivalent to
coilLayer.cellSize1 = half_z; //half extension along z-axis
coilData->layers.push_back(coilLayer);
coil.addExtension< LayeredCalorimeterData >( coilData ) ;
return coil;
}
DECLARE_DETELEMENT(SCoil02,create_element)
......@@ -327,7 +327,13 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
PlacedVolume pv;
sens.setType("tracker");
if (x_det.hasChild(_U(sensitive))) {
xml_dim_t sd_typ = x_det.child(_U(sensitive));
sens.setType(sd_typ.typeStr());
}
else {
sens.setType("tracker");
}
// --- create assembly and DetElement for support and service volumes
......@@ -1016,7 +1022,11 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
petalSupport(theDetector, ftd, valuesDict, FTDPetalAirLogical ) ;
VolVec volV = petalSensor( theDetector, ftd, sens, valuesDict, FTDPetalAirLogical );
if (x_det.hasAttr(_U(limits))) {
for (auto vol : volV) {
vol.first.setLimitSet(theDetector, x_det.limitsStr());
}
}
//---- meassurement surface vectors
......@@ -1274,7 +1284,9 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
ftd.addExtension< ZDiskPetalsData >( zDiskPetalsData ) ;
//--------------------------------------
if ( x_det.hasAttr(_U(combineHits)) ) {
ftd.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens);
}
return ftd;
}
......
......@@ -327,7 +327,13 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
PlacedVolume pv;
sens.setType("tracker");
if (x_det.hasChild(_U(sensitive))) {
xml_dim_t sd_typ = x_det.child(_U(sensitive));
sens.setType(sd_typ.typeStr());
}
else {
sens.setType("tracker");
}
// --- create assembly and DetElement for support and service volumes
......@@ -563,6 +569,9 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
{
_dbParDisk.ZStartOuterCylinder = _z_position;
}
_dbParDisk.ZStopOuterCylinder = _zEnd;
_dbParDisk.ZStopInnerCylinder = _zEnd;
break;
case 7:
......@@ -1015,7 +1024,11 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
petalSupport(theDetector, ftd, valuesDict, FTDPetalAirLogical ) ;
VolVec volV = petalSensor( theDetector, ftd, sens, valuesDict, FTDPetalAirLogical );
if (x_det.hasAttr(_U(limits))) {
for (auto vol : volV) {
vol.first.setLimitSet(theDetector, x_det.limitsStr());
}
}
//---- meassurement surface vectors
......@@ -1273,7 +1286,9 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
ftd.addExtension< ZDiskPetalsData >( zDiskPetalsData ) ;
//--------------------------------------
if ( x_det.hasAttr(_U(combineHits)) ) {
ftd.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens);
}
return ftd;
}
......
......@@ -77,9 +77,13 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
//PlacedVolume pv;
sens.setType("tracker");
if (x_det.hasChild(_U(sensitive))) {
xml_dim_t sd_typ = x_det.child(_U(sensitive));
sens.setType(sd_typ.typeStr());
}
else {
sens.setType("tracker");
}
dd4hep::rec::ZPlanarData* zPlanarData = new ZPlanarData ;
......@@ -297,7 +301,7 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
dd4hep::Volume setSenLogical( dd4hep:: _toString( layer_id,"SET_SenLogical_%02d"), setSenSolid,sensitiveMat ) ;
setSenLogical.setSensitiveDetector(sens);
if (x_det.hasAttr(_U(limits))) setSenLogical.setLimitSet(theDetector, x_det.limitsStr());
//====== create the meassurement surface ===================
......@@ -456,6 +460,10 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
set.setVisAttributes( theDetector, x_det.visStr(), envelope );
if ( x_det.hasAttr(_U(combineHits)) ) {
set.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens);
}
return set;
}
......
......@@ -84,9 +84,13 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
dd4hep::PlacedVolume pv;
sens.setType("tracker");
if (x_det.hasChild(_U(sensitive))) {
xml_dim_t sd_typ = x_det.child(_U(sensitive));
sens.setType(sd_typ.typeStr());
}
else {
sens.setType("tracker");
}
dd4hep::rec::ZPlanarData* zPlanarData = new dd4hep::rec::ZPlanarData ;
......@@ -126,7 +130,11 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
dd4hep::Material sensitiveMat = theDetector.material(db->fetchString("sensitive_mat"));
dd4hep::Material supportMat = theDetector.material(db->fetchString("support_mat"));
db = XMLHandlerDB( x_det.child( _Unicode( display ) ) ) ;
std::string ladderVis = db->fetchString("ladder");
std::string supportVis = db->fetchString("support");
std::string sensEnvVis = db->fetchString("sens_env");
std::string sensVis = db->fetchString("sens");
// // // setup the encoder
// // UTIL::BitField64 encoder( LCTrackerCellID::encoding_string() ) ;
......@@ -286,7 +294,7 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
layer_geom.ladder_width / 2.0,
layer_geom.half_z);
dd4hep::Volume sitLadderLogical( dd4hep::_toString( layer_id,"SIT_LadderLogical_%02d"), sitLadderSolid, air ) ;
dd4hep::Volume sitLadderLogical( name + dd4hep::_toString( layer_id,"_LadderLogical_%02d"), sitLadderSolid, air ) ;
// now create an envelope volume to represent the sensitive area, which will be divided up into individual sensors
......@@ -295,7 +303,7 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
layer_geom.half_z);
//fixme: material ??? Volume sitSenEnvelopeLogical( _toString( layer_id,"SIT_SenEnvelopeLogical_%02d"), sitSenEnvelopeSolid, sensitiveMat ) ;
dd4hep::Volume sitSenEnvelopeLogical( dd4hep::_toString( layer_id,"SIT_SenEnvelopeLogical_%02d"),
dd4hep::Volume sitSenEnvelopeLogical( name + dd4hep::_toString( layer_id,"_SenEnvelopeLogical_%02d"),
sitSenEnvelopeSolid, air ) ;
// create the sensor volumes and place them in the senstive envelope volume
......@@ -304,10 +312,10 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
layer_geom.ladder_width / 2.0,
(layer_geom.sensor_length / 2.0 ) - 1.e-06 * dd4hep::mm ); // added tolerance to avoid false overlap detection
dd4hep::Volume sitSenLogical( dd4hep::_toString( layer_id,"SIT_SenLogical_%02d"), sitSenSolid,sensitiveMat ) ;
dd4hep::Volume sitSenLogical( name + dd4hep::_toString( layer_id,"_SenLogical_%02d"), sitSenSolid,sensitiveMat ) ;
sitSenLogical.setSensitiveDetector(sens);
if (x_det.hasAttr(_U(limits))) sitSenLogical.setLimitSet(theDetector, x_det.limitsStr());
//====== create the meassurement surface ===================
dd4hep::rec::Vector3D u,v,n ;
......@@ -371,10 +379,10 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
pvV[isensor] = pv ;
}
sit.setVisAttributes(theDetector, "SeeThrough", sitLadderLogical ) ;
sit.setVisAttributes(theDetector, "SeeThrough", sitSenEnvelopeLogical ) ;
sit.setVisAttributes(theDetector, ladderVis, sitLadderLogical ) ;
sit.setVisAttributes(theDetector, sensEnvVis, sitSenEnvelopeLogical ) ;
sit.setVisAttributes(theDetector, "BlueVis", sitSenLogical ) ;
sit.setVisAttributes(theDetector, sensVis, sitSenLogical ) ;
// encoder.reset() ; // reset to 0
......@@ -398,10 +406,10 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
layer_geom.ladder_width / 2.0,
layer_geom.half_z);
Volume sitSupLogical( _toString( layer_id,"SIT_SupLogical_%02d"), sitSupSolid, supportMat ) ;
Volume sitSupLogical( name + _toString( layer_id,"_SupLogical_%02d"), sitSupSolid, supportMat ) ;
sit.setVisAttributes(theDetector, "RedVis", sitSupLogical ) ;
sit.setVisAttributes(theDetector, supportVis, sitSupLogical ) ;
pv = sitLadderLogical.placeVolume( sitSupLogical, Transform3D( RotationY( 0.),
......@@ -472,6 +480,10 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
//--------------------------------------
sit.setVisAttributes( theDetector, x_det.visStr(), envelope );
if ( x_det.hasAttr(_U(combineHits)) ) {
sit.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens);
}
return sit;
}
......
......@@ -84,9 +84,13 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
dd4hep::PlacedVolume pv;
sens.setType("tracker");
if (x_det.hasChild(_U(sensitive))) {
xml_dim_t sd_typ = x_det.child(_U(sensitive));
sens.setType(sd_typ.typeStr());
}
else {
sens.setType("tracker");
}
dd4hep::rec::ZPlanarData* zPlanarData = new dd4hep::rec::ZPlanarData ;
......@@ -307,7 +311,7 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
dd4hep::Volume sitSenLogical( dd4hep::_toString( layer_id,"SIT_SenLogical_%02d"), sitSenSolid,sensitiveMat ) ;
sitSenLogical.setSensitiveDetector(sens);
if (x_det.hasAttr(_U(limits))) sitSenLogical.setLimitSet(theDetector, x_det.limitsStr());
//====== create the meassurement surface ===================
dd4hep::rec::Vector3D u,v,n ;
......@@ -473,6 +477,10 @@ static dd4hep::Ref_t create_element(dd4hep::Detector& theDetector, xml_h e, dd4h
//--------------------------------------
sit.setVisAttributes( theDetector, x_det.visStr(), envelope );
if ( x_det.hasAttr(_U(combineHits)) ) {
sit.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens);
}
return sit;
}
......
......@@ -26,7 +26,7 @@ using dd4hep::rec::SurfaceType;
using dd4hep::rec::volSurfaceList;
using dd4hep::rec::VolPlane;
using dd4hep::rec::FixedPadSizeTPCData;
using dd4hep::rec::ConicalSupportData;
/** Construction of TPC detector, ported from Mokka driver TPC10.cc
* Mokka History:
* - modified version of TPC driver by Ties Behnke
......@@ -68,7 +68,13 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
PlacedVolume pv;
sens.setType("tracker");
if (x_det.hasChild(_U(sensitive))) {
xml_dim_t sd_typ = x_det.child(_U(sensitive));
sens.setType(sd_typ.typeStr());
}
else {
sens.setType("tracker");
}
std::cout << " ** building TPC10_geo in lcgeo " << lcgeo::versionString() << std::endl ;
......@@ -476,7 +482,10 @@ Material endplate_MaterialMix = theDetector.material( "TPC_endplate_mix" ) ;
lowerlayerLog.setSensitiveDetector(sens);
upperlayerLog.setSensitiveDetector(sens);
if (x_det.hasAttr(_U(limits))) {
lowerlayerLog.setLimitSet(theDetector, x_det.limitsStr());
upperlayerLog.setLimitSet(theDetector, x_det.limitsStr());
}
#else
// create just one volume per pad ring
......@@ -506,7 +515,9 @@ Material endplate_MaterialMix = theDetector.material( "TPC_endplate_mix" ) ;
layerDEbwd.setPlacement( pv ) ;
layerLog.setSensitiveDetector(sens);
if (x_det.hasAttr(_U(limits))) {
layerLog.setLimitSet(theDetector, x_det.limitsStr());
}
#endif
}
......@@ -620,9 +631,27 @@ Material endplate_MaterialMix = theDetector.material( "TPC_endplate_mix" ) ;
tpcData->driftLength = dz_Sensitive + dz_Cathode/2.0; // SJA: cathode has to be added as the sensitive region does not start at 0.00
tpcData->zMinReadout = dz_Cathode/2.0;
// tpcData.z_anode = dzTotal - dz_Endplate; // the edge of the readout terminating the drift volume
tpc.addExtension< FixedPadSizeTPCData >( tpcData ) ;
ConicalSupportData* supportData = new ConicalSupportData;
ConicalSupportData::Section section0;
section0.rInner = rMin_GasVolume;
section0.rOuter = rMax_GasVolume;
section0.zPos = dz_GasVolume - dz_Readout;
ConicalSupportData::Section section1;
section1.rInner = rMin_GasVolume;
section1.rOuter = rMax_GasVolume;
section1.zPos = dz_GasVolume;
ConicalSupportData::Section section2;
section2.rInner = rInner;
section2.rOuter = rOuter;
section2.zPos = dz_GasVolume + dz_Endplate;
supportData->sections.push_back(section0);
supportData->sections.push_back(section1);
supportData->sections.push_back(section2);
tpc.addExtension< FixedPadSizeTPCData >( tpcData ) ;
tpc.addExtension< ConicalSupportData > (supportData);
//######################################################################################################################################################################
......
......@@ -74,7 +74,13 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
//-----------------------------------------------------------------------------------
sens.setType("tracker");
if (x_det.hasChild(_U(sensitive))) {
xml_dim_t sd_typ = x_det.child(_U(sensitive));
sens.setType(sd_typ.typeStr());
}
else {
sens.setType("tracker");
}
// --- create assembly and DetElement for support and service volumes
......@@ -1071,7 +1077,7 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
vxd.setVisAttributes(theDetector, "BlueVis" , SiActiveLayerLogical ) ;
SiActiveLayerLogical.setSensitiveDetector(sens);
if (x_det.hasAttr(_U(limits))) SiActiveLayerLogical.setLimitSet(theDetector, x_det.limitsStr());
//====== create the meassurement surface ===================
Vector3D u( 1. , 0. , 0. ) ;
......@@ -1582,10 +1588,12 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se
//--------------------------------------
vxd.setVisAttributes( theDetector, x_det.visStr(), envelope );
if ( x_det.hasAttr(_U(combineHits)) ) {
vxd.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens);
}
return vxd;
}
DECLARE_DETELEMENT(VXD04,create_element)