Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:14:01

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 //==========================================================================
0011 
0012 #include "DDDetectors/OtherDetectorHelpers.h"
0013 
0014 #include "DD4hep/DetFactoryHelper.h"
0015 #include "DD4hep/DD4hepUnits.h"
0016 #include "DD4hep/DetType.h"
0017 #include "DD4hep/Printout.h"
0018 
0019 #include "DDRec/DetectorData.h"
0020 #include "DDRec/Surface.h"
0021 
0022 #include "XML/Utilities.h"
0023 
0024 #include <cmath>
0025 #include <map>
0026 #include <string>
0027 
0028 using dd4hep::Transform3D;
0029 using dd4hep::Position;
0030 using dd4hep::RotationY;
0031 using dd4hep::RotateY;
0032 using dd4hep::ConeSegment;
0033 using dd4hep::SubtractionSolid;
0034 using dd4hep::Material;
0035 using dd4hep::Volume;
0036 using dd4hep::Solid;
0037 using dd4hep::Tube;
0038 namespace units = dd4hep;
0039 using dd4hep::rec::Vector3D;
0040 using dd4hep::rec::VolCylinder;
0041 using dd4hep::rec::VolCone;
0042 using dd4hep::rec::SurfaceType;
0043 
0044 /// helper class for a simple cylinder surface parallel to z with a given length - used as IP layer
0045 class SimpleCylinderImpl : public  dd4hep::rec::VolCylinderImpl{
0046   double _half_length ;
0047 public:
0048   /// standard c'tor with all necessary arguments - origin is (0,0,0) if not given.
0049   SimpleCylinderImpl( dd4hep::Volume vol, SurfaceType type,
0050               double thickness_inner ,double thickness_outer,  Vector3D origin ) :
0051     dd4hep::rec::VolCylinderImpl( vol,  type, thickness_inner, thickness_outer,   origin ),
0052     _half_length(0){
0053   }
0054   void setHalfLength( double half_length){
0055     _half_length = half_length ;
0056   }
0057   void setID( dd4hep::FieldID id ) { _id = id ;
0058   }
0059   // overwrite to include points inside the inner radius of the barrel
0060   bool insideBounds(const Vector3D& point, double epsilon) const {
0061     return ( std::abs( point.rho() - origin().rho() ) < epsilon && std::abs( point.z() ) < _half_length ) ;
0062   }
0063 
0064   virtual std::vector< std::pair<Vector3D, Vector3D> > getLines(unsigned nMax=100){
0065 
0066     std::vector< std::pair<Vector3D, Vector3D> >  lines ;
0067 
0068     lines.reserve( nMax ) ;
0069 
0070     Vector3D zv( 0. , 0. , _half_length ) ;
0071     double r = _o.rho() ;
0072 
0073     unsigned n = nMax / 4 ;
0074     double dPhi = 2.* ROOT::Math::Pi() / double( n ) ;
0075 
0076     for( unsigned i = 0 ; i < n ; ++i ) {
0077 
0078       Vector3D rv0(  r*sin(  i   *dPhi ) , r*cos(  i   *dPhi )  , 0. ) ;
0079       Vector3D rv1(  r*sin( (i+1)*dPhi ) , r*cos( (i+1)*dPhi )  , 0. ) ;
0080 
0081       Vector3D pl0 =  zv + rv0 ;
0082       Vector3D pl1 =  zv + rv1 ;
0083       Vector3D pl2 = -zv + rv1  ;
0084       Vector3D pl3 = -zv + rv0 ;
0085 
0086       lines.push_back( std::make_pair( pl0, pl1 ) ) ;
0087       lines.push_back( std::make_pair( pl1, pl2 ) ) ;
0088       lines.push_back( std::make_pair( pl2, pl3 ) ) ;
0089       lines.push_back( std::make_pair( pl3, pl0 ) ) ;
0090     }
0091     return lines;
0092   }
0093 };
0094 
0095 class SimpleCylinder : public dd4hep::rec::VolSurface{
0096 public:
0097   SimpleCylinder( dd4hep::Volume vol, dd4hep::rec::SurfaceType type, double thickness_inner ,
0098           double thickness_outer,  Vector3D origin ) :
0099     dd4hep::rec::VolSurface( new SimpleCylinderImpl( vol,  type,  thickness_inner , thickness_outer, origin ) ) {
0100   }
0101   SimpleCylinderImpl* operator->() { return static_cast<SimpleCylinderImpl*>( _surf ) ; }
0102 } ;
0103 
0104 
0105 static dd4hep::Ref_t create_element(dd4hep::Detector& description,
0106                           xml_h element,
0107                           dd4hep::SensitiveDetector /*sens*/) {
0108 
0109   printout(dd4hep::DEBUG,"DD4hep_Beampipe", "Creating Beampipe" ) ;
0110 
0111   //Access to the XML File
0112   xml_det_t xmlBeampipe = element;
0113   const std::string name = xmlBeampipe.nameStr();
0114   bool nocore  = xmlBeampipe.nocore(false);
0115 
0116   dd4hep::DetElement tube(  name, xmlBeampipe.id()  ) ;
0117 
0118   // --- create an envelope volume and position it into the world ---------------------
0119 
0120   Volume envelope = dd4hep::xml::createPlacedEnvelope( description,  element , tube ) ;
0121 
0122   dd4hep::xml::setDetectorTypeFlag( element, tube ) ;
0123 
0124   if( description.buildType() == dd4hep::BUILD_ENVELOPE ) return tube ;
0125 
0126   //-----------------------------------------------------------------------------------
0127 
0128 
0129   dd4hep::rec::ConicalSupportData* beampipeData = new dd4hep::rec::ConicalSupportData ;
0130 
0131   //DD4hep/TGeo seems to need rad (as opposed to the manual)
0132   const double phi1 = 0 ;
0133   const double phi2 = 360.0*units::degree;
0134 
0135   //Parameters we have to know about
0136   dd4hep::xml::Component xmlParameter = xmlBeampipe.child(_Unicode(parameter));
0137   const double crossingAngle  = xmlParameter.attr< double >(_Unicode(crossingangle))*0.5; //  only half the angle
0138 
0139 
0140   double min_radius = 1.e99 ;
0141 
0142   for(xml_coll_t c( xmlBeampipe ,Unicode("section")); c; ++c) {
0143 
0144     xml_comp_t xmlSection( c );
0145 
0146     ODH::ECrossType crossType = ODH::getCrossType(xmlSection.attr< std::string >(_Unicode(type)));
0147     const double zStart       = xmlSection.attr< double > (_Unicode(start));
0148     const double zEnd         = xmlSection.attr< double > (_Unicode(end));
0149     const double rInnerStart  = xmlSection.attr< double > (_Unicode(rMin1));
0150     const double rInnerEnd    = xmlSection.attr< double > (_Unicode(rMin2));
0151     const double rOuterStart  = xmlSection.attr< double > (_Unicode(rMax1));
0152     const double rOuterEnd    = xmlSection.attr< double > (_Unicode(rMax2));
0153     const double thickness    = rOuterStart - rInnerStart;
0154     Material sectionMat  = description.material(xmlSection.materialStr());
0155     const std::string volName      = "tube_" + xmlSection.nameStr();
0156 
0157     std::stringstream pipeInfo;
0158     pipeInfo << std::setw(8) << zStart      /units::mm
0159          << std::setw(8) << zEnd        /units::mm
0160          << std::setw(8) << rInnerStart /units::mm
0161          << std::setw(8) << rInnerEnd   /units::mm
0162          << std::setw(8) << rOuterStart /units::mm
0163          << std::setw(8) << rOuterEnd   /units::mm
0164          << std::setw(8) << thickness   /units::mm
0165          << std::setw(8) << crossType
0166          << std::setw(35) << volName
0167          << std::setw(15) << sectionMat.name();
0168 
0169     printout(dd4hep::INFO, "DD4hep_Beampipe", pipeInfo.str() );
0170 
0171     if( crossType == ODH::kCenter ) { // store only the central sections !
0172       dd4hep::rec::ConicalSupportData::Section section ;
0173       section.rInner = rInnerStart ;
0174       section.rOuter = rOuterStart ;
0175       section.zPos   = zStart ;
0176       beampipeData->sections.push_back( section ) ;
0177     }
0178 
0179     // things which can be calculated immediately
0180     const double zHalf       = fabs(zEnd - zStart) * 0.5; // half z length of the cone
0181     const double zPosition   = fabs(zEnd + zStart) * 0.5; // middle z position
0182     Material coreMaterial    = description.material("beam"); // always the same
0183     Material wallMaterial    = sectionMat;
0184 
0185     // this could mess up your geometry, so better check it
0186     if (not checkForSensibleGeometry(crossingAngle, crossType)){
0187 
0188       throw std::runtime_error( " Beampipe_o1_v01_geo.cpp : checkForSensibleGeometry() failed " ) ;
0189       //      return false;
0190     }
0191     const double rotateAngle = getCurrentAngle(crossingAngle, crossType); // for the placement at +z (better make it const now)
0192     const double mirrorAngle = M_PI - rotateAngle; // for the "mirrored" placement at -z
0193     // the "mirroring" in fact is done by a rotation of (almost) 180 degrees around the y-axis
0194 
0195     switch (crossType) {
0196     case ODH::kCenter:
0197     case ODH::kUpstream:
0198     case ODH::kDnstream: {
0199       // a volume on the z-axis, on the upstream branch, or on the downstream branch
0200 
0201       // absolute transformations for the placement in the world
0202       Transform3D transformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition), rotateAngle) );
0203       Transform3D transmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition), mirrorAngle) );
0204 
0205       // solid for the tube (including vacuum and wall): a solid cone
0206       ConeSegment tubeSolid( zHalf, 0, rOuterStart, 0, rOuterEnd , phi1, phi2);
0207 
0208       // tube consists of vacuum
0209       // place tube twice explicitely so we can attach surfaces to each one
0210       Volume tubeLog( volName, tubeSolid, coreMaterial ) ;
0211       Volume tubeLog2( volName, tubeSolid, coreMaterial ) ;
0212 
0213       // if inner and outer radii are equal, then omit the tube wall
0214       if (rInnerStart != rOuterStart || rInnerEnd != rOuterEnd) {
0215 
0216     // the wall solid: a tubular cone
0217     ConeSegment wallSolid( zHalf, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, phi1, phi2);
0218 
0219     // the wall consists of the material given in the XML
0220     Volume wallLog ( volName + "_wall", wallSolid, wallMaterial);
0221     Volume wallLog2( volName + "_wall2", wallSolid, wallMaterial);
0222 
0223     if( crossType == ODH::kCenter ) {
0224 
0225       // add surface for tracking ....
0226       const bool isCylinder = ( rInnerStart == rInnerEnd );
0227 
0228 
0229       if (isCylinder) {  // cylinder
0230 
0231         Vector3D ocyl(  rInnerStart + thickness/2.  , 0. , 0. ) ;
0232 
0233         VolCylinder cylSurf1( wallLog , SurfaceType( SurfaceType::Helper ) , 0.5*thickness  , 0.5*thickness , ocyl );
0234         VolCylinder cylSurf2( wallLog2, SurfaceType( SurfaceType::Helper ) , 0.5*thickness  , 0.5*thickness , ocyl );
0235 
0236         dd4hep::rec::volSurfaceList( tube )->push_back( cylSurf1 );
0237         dd4hep::rec::volSurfaceList( tube )->push_back( cylSurf2 );
0238 
0239       }else{   // cone
0240 
0241         const double dr    = rInnerEnd - rInnerStart ;
0242         const double theta = atan2( dr , 2.* zHalf ) ;
0243 
0244         Vector3D ocon( rInnerStart + 0.5 * ( dr + thickness ), 0. , 0. );
0245 
0246         Vector3D v( 1. , 0. , theta, Vector3D::spherical ) ;
0247 
0248         VolCone conSurf1( wallLog , SurfaceType( SurfaceType::Helper ) , 0.5*thickness  , 0.5*thickness , v, ocon );
0249         VolCone conSurf2( wallLog2, SurfaceType( SurfaceType::Helper ) , 0.5*thickness  , 0.5*thickness , v, ocon );
0250 
0251         dd4hep::rec::volSurfaceList( tube )->push_back( conSurf1 );
0252         dd4hep::rec::volSurfaceList( tube )->push_back( conSurf2 );
0253 
0254       }
0255 
0256       if( rInnerStart < min_radius ) min_radius = rInnerStart ;
0257       if( rOuterStart < min_radius ) min_radius = rOuterStart ;
0258     }
0259 
0260     wallLog.setVisAttributes(description, "TubeVis");
0261     wallLog2.setVisAttributes(description, "TubeVis");
0262     tubeLog.setVisAttributes(description, "VacVis");
0263     tubeLog2.setVisAttributes(description, "VacVis");
0264 
0265     if (nocore){
0266       
0267       //placement of the wall only
0268       envelope.placeVolume( wallLog,  transformer );
0269       envelope.placeVolume( wallLog2,  transmirror );
0270       
0271     }else{
0272       
0273       // placement of the tube in the world, both at +z and -z
0274       envelope.placeVolume( tubeLog,  transformer );
0275       envelope.placeVolume( tubeLog2,  transmirror );
0276       
0277       // placement as a daughter volume of the tube, will appear in both placements of the tube
0278       tubeLog.placeVolume( wallLog,  Transform3D() );
0279       tubeLog2.placeVolume( wallLog2,  Transform3D() );
0280     }
0281     
0282       }
0283     }
0284       break;
0285 
0286     case ODH::kPunchedCenter: {
0287       // a volume on the z-axis with one or two inner holes
0288       // (implemented as a cone from which tubes are punched out)
0289 
0290       const double rUpstreamPunch = rInnerStart; // just alias names denoting what is meant here
0291       const double rDnstreamPunch = rInnerEnd; // (the database entries are "abused" in this case)
0292 
0293       // relative transformations for the composition of the SubtractionVolumes
0294       Transform3D upstreamTransformer(RotationY(-crossingAngle), Position(zPosition * tan(-crossingAngle), 0, 0));
0295       Transform3D dnstreamTransformer(RotationY(+crossingAngle), Position(zPosition * tan(+crossingAngle), 0, 0));
0296 
0297       // absolute transformations for the final placement in the world (angles always equal zero and 180 deg)
0298       Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition) , rotateAngle) );
0299       Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition) , mirrorAngle) );
0300 
0301       // solid for the tube (including vacuum and wall): a solid cone
0302       ConeSegment tubeSolid( zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2);
0303 
0304       // tube consists of vacuum (will later have two different daughters)
0305       Volume tubeLog0( volName + "_0", tubeSolid, coreMaterial );
0306       Volume tubeLog1( volName + "_1", tubeSolid, coreMaterial );
0307 
0308       // the wall solid and placeholders for possible SubtractionSolids
0309       ConeSegment wholeSolid(  zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2);
0310 
0311       Solid tmpSolid0, tmpSolid1, wallSolid0, wallSolid1;
0312 
0313       // the punched subtraction solids can be asymmetric and therefore have to be created twice:
0314       // one time in the "right" way, another time in the "reverse" way, because the "mirroring"
0315       // rotation around the y-axis will not only exchange +z and -z, but also +x and -x
0316 
0317       if ( rUpstreamPunch > 1e-6 ) { // do we need a hole on the upstream branch?
0318     Tube upstreamPunch( 0, rUpstreamPunch, 5 * zHalf, phi1, phi2); // a bit longer
0319     tmpSolid0 = SubtractionSolid( wholeSolid, upstreamPunch, upstreamTransformer);
0320     tmpSolid1 = SubtractionSolid( wholeSolid, upstreamPunch, dnstreamTransformer); // [sic]
0321       } else { // dont't do anything, just pass on the unmodified shape
0322     tmpSolid0 = wholeSolid;
0323     tmpSolid1 = wholeSolid;
0324       }
0325 
0326       if (rDnstreamPunch > 1e-6 ) { // do we need a hole on the downstream branch?
0327     Tube dnstreamPunch( 0, rDnstreamPunch, 5 * zHalf, phi1, phi2); // a bit longer
0328     wallSolid0 = SubtractionSolid( tmpSolid0, dnstreamPunch, dnstreamTransformer);
0329     wallSolid1 = SubtractionSolid( tmpSolid1, dnstreamPunch, upstreamTransformer); // [sic]
0330       } else { // dont't do anything, just pass on the unmodified shape
0331     wallSolid0 = tmpSolid0;
0332     wallSolid1 = tmpSolid1;
0333       }
0334 
0335       // the wall consists of the material given in the XML
0336       Volume wallLog0( volName + "_wall_0", wallSolid0, wallMaterial );
0337       Volume wallLog1( volName + "_wall_1", wallSolid1, wallMaterial );
0338 
0339       wallLog0.setVisAttributes(description, "TubeVis");
0340       wallLog1.setVisAttributes(description, "TubeVis");
0341       tubeLog0.setVisAttributes(description, "VacVis");
0342       tubeLog1.setVisAttributes(description, "VacVis");
0343 
0344       if (nocore){
0345     
0346     // placement of the wall only
0347     envelope.placeVolume( wallLog0, placementTransformer );
0348     envelope.placeVolume( wallLog1, placementTransmirror );
0349     
0350       }else{
0351     
0352     // placement of the tube in the world, both at +z and -z
0353     envelope.placeVolume( tubeLog0, placementTransformer );
0354     envelope.placeVolume( tubeLog1, placementTransmirror );
0355     
0356     // placement as a daughter volumes of the tube
0357     tubeLog0.placeVolume( wallLog0, Position() );
0358     tubeLog1.placeVolume( wallLog1, Position() );
0359       }
0360 
0361       break;
0362     }
0363 
0364     case ODH::kPunchedUpstream:
0365     case ODH::kPunchedDnstream: {
0366       // a volume on the upstream or downstream branch with two inner holes
0367       // (implemented as a cone from which another tube is punched out)
0368 
0369       const double rCenterPunch = (crossType == ODH::kPunchedUpstream) ? (rInnerStart) : (rInnerEnd); // just alias names denoting what is meant here
0370       const double rOffsetPunch = (crossType == ODH::kPunchedDnstream) ? (rInnerStart) : (rInnerEnd); // (the database entries are "abused" in this case)
0371 
0372       // relative transformations for the composition of the SubtractionVolumes
0373       Transform3D punchTransformer(RotationY(-2 * rotateAngle), Position(zPosition * tan(-2 * rotateAngle), 0, 0));
0374       Transform3D punchTransmirror(RotationY(+2 * rotateAngle), Position(zPosition * tan(+2 * rotateAngle), 0, 0));
0375 
0376       // absolute transformations for the final placement in the world
0377       Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition) , rotateAngle) );
0378       Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition) , mirrorAngle) );
0379 
0380       // solid for the tube (including vacuum and wall): a solid cone
0381       ConeSegment tubeSolid( zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2);
0382 
0383       // tube consists of vacuum (will later have two different daughters)
0384       Volume tubeLog0( volName + "_0", tubeSolid, coreMaterial );
0385       Volume tubeLog1( volName + "_1", tubeSolid, coreMaterial );
0386 
0387       // the wall solid and the piece (only a tube, for the moment) which will be punched out
0388       ConeSegment wholeSolid( zHalf, rCenterPunch , rOuterStart, rCenterPunch, rOuterEnd, phi1, phi2);
0389 
0390       Tube punchSolid( 0, rOffsetPunch, 5 * zHalf, phi1, phi2); // a bit longer
0391 
0392       // the punched subtraction solids can be asymmetric and therefore have to be created twice:
0393       // one time in the "right" way, another time in the "reverse" way, because the "mirroring"
0394       // rotation around the y-axis will not only exchange +z and -z, but also +x and -x
0395       SubtractionSolid wallSolid0( wholeSolid, punchSolid, punchTransformer);
0396       SubtractionSolid wallSolid1( wholeSolid, punchSolid, punchTransmirror);
0397 
0398       // the wall consists of the material given in the database
0399       Volume wallLog0( volName + "_wall_0", wallSolid0, wallMaterial );
0400       Volume wallLog1( volName + "_wall_1", wallSolid1, wallMaterial );
0401 
0402       wallLog0.setVisAttributes(description, "TubeVis");
0403       wallLog1.setVisAttributes(description, "TubeVis");
0404 
0405       tubeLog0.setVisAttributes(description, "VacVis");
0406       tubeLog1.setVisAttributes(description, "VacVis");
0407 
0408 
0409       if (nocore){
0410 
0411     // placement of the wall only
0412     envelope.placeVolume( wallLog0, placementTransformer );
0413     envelope.placeVolume( wallLog1, placementTransmirror );
0414 
0415       }else{
0416 
0417     // placement of the tube in the world, both at +z and -z
0418     envelope.placeVolume( tubeLog0, placementTransformer );
0419     envelope.placeVolume( tubeLog1, placementTransmirror );
0420 
0421     // placement as a daughter volumes of the tube
0422     tubeLog0.placeVolume( wallLog0 , Position() );
0423     tubeLog1.placeVolume( wallLog1 , Position() );
0424       }
0425 
0426       break;
0427     }
0428 
0429     case ODH::kUpstreamClippedFront:
0430     case ODH::kDnstreamClippedFront:
0431     case ODH::kUpstreamSlicedFront:
0432     case ODH::kDnstreamSlicedFront: {
0433       // a volume on the upstream or donwstream branch, but with the front face parallel to the xy-plane
0434       // or to a piece tilted in the other direction ("sliced" like a salami with 2 * rotateAngle)
0435       // (implemented as a slightly longer cone from which the end is clipped off)
0436 
0437       // the volume which will be used for clipping: a solid tube
0438       const double clipSize = rOuterStart; // the right order of magnitude for the clipping volume (alias name)
0439       Tube clipSolid( 0, 2 * clipSize, clipSize, phi1, phi2); // should be large enough
0440 
0441       // relative transformations for the composition of the SubtractionVolumes
0442       const double clipAngle = (crossType == ODH::kUpstreamClippedFront || crossType == ODH::kDnstreamClippedFront) ? (rotateAngle) : (2 * rotateAngle);
0443       const double clipShift = (zStart - clipSize) / cos(clipAngle) - (zPosition - clipSize / 2); // question: why is this correct?
0444       Transform3D clipTransformer(RotationY(-clipAngle), Position(0, 0, clipShift));
0445       Transform3D clipTransmirror(RotationY(+clipAngle), Position(0, 0, clipShift));
0446 
0447       // absolute transformations for the final placement in the world
0448       Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition - clipSize / 2) , rotateAngle) );
0449       Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition - clipSize / 2) , mirrorAngle) );
0450 
0451       // solid for the tube (including vacuum and wall): a solid cone
0452 
0453       ConeSegment wholeSolid(  zHalf + clipSize / 2, 0, rOuterStart, 0, rOuterEnd,  phi1, phi2); // a bit longer
0454 
0455       // clip away the protruding end
0456       SubtractionSolid tubeSolid0( wholeSolid, clipSolid, clipTransformer);
0457       SubtractionSolid tubeSolid1( wholeSolid, clipSolid, clipTransmirror);
0458 
0459       // tube consists of vacuum (will later have two different daughters)
0460       Volume tubeLog0( volName + "_0", tubeSolid0, coreMaterial );
0461       Volume tubeLog1( volName + "_1", tubeSolid1, coreMaterial );
0462 
0463       if (nocore==false){
0464     // placement of the tube in the world, both at +z and -z
0465     envelope.placeVolume( tubeLog0, placementTransformer );
0466     envelope.placeVolume( tubeLog1, placementTransmirror );
0467       }
0468 
0469       if (rInnerStart != rOuterStart || rInnerEnd != rOuterEnd) {
0470     // the wall solid: a tubular cone
0471     ConeSegment wallWholeSolid(  zHalf + clipSize / 2, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, phi1, phi2); // a bit longer
0472 
0473     // clip away the protruding end
0474     SubtractionSolid wallSolid0( wallWholeSolid, clipSolid, clipTransformer);
0475     SubtractionSolid wallSolid1( wallWholeSolid, clipSolid, clipTransmirror);
0476 
0477     // the wall consists of the material given in the database
0478     Volume wallLog0( volName + "_wall_0", wallSolid0, wallMaterial );
0479     Volume wallLog1( volName + "_wall_1", wallSolid1, wallMaterial );
0480 
0481     wallLog0.setVisAttributes(description, "TubeVis");
0482     wallLog1.setVisAttributes(description, "TubeVis");
0483 
0484     tubeLog0.setVisAttributes(description, "VacVis");
0485     tubeLog1.setVisAttributes(description, "VacVis");
0486     if (nocore==false){
0487       // placement as a daughter volumes of the tube
0488       tubeLog0.placeVolume( wallLog0, Position() );
0489       tubeLog1.placeVolume( wallLog1, Position() );
0490     }else{    // placement of the wall only
0491       envelope.placeVolume( wallLog0, placementTransformer );
0492       envelope.placeVolume( wallLog1, placementTransmirror );
0493     }
0494       }
0495     }
0496       break;
0497 
0498     case ODH::kUpstreamClippedRear:
0499     case ODH::kDnstreamClippedRear:
0500     case ODH::kUpstreamSlicedRear:
0501     case ODH::kDnstreamSlicedRear: {
0502       // a volume on the upstream or donwstream branch, but with the rear face parallel to the xy-plane
0503       // or to a piece tilted in the other direction ("sliced" like a salami with 2 * rotateAngle)
0504       // (implemented as a slightly longer cone from which the end is clipped off)
0505 
0506       // the volume which will be used for clipping: a solid tube
0507       const double clipSize = rOuterEnd; // the right order of magnitude for the clipping volume (alias name)
0508       Tube clipSolid( 0, 2 * clipSize, clipSize, phi1, phi2); // should be large enough
0509 
0510       // relative transformations for the composition of the SubtractionVolumes
0511       const double clipAngle = (crossType == ODH::kUpstreamClippedRear || crossType == ODH::kDnstreamClippedRear) ? (rotateAngle) : (2 * rotateAngle);
0512       const double clipShift = (zEnd + clipSize) / cos(clipAngle) - (zPosition + clipSize / 2); // question: why is this correct?
0513       Transform3D clipTransformer(RotationY(-clipAngle), Position(0, 0, clipShift));
0514       Transform3D clipTransmirror(RotationY(+clipAngle), Position(0, 0, clipShift));
0515 
0516       // absolute transformations for the final placement in the world
0517       Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition + clipSize / 2) , rotateAngle) );
0518       Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition + clipSize / 2) , mirrorAngle) );
0519 
0520       // solid for the tube (including vacuum and wall): a solid cone
0521       ConeSegment wholeSolid( 0, rOuterStart, 0, rOuterEnd, zHalf + clipSize / 2, phi1, phi2); // a bit longer
0522 
0523       // clip away the protruding end
0524       SubtractionSolid tubeSolid0( wholeSolid, clipSolid, clipTransformer);
0525       SubtractionSolid tubeSolid1( wholeSolid, clipSolid, clipTransmirror);
0526 
0527       // tube consists of vacuum (will later have two different daughters)
0528       Volume tubeLog0( volName + "_0", tubeSolid0, coreMaterial );
0529       Volume tubeLog1( volName + "_1", tubeSolid1, coreMaterial );
0530 
0531       if (nocore==false){
0532     // placement of the tube in the world, both at +z and -z
0533     envelope.placeVolume( tubeLog0, placementTransformer );
0534     envelope.placeVolume( tubeLog1, placementTransmirror );
0535       }
0536 
0537       if (rInnerStart != rOuterStart || rInnerEnd != rOuterEnd) {
0538     // the wall solid: a tubular cone
0539     ConeSegment wallWholeSolid( rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, zHalf + clipSize / 2, phi1, phi2); // a bit longer
0540 
0541     // clip away the protruding end
0542     SubtractionSolid wallSolid0( wallWholeSolid, clipSolid, clipTransformer);
0543     SubtractionSolid wallSolid1( wallWholeSolid, clipSolid, clipTransmirror);
0544 
0545     // the wall consists of the material given in the database
0546     Volume wallLog0( volName + "_wall_0", wallSolid0, wallMaterial );
0547     Volume wallLog1( volName + "_wall_1", wallSolid1, wallMaterial );
0548 
0549     wallLog0.setVisAttributes(description, "TubeVis");
0550     wallLog1.setVisAttributes(description, "TubeVis");
0551 
0552     tubeLog0.setVisAttributes(description, "VacVis");
0553     tubeLog1.setVisAttributes(description, "VacVis");
0554 
0555     if (nocore==false){
0556     // placement as a daughter volumes of the tube
0557       tubeLog0.placeVolume( wallLog0, Transform3D() );
0558       tubeLog1.placeVolume( wallLog1, Transform3D() );
0559     }else{   // placement of the wall only
0560       envelope.placeVolume( wallLog0, placementTransformer );
0561       envelope.placeVolume( wallLog1, placementTransmirror );
0562     }
0563       }
0564       break;
0565     }
0566 
0567     case ODH::kUpstreamClippedBoth:
0568     case ODH::kDnstreamClippedBoth:
0569     case ODH::kUpstreamSlicedBoth:
0570     case ODH::kDnstreamSlicedBoth: {
0571       // a volume on the upstream or donwstream branch, but with both faces parallel to the xy-plane
0572       // or to a piece tilted in the other direction ("sliced" like a salami with 2 * rotateAngle)
0573       // (implemented as a slightly longer cone from which the end is clipped off)
0574 
0575       // the volume which will be used for clipping: a solid tube
0576       const double clipSize = rOuterEnd; // the right order of magnitude for the clipping volume (alias name)
0577       Tube clipSolid( 0, 2 * clipSize, clipSize, phi1, phi2); // should be large enough
0578 
0579       // relative transformations for the composition of the SubtractionVolumes
0580       const double clipAngle = (crossType == ODH::kUpstreamClippedBoth || crossType == ODH::kDnstreamClippedBoth) ? (rotateAngle) : (2 * rotateAngle);
0581       const double clipShiftFrnt = (zStart - clipSize) / cos(clipAngle) - zPosition;
0582       const double clipShiftRear = (zEnd   + clipSize) / cos(clipAngle) - zPosition;
0583       Transform3D clipTransformerFrnt(RotationY(-clipAngle), Position(0, 0, clipShiftFrnt));
0584       Transform3D clipTransformerRear(RotationY(-clipAngle), Position(0, 0, clipShiftRear));
0585       Transform3D clipTransmirrorFrnt(RotationY(+clipAngle), Position(0, 0, clipShiftFrnt));
0586       Transform3D clipTransmirrorRear(RotationY(+clipAngle), Position(0, 0, clipShiftRear));
0587 
0588       // absolute transformations for the final placement in the world
0589       Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition) , rotateAngle) );
0590       Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition) , mirrorAngle) );
0591 
0592       // solid for the tube (including vacuum and wall): a solid cone
0593       ConeSegment wholeSolid( 0, rOuterStart, 0, rOuterEnd, zHalf + clipSize, phi1, phi2); // a bit longer
0594 
0595       // clip away the protruding ends
0596       SubtractionSolid tmpSolid0 ( wholeSolid, clipSolid, clipTransformerFrnt);
0597       SubtractionSolid tmpSolid1 ( wholeSolid, clipSolid, clipTransmirrorFrnt);
0598       SubtractionSolid tubeSolid0( tmpSolid0,  clipSolid, clipTransformerRear);
0599       SubtractionSolid tubeSolid1( tmpSolid1,  clipSolid, clipTransmirrorRear);
0600 
0601       // tube consists of vacuum (will later have two different daughters)
0602       Volume tubeLog0( volName + "_0", tubeSolid0, coreMaterial );
0603       Volume tubeLog1( volName + "_1", tubeSolid1, coreMaterial );
0604 
0605       if (nocore==false){
0606     // placement of the tube in the world, both at +z and -z
0607     envelope.placeVolume( tubeLog0, placementTransformer );
0608     envelope.placeVolume( tubeLog1, placementTransmirror );
0609       }
0610 
0611       if (rInnerStart != rOuterStart || rInnerEnd != rOuterEnd) {
0612     // the wall solid: a tubular cone
0613     ConeSegment wallWholeSolid( rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, zHalf + clipSize, phi1, phi2); // a bit longer
0614 
0615     // clip away the protruding ends
0616     SubtractionSolid wallTmpSolid0( wallWholeSolid, clipSolid, clipTransformerFrnt);
0617     SubtractionSolid wallTmpSolid1( wallWholeSolid, clipSolid, clipTransmirrorFrnt);
0618     SubtractionSolid wallSolid0   ( wallTmpSolid0,  clipSolid, clipTransformerRear);
0619     SubtractionSolid wallSolid1   ( wallTmpSolid1,  clipSolid, clipTransmirrorRear);
0620 
0621     // the wall consists of the material given in the database
0622     Volume wallLog0(volName + "_wall_0", wallSolid0, wallMaterial );
0623     Volume wallLog1(volName + "_wall_1", wallSolid1, wallMaterial );
0624 
0625     wallLog0.setVisAttributes(description, "TubeVis");
0626     wallLog1.setVisAttributes(description, "TubeVis");
0627 
0628     tubeLog0.setVisAttributes(description, "VacVis");
0629     tubeLog1.setVisAttributes(description, "VacVis");
0630 
0631     if (nocore==false){
0632       // placement as a daughter volumes of the tube
0633       tubeLog0.placeVolume( wallLog0, Transform3D() );
0634       tubeLog1.placeVolume( wallLog1, Transform3D() );
0635     }else{  // placement of the wall only
0636       envelope.placeVolume( wallLog0, placementTransformer );
0637       envelope.placeVolume( wallLog1, placementTransmirror );
0638     }
0639       }
0640       break;
0641     }
0642     default: {
0643       throw std::runtime_error( " Beampipe_o1_v01_geo.cpp : fatal failure !! ??  " ) ;
0644 
0645       //      return false; // fatal failure
0646     }
0647 
0648     }//end switch
0649   }//for all xmlSections
0650 
0651   //######################################################################################################################################################################
0652 
0653 
0654   // add a surface just inside the beampipe for tracking:
0655   if (nocore==false){
0656     Vector3D oIPCyl( (min_radius-1.e-3)  , 0. , 0.  ) ;
0657     SimpleCylinder ipCylSurf( envelope , SurfaceType( SurfaceType::Helper ) , 1.e-5  , 1e-5 , oIPCyl ) ;
0658     // the length does not really matter here as long as it is long enough for all tracks ...
0659     ipCylSurf->setHalfLength(  100*units::cm ) ;
0660     dd4hep::rec::volSurfaceList( tube )->push_back( ipCylSurf ) ;
0661   }
0662 
0663   tube.addExtension< dd4hep::rec::ConicalSupportData >( beampipeData ) ;
0664 
0665   //--------------------------------------
0666 
0667   tube.setVisAttributes( description, xmlBeampipe.visStr(), envelope );
0668 
0669   // // tube.setPlacement(pv);
0670 
0671   return tube;
0672 }
0673 DECLARE_DETELEMENT(DD4hep_Beampipe_o1_v01,create_element)