ECCE @ 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 
19 
20 namespace {
22 using Grid2D =
24 using Grid3D =
27 using MaterialGrid3D =
29 
30 } // namespace
31 
33  const Config& cfg, StraightLinePropagator propagator,
34  std::unique_ptr<const Logger> slogger)
35  : m_cfg(cfg),
36  m_propagator(std::move(propagator)),
37  m_logger(std::move(slogger)) {}
38 
40  const GeometryContext& gctx, const MagneticFieldContext& mctx,
41  const TrackingGeometry& tGeometry) const {
42  // Parse the geometry and find all surfaces with material proxies
43  auto world = tGeometry.highestTrackingVolume();
44 
45  // The Surface material mapping state
46  State mState(gctx, mctx);
47  resolveMaterialVolume(mState, *world);
48  return mState;
49 }
50 
52  State& mState, const TrackingVolume& tVolume) const {
53  ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
54  << "' for material surfaces.")
55 
56  ACTS_VERBOSE("- Insert Volume ...");
57  checkAndInsert(mState, tVolume);
58 
59  // Step down into the sub volume
60  if (tVolume.confinedVolumes()) {
61  ACTS_VERBOSE("- Check children volume ...");
62  for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
63  // Recursive call
64  resolveMaterialVolume(mState, *sVolume);
65  }
66  }
67  if (!tVolume.denseVolumes().empty()) {
68  for (auto& sVolume : tVolume.denseVolumes()) {
69  // Recursive call
70  resolveMaterialVolume(mState, *sVolume);
71  }
72  }
73 }
74 
76  State& mState, const TrackingVolume& volume) const {
77  auto volumeMaterial = volume.volumeMaterial();
78  // Check if the volume has a proxy
79  if (volumeMaterial != nullptr) {
80  auto geoID = volume.geoID();
81  size_t volumeID = geoID.volume();
82  ACTS_DEBUG("Material volume found with volumeID " << volumeID);
83  ACTS_DEBUG(" - ID is " << geoID);
84 
86  mState.recordedMaterial[geoID] = mat;
87 
88  // We need a dynamic_cast to either a volume material proxy or
89  // proper surface material
90  auto psm = dynamic_cast<const ProtoVolumeMaterial*>(volumeMaterial);
91  // Get the bin utility: try proxy material first
92  const BinUtility* bu = (psm != nullptr) ? (&psm->binUtility()) : nullptr;
93  if (bu != nullptr) {
94  // Screen output for Binned Surface material
95  ACTS_DEBUG(" - (proto) binning is " << *bu);
96  // Now update
97  BinUtility buAdjusted = adjustBinUtility(*bu, volume);
98  // Screen output for Binned Surface material
99  ACTS_DEBUG(" - adjusted binning is " << buAdjusted);
100  mState.materialBin[geoID] = buAdjusted;
101  return;
102  }
103  // Second attempt: binned material
104  auto bmp = dynamic_cast<
106  volumeMaterial);
107  if (bmp != nullptr) {
108  // Screen output for Binned Surface material
109  ACTS_DEBUG(" - binning is " << *bu);
110  mState.materialBin[geoID] = *bu;
111  return;
112  } else {
113  // Create a homogeneous type of material
114  ACTS_DEBUG(" - this is homogeneous material.");
115  BinUtility buHomogeneous;
116  mState.materialBin[geoID] = buHomogeneous;
117  return;
118  }
119  }
120 }
121 
123  // iterate over the volumes
124  for (auto& recMaterial : mState.recordedMaterial) {
125  ACTS_DEBUG("Create the material for volume " << recMaterial.first);
126  if (mState.materialBin[recMaterial.first].dimensions() == 0) {
127  // Accumulate all the recorded material onto a signle point
128  ACTS_DEBUG("Homogeneous material volume");
129  Acts::AccumulatedVolumeMaterial homogeneousAccumulation;
130  for (const auto& rm : recMaterial.second) {
131  homogeneousAccumulation.accumulate(rm.first);
132  }
133  Acts::Material mat = homogeneousAccumulation.average();
134  mState.volumeMaterial[recMaterial.first] =
135  std::make_unique<HomogeneousVolumeMaterial>(std::move(mat));
136  return;
137  } else if (mState.materialBin[recMaterial.first].dimensions() == 2) {
138  // Accumulate all the recorded material onto a grid
139  ACTS_DEBUG("Grid material volume");
140  std::function<Acts::Vector2D(Acts::Vector3D)> transfoGlobalToLocal;
141  Grid2D Grid = createGrid2D(mState.materialBin[recMaterial.first],
142  transfoGlobalToLocal);
143  MaterialGrid2D matGrid =
144  mapMaterialPoints(Grid, recMaterial.second, transfoGlobalToLocal);
145  MaterialMapper<MaterialGrid2D> matMap(transfoGlobalToLocal, matGrid);
146  mState.volumeMaterial[recMaterial.first] = std::make_unique<
148  std::move(matMap), mState.materialBin[recMaterial.first]);
149  return;
150  } else if (mState.materialBin[recMaterial.first].dimensions() == 3) {
151  // Accumulate all the recorded material onto a grid
152  ACTS_DEBUG("Grid material volume");
153  std::function<Acts::Vector3D(Acts::Vector3D)> transfoGlobalToLocal;
154  Grid3D Grid = createGrid3D(mState.materialBin[recMaterial.first],
155  transfoGlobalToLocal);
156  MaterialGrid3D matGrid =
157  mapMaterialPoints(Grid, recMaterial.second, transfoGlobalToLocal);
158  MaterialMapper<MaterialGrid3D> matMap(transfoGlobalToLocal, matGrid);
159  mState.volumeMaterial[recMaterial.first] = std::make_unique<
161  std::move(matMap), mState.materialBin[recMaterial.first]);
162  return;
163  } else {
164  throw std::invalid_argument(
165  "Incorrect bin dimension, only 0, 2 and 3 are accepted");
166  }
167  }
168 }
169 
171  State& mState, RecordedMaterialTrack& mTrack) const {
172  // Neutral curvilinear parameters
173  NeutralCurvilinearParameters start(std::nullopt, mTrack.first.first,
174  mTrack.first.second, 0.);
175 
176  // Prepare Action list and abort list
177  using MaterialVolumeCollector = VolumeCollector<MaterialVolume>;
180 
182  mState.magFieldContext);
183  options.debug = m_cfg.mapperDebugOutput;
184 
185  // Now collect the material volume by using the straight line propagator
186  const auto& result = m_propagator.propagate(start, options).value();
187  auto mcResult = result.get<MaterialVolumeCollector::result_type>();
188  // Massive screen output
189  if (m_cfg.mapperDebugOutput) {
190  auto debugOutput = result.get<DebugOutputActor::result_type>();
191  ACTS_VERBOSE("Debug propagation output.");
192  ACTS_VERBOSE(debugOutput.debugString);
193  }
194 
195  auto mappingVolumes = mcResult.collected;
196 
197  // Retrieve the recorded material from the recorded material track
198  auto& rMaterial = mTrack.second.materialInteractions;
199  ACTS_VERBOSE("Retrieved " << rMaterial.size()
200  << " recorded material steps to map.")
201 
202  // These should be mapped onto the mapping surfaces found
203  ACTS_VERBOSE("Found " << mappingVolumes.size()
204  << " mapping volumes for this track.");
205  ACTS_VERBOSE("Mapping volumes are :")
206  for (auto& mVolumes : mappingVolumes) {
207  ACTS_VERBOSE(" - Volume : " << mVolumes.volume->geoID()
208  << " at position = (" << mVolumes.position.x()
209  << ", " << mVolumes.position.y() << ", "
210  << mVolumes.position.z() << ")");
211 
212  mappingVolumes.push_back(mVolumes);
213  }
214  // Run the mapping process, i.e. take the recorded material and map it
215  // onto the mapping volume:
216  auto rmIter = rMaterial.begin();
217  auto volIter = mappingVolumes.begin();
218  bool encounterVolume = false;
219 
220  // Use those to minimize the lookup
221  GeometryID lastID = GeometryID();
222  GeometryID currentID = GeometryID();
223  auto currentRecMaterial = mState.recordedMaterial.end();
224 
225  // Use those to create additional extrapolated step
226  int volumeStep = 1;
227  Acts::Vector3D extraPosition = {0, 0, 0};
228  Acts::Vector3D extraDirection = {0, 0, 0};
229 
230  while (rmIter != rMaterial.end() && volIter != mappingVolumes.end()) {
231  if (volIter != mappingVolumes.end() && encounterVolume == true &&
232  !volIter->volume->inside(rmIter->position)) {
233  encounterVolume = false;
234  // Switch to next assignment volume
235  ++volIter;
236  }
237  if (volIter != mappingVolumes.end() &&
238  volIter->volume->inside(rmIter->position)) {
239  currentID = volIter->volume->geoID();
240  if (not(currentID == lastID)) {
241  // Let's (re-)assess the information
242  lastID = currentID;
243  currentRecMaterial = mState.recordedMaterial.find(currentID);
244  }
245  if (currentRecMaterial != mState.recordedMaterial.end()) {
246  // If the curent volume has a ProtoVolumeMaterial
247  volumeStep =
248  floor(rmIter->materialProperties.thickness() / m_cfg.mappingStep);
249  auto properties = rmIter->materialProperties;
250  float remainder = rmIter->materialProperties.thickness() -
251  m_cfg.mappingStep * volumeStep;
252  properties.scaleThickness(m_cfg.mappingStep / properties.thickness());
253  mState.recordedMaterial[volIter->volume->geoID()].push_back(
254  std::pair(properties, rmIter->position));
255  for (int step = 1; step <= volumeStep; step++) {
256  // Create additional extrapolated point for the grid mapping
257  extraDirection = rmIter->direction;
258  extraDirection =
259  extraDirection * (m_cfg.mappingStep / extraDirection.norm());
260  extraPosition = rmIter->position + step * extraDirection;
261  if (step == volumeStep) {
262  // adjust the thickness of the last extrapolated step
263  properties.scaleThickness(remainder / properties.thickness());
264  }
265  mState.recordedMaterial[volIter->volume->geoID()].push_back(
266  std::pair(properties, extraPosition));
267  }
268  }
269  encounterVolume = true;
270  }
271  ++rmIter;
272  }
273 }