EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
VolumeMaterialMapper.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file VolumeMaterialMapper.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019-2020 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 
20 
21 namespace {
23 using Grid2D =
25 using Grid3D =
28 using MaterialGrid3D =
30 
31 } // namespace
32 
34  const Config& cfg, StraightLinePropagator propagator,
35  std::unique_ptr<const Logger> slogger)
36  : m_cfg(cfg),
37  m_propagator(std::move(propagator)),
38  m_logger(std::move(slogger)) {}
39 
41  const GeometryContext& gctx, const MagneticFieldContext& mctx,
42  const TrackingGeometry& tGeometry) const {
43  // Parse the geometry and find all surfaces with material proxies
44  auto world = tGeometry.highestTrackingVolume();
45 
46  // The Surface material mapping state
47  State mState(gctx, mctx);
48  resolveMaterialVolume(mState, *world);
49  collectMaterialSurfaces(mState, *world);
50  return mState;
51 }
52 
54  State& mState, const TrackingVolume& tVolume) const {
55  ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
56  << "' for material surfaces.")
57 
58  ACTS_VERBOSE("- Insert Volume ...");
59  checkAndInsert(mState, tVolume);
60 
61  // Step down into the sub volume
62  if (tVolume.confinedVolumes()) {
63  ACTS_VERBOSE("- Check children volume ...");
64  for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
65  // Recursive call
66  resolveMaterialVolume(mState, *sVolume);
67  }
68  }
69  if (!tVolume.denseVolumes().empty()) {
70  for (auto& sVolume : tVolume.denseVolumes()) {
71  // Recursive call
72  resolveMaterialVolume(mState, *sVolume);
73  }
74  }
75 }
76 
78  State& mState, const TrackingVolume& volume) const {
79  auto volumeMaterial = volume.volumeMaterial();
80  // Check if the volume has a proxy
81  if (volumeMaterial != nullptr) {
82  auto geoID = volume.geometryId();
83  size_t volumeID = geoID.volume();
84  ACTS_DEBUG("Material volume found with volumeID " << volumeID);
85  ACTS_DEBUG(" - ID is " << geoID);
86 
88  mState.recordedMaterial[geoID] = mat;
89 
90  // We need a dynamic_cast to either a volume material proxy or
91  // proper surface material
92  auto psm = dynamic_cast<const ProtoVolumeMaterial*>(volumeMaterial);
93  // Get the bin utility: try proxy material first
94  const BinUtility* bu = (psm != nullptr) ? (&psm->binUtility()) : nullptr;
95  if (bu != nullptr) {
96  // Screen output for Binned Surface material
97  ACTS_DEBUG(" - (proto) binning is " << *bu);
98  // Now update
99  BinUtility buAdjusted = adjustBinUtility(*bu, volume);
100  // Screen output for Binned Surface material
101  ACTS_DEBUG(" - adjusted binning is " << buAdjusted);
102  mState.materialBin[geoID] = buAdjusted;
103  return;
104  }
105  // Second attempt: binned material
106  auto bmp = dynamic_cast<
108  volumeMaterial);
109  if (bmp != nullptr) {
110  // Screen output for Binned Surface material
111  ACTS_DEBUG(" - binning is " << *bu);
112  mState.materialBin[geoID] = *bu;
113  return;
114  } else {
115  // Create a homogeneous type of material
116  ACTS_DEBUG(" - this is homogeneous material.");
117  BinUtility buHomogeneous;
118  mState.materialBin[geoID] = buHomogeneous;
119  return;
120  }
121  }
122 }
123 
125  State& mState, const TrackingVolume& tVolume) const {
126  ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
127  << "' for material surfaces.")
128 
129  ACTS_VERBOSE("- boundary surfaces ...");
130  // Check the boundary surfaces
131  for (auto& bSurface : tVolume.boundarySurfaces()) {
132  if (bSurface->surfaceRepresentation().surfaceMaterial() != nullptr) {
133  mState.surfaceMaterial[bSurface->surfaceRepresentation().geometryId()] =
134  bSurface->surfaceRepresentation().surfaceMaterialSharedPtr();
135  }
136  }
137 
138  ACTS_VERBOSE("- confined layers ...");
139  // Check the confined layers
140  if (tVolume.confinedLayers() != nullptr) {
141  for (auto& cLayer : tVolume.confinedLayers()->arrayObjects()) {
142  // Take only layers that are not navigation layers
143  if (cLayer->layerType() != navigation) {
144  // Check the representing surface
145  if (cLayer->surfaceRepresentation().surfaceMaterial() != nullptr) {
146  mState.surfaceMaterial[cLayer->surfaceRepresentation().geometryId()] =
147  cLayer->surfaceRepresentation().surfaceMaterialSharedPtr();
148  }
149  // Get the approach surfaces if present
150  if (cLayer->approachDescriptor() != nullptr) {
151  for (auto& aSurface :
152  cLayer->approachDescriptor()->containedSurfaces()) {
153  if (aSurface != nullptr) {
154  if (aSurface->surfaceMaterial() != nullptr) {
155  mState.surfaceMaterial[aSurface->geometryId()] =
156  aSurface->surfaceMaterialSharedPtr();
157  }
158  }
159  }
160  }
161  // Get the sensitive surface is present
162  if (cLayer->surfaceArray() != nullptr) {
163  // Sensitive surface loop
164  for (auto& sSurface : cLayer->surfaceArray()->surfaces()) {
165  if (sSurface != nullptr) {
166  if (sSurface->surfaceMaterial() != nullptr) {
167  mState.surfaceMaterial[sSurface->geometryId()] =
168  sSurface->surfaceMaterialSharedPtr();
169  }
170  }
171  }
172  }
173  }
174  }
175  }
176  // Step down into the sub volume
177  if (tVolume.confinedVolumes()) {
178  for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
179  // Recursive call
180  collectMaterialSurfaces(mState, *sVolume);
181  }
182  }
183 }
184 
186  RecordedMaterialVolumePoint& matPoint, Acts::MaterialSlab properties,
187  Vector3D position, Vector3D direction) const {
188  std::vector<Acts::Vector3D> extraPosition;
189  std::vector<Acts::Vector3D> extraRemainderPositions;
190 
191  int volumeStep = floor(properties.thickness() / m_cfg.mappingStep);
192  float remainder = properties.thickness() - m_cfg.mappingStep * volumeStep;
193  properties.scaleThickness(m_cfg.mappingStep / properties.thickness());
194  direction = direction * (m_cfg.mappingStep / direction.norm());
195 
196  for (int extraStep = 0; extraStep < volumeStep; extraStep++) {
197  // Create additional extrapolated points for the grid mapping
198  extraPosition.push_back(position + extraStep * direction);
199  }
200  matPoint.push_back(std::pair(properties, extraPosition));
201 
202  if (remainder > 0) {
203  // adjust the thickness of the last extrapolated step
204  properties.scaleThickness(remainder / properties.thickness());
205  extraRemainderPositions.push_back(position + volumeStep * direction);
206  matPoint.push_back(std::pair(properties, extraRemainderPositions));
207  }
208 }
209 
211  // iterate over the volumes
212  for (auto& recMaterial : mState.recordedMaterial) {
213  ACTS_DEBUG("Create the material for volume " << recMaterial.first);
214  if (mState.materialBin[recMaterial.first].dimensions() == 0) {
215  // Accumulate all the recorded material onto a signle point
216  ACTS_DEBUG("Homogeneous material volume");
217  Acts::AccumulatedVolumeMaterial homogeneousAccumulation;
218  for (const auto& rm : recMaterial.second) {
219  homogeneousAccumulation.accumulate(rm.first);
220  }
221  Acts::Material mat = homogeneousAccumulation.average();
222  mState.volumeMaterial[recMaterial.first] =
223  std::make_unique<HomogeneousVolumeMaterial>(std::move(mat));
224  } else if (mState.materialBin[recMaterial.first].dimensions() == 2) {
225  // Accumulate all the recorded material onto a grid
226  ACTS_DEBUG("Grid material volume");
227  std::function<Acts::Vector2D(Acts::Vector3D)> transfoGlobalToLocal;
228  Grid2D Grid = createGrid2D(mState.materialBin[recMaterial.first],
229  transfoGlobalToLocal);
230  MaterialGrid2D matGrid =
231  mapMaterialPoints(Grid, recMaterial.second, transfoGlobalToLocal);
232  MaterialMapper<MaterialGrid2D> matMap(transfoGlobalToLocal, matGrid);
233  mState.volumeMaterial[recMaterial.first] = std::make_unique<
235  std::move(matMap), mState.materialBin[recMaterial.first]);
236  } else if (mState.materialBin[recMaterial.first].dimensions() == 3) {
237  // Accumulate all the recorded material onto a grid
238  ACTS_DEBUG("Grid material volume");
239  std::function<Acts::Vector3D(Acts::Vector3D)> transfoGlobalToLocal;
240  Grid3D Grid = createGrid3D(mState.materialBin[recMaterial.first],
241  transfoGlobalToLocal);
242  MaterialGrid3D matGrid =
243  mapMaterialPoints(Grid, recMaterial.second, transfoGlobalToLocal);
244  MaterialMapper<MaterialGrid3D> matMap(transfoGlobalToLocal, matGrid);
245  mState.volumeMaterial[recMaterial.first] = std::make_unique<
247  std::move(matMap), mState.materialBin[recMaterial.first]);
248  } else {
249  throw std::invalid_argument(
250  "Incorrect bin dimension, only 0, 2 and 3 are accepted");
251  }
252  }
253 }
254 
256  State& mState, RecordedMaterialTrack& mTrack) const {
258 
259  // Neutral curvilinear parameters
260  NeutralCurvilinearTrackParameters start(makeVector4(mTrack.first.first, 0),
261  mTrack.first.second,
262  1 / mTrack.first.second.norm());
263 
264  // Prepare Action list and abort list
265  using BoundSurfaceCollector = SurfaceCollector<BoundSurfaceSelector>;
266  using MaterialVolumeCollector = VolumeCollector<MaterialVolumeSelector>;
269 
270  auto propLogger = getDefaultLogger("Propagator", Logging::INFO);
272  mState.geoContext, mState.magFieldContext, LoggerWrapper{*propLogger});
273 
274  // Now collect the material volume by using the straight line propagator
275  const auto& result = m_propagator.propagate(start, options).value();
276  auto mcResult = result.get<BoundSurfaceCollector::result_type>();
277  auto mvcResult = result.get<MaterialVolumeCollector::result_type>();
278 
279  auto mappingSurfaces = mcResult.collected;
280  auto mappingVolumes = mvcResult.collected;
281 
282  // Retrieve the recorded material from the recorded material track
283  auto& rMaterial = mTrack.second.materialInteractions;
284  ACTS_VERBOSE("Retrieved " << rMaterial.size()
285  << " recorded material steps to map.")
286 
287  // These should be mapped onto the mapping surfaces found
288  ACTS_VERBOSE("Found " << mappingVolumes.size()
289  << " mapping volumes for this track.");
290  ACTS_VERBOSE("Mapping volumes are :")
291  for (auto& mVolumes : mappingVolumes) {
292  ACTS_VERBOSE(" - Volume : " << mVolumes.volume->geometryId()
293  << " at position = (" << mVolumes.position.x()
294  << ", " << mVolumes.position.y() << ", "
295  << mVolumes.position.z() << ")");
296 
297  mappingVolumes.push_back(mVolumes);
298  }
299  // Run the mapping process, i.e. take the recorded material and map it
300  // onto the mapping volume:
301  auto rmIter = rMaterial.begin();
302  auto sfIter = mappingSurfaces.begin();
303  auto volIter = mappingVolumes.begin();
304 
305  // Use those to minimize the lookup
306  GeometryIdentifier lastID = GeometryIdentifier();
307  GeometryIdentifier currentID = GeometryIdentifier();
308  auto currentRecMaterial = mState.recordedMaterial.end();
309 
310  // store end position of the last material slab
311  Acts::Vector3D lastPositionEnd = {0, 0, 0};
312  Acts::Vector3D direction = {0, 0, 0};
313 
314  if (volIter != mappingVolumes.end()) {
315  lastPositionEnd = volIter->position;
316  }
317 
318  // loop over all the material hit in the track or until there no more volume
319  // to map onto
320  while (rmIter != rMaterial.end() && volIter != mappingVolumes.end()) {
321  if (volIter != mappingVolumes.end() &&
322  !volIter->volume->inside(rmIter->position)) {
323  // Check if the material point is past the entry point to the current
324  // volume
325  double distVol = (volIter->position - mTrack.first.first).norm();
326  double distMat = (rmIter->position - mTrack.first.first).norm();
327  if (distMat - distVol > s_epsilon) {
328  // Switch to next material volume
329  ++volIter;
330  }
331  }
332  if (volIter != mappingVolumes.end() &&
333  volIter->volume->inside(rmIter->position)) {
334  currentID = volIter->volume->geometryId();
335  if (not(currentID == lastID)) {
336  // Let's (re-)assess the information
337  lastID = currentID;
338  lastPositionEnd = volIter->position;
339  currentRecMaterial = mState.recordedMaterial.find(currentID);
340  }
341  // If the curent volume has a ProtoVolumeMaterial
342  // and the material hit has a non 0 thickness
343  if (currentRecMaterial != mState.recordedMaterial.end() &&
344  rmIter->materialSlab.thickness() > 0) {
345  // check if there is vacuum between this material point and the last one
346  float vacuumThickness = (rmIter->position - lastPositionEnd).norm();
347  if (vacuumThickness > s_epsilon) {
348  auto properties = Acts::MaterialSlab(vacuumThickness);
349  // creat vacuum hits
350  createExtraHits(currentRecMaterial->second, properties,
351  lastPositionEnd, direction);
352  }
353  // determine the position of the last material slab using the track
354  // direction
355  direction = rmIter->direction;
356  direction =
357  direction * (rmIter->materialSlab.thickness() / direction.norm());
358  lastPositionEnd = rmIter->position + direction;
359  // create additional material point
360  createExtraHits(currentRecMaterial->second, rmIter->materialSlab,
361  rmIter->position, direction);
362  }
363 
364  // check if we have reached the end of the volume or the last hit of the
365  // track.
366  if ((rmIter + 1) == rMaterial.end() ||
367  !volIter->volume->inside((rmIter + 1)->position)) {
368  // find the boundary surface corresponding to the end of the volume
369  while (sfIter != mappingSurfaces.end()) {
370  if (sfIter->surface->geometryId().volume() == lastID.volume() ||
371  ((volIter + 1) != mappingVolumes.end() &&
372  sfIter->surface->geometryId().volume() ==
373  (volIter + 1)->volume->geometryId().volume())) {
374  double distVol = (volIter->position - mTrack.first.first).norm();
375  double distSur = (sfIter->position - mTrack.first.first).norm();
376  if (distSur - distVol > s_epsilon) {
377  float vacuumThickness =
378  (sfIter->position - lastPositionEnd).norm();
379  // if the last material slab stop before the boundary surface
380  // create vacuum hits
381  if (vacuumThickness > s_epsilon) {
382  auto properties = Acts::MaterialSlab(vacuumThickness);
383  createExtraHits(currentRecMaterial->second, properties,
384  lastPositionEnd, direction);
385  lastPositionEnd = sfIter->position;
386  }
387  break;
388  }
389  }
390  sfIter++;
391  }
392  }
393  rmIter->volume = volIter->volume;
394  }
395  ++rmIter;
396  }
397 }