Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:15:26

0001 //====================================================================
0002 //  LCGeo - LC detector models in DD4hep
0003 //--------------------------------------------------------------------
0004 // Mask based on the Beampipe driver (based on TubeX from Mokka), but not
0005 // filling the centre with Beam vaccum, just places cylinders in arbitrary
0006 // places with different alignments
0007 //  A.Sailer, CERN
0008 //  $Id$
0009 //====================================================================
0010 #include "FCC_OtherDetectorHelpers.h"
0011 
0012 
0013 // todo: remove gaudi logging and properly capture output
0014 #define endmsg std::endl
0015 #define lLog std::cout
0016 namespace MSG {
0017 const std::string DEBUG = " Debug: ";
0018 }
0019 
0020 #include "DD4hep/DD4hepUnits.h"
0021 #include "DD4hep/DetFactoryHelper.h"
0022 #include <cmath>
0023 #include <string>
0024 
0025 using dd4hep::Assembly;
0026 using dd4hep::ConeSegment;
0027 using dd4hep::DetElement;
0028 using dd4hep::Detector;
0029 using dd4hep::Material;
0030 using dd4hep::PlacedVolume;
0031 using dd4hep::Position;
0032 using dd4hep::Ref_t;
0033 using dd4hep::RotateY;
0034 using dd4hep::RotationY;
0035 using dd4hep::SensitiveDetector;
0036 using dd4hep::Solid;
0037 using dd4hep::SubtractionSolid;
0038 using dd4hep::Transform3D;
0039 using dd4hep::Tube;
0040 using dd4hep::Volume;
0041 
0042 static Ref_t create_element(Detector& theDetector, xml_h xmlHandle, SensitiveDetector /*sens*/) {
0043   //------------------------------------------
0044   //  See comments starting with '//**' for
0045   //     hints on porting issues
0046   //------------------------------------------
0047 
0048   // Access to the XML File
0049   xml_det_t xmlMask = xmlHandle;
0050   const std::string name = xmlMask.nameStr();
0051 
0052   //--------------------------------
0053   Assembly envelope(name + "_assembly");
0054   //--------------------------------
0055 
0056   DetElement tube(name, xmlMask.id());
0057 
0058   const double phi1 = 0;
0059   const double phi2 = 360.0 * dd4hep::degree;
0060 
0061   // Parameters we have to know about
0062   dd4hep::xml::Component xmlParameter = xmlMask.child(_Unicode(parameter));
0063   const double crossingAngle = xmlParameter.attr<double>(_Unicode(crossingangle)) * 0.5;  //  only half the angle
0064 
0065   for (xml_coll_t c(xmlMask, Unicode("section")); c; ++c) {
0066 
0067     xml_comp_t xmlSection(c);
0068 
0069     ODH::ECrossType crossType = ODH::getCrossType(xmlSection.attr<std::string>(_Unicode(type)));
0070     const double zStart = xmlSection.attr<double>(_Unicode(start));
0071     const double zEnd = xmlSection.attr<double>(_Unicode(end));
0072     const double rInnerStart = xmlSection.attr<double>(_Unicode(rMin1));
0073     const double rInnerEnd = xmlSection.attr<double>(_Unicode(rMin2));
0074     const double rOuterStart = xmlSection.attr<double>(_Unicode(rMax1));
0075     const double rOuterEnd = xmlSection.attr<double>(_Unicode(rMax2));
0076     const double thickness = rOuterStart - rInnerStart;
0077     Material sectionMat = theDetector.material(xmlSection.materialStr());
0078     const std::string volName = "tube_" + xmlSection.nameStr();
0079 
0080     lLog << MSG::DEBUG << std::setw(8) << zStart << std::setw(8) << zEnd << std::setw(8) << rInnerStart << std::setw(8)
0081               << rInnerEnd << std::setw(8) << rOuterStart << std::setw(8) << rOuterEnd << std::setw(8) << thickness
0082               << std::setw(8) << crossType << std::setw(15) << volName << std::setw(15) << sectionMat.name()
0083               << endmsg;
0084 
0085     // things which can be calculated immediately
0086     const double zHalf = fabs(zEnd - zStart) * 0.5;      // half z length of the cone
0087     const double zPosition = fabs(zEnd + zStart) * 0.5;  // middle z position
0088     Material material = sectionMat;
0089 
0090     // this could mess up your geometry, so better check it
0091     if (not ODH::checkForSensibleGeometry(crossingAngle, crossType)) {
0092       throw std::runtime_error(" Mask_o1_v01_geo.cpp : checkForSensibleGeometry() failed ");
0093     }
0094 
0095     const double rotateAngle =
0096         getCurrentAngle(crossingAngle, crossType);  // for the placement at +z (better make it const now)
0097     const double mirrorAngle = M_PI - rotateAngle;  // for the "mirrored" placement at -z
0098     // the "mirroring" in fact is done by a rotation of (almost) 180 degrees around the y-axis
0099 
0100     switch (crossType) {
0101     case ODH::kCenter:
0102     case ODH::kUpstream:
0103     case ODH::kDnstream: {
0104       // a volume on the z-axis, on the upstream branch, or on the downstream branch
0105 
0106       // absolute transformations for the placement in the world
0107       Transform3D transformer(RotationY(rotateAngle), RotateY(Position(0, 0, zPosition), rotateAngle));
0108       Transform3D transmirror(RotationY(mirrorAngle), RotateY(Position(0, 0, zPosition), mirrorAngle));
0109 
0110       // solid for the tube (including vacuum and wall): a solid cone
0111       ConeSegment tubeSolid(zHalf, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, phi1, phi2);
0112 
0113       // tube consists of vacuum
0114       Volume tubeLog(volName, tubeSolid, material);
0115       tubeLog.setVisAttributes(theDetector, xmlMask.visStr());
0116 
0117       // placement of the tube in the world, both at +z and -z
0118       envelope.placeVolume(tubeLog, transformer);
0119       envelope.placeVolume(tubeLog, transmirror);
0120 
0121     } break;
0122 
0123     case ODH::kPunchedCenter: {
0124       // a cone with one or two inner holes (two tubes are punched out)
0125 
0126       const double rUpstreamPunch = rInnerStart;  // just alias names denoting what is meant here
0127       const double rDnstreamPunch = rInnerEnd;    // (the database entries are "abused" in this case)
0128 
0129       // relative transformations for the composition of the SubtractionVolumes
0130       Transform3D upstreamTransformer(RotationY(-crossingAngle), Position(zPosition * tan(-crossingAngle), 0, 0));
0131       Transform3D dnstreamTransformer(RotationY(+crossingAngle), Position(zPosition * tan(+crossingAngle), 0, 0));
0132 
0133       // absolute transformations for the final placement in the world (angles always equal zero and 180 deg)
0134       Transform3D placementTransformer(RotationY(rotateAngle), RotateY(Position(0, 0, zPosition), rotateAngle));
0135       Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY(Position(0, 0, zPosition), mirrorAngle));
0136 
0137       // the main solid and the two pieces (only tubes, for the moment) which will be punched out
0138       ConeSegment wholeSolid(zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2);
0139       Solid tmpSolid0, tmpSolid1, finalSolid0, finalSolid1;
0140 
0141       // the punched subtraction solids can be asymmetric and therefore have to be created twice:
0142       // one time in the "right" way, another time in the "reverse" way, because the "mirroring"
0143       // rotation around the y-axis will not only exchange +z and -z, but also +x and -x
0144 
0145       if (rUpstreamPunch > 1e-6) {                                     // do we need a hole on the upstream branch?
0146         Tube upstreamPunch(0, rUpstreamPunch, 5 * zHalf, phi1, phi2);  // a bit longer
0147         tmpSolid0 = SubtractionSolid(wholeSolid, upstreamPunch, upstreamTransformer);
0148         tmpSolid1 = SubtractionSolid(wholeSolid, upstreamPunch, dnstreamTransformer);  // [sic]
0149       } else {  // dont't do anything, just pass on the unmodified shape
0150         tmpSolid0 = wholeSolid;
0151         tmpSolid1 = wholeSolid;
0152       }
0153 
0154       if (rDnstreamPunch > 1e-6) {                                     // do we need a hole on the downstream branch?
0155         Tube dnstreamPunch(0, rDnstreamPunch, 5 * zHalf, phi1, phi2);  // a bit longer
0156         finalSolid0 = SubtractionSolid(tmpSolid0, dnstreamPunch, dnstreamTransformer);
0157         finalSolid1 = SubtractionSolid(tmpSolid1, dnstreamPunch, upstreamTransformer);  // [sic]
0158       } else {  // dont't do anything, just pass on the unmodified shape
0159         finalSolid0 = tmpSolid0;
0160         finalSolid1 = tmpSolid1;
0161       }
0162 
0163       // tube consists of vacuum (will later have two different daughters)
0164       Volume tubeLog0(volName + "_0", finalSolid0, material);
0165       Volume tubeLog1(volName + "_1", finalSolid1, material);
0166       tubeLog0.setVisAttributes(theDetector, xmlMask.visStr());
0167       tubeLog1.setVisAttributes(theDetector, xmlMask.visStr());
0168 
0169       // placement of the tube in the world, both at +z and -z
0170       envelope.placeVolume(tubeLog0, placementTransformer);
0171       envelope.placeVolume(tubeLog1, placementTransmirror);
0172 
0173       break;
0174     }
0175 
0176     case ODH::kPunchedUpstream:
0177     case ODH::kPunchedDnstream: {
0178       // a volume on the upstream or downstream branch with two inner holes
0179       // (implemented as a cone from which another tube is punched out)
0180 
0181       const double rCenterPunch = (crossType == ODH::kPunchedUpstream)
0182           ? (rInnerStart)
0183           : (rInnerEnd);  // just alias names denoting what is meant here
0184       const double rOffsetPunch = (crossType == ODH::kPunchedDnstream)
0185           ? (rInnerStart)
0186           : (rInnerEnd);  // (the database entries are "abused" in this case)
0187 
0188       // relative transformations for the composition of the SubtractionVolumes
0189       Transform3D punchTransformer(RotationY(-2 * rotateAngle), Position(zPosition * tan(-2 * rotateAngle), 0, 0));
0190       Transform3D punchTransmirror(RotationY(+2 * rotateAngle), Position(zPosition * tan(+2 * rotateAngle), 0, 0));
0191 
0192       // absolute transformations for the final placement in the world
0193       Transform3D placementTransformer(RotationY(rotateAngle), RotateY(Position(0, 0, zPosition), rotateAngle));
0194       Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY(Position(0, 0, zPosition), mirrorAngle));
0195 
0196       // the main solid and the piece (only a tube, for the moment) which will be punched out
0197       ConeSegment wholeSolid(zHalf, rCenterPunch, rOuterStart, rCenterPunch, rOuterEnd, phi1, phi2);
0198       Tube punchSolid(0, rOffsetPunch, 5 * zHalf, phi1, phi2);  // a bit longer
0199 
0200       // the punched subtraction solids can be asymmetric and therefore have to be created twice:
0201       // one time in the "right" way, another time in the "reverse" way, because the "mirroring"
0202       // rotation around the y-axis will not only exchange +z and -z, but also +x and -x
0203       SubtractionSolid finalSolid0(wholeSolid, punchSolid, punchTransformer);
0204       SubtractionSolid finalSolid1(wholeSolid, punchSolid, punchTransmirror);
0205 
0206       // tube consists of vacuum (will later have two different daughters)
0207       Volume tubeLog0(volName + "_0", finalSolid0, material);
0208       Volume tubeLog1(volName + "_1", finalSolid1, material);
0209       tubeLog0.setVisAttributes(theDetector, xmlMask.visStr());
0210       tubeLog1.setVisAttributes(theDetector, xmlMask.visStr());
0211 
0212       // placement of the tube in the world, both at +z and -z
0213       envelope.placeVolume(tubeLog0, placementTransformer);
0214       envelope.placeVolume(tubeLog1, placementTransmirror);
0215 
0216       break;
0217     }
0218     default: { throw std::runtime_error(" Mask_o1_v01_geo.cpp : fatal failure !! ??  "); }
0219 
0220     }  // end switch
0221   }    // for all xmlSections
0222 
0223   //--------------------------------------
0224   Volume mother = theDetector.pickMotherVolume(tube);
0225   PlacedVolume pv(mother.placeVolume(envelope));
0226   pv.addPhysVolID("system", xmlMask.id());  //.addPhysVolID("side", 0 ) ;
0227 
0228   tube.setVisAttributes(theDetector, xmlMask.visStr(), envelope);
0229 
0230   tube.setPlacement(pv);
0231 
0232   return tube;
0233 }
0234 DECLARE_DETELEMENT(DD4hep_FCC_Mask_o1_v01, create_element)