Belle II Software  release-06-02-00
GeoCache.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 
10 #include <vxd/geometry/GeoCache.h>
11 #include <vxd/simulation/SensitiveDetectorBase.h>
12 #include <framework/gearbox/Unit.h>
13 #include <framework/logging/Logger.h>
14 
15 #include <stack>
16 #include <memory>
17 
18 #include <G4LogicalVolume.hh>
19 #include <G4VPhysicalVolume.hh>
20 #include <G4NavigationHistory.hh>
21 #include <G4Transform3D.hh>
22 
23 using namespace std;
24 
25 namespace Belle2 {
30  namespace VXD {
31  GeoCache::GeoCache()
32  {
33  // Add callback to update ReconstructionTransformation whenever alignment changes
34  m_vxdAlignments.addCallback(this, &VXD::GeoCache::setupReconstructionTransformations);
35  }
36 
37  void GeoCache::clear()
38  {
39  m_pxdLayers.clear();
40  m_svdLayers.clear();
41  m_telLayers.clear();
42  m_ladders.clear();
43  m_sensors.clear();
44  m_sensorInfo.clear();
45 
46  m_halfShellPlacements.clear();
47  m_ladderPlacements.clear();
48  m_sensorPlacements.clear();
49  }
50 
51  bool GeoCache::validSensorID(Belle2::VxdID id) const
52  {
53  id.setSegmentNumber(0);
54  SensorInfoMap::const_iterator info = m_sensorInfo.find(id);
55  return (info != m_sensorInfo.end());
56  }
57 
58  const vector<VxdID> GeoCache::getListOfSensors() const
59  {
60  vector<VxdID> sensors;
61  for (auto entry : m_sensorInfo)
62  sensors.push_back(entry.first);
63  return sensors;
64  }
65 
66  const SensorInfoBase& GeoCache::getSensorInfo(VxdID id) const
67  {
68  id.setSegmentNumber(0);
69  SensorInfoMap::const_iterator info = m_sensorInfo.find(id);
70  if (info == m_sensorInfo.end()) {
71  B2WARNING("VXD Sensor " << id << " does not exist.");
72  return *(m_sensorInfo.begin()->second);
73  }
74  return *(info->second);
75  }
76 
77  void GeoCache::findVolumes(G4VPhysicalVolume* envelope)
78  {
79  //So, lets loop over the geometry tree and find all sensitive volumes.
80  //To get the correct Transformation matrices we use the
81  //G4NavigationHistory which is a stack of premultiplied transformations.
82  G4NavigationHistory nav;
83  //To avoid recursion we store all volumes in a stack, starting with the
84  //envelope we are about to search in
85  stack<G4VPhysicalVolume*> volumes;
86  volumes.push(envelope);
87 
88  //Now lets just continue until the stack is empty
89  while (!volumes.empty()) {
90  G4VPhysicalVolume* physical = volumes.top();
91  volumes.pop();
92  //NULL indicates that we are finished with the children of a node, so
93  //pop a transformation level
94  if (!physical) {
95  nav.BackLevel();
96  continue;
97  }
98  //Add a NULL to so that we know that all children are finished once we
99  //emptied the stack of volumes back to this NULL
100  volumes.push(0);
101  //Now enter the volume
102  nav.NewLevel(physical);
103 
104  G4LogicalVolume* logical = physical->GetLogicalVolume();
105 
106  //Check if we found a sensitive volume with correct type
107  SensitiveDetectorBase* sensitive = dynamic_cast<SensitiveDetectorBase*>(logical->GetSensitiveDetector());
108  if (sensitive) {
109  //Apparently we did, so get the sensor Information and add it
110  SensorInfoBase* info = sensitive->getSensorInfo();
111  if (!info) B2FATAL("No SensorInfo found for Volume " << logical->GetName());
112 
113  //Convert transformation to ROOT
114  const G4AffineTransform g4transform = nav.GetTopTransform().Inverse();
115  TGeoHMatrix transform;
116  double rotation[9] = {
117  g4transform[0], g4transform[4], g4transform[8],
118  g4transform[1], g4transform[5], g4transform[9],
119  g4transform[2], g4transform[6], g4transform[10]
120  };
121  transform.SetRotation(rotation);
122  transform.SetDx(g4transform[12]*Unit::mm);
123  transform.SetDy(g4transform[13]*Unit::mm);
124  transform.SetDz(g4transform[14]*Unit::mm);
125  info->setTransformation(transform);
126  info->setTransformation(transform, true);
127 
128  addSensor(info);
129  }
130 
131  int nDaughters = logical->GetNoDaughters();
132  //Add all children. Since we use a stack they will be processed in
133  //opposite order In principle we do not care, but for niceness sake we
134  //add them back to front so that they are processed in the "correct"
135  //order
136  for (int i = nDaughters - 1; i >= 0; --i) {
137  G4VPhysicalVolume* daughter = logical->GetDaughter(i);
138  volumes.push(daughter);
139  }
140  }
141 
142  // Finally set-up reconstruction transformations
143  setupReconstructionTransformations();
144  }
145 
146  void GeoCache::addSensor(SensorInfoBase* sensorinfo)
147  {
148  //Save pointer to the SensorInfo and update lists of all existing
149  //layers,ladders,sensors
150  VxdID sensorID = sensorinfo->getID();
151  VxdID ladderID = sensorID;
152  ladderID.setSensorNumber(0);
153  VxdID layerID = ladderID;
154  layerID.setLadderNumber(0);
155 
156  m_sensorInfo[sensorID] = sensorinfo;
157 
158  switch (sensorinfo->getType()) {
159  case SensorInfoBase::PXD:
160  m_pxdLayers.insert(layerID);
161  break;
162  case SensorInfoBase::SVD:
163  m_svdLayers.insert(layerID);
164  break;
165  case SensorInfoBase::TEL:
166  m_telLayers.insert(layerID);
167  break;
168  default:
169  B2FATAL("Cannot use anything else as SensorTypes PXD, SVD, or TEL when creating VXD Sensors");
170  }
171  m_ladders[layerID].insert(ladderID);
172  m_sensors[ladderID].insert(sensorID);
173  }
174 
175  const set<VxdID> GeoCache::getLayers(SensorInfoBase::SensorType type)
176  {
177  switch (type) {
178  case SensorInfoBase::PXD:
179  return m_pxdLayers;
180  case SensorInfoBase::SVD:
181  return m_svdLayers;
182  case SensorInfoBase::TEL:
183  return m_telLayers;
184  default:
185  std::set<VxdID> allLayers = m_pxdLayers;
186  allLayers.insert(m_svdLayers.begin(), m_svdLayers.end());
187  allLayers.insert(m_telLayers.begin(), m_telLayers.end());
188  return allLayers;
189  }
190  }
191 
192  const set<VxdID>& GeoCache::getLadders(VxdID layer) const
193  {
194  //We only index by layer, so set everything else to 0
195  layer.setLadderNumber(0);
196  layer.setSensorNumber(0);
197  layer.setSegmentNumber(0);
198  SensorHierachy::const_iterator info = m_ladders.find(layer);
199  if (info == m_ladders.end()) B2FATAL("VXD Layer " << layer << "does not exist.");
200  return info->second;
201  }
202 
203  const set<VxdID>& GeoCache::getSensors(VxdID ladder) const
204  {
205  //We only index by layer and ladder, set sensor to 0
206  ladder.setSensorNumber(0);
207  ladder.setSegmentNumber(0);
208  SensorHierachy::const_iterator info = m_sensors.find(ladder);
209  if (info == m_sensors.end()) B2FATAL("VXD Ladder " << ladder << "does not exist.");
210  return info->second;
211  }
212 
213  GeoCache& GeoCache::getInstance()
214  {
215  static unique_ptr<GeoCache> instance(new GeoCache());
216  return *instance;
217  }
218 
219  void GeoCache::addSensorPlacement(VxdID ladder, VxdID sensor, const G4Transform3D& placement)
220  {
221  m_sensorPlacements[ladder].push_back(std::make_pair(sensor, g4Transform3DToTGeo(placement)));
222  }
223 
224  void GeoCache::addLadderPlacement(VxdID halfShell, VxdID ladder, const G4Transform3D& placement)
225  {
226  m_ladderPlacements[halfShell].push_back(std::make_pair(ladder, g4Transform3DToTGeo(placement)));
227  // Add the (empty) container for sensor placements inside this ladder
228  m_sensorPlacements[ladder] = std::vector<std::pair<VxdID, TGeoHMatrix>>();
229  }
230 
231  void GeoCache::addHalfShellPlacement(VxdID halfShell, const G4Transform3D& placement)
232  {
233  m_halfShellPlacements[halfShell] = g4Transform3DToTGeo(placement);
234  // Add the (empty) container for ladder placements inside this halfshell
235  m_ladderPlacements[halfShell] = std::vector<std::pair<VxdID, TGeoHMatrix>>();
236  }
237 
238  const map<VxdID, TGeoHMatrix>& GeoCache::getHalfShellPlacements() const {return m_halfShellPlacements;}
239 
240  const vector< pair< VxdID, TGeoHMatrix > >& GeoCache::getSensorPlacements(VxdID ladder) const
241  {
242  auto placements = m_sensorPlacements.find(ladder);
243  if (placements == m_sensorPlacements.end())
244  throw std::invalid_argument("Invalid ladder id " + (std::string) ladder);
245 
246  return placements->second;
247  }
248 
249  const vector< pair< VxdID, TGeoHMatrix > >& GeoCache::getLadderPlacements(VxdID halfShell) const
250  {
251  auto placements = m_ladderPlacements.find(halfShell);
252  if (placements == m_ladderPlacements.end())
253  throw std::invalid_argument("Invalid half-shelve id " + (std::string) halfShell);
254 
255  return placements->second;
256  }
257 
258  void GeoCache::setupReconstructionTransformations()
259  {
260  if (!m_vxdAlignments.isValid()) {
261  B2WARNING("No VXD alignment data. Defaults (0's) will be used!");
262  return;
263  }
264 
265  // Loop over VXD sensors to read parameters for description of planar defomration
266  for (auto& sensorID : getListOfSensors()) {
267  std::vector<double> planarParameters = {
268  // Numbering of VXD alignment parameters:
269  // -> 0-6: Rigid body alignment
270  // -> 31-33: First level of surface deformation
271  // -> 41-44: Second level of surface deformation
272  // -> 51-55: Third level of surface deformation
273  m_vxdAlignments->get(sensorID, 31),
274  m_vxdAlignments->get(sensorID, 32),
275  m_vxdAlignments->get(sensorID, 33),
276  m_vxdAlignments->get(sensorID, 41),
277  m_vxdAlignments->get(sensorID, 42),
278  m_vxdAlignments->get(sensorID, 43),
279  m_vxdAlignments->get(sensorID, 44),
280  m_vxdAlignments->get(sensorID, 51),
281  m_vxdAlignments->get(sensorID, 52),
282  m_vxdAlignments->get(sensorID, 53),
283  m_vxdAlignments->get(sensorID, 54),
284  m_vxdAlignments->get(sensorID, 55),
285  };
286 
287  // Store parameters for planar deformation
288  VXD::SensorInfoBase& sensorInfo = const_cast<VXD::SensorInfoBase&>(getSensorInfo(sensorID));
289  sensorInfo.setSurfaceParameters(planarParameters);
290  }
291 
303  for (auto& halfShellPlacement : getHalfShellPlacements()) {
304  TGeoHMatrix trafoHalfShell = halfShellPlacement.second;
305  trafoHalfShell *= getTGeoFromRigidBodyParams(
306  m_vxdAlignments->get(halfShellPlacement.first, VXDAlignment::dU),
307  m_vxdAlignments->get(halfShellPlacement.first, VXDAlignment::dV),
308  m_vxdAlignments->get(halfShellPlacement.first, VXDAlignment::dW),
309  m_vxdAlignments->get(halfShellPlacement.first, VXDAlignment::dAlpha),
310  m_vxdAlignments->get(halfShellPlacement.first, VXDAlignment::dBeta),
311  m_vxdAlignments->get(halfShellPlacement.first, VXDAlignment::dGamma)
312  );
313 
314  for (auto& ladderPlacement : getLadderPlacements(halfShellPlacement.first)) {
315  // Updated trafo
316  TGeoHMatrix trafoLadder = ladderPlacement.second;
317  trafoLadder *= getTGeoFromRigidBodyParams(
318  m_vxdAlignments->get(ladderPlacement.first, VXDAlignment::dU),
319  m_vxdAlignments->get(ladderPlacement.first, VXDAlignment::dV),
320  m_vxdAlignments->get(ladderPlacement.first, VXDAlignment::dW),
321  m_vxdAlignments->get(ladderPlacement.first, VXDAlignment::dAlpha),
322  m_vxdAlignments->get(ladderPlacement.first, VXDAlignment::dBeta),
323  m_vxdAlignments->get(ladderPlacement.first, VXDAlignment::dGamma)
324  );
325 
326  for (auto& sensorPlacement : getSensorPlacements(ladderPlacement.first)) {
327  // Updated trafo
328  TGeoHMatrix trafoSensor = sensorPlacement.second;
329  trafoSensor *= getTGeoFromRigidBodyParams(
330  m_vxdAlignments->get(sensorPlacement.first, VXDAlignment::dU),
331  m_vxdAlignments->get(sensorPlacement.first, VXDAlignment::dV),
332  m_vxdAlignments->get(sensorPlacement.first, VXDAlignment::dW),
333  m_vxdAlignments->get(sensorPlacement.first, VXDAlignment::dAlpha),
334  m_vxdAlignments->get(sensorPlacement.first, VXDAlignment::dBeta),
335  m_vxdAlignments->get(sensorPlacement.first, VXDAlignment::dGamma)
336  );
337 
338  // Store new reco-transformation
339  VXD::SensorInfoBase& geometry = const_cast<VXD::SensorInfoBase&>(getSensorInfo(sensorPlacement.first));
340  geometry.setTransformation(trafoHalfShell * trafoLadder * trafoSensor, true);
341 
342  }
343  }
344  }
345 
346  }
347 
348  TGeoHMatrix GeoCache::g4Transform3DToTGeo(const G4Transform3D& g4)
349  {
350  TGeoHMatrix trafo;
351  // Differential translation
352  TGeoTranslation translation;
353  // Differential rotation
354  TGeoRotation rotation;
355 
356  //NOTE: for some reason, there is cm vs. mm difference
357  trafo.SetDx(g4.getTranslation()[0] / 10.);
358  trafo.SetDy(g4.getTranslation()[1] / 10.);
359  trafo.SetDz(g4.getTranslation()[2] / 10.);
360 
361  Double_t rotMatrix[9];
362  for (int i = 0; i < 3; ++i) {
363  for (int j = 0; j < 3; ++j) {
364  rotMatrix[i * 3 + j] = g4.getRotation()[i][j];
365  }
366  }
367  trafo.SetRotation(rotMatrix);
368  return trafo;
369  }
370 
371  TGeoHMatrix GeoCache::getTGeoFromRigidBodyParams(double dU, double dV, double dW, double dAlpha, double dBeta, double dGamma)
372  {
373  // Differential translation
374  TGeoTranslation translation;
375  // Differential rotation
376  TGeoRotation rotation;
377 
378  translation.SetTranslation(dU, dV, dW);
379  rotation.RotateX(- dAlpha * TMath::RadToDeg());
380  rotation.RotateY(- dBeta * TMath::RadToDeg());
381  rotation.RotateZ(- dGamma * TMath::RadToDeg());
382 
383  // Differential trafo (trans + rot)
384  TGeoCombiTrans combi(translation, rotation);
385  TGeoHMatrix trafo;
386  trafo = trafo * combi;
387  return trafo;
388  }
389  } //VXD namespace
391 } //Belle2 namespace
Class to faciliate easy access to sensor information of the VXD like coordinate transformations or pi...
Definition: GeoCache.h:39
Base class for Sensitive Detector implementation of PXD and SVD.
SensorInfoBase * getSensorInfo()
Return a pointer to the SensorInfo associated with this instance.
Base class to provide Sensor Information for PXD and SVD.
SensorType getType() const
Return the Type of the Sensor.
SensorType
Enum specifing the type of sensor the SensorInfo represents.
VxdID getID() const
Return the ID of the Sensor.
void setSurfaceParameters(const std::vector< double > &planarParameters)
Fill parameters of planar deformation to vector.
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33
void setSensorNumber(baseType sensor)
Set the sensor id.
Definition: VxdID.h:111
void setLadderNumber(baseType ladder)
Set the ladder id.
Definition: VxdID.h:109
Abstract base class for different kinds of events.