EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ODDStripBarrel_geo.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ODDStripBarrel_geo.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 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 
11 
12 #include "DD4hep/DetFactoryHelper.h"
13 #include "ODDModuleHelper.hpp"
14 #include "ODDServiceHelper.hpp"
15 
16 using namespace std;
17 using namespace dd4hep;
18 
19 static Ref_t create_element(Detector& oddd, xml_h xml, SensitiveDetector sens) {
20  xml_det_t x_det = xml;
21  string detName = x_det.nameStr();
22 
23  // Make DetElement
24  DetElement barrelDetector(detName, x_det.id());
25 
26  // Add Extension to DetElement for the RecoGeometry
27  Acts::ActsExtension* barrelExtension = new Acts::ActsExtension();
28  barrelExtension->addType("barrel", "detector");
29  // Add the volume boundary material if configured
30  for (xml_coll_t bmat(x_det, _Unicode(boundary_material)); bmat; ++bmat) {
31  xml_comp_t x_boundary_material = bmat;
32  xmlToProtoSurfaceMaterial(x_boundary_material, *barrelExtension,
33  "boundary_material");
34  }
35  barrelDetector.addExtension<Acts::ActsExtension>(barrelExtension);
36 
37  // Make Volume
38  dd4hep::xml::Dimension x_det_dim(x_det.dimensions());
39  string barrelShapeName = x_det_dim.nameStr();
40 
41  Tube barrelShape(x_det_dim.rmin(), x_det_dim.rmax(), x_det_dim.dz());
42  Volume barrelVolume(detName, barrelShape, oddd.air());
43  barrelVolume.setVisAttributes(oddd, x_det.visStr());
44 
45  // Create the stave volume and DetElement tree
46  xml_comp_t x_stave = x_det.child(_U(stave));
47  Assembly staveAssembly("stave");
48  // Visualization
49  staveAssembly.setVisAttributes(oddd, x_stave.visStr());
50  // DetElement tree
51  DetElement staveElementTemplate("StaveElementTemplate", 0);
52 
53  // Build a template module for the Barrel
54  xml_comp_t x_module = x_det.child(_U(module));
55  double length = 0.;
56  auto module =
57  ODDModuleHelper::assembleRectangularModule(oddd, sens, x_module, length);
58 
59  // Place the modules into the stave
60  double gap = x_stave.gap();
61  unsigned int nModules = x_stave.nmodules();
62  double ystep = length + gap;
63  double ymin = (nModules * 0.5 - 0.5) * length;
64  double staveHlength = ymin + 0.5 * length;
65 
66  // Loop over the modules and place them in the stave
67  for (unsigned int moduleNum = 0; moduleNum < nModules; ++moduleNum) {
68  double positionY = -ymin + moduleNum * ystep;
69  // Place the cable bundle, one per stave
70  if (x_stave.hasChild(_U(eltube))) {
71  // Retrieve cable parameters
72  xml_comp_t x_cable = x_stave.child(_U(eltube));
73 
74  double rMin = x_cable.rmin();
75  double rMax = x_cable.rmax();
76 
77  // For an odd number of modules this will create an asymmetric powering
78  // (as it should)
79  double rStep = (rMax - rMin) / (0.5 * nModules);
80  double rCable = rMin + abs(moduleNum - 0.5 * nModules) * rStep;
81 
82  Tube cable(0., rCable, 0.495 * ystep);
83  // Create the scable volume
84  Volume cableVolume("Cable", cable, oddd.material(x_cable.materialStr()));
85  cableVolume.setVisAttributes(oddd, x_cable.visStr());
86 
87  // Place the pipe in the stave
88  staveAssembly.placeVolume(
89  cableVolume, Transform3D(RotationX(0.5 * M_PI),
90  Position(x_cable.x_offset(), positionY,
91  x_cable.z_offset())));
92  }
93 
94  // Place them along local y
95  PlacedVolume placedModule =
96  staveAssembly.placeVolume(module.first, Position(0., positionY, 0.));
97  placedModule.addPhysVolID("module", moduleNum);
98 
99  string moduleName = _toString((int)moduleNum, "module%d");
100  // Clone the detector element
101  auto moduleElement = module.second.clone(moduleName, moduleNum);
102  moduleElement.setPlacement(placedModule);
103  // Assign it as child to the stave template
104  staveElementTemplate.add(moduleElement);
105  }
106 
107  // Remember the layer radii
108  std::vector<double> layerR;
109 
110  // Loop over the layers to build staves
111  size_t layerNum = 0;
112  for (xml_coll_t lay(xml, _U(layer)); lay; ++lay, ++layerNum) {
113  xml_comp_t x_layer = lay;
114 
115  string layerName = detName + std::to_string(layerNum);
116  // The Module envelope volume
117  Volume layerVolume(
118  layerName,
119  Tube(x_layer.rmin(), x_layer.rmax(), staveHlength + x_layer.outer_z()),
120  oddd.air());
121  // Visualization
122  layerVolume.setVisAttributes(oddd, x_layer.visStr());
123 
124  // The DetElement tree, keep it flat
125  DetElement layerElement(barrelDetector, layerName, layerNum);
126 
127  // Place the staves in the layer
128  unsigned int nStaves = x_layer.nphi();
129  double phiStep = 2. * M_PI / nStaves;
130  double phiTilt = x_layer.phi_tilt();
131  double phi0 = x_layer.phi0();
132  double r = x_layer.r();
133  layerR.push_back(r);
134 
135  // Loop over the staves and place them
136  for (unsigned int staveNum = 0; staveNum < nStaves; ++staveNum) {
137  string staveName = _toString((int)staveNum, "stave%d");
138  // position of the stave
139  double phi = phi0 + staveNum * phiStep;
140  double x = r * cos(phi);
141  double y = r * sin(phi);
142  // Now place the stave
143  PlacedVolume placedStave = layerVolume.placeVolume(
144  staveAssembly,
145  Transform3D(RotationY(0.5 * M_PI) * RotationZ(0.5 * M_PI) *
146  RotationY(phi + phiTilt),
147  Position(x, y, 0.)));
148  placedStave.addPhysVolID("stave", staveNum);
149 
150  // Clone the stave element from the template
151  DetElement staveElement = staveElementTemplate.clone(staveName, staveNum);
152  staveElement.setPlacement(placedStave);
153  // Add to the layer element
154  layerElement.add(staveElement);
155  }
156 
157  // Place the support cylinder
158  std::vector<double> dummyR;
159  buildSupportCylinder(oddd, barrelVolume, x_layer, dummyR);
160 
161  // Place the layer with appropriate Acts::Extension
162  // Configure the ACTS extension
163  Acts::ActsExtension* layerExtension = new Acts::ActsExtension();
164  layerExtension->addType("sensitive cylinder", "layer");
165  layerElement.addExtension<Acts::ActsExtension>(layerExtension);
166  // Add the proto layer material
167  for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) {
168  xml_comp_t x_layer_material = lmat;
169  xmlToProtoSurfaceMaterial(x_layer_material, *layerExtension,
170  "layer_material");
171  }
172  PlacedVolume placedLayer = barrelVolume.placeVolume(layerVolume);
173  placedLayer.addPhysVolID("layer", layerNum);
174 
175  // Assign layer DetElement to layer volume
176  layerElement.setPlacement(placedLayer);
177 
178  } // loop over layers
179 
180  // Place the support rails
181  buildSupportCylinder(oddd, barrelVolume, x_det, layerR);
182 
183  // Route the services out on both sides
184  if (x_det.hasChild(_Unicode(services))) {
185  // Grab the services
186  xml_comp_t x_services = x_det.child(_Unicode(services));
187  if (x_services.hasChild(_Unicode(cable_routing))) {
188  xml_comp_t x_cable_routing = x_services.child(_Unicode(cable_routing));
189  buildBarrelRouting(oddd, barrelVolume, x_cable_routing, layerR);
190  }
191  if (x_services.hasChild(_Unicode(cooling_routing))) {
192  xml_comp_t x_cooling_routing =
193  x_services.child(_Unicode(cooling_routing));
194  buildBarrelRouting(oddd, barrelVolume, x_cooling_routing, layerR);
195  }
196  }
197 
198  // Place Volume
199  Volume motherVolume = oddd.pickMotherVolume(barrelDetector);
200  Position translation(0., 0., x_det_dim.z());
201  PlacedVolume placedBarrel =
202  motherVolume.placeVolume(barrelVolume, translation);
203  // "system" is hard coded in the DD4Hep::VolumeManager
204  placedBarrel.addPhysVolID("system", barrelDetector.id());
205  barrelDetector.setPlacement(placedBarrel);
206 
207  // And return it
208  return barrelDetector;
209 }
210 
211 DECLARE_DETELEMENT(ODDStripBarrel, create_element)