ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FCChhTrackerTkLayout_Endcap.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FCChhTrackerTkLayout_Endcap.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include "../DetUtils.h"
11 #include "DD4hep/DetFactoryHelper.h"
12 
13 using dd4hep::DetElement;
14 using dd4hep::PlacedVolume;
15 using dd4hep::Volume;
16 using dd4hep::xml::Component;
17 using dd4hep::xml::Dimension;
18 
19 namespace det {
20 static dd4hep::Ref_t createTkLayoutTrackerEndcap(
21  dd4hep::Detector& lcdd, dd4hep::xml::Handle_t xmlElement,
22  dd4hep::SensitiveDetector sensDet) {
23  // shorthands
24  dd4hep::xml::DetElement xmlDet =
25  static_cast<dd4hep::xml::DetElement>(xmlElement);
26  Dimension dimensions(xmlDet.dimensions());
27  double l_overlapMargin = 0.01;
28 
29  // get sensitive detector type from xml
30  dd4hep::xml::Dimension sdTyp =
31  xmlElement.child(_Unicode(sensitive)); // retrieve the type
32  sensDet.setType(sdTyp.typeStr()); // set for the whole detector
33 
34  // definition of top volume
35  std::string detName = xmlDet.nameStr();
36  DetElement worldDetElement(detName, xmlDet.id());
37  DetElement posEcapDetElement(worldDetElement, "posEndcap", 0);
38 
39  Acts::ActsExtension* ecapDetExt = new Acts::ActsExtension();
40  ecapDetExt->addType("endcap", "detector");
41  posEcapDetElement.addExtension<Acts::ActsExtension>(ecapDetExt);
42 
43  dd4hep::Assembly envelopeVolume("endcapEnvelope");
44  envelopeVolume.setVisAttributes(lcdd.invisible());
45 
46  Component xDiscs = xmlElement.child(_Unicode(discs));
47 
48  double envelopeThickness = 0.5 * (dimensions.zmax() - dimensions.zmin());
49 
50  l_overlapMargin *= 0.9;
51 
52  unsigned int discCounter = 0;
53  unsigned int compCounter = 0;
54  double currentZ;
55  std::vector<Volume> discVolumeVec;
56  std::vector<DetElement> discDetElementVec;
58  for (dd4hep::xml::Collection_t xDiscColl(xDiscs, _Unicode(discZPls));
59  nullptr != xDiscColl; ++xDiscColl) {
60  Component xDisc = static_cast<Component>(xDiscColl);
61  Component xCurrentRings = xDisc.child(_Unicode(rings));
62  // create disc volume
63  double discThickness = 0.5 * (xDisc.zmax() - xDisc.zmin());
64  currentZ = xDisc.z() - dimensions.zmin() - envelopeThickness;
65  if (xCurrentRings.hasChild(
66  _Unicode(ring))) { // we have information to construct a new volume
67  dd4hep::Tube discShape(xDisc.rmin() - l_overlapMargin,
68  xDisc.rmax() + l_overlapMargin,
69  discThickness + l_overlapMargin);
70 
71  discVolumeVec.emplace_back("disc", discShape, lcdd.air());
72  discDetElementVec.emplace_back(
73  posEcapDetElement, "disc" + std::to_string(discCounter), discCounter);
74  // the local coordinate systems of modules in dd4hep and acts differ
75  // see http://acts.web.cern.ch/ACTS/latest/doc/group__DD4hepPlugins.html
76  Acts::ActsExtension* detlayer = new Acts::ActsExtension();
77  detlayer->addType("sensitive disk", "layer");
78  detlayer->addType("axes", "definitions", "XZY");
79  discDetElementVec.back().addExtension<Acts::ActsExtension>(detlayer);
80  // iterate over rings
81  for (dd4hep::xml::Collection_t xRingColl(xCurrentRings, _U(ring));
82  (nullptr != xRingColl); ++xRingColl) {
83  Component xRing = static_cast<Component>(xRingColl);
84  Component xRingModules = xRing.child(_Unicode(modules));
85  Component xModuleOdd = xRingModules.child(_Unicode(moduleOdd));
86  Component xModuleEven = xRingModules.child(_Unicode(moduleEven));
87  Component xModuleProperties = xRing.child(_Unicode(moduleProperties));
88  Component xModulePropertiesComp =
89  xModuleProperties.child(_Unicode(components));
90  Component xSensorProperties = xRing.child(_Unicode(sensorProperties));
91 
92  // the component materials
93  std::vector<std::pair<dd4hep::Material, double>> compMaterials;
94  // place components in module
95  for (dd4hep::xml::Collection_t xCompColl(xModulePropertiesComp,
96  _U(component));
97  nullptr != xCompColl; ++xCompColl) {
98  dd4hep::xml::Component xComp = static_cast<Component>(xCompColl);
99  // collect module materials
100  compMaterials.push_back(std::make_pair(
101  lcdd.material(xComp.materialStr()), xComp.thickness()));
102  }
103  double integratedCompThickness = 0.;
104  for (dd4hep::xml::Collection_t xCompColl(xModulePropertiesComp,
105  _U(component));
106  nullptr != xCompColl; ++xCompColl) {
107  Component xComp = static_cast<Component>(xCompColl);
108  double compMinWidth =
109  0.5 * xModuleProperties.attr<double>("modWidthMin");
110  double compMaxWidth =
111  0.5 * xModuleProperties.attr<double>("modWidthMax");
112  double compThickness = 0.5 * xComp.thickness();
113  double compLength =
114  0.5 * xSensorProperties.attr<double>("sensorLength");
115  Volume componentVolume(
116  "component",
117  dd4hep::Trapezoid(compMinWidth, compMaxWidth, compThickness,
118  compThickness, compLength),
119  lcdd.material(xComp.materialStr()));
120 
121  // Create digitization module
122  auto digiModule = det::utils::trapezoidalDigiModuleXZ(
123  compMinWidth, compMaxWidth, compLength, compThickness, xRing.X(),
124  xRing.Z());
125 
126  componentVolume.setVisAttributes(lcdd.invisible());
127  unsigned int nPhi = xRing.attr<int>("nModules");
128  double phi = 0;
129  for (unsigned int phiIndex = 0; phiIndex < nPhi; ++phiIndex) {
130  double lX = 0;
131  double lY = 0;
132  double lZ = 0;
133  double phiTilt = 0;
134  double thetaTilt = 0;
135  if (0 == phiIndex % 2) {
136  // the rotation for the odd module is already taken care
137  // of by the position in tklayout xml
138  phi = 2 * dd4hep::pi * static_cast<double>(phiIndex) /
139  static_cast<double>(nPhi);
140  lX = xModuleEven.X();
141  lY = xModuleEven.Y();
142  lZ = xModuleEven.Z() - xDisc.zmin() - discThickness;
143  phiTilt = xModuleEven.attr<double>("phiTilt");
144  thetaTilt = xModuleEven.attr<double>("thetaTilt");
145  } else {
146  lX = xModuleOdd.X();
147  lY = xModuleOdd.Y();
148  lZ = xModuleOdd.Z() - xDisc.zmin() - discThickness;
149  phiTilt = xModuleOdd.attr<double>("phiTilt");
150  thetaTilt = xModuleOdd.attr<double>("thetaTilt");
151  }
152  // position module in the x-y plane, smaller end inward
153  // and incorporate phi tilt if any
154  dd4hep::RotationY lRotation1(M_PI * 0.5);
155  dd4hep::RotationX lRotation2(M_PI * 0.5 + phiTilt);
156  // align radially
157  double componentOffset =
158  integratedCompThickness -
159  0.5 * xModuleProperties.attr<double>("modThickness") +
160  0.5 * xComp.thickness();
161  dd4hep::RotationZ lRotation3(atan2(lY, lX));
162  // theta tilt, if any -- note the different convention between
163  // tklayout and here, thus the subtraction of pi / 2
164  dd4hep::RotationY lRotation4(thetaTilt - M_PI * 0.5);
165  dd4hep::RotationZ lRotation_PhiPos(phi);
166  // position in disk
167  dd4hep::Translation3D lTranslation(lX, lY, lZ + componentOffset);
168  dd4hep::Transform3D myTrafo(
169  lRotation4 * lRotation3 * lRotation2 * lRotation1,
170  lTranslation);
171  PlacedVolume placedComponentVolume =
172  discVolumeVec.back().placeVolume(componentVolume,
173  lRotation_PhiPos * myTrafo);
174  if (xComp.isSensitive()) {
175  placedComponentVolume.addPhysVolID("component", compCounter);
176  componentVolume.setSensitiveDetector(sensDet);
177  DetElement moduleDetElement(discDetElementVec.back(),
178  "comp" + std::to_string(compCounter),
179  compCounter);
180 
181  // add extension to hand over material
182  Acts::ActsExtension* moduleExtension = new Acts::ActsExtension();
183  moduleDetElement.addExtension<Acts::ActsExtension>(
184  moduleExtension);
185 
186  moduleDetElement.setPlacement(placedComponentVolume);
187  ++compCounter;
188  }
189  }
190  integratedCompThickness += xComp.thickness();
191  }
192  }
193  } else {
194  discDetElementVec.emplace_back(
195  discDetElementVec.back().clone("disc" + std::to_string(discCounter)));
196  posEcapDetElement.add(discDetElementVec.back());
197  }
198  PlacedVolume placedDiscVolume = envelopeVolume.placeVolume(
199  discVolumeVec.back(), dd4hep::Position(0, 0, currentZ));
200  placedDiscVolume.addPhysVolID("disc", discCounter);
201  ++discCounter;
202 
203  discDetElementVec.back().setPlacement(placedDiscVolume);
204  }
205  dd4hep::Assembly bothEndcaps("bothEndcapsEnvelope");
206 
207  dd4hep::Translation3D envelopeTranslation(
208  0, 0, dimensions.zmin() + envelopeThickness);
209 
210  dd4hep::RotationX envelopeNegRotation(dd4hep::pi);
211  dd4hep::RotationX envelopePosRotation(0.);
212  PlacedVolume placedEnvelopeVolume = bothEndcaps.placeVolume(
213  envelopeVolume, envelopePosRotation * envelopeTranslation);
214  PlacedVolume placedNegEnvelopeVolume = bothEndcaps.placeVolume(
215  envelopeVolume, envelopeNegRotation * envelopeTranslation);
216  placedEnvelopeVolume.addPhysVolID("posneg", 0);
217  placedNegEnvelopeVolume.addPhysVolID("posneg", 1);
218  auto negEcapDetElement = posEcapDetElement.clone("negEndcap");
219 
220  posEcapDetElement.setPlacement(placedEnvelopeVolume);
221  negEcapDetElement.setPlacement(placedNegEnvelopeVolume);
222  worldDetElement.add(negEcapDetElement);
223  // top of the hierarchy
224  PlacedVolume mplv =
225  lcdd.pickMotherVolume(worldDetElement).placeVolume(bothEndcaps);
226  worldDetElement.setPlacement(mplv);
227  mplv.addPhysVolID("system", xmlDet.id());
228  return worldDetElement;
229 }
230 } // namespace det
231 
232 DECLARE_DETELEMENT(TkLayoutEcapTracker, det::createTkLayoutTrackerEndcap)