DD4hep  1.38.0
Detector Description Toolkit for High Energy Physics
Mask_o1_v01_geo.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 //==========================================================================
12 
14 #include "DD4hep/Printout.h"
15 #include "DD4hep/DD4hepUnits.h"
16 #include "DD4hep/DetType.h"
17 #include "DDRec/DetectorData.h"
18 #include "XML/Utilities.h"
19 
20 #include <cmath>
21 #include <string>
22 
24 using dd4hep::Position;
25 using dd4hep::RotationX;
26 using dd4hep::RotationY;
27 using dd4hep::RotateY;
28 using dd4hep::RotateX;
31 using dd4hep::Material;
32 using dd4hep::Volume;
33 using dd4hep::Solid;
34 using dd4hep::Tube;
36 using dd4hep::Assembly;
37 using dd4hep::Detector;
39 using dd4hep::Ref_t;
40 using dd4hep::Rotation3D;
41 using dd4hep::RotationZ;
42 using dd4hep::Trd1;
43 using dd4hep::Trd2;
44 
45 namespace units = dd4hep;
46 
47 
48 static Ref_t create_detector(Detector& description,
49  xml_h xmlHandle,
50  SensitiveDetector sens) {
51 
52  printout(dd4hep::DEBUG,"DD4hep_Mask", "Creating Mask" ) ;
53 
54  //Access to the XML File
55  xml_det_t xmlMask = xmlHandle;
56  const std::string name = xmlMask.nameStr();
57 
58  //--------------------------------
59  Assembly envelope( name + "_assembly" ) ;
60  //--------------------------------
61 
62  dd4hep::DetElement tube( name, xmlMask.id() ) ;
63 
64  bool rotationX= false;
65 
66  //Parameters we have to know about
67  dd4hep::xml::Component xmlParameter = xmlMask.child(_Unicode(parameter));
68  const double crossingAngle = xmlParameter.attr< double >(_Unicode(crossingangle))*0.5; // only half the angle
69 
70  if (xmlParameter.hasAttr(_Unicode(rotationX)))
71  rotationX = xmlParameter.attr< bool >(_Unicode(rotationX));
72 
73  int counter = 0;
74  for(xml_coll_t c( xmlMask ,Unicode("section")); c; ++c, counter++) {
75 
76  xml_comp_t xmlSection( c );
77  bool isSensitive = false;
78  ODH::ECrossType crossType = ODH::getCrossType(xmlSection.attr< std::string >(_Unicode(type)));
79  const double zStart = xmlSection.attr< double > (_Unicode(start));
80  const double zEnd = xmlSection.attr< double > (_Unicode(end));
81  const double rInnerStart = xmlSection.attr< double > (_Unicode(rMin1));
82  const double rInnerEnd = xmlSection.attr< double > (_Unicode(rMin2));
83  const double rOuterStart = xmlSection.attr< double > (_Unicode(rMax1));
84  const double rOuterEnd = xmlSection.attr< double > (_Unicode(rMax2));
85  const double thickness = rOuterStart - rInnerStart;
86  Material sectionMat = description.material(xmlSection.materialStr());
87  const std::string volName = "tube_" + xmlSection.nameStr();
88 
89  double phi1 = 0 ;
90  double phi2 = 360.0*units::degree;
91  if (xmlSection.hasAttr(_U(phi1)))
92  phi1 = xmlSection.attr< double > (_U(phi1));
93  if (xmlSection.hasAttr(_U(phi2)))
94  phi2 = xmlSection.attr< double > (_U(phi2));
95 
96  std::string ssensitive = "none";
97  if (xmlSection.hasAttr(_U(sensitive))){
98  isSensitive = true;
99  ssensitive = xmlSection.attr< std::string > (_U(sensitive));
100  sens.setType( xmlSection.attr< std::string > (_U(sensitive)) ); //decide the type of SD (tracker / calorimeter) check for k4run
101  printout(dd4hep::DEBUG, "sensitive in sens ", ssensitive);
102  }
103 
104 
105  std::stringstream pipeInfo;
106  pipeInfo << std::setw(8) << zStart /units::mm
107  << std::setw(8) << zEnd /units::mm
108  << std::setw(8) << rInnerStart /units::mm
109  << std::setw(8) << rInnerEnd /units::mm
110  << std::setw(8) << rOuterStart /units::mm
111  << std::setw(8) << rOuterEnd /units::mm
112  << std::setw(8) << thickness /units::mm
113  << std::setw(8) << crossType
114  << std::setw(35) << volName
115  << std::setw(15) << sectionMat.name()
116  << std::setw(8) << phi1
117  << std::setw(8) << phi2
118  << std::setw(8) << ssensitive;
119 
120  printout(dd4hep::INFO, "DD4hep_Mask", pipeInfo.str() );
121 
122  // things which can be calculated immediately
123  const double zHalf = fabs(zEnd - zStart) * 0.5; // half z length of the cone
124  const double zPosition = fabs(zEnd + zStart) * 0.5; // middle z position
125  Material material = sectionMat;
126 
127  // this could mess up your geometry, so better check it
128  if (not ODH::checkForSensibleGeometry(crossingAngle, crossType)){
129  throw std::runtime_error( " Mask_o1_v01_geo.cpp : checkForSensibleGeometry() failed " ) ;
130  }
131 
132  const double rotateAngle = getCurrentAngle(crossingAngle, crossType); // for the placement at +z (better make it const now)
133  const double mirrorAngle = M_PI - rotateAngle; // for the "mirrored" placement at -z
134  // the "mirroring" in fact is done by a rotation of (almost) 180 degrees around the y-axis
135 
136 
137  switch (crossType) {
138  case ODH::kCenter:
139  case ODH::kUpstream:
140  case ODH::kDnstream: {
141  // a volume on the z-axis, on the upstream branch, or on the downstream branch
142  Transform3D transformer, transmirror;
143 
144  if( rotationX == true) {
145  // absolute transformations for the placement in the world, rotate over X
146  transformer = Transform3D(RotationX(rotateAngle), RotateX( Position(0, 0, zPosition), rotateAngle) );
147  transmirror = Transform3D(RotationX(mirrorAngle), RotateX( Position(0, 0, zPosition), mirrorAngle) );
148  } else{
149  // absolute transformations for the placement in the world
150  transformer = Transform3D(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition), rotateAngle) );
151  transmirror = Transform3D(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition), mirrorAngle) );
152  }
153 
154  // solid for the tube (including vacuum and wall): a solid cone
155  ConeSegment tubeSolid( zHalf, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd , phi1, phi2);
156 
157  // tube consists of vacuum
158  Volume tubeLog0( volName, tubeSolid, material ) ;
159  Volume tubeLog1( volName, tubeSolid, material ) ;
160  if (isSensitive) {
161  tubeLog0.setSensitiveDetector(sens);
162  tubeLog1.setSensitiveDetector(sens);
163  }
164  tubeLog0.setVisAttributes(description, xmlMask.visStr() );
165  tubeLog1.setVisAttributes(description, xmlMask.visStr() );
166 
167  // placement of the tube in the world, both at +z and -z
168  PlacedVolume placed0 = envelope.placeVolume( tubeLog0, transformer );
169  PlacedVolume placed1 = envelope.placeVolume( tubeLog1, transmirror );
170 
171  placed0.addPhysVolID("side",1);
172  placed0.addPhysVolID("layer",counter);
173  placed1.addPhysVolID("side",-1);
174  placed1.addPhysVolID("layer",counter);
175 
176  }
177  break;
178 
179  case ODH::kPunchedCenter: {
180  // a cone with one or two inner holes (two tubes are punched out)
181 
182  const double rUpstreamPunch = rInnerStart; // just alias names denoting what is meant here
183  const double rDnstreamPunch = rInnerEnd; // (the database entries are "abused" in this case)
184 
185  // relative transformations for the composition of the SubtractionVolumes
186  Transform3D upstreamTransformer(RotationY(-crossingAngle), Position(zPosition * tan(-crossingAngle), 0, 0));
187  Transform3D dnstreamTransformer(RotationY(+crossingAngle), Position(zPosition * tan(+crossingAngle), 0, 0));
188 
189  // absolute transformations for the final placement in the world (angles always equal zero and 180 deg)
190  Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition) , rotateAngle) );
191  Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition) , mirrorAngle) );
192 
193  // the main solid and the two pieces (only tubes, for the moment) which will be punched out
194  ConeSegment wholeSolid( zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2 );
195  Solid tmpSolid0, tmpSolid1, finalSolid0, finalSolid1;
196 
197  // the punched subtraction solids can be asymmetric and therefore have to be created twice:
198  // one time in the "right" way, another time in the "reverse" way, because the "mirroring"
199  // rotation around the y-axis will not only exchange +z and -z, but also +x and -x
200 
201  if ( rUpstreamPunch > 1e-6 ) { // do we need a hole on the upstream branch?
202  Tube upstreamPunch( 0, rUpstreamPunch, 5 * zHalf, phi1, phi2); // a bit longer
203  tmpSolid0 = SubtractionSolid( wholeSolid, upstreamPunch, upstreamTransformer);
204  tmpSolid1 = SubtractionSolid( wholeSolid, upstreamPunch, dnstreamTransformer); // [sic]
205  } else { // dont't do anything, just pass on the unmodified shape
206  tmpSolid0 = wholeSolid;
207  tmpSolid1 = wholeSolid;
208  }
209 
210  if (rDnstreamPunch > 1e-6 ) { // do we need a hole on the downstream branch?
211  Tube dnstreamPunch( 0, rDnstreamPunch, 5 * zHalf, phi1, phi2); // a bit longer
212  finalSolid0 = SubtractionSolid( tmpSolid0, dnstreamPunch, dnstreamTransformer);
213  finalSolid1 = SubtractionSolid( tmpSolid1, dnstreamPunch, upstreamTransformer); // [sic]
214  } else { // dont't do anything, just pass on the unmodified shape
215  finalSolid0 = tmpSolid0;
216  finalSolid1 = tmpSolid1;
217  }
218 
219  // tube consists of vacuum (will later have two different daughters)
220  Volume tubeLog0( volName + "_0", finalSolid0, material );
221  Volume tubeLog1( volName + "_1", finalSolid1, material );
222  if (isSensitive) {
223  tubeLog0.setSensitiveDetector(sens);
224  tubeLog1.setSensitiveDetector(sens);
225  }
226  tubeLog0.setVisAttributes(description, xmlMask.visStr() );
227  tubeLog1.setVisAttributes(description, xmlMask.visStr() );
228 
229  // placement of the tube in the world, both at +z and -z
230  PlacedVolume placed0 = envelope.placeVolume( tubeLog0, placementTransformer );
231  PlacedVolume placed1 = envelope.placeVolume( tubeLog1, placementTransmirror );
232 
233  placed0.addPhysVolID("side", 1);
234  placed1.addPhysVolID("side", -1);
235  placed0.addPhysVolID("layer", counter);
236  placed1.addPhysVolID("layer", counter);
237 
238  break;
239  }
240 
242  case ODH::kPunchedDnstream: {
243  // a volume on the upstream or downstream branch with two inner holes
244  // (implemented as a cone from which another tube is punched out)
245 
246  const double rCenterPunch = (crossType == ODH::kPunchedUpstream) ? (rInnerStart) : (rInnerEnd); // just alias names denoting what is meant here
247  const double rOffsetPunch = (crossType == ODH::kPunchedDnstream) ? (rInnerStart) : (rInnerEnd); // (the database entries are "abused" in this case)
248 
249  // relative transformations for the composition of the SubtractionVolumes
250  Transform3D punchTransformer(RotationY(-2 * rotateAngle), Position(zPosition * tan(-2 * rotateAngle), 0, 0));
251  Transform3D punchTransmirror(RotationY(+2 * rotateAngle), Position(zPosition * tan(+2 * rotateAngle), 0, 0));
252 
253  // absolute transformations for the final placement in the world
254  Transform3D placementTransformer(RotationY(rotateAngle), RotateY( Position(0, 0, zPosition) , rotateAngle) );
255  Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY( Position(0, 0, zPosition) , mirrorAngle) );
256 
257  // the main solid and the piece (only a tube, for the moment) which will be punched out
258  ConeSegment wholeSolid( zHalf, rCenterPunch , rOuterStart, rCenterPunch, rOuterEnd, phi1, phi2);
259  Tube punchSolid( 0, rOffsetPunch, 5 * zHalf, phi1, phi2); // a bit longer
260 
261  // the punched subtraction solids can be asymmetric and therefore have to be created twice:
262  // one time in the "right" way, another time in the "reverse" way, because the "mirroring"
263  // rotation around the y-axis will not only exchange +z and -z, but also +x and -x
264  SubtractionSolid finalSolid0( wholeSolid, punchSolid, punchTransformer);
265  SubtractionSolid finalSolid1( wholeSolid, punchSolid, punchTransmirror);
266 
267  // tube consists of vacuum (will later have two different daughters)
268  Volume tubeLog0( volName + "_0", finalSolid0, material );
269  Volume tubeLog1( volName + "_1", finalSolid1, material );
270  if (isSensitive) {
271  tubeLog0.setSensitiveDetector(sens);
272  tubeLog1.setSensitiveDetector(sens);
273  }
274  tubeLog0.setVisAttributes(description, xmlMask.visStr() );
275  tubeLog1.setVisAttributes(description, xmlMask.visStr() );
276 
277  // placement of the tube in the world, both at +z and -z
278  PlacedVolume placed0 = envelope.placeVolume( tubeLog0, placementTransformer );
279  PlacedVolume placed1 = envelope.placeVolume( tubeLog1, placementTransmirror );
280 
281  placed0.addPhysVolID("side", 1);
282  placed1.addPhysVolID("side", -1);
283  placed0.addPhysVolID("layer", counter);
284  placed1.addPhysVolID("layer", counter);
285 
286  break;
287  }
288 
290  int maskSide = 1;
291  if (xmlSection.hasAttr(_Unicode(side))) {
292  maskSide = xmlSection.attr<int>(_Unicode(side));
293  }
294 
295  double extraThick = 0.0;
296  if (xmlSection.hasAttr(_Unicode(extra_thickness))) {
297  extraThick = xmlSection.attr<double>(_Unicode(extra_thickness));
298  }
299 
300  // Trapezoid variables from xml
301  const double origBaseHalf = zHalf;
302  const double maskWidthHalf = rInnerStart; // SeparatedBeamPipe_rmax
303  const double offset = rInnerEnd; // Distance from beam axis
304  const double maskTopHalf = rOuterStart; // Flat inner section half-length
305  const double origHeightHalf = rOuterEnd; // Original thickness half-length
306 
307  // Slope-preserving math for the oversized trapezoid
308  // As height increases by extraThick, the base expands proportionally so the slope angle remains invariant.
309  const double maskHeightHalf = origHeightHalf + (extraThick / 2.0);
310  const double maskBaseHalf = maskTopHalf + (origBaseHalf - maskTopHalf) * (maskHeightHalf / origHeightHalf);
311 
312  Trd2 oversizedMask(maskBaseHalf, maskTopHalf, maskWidthHalf, maskWidthHalf, maskHeightHalf);
313 
314  // Determine Orientation and Position in the branch local frame
315  Rotation3D maskOrientation;
316  Position maskLocalPos;
317 
318  if (maskSide == 1) {
319  // RIGHT MASK: Flat top facing inwards (-X)
320  maskOrientation = Rotation3D(RotationY(-90.0 * units::degree));
321  maskLocalPos = Position(offset + maskHeightHalf, 0.0, 0.0);
322  } else {
323  // LEFT MASK: Flat top facing inwards (+X)
324  maskOrientation = Rotation3D(RotationZ(180.0 * units::degree) * RotationY(-90.0 * units::degree));
325  maskLocalPos = Position(-(offset + maskHeightHalf), 0.0, 0.0);
326  }
327 
328  // Create the Transformation mapping from the mask's frame to the branch's frame
329  Transform3D maskTransform(maskOrientation, maskLocalPos);
330 
331  // Boolean Subtraction to carve out the cylindrical wall
332  // Multiply zHalf by 2.0 to guarantee the cutter is safely longer than the mask)
333  Tube outerTube(rInnerStart, rInnerStart + extraThick + 10.0 * units::mm, zHalf * 2.0);
334 
335  // To apply the subtraction, outerTube (which is at 0,0,0 in the branch frame)
336  // must be projected backward into the mask's local coordinate frame.
337  Transform3D tubeInMaskFrame = maskTransform.Inverse();
338 
339  SubtractionSolid finalMaskSolid(oversizedMask, outerTube, tubeInMaskFrame);
340 
341  // Create the Logical Volume
342  Volume maskVol(volName, finalMaskSolid, material);
343  if (isSensitive) {
344  maskVol.setSensitiveDetector(sens);
345  }
346  maskVol.setVisAttributes(description, xmlMask.visStr());
347 
348  // Global Placements
349  Transform3D transformer, transmirror;
350  if (rotationX) {
351  transformer = Transform3D(RotationX(rotateAngle), RotateX(Position(0, 0, zPosition), rotateAngle));
352  transmirror = Transform3D(RotationX(mirrorAngle), RotateX(Position(0, 0, zPosition), mirrorAngle));
353  } else {
354  transformer = Transform3D(RotationY(rotateAngle), RotateY(Position(0, 0, zPosition), rotateAngle));
355  transmirror = Transform3D(RotationY(mirrorAngle), RotateY(Position(0, 0, zPosition), mirrorAngle));
356  }
357 
358  // Multiply the global branch matrix by the local mask placement matrix
359  Transform3D transformFwd = transformer * maskTransform;
360  PlacedVolume placedFwd = envelope.placeVolume(maskVol, transformFwd);
361 
362  Transform3D transformBwd = transmirror * maskTransform;
363  PlacedVolume placedBwd = envelope.placeVolume(maskVol, transformBwd);
364 
365  // Physical IDs
366  placedFwd.addPhysVolID("side", 1).addPhysVolID("layer", counter).addPhysVolID("module", maskSide);
367  placedBwd.addPhysVolID("side", -1).addPhysVolID("layer", counter).addPhysVolID("module", maskSide);
368 
369  break;
370  }
371 
372  default: {
373  throw std::runtime_error( " Mask_o1_v01_geo.cpp : fatal failure !! ?? " ) ;
374  }
375 
376  }//end switch
377 
378  }//for all xmlSections
379 
380  //--------------------------------------
381  Volume mother = description.pickMotherVolume( tube ) ;
382  PlacedVolume pv(mother.placeVolume(envelope));
383  pv.addPhysVolID( "system", xmlMask.id() ) ; //.addPhysVolID("side", 0 ) ;
384 
385  tube.setVisAttributes( description, xmlMask.visStr(), envelope );
386 
387  tube.setPlacement(pv);
388 
389  return tube;
390 }
391 DECLARE_DETELEMENT(DD4hep_Mask_o1_v01,create_detector)
dd4hep::xml::Collection_t
Class to support the access to collections of XmlNodes (or XmlElements)
Definition: XMLElements.h:636
ODH::kCenter
@ kCenter
Definition: OtherDetectorHelpers.h:23
DetectorData.h
dd4hep::SensitiveDetector
Handle class to hold the information of a sensitive detector.
Definition: DetElement.h:43
DECLARE_DETELEMENT
#define DECLARE_DETELEMENT(name, func)
Definition: Factories.h:339
M_PI
#define M_PI
Definition: Handle.h:31
ODH::kPunchedUpstream
@ kPunchedUpstream
Definition: OtherDetectorHelpers.h:27
dd4hep::PlacedVolume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:164
dd4hep::PlacedVolume::addPhysVolID
PlacedVolume & addPhysVolID(const std::string &name, int value)
Add identifier.
Definition: Volumes.cpp:501
dd4hep::Rotation3D
ROOT::Math::Rotation3D Rotation3D
Definition: Objects.h:112
dd4hep::Detector::pickMotherVolume
virtual Volume pickMotherVolume(const DetElement &sd) const =0
Access mother volume by detector element.
dd4hep::xml::Handle_t
Class to easily access the properties of single XmlElements.
Definition: XMLElements.h:380
dd4hep::Handle::name
const char * name() const
Access the object name (or "" if not supported by the object)
DetType.h
dd4hep::Assembly
Implementation class extending the ROOT assembly volumes (TGeoVolumeAssembly)
Definition: Volumes.h:762
dd4hep::Volume::placeVolume
PlacedVolume placeVolume(const Volume &volume) const
Place daughter volume. The position and rotation are the identity.
Definition: Volumes.cpp:859
dd4hep::RotateY
V RotateY(const V &v, double a)
Definition: Objects.h:87
dd4hep::ConeSegment
Class describing a cone segment shape.
Definition: Shapes.h:543
xml_comp_t
dd4hep::xml::Component xml_comp_t
Definition: XML.h:33
_Unicode
#define _Unicode(a)
Definition: Tags.h:24
dd4hep::Trd2
Class describing a Trd2 shape.
Definition: Shapes.h:1159
dd4hep::Material
Handle class describing a material.
Definition: Objects.h:271
ODH::ECrossType
ECrossType
Definition: OtherDetectorHelpers.h:22
dd4hep::Detector::material
virtual Material material(const std::string &name) const =0
Retrieve a matrial by its name from the detector description.
dd4hep::DetElement
Handle class describing a detector element.
Definition: DetElement.h:187
dd4hep::Volume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:371
dd4hep::RotationZ
ROOT::Math::RotationZ RotationZ
Definition: Objects.h:106
Unicode
dd4hep::xml::Strng_t Unicode
Definition: XML.h:24
xml_det_t
dd4hep::xml::DetElement xml_det_t
Definition: XML.h:32
_U
#define _U(a)
Definition: Tags.h:23
dd4hep::RotateX
V RotateX(const V &v, double a)
Definition: Objects.h:84
dd4hep::Trd1
Class describing a Trd1 shape.
Definition: Shapes.h:1099
ODH::kPunchedCenter
@ kPunchedCenter
Definition: OtherDetectorHelpers.h:26
dd4hep::Transform3D
ROOT::Math::Transform3D Transform3D
Definition: Objects.h:116
ODH::kPunchedDnstream
@ kPunchedDnstream
Definition: OtherDetectorHelpers.h:28
dd4hep::Position
ROOT::Math::XYZVector Position
Definition: Objects.h:80
dd4hep::RotationY
ROOT::Math::RotationY RotationY
Definition: Objects.h:108
dd4hep::Ref_t
Handle< NamedObject > Ref_t
Default Ref_t definition describing named objects.
Definition: Handle.h:180
DetFactoryHelper.h
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::Solid
Solid_type< TGeoShape > Solid
Definition: Shapes.h:198
ODH::kDnstream
@ kDnstream
Definition: OtherDetectorHelpers.h:25
dd4hep::Detector
The main interface to the dd4hep detector description package.
Definition: Detector.h:89
dd4hep::RotationX
ROOT::Math::RotationX RotationX
Definition: Objects.h:110
ODH::kUpstreamTrapezoid
@ kUpstreamTrapezoid
Definition: OtherDetectorHelpers.h:41
DD4hepUnits.h
dd4hep::Tube
Class describing a tube shape of a section of a tube.
Definition: Shapes.h:629
OtherDetectorHelpers.h
Printout.h
Utilities.h
dd4hep::SubtractionSolid
Class describing boolean subtraction solid.
Definition: Shapes.h:1874
dd4hep::SensitiveDetector::setType
SensitiveDetector & setType(const std::string &typ)
Set detector type (structure, tracker, calorimeter, etc.).
Definition: DetElement.cpp:403
ODH::kUpstream
@ kUpstream
Definition: OtherDetectorHelpers.h:24