From 1bb6957ca38bc4d82f5fa4f96448021b53cf8a22 Mon Sep 17 00:00:00 2001 From: Chengdong Fu <fucd@ihep.ac.cn> Date: Fri, 22 Apr 2022 16:50:05 +0800 Subject: [PATCH] add AHcal module --- Detector/DetCEPCv4/CMakeLists.txt | 8 +- .../src/calorimeter/SHcalSc04_Barrel_v04.cpp | 723 ++++++++++++++++++ .../src/calorimeter/SHcalSc04_Endcaps_v01.cpp | 498 ++++++++++++ .../SHcalSc04_Barrel_v04_01.xml | 71 ++ .../SHcalSc04_Endcaps_v01_01.xml | 90 +++ .../Standalone/Standalone-SHcalSc04.xml | 51 ++ 6 files changed, 1438 insertions(+), 3 deletions(-) create mode 100644 Detector/DetCEPCv4/src/calorimeter/SHcalSc04_Barrel_v04.cpp create mode 100644 Detector/DetCEPCv4/src/calorimeter/SHcalSc04_Endcaps_v01.cpp create mode 100644 Detector/DetCRD/compact/CRD_common_v01/SHcalSc04_Barrel_v04_01.xml create mode 100644 Detector/DetCRD/compact/CRD_common_v01/SHcalSc04_Endcaps_v01_01.xml create mode 100644 Detector/DetCRD/compact/Standalone/Standalone-SHcalSc04.xml diff --git a/Detector/DetCEPCv4/CMakeLists.txt b/Detector/DetCEPCv4/CMakeLists.txt index 19046a69..03b897ae 100644 --- a/Detector/DetCEPCv4/CMakeLists.txt +++ b/Detector/DetCEPCv4/CMakeLists.txt @@ -32,11 +32,13 @@ gaudi_add_module(DetCEPCv4 src/calorimeter/SHcalRpc02_Barrel.cpp src/calorimeter/SHcalRpc01_Endcaps.cpp src/calorimeter/SHcalRpc01_EndcapRing.cpp - src/calorimeter/Yoke05_Barrel.cpp - src/calorimeter/Yoke05_Endcaps.cpp + src/calorimeter/SHcalSc04_Barrel_v04.cpp + src/calorimeter/SHcalSc04_Endcaps_v01.cpp + src/calorimeter/Yoke05_Barrel.cpp + src/calorimeter/Yoke05_Endcaps.cpp src/other/BoxSupport_o1_v01_geo.cpp src/other/TubeSupport_o1_v01_geo.cpp - src/other/SCoil02_geo.cpp + src/other/SCoil02_geo.cpp LINK ${DD4hep_COMPONENT_LIBRARIES} ) diff --git a/Detector/DetCEPCv4/src/calorimeter/SHcalSc04_Barrel_v04.cpp b/Detector/DetCEPCv4/src/calorimeter/SHcalSc04_Barrel_v04.cpp new file mode 100644 index 00000000..334af303 --- /dev/null +++ b/Detector/DetCEPCv4/src/calorimeter/SHcalSc04_Barrel_v04.cpp @@ -0,0 +1,723 @@ +//==================================================================== +// 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::BUILD_ENVELOPE; +using dd4hep::Box; +using dd4hep::DetElement; +using dd4hep::Detector; +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::_toString; + +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){ + + bool Error = false; + bool Warning = false; + double spaceAllowed = rOuter*cos(M_PI/16.) - 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_v01", " Layer number is more than it can be built! " ) ; + Error = true; + } + else if ( spaceToleranted < spaceAllowed ) + { + printout( dd4hep::WARNING, "SHcalSc04_Barrel_v01", " Layer number is less than it is able to build!" ) ; + Warning = true; + } + else + { + printout( dd4hep::DEBUG, "SHcalSc04_Barrel_v01"," 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(); + 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_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"); + + double TPC_outer_radius = theDetector.constant<double>("TPC_outer_radius"); + + double Ecal_outer_radius = theDetector.constant<double>("Ecal_outer_radius"); + + printout( dd4hep::DEBUG, "SHcalSc04_Barrel_v04", "TPC_outer_radius : %e - Ecal_outer_radius: %e ", TPC_outer_radius , Ecal_outer_radius) ; + + validateEnvelope(Hcal_inner_radius, Hcal_outer_radius, Hcal_radiator_thickness, Hcal_chamber_thickness, Hcal_nlayers); + + Readout readout = sens.readout(); + dd4hep::Segmentation seg = readout.segmentation(); + + dd4hep::DDSegmentation::BitField64 encoder = seg.decoder(); + encoder.setValue(0) ; + + + //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 : + + dd4hep::DDSegmentation::MultiSegmentation* multiSeg = + dynamic_cast< dd4hep::DDSegmentation::MultiSegmentation*>( seg.segmentation() ) ; + + dd4hep::DDSegmentation::TiledLayerGridXY* tileSeg = 0 ; + + 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_Barrel: Error: MultiSegmentation specified but no " + " <subsegmentation key="" value=""/> element defined for detector ! " ) ; + } + + // check if we have a TiledLayerGridXY segmentation : + const dd4hep::DDSegmentation::TiledLayerGridXY* ts0 = + dynamic_cast<const dd4hep::DDSegmentation::TiledLayerGridXY*>( &multiSeg->subsegmentation( encoder.getValue() ) ) ; + + tileSeg = const_cast<dd4hep::DDSegmentation::TiledLayerGridXY*>( ts0 ) ; + + if( ! tileSeg ){ // if the current segmentation is not a tileSeg, we see if there is another one + + for( auto s : multiSeg->subSegmentations() ){ + const dd4hep::DDSegmentation::TiledLayerGridXY* ts = + dynamic_cast<const dd4hep::DDSegmentation::TiledLayerGridXY*>( s.segmentation ) ; + + if( ts ) { + tileSeg = const_cast<dd4hep::DDSegmentation::TiledLayerGridXY*>( ts ) ; + break ; + } + } + } + + } else { + + tileSeg = + dynamic_cast< dd4hep::DDSegmentation::TiledLayerGridXY*>( seg.segmentation() ) ; + } + + + + std::vector<double> cellSizeVector = seg.cellDimensions( encoder.getValue() ); //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 = 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_stave_gaps; + double Hcal_normal_dim_z = (2 * Hcal_half_length - Hcal_modules_gap)/2.; + + //only the middle has the steel plate. + double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z - Hcal_lateral_plate_thickness; + + //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. +// ========================================================================== + + double chambers_y_off_correction = 0.; + + // stave modules shaper parameters + double BHX = (Hcal_bottom_dim_x + 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.; + + 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_det.regionStr(),x_det.limitsStr(),x_det.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_length; //dimension of an Hcal barrel layer on the x-axis + double y_height; //dimension of an Hcal barrel layer on the y-axis + double z_width; //dimension of an Hcal barrel layer on the z-axis + x_length = 0.; // Each Layer the x_length has new value. + y_height = Hcal_chamber_thickness / 2.; + z_width = Hcal_regular_chamber_dim_z/2.; + + double xOffset = 0.;//the x_length 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 + + + //-------------------- start loop over HCAL layers ---------------------- + + for (int layer_id = 1; layer_id <= (2*Hcal_nlayers); layer_id++) + { + + double TanPiDiv8 = tan(M_PI/Hcal_inner_symmetry); + double x_total = 0.; + double x_halfLength; + x_length = 0.; + + int logical_layer_id = 0; + + if ( (layer_id < Hcal_nlayers) + || (layer_id > Hcal_nlayers && layer_id < (2*Hcal_nlayers)) ) + logical_layer_id = layer_id % Hcal_nlayers; + else if ( (layer_id == Hcal_nlayers) + || (layer_id == 2*Hcal_nlayers) ) logical_layer_id = Hcal_nlayers; + + //---- bottom barrel------------------------------------------------------------ + if( logical_layer_id *(Hcal_radiator_thickness + Hcal_chamber_thickness) + < (Hcal_outer_radius * cos(M_PI/Hcal_inner_symmetry) - Hcal_inner_radius ) ) { + xOffset = (logical_layer_id * Hcal_radiator_thickness + + (logical_layer_id -1) * Hcal_chamber_thickness) * TanPiDiv8; + + x_total = Hcal_bottom_dim_x/2 - Hcal_middle_stave_gaps/2 + xOffset; + x_length = x_total - 2*Hcal_layer_air_gap; + x_halfLength = x_length/2.; + + } else {//----- top barrel ------------------------------------------------- + double y_layerID = logical_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_length = x_total - Hcal_middle_stave_gaps; + + x_halfLength = x_length/2.; + + xOffset = (logical_layer_id * Hcal_radiator_thickness + + (logical_layer_id - 1) * Hcal_chamber_thickness - Hcal_y_dim1_for_x) / TanPiDiv8 + + Hcal_chamber_thickness / TanPiDiv8; + + } + + double xAbsShift = (Hcal_middle_stave_gaps/2 + Hcal_layer_air_gap + x_halfLength); + + if (layer_id <= Hcal_nlayers) xShift = - xAbsShift; + else if (layer_id > Hcal_nlayers) xShift = xAbsShift; + + x_length = x_length/2.; + + + //calculate the size of a fractional tile + //-> this sets fract_cell_dim_x + + //double fract_cell_dim_x = 0.; + //this->CalculateFractTileSize(2*x_length, Hcal_cell_dim_x, fract_cell_dim_x); + + //Vector newFractCellDim(fract_cell_dim_x, Hcal_chamber_thickness, Hcal_cell_dim_z); + //theBarrilRegSD->SetFractCellDimPerLayer(layer_id, newFractCellDim); + + encoder["layer"] = logical_layer_id ; + cellSizeVector = seg.segmentation()->cellDimensions( encoder.getValue() ); + cell_sizeX = cellSizeVector[0]; + cell_sizeY = cellSizeVector[1]; + + LayeredCalorimeterData::Layer caloLayer ; + caloLayer.cellSize0 = cell_sizeX; + caloLayer.cellSize1 = cell_sizeY; + + + //-------------------------------------------------------------------------------- + // 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_length*2., z_width*2. , y_height*2. ); + + //check if x_length (scintillator length) is divisible with x_integerTileSize + if( layer_id <= Hcal_nlayers) { + double fracPart, intPart; + double temp = x_length*2./cell_sizeX; + fracPart = modf(temp, &intPart); + int noOfIntCells = int(temp); + + + if( tileSeg !=0 ){ + + tileSeg->setBoundaryLayerX(x_length); + + if (fracPart == 0){ //divisible + if ( noOfIntCells%2 ) { + if( tileSeg !=0 ) tileSeg->setLayerOffsetX(0); + } + else { + if( tileSeg !=0 ) tileSeg->setLayerOffsetX(1); + } + tileSeg->setFractCellSizeXPerLayer(0); + } + else if (fracPart>0){ + if ( noOfIntCells%2 ) { + if( tileSeg !=0 ) tileSeg->setLayerOffsetX(1); + } + else { + if( tileSeg !=0 ) tileSeg->setLayerOffsetX(0); + } + tileSeg->setFractCellSizeXPerLayer( (fracPart+1.0)/2.0*cell_sizeX ); + } + + if ( (int)( (z_width*2.) / cell_sizeX)%2 ){ + if( tileSeg !=0 ) tileSeg->setLayerOffsetY(0); + } + else { + if( tileSeg !=0 ) tileSeg->setLayerOffsetY(1); + } + + } + } + Box ChamberSolid((x_length + Hcal_layer_air_gap), //x + air gaps at two side, do not need to build air gaps individualy. + z_width, //z attention! + y_height); //y attention! + + string ChamberLogical_name = det_name+_toString(layer_id,"_layer%d"); + + Volume ChamberLogical(ChamberLogical_name, ChamberSolid, air); + + + + double layer_thickness = y_height*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_length,z_width,slice_thickness/2.),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 = ChamberLogical.placeVolume(slice_vol,Position(0.,0.,slice_pos_z)); + + slice_phv.addPhysVolID("layer",logical_layer_id).addPhysVolID("slice", slice_number ); + + + if ( x_slice.isSensitive() ) { + int tower_id = (layer_id > Hcal_nlayers)? 1:-1; + slice_phv.addPhysVolID("tower",tower_id); + printout( dd4hep::DEBUG, "SHcalSc04_Barrel_v04", " logical_layer_id: %d tower_id: %d", logical_layer_id, tower_id ) ; + } + + slice.setPlacement(slice_phv); + // Increment x 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. + + (logical_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 + chambers_y_off_correction)); + + + + //----------------------------------------------------------------------------------------- + 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 + chambers_y_off_correction) + - 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; + + if( tileSeg !=0 ){ + // check the offsets directly in the TileSeg ... + std::vector<double> LOX = tileSeg->layerOffsetX(); + std::vector<double> LOY = tileSeg->layerOffsetY(); + + std::stringstream sts ; + sts <<" layerOffsetX(): "; + for (std::vector<double>::const_iterator ix = LOX.begin(); ix != LOX.end(); ++ix) + sts << *ix << ' '; + printout( dd4hep::DEBUG, "SHcalSc04_Barrel_v04", "%s" , sts.str().c_str() ) ; + sts.clear() ; sts.str("") ; + sts <<" layerOffsetY(): "; + for (std::vector<double>::const_iterator iy = LOY.begin(); iy != LOY.end(); ++iy) + sts << *iy << ' '; + printout( dd4hep::DEBUG, "SHcalSc04_Barrel_v04", "%s" , sts.str().c_str() ) ; + + } + + + +//==================================================================== +// Place HCAL Barrel stave module into the envelope +//==================================================================== + double stave_phi_offset, module_z_offset, lateral_plate_z_offset; + + 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++) + { + module_z_offset = - (Hcal_normal_dim_z + Hcal_modules_gap + Hcal_lateral_plate_thickness)/2.; + lateral_plate_z_offset = - (Hcal_lateral_plate_thickness + Hcal_modules_gap)/2.; + + 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; + 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) diff --git a/Detector/DetCEPCv4/src/calorimeter/SHcalSc04_Endcaps_v01.cpp b/Detector/DetCEPCv4/src/calorimeter/SHcalSc04_Endcaps_v01.cpp new file mode 100644 index 00000000..4b074089 --- /dev/null +++ b/Detector/DetCEPCv4/src/calorimeter/SHcalSc04_Endcaps_v01.cpp @@ -0,0 +1,498 @@ +//==================================================================== +// 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) diff --git a/Detector/DetCRD/compact/CRD_common_v01/SHcalSc04_Barrel_v04_01.xml b/Detector/DetCRD/compact/CRD_common_v01/SHcalSc04_Barrel_v04_01.xml new file mode 100644 index 00000000..32810ce1 --- /dev/null +++ b/Detector/DetCRD/compact/CRD_common_v01/SHcalSc04_Barrel_v04_01.xml @@ -0,0 +1,71 @@ +<!-- comment>Calorimeters</comment --> + +<lccdd> + <define> + <constant name="Hcal_cell_size" value="10*mm"/> + <constant name="Hcal_inner_radius" value="Hcal_barrel_inner_radius"/> + <constant name="Hcal_half_length" value="Hcal_barrel_half_length"/> + <constant name="Hcal_inner_symmetry" value="Hcal_barrel_symmetry"/> + <constant name="Hcal_nlayers" value="38"/> + <constant name="Hcal_radiator_thickness" value="20.0*mm"/> + <constant name="Hcal_chamber_thickness" value="6.5*mm"/> + <constant name="Hcal_back_plate_thickness" value="15*mm"/> + <constant name="Hcal_lateral_structure_thickness" value="10*mm"/> + <constant name="Hcal_stave_gaps" value="0*mm"/> + <constant name="Hcal_middle_stave_gaps" value="0*mm"/> + <constant name="Hcal_modules_gap" value="2*mm"/> + <constant name="Hcal_layer_air_gap" value="0*mm"/> + <constant name="HcalSD_glass_anode_thickness" value="0.7*mm"/> + <constant name="HcalSD_sensitive_gas_gap" value="1.2*mm"/> + <constant name="HcalSD_glass_cathode_thickness" value="1.1*mm"/> + <constant name="Hcal_scintillator_thickness" value="3.0*mm"/> + <constant name="Ecal_outer_radius" value="Ecal_barrel_outer_radius"/> + <constant name="Hcal_readout_segmentation_slice" value="3"/> + </define> + <detectors> + <detector name="HcalBarrel" type="SHcalSc04_Barrel_v04" id="DetID_HCAL" readout="HcalBarrelCollection" vis="GreenVis" insideTrackingVolume="false" > + <comment>Hadron Calorimeter Barrel</comment> + + <envelope vis="ILD_HCALVis"> + <shape type="BooleanShape" operation="Subtraction" material="Air" > + <shape type="Cone" rmin1="0.0" rmax1="Hcal_outer_radius + env_safety" rmin2="0.0" rmax2="Hcal_outer_radius + env_safety" z="Hcal_half_length + env_safety/2.0"/> + <shape type="PolyhedraRegular" numsides="Hcal_inner_symmetry" rmin="0.0" + rmax="Hcal_inner_radius - env_safety" dz="2*(Hcal_half_length + env_safety)"/> + </shape> + <rotation x="0" y="0" z="90*deg-180*deg/Hcal_inner_symmetry"/> + </envelope> + + <type_flags type=" DetType_CALORIMETER + DetType_BARREL + DetType_HADRONIC " /> + + <staves material = "Steel235" vis="BlueVis"/> + + + <!-- select which subsegmentation will be used to fill the DDRec:LayeredCalorimeterData cell dimensions --> + <subsegmentation key="slice" value="Hcal_readout_segmentation_slice"/> + + <layer repeat="Hcal_nlayers" vis="SeeThrough"> + <slice material="FloatGlass" thickness="HcalSD_glass_anode_thickness" vis="Invisible"/> + <slice material="RPCGAS2" thickness="HcalSD_sensitive_gas_gap" sensitive="yes" limits="cal_limits" vis="YellowVis"/> + <slice material="FloatGlass" thickness="HcalSD_glass_cathode_thickness" vis="Invisible"/> + <slice material="G4_POLYSTYRENE" thickness = "Hcal_scintillator_thickness" sensitive = "yes" limits="cal_limits" vis="CyanVis" /> + <slice material="Air" thickness="Hcal_chamber_thickness - ( HcalSD_glass_anode_thickness + HcalSD_sensitive_gas_gap + HcalSD_glass_cathode_thickness + Hcal_scintillator_thickness)" vis="Invisible" /> + </layer> + </detector> + </detectors> + + <readouts> + <readout name="HcalBarrelCollection"> + <segmentation type="MultiSegmentation" key="slice"> + <segmentation name="RPCgrid" type="CartesianGridXY" key_value="1" grid_size_x="Hcal_cell_size" grid_size_y="Hcal_cell_size" /> + <segmentation name="Scigrid" type="TiledLayerGridXY" key_value="3" grid_size_x="3" grid_size_y="3.03248"/> + </segmentation> + <hits_collections> + <hits_collection name="HCalBarrelRPCHits" key="slice" key_value="1"/> + <hits_collection name="HcalBarrelRegCollection" key="slice" key_value="3"/> + </hits_collections> + <id>system:5,module:3,stave:4,tower:5,layer:6,slice:4,x:32:-16,y:-16</id> + </readout> + </readouts> + + +</lccdd> diff --git a/Detector/DetCRD/compact/CRD_common_v01/SHcalSc04_Endcaps_v01_01.xml b/Detector/DetCRD/compact/CRD_common_v01/SHcalSc04_Endcaps_v01_01.xml new file mode 100644 index 00000000..6b11b773 --- /dev/null +++ b/Detector/DetCRD/compact/CRD_common_v01/SHcalSc04_Endcaps_v01_01.xml @@ -0,0 +1,90 @@ +<lccdd> + <define> + <constant name="SDHCal_cell_size" value="10*mm"/> + <constant name="AHCal_cell_size" value="10*mm"/> + <constant name="Hcal_endcap_lateral_structure_thickness" value="5.0*mm"/> + <constant name="Hcal_endcap_layer_air_gap" value="2.5*mm"/> + <constant name="Hcal_steel_cassette_thickness" value="0.5*mm"/> + <constant name="Hcal_services_outer_FR4_thickness" value="2.8*mm"/> + <constant name="Hcal_services_outer_Cu_thickness" value="0.4*mm"/> + <constant name="Hcal_endcap_services_module_width" value="100.0*mm"/> + <constant name="Hcal_endcap_nlayers" value="40"/> + <constant name="Hcal_endcap_env_thickness" value="Hcal_endcap_zmax-Hcal_endcap_zmin"/> + <constant name="Hcal_x_modul" value="12"/> + <constant name="Hcal_x_width" value="Hcal_endcap_inner_radius*2/2"/><!--350--> + <constant name="Hcal_y_height" value="Hcal_x_width*Hcal_x_modul/2"/><!--2100--> + <constant name="Hcal_hole_height" value="Hcal_endcap_inner_radius"/> + <constant name="Hcal_r_max" value="Hcal_y_height/cos(pi/Hcal_endcap_symmetry)"/><!--2174.08--> + <constant name="Hcal_x_top" value="Hcal_y_height*tan(pi/Hcal_endcap_symmetry)"/> <!--562.69--> + <constant name="Hcal_x_point" value="(Hcal_y_height+Hcal_x_top*tan(2*pi/Hcal_endcap_symmetry))/(1+tan(2*pi/Hcal_endcap_symmetry))"/><!--1537.30--> + <constant name="Hcal_y5" value="Hcal_y_height-(Hcal_x_width*2-Hcal_x_top)*tan(2*pi/Hcal_endcap_symmetry)"/> + <constant name="Hcal_y4" value="Hcal_y5-Hcal_x_width*tan(2*pi/Hcal_endcap_symmetry)"/> + <constant name="Hcal_y3" value="Hcal_y4-Hcal_x_width*tan(2*pi/Hcal_endcap_symmetry)"/> + <constant name="Hcal_y2" value="Hcal_x_top+Hcal_x_width/tan(2*pi/Hcal_endcap_symmetry)"/> + + </define> + <detectors> + <detector id="DetID_HCAL_ENDCAP" name="HcalEndcap" type="SHcalSc04_Endcaps_v01" readout="HcalEndcapsReadout" vis="GreenVis" calorimeterType="HAD_ENDCAP"> + <comment>Hadron Calorimeter Endcap</comment> + + <envelope vis="ILD_HCALVis"> + <shape type="BooleanShape" operation="Subtraction" material="Air"><!--2. create center box hole --> + <shape type="BooleanShape" operation="Subtraction" material="Air"><!--1. create Endcaps envelope --> + <shape type="Tube" rmin="0.0" rmax="Solenoid_inner_radius" dz="Hcal_endcap_zmax + env_safety"/> + <shape type="Tube" rmin="0.0" rmax="Solenoid_inner_radius" dz="Hcal_endcap_zmin - env_safety"/> + </shape> + <shape type="Box" dx="Hcal_endcap_inner_radius - env_safety" dy="Hcal_endcap_inner_radius - env_safety" + dz="Hcal_endcap_zmax + 2.0*env_safety"/> + </shape> + <rotation x="0" y="0" z="0"/> + </envelope> + + <type_flags type=" DetType_CALORIMETER + DetType_ENDCAP + DetType_HADRONIC " /> + + <material name="Steel235"/><!-- radiator and the thickness has been defined in the main xml file--> + + <dimensions numsides="Hcal_x_modul" > + <dimensions id="1" y_offset="Hcal_x_top/2" dim_x="Hcal_hole_height" dim_y="Hcal_x_top" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="2" y_offset="Hcal_y2/2" dim_x="Hcal_hole_height" dim_y="Hcal_y2" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="3" y_offset="Hcal_y3/2" dim_x="Hcal_hole_height" dim_y="Hcal_y3" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="4" y_offset="Hcal_y4/2" dim_x="Hcal_hole_height" dim_y="Hcal_y4" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="5" y_offset="Hcal_y5/2" dim_x="Hcal_hole_height" dim_y="Hcal_y5" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="6" y_offset="Hcal_y_height/2+Hcal_hole_height/2" dim_x="Hcal_hole_height" dim_y="Hcal_y_height-Hcal_hole_height" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="7" y_offset="Hcal_y_height/2+Hcal_hole_height/2" dim_x="Hcal_hole_height" dim_y="Hcal_y_height-Hcal_hole_height" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="8" y_offset="Hcal_y5/2" dim_x="Hcal_hole_height" dim_y="Hcal_y5" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="9" y_offset="Hcal_y4/2" dim_x="Hcal_hole_height" dim_y="Hcal_y4" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="10" y_offset="Hcal_y3/2" dim_x="Hcal_hole_height" dim_y="Hcal_y3" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="11" y_offset="Hcal_y2/2" dim_x="Hcal_hole_height" dim_y="Hcal_y2" dim_z="Hcal_endcap_env_thickness"/> + <dimensions id="12" y_offset="Hcal_x_top/2" dim_x="Hcal_hole_height" dim_y="Hcal_x_top" dim_z="Hcal_endcap_env_thickness"/> + </dimensions> + + <!-- select which subsegmentation will be used to fill the DDRec:LayeredCalorimeterData cell dimensions --> + <subsegmentation key="slice" value="Hcal_readout_segmentation_slice"/> + + <layer repeat="Hcal_endcap_nlayers" vis="SeeThrough"> + <slice material="FloatGlass" thickness="HcalSD_glass_anode_thickness" vis="Invisible"/> + <slice material="RPCGAS2" thickness="HcalSD_sensitive_gas_gap" sensitive="yes" limits="cal_limits" vis="YellowVis"/> + <slice material="FloatGlass" thickness="HcalSD_glass_cathode_thickness" vis="Invisible"/> + <slice material="G4_POLYSTYRENE" thickness = "Hcal_scintillator_thickness" sensitive = "yes" limits="cal_limits" vis="CyanVis" /> + <slice material="Air" thickness="Hcal_chamber_thickness - ( HcalSD_glass_anode_thickness + HcalSD_sensitive_gas_gap + HcalSD_glass_cathode_thickness + Hcal_scintillator_thickness)" vis="Invisible" /> + </layer> + </detector> + </detectors> + + <readouts> + <readout name="HcalEndcapsReadout"> + <segmentation type="MultiSegmentation" key="slice"> + <segmentation name="RPCgrid" type="CartesianGridXY" key_value="1" grid_size_x="SDHCal_cell_size" grid_size_y="SDHCal_cell_size" offset_x="SDHCal_cell_size/2.0" offset_y="SDHCal_cell_size/2.0" /> + <segmentation name="Scigrid" type="CartesianGridXY" key_value="3" grid_size_x="AHCal_cell_size" grid_size_y="AHCal_cell_size" offset_x="AHCal_cell_size/2.0" offset_y="AHCal_cell_size/2.0" /> + </segmentation> + <hits_collections> + <hits_collection name="HCalEndcapRPCHits" key="slice" key_value="1"/> + <hits_collection name="HcalEndcapsCollection" key="slice" key_value="3"/> + </hits_collections> + <id>system:5,module:3,stave:3,tower:5,layer:6,slice:4,x:32:-16,y:-16</id> + </readout> + </readouts> + + +</lccdd> + diff --git a/Detector/DetCRD/compact/Standalone/Standalone-SHcalSc04.xml b/Detector/DetCRD/compact/Standalone/Standalone-SHcalSc04.xml new file mode 100644 index 00000000..42edeebe --- /dev/null +++ b/Detector/DetCRD/compact/Standalone/Standalone-SHcalSc04.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd"> + <info name="StandaloneEcalRotCrystal" + title="CepC standalone calorimeter with rotated crystal" + author="C.D.Fu" + url="http://cepc.ihep.ac.cn" + status="developing" + version="v01"> + <comment>CepC detector simulation models used for detector study </comment> + </info> + + <includes> + <gdmlFile ref="${DD4hepINSTALL}/DDDetectors/compact/elements.xml"/> + <gdmlFile ref="../CRD_common_v01/materials.xml"/> + </includes> + + <define> + <constant name="world_size" value="6*m"/> + <constant name="world_x" value="world_size"/> + <constant name="world_y" value="world_size"/> + <constant name="world_z" value="world_size"/> + + <include ref="${DD4hepINSTALL}/DDDetectors/compact/detector_types.xml"/> + </define> + + <include ref="./Dimensions_v01_01.xml"/> + + <!--include ref="../CRD_common_v01/Coil_Simple_v01_01.xml"/--> + <include ref="../CRD_common_v01/SHcalSc04_Barrel_v04_01.xml"/> + <include ref="../CRD_common_v01/SHcalSc04_Endcaps_v01_01.xml"/> + + <fields> + <field name="InnerSolenoid" type="solenoid" + inner_field="Field_nominal_value" + outer_field="0" + zmax="SolenoidCoil_half_length" + inner_radius="SolenoidCoil_center_radius" + outer_radius="Solenoid_outer_radius"> + </field> + <field name="OuterSolenoid" type="solenoid" + inner_field="0" + outer_field="Field_outer_nominal_value" + zmax="SolenoidCoil_half_length" + inner_radius="Solenoid_outer_radius" + outer_radius="Yoke_barrel_inner_radius"> + </field> + </fields> + +</lccdd> -- GitLab