static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) { xml_det_t x_det = element; string det_name = x_det.nameStr(); DetElement sdet( det_name,x_det.id() ); Layering layering(x_det); xml_dim_t dim = x_det.dimensions(); // --- 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 ; //----------------------------------------------------------------------------------- Material air = theDetector.air(); sens.setType("calorimeter"); //==================================================================== // // Read all the dimensions from compact.xml, user can update the value. // Use them to build a calo box prototye. // //==================================================================== double Calo_dim_x = dim.x(); double Calo_dim_y = dim.y(); double Calo_dim_z = dim.z(); printout( dd4hep::DEBUG, "building SamplingCaloBoxPrototype_v01", "Calo_dim_x : %e Calo_dim_y: %e Calo_dim_z: %e ", Calo_dim_x, Calo_dim_y, Calo_dim_z) ; //==================================================================== // // general calculated parameters // //==================================================================== //calorimeter dimensions double cal_hx = Calo_dim_x/2.0; double cal_hy = Calo_dim_y/2.0; double cal_hz = Calo_dim_z/2.0; //==================================================================== // // build sampling layers in the CaloBox // //==================================================================== int layer_num = 0; int layerType = 0; double layer_pos_z = - cal_hz; for (xml_coll_t c(x_det, _U(layer)); c; ++c) { xml_comp_t x_layer = c; int repeat = x_layer.repeat(); const Layer* lay = layering.layer(layer_num); double layer_thickness = lay->thickness(); string layer_type_name = _toString(layerType,"layerType%d"); // Loop over repeats for this layer. for (int j = 0; j < repeat; j++) { string layer_name = _toString(layer_num, "layer%d"); DetElement layer(layer_name, layer_num); // Layer box & volume Volume layer_vol(layer_type_name, Box(cal_hx, cal_hy, layer_thickness / 2), air); // Create the slices (sublayers) within the layer. 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 = _toString(slice_number, "slice%d"); double slice_thickness = x_slice.thickness(); Material slice_material = theDetector.material(x_slice.materialStr()); DetElement slice(layer, slice_name, slice_number); slice_pos_z += slice_thickness / 2; // Slice volume & box Volume slice_vol(slice_name, Box(cal_hx, cal_hy, slice_thickness / 2), slice_material); if (x_slice.isSensitive()) { sens.setType("calorimeter"); slice_vol.setSensitiveDetector(sens); } // 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; // Increment slice number. ++slice_number; } // Set region, limitset, and vis. layer_vol.setAttributes(theDetector, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr()); // Layer position in Z within the stave. layer_pos_z += layer_thickness / 2; // Layer physical volume. PlacedVolume layer_phv = envelope.placeVolume(layer_vol, Position(0, 0, layer_pos_z)); layer_phv.addPhysVolID("layer", layer_num); layer.setPlacement(layer_phv); // Increment the layer Z position. layer_pos_z += layer_thickness / 2; // Increment the layer number. ++layer_num; } ++layerType; } return sdet; }
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); Material air = theDetector.air(); //unused: Material vacuum = theDetector.vacuum(); int det_id = x_det.id(); xml_comp_t x_staves = x_det.staves(); DetElement sdet (det_name,det_id); xml_comp_t x_dim = x_det.dimensions(); int nsides = x_dim.numsides(); double dphi = (2*M_PI/nsides); double hphi = dphi/2; // --- 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"); Material stave_material = theDetector.material(x_staves.materialStr()); DetElement stave_det("module0stave0",det_id); Readout readout = sens.readout(); Segmentation seg = readout.segmentation(); // check if we have a WaferGridXY segmentation : WaferGridXY* waferSeg = dynamic_cast< WaferGridXY*>( seg.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]; //==================================================================== // // Read all the constant from ILD_o1_v05.xml // Use them to build HcalBarrel // //==================================================================== int N_FIBERS_W_STRUCTURE = 2; int N_FIBERS_ALVOULUS = 3; // read parametere from compact.xml file double Ecal_Alveolus_Air_Gap = theDetector.constant<double>("Ecal_Alveolus_Air_Gap"); double Ecal_Slab_shielding = theDetector.constant<double>("Ecal_Slab_shielding"); double Ecal_Slab_copper_thickness = theDetector.constant<double>("Ecal_Slab_copper_thickness"); double Ecal_Slab_PCB_thickness = theDetector.constant<double>("Ecal_Slab_PCB_thickness"); double Ecal_Slab_glue_gap = theDetector.constant<double>("Ecal_Slab_glue_gap"); double Ecal_Slab_ground_thickness = theDetector.constant<double>("Ecal_Slab_ground_thickness"); double Ecal_fiber_thickness = theDetector.constant<double>("Ecal_fiber_thickness"); double Ecal_Si_thickness = theDetector.constant<double>("Ecal_Si_thickness"); double Ecal_inner_radius = theDetector.constant<double>("TPC_outer_radius") +theDetector.constant<double>("Ecal_Tpc_gap"); double Ecal_radiator_thickness1 = theDetector.constant<double>("Ecal_radiator_layers_set1_thickness"); double Ecal_radiator_thickness2 = theDetector.constant<double>("Ecal_radiator_layers_set2_thickness"); double Ecal_radiator_thickness3 = theDetector.constant<double>("Ecal_radiator_layers_set3_thickness"); double Ecal_Barrel_halfZ = theDetector.constant<double>("Ecal_Barrel_halfZ"); double Ecal_support_thickness = theDetector.constant<double>("Ecal_support_thickness"); double Ecal_front_face_thickness = theDetector.constant<double>("Ecal_front_face_thickness"); double Ecal_lateral_face_thickness = theDetector.constant<double>("Ecal_lateral_face_thickness"); double Ecal_Slab_H_fiber_thickness = theDetector.constant<double>("Ecal_Slab_H_fiber_thickness"); double Ecal_Slab_Sc_PCB_thickness = theDetector.constant<double>("Ecal_Slab_Sc_PCB_thickness"); double Ecal_Sc_thickness = theDetector.constant<double>("Ecal_Sc_thickness"); double Ecal_Sc_reflector_thickness = theDetector.constant<double>("Ecal_Sc_reflector_thickness"); int Ecal_nlayers1 = theDetector.constant<int>("Ecal_nlayers1"); int Ecal_nlayers2 = theDetector.constant<int>("Ecal_nlayers2"); int Ecal_nlayers3 = theDetector.constant<int>("Ecal_nlayers3"); int Ecal_barrel_number_of_towers = theDetector.constant<int>("Ecal_barrel_number_of_towers"); //double Ecal_cells_size = theDetector.constant<double>("Ecal_cells_size"); double Ecal_guard_ring_size = theDetector.constant<double>("Ecal_guard_ring_size"); //==================================================================== // // general calculated parameters // //==================================================================== double Ecal_total_SiSlab_thickness = Ecal_Slab_shielding + Ecal_Slab_copper_thickness + Ecal_Slab_PCB_thickness + Ecal_Slab_glue_gap + Ecal_Si_thickness + Ecal_Slab_ground_thickness + Ecal_Alveolus_Air_Gap / 2; #ifdef VERBOSE std::cout << " Ecal_total_SiSlab_thickness = " << Ecal_total_SiSlab_thickness << std::endl; #endif double Ecal_total_ScSlab_thickness = Ecal_Slab_shielding + Ecal_Slab_copper_thickness + Ecal_Slab_Sc_PCB_thickness + Ecal_Sc_thickness + Ecal_Sc_reflector_thickness * 2 + Ecal_Alveolus_Air_Gap / 2; #ifdef VERBOSE std::cout << " Ecal_total_ScSlab_thickness = " << Ecal_total_ScSlab_thickness << std::endl; #endif int Number_of_Si_Layers_in_Barrel = 0; int Number_of_Sc_Layers_in_Barrel = 0; #ifdef VERBOSE std::cout << " Ecal total number of Silicon layers = " << Number_of_Si_Layers_in_Barrel << std::endl; std::cout << " Ecal total number of Scintillator layers = " << Number_of_Sc_Layers_in_Barrel << std::endl; #endif // In this release the number of modules is fixed to 5 double Ecal_Barrel_module_dim_z = 2 * Ecal_Barrel_halfZ / 5. ; #ifdef VERBOSE std::cout << "Ecal_Barrel_module_dim_z = " << Ecal_Barrel_module_dim_z << std::endl; #endif // The alveolus size takes in account the module Z size // but also 4 fiber layers for the alveoulus wall, the all // divided by the number of towers double alveolus_dim_z = (Ecal_Barrel_module_dim_z - 2. * Ecal_lateral_face_thickness) / Ecal_barrel_number_of_towers - 2 * N_FIBERS_ALVOULUS * Ecal_fiber_thickness - 2 * Ecal_Slab_H_fiber_thickness - 2 * Ecal_Slab_shielding; #ifdef VERBOSE std::cout << "alveolus_dim_z = " << alveolus_dim_z << std::endl; #endif int n_total_layers = Ecal_nlayers1 + Ecal_nlayers2 + Ecal_nlayers3; Number_of_Si_Layers_in_Barrel = n_total_layers+1; double module_thickness = Ecal_nlayers1 * Ecal_radiator_thickness1 + Ecal_nlayers2 * Ecal_radiator_thickness2 + Ecal_nlayers3 * Ecal_radiator_thickness3 + int(n_total_layers/2) * // fiber around W struct layers (N_FIBERS_W_STRUCTURE * 2 * Ecal_fiber_thickness) + Number_of_Si_Layers_in_Barrel * // Silicon slabs plus fiber around and inside (Ecal_total_SiSlab_thickness + (N_FIBERS_ALVOULUS + 1 ) * Ecal_fiber_thickness) + Number_of_Sc_Layers_in_Barrel * // Scintillator slabs plus fiber around and inside (Ecal_total_ScSlab_thickness + (N_FIBERS_ALVOULUS + 1 ) * Ecal_fiber_thickness) + Ecal_support_thickness + Ecal_front_face_thickness; #ifdef VERBOSE std::cout << "For information : module_thickness = " << module_thickness << std::endl; #endif // module barrel key parameters double bottom_dim_x = 2. * tan(M_PI/8.) * Ecal_inner_radius + module_thickness/sin(M_PI/4.); double top_dim_x = bottom_dim_x - 2 * module_thickness; //------------------------------------------------------------------------------------ LayeredCalorimeterData::Layer caloLayer ; caloLayer.cellSize0 = cell_sizeX; caloLayer.cellSize1 = cell_sizeY; //== For Wafer === double cell_dim_x = caloLayer.cellSize0; double total_Si_dim_z = alveolus_dim_z; double util_SI_wafer_dim_z = total_Si_dim_z/2 - 2 * Ecal_guard_ring_size; double cell_dim_z = util_SI_wafer_dim_z/ floor(util_SI_wafer_dim_z/ cell_dim_x); int N_cells_in_Z = int(util_SI_wafer_dim_z/cell_dim_z); int N_cells_in_X = N_cells_in_Z; cell_dim_x = cell_dim_z; #ifdef VERBOSE std::cout << " bottom_dim_x = " << bottom_dim_x << std::endl; std::cout << " top_dim_x = " << top_dim_x << std::endl; std::cout << " Ecal total number of Silicon layers = " << Number_of_Si_Layers_in_Barrel << std::endl; std::cout << " Ecal total number of Scintillator layers = " << Number_of_Sc_Layers_in_Barrel << std::endl; #endif // ========= Create Ecal Barrel stave ==================================== // It will be the volume for palcing the Ecal Barrel alveolus(i.e. Layers). // And the structure W plate. // Itself will be placed into the world volume. // ========================================================================== // The TOP_X and BOTTOM_X is different in Mokka and DD4hep Trapezoid trd(top_dim_x / 2, bottom_dim_x / 2, Ecal_Barrel_module_dim_z / 2, Ecal_Barrel_module_dim_z / 2, module_thickness/2); // Volume mod_vol(det_name+"_module",trd,theDetector.material("g10")); Volume mod_vol(det_name+"_module",trd,theDetector.material("CarbonFiber")); // DJeans 5-sep-2016 // We count the layers starting from IP and from 1, // so odd layers should be inside slabs and // even ones on the structure. // The structure W layers are here big plans, as the // gap between each W plate is too small to create problems // The even W layers are part of H structure placed inside // the alveolus. // ############################ // Dimension of radiator wLog // slice provide the thickness // ############################ double y_floor = Ecal_front_face_thickness + N_FIBERS_ALVOULUS * Ecal_fiber_thickness; // ############################ // Dimension of alveolus // slice provide the thickness // ############################ // ===== build Si Slab and put into the Layer volume ===== // ===== place the layer into the module 5 time for one full layer into the trd module ==== // ===== build and place barrel structure into trd module ==== // Parameters for computing the layer X dimension: double stave_z =(Ecal_Barrel_module_dim_z - 2. * Ecal_lateral_face_thickness) / Ecal_barrel_number_of_towers/2.; double l_dim_x = bottom_dim_x/2.; // Starting X dimension for the layer. double l_pos_z = module_thickness/2; l_dim_x -= y_floor; l_pos_z -= y_floor; // ------------- create extension objects for reconstruction ----------------- //========== fill data for reconstruction ============================ LayeredCalorimeterData* caloData = new LayeredCalorimeterData ; caloData->layoutType = LayeredCalorimeterData::BarrelLayout ; caloData->inner_symmetry = nsides ; //added by Thorben Quast caloData->outer_symmetry = nsides ; caloData->phi0 = 0 ; // hardcoded /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm. caloData->extent[0] = Ecal_inner_radius ; //line fixed by Thorben Quast since actual conversion is made during the drawing caloData->extent[1] = ( Ecal_inner_radius + module_thickness ); //caloData->extent[1] = ( Ecal_inner_radius + module_thickness ) / cos( M_PI/8. ) ; caloData->extent[2] = 0. ; caloData->extent[3] = Ecal_Barrel_halfZ ; // // base vectors for surfaces: // dd4hep::rec::Vector3D u(1,0,0) ; // dd4hep::rec::Vector3D v(0,1,0) ; // dd4hep::rec::Vector3D n(0,0,1) ; //-------------------- start loop over ECAL layers ---------------------- // Loop over the sets of layer elements in the detector. double nRadiationLengths = 0. ; double nInteractionLengths = 0. ; double thickness_sum = 0. ; nRadiationLengths = Ecal_radiator_thickness1/(stave_material.radLength()) + y_floor/air.radLength(); nInteractionLengths = Ecal_radiator_thickness1/(stave_material.intLength()) + y_floor/air.intLength(); thickness_sum = Ecal_radiator_thickness1 + y_floor; int l_num = 1; bool isFirstSens = true; int myLayerNum = 0 ; 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 j=0; j<repeat; j++) { string l_name = _toString(l_num,"layer%d"); double l_thickness = layering.layer(l_num-1)->thickness(); // Layer's thickness. double xcut = (l_thickness); // X dimension for this layer. l_dim_x -= xcut; Box l_box(l_dim_x-tolerance,stave_z-tolerance,l_thickness/2.0-tolerance); Volume l_vol(det_name+"_"+l_name,l_box,air); l_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr())); //fg: need vector of DetElements for towers ! // DetElement layer(stave_det, l_name, det_id); std::vector< DetElement > layers( Ecal_barrel_number_of_towers ) ; // place layer 5 times in module. at same layer position (towers !) double l_pos_y = Ecal_Barrel_module_dim_z / 2. - ( Ecal_lateral_face_thickness + Ecal_fiber_thickness * N_FIBERS_ALVOULUS + Ecal_Slab_shielding + Ecal_Slab_H_fiber_thickness + alveolus_dim_z /2.); for (int i=0; i<Ecal_barrel_number_of_towers; i++){ // need four clone layers[i] = DetElement( stave_det, l_name+_toString(i,"tower%02d") , det_id ) ; Position l_pos(0,l_pos_y,l_pos_z-l_thickness/2.); // Position of the layer. PlacedVolume layer_phv = mod_vol.placeVolume(l_vol,l_pos); // layer_phv.addPhysVolID("layer", l_num); layer_phv.addPhysVolID("tower", i); layers[i].setPlacement(layer_phv); l_pos_y -= (alveolus_dim_z + 2. * Ecal_fiber_thickness * N_FIBERS_ALVOULUS + 2. * Ecal_Slab_H_fiber_thickness + 2. * Ecal_Slab_shielding); } // Loop over the sublayers or slices for this layer. int s_num = 1; double s_pos_z = l_thickness / 2.; //-------------------------------------------------------------------------------- // BuildBarrelAlveolus: BuildSiliconSlab: //-------------------------------------------------------------------------------- double radiator_dim_y = Ecal_radiator_thickness1; //to be updated with slice 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_thick = x_slice.thickness(); Material slice_material = theDetector.material(x_slice.materialStr()); #ifdef VERBOSE std::cout<<"Ecal_barrel_number_of_towers: "<< Ecal_barrel_number_of_towers <<std::endl; #endif double slab_dim_x = l_dim_x-tolerance; double slab_dim_y = s_thick/2.; double slab_dim_z = stave_z-tolerance; Box s_box(slab_dim_x,slab_dim_z,slab_dim_y); Volume s_vol(det_name+"_"+l_name+"_"+s_name,s_box,slice_material); //fg: not needed DetElement slice(layer,s_name,det_id); s_vol.setVisAttributes(theDetector.visAttributes(x_slice.visStr())); #ifdef VERBOSE std::cout<<"x_slice.materialStr(): "<< x_slice.materialStr() <<std::endl; #endif if (x_slice.materialStr().compare(x_staves.materialStr()) == 0){ radiator_dim_y = s_thick; // W StructureLayer has the same thickness as W radiator layer in the Alveolus layer #if DD4HEP_VERSION_GE( 0, 15 ) caloLayer.outer_nRadiationLengths = nRadiationLengths; caloLayer.outer_nInteractionLengths = nInteractionLengths; caloLayer.outer_thickness = thickness_sum; if (!isFirstSens){ caloData->layers.push_back( caloLayer ) ; #ifdef VERBOSE std::cout<<" caloLayer.distance: "<< caloLayer.distance <<std::endl; std::cout<<" caloLayer.inner_nRadiationLengths: "<< caloLayer.inner_nRadiationLengths <<std::endl; std::cout<<" caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl; std::cout<<" caloLayer.inner_thickness: "<< caloLayer.inner_thickness <<std::endl; std::cout<<" caloLayer.sensitive_thickness: "<< caloLayer.sensitive_thickness <<std::endl; std::cout<<" caloLayer.outer_nRadiationLengths: "<< caloLayer.outer_nRadiationLengths <<std::endl; std::cout<<" caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl; std::cout<<" caloLayer.outer_thickness: "<< caloLayer.outer_thickness <<std::endl; std::cout<<" EcalBarrel[1]==>caloLayer.inner_thickness + caloLayer.outer_thickness: " << caloLayer.inner_thickness + caloLayer.outer_thickness <<std::endl; #endif } #endif // Init for inner nRadiationLengths = 0. ; nInteractionLengths = 0. ; thickness_sum = 0. ; isFirstSens = false; } nRadiationLengths += s_thick/(2.*slice_material.radLength()); nInteractionLengths += s_thick/(2.*slice_material.intLength()); thickness_sum += s_thick/2.; if ( x_slice.isSensitive() ) { //s_vol.setSensitiveDetector(sens); // Normal squared wafers double wafer_dim_x = N_cells_in_X * cell_dim_x; double wafer_dim_z = N_cells_in_Z * cell_dim_z; Box WaferSiSolid( wafer_dim_x/2,wafer_dim_z/2,slab_dim_y); //Volume WaferSiLog(det_name+"_"+l_name+"_"+s_name+"Wafer",WaferSiSolid,slice_material); //WaferSiLog.setSensitiveDetector(sens); double real_wafer_size_x = wafer_dim_x + 2 * Ecal_guard_ring_size; int n_wafers_x = int(floor(slab_dim_x*2 / real_wafer_size_x)); double wafer_pos_x = -slab_dim_x + Ecal_guard_ring_size + wafer_dim_x /2 ; int n_wafer_x; int wafer_num = 0; for (n_wafer_x = 1; n_wafer_x < n_wafers_x + 1; n_wafer_x++) { double wafer_pos_z = -alveolus_dim_z/2.0 + Ecal_guard_ring_size + wafer_dim_z /2; for (int n_wafer_z = 1; n_wafer_z < 3; n_wafer_z++) { wafer_num++; string Wafer_name = _toString(wafer_num,"wafer%d"); Volume WaferSiLog(det_name+"_"+l_name+"_"+s_name+"_"+Wafer_name,WaferSiSolid,slice_material); WaferSiLog.setSensitiveDetector(sens); //WaferSiLog.setVisAttributes(theDetector.visAttributes(x_slice.visStr())); PlacedVolume wafer_phv = s_vol.placeVolume(WaferSiLog,Position(wafer_pos_x, wafer_pos_z, 0)); wafer_phv.addPhysVolID("wafer", wafer_num); // Normal squared wafers, this waferOffsetX is 0.0 waferSeg->setWaferOffsetX(myLayerNum, wafer_num, 0.0); wafer_pos_z += wafer_dim_z + 2 * Ecal_guard_ring_size; } wafer_pos_x += wafer_dim_x + 2 * Ecal_guard_ring_size; } // Magic wafers to complete the slab... // (wafers with variable number of cells just // to complete the slab. in reality we think that // we'll have just a few models of special wafers // for that. double resting_dim_x = slab_dim_x*2 - (wafer_dim_x + 2 * Ecal_guard_ring_size) * n_wafers_x; if(resting_dim_x > (cell_dim_x + 2 * Ecal_guard_ring_size)) { int N_cells_x_remaining = int(floor((resting_dim_x - 2 * Ecal_guard_ring_size) /cell_dim_x)); wafer_dim_x = N_cells_x_remaining * cell_dim_x; Box MagicWaferSiSolid( wafer_dim_x/2,wafer_dim_z/2,slab_dim_y); //Volume MagicWaferSiLog(det_name+"_"+l_name+"_"+s_name+"MagicWafer",MagicWaferSiSolid,slice_material); // Magic wafers, this waferOffsetX has to be taken care, 0.0 or half cell size in X. double thisWaferOffsetX = 0.0; if ( N_cells_x_remaining%2 ) thisWaferOffsetX = cell_dim_x/2.0; wafer_pos_x = -slab_dim_x + n_wafers_x * real_wafer_size_x + (wafer_dim_x + 2 * Ecal_guard_ring_size)/2; real_wafer_size_x = wafer_dim_x + 2 * Ecal_guard_ring_size; double wafer_pos_z = -alveolus_dim_z/2.0 + Ecal_guard_ring_size + wafer_dim_z /2; //int MagicWafer_num = 0; for (int n_wafer_z = 1; n_wafer_z < 3; n_wafer_z++) { wafer_num++; string MagicWafer_name = _toString(wafer_num,"MagicWafer%d"); Volume MagicWaferSiLog(det_name+"_"+l_name+"_"+s_name+"_"+MagicWafer_name,MagicWaferSiSolid,slice_material); MagicWaferSiLog.setSensitiveDetector(sens); //MagicWaferSiLog.setVisAttributes(theDetector.visAttributes(x_slice.visStr())); PlacedVolume wafer_phv = s_vol.placeVolume(MagicWaferSiLog,Position(wafer_pos_x, wafer_pos_z, 0)); wafer_phv.addPhysVolID("wafer", wafer_num); // Magic wafers, set the waferOffsetX for this layer this wafer. waferSeg->setWaferOffsetX(myLayerNum, wafer_num, thisWaferOffsetX); wafer_pos_z += wafer_dim_z + 2 * Ecal_guard_ring_size; } } #if DD4HEP_VERSION_GE( 0, 15 ) //Store "inner" quantities caloLayer.inner_nRadiationLengths = nRadiationLengths ; caloLayer.inner_nInteractionLengths = nInteractionLengths ; caloLayer.inner_thickness = thickness_sum ; //Store sensitive slice thickness caloLayer.sensitive_thickness = s_thick ; #ifdef VERBOSE std::cout<<" l_num: "<<l_num <<std::endl; std::cout<<" s_num: "<<s_num <<std::endl; std::cout<<" Ecal_inner_radius: "<< Ecal_inner_radius <<std::endl; std::cout<<" module_thickness: "<< module_thickness <<std::endl; std::cout<<" l_pos_z: "<< l_pos_z <<std::endl; std::cout<<" l_thickness: "<< l_thickness <<std::endl; std::cout<<" s_pos_z: "<< s_pos_z <<std::endl; std::cout<<" s_thick: "<< s_thick <<std::endl; std::cout<<" radiator_dim_y: "<< radiator_dim_y <<std::endl; #endif //----------------------------------------------------------------------------------------- caloLayer.distance = Ecal_inner_radius + module_thickness/2.0 - l_pos_z + l_thickness/2. + (s_pos_z+s_thick/2.) - caloLayer.inner_thickness; caloLayer.absorberThickness = radiator_dim_y ; //----------------------------------------------------------------------------------------- #endif // Init for outer nRadiationLengths = 0. ; nInteractionLengths = 0. ; thickness_sum = 0. ; } nRadiationLengths += s_thick/(2.*slice_material.radLength()); nInteractionLengths += s_thick/(2.*slice_material.intLength()); thickness_sum += s_thick/2; // Slice placement. PlacedVolume slice_phv = l_vol.placeVolume(s_vol,Position(0,0,s_pos_z-s_thick/2)); if ( x_slice.isSensitive() ) { slice_phv.addPhysVolID("layer", myLayerNum++ ); // slice_phv.addPhysVolID("slice",s_num); } //fg: not needed slice.setPlacement(slice_phv); // Increment Z position of slice. s_pos_z -= s_thick; // Increment slice number. ++s_num; } #if DD4HEP_VERSION_GE( 0, 15 ) caloLayer.outer_nRadiationLengths = nRadiationLengths + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.radLength(); caloLayer.outer_nInteractionLengths = nInteractionLengths + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.intLength(); caloLayer.outer_thickness = thickness_sum + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); if (!isFirstSens) caloData->layers.push_back( caloLayer ) ; #ifdef VERBOSE std::cout<<" caloLayer.distance: "<< caloLayer.distance <<std::endl; std::cout<<" caloLayer.inner_nRadiationLengths: "<< caloLayer.inner_nRadiationLengths <<std::endl; std::cout<<" caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl; std::cout<<" caloLayer.inner_thickness: "<< caloLayer.inner_thickness <<std::endl; std::cout<<" caloLayer.sensitive_thickness: "<< caloLayer.sensitive_thickness <<std::endl; std::cout<<" caloLayer.outer_nRadiationLengths: "<< caloLayer.outer_nRadiationLengths <<std::endl; std::cout<<" caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl; std::cout<<" caloLayer.outer_thickness: "<< caloLayer.outer_thickness <<std::endl; std::cout<<" EcalBarrel[2]==>caloLayer.inner_thickness + caloLayer.outer_thickness: " << caloLayer.inner_thickness + caloLayer.outer_thickness <<std::endl; #endif #endif // Init for next double layer nRadiationLengths = radiator_dim_y/(stave_material.radLength()) + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.radLength(); nInteractionLengths = radiator_dim_y/(stave_material.intLength()) + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.intLength(); thickness_sum = radiator_dim_y + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); if(radiator_dim_y <= 0) { stringstream err; err << " \n ERROR: The subdetector " << x_det.nameStr() << " geometry parameter -- radiator_dim_y = " << radiator_dim_y ; err << " \n Please check the radiator material name in the subdetector xml file"; throw runtime_error(err.str()); } // ######################### // BuildBarrelStructureLayer // ######################### l_dim_x -= (radiator_dim_y + Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); double radiator_dim_x = l_dim_x*2.; #ifdef VERBOSE std::cout << "radiator_dim_x = " << radiator_dim_x << std::endl; #endif double radiator_dim_z = Ecal_Barrel_module_dim_z - 2 * Ecal_lateral_face_thickness - 2 * N_FIBERS_W_STRUCTURE * Ecal_fiber_thickness; string bs_name="bs"; Box barrelStructureLayer_box(radiator_dim_x/2.,radiator_dim_z/2.,radiator_dim_y/2.); Volume barrelStructureLayer_vol(det_name+"_"+l_name+"_"+bs_name,barrelStructureLayer_box,stave_material); barrelStructureLayer_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr())); // Increment to next layer Z position. l_pos_z -= l_thickness; // Without last W StructureLayer, the last part is Si SD even layer. // the last number of Ecal_nlayers1, Ecal_nlayers2 and Ecal_nlayers3 is odd. int even_layer = l_num*2; if(even_layer > Ecal_nlayers1 + Ecal_nlayers2 + Ecal_nlayers3) continue; //if ( Number_of_Si_Layers_in_Barrel > n_total_layers ) continue; double bsl_pos_z = l_pos_z - (radiator_dim_y/2. + Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); l_pos_z -= (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); Position bsl_pos(0,0,bsl_pos_z); // Position of the layer. // PlacedVolume barrelStructureLayer_phv = mod_vol.placeVolume(barrelStructureLayer_vol,bsl_pos); l_dim_x -= (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); l_pos_z -= (radiator_dim_y + Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); ++l_num; } } // Set stave visualization. if (x_staves) { mod_vol.setVisAttributes(theDetector.visAttributes(x_staves.visStr())); } //==================================================================== // Place ECAL Barrel stave module into the envelope volume //==================================================================== double X,Y; X = module_thickness * sin(M_PI/4.); Y = Ecal_inner_radius + module_thickness / 2.; for (int stave_id = 1; stave_id <= nsides ; stave_id++) for (int module_id = 1; module_id < 6; module_id++) { double phirot = (stave_id-1) * dphi - hphi*3.0; double module_z_offset = (2 * module_id-6) * Ecal_Barrel_module_dim_z/2.; // And the rotation in Mokka is right hand rule, and the rotation in DD4hep is clockwise rule // So there is a negitive sign when port Mokka into DD4hep Transform3D tr(RotationZYX(0,phirot,M_PI*0.5),Translation3D(X*cos(phirot)-Y*sin(phirot), X*sin(phirot)+Y*cos(phirot), module_z_offset)); PlacedVolume pv = envelope.placeVolume(mod_vol,tr); pv.addPhysVolID("module",module_id); pv.addPhysVolID("stave",stave_id); DetElement sd = (module_id==0&&stave_id==0) ? stave_det : stave_det.clone(_toString(module_id,"module%d")+_toString(stave_id,"stave%d")); sd.setPlacement(pv); sdet.add(sd); } // Set envelope volume attributes. envelope.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); sdet.addExtension< LayeredCalorimeterData >( caloData ) ; return sdet; }
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; int det_id = x_det.id(); string det_name = x_det.nameStr(); DetElement sdet (det_name,det_id); // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, e , sdet ) ; dd4hep::xml::setDetectorTypeFlag( e, sdet ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- xml_dim_t dim = x_det.dimensions(); Material air = theDetector.air(); int nsides_inner = dim.nsides_inner(); int nsides_outer = dim.nsides_outer(); double rmin = dim.rmin(); double rmax = dim.rmax(); /// FIXME: IS THIS RIGHT? double zmin = dim.zmin(); double rcutout = dim.hasAttr(_U(rmin2)) ? dim.rmin2() : 0.; double zcutout = dim.hasAttr(_U(z2)) ? dim.z2() : 0.; Layering layering(x_det); double totalThickness = layering.totalThickness(); Readout readout = sens.readout(); Segmentation seg = readout.segmentation(); std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID double cell_sizeX = cellSizeVector[0]; double cell_sizeY = cellSizeVector[1]; PolyhedraRegular polyVolume(nsides_outer,rmin,rmax,totalThickness); Volume endcapVol("endcap",polyVolume,air); if(zcutout >0. || rcutout > 0.){ PolyhedraRegular cutoutPolyVolume(nsides_inner,0,rmin+rcutout,zcutout); Position cutoutPos(0,0,(zcutout-totalThickness)/2.0); std::cout<<"Cutout z width will be "<<zcutout<<std::endl; endcapVol=Volume("endcap",SubtractionSolid(polyVolume,cutoutPolyVolume,cutoutPos),air); } DetElement endcapA(sdet,"endcap",det_id); Ref_t(endcapA)->SetName((det_name+"_A").c_str()); int layer_num = 0; int layerType = 0; double layerZ = -totalThickness/2; //Create caloData object to extend driver with data required for reconstruction LayeredCalorimeterData* caloData = new LayeredCalorimeterData ; caloData->layoutType = LayeredCalorimeterData::EndcapLayout ; caloData->inner_symmetry = nsides_inner; caloData->outer_symmetry = nsides_outer; /** NOTE: phi0=0 means lower face flat parallel to experimental floor * This is achieved by rotating the modules with respect to the envelope * which is assumed to be a Polyhedron and has its axes rotated with respect * to the world by 180/nsides. In any other case (e.g. if you want to have * a tip of the calorimeter touching the ground) this value needs to be computed */ caloData->inner_phi0 = 0.; caloData->outer_phi0 = 0.; caloData->gap0 = 0.; //FIXME caloData->gap1 = 0.; //FIXME caloData->gap2 = 0.; //FIXME /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm. caloData->extent[0] = rmin ; caloData->extent[1] = rmax ; ///FIXME: CHECK WHAT IS NEEDED (EXSCRIBED?) caloData->extent[2] = zmin ; caloData->extent[3] = zmin + totalThickness; endcapVol.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); for(xml_coll_t c(x_det,_U(layer)); c; ++c) { xml_comp_t x_layer = c; double layer_thick = layering.layer(layer_num)->thickness(); string layer_type_name = _toString(layerType,"layerType%d"); int layer_repeat = x_layer.repeat(); double layer_rcutout = x_layer.hasAttr(_U(gap)) ? x_layer.gap() : 0; std::cout<<"Number of layers in group "<<layerType<<" : "<<layer_repeat<<std::endl; Volume layer_vol(layer_type_name,PolyhedraRegular(nsides_outer,rmin+layer_rcutout,rmax,layer_thick),air); int slice_num = 0; double sliceZ = -layer_thick/2; //Create a caloLayer struct for thiss layer type to store copies of in the parent struct LayeredCalorimeterData::Layer caloLayer ; caloLayer.cellSize0 = cell_sizeX; caloLayer.cellSize1 = cell_sizeY; double nRadiationLengths=0.; double nInteractionLengths=0.; double thickness_sum=0; for(xml_coll_t s(x_layer,_U(slice)); s; ++s) { xml_comp_t x_slice = s; string slice_name = _toString(slice_num,"slice%d"); double slice_thickness = x_slice.thickness(); Material slice_material = theDetector.material(x_slice.materialStr()); Volume slice_vol(slice_name,PolyhedraRegular(nsides_outer,rmin+layer_rcutout,rmax,slice_thickness),slice_material); slice_vol.setVisAttributes(theDetector.visAttributes(x_slice.visStr())); sliceZ += slice_thickness/2; layer_vol.placeVolume(slice_vol,Position(0,0,sliceZ)); nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; if ( x_slice.isSensitive() ) { sens.setType("calorimeter"); slice_vol.setSensitiveDetector(sens); #if DD4HEP_VERSION_GE( 0, 15 ) //Store "inner" quantities caloLayer.inner_nRadiationLengths = nRadiationLengths; caloLayer.inner_nInteractionLengths = nInteractionLengths; caloLayer.inner_thickness = thickness_sum; //Store scintillator thickness caloLayer.sensitive_thickness = slice_thickness; #endif //Reset counters to measure "outside" quantitites nRadiationLengths=0.; nInteractionLengths=0.; thickness_sum = 0.; } nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; sliceZ += slice_thickness/2; slice_num++; } #if DD4HEP_VERSION_GE( 0, 15 ) //Store "outer" quantities caloLayer.outer_nRadiationLengths = nRadiationLengths; caloLayer.outer_nInteractionLengths = nInteractionLengths; caloLayer.outer_thickness = thickness_sum; #endif layer_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr())); if ( layer_repeat <= 0 ) throw std::runtime_error(x_det.nameStr()+"> Invalid repeat value"); for(int j=0; j<layer_repeat; ++j) { string phys_lay = _toString(layer_num,"layer%d"); //The rest of the data is constant; only the distance needs to be updated //Store the position up to the inner face of the layer caloLayer.distance = zmin + totalThickness/2 + layerZ; //Push back a copy to the caloData structure caloData->layers.push_back( caloLayer ); layerZ += layer_thick/2; DetElement layer_elt(endcapA, phys_lay, layer_num); PlacedVolume pv = endcapVol.placeVolume(layer_vol,Position(0,0,layerZ)); pv.addPhysVolID("layer", layer_num); layer_elt.setPlacement(pv); layerZ += layer_thick/2; ++layer_num; } ++layerType; } double z_pos = zmin+totalThickness/2; PlacedVolume pv; // Reflect it. DetElement endcapB = endcapA.clone(det_name+"_B",x_det.id()); //Removed rotations to align with envelope //NOTE: If the envelope is not a polyhedron (eg. if you use a tube) //you may need to rotate so the axes match pv = envelope.placeVolume(endcapVol,Transform3D(RotationZYX(0,0,0), Position(0,0,z_pos))); pv.addPhysVolID("side", 1); endcapA.setPlacement(pv); //Removed rotations pv = envelope.placeVolume(endcapVol,Transform3D(RotationZYX(0,M_PI,0), Position(0,0,-z_pos))); pv.addPhysVolID("side", 2); endcapB.setPlacement(pv); sdet.add(endcapB); sdet.addExtension< LayeredCalorimeterData >( caloData ) ; return sdet; }
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { typedef vector<PlacedVolume> Placements; xml_det_t x_det = e; Material air = theDetector.air(); int det_id = x_det.id(); string det_name = x_det.nameStr(); DetElement sdet (det_name,det_id); // Assembly assembly (det_name); map<string, Volume> volumes; map<string, Placements> sensitives; PlacedVolume pv; // for encoding std::string cellIDEncoding = sens.readout().idSpec().fieldDescription(); UTIL::BitField64 encoder( cellIDEncoding ); encoder.reset(); encoder[lcio::LCTrackerCellID::subdet()] = det_id; encoder[lcio::LCTrackerCellID::side()] = lcio::ILDDetID::barrel; // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, e , sdet ) ; dd4hep::xml::setDetectorTypeFlag( e, sdet ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- ZPlanarData* zPlanarData = new ZPlanarData() ; NeighbourSurfacesData* neighbourSurfacesData = new NeighbourSurfacesData() ; sens.setType("tracker"); //NOTE modules are what is defined in compact. Later we call a "module" as a "sensor". for(xml_coll_t mi(x_det,_U(module)); mi; ++mi) { xml_comp_t x_mod = mi; xml_comp_t m_env = x_mod.child(_U(module_envelope)); string m_nam = x_mod.nameStr(); if ( volumes.find(m_nam) != volumes.end() ) { printout(ERROR,"TrackerBarrel","Logics error in building modules."); throw runtime_error("Logic error in building modules."); } double module_thickness = 0; for(xml_coll_t incl(x_mod,_U(include)); incl; ++incl) { dd4hep::xml::DocumentHolder doc(dd4hep::xml::DocumentHandler().load(incl, incl.attr_value(_U(ref)))); xml_h includes = doc.root(); xml_det_t incl_stack = includes; for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci) { xml_comp_t x_comp = ci; module_thickness = module_thickness + x_comp.thickness(); } } Volume m_vol(m_nam,Box(m_env.width()/2.,m_env.length()/2.,module_thickness/2.),air); volumes[m_nam] = m_vol; m_vol.setVisAttributes(theDetector.visAttributes(x_mod.visStr())); int ncomponents = 0; //First component on top of the list is the innermost one. double position_z= -module_thickness/2.; for(xml_coll_t incl(x_mod,_U(include)); incl; ++incl) { dd4hep::xml::DocumentHolder doc(dd4hep::xml::DocumentHandler().load(incl, incl.attr_value(_U(ref)))); xml_h includes = doc.root(); xml_det_t incl_stack = includes; for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci, ++ncomponents) { xml_comp_t x_comp = ci; string c_nam = _toString(ncomponents, "component%d"); Box c_box(m_env.width() / 2.0, m_env.length() / 2.0, x_comp.thickness() / 2.0); Volume c_vol(c_nam, c_box, theDetector.material(x_comp.materialStr())); pv = m_vol.placeVolume(c_vol, Position(0, 0, position_z + x_comp.thickness() / 2.0)); c_vol.setRegion(theDetector, x_comp.regionStr()); c_vol.setLimitSet(theDetector, x_comp.limitsStr()); c_vol.setVisAttributes(theDetector, x_comp.visStr()); if (x_comp.isSensitive()) { // pv.addPhysVolID("wafer",wafer_number++); c_vol.setSensitiveDetector(sens); sensitives[m_nam].push_back(pv); } position_z += x_comp.thickness(); } } } for(xml_coll_t li(x_det,_U(layer)); li; ++li) { xml_comp_t x_layer = li; xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the <z_layout> element. int lay_id = x_layer.id(); // int type = x_layer.type(); string m_nam = x_layer.moduleStr(); string lay_nam = _toString(x_layer.id(),"layer%d"); Assembly lay_vol (lay_nam); // Create the layer envelope volume. double phi0 = x_layout.phi0(); // Starting phi of first sensor. double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a sensor. double rc = x_layout.rc(); // Radius of the sensor center. int nphi = x_layout.nphi(); // Number of sensors in phi. double rphi_dr = x_layout.dr(); // The delta radius of every other sensor. double phi_incr = (M_PI * 2) / nphi; // Phi increment for one sensor. double phic = phi0; // Phi of the sensor center. double z0 = z_layout.z0(); // Z position of first sensor in phi. double nz = z_layout.nz(); // Number of sensors to place in z. double z_dr = z_layout.dr(); // Radial displacement parameter, of every other sensor. Volume m_env = volumes[m_nam]; DetElement lay_elt(sdet,_toString(x_layer.id(),"layer%d"),lay_id); Placements& waferVols = sensitives[m_nam]; // Z increment for sensor placement along Z axis. // Adjust for z0 at center of sensor rather than // the end of cylindrical envelope. double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0; // Starting z for sensor placement along Z axis. double sensor_z = -z0; int module_idx =0; ZPlanarData::LayerLayout thisLayer ; // Loop over the number of sensors in phi. for (int ii = 0; ii < nphi; ii++) { double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of sensor position. double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of sensor position. double x = rc * std::cos(phic); // Basic x sensor position. double y = rc * std::sin(phic); // Basic y sensor position. // Loop over the number of sensors in z. //Create stave FIXME disable for now string module_name = _toString(module_idx,"module%d"); // DetElement module_elt(lay_elt,module_name,module_idx); int sensor_idx = 0; for (int j = 0; j < nz; j++) { string sensor_name = _toString(sensor_idx,"sensor%d"); /////////////////// //get cellID and fill map< cellID of surface, vector of cellID of neighbouring surfaces > //encoding encoder[lcio::LCTrackerCellID::layer()] = lay_id; encoder[lcio::LCTrackerCellID::module()] = module_idx; encoder[lcio::LCTrackerCellID::sensor()] = sensor_idx; dd4hep::long64 cellID = encoder.lowWord(); // 32 bits //compute neighbours int n_neighbours_module = 1; // 1 gives the adjacent modules (i do not think we would like to change this) int n_neighbours_sensor = 1; int newmodule=0, newsensor=0; for(int imodule=-n_neighbours_module; imodule<=n_neighbours_module; imodule++){ // neighbouring modules for(int isensor=-n_neighbours_sensor; isensor<=n_neighbours_sensor; isensor++){ // neighbouring sensors if (imodule==0 && isensor==0) continue; // cellID we started with newmodule = module_idx + imodule; newsensor = sensor_idx + isensor; //compute special case at the boundary //general computation to allow (if necessary) more then adjacent neighbours (ie: +-2) if (newmodule < 0) newmodule = nphi + newmodule; if (newmodule >= nphi) newmodule = newmodule - nphi; if (newsensor < 0 || newsensor >= nz) continue; //out of the stave //encoding encoder[lcio::LCTrackerCellID::module()] = newmodule; encoder[lcio::LCTrackerCellID::sensor()] = newsensor; neighbourSurfacesData->sameLayer[cellID].push_back(encoder.lowWord()); } } /////////////////// //FIXME sensor_name = module_name + sensor_name; DetElement sens_elt(lay_elt,sensor_name,sensor_idx); // Module PhysicalVolume. Transform3D tr(RotationZYX(0,((M_PI/2)-phic-phi_tilt),-M_PI/2),Position(x,y,sensor_z)); //FIXME pv = lay_vol.placeVolume(m_env,tr); pv.addPhysVolID(_U(module), module_idx); pv.addPhysVolID(_U(sensor), sensor_idx); sens_elt.setPlacement(pv); for(size_t ic=0; ic<waferVols.size(); ++ic) { // std::cout<<"Layer: "<<lay_id<<" phiIdx: "<<ii<<" zidx: "<<j<<" wafer idx: "<<ic<<std::endl; PlacedVolume wafer_pv = waferVols[ic]; DetElement comp_elt(sens_elt,wafer_pv.volume().name(),sensor_idx); comp_elt.setPlacement(wafer_pv); ///GET GEAR INFORMATION FROM FIRST "MODULE" IN Z AND phi ///NOTE WORKS ONLY FOR ONE WAFER if (ii==0 && j==0 && ic==0){ Box mod_shape(m_env.solid()), comp_shape(wafer_pv.volume().solid()); const double* trans = comp_elt.placement()->GetMatrix()->GetTranslation(); double half_module_thickness = mod_shape->GetDZ(); double half_silicon_thickness = comp_shape->GetDZ(); double sensitive_z_position = trans[2]; double inner_thickness = half_module_thickness - sensitive_z_position; thisLayer.distanceSupport = rc ; thisLayer.offsetSupport = 0; thisLayer.thicknessSupport = inner_thickness- half_silicon_thickness; thisLayer.zHalfSupport = z0 + mod_shape->GetDY(); thisLayer.widthSupport = 2*mod_shape->GetDX(); thisLayer.distanceSensitive = rc+sensitive_z_position; thisLayer.offsetSensitive = 0. ; thisLayer.thicknessSensitive = 2*half_silicon_thickness;//Assembled along Z //Changed by Thorben Quast (same applies to zHalfSupport) //z0 = center of most right sensor, comp_shape-GetDY() = half length of one sensitive are of the module thisLayer.zHalfSensitive = z0 + comp_shape->GetDY(); thisLayer.widthSensitive = 2*comp_shape->GetDX(); thisLayer.ladderNumber = (int) nphi ; thisLayer.phi0 = phic; } } /// Increase counters etc. sensor_idx++; // Adjust the x and y coordinates of the sensor. x += dx; y += dy; // Flip sign of x and y adjustments. dx *= -1; dy *= -1; // Add z increment to get next z placement pos. sensor_z += z_incr; } module_idx++; phic += phi_incr; // Increment the phi placement of sensor. rc += rphi_dr; // Increment the center radius according to dr parameter. rphi_dr *= -1; // Flip sign of dr parameter. sensor_z = -z0; // Reset the Z placement parameter for sensor. } // Create the PhysicalVolume for the layer. pv = envelope.placeVolume(lay_vol); // Place layer in mother pv.addPhysVolID("layer", lay_id); // Set the layer ID. lay_elt.setAttributes(theDetector,lay_vol,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr()); lay_elt.setPlacement(pv); zPlanarData->layers.push_back( thisLayer ) ; } sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); sdet.addExtension< ZPlanarData >( zPlanarData ) ; sdet.addExtension< NeighbourSurfacesData >( neighbourSurfacesData ) ; //envelope.setVisAttributes(theDetector.invisible()); /*pv = theDetector.pickMotherVolume(sdet).placeVolume(assembly); pv.addPhysVolID("system", det_id); // Set the subdetector system ID. pv.addPhysVolID("barrel", 0); // Flag this as a barrel subdetector. sdet.setPlacement(pv);*/ return sdet; }
static Ref_t create_detector(Detector& lcdd, xml_h e, SensitiveDetector /*sens*/) { xml_det_t x_det = e; int det_id = x_det.id(); string det_name = x_det.nameStr(); DetElement sdet(det_name, det_id); bool reflect = x_det.reflect(); Volume envelope = dd4hep::xml::createPlacedEnvelope(lcdd, e , sdet) ; if (lcdd.buildType() == BUILD_ENVELOPE) return sdet ; const double phi1 = 0 ; const double phi2 = 360.0 * dd4hep::degree; for (xml_coll_t c(x_det, Unicode("section")); c; ++c) { xml_comp_t xmlSection(c); const double zStart = xmlSection.attr< double > (_Unicode(start)); const double zEnd = xmlSection.attr< double > (_Unicode(end)); const double rInnerStart = xmlSection.attr< double > (_Unicode(rMin1)); const double rInnerEnd = xmlSection.attr< double > (_Unicode(rMin2)); const double rOuterStart = xmlSection.attr< double > (_Unicode(rMax1)); const double rOuterEnd = xmlSection.attr< double > (_Unicode(rMax2)); const double thickness = rOuterStart - rInnerStart; Material sectionMat = lcdd.material(xmlSection.materialStr()); const std::string volName = "section_" + xmlSection.nameStr(); const double zHalf = fabs(zEnd - zStart) * 0.5; // half z length of the cone const double zPosition = fabs(zEnd + zStart) * 0.5; // middle z position // solid for the tube (including vacuum and wall): a solid cone ConeSegment tubeSolid(zHalf, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd , phi1, phi2); Volume tubeVol(volName + "_pos", tubeSolid, sectionMat); tubeVol.setAttributes(lcdd, xmlSection.regionStr(), xmlSection.limitsStr(), xmlSection.visStr()); envelope.placeVolume(tubeVol, Position(0, 0, zPosition)); const double dr = rInnerEnd - rInnerStart ; const double theta = atan2(dr , 2.* zHalf) ; Vector3D ocon(rInnerStart + 0.5 * (dr + thickness), 0. , 0.); Vector3D v(1. , 0. , theta, Vector3D::spherical) ; VolCone conSurf1(tubeVol , SurfaceType(SurfaceType::Helper) , 0.5 * thickness , 0.5 * thickness , v, ocon); volSurfaceList(sdet)->push_back(conSurf1); if (reflect) { Volume tubeVol2(volName + "_neg", tubeSolid, sectionMat); tubeVol2.setAttributes(lcdd, xmlSection.regionStr(), xmlSection.limitsStr(), xmlSection.visStr()); Transform3D Vol2Place(RotationY(-180.0 * dd4hep::degree), Position(0, 0, -1.*zPosition)); envelope.placeVolume(tubeVol2, Vol2Place); VolCone conSurf2(tubeVol2, SurfaceType(SurfaceType::Helper) , 0.5 * thickness , 0.5 * thickness , v, ocon); volSurfaceList(sdet)->push_back(conSurf2); } } return sdet; }
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) { std::cout << __PRETTY_FUNCTION__ << std::endl; std::cout << "Here is my LumiCal" << std::endl; std::cout << " and this is the sensitive detector: " << &sens << std::endl; sens.setType("calorimeter"); //Materials Material air = theDetector.air(); //Access to the XML File xml_det_t xmlLumiCal = element; const std::string detName = xmlLumiCal.nameStr(); DetElement sdet ( detName, xmlLumiCal.id() ); // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ; DetElement lumiCalDE_1(sdet,"Calorimeter1",1); DetElement lumiCalDE_2(sdet,"Calorimeter2",2); sdet.setTypeFlag( DetType::CALORIMETER | DetType::ENDCAP | DetType::ELECTROMAGNETIC | DetType::FORWARD ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- dd4hep::xml::Dimension dimensions = xmlLumiCal.dimensions(); //LumiCal Dimensions const double lcalInnerR = dimensions.inner_r(); const double lcalOuterR = dimensions.outer_r(); const double lcalInnerZ = dimensions.inner_z(); const double lcalThickness = Layering(xmlLumiCal).totalThickness(); const double lcalCentreZ = lcalInnerZ+lcalThickness*0.5; double LumiCal_cell_size = theDetector.constant<double>("LumiCal_cell_size"); //========== fill data for reconstruction ============================ LayeredCalorimeterData* caloData = new LayeredCalorimeterData ; caloData->layoutType = LayeredCalorimeterData::EndcapLayout ; caloData->inner_symmetry = 0 ; // hardcoded tube caloData->outer_symmetry = 0 ; caloData->phi0 = 0 ; /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm. caloData->extent[0] = lcalInnerR ; caloData->extent[1] = lcalOuterR ; caloData->extent[2] = lcalInnerZ ; caloData->extent[3] = lcalInnerZ + lcalThickness ; // counter for the current layer to be placed int thisLayerId = 0; //Parameters we have to know about dd4hep::xml::Component xmlParameter = xmlLumiCal.child(_Unicode(parameter)); const double fullCrossingAngle = xmlParameter.attr< double >(_Unicode(crossingangle)); std::cout << " The crossing angle is: " << fullCrossingAngle << " radian" << std::endl; //Envelope to place the layers in Tube envelopeTube (lcalInnerR, lcalOuterR, lcalThickness*0.5 ); Volume envelopeVol(detName+"_module",envelopeTube,air); envelopeVol.setVisAttributes(theDetector,xmlLumiCal.visStr()); //////////////////////////////////////////////////////////////////////////////// // Create all the layers //////////////////////////////////////////////////////////////////////////////// //Loop over all the layer (repeat=NN) sections //This is the starting point to place all layers, we need this when we have more than one layer block double referencePosition = -lcalThickness*0.5; for(dd4hep::xml::Collection_t coll(xmlLumiCal,_U(layer)); coll; ++coll) { dd4hep::xml::Component xmlLayer(coll); //we know this thing is a layer //This just calculates the total size of a single layer //Why no convenience function for this? double layerThickness = 0; for(dd4hep::xml::Collection_t l(xmlLayer,_U(slice)); l; ++l) layerThickness += xml_comp_t(l).thickness(); std::cout << "Total Length " << lcalThickness/dd4hep::cm << " cm" << std::endl; std::cout << "Layer Thickness " << layerThickness/dd4hep::cm << " cm" << std::endl; //Loop for repeat=NN for(int i=0, repeat=xmlLayer.repeat(); i<repeat; ++i) { std::string layer_name = detName + dd4hep::xml::_toString(thisLayerId,"_layer%d"); Tube layer_base(lcalInnerR,lcalOuterR,layerThickness*0.5); Volume layer_vol(layer_name,layer_base,air); int sliceID=0; double inThisLayerPosition = -layerThickness*0.5; double nRadiationLengths=0.; double nInteractionLengths=0.; double thickness_sum=0; LayeredCalorimeterData::Layer caloLayer ; for(dd4hep::xml::Collection_t collSlice(xmlLayer,_U(slice)); collSlice; ++collSlice) { dd4hep::xml::Component compSlice = collSlice; const double slice_thickness = compSlice.thickness(); const std::string sliceName = layer_name + dd4hep::xml::_toString(sliceID,"slice%d"); Material slice_material = theDetector.material(compSlice.materialStr()); Tube sliceBase(lcalInnerR,lcalOuterR,slice_thickness/2); Volume slice_vol (sliceName,sliceBase,slice_material); nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; if ( compSlice.isSensitive() ) { #if DD4HEP_VERSION_GE( 0, 15 ) //Store "inner" quantities caloLayer.inner_nRadiationLengths = nRadiationLengths; caloLayer.inner_nInteractionLengths = nInteractionLengths; caloLayer.inner_thickness = thickness_sum; //Store scintillator thickness caloLayer.sensitive_thickness = slice_thickness; #endif //Reset counters to measure "outside" quantitites nRadiationLengths=0.; nInteractionLengths=0.; thickness_sum = 0.; slice_vol.setSensitiveDetector(sens); } nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; slice_vol.setAttributes(theDetector,compSlice.regionStr(),compSlice.limitsStr(),compSlice.visStr()); layer_vol.placeVolume(slice_vol,Position(0,0,inThisLayerPosition+slice_thickness*0.5)); inThisLayerPosition += slice_thickness; ++sliceID; }//For all slices in this layer //----------------------------------------------------------------------------------------- ///Needs to be innermost face distance caloLayer.distance = lcalCentreZ + referencePosition; #if DD4HEP_VERSION_GE( 0, 15 ) caloLayer.outer_nRadiationLengths = nRadiationLengths; caloLayer.outer_nInteractionLengths = nInteractionLengths; caloLayer.outer_thickness = thickness_sum; #endif caloLayer.cellSize0 = LumiCal_cell_size ; caloLayer.cellSize1 = LumiCal_cell_size ; caloData->layers.push_back( caloLayer ) ; //----------------------------------------------------------------------------------------- //Why are we doing this for each layer, this just needs to be done once and then placed multiple times //Do we need unique IDs for each piece? layer_vol.setVisAttributes(theDetector,xmlLayer.visStr()); Position layer_pos(0,0,referencePosition+0.5*layerThickness); referencePosition += layerThickness; PlacedVolume pv = envelopeVol.placeVolume(layer_vol,layer_pos); pv.addPhysVolID("layer",thisLayerId); ++thisLayerId; }//for all layers }// for all layer collections const Position bcForwardPos (std::tan(0.5*fullCrossingAngle)*lcalCentreZ,0.0, lcalCentreZ); const Position bcBackwardPos(std::tan(0.5*fullCrossingAngle)*lcalCentreZ,0.0,-lcalCentreZ); const Rotation3D bcForwardRot ( RotationY(fullCrossingAngle*0.5 ) ); const Rotation3D bcBackwardRot( RotationZYX ( (M_PI), (M_PI-fullCrossingAngle*0.5), (0.0))); PlacedVolume pv = envelope.placeVolume(envelopeVol, Transform3D( bcForwardRot, bcForwardPos ) ); pv.addPhysVolID("barrel", 1); lumiCalDE_1.setPlacement(pv); PlacedVolume pv2 = envelope.placeVolume(envelopeVol, Transform3D( bcBackwardRot, bcBackwardPos ) ); pv2.addPhysVolID("barrel", 2); lumiCalDE_2.setPlacement(pv2); sdet.addExtension< LayeredCalorimeterData >( caloData ) ; return sdet; }
static Ref_t create_element(Detector& theDetector, xml_h element, SensitiveDetector sens) { xml_det_t x_det = element; std::string name = x_det.nameStr(); DetElement sdet( name, x_det.id() ) ; PlacedVolume pv; // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- // ----- read xml ---------------------- xml_dim_t dim = x_det.dimensions(); double inner_r = dim.rmin() ; double outer_r = dim.rmax() ; double z0 = dim.z0() ; double z1 = dim.z1() ; // double phi0 = dim.phi0() ; unsigned nsides = dim.nsides(); double thick = z1 - z0 ; double zpos = z0 + thick/2. ; Material mat = envelope.material() ; //-------------------------------------- sens.setType("tracker"); // base vectors for surfaces: Vector3D u(0,1,0) ; Vector3D v(1,0,0) ; Vector3D n(0,0,1) ; PolyhedraRegular phSolid ( nsides, inner_r, outer_r , 0.5*thick ) ; //============================================================================== DetElement fwdDE( sdet, name + std::string( "_fwd" ) , x_det.id() ); Volume phVol( name + std::string("_vol") , phSolid , mat ) ; phVol.setSensitiveDetector(sens); //fixme: the drawing of endcap surfaces in a polyhedral shape does not work right now // -> set surface to be invisible for now VolPlane surf( phVol,SurfaceType(SurfaceType::Sensitive, SurfaceType::Invisible), thick/4., thick/4., u,v,n ) ; volSurfaceList( fwdDE )->push_back( surf ) ; pv = envelope.placeVolume( phVol , Position( 0., 0., zpos ) ) ; pv.addPhysVolID("layer", 0 ).addPhysVolID( "side" , +1 ) ; fwdDE.setPlacement( pv ) ; //============================================================================== DetElement bwdDE( sdet, name + std::string( "_bwd" ) , x_det.id() ); // Volume phVol( name + std::string("_bwd") , phSolid , mat ) ; phVol.setSensitiveDetector(sens); volSurfaceList( bwdDE )->push_back( surf ) ; pv = envelope.placeVolume( phVol , Position( 0., 0., -zpos ) ) ; pv.addPhysVolID("layer", 0 ).addPhysVolID( "side" , -1 ) ; bwdDE.setPlacement( pv ) ; //-------------------------------------- return sdet ; }
/** Construction of VTX detector, ported from Mokka driver TubeX01.cc * * Mokka History: * - first implementation as Tube00: Paulo Mora de Freitas, Sep 2002 * - modified from Tube00 to Tube01DT: Ties Behnke, 2003-02-11 * - modified for a crossing angle as TubeX00: Adrian Vogel, 2005-05-18 * - modified for fancier geometries as TubeX01: Adrian Vogel, 2006-04-20 * * @author: F.Gaede, DESY, Jan 2014 * */ static Ref_t create_element(Detector& theDetector, xml_h element, SensitiveDetector /*sens*/) { //------------------------------------------ // See comments starting with '//**' for // hints on porting issues //------------------------------------------ std::cout << "This is the Beampipe:" << std::endl; //Access to the XML File xml_det_t xmlBeampipe = element; const std::string name = xmlBeampipe.nameStr(); DetElement tube( name, xmlBeampipe.id() ) ; // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , tube ) ; dd4hep::xml::setDetectorTypeFlag( element, tube ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return tube ; //----------------------------------------------------------------------------------- ConicalSupportData* beampipeData = new ConicalSupportData ; //###################################################################################################################################################################### // code ported from TubeX01::construct() : //################################## //** DD4hep/TGeo seems to need rad (as opposed to the manual) const double phi1 = 0 ; const double phi2 = 360.0*dd4hep::degree; //Parameters we have to know about dd4hep::xml::Component xmlParameter = xmlBeampipe.child(_Unicode(parameter)); const double crossingAngle = xmlParameter.attr< double >(_Unicode(crossingangle))*0.5; // only half the angle double min_radius = 1.e99 ; for(xml_coll_t c( xmlBeampipe ,Unicode("section")); c; ++c) { xml_comp_t xmlSection( c ); ODH::ECrossType crossType = ODH::getCrossType(xmlSection.attr< std::string >(_Unicode(type))); const double zStart = xmlSection.attr< double > (_Unicode(start)); const double zEnd = xmlSection.attr< double > (_Unicode(end)); const double rInnerStart = xmlSection.attr< double > (_Unicode(rMin1)); const double rInnerEnd = xmlSection.attr< double > (_Unicode(rMin2)); const double rOuterStart = xmlSection.attr< double > (_Unicode(rMax1)); const double rOuterEnd = xmlSection.attr< double > (_Unicode(rMax2)); const double thickness = rOuterStart - rInnerStart; Material sectionMat = theDetector.material(xmlSection.materialStr()); const std::string volName = "tube_" + xmlSection.nameStr(); std::cout << std::setw(8) << zStart /dd4hep::mm << std::setw(8) << zEnd /dd4hep::mm << std::setw(8) << rInnerStart /dd4hep::mm << std::setw(8) << rInnerEnd /dd4hep::mm << std::setw(8) << rOuterStart /dd4hep::mm << std::setw(8) << rOuterEnd /dd4hep::mm << std::setw(8) << thickness /dd4hep::mm << std::setw(8) << crossType << std::setw(35) << volName << std::setw(15) << sectionMat.name() << std::endl; if( crossType == ODH::kCenter ) { // store only the central sections ! ConicalSupportData::Section section ; section.rInner = rInnerStart ; section.rOuter = rOuterStart ; section.zPos = zStart ; beampipeData->sections.push_back( section ) ; } // things which can be calculated immediately const double zHalf = fabs(zEnd - zStart) * 0.5; // half z length of the cone const double zPosition = fabs(zEnd + zStart) * 0.5; // middle z position Material coreMaterial = theDetector.material("beam"); // always the same Material wallMaterial = sectionMat; // this could mess up your geometry, so better check it if (not checkForSensibleGeometry(crossingAngle, crossType)){ throw std::runtime_error( " Beampipe_o1_v01_geo.cpp : checkForSensibleGeometry() failed " ) ; // return false; } const double rotateAngle = getCurrentAngle(crossingAngle, crossType); // for the placement at +z (better make it const now) const double mirrorAngle = M_PI - rotateAngle; // for the "mirrored" placement at -z // the "mirroring" in fact is done by a rotation of (almost) 180 degrees around the y-axis switch (crossType) { case ODH::kCenter: case ODH::kUpstream: case ODH::kDnstream: { // a volume on the z-axis, on the upstream branch, or on the downstream branch // absolute transformations for the placement in the world Transform3D transformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition), rotateAngle) ); Transform3D transmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition), mirrorAngle) ); // solid for the tube (including vacuum and wall): a solid cone ConeSegment tubeSolid( zHalf, 0, rOuterStart, 0, rOuterEnd , phi1, phi2); // tube consists of vacuum // place tube twice explicitely so we can attach surfaces to each one Volume tubeLog( volName, tubeSolid, coreMaterial ) ; Volume tubeLog2( volName, tubeSolid, coreMaterial ) ; // placement of the tube in the world, both at +z and -z envelope.placeVolume( tubeLog, transformer ); envelope.placeVolume( tubeLog2, transmirror ); // if inner and outer radii are equal, then omit the tube wall if (rInnerStart != rOuterStart || rInnerEnd != rOuterEnd) { // the wall solid: a tubular cone ConeSegment wallSolid( zHalf, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, phi1, phi2); // the wall consists of the material given in the XML Volume wallLog ( volName + "_wall", wallSolid, wallMaterial); Volume wallLog2( volName + "_wall2", wallSolid, wallMaterial); if( crossType == ODH::kCenter ) { // add surface for tracking .... const bool isCylinder = ( rInnerStart == rInnerEnd ); if (isCylinder) { // cylinder Vector3D ocyl( rInnerStart + thickness/2. , 0. , 0. ) ; VolCylinder cylSurf1( wallLog , SurfaceType( SurfaceType::Helper ) , 0.5*thickness , 0.5*thickness , ocyl ); VolCylinder cylSurf2( wallLog2, SurfaceType( SurfaceType::Helper ) , 0.5*thickness , 0.5*thickness , ocyl ); volSurfaceList( tube )->push_back( cylSurf1 ); volSurfaceList( tube )->push_back( cylSurf2 ); }else{ // cone const double dr = rInnerEnd - rInnerStart ; const double theta = atan2( dr , 2.* zHalf ) ; Vector3D ocon( rInnerStart + 0.5 * ( dr + thickness ), 0. , 0. ); Vector3D v( 1. , 0. , theta, Vector3D::spherical ) ; VolCone conSurf1( wallLog , SurfaceType( SurfaceType::Helper ) , 0.5*thickness , 0.5*thickness , v, ocon ); VolCone conSurf2( wallLog2, SurfaceType( SurfaceType::Helper ) , 0.5*thickness , 0.5*thickness , v, ocon ); volSurfaceList( tube )->push_back( conSurf1 ); volSurfaceList( tube )->push_back( conSurf2 ); } if( rInnerStart < min_radius ) min_radius = rInnerStart ; if( rOuterStart < min_radius ) min_radius = rOuterStart ; } wallLog.setVisAttributes(theDetector, "TubeVis"); wallLog2.setVisAttributes(theDetector, "TubeVis"); tubeLog.setVisAttributes(theDetector, "VacVis"); tubeLog2.setVisAttributes(theDetector, "VacVis"); // placement as a daughter volume of the tube, will appear in both placements of the tube tubeLog.placeVolume( wallLog, Transform3D() ); tubeLog2.placeVolume( wallLog2, Transform3D() ); } } break; case ODH::kPunchedCenter: { // a volume on the z-axis with one or two inner holes // (implemented as a cone from which tubes are punched out) const double rUpstreamPunch = rInnerStart; // just alias names denoting what is meant here const double rDnstreamPunch = rInnerEnd; // (the database entries are "abused" in this case) // relative transformations for the composition of the SubtractionVolumes Transform3D upstreamTransformer(RotationY(-crossingAngle), Position(zPosition * tan(-crossingAngle), 0, 0)); Transform3D dnstreamTransformer(RotationY(+crossingAngle), Position(zPosition * tan(+crossingAngle), 0, 0)); // absolute transformations for the final placement in the world (angles always equal zero and 180 deg) Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition) , rotateAngle) ); Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition) , mirrorAngle) ); // solid for the tube (including vacuum and wall): a solid cone ConeSegment tubeSolid( zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2); // tube consists of vacuum (will later have two different daughters) Volume tubeLog0( volName + "_0", tubeSolid, coreMaterial ); Volume tubeLog1( volName + "_1", tubeSolid, coreMaterial ); // placement of the tube in the world, both at +z and -z envelope.placeVolume( tubeLog0, placementTransformer ); envelope.placeVolume( tubeLog1, placementTransmirror ); // the wall solid and placeholders for possible SubtractionSolids ConeSegment wholeSolid( zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2); Solid tmpSolid0, tmpSolid1, wallSolid0, wallSolid1; // the punched subtraction solids can be asymmetric and therefore have to be created twice: // one time in the "right" way, another time in the "reverse" way, because the "mirroring" // rotation around the y-axis will not only exchange +z and -z, but also +x and -x if ( rUpstreamPunch > 1e-6 ) { // do we need a hole on the upstream branch? Tube upstreamPunch( 0, rUpstreamPunch, 5 * zHalf, phi1, phi2); // a bit longer tmpSolid0 = SubtractionSolid( wholeSolid, upstreamPunch, upstreamTransformer); tmpSolid1 = SubtractionSolid( wholeSolid, upstreamPunch, dnstreamTransformer); // [sic] } else { // dont't do anything, just pass on the unmodified shape tmpSolid0 = wholeSolid; tmpSolid1 = wholeSolid; } if (rDnstreamPunch > 1e-6 ) { // do we need a hole on the downstream branch? Tube dnstreamPunch( 0, rDnstreamPunch, 5 * zHalf, phi1, phi2); // a bit longer wallSolid0 = SubtractionSolid( tmpSolid0, dnstreamPunch, dnstreamTransformer); wallSolid1 = SubtractionSolid( tmpSolid1, dnstreamPunch, upstreamTransformer); // [sic] } else { // dont't do anything, just pass on the unmodified shape wallSolid0 = tmpSolid0; wallSolid1 = tmpSolid1; } // the wall consists of the material given in the XML Volume wallLog0( volName + "_wall_0", wallSolid0, wallMaterial ); Volume wallLog1( volName + "_wall_1", wallSolid1, wallMaterial ); wallLog0.setVisAttributes(theDetector, "TubeVis"); wallLog1.setVisAttributes(theDetector, "TubeVis"); tubeLog0.setVisAttributes(theDetector, "VacVis"); tubeLog1.setVisAttributes(theDetector, "VacVis"); // placement as a daughter volumes of the tube tubeLog0.placeVolume( wallLog0, Position() ); tubeLog1.placeVolume( wallLog1, Position() ); break; } case ODH::kPunchedUpstream: case ODH::kPunchedDnstream: { // a volume on the upstream or downstream branch with two inner holes // (implemented as a cone from which another tube is punched out) const double rCenterPunch = (crossType == ODH::kPunchedUpstream) ? (rInnerStart) : (rInnerEnd); // just alias names denoting what is meant here const double rOffsetPunch = (crossType == ODH::kPunchedDnstream) ? (rInnerStart) : (rInnerEnd); // (the database entries are "abused" in this case) // relative transformations for the composition of the SubtractionVolumes Transform3D punchTransformer(RotationY(-2 * rotateAngle), Position(zPosition * tan(-2 * rotateAngle), 0, 0)); Transform3D punchTransmirror(RotationY(+2 * rotateAngle), Position(zPosition * tan(+2 * rotateAngle), 0, 0)); // absolute transformations for the final placement in the world Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition) , rotateAngle) ); Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition) , mirrorAngle) ); // solid for the tube (including vacuum and wall): a solid cone ConeSegment tubeSolid( zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2); // tube consists of vacuum (will later have two different daughters) Volume tubeLog0( volName + "_0", tubeSolid, coreMaterial ); Volume tubeLog1( volName + "_1", tubeSolid, coreMaterial ); // placement of the tube in the world, both at +z and -z envelope.placeVolume( tubeLog0, placementTransformer ); envelope.placeVolume( tubeLog1, placementTransmirror ); // the wall solid and the piece (only a tube, for the moment) which will be punched out ConeSegment wholeSolid( zHalf, rCenterPunch , rOuterStart, rCenterPunch, rOuterEnd, phi1, phi2); Tube punchSolid( 0, rOffsetPunch, 5 * zHalf, phi1, phi2); // a bit longer // the punched subtraction solids can be asymmetric and therefore have to be created twice: // one time in the "right" way, another time in the "reverse" way, because the "mirroring" // rotation around the y-axis will not only exchange +z and -z, but also +x and -x SubtractionSolid wallSolid0( wholeSolid, punchSolid, punchTransformer); SubtractionSolid wallSolid1( wholeSolid, punchSolid, punchTransmirror); // the wall consists of the material given in the database Volume wallLog0( volName + "_wall_0", wallSolid0, wallMaterial ); Volume wallLog1( volName + "_wall_1", wallSolid1, wallMaterial ); wallLog0.setVisAttributes(theDetector, "TubeVis"); wallLog1.setVisAttributes(theDetector, "TubeVis"); tubeLog0.setVisAttributes(theDetector, "VacVis"); tubeLog1.setVisAttributes(theDetector, "VacVis"); // placement as a daughter volumes of the tube tubeLog0.placeVolume( wallLog0 , Position() ); tubeLog1.placeVolume( wallLog1 , Position() ); break; } case ODH::kUpstreamClippedFront: case ODH::kDnstreamClippedFront: case ODH::kUpstreamSlicedFront: case ODH::kDnstreamSlicedFront: { // a volume on the upstream or donwstream branch, but with the front face parallel to the xy-plane // or to a piece tilted in the other direction ("sliced" like a salami with 2 * rotateAngle) // (implemented as a slightly longer cone from which the end is clipped off) // the volume which will be used for clipping: a solid tube const double clipSize = rOuterStart; // the right order of magnitude for the clipping volume (alias name) Tube clipSolid( 0, 2 * clipSize, clipSize, phi1, phi2); // should be large enough // relative transformations for the composition of the SubtractionVolumes const double clipAngle = (crossType == ODH::kUpstreamClippedFront || crossType == ODH::kDnstreamClippedFront) ? (rotateAngle) : (2 * rotateAngle); const double clipShift = (zStart - clipSize) / cos(clipAngle) - (zPosition - clipSize / 2); // question: why is this correct? Transform3D clipTransformer(RotationY(-clipAngle), Position(0, 0, clipShift)); Transform3D clipTransmirror(RotationY(+clipAngle), Position(0, 0, clipShift)); // absolute transformations for the final placement in the world Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition - clipSize / 2) , rotateAngle) ); Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition - clipSize / 2) , mirrorAngle) ); // solid for the tube (including vacuum and wall): a solid cone ConeSegment wholeSolid( zHalf + clipSize / 2, 0, rOuterStart, 0, rOuterEnd, phi1, phi2); // a bit longer // clip away the protruding end SubtractionSolid tubeSolid0( wholeSolid, clipSolid, clipTransformer); SubtractionSolid tubeSolid1( wholeSolid, clipSolid, clipTransmirror); // tube consists of vacuum (will later have two different daughters) Volume tubeLog0( volName + "_0", tubeSolid0, coreMaterial ); Volume tubeLog1( volName + "_1", tubeSolid1, coreMaterial ); // placement of the tube in the world, both at +z and -z envelope.placeVolume( tubeLog0, placementTransformer ); envelope.placeVolume( tubeLog1, placementTransmirror ); if (rInnerStart != rOuterStart || rInnerEnd != rOuterEnd) { // the wall solid: a tubular cone ConeSegment wallWholeSolid( zHalf + clipSize / 2, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, phi1, phi2); // a bit longer // clip away the protruding end SubtractionSolid wallSolid0( wallWholeSolid, clipSolid, clipTransformer); SubtractionSolid wallSolid1( wallWholeSolid, clipSolid, clipTransmirror); // the wall consists of the material given in the database Volume wallLog0( volName + "_wall_0", wallSolid0, wallMaterial ); Volume wallLog1( volName + "_wall_1", wallSolid1, wallMaterial ); wallLog0.setVisAttributes(theDetector, "TubeVis"); wallLog1.setVisAttributes(theDetector, "TubeVis"); tubeLog0.setVisAttributes(theDetector, "VacVis"); tubeLog1.setVisAttributes(theDetector, "VacVis"); // placement as a daughter volumes of the tube tubeLog0.placeVolume( wallLog0, Position() ); tubeLog1.placeVolume( wallLog1, Position() ); } } break; case ODH::kUpstreamClippedRear: case ODH::kDnstreamClippedRear: case ODH::kUpstreamSlicedRear: case ODH::kDnstreamSlicedRear: { // a volume on the upstream or donwstream branch, but with the rear face parallel to the xy-plane // or to a piece tilted in the other direction ("sliced" like a salami with 2 * rotateAngle) // (implemented as a slightly longer cone from which the end is clipped off) // the volume which will be used for clipping: a solid tube const double clipSize = rOuterEnd; // the right order of magnitude for the clipping volume (alias name) Tube clipSolid( 0, 2 * clipSize, clipSize, phi1, phi2); // should be large enough // relative transformations for the composition of the SubtractionVolumes const double clipAngle = (crossType == ODH::kUpstreamClippedRear || crossType == ODH::kDnstreamClippedRear) ? (rotateAngle) : (2 * rotateAngle); const double clipShift = (zEnd + clipSize) / cos(clipAngle) - (zPosition + clipSize / 2); // question: why is this correct? Transform3D clipTransformer(RotationY(-clipAngle), Position(0, 0, clipShift)); Transform3D clipTransmirror(RotationY(+clipAngle), Position(0, 0, clipShift)); // absolute transformations for the final placement in the world Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition + clipSize / 2) , rotateAngle) ); Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition + clipSize / 2) , mirrorAngle) ); // solid for the tube (including vacuum and wall): a solid cone ConeSegment wholeSolid( 0, rOuterStart, 0, rOuterEnd, zHalf + clipSize / 2, phi1, phi2); // a bit longer // clip away the protruding end SubtractionSolid tubeSolid0( wholeSolid, clipSolid, clipTransformer); SubtractionSolid tubeSolid1( wholeSolid, clipSolid, clipTransmirror); // tube consists of vacuum (will later have two different daughters) Volume tubeLog0( volName + "_0", tubeSolid0, coreMaterial ); Volume tubeLog1( volName + "_1", tubeSolid1, coreMaterial ); // placement of the tube in the world, both at +z and -z envelope.placeVolume( tubeLog0, placementTransformer ); envelope.placeVolume( tubeLog1, placementTransmirror ); if (rInnerStart != rOuterStart || rInnerEnd != rOuterEnd) { // the wall solid: a tubular cone ConeSegment wallWholeSolid( rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, zHalf + clipSize / 2, phi1, phi2); // a bit longer // clip away the protruding end SubtractionSolid wallSolid0( wallWholeSolid, clipSolid, clipTransformer); SubtractionSolid wallSolid1( wallWholeSolid, clipSolid, clipTransmirror); // the wall consists of the material given in the database Volume wallLog0( volName + "_wall_0", wallSolid0, wallMaterial ); Volume wallLog1( volName + "_wall_1", wallSolid1, wallMaterial ); wallLog0.setVisAttributes(theDetector, "TubeVis"); wallLog1.setVisAttributes(theDetector, "TubeVis"); tubeLog0.setVisAttributes(theDetector, "VacVis"); tubeLog1.setVisAttributes(theDetector, "VacVis"); // placement as a daughter volumes of the tube tubeLog0.placeVolume( wallLog0, Transform3D() ); tubeLog1.placeVolume( wallLog1, Transform3D() ); } break; } case ODH::kUpstreamClippedBoth: case ODH::kDnstreamClippedBoth: case ODH::kUpstreamSlicedBoth: case ODH::kDnstreamSlicedBoth: { // a volume on the upstream or donwstream branch, but with both faces parallel to the xy-plane // or to a piece tilted in the other direction ("sliced" like a salami with 2 * rotateAngle) // (implemented as a slightly longer cone from which the end is clipped off) // the volume which will be used for clipping: a solid tube const double clipSize = rOuterEnd; // the right order of magnitude for the clipping volume (alias name) Tube clipSolid( 0, 2 * clipSize, clipSize, phi1, phi2); // should be large enough // relative transformations for the composition of the SubtractionVolumes const double clipAngle = (crossType == ODH::kUpstreamClippedBoth || crossType == ODH::kDnstreamClippedBoth) ? (rotateAngle) : (2 * rotateAngle); const double clipShiftFrnt = (zStart - clipSize) / cos(clipAngle) - zPosition; const double clipShiftRear = (zEnd + clipSize) / cos(clipAngle) - zPosition; Transform3D clipTransformerFrnt(RotationY(-clipAngle), Position(0, 0, clipShiftFrnt)); Transform3D clipTransformerRear(RotationY(-clipAngle), Position(0, 0, clipShiftRear)); Transform3D clipTransmirrorFrnt(RotationY(+clipAngle), Position(0, 0, clipShiftFrnt)); Transform3D clipTransmirrorRear(RotationY(+clipAngle), Position(0, 0, clipShiftRear)); // absolute transformations for the final placement in the world Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition) , rotateAngle) ); Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition) , mirrorAngle) ); // solid for the tube (including vacuum and wall): a solid cone ConeSegment wholeSolid( 0, rOuterStart, 0, rOuterEnd, zHalf + clipSize, phi1, phi2); // a bit longer // clip away the protruding ends SubtractionSolid tmpSolid0 ( wholeSolid, clipSolid, clipTransformerFrnt); SubtractionSolid tmpSolid1 ( wholeSolid, clipSolid, clipTransmirrorFrnt); SubtractionSolid tubeSolid0( tmpSolid0, clipSolid, clipTransformerRear); SubtractionSolid tubeSolid1( tmpSolid1, clipSolid, clipTransmirrorRear); // tube consists of vacuum (will later have two different daughters) Volume tubeLog0( volName + "_0", tubeSolid0, coreMaterial ); Volume tubeLog1( volName + "_1", tubeSolid1, coreMaterial ); // placement of the tube in the world, both at +z and -z envelope.placeVolume( tubeLog0, placementTransformer ); envelope.placeVolume( tubeLog1, placementTransmirror ); if (rInnerStart != rOuterStart || rInnerEnd != rOuterEnd) { // the wall solid: a tubular cone ConeSegment wallWholeSolid( rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, zHalf + clipSize, phi1, phi2); // a bit longer // clip away the protruding ends SubtractionSolid wallTmpSolid0( wallWholeSolid, clipSolid, clipTransformerFrnt); SubtractionSolid wallTmpSolid1( wallWholeSolid, clipSolid, clipTransmirrorFrnt); SubtractionSolid wallSolid0 ( wallTmpSolid0, clipSolid, clipTransformerRear); SubtractionSolid wallSolid1 ( wallTmpSolid1, clipSolid, clipTransmirrorRear); // the wall consists of the material given in the database Volume wallLog0(volName + "_wall_0", wallSolid0, wallMaterial ); Volume wallLog1(volName + "_wall_1", wallSolid1, wallMaterial ); wallLog0.setVisAttributes(theDetector, "TubeVis"); wallLog1.setVisAttributes(theDetector, "TubeVis"); tubeLog0.setVisAttributes(theDetector, "VacVis"); tubeLog1.setVisAttributes(theDetector, "VacVis"); // placement as a daughter volumes of the tube tubeLog0.placeVolume( wallLog0, Transform3D() ); tubeLog1.placeVolume( wallLog1, Transform3D() ); } break; } default: { throw std::runtime_error( " Beampipe_o1_v01_geo.cpp : fatal failure !! ?? " ) ; // return false; // fatal failure } }//end switch }//for all xmlSections //###################################################################################################################################################################### // add a surface just inside the beampipe for tracking: Vector3D oIPCyl( (min_radius-1.e-3) , 0. , 0. ) ; SimpleCylinder ipCylSurf( envelope , SurfaceType( SurfaceType::Helper ) , 1.e-5 , 1e-5 , oIPCyl ) ; // the length does not really matter here as long as it is long enough for all tracks ... ipCylSurf->setHalfLength( 100*dd4hep::cm ) ; volSurfaceList( tube )->push_back( ipCylSurf ) ; tube.addExtension< ConicalSupportData >( beampipeData ) ; //-------------------------------------- tube.setVisAttributes( theDetector, xmlBeampipe.visStr(), envelope ); // // tube.setPlacement(pv); return tube; }
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(); //unused: string det_type = x_det.typeStr(); 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>("HcalEndcap_inner_radius"); double HcalEndcap_outer_radius = theDetector.constant<double>("HcalEndcap_outer_radius"); double HcalEndcap_min_z = theDetector.constant<double>("HcalEndcap_min_z"); double HcalEndcap_max_z = theDetector.constant<double>("HcalEndcap_max_z"); double Hcal_steel_cassette_thickness = theDetector.constant<double>("Hcal_steel_cassette_thickness"); double HcalServices_outer_FR4_thickness = theDetector.constant<double>("HcalServices_outer_FR4_thickness"); double HcalServices_outer_Cu_thickness = theDetector.constant<double>("HcalServices_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(); 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 = 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; // total thickness, all are same double box_half_z= dim_z/2.0; // module length, changed, 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 = box_half_y; double FEE_half_Z = Hcal_endcap_services_module_width/2.0; 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,FEELayer_thickness/2.0,FEE_half_Z); Volume FEELayer("FEELayer",FEELayerBox,air); Box FEELayerSteelBox(FEE_half_x,Hcal_steel_cassette_thickness/2.0,FEE_half_Z); Volume FEELayerSteel("FEELayerSteel",FEELayerSteelBox,stainless_steel); pVol = FEELayer.placeVolume(FEELayerSteel, Position(0, (-FEELayer_thickness/2.0 +Hcal_steel_cassette_thickness/2.0), 0)); Box FEELayerFR4Box(FEE_half_x,HcalServices_outer_FR4_thickness/2.0,FEE_half_Z); Volume FEELayerFR4("FEELayerFR4",FEELayerFR4Box,PCB); pVol = FEELayer.placeVolume(FEELayerFR4, Position(0, (-FEELayer_thickness/2.0+Hcal_steel_cassette_thickness +HcalServices_outer_FR4_thickness/2.0), 0)); Box FEELayerCuBox(FEE_half_x,HcalServices_outer_Cu_thickness/2.0,FEE_half_Z); Volume FEELayerCu("FEELayerCu",FEELayerCuBox,copper); pVol = FEELayer.placeVolume(FEELayerCu, Position(0, (-FEELayer_thickness/2.0+Hcal_steel_cassette_thickness+HcalServices_outer_FR4_thickness +HcalServices_outer_Cu_thickness/2.0), 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_y = - box_half_y + 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 = layer_thickness/2.0; double active_layer_dim_z = box_half_z; // 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); LayeredCalorimeterData::Layer caloLayer ; caloLayer.cellSize0 = cell_sizeX; caloLayer.cellSize1 = cell_sizeY; // ========= Create sublayer slices ========================================= // Create and place the slices into Layer // ========================================================================== // Create the slices (sublayers) within the Hcal Chamber. double slice_pos_y = -(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_y += slice_thickness / 2.0; // Slice volume & box Volume slice_vol(slice_name,Box(active_layer_dim_x,slice_thickness/2.0,active_layer_dim_z),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() ) { sens.setType("calorimeter"); slice_vol.setSensitiveDetector(sens); #if DD4HEP_VERSION_GE( 0, 15 ) //Store "inner" quantities caloLayer.inner_nRadiationLengths = nRadiationLengths; caloLayer.inner_nInteractionLengths = nInteractionLengths; caloLayer.inner_thickness = thickness_sum; //Store scintillator thickness caloLayer.sensitive_thickness = slice_thickness; #endif //Reset counters to measure "outside" quantitites nRadiationLengths=0.; nInteractionLengths=0.; thickness_sum = 0.; } nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; // 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,slice_pos_y,0)); //slice_phv.addPhysVolID("slice",slice_number); slice.setPlacement(slice_phv); // Increment Z position for next slice. slice_pos_y += 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()); #if DD4HEP_VERSION_GE( 0, 15 ) //Store "outer" quantities caloLayer.outer_nRadiationLengths = nRadiationLengths; caloLayer.outer_nInteractionLengths = nInteractionLengths; caloLayer.outer_thickness = thickness_sum; #endif // ========= 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_y += layer_thickness / 2.0; PlacedVolume layer_phv = envelopeVol.placeVolume(layer_vol, Position(0,layer_pos_y,0)); // 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,layer_pos_y,0)); //----------------------------------------------------------------------------------------- if ( caloData->layers.size() < (unsigned int)repeat ) { caloLayer.distance = HcalEndcap_min_z + box_half_y + layer_pos_y - 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_y += layer_thickness / 2.0; layer_pos_y += 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_y; 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_y; 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_z + 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_z - 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/2.0):(M_PI/2.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; }
static Ref_t create_element(Detector& theDetector, xml_h xmlHandle, SensitiveDetector /*sens*/) { //------------------------------------------ // See comments starting with '//**' for // hints on porting issues //------------------------------------------ std::cout << "This is the Mask:" << std::endl; // Access to the XML File xml_det_t xmlMask = xmlHandle; const std::string name = xmlMask.nameStr(); //-------------------------------- Assembly envelope(name + "_assembly"); //-------------------------------- DetElement tube(name, xmlMask.id()); // const double phi1 = 0 ; // const double phi2 = 360.0*dd4hep::degree; // Parameters we have to know about dd4hep::xml::Component xmlParameter = xmlMask.child(_Unicode(parameter)); const double crossingAngle = xmlParameter.attr<double>(_Unicode(crossingangle)) * 0.5; // only half the angle for (xml_coll_t c(xmlMask, Unicode("section")); c; ++c) { xml_comp_t xmlSection(c); ODH::ECrossType crossType = ODH::getCrossType(xmlSection.attr<std::string>(_Unicode(type))); const double zStart = xmlSection.attr<double>(_Unicode(start)); const double zEnd = xmlSection.attr<double>(_Unicode(end)); const double rInnerStart = xmlSection.attr<double>(_Unicode(rMin1)); const double rInnerEnd = xmlSection.attr<double>(_Unicode(rMin2)); const double rOuterStart = xmlSection.attr<double>(_Unicode(rMax1)); const double rOuterEnd = xmlSection.attr<double>(_Unicode(rMax2)); const double phi1 = xmlSection.attr<double>(_Unicode(Phi1)); const double phi2 = xmlSection.attr<double>(_Unicode(Phi2)); const double thickness = rOuterStart - rInnerStart; Material sectionMat = theDetector.material(xmlSection.materialStr()); const std::string volName = "tube_" + xmlSection.nameStr(); std::cout << std::setw(8) << zStart << std::setw(8) << zEnd << std::setw(8) << rInnerStart << std::setw(8) << rInnerEnd << std::setw(8) << rOuterStart << std::setw(8) << rOuterEnd << std::setw(8) << thickness << std::setw(8) << crossType << std::setw(8) << phi1 << std::setw(8) << phi2 << std::setw(15) << volName << std::setw(15) << sectionMat.name() << std::endl; // things which can be calculated immediately const double zHalf = fabs(zEnd - zStart) * 0.5; // half z length of the cone const double zPosition = fabs(zEnd + zStart) * 0.5; // middle z position Material material = sectionMat; // this could mess up your geometry, so better check it if (not ODH::checkForSensibleGeometry(crossingAngle, crossType)) { throw std::runtime_error(" Mask_o1_v01_noRot_geo.cpp : checkForSensibleGeometry() failed "); } const double rotateAngle = getCurrentAngle(crossingAngle, crossType); // for the placement at +z (better make it const now) const double mirrorAngle = M_PI - rotateAngle; // for the "mirrored" placement at -z // the "mirroring" in fact is done by a rotation of (almost) 180 degrees around the y-axis switch (crossType) { case ODH::kCenter: case ODH::kUpstream: case ODH::kDnstream: { // a volume on the z-axis, on the upstream branch, or on the downstream branch // absolute transformations for the placement in the world, rotate over X Transform3D transformer(RotationX(rotateAngle), RotateX(Position(0, 0, zPosition), rotateAngle)); Transform3D transmirror(RotationX(mirrorAngle), RotateX(Position(0, 0, zPosition), mirrorAngle)); // solid for the tube (including vacuum and wall): a solid cone ConeSegment tubeSolid(zHalf, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, phi1, phi2); // tube consists of vacuum Volume tubeLog(volName, tubeSolid, material); tubeLog.setVisAttributes(theDetector, xmlMask.visStr()); // placement of the tube in the world, both at +z and -z envelope.placeVolume(tubeLog, transformer); envelope.placeVolume(tubeLog, transmirror); } break; case ODH::kPunchedCenter: { // a cone with one or two inner holes (two tubes are punched out) const double rUpstreamPunch = rInnerStart; // just alias names denoting what is meant here const double rDnstreamPunch = rInnerEnd; // (the database entries are "abused" in this case) // relative transformations for the composition of the SubtractionVolumes Transform3D upstreamTransformer(RotationY(-crossingAngle), Position(zPosition * tan(-crossingAngle), 0, 0)); Transform3D dnstreamTransformer(RotationY(+crossingAngle), Position(zPosition * tan(+crossingAngle), 0, 0)); // absolute transformations for the final placement in the world (angles always equal zero and 180 deg) Transform3D placementTransformer(RotationY(rotateAngle), RotateY(Position(0, 0, zPosition), rotateAngle)); Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY(Position(0, 0, zPosition), mirrorAngle)); // the main solid and the two pieces (only tubes, for the moment) which will be punched out ConeSegment wholeSolid(zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2); Solid tmpSolid0, tmpSolid1, finalSolid0, finalSolid1; // the punched subtraction solids can be asymmetric and therefore have to be created twice: // one time in the "right" way, another time in the "reverse" way, because the "mirroring" // rotation around the y-axis will not only exchange +z and -z, but also +x and -x if (rUpstreamPunch > 1e-6) { // do we need a hole on the upstream branch? Tube upstreamPunch(0, rUpstreamPunch, 5 * zHalf, phi1, phi2); // a bit longer tmpSolid0 = SubtractionSolid(wholeSolid, upstreamPunch, upstreamTransformer); tmpSolid1 = SubtractionSolid(wholeSolid, upstreamPunch, dnstreamTransformer); // [sic] } else { // dont't do anything, just pass on the unmodified shape tmpSolid0 = wholeSolid; tmpSolid1 = wholeSolid; } if (rDnstreamPunch > 1e-6) { // do we need a hole on the downstream branch? Tube dnstreamPunch(0, rDnstreamPunch, 5 * zHalf, phi1, phi2); // a bit longer finalSolid0 = SubtractionSolid(tmpSolid0, dnstreamPunch, dnstreamTransformer); finalSolid1 = SubtractionSolid(tmpSolid1, dnstreamPunch, upstreamTransformer); // [sic] } else { // dont't do anything, just pass on the unmodified shape finalSolid0 = tmpSolid0; finalSolid1 = tmpSolid1; } // tube consists of vacuum (will later have two different daughters) Volume tubeLog0(volName + "_0", finalSolid0, material); Volume tubeLog1(volName + "_1", finalSolid1, material); tubeLog0.setVisAttributes(theDetector, xmlMask.visStr()); tubeLog1.setVisAttributes(theDetector, xmlMask.visStr()); // placement of the tube in the world, both at +z and -z envelope.placeVolume(tubeLog0, placementTransformer); envelope.placeVolume(tubeLog1, placementTransmirror); break; } case ODH::kPunchedUpstream: case ODH::kPunchedDnstream: { // a volume on the upstream or downstream branch with two inner holes // (implemented as a cone from which another tube is punched out) const double rCenterPunch = (crossType == ODH::kPunchedUpstream) ? (rInnerStart) : (rInnerEnd); // just alias names denoting what is meant here const double rOffsetPunch = (crossType == ODH::kPunchedDnstream) ? (rInnerStart) : (rInnerEnd); // (the database entries are "abused" in this case) // relative transformations for the composition of the SubtractionVolumes Transform3D punchTransformer(RotationY(-2 * rotateAngle), Position(zPosition * tan(-2 * rotateAngle), 0, 0)); Transform3D punchTransmirror(RotationY(+2 * rotateAngle), Position(zPosition * tan(+2 * rotateAngle), 0, 0)); // absolute transformations for the final placement in the world Transform3D placementTransformer(RotationY(rotateAngle), RotateY(Position(0, 0, zPosition), rotateAngle)); Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY(Position(0, 0, zPosition), mirrorAngle)); // the main solid and the piece (only a tube, for the moment) which will be punched out ConeSegment wholeSolid(zHalf, rCenterPunch, rOuterStart, rCenterPunch, rOuterEnd, phi1, phi2); Tube punchSolid(0, rOffsetPunch, 5 * zHalf, phi1, phi2); // a bit longer // the punched subtraction solids can be asymmetric and therefore have to be created twice: // one time in the "right" way, another time in the "reverse" way, because the "mirroring" // rotation around the y-axis will not only exchange +z and -z, but also +x and -x SubtractionSolid finalSolid0(wholeSolid, punchSolid, punchTransformer); SubtractionSolid finalSolid1(wholeSolid, punchSolid, punchTransmirror); // tube consists of vacuum (will later have two different daughters) Volume tubeLog0(volName + "_0", finalSolid0, material); Volume tubeLog1(volName + "_1", finalSolid1, material); tubeLog0.setVisAttributes(theDetector, xmlMask.visStr()); tubeLog1.setVisAttributes(theDetector, xmlMask.visStr()); // placement of the tube in the world, both at +z and -z envelope.placeVolume(tubeLog0, placementTransformer); envelope.placeVolume(tubeLog1, placementTransmirror); break; } default: { throw std::runtime_error(" Mask_o1_v01_geo.cpp : fatal failure !! ?? "); } } // end switch } // for all xmlSections //-------------------------------------- Volume mother = theDetector.pickMotherVolume(tube); PlacedVolume pv(mother.placeVolume(envelope)); pv.addPhysVolID("system", xmlMask.id()); //.addPhysVolID("side", 0 ) ; tube.setVisAttributes(theDetector, xmlMask.visStr(), envelope); tube.setPlacement(pv); return tube; }
static Ref_t create_detector(Detector& theDetector,xml_h e,SensitiveDetector sens){ typedef vector<PlacedVolume>Placements; xml_det_t x_det=e; Material vacuum=theDetector.vacuum(); int det_id= x_det.id(); string det_name=x_det.nameStr(); bool reflect = x_det.reflect(false); DetElement sdet(det_name,det_id); int m_id=0,c_id=0,n_sensor=0; map<string,Volume>modules; map<string,Placements>sensitives; PlacedVolume pv; //encoding that was missing std::string cellIDEncoding=sens.readout().idSpec().fieldDescription(); UTIL::BitField64 encoder(cellIDEncoding); encoder.reset(); encoder[lcio::LCTrackerCellID::subdet()]=det_id; // --- create an envelope volume and position it into the world --------------------- Volume envelope=dd4hep::xml::createPlacedEnvelope(theDetector,e,sdet); dd4hep::xml::setDetectorTypeFlag(e,sdet); if(theDetector.buildType() == BUILD_ENVELOPE)return sdet; //----------------------------------------------------------------------------------- dd4hep::rec::ZDiskPetalsData* zDiskPetalsData=new dd4hep::rec::ZDiskPetalsData; //neighbour surfaces added dd4hep::rec::NeighbourSurfacesData* neighbourSurfacesData=new dd4hep::rec::NeighbourSurfacesData(); // std::map< std::string, double > moduleSensThickness; envelope.setVisAttributes(theDetector.invisible()); sens.setType("tracker"); for(xml_coll_t mi(x_det,_U(module));mi;++mi,++m_id){ xml_comp_t x_mod=mi; string m_nam=x_mod.nameStr(); xml_comp_t trd=x_mod.trd(); double posY; double x1=trd.x1(); double x2=trd.x2(); double z=trd.z(); double y1,y2,total_thickness=0.; xml_coll_t ci(x_mod,_U(module_component)); for(ci.reset(),total_thickness=0.0;ci;++ci) total_thickness += xml_comp_t(ci).thickness(); y1 = y2 = total_thickness / 2; Volume m_volume(m_nam, Trapezoid(x1, x2, y1, y2, z), vacuum); m_volume.setVisAttributes(theDetector.visAttributes(x_mod.visStr())); // Loop over slices // The first slice (top in the xml) is placed at the "bottom" of the module for(ci.reset(), n_sensor=1, c_id=0, posY=-y1; ci; ++ci, ++c_id){ xml_comp_t c=ci; double c_thick=c.thickness(); Material c_mat=theDetector.material(c.materialStr()); string c_name=_toString(c_id,"component%d"); Volume c_vol(c_name, Trapezoid(x1,x2,c_thick/2e0,c_thick/2e0,z), c_mat); c_vol.setVisAttributes(theDetector.visAttributes(c.visStr())); pv = m_volume.placeVolume(c_vol,Position(0,posY+c_thick/2,0)); if (c.isSensitive()){ c_vol.setSensitiveDetector(sens); sensitives[m_nam].push_back(pv); ++n_sensor; } posY += c_thick; } modules[m_nam] = m_volume; } for(xml_coll_t li(x_det,_U(layer));li;++li){ xml_comp_t x_layer(li); int l_id=x_layer.id(); int mod_num=0; int ring_num=0; double sumZ(0.),innerR(1e100),outerR(0.); //loop only to count the number of rings in a disk - it is then needed for looking for neighborous when you are in a "border" cell int nrings = 0; for(xml_coll_t ri(x_layer,_U(ring)); ri; ++ri) { nrings++; } dd4hep::rec::ZDiskPetalsData::LayerLayout thisLayer; for(xml_coll_t ri(x_layer,_U(ring)); ri; ++ri) { xml_comp_t x_ring = ri; double r=x_ring.r(); double phi0=x_ring.phi0(0); double zstart=x_ring.zstart(); double dz=x_ring.dz(0); int nmodules=x_ring.nmodules(); string m_nam=x_ring.moduleStr(); Volume m_vol=modules[m_nam]; double iphi=2*M_PI/nmodules; double phi=phi0; Placements& sensVols=sensitives[m_nam]; Box mod_shape(m_vol.solid()); if(r-mod_shape->GetDZ()<innerR) innerR=r-mod_shape->GetDZ(); if(r+mod_shape->GetDZ()>outerR) outerR=r+mod_shape->GetDZ(); sumZ+=zstart; r=r+mod_shape->GetDY(); for(int k=0;k<nmodules;++k){ string m_base=_toString(l_id,"layer%d")+_toString(mod_num,"_module%d")+_toString(k,"_sensor%d"); double x=-r*std::cos(phi); double y=-r*std::sin(phi); DetElement module(sdet,m_base+"_pos",det_id); pv=envelope.placeVolume(m_vol,Transform3D(RotationZYX(0,-M_PI/2-phi,-M_PI/2),Position(x,y,zstart+dz))); pv.addPhysVolID("side",1).addPhysVolID("layer", l_id).addPhysVolID("module",mod_num).addPhysVolID("sensor",k); module.setPlacement(pv); for(size_t ic=0;ic<sensVols.size();++ic){ PlacedVolume sens_pv=sensVols[ic]; DetElement comp_elt(module,sens_pv.volume().name(),mod_num); comp_elt.setPlacement(sens_pv); } if(reflect){ pv = envelope.placeVolume(m_vol,Transform3D(RotationZYX(M_PI,-M_PI/2-phi,-M_PI/2),Position(x,y,-zstart-dz))); pv.addPhysVolID("side",-1).addPhysVolID("layer",l_id).addPhysVolID("module",mod_num).addPhysVolID("sensor",k); DetElement r_module(sdet,m_base+"_neg",det_id); r_module.setPlacement(pv); for(size_t ic=0;ic<sensVols.size();++ic){ PlacedVolume sens_pv=sensVols[ic]; DetElement comp_elt(r_module,sens_pv.volume().name(),mod_num); comp_elt.setPlacement(sens_pv); } } //modified on comparison with TrackerEndcap_o2_v06_geo.cpp //get cellID and fill map< cellID of surface, vector of cellID of neighbouring surfaces > dd4hep::long64 cellID_reflect; if(reflect){ encoder[lcio::LCTrackerCellID::side()]=lcio::ILDDetID::bwd; encoder[lcio::LCTrackerCellID::layer()]=l_id; encoder[lcio::LCTrackerCellID::module()]=mod_num; encoder[lcio::LCTrackerCellID::sensor()]=k; cellID_reflect=encoder.lowWord(); // 32 bits } encoder[lcio::LCTrackerCellID::side()]=lcio::ILDDetID::fwd; encoder[lcio::LCTrackerCellID::layer()]=l_id; encoder[lcio::LCTrackerCellID::module()]=mod_num; encoder[lcio::LCTrackerCellID::sensor()]=k; dd4hep::long64 cellID = encoder.lowWord(); // 32 bits //compute neighbours int n_neighbours_module = 1; // 1 gives the adjacent modules (i do not think we would like to change this) int n_neighbours_sensor = 1; int newmodule=0,newsensor=0; for(int imodule=-n_neighbours_module; imodule<=n_neighbours_module; imodule++){ // neighbouring modules for(int isensor=-n_neighbours_sensor; isensor<=n_neighbours_sensor; isensor++){ // neighbouring sensors if (imodule==0 && isensor==0) continue; // cellID we started with newmodule = mod_num + imodule; newsensor = k + isensor; //compute special case at the boundary //general computation to allow (if necessary) more then adiacent neighbours (ie: +-2) if (newsensor < 0) newsensor = nmodules + newsensor; if (newsensor >= nmodules) newsensor = newsensor - nmodules; if (newmodule < 0 || newmodule >= nrings)continue; //out of disk //encoding encoder[lcio::LCTrackerCellID::module()] = newmodule; encoder[lcio::LCTrackerCellID::sensor()] = newsensor; neighbourSurfacesData->sameLayer[cellID].push_back(encoder.lowWord()); if (reflect){ encoder[lcio::LCTrackerCellID::side()]=lcio::ILDDetID::bwd; encoder[lcio::LCTrackerCellID::layer()]=l_id; encoder[lcio::LCTrackerCellID::module()]=newmodule; encoder[lcio::LCTrackerCellID::sensor()]=newsensor; neighbourSurfacesData->sameLayer[cellID_reflect].push_back(encoder.lowWord()); } } } dz = -dz; phi += iphi; } ++mod_num; ++ring_num; } // Only filling what is needed for CED/DDMarlinPandora thisLayer.zPosition=sumZ/ring_num; // average z thisLayer.distanceSensitive=innerR; thisLayer.lengthSensitive=outerR - innerR; thisLayer.petalNumber=ring_num; // number of rings in petalNumber, needed for tracking zDiskPetalsData->layers.push_back(thisLayer); } sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); sdet.addExtension<dd4hep::rec::ZDiskPetalsData>(zDiskPetalsData); //added extension sdet.addExtension<dd4hep::rec::NeighbourSurfacesData>(neighbourSurfacesData); std::cout<<"XXX Tracker endcap layers:"<<zDiskPetalsData->layers.size()<<std::endl; return sdet; }
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { typedef vector<PlacedVolume> Placements; xml_det_t x_det = e; Material vacuum = theDetector.vacuum(); int det_id = x_det.id(); string det_name = x_det.nameStr(); bool reflect = x_det.reflect(false); DetElement sdet (det_name,det_id); int m_id=0, c_id=0, n_sensor=0; map<string, Volume> modules; map<string, Placements> sensitives; PlacedVolume pv; // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope(theDetector, e, sdet); dd4hep::xml::setDetectorTypeFlag(e, sdet); if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet; //----------------------------------------------------------------------------------- envelope.setVisAttributes(theDetector.invisible()); sens.setType("tracker"); // Build the sensor units // Loop over 'modules' as defined in the XML for(xml_coll_t mi(x_det,_U(module)); mi; ++mi, ++m_id) { xml_comp_t x_mod = mi; string m_nam = x_mod.nameStr(); xml_comp_t trd = x_mod.trd(); double posY; double x1 = trd.x1(); double x2 = trd.x2(); double z = trd.z(); double y1, y2, total_thickness=0.; xml_coll_t ci(x_mod, _U(module_component)); for(ci.reset(), total_thickness=0.0; ci; ++ci) total_thickness += xml_comp_t(ci).thickness(); y1 = y2 = total_thickness / 2; Volume m_volume(m_nam, Trapezoid(x1, x2, y1, y2, z), vacuum); m_volume.setVisAttributes(theDetector.visAttributes(x_mod.visStr())); std::cout << m_nam << ", thickness=" << total_thickness << std::endl; // Loop over the module_components ('slices') in the 'module' // The first component (top in the XML) is placed at the 'bottom' for(ci.reset(), n_sensor=1, c_id=0, posY=-y1; ci; ++ci, ++c_id) { xml_comp_t c = ci; double c_thick = c.thickness(); Material c_mat = theDetector.material(c.materialStr()); string c_name = _toString(c_id, "component%d"); Volume c_vol(c_name, Trapezoid(x1,x2,c_thick/2e0,c_thick/2e0,z), c_mat); std::cout << " + sensor " << n_sensor << " " << c_name; c_vol.setVisAttributes(theDetector.visAttributes(c.visStr())); pv = m_volume.placeVolume(c_vol, Position(0, posY + c_thick/2, 0)); if ( c.isSensitive() ) { sdet.check(n_sensor > 2, "SiTrackerEndcap::fromCompact: " + c_name + " Max of 2 modules allowed!"); pv.addPhysVolID("sensor", n_sensor); c_vol.setSensitiveDetector(sens); sensitives[m_nam].push_back(pv); std::cout << " (" << n_sensor << " is sensitive) "; ++n_sensor; } std::cout << std::endl; posY += c_thick; } modules[m_nam] = m_volume; } // done building the 2 modules, of 12 layers each int mod_count[12] = {0}; // Build now the detector itself // Loop over layers as defined in the XML for(xml_coll_t li(x_det, _U(layer)); li; ++li) { xml_comp_t x_layer(li); int l_id = x_layer.id(); int ring_num = 0; std::cout << "Layer " << l_id << ":" << std::endl; // Loop over rings, as defined in the XML for(xml_coll_t ri(x_layer, _U(ring)); ri; ++ri) { xml_comp_t x_ring = ri; double r = x_ring.r(); double phi0 = x_ring.phi0(0); double zstart = x_ring.zstart(); double dz = x_ring.dz(0); int nmodules = x_ring.nmodules(); string m_nam = x_ring.moduleStr(); Volume m_vol = modules[m_nam]; double iphi = 2*M_PI/nmodules; double phi = phi0; Placements& sensVols = sensitives[m_nam]; // This driver version encodes the rings as layers and the // petals as modules, such that 'layer' 1 contains all innermost rings // and last 'layer' contains the outermost rings in the tracker // farthest away on z from the IP (unintuititive, but works) std::cout << " Ring " << ring_num << ":" << std::endl; // Loop over modules in each ring, modules are either type 1 or 2 for(int k=0; k < nmodules; ++k) { double x = -r*std::cos(phi); double y = -r*std::sin(phi); for(int s=1-2*int(reflect); s<2; s+=1+int(reflect)){ string e_name = _toString(s, "side%d") + _toString(l_id, "_layer%d") + _toString(ring_num, "_ring%d") + _toString(k, "_sensor%d"); DetElement module(sdet, e_name, det_id); pv = envelope.placeVolume(m_vol, Transform3D(RotationZYX(0,-M_PI/2-phi,-M_PI/2), Position(x, y, s*(zstart+dz) ))); pv.addPhysVolID("side", s).addPhysVolID("layer", ring_num).addPhysVolID("module", mod_count[ring_num] + k); module.setPlacement(pv); for(size_t ic=0; ic<sensVols.size(); ++ic) { PlacedVolume sens_pv = sensVols[ic]; DetElement comp_elt(module, sens_pv.volume().name(), det_id); comp_elt.setPlacement(sens_pv); std::cout << "Name: " << e_name << "_" << sens_pv.volume().name() << std::endl; std::cout << " ID: side " << s << ", layer " << ring_num << ", module " << mod_count[ring_num] + k << ", sensor" << ic+1 << std::endl; } } dz = -dz; phi += iphi; } mod_count[ring_num] += nmodules; ++ring_num; } } std::cout << "Number of modules per 'layer':" << std::endl; for(int ii=0; ii<12; ii++){ std::cout << " mod_count[" << ii << "] = " << mod_count[ii] << std::endl; } return sdet; }