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