diff --git a/DDDetectors/include/DDDetectors/OtherDetectorHelpers.h b/DDDetectors/include/DDDetectors/OtherDetectorHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..16457c04591501aa2b195ee92019bf0cd4dceed9 --- /dev/null +++ b/DDDetectors/include/DDDetectors/OtherDetectorHelpers.h @@ -0,0 +1,114 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +//========================================================================== +#ifndef Other_Helpers_hh +#define Other_Helpers_hh 1 + +#include "DD4hep/Printout.h" + +#include <iostream> +#include <map> +#include <stdexcept> + +namespace ODH {//OtherDetectorHelpers + + typedef enum { // These constants are also used in the MySQL database: + kCenter = 0, // centered on the z-axis + kUpstream = 1, // on the upstream branch, rotated by half the crossing angle + kDnstream = 2, // on the downstream branch, rotated by half the crossing angle + kPunchedCenter = 3, // centered, with one or two inner holes + kPunchedUpstream = 4, // on the upstream branch, with two inner holes + kPunchedDnstream = 5, // on the downstrem branch, with two inner holes + kUpstreamClippedFront = 6, // upstream, with the front face parallel to the xy-plane + kDnstreamClippedFront = 7, // downstream, with the front face parallel to the xy-plane + kUpstreamClippedRear = 8, // upstream, with the rear face parallel to the xy-plane + kDnstreamClippedRear = 9, // downstream, with the rear face parallel to the xy-plane + kUpstreamClippedBoth = 10, // upstream, with both faces parallel to the xy-plane + kDnstreamClippedBoth = 11, // downstream, with both faces parallel to the xy-plane + kUpstreamSlicedFront = 12, // upstream, with the front face parallel to a tilted piece + kDnstreamSlicedFront = 13, // downstream, with the front face parallel to a tilted piece + kUpstreamSlicedRear = 14, // upstream, with the rear face parallel to a tilted piece + kDnstreamSlicedRear = 15, // downstream, with the rear face parallel to a tilted piece + kUpstreamSlicedBoth = 16, // upstream, with both faces parallel to a tilted piece + kDnstreamSlicedBoth = 17 // downstream, with both faces parallel to a tilted piece + } ECrossType; + + + + static ECrossType getCrossType( std::string const & type) { + + std::map< std::string, ODH::ECrossType > CrossTypes; + CrossTypes["Center"] = ODH::kCenter ; + CrossTypes["Upstream"] = ODH::kUpstream ; + CrossTypes["Dnstream"] = ODH::kDnstream ; + CrossTypes["PunchedCenter"] = ODH::kPunchedCenter ; + CrossTypes["PunchedUpstream"] = ODH::kPunchedUpstream ; + CrossTypes["PunchedDnstream"] = ODH::kPunchedDnstream ; + CrossTypes["UpstreamClippedFront"] = ODH::kUpstreamClippedFront ; + CrossTypes["DnstreamClippedFront"] = ODH::kDnstreamClippedFront ; + CrossTypes["UpstreamClippedRear"] = ODH::kUpstreamClippedRear ; + CrossTypes["DnstreamClippedRear"] = ODH::kDnstreamClippedRear ; + CrossTypes["UpstreamClippedBoth"] = ODH::kUpstreamClippedBoth ; + CrossTypes["DnstreamClippedBoth"] = ODH::kDnstreamClippedBoth ; + CrossTypes["UpstreamSlicedFront"] = ODH::kUpstreamSlicedFront ; + CrossTypes["DnstreamSlicedFront"] = ODH::kDnstreamSlicedFront ; + CrossTypes["UpstreamSlicedRear"] = ODH::kUpstreamSlicedRear ; + CrossTypes["DnstreamSlicedRear"] = ODH::kDnstreamSlicedRear ; + CrossTypes["UpstreamSlicedBoth"] = ODH::kUpstreamSlicedBoth ; + CrossTypes["DnstreamSlicedBoth"] = ODH::kDnstreamSlicedBoth ; + + std::map < std::string, ODH::ECrossType>::const_iterator ct = CrossTypes.find(type); + if ( ct == CrossTypes.end() ) { + throw std::runtime_error("Unknown Crossing Type for this geometry"); + } + return ct->second; + } + + static bool checkForSensibleGeometry(double crossingAngle, ECrossType crossType) { + if (crossingAngle == 0 && crossType != kCenter) { + printout(DD4hep::ERROR, "Mask/Beampip", "You are trying to build a crossing geometry without a crossing angle.\n" ); + printout(DD4hep::ERROR, "Mask/Beampip", "This is probably not what you want - better check your geometry data!"); + return false; // premature exit, dd4hep will abort now + } + return true; + } + + + static double getCurrentAngle( double crossingAngle, ECrossType crossType ) { + double tmpAngle; + switch (crossType) { + case kUpstream: + case kPunchedUpstream: + case kUpstreamClippedFront: + case kUpstreamClippedRear: + case kUpstreamClippedBoth: + case kUpstreamSlicedFront: + case kUpstreamSlicedRear: + case kUpstreamSlicedBoth: + tmpAngle = -crossingAngle; break; + case kDnstream: + case kPunchedDnstream: + case kDnstreamClippedFront: + case kDnstreamClippedRear: + case kDnstreamClippedBoth: + case kDnstreamSlicedFront: + case kDnstreamSlicedRear: + case kDnstreamSlicedBoth: + tmpAngle = +crossingAngle; break; + default: + tmpAngle = 0; break; + } + + return tmpAngle; + } + +}//namespace + +#endif // Other_Helpers_hh diff --git a/DDDetectors/src/Beampipe_o1_v01_geo.cpp b/DDDetectors/src/Beampipe_o1_v01_geo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..508c11a9a87047abe76822db2b316881e7d89ce3 --- /dev/null +++ b/DDDetectors/src/Beampipe_o1_v01_geo.cpp @@ -0,0 +1,622 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +//========================================================================== + +#include "DDDetectors/OtherDetectorHelpers.h" + +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/DD4hepUnits.h" +#include "DD4hep/DetType.h" +#include "DD4hep/Printout.h" + +#include "DDRec/DetectorData.h" +#include "DDRec/Surface.h" + +#include "XML/Utilities.h" + +#include <cmath> +#include <map> +#include <string> + +using DD4hep::Geometry::Transform3D; +using DD4hep::Geometry::Position; +using DD4hep::Geometry::RotationY; +using DD4hep::Geometry::RotateY; +using DD4hep::Geometry::ConeSegment; +using DD4hep::Geometry::SubtractionSolid; +using DD4hep::Geometry::Material; +using DD4hep::Geometry::Volume; +using DD4hep::Geometry::Solid; +using DD4hep::Geometry::Tube; + +using DD4hep::DDRec::Vector3D; +using DD4hep::DDRec::VolCylinder; +using DD4hep::DDRec::VolCone; +using DD4hep::DDRec::SurfaceType; + +/// helper class for a simple cylinder surface parallel to z with a given length - used as IP layer +class SimpleCylinderImpl : public DD4hep::DDRec::VolCylinderImpl{ + double _half_length ; +public: + /// standard c'tor with all necessary arguments - origin is (0,0,0) if not given. + SimpleCylinderImpl( DD4hep::Geometry::Volume vol, DDSurfaces::SurfaceType type, + double thickness_inner ,double thickness_outer, DDSurfaces::Vector3D origin ) : + DD4hep::DDRec::VolCylinderImpl( vol, type, thickness_inner, thickness_outer, origin ), + _half_length(0){ + } + void setHalfLength( double half_length){ + _half_length = half_length ; + } + void setID( DD4hep::long64 id ) { _id = id ; + } + // overwrite to include points inside the inner radius of the barrel + bool insideBounds(const DDSurfaces::Vector3D& point, double epsilon) const { + return ( std::abs( point.rho() - origin().rho() ) < epsilon && std::abs( point.z() ) < _half_length ) ; + } + + virtual std::vector< std::pair<DDSurfaces::Vector3D, DDSurfaces::Vector3D> > getLines(unsigned nMax=100){ + + std::vector< std::pair<DDSurfaces::Vector3D, DDSurfaces::Vector3D> > lines ; + + lines.reserve( nMax ) ; + + Vector3D zv( 0. , 0. , _half_length ) ; + double r = _o.rho() ; + + unsigned n = nMax / 4 ; + double dPhi = 2.* ROOT::Math::Pi() / double( n ) ; + + for( unsigned i = 0 ; i < n ; ++i ) { + + Vector3D rv0( r*sin( i *dPhi ) , r*cos( i *dPhi ) , 0. ) ; + Vector3D rv1( r*sin( (i+1)*dPhi ) , r*cos( (i+1)*dPhi ) , 0. ) ; + + Vector3D pl0 = zv + rv0 ; + Vector3D pl1 = zv + rv1 ; + Vector3D pl2 = -zv + rv1 ; + Vector3D pl3 = -zv + rv0 ; + + lines.push_back( std::make_pair( pl0, pl1 ) ) ; + lines.push_back( std::make_pair( pl1, pl2 ) ) ; + lines.push_back( std::make_pair( pl2, pl3 ) ) ; + lines.push_back( std::make_pair( pl3, pl0 ) ) ; + } + return lines; + } +}; + +class SimpleCylinder : public DD4hep::DDRec::VolSurface{ +public: + SimpleCylinder( DD4hep::Geometry::Volume vol, DD4hep::DDRec::SurfaceType type, double thickness_inner , + double thickness_outer, Vector3D origin ) : + DD4hep::DDRec::VolSurface( new SimpleCylinderImpl( vol, type, thickness_inner , thickness_outer, origin ) ) { + } + SimpleCylinderImpl* operator->() { return static_cast<SimpleCylinderImpl*>( _surf ) ; } +} ; + + +static DD4hep::Geometry::Ref_t create_element(DD4hep::Geometry::LCDD& lcdd, + xml_h element, + DD4hep::Geometry::SensitiveDetector /*sens*/) { + + printout(DD4hep::DEBUG,"DD4hep_Beampipe", "Creating Beampipe" ) ; + + //Access to the XML File + xml_det_t xmlBeampipe = element; + const std::string name = xmlBeampipe.nameStr(); + + + DD4hep::Geometry::DetElement tube( name, xmlBeampipe.id() ) ; + + // --- create an envelope volume and position it into the world --------------------- + + Volume envelope = DD4hep::XML::createPlacedEnvelope( lcdd, element , tube ) ; + + DD4hep::XML::setDetectorTypeFlag( element, tube ) ; + + if( lcdd.buildType() == DD4hep::BUILD_ENVELOPE ) return tube ; + + //----------------------------------------------------------------------------------- + + + DD4hep::DDRec::ConicalSupportData* beampipeData = new DD4hep::DDRec::ConicalSupportData ; + + //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 = lcdd.material(xmlSection.materialStr()); + const std::string volName = "tube_" + xmlSection.nameStr(); + + std::stringstream pipeInfo; + pipeInfo << 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(); + + printout(DD4hep::INFO, "DD4hep_Beampipe", pipeInfo.str() ); + + if( crossType == ODH::kCenter ) { // store only the central sections ! + DD4hep::DDRec::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 = lcdd.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 ); + + DD4hep::DDRec::volSurfaceList( tube )->push_back( cylSurf1 ); + DD4hep::DDRec::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 ); + + DD4hep::DDRec::volSurfaceList( tube )->push_back( conSurf1 ); + DD4hep::DDRec::volSurfaceList( tube )->push_back( conSurf2 ); + + } + + if( rInnerStart < min_radius ) min_radius = rInnerStart ; + if( rOuterStart < min_radius ) min_radius = rOuterStart ; + } + + wallLog.setVisAttributes(lcdd, "TubeVis"); + wallLog2.setVisAttributes(lcdd, "TubeVis"); + tubeLog.setVisAttributes(lcdd, "VacVis"); + tubeLog2.setVisAttributes(lcdd, "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(lcdd, "TubeVis"); + wallLog1.setVisAttributes(lcdd, "TubeVis"); + tubeLog0.setVisAttributes(lcdd, "VacVis"); + tubeLog1.setVisAttributes(lcdd, "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(lcdd, "TubeVis"); + wallLog1.setVisAttributes(lcdd, "TubeVis"); + + tubeLog0.setVisAttributes(lcdd, "VacVis"); + tubeLog1.setVisAttributes(lcdd, "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(lcdd, "TubeVis"); + wallLog1.setVisAttributes(lcdd, "TubeVis"); + + tubeLog0.setVisAttributes(lcdd, "VacVis"); + tubeLog1.setVisAttributes(lcdd, "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(lcdd, "TubeVis"); + wallLog1.setVisAttributes(lcdd, "TubeVis"); + + tubeLog0.setVisAttributes(lcdd, "VacVis"); + tubeLog1.setVisAttributes(lcdd, "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(lcdd, "TubeVis"); + wallLog1.setVisAttributes(lcdd, "TubeVis"); + + tubeLog0.setVisAttributes(lcdd, "VacVis"); + tubeLog1.setVisAttributes(lcdd, "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 ) ; + DD4hep::DDRec::volSurfaceList( tube )->push_back( ipCylSurf ) ; + + tube.addExtension< DD4hep::DDRec::ConicalSupportData >( beampipeData ) ; + + //-------------------------------------- + + tube.setVisAttributes( lcdd, xmlBeampipe.visStr(), envelope ); + + // // tube.setPlacement(pv); + + return tube; +} +DECLARE_DETELEMENT(DD4hep_Beampipe_o1_v01,create_element) diff --git a/DDDetectors/src/Mask_o1_v01_geo.cpp b/DDDetectors/src/Mask_o1_v01_geo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc6b56114ef0a93db67e649f4b6284bd7b51ea96 --- /dev/null +++ b/DDDetectors/src/Mask_o1_v01_geo.cpp @@ -0,0 +1,232 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +//========================================================================== +#include "DDDetectors/OtherDetectorHelpers.h" + +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "DD4hep/DD4hepUnits.h" + +#include <cmath> +#include <string> + +using DD4hep::Geometry::Transform3D; +using DD4hep::Geometry::Position; +using DD4hep::Geometry::RotationY; +using DD4hep::Geometry::RotateY; +using DD4hep::Geometry::ConeSegment; +using DD4hep::Geometry::SubtractionSolid; +using DD4hep::Geometry::Material; +using DD4hep::Geometry::Volume; +using DD4hep::Geometry::Solid; +using DD4hep::Geometry::Tube; +using DD4hep::Geometry::PlacedVolume; +using DD4hep::Geometry::Assembly; + +static DD4hep::Geometry::Ref_t create_element(DD4hep::Geometry::LCDD& lcdd, + xml_h xmlHandle, + DD4hep::Geometry::SensitiveDetector /*sens*/) { + + printout(DD4hep::DEBUG,"DD4hep_Mask", "Creating Mask" ) ; + + //Access to the XML File + xml_det_t xmlMask = xmlHandle; + const std::string name = xmlMask.nameStr(); + + //-------------------------------- + Assembly envelope( name + "_assembly" ) ; + //-------------------------------- + + DD4hep::Geometry::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 thickness = rOuterStart - rInnerStart; + Material sectionMat = lcdd.material(xmlSection.materialStr()); + const std::string volName = "tube_" + xmlSection.nameStr(); + + std::stringstream pipeInfo; + pipeInfo << 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(); + + printout(DD4hep::INFO, "DD4hep_Mask", pipeInfo.str() ); + + // 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_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 + 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, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd , phi1, phi2); + + // tube consists of vacuum + Volume tubeLog( volName, tubeSolid, material ) ; + tubeLog.setVisAttributes(lcdd, 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(lcdd, xmlMask.visStr() ); + tubeLog1.setVisAttributes(lcdd, 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(lcdd, xmlMask.visStr() ); + tubeLog1.setVisAttributes(lcdd, 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 = lcdd.pickMotherVolume( tube ) ; + PlacedVolume pv(mother.placeVolume(envelope)); + pv.addPhysVolID( "system", xmlMask.id() ) ; //.addPhysVolID("side", 0 ) ; + + tube.setVisAttributes( lcdd, xmlMask.visStr(), envelope ); + + tube.setPlacement(pv); + + return tube; +} +DECLARE_DETELEMENT(DD4hep_Mask_o1_v01,create_element) diff --git a/DDDetectors/src/Solenoid_o1_v01_gep.cpp b/DDDetectors/src/Solenoid_o1_v01_gep.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af085baebf95829a45903344b44012627874b52e --- /dev/null +++ b/DDDetectors/src/Solenoid_o1_v01_gep.cpp @@ -0,0 +1,137 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +//========================================================================== + +#include "DDRec/DetectorData.h" + +#include "DD4hep/DetFactoryHelper.h" + +#include "XML/Layering.h" +#include "XML/Utilities.h" + + +#include "TGeoTrd2.h" + +using namespace std; +using namespace DD4hep; +using namespace DD4hep::Geometry; + +static Ref_t create_detector(LCDD& 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); + + + // --- create an envelope volume and position it into the world --------------------- + + Volume envelope = XML::createPlacedEnvelope( lcdd, e , sdet ) ; + XML::setDetectorTypeFlag( e, sdet ) ; + + if( lcdd.buildType() == BUILD_ENVELOPE ) return sdet ; + + //----------------------------------------------------------------------------------- + + + Material air = lcdd.air(); + PlacedVolume pv; + int n = 0; + + //added code by Thorben Quast for event display + DDRec::LayeredCalorimeterData* solenoidData = new DDRec::LayeredCalorimeterData; + solenoidData->inner_symmetry = 0; + solenoidData->outer_symmetry = 0; + solenoidData->layoutType = DDRec::LayeredCalorimeterData::BarrelLayout ; + + double inner_radius= std::numeric_limits<double>::max(); + double outer_radius= 0; + + double detZ= 0.; + + for(xml_coll_t i(x_det,_U(layer)); i; ++i, ++n) { + xml_comp_t x_layer = i; + string l_name = det_name+_toString(n,"_layer%d"); + double z = x_layer.outer_z(); + double rmin = x_layer.inner_r(); + double r = rmin; + DetElement layer(sdet,_toString(n,"layer%d"),x_layer.id()); + Tube l_tub (rmin,2*rmin,z); + Volume l_vol(l_name,l_tub,air); + int m = 0; + + + for(xml_coll_t j(x_layer,_U(slice)); j; ++j, ++m) { + xml_comp_t x_slice = j; + Material mat = lcdd.material(x_slice.materialStr()); + string s_name= l_name+_toString(m,"_slice%d"); + double thickness = x_slice.thickness(); + + //NN: These probably need to be fixed and ced modified to read the extent, rather than the layer + //added code by Thorben Quast for event display + DDRec::LayeredCalorimeterData::Layer solenoidLayer; + solenoidLayer.distance = r; + + solenoidLayer.inner_thickness = thickness/2.; + solenoidLayer.outer_thickness = solenoidLayer.inner_thickness ; + + solenoidLayer.cellSize0 = 0; //equivalent to + solenoidLayer.cellSize1 = z; //half extension along z-axis + solenoidData->layers.push_back(solenoidLayer); + + Tube s_tub(r,r+thickness,z,2*M_PI); + Volume s_vol(s_name, s_tub, mat); + + r += thickness; + if ( x_slice.isSensitive() ) { + sens.setType("tracker"); + s_vol.setSensitiveDetector(sens); + } + // Set Attributes + s_vol.setAttributes(lcdd,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr()); + pv = l_vol.placeVolume(s_vol); + // Slices have no extra id. Take the ID of the layer! + pv.addPhysVolID("slice",m); + } + l_tub.setDimensions(rmin,r,z); + + if (rmin < inner_radius) + inner_radius = rmin; + + if (z>detZ) + detZ = z; + + if (r>outer_radius) + outer_radius = r; + + l_vol.setVisAttributes(lcdd,x_layer.visStr()); + + pv = envelope.placeVolume(l_vol); + pv.addPhysVolID("layer",n); + layer.setPlacement(pv); + } + if ( x_det.hasAttr(_U(combineHits)) ) { + sdet.setCombineHits(x_det.combineHits(),sens); + } + + /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm. + solenoidData->extent[0] = inner_radius ; + solenoidData->extent[1] = outer_radius ; + solenoidData->extent[2] = 0. ; + solenoidData->extent[3] = detZ; + + //added code by Thorben Quast for event display + sdet.addExtension< DDRec::LayeredCalorimeterData >( solenoidData ) ; + + + return sdet; + +} + +DECLARE_DETELEMENT(DD4hep_Solenoid_o1_v01,create_detector)