static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; xml_dim_t dim = x_det.dimensions(); Material air = description.air(); string det_name = x_det.nameStr(); DetElement sdet (det_name,x_det.id()); double z = dim.outer_z(); double rmin = dim.inner_r(); double r = rmin; int n = 0; Tube envelope(rmin,2*rmin,2*z); Volume envelopeVol(det_name+"_envelope",envelope,air); for(xml_coll_t c(x_det,_U(layer)); c; ++c) { xml_comp_t x_layer = c; for(int i=0, im=0, repeat=x_layer.repeat(); i<repeat; ++i, im=0) { string layer_name = det_name + _toString(n,"_layer%d"); double rlayer = r; Tube layer_tub(rmin,rlayer,2*z); Volume layer_vol(layer_name,layer_tub,air); for(xml_coll_t l(x_layer,_U(slice)); l; ++l, ++im) { xml_comp_t x_slice = l; double router = r + x_slice.thickness(); Material slice_mat = description.material(x_slice.materialStr()); string slice_name = layer_name + _toString(im,"slice%d"); Tube slice_tube(r,router,z*2); Volume slice_vol (slice_name,slice_tube,slice_mat); if ( x_slice.isSensitive() ) { sens.setType("calorimeter"); slice_vol.setSensitiveDetector(sens); } r = router; slice_vol.setAttributes(description,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr()); // Instantiate physical volume layer_vol.placeVolume(slice_vol); } layer_vol.setVisAttributes(description,x_layer.visStr()); layer_tub.setDimensions(rlayer,r,z*2,0,2*M_PI); PlacedVolume layer_physvol = envelopeVol.placeVolume(layer_vol); layer_physvol.addPhysVolID("layer",n); ++n; } } envelope.setDimensions(rmin,r,2*z); // Set region of slice envelopeVol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); PlacedVolume physvol = description.pickMotherVolume(sdet).placeVolume(envelopeVol); physvol.addPhysVolID("system",sdet.id()).addPhysVolID(_U(barrel),0); sdet.setPlacement(physvol); return sdet; }
static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; Layering layering(x_det); //xml_comp_t staves = x_det.staves(); xml_dim_t dim = x_det.dimensions(); string det_name = x_det.nameStr(); Material air = description.air(); double totalThickness = layering.totalThickness(); int numSides = dim.numsides(); double detZ = dim.z(); double rmin = dim.rmin(); double rmax = dim.rmax(); DetElement sdet(det_name,x_det.id()); DetElement stave("stave1",x_det.id()); Volume motherVol = description.pickMotherVolume(sdet); PolyhedraRegular polyhedron(numSides,0.,rmin,detZ+10); Tube tube(0.,rmin+totalThickness,detZ/2,0,2*M_PI); SubtractionSolid sub(tube,polyhedron); Volume envelopeVol(det_name+"_envelope",sub,air); // Add the subdetector envelope to the structure. double externalAngle = 2*M_PI/numSides; double halfExternalAngle = externalAngle/2; double tan_external = std::tan(externalAngle); double tan_half = std::tan(halfExternalAngle); double half_polyFace = rmin * tan_half; double innerFaceLen = std::sqrt(rmax*rmax - rmin*rmin)+half_polyFace; //double outerFaceLen = (rmin+totalThickness) * tan_external; double staveThickness = totalThickness; // Trapezoid staveTrdOuter(innerFaceLen/2,outerFaceLen/2,detZ/2,detZ/2,staveThickness/2); // Volume staveOuterVol(det_name+"_stave",staveTrdOuter,air); Assembly staveOuterVol(det_name+"_stave"); // Trapezoid staveTrdInner(innerFaceLen/2-gap,outerFaceLen/2-gap,detZ/2,detZ/2,staveThickness/2); // Volume staveInnerVol(det_name+"_inner",staveTrdInner,air); //double layerOuterAngle = (M_PI-externalAngle)/2; //double layerexternalAngle = (M_PI/2 - layerOuterAngle); double layer_pos_z = -(staveThickness / 2); double layer_pos_x = 0; double layer_dim_x = innerFaceLen/2; int layer_num = 1; double layerR = rmin; // Set envelope volume attributes. envelopeVol.setAttributes(description,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; int repeat = x_layer.repeat(); // Get number of times to repeat this layer. const Layer* lay = layering.layer(layer_num-1); // Get the layer from the layering engine. // Loop over repeats for this layer. for (int j = 0; j < repeat; j++) { string layer_name = det_name+_toString(layer_num,"_layer%d"); double layer_thickness = lay->thickness(); DetElement layer(stave,_toString(layer_num,"layer%d"),x_det.id()); // Layer position in Z within the stave. layer_pos_z += layer_thickness / 2; // Layer box & volume Volume layer_vol(layer_name, Box(layer_dim_x,detZ/2,layer_thickness/2), air); // Create the slices (sublayers) within the layer. double slice_pos_z = -(layer_thickness / 2); int slice_number = 1; 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 = description.material(x_slice.materialStr()); DetElement slice(layer,_toString(slice_number,"slice%d"),x_det.id()); slice_pos_z += slice_thickness / 2; // Slice volume & box Volume slice_vol(slice_name,Box(layer_dim_x,detZ/2,slice_thickness/2),slice_material); if ( x_slice.isSensitive() ) { sens.setType("calorimeter"); slice_vol.setSensitiveDetector(sens); } // Set region, limitset, and vis. slice_vol.setAttributes(description,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(description,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr()); // Layer physical volume. PlacedVolume layer_phv = staveOuterVol.placeVolume(layer_vol,Position((layer_dim_x+layer_pos_x-half_polyFace),0,layer_pos_z)); layer_phv.addPhysVolID("layer",layer_num); layer.setPlacement(layer_phv); layerR += layer_thickness; // Increment the layer X dimension. layer_pos_x = (layerR-rmin)/tan_external; layer_dim_x = (std::sqrt(rmax*rmax - layerR*layerR)+half_polyFace - layer_pos_x)/2.0; cout<<"Rmin: "<< rmin<<" Rmax: "<<rmax<<" half_polyFace: "<<half_polyFace<<" Layer " <<layer_num<<" layerR: "<<layerR<<" layer_dim_x:" <<layer_dim_x<<endl; // Increment the layer Z position. layer_pos_z += layer_thickness / 2; // Increment the layer number. ++layer_num; } } // Add stave inner physical volume to outer stave volume. // staveOuterVol.placeVolume(staveInnerVol); //not needed // Set the vis attributes of the outer stave section. // stave.setVisAttributes(description,staves.visStr(),staveOuterVol); //not applicable for Assembly // Place the staves. placeStaves(sdet,stave,rmin,numSides,totalThickness,envelopeVol,externalAngle,staveOuterVol); double z_offset = dim.hasAttr(_U(z_offset)) ? dim.z_offset() : 0.0; Transform3D transform(RotationZ(M_PI-(M_PI/numSides)),Translation3D(0,0,z_offset)); PlacedVolume env_phv = motherVol.placeVolume(envelopeVol,transform); env_phv.addPhysVolID("system", sdet.id()); env_phv.addPhysVolID("barrel", 0); sdet.setPlacement(env_phv); //sdet.addExtension<LayerStack>(new PolyhedralCalorimeterLayerStack(sdet)); 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& description, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; Material air = description.air(); string det_name = x_det.nameStr(); bool reflect = x_det.reflect(); DetElement sdet(det_name,x_det.id()); Assembly assembly(det_name); PlacedVolume pv; int l_num = 0; for(xml_coll_t i(x_det,_U(layer)); i; ++i, ++l_num) { xml_comp_t x_layer = i; string l_nam = det_name+_toString(l_num,"_layer%d"); double zmin = x_layer.inner_z(); double rmin = x_layer.inner_r(); double rmax = x_layer.outer_r(); double z = zmin, layerWidth = 0.; int s_num = 0; for(xml_coll_t j(x_layer,_U(slice)); j; ++j) { double thickness = xml_comp_t(j).thickness(); layerWidth += thickness; } Tube l_tub(rmin,rmax,layerWidth,2*M_PI); Volume l_vol(l_nam,l_tub,air); l_vol.setVisAttributes(description,x_layer.visStr()); for(xml_coll_t j(x_layer,_U(slice)); j; ++j, ++s_num) { xml_comp_t x_slice = j; double thick = x_slice.thickness(); Material mat = description.material(x_slice.materialStr()); string s_nam = l_nam+_toString(s_num,"_slice%d"); Volume s_vol(s_nam, Tube(rmin,rmax,thick), mat); if ( x_slice.isSensitive() ) { sens.setType("tracker"); s_vol.setSensitiveDetector(sens); } s_vol.setAttributes(description,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr()); pv = l_vol.placeVolume(s_vol,Position(0,0,z-zmin-layerWidth/2+thick/2)); pv.addPhysVolID("slice",s_num); } DetElement layer(sdet,l_nam+"_pos",l_num); pv = assembly.placeVolume(l_vol,Position(0,0,zmin+layerWidth/2.)); pv.addPhysVolID("layer",l_num); pv.addPhysVolID("barrel",1); layer.setPlacement(pv); if ( reflect ) { pv = assembly.placeVolume(l_vol,Transform3D(RotationY(M_PI),Position(0,0,-zmin-layerWidth/2))); pv.addPhysVolID("layer",l_num); pv.addPhysVolID("barrel",2); DetElement layerR = layer.clone(l_nam+"_neg"); sdet.add(layerR.setPlacement(pv)); } } if ( x_det.hasAttr(_U(combineHits)) ) { sdet.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens); } pv = description.pickMotherVolume(sdet).placeVolume(assembly); pv.addPhysVolID("system", x_det.id()); // Set the subdetector system ID. sdet.setPlacement(pv); return sdet; }