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