EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SurfaceMaterialMapper.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SurfaceMaterialMapper.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2018-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 
22 
24  const Config& cfg, StraightLinePropagator propagator,
25  std::unique_ptr<const Logger> slogger)
26  : m_cfg(cfg),
27  m_propagator(std::move(propagator)),
28  m_logger(std::move(slogger)) {}
29 
31  const GeometryContext& gctx, const MagneticFieldContext& mctx,
32  const TrackingGeometry& tGeometry) const {
33  // Parse the geometry and find all surfaces with material proxies
34  auto world = tGeometry.highestTrackingVolume();
35 
36  // The Surface material mapping state
37  State mState(gctx, mctx);
38  resolveMaterialSurfaces(mState, *world);
39  collectMaterialVolumes(mState, *world);
40 
41  ACTS_DEBUG(mState.accumulatedMaterial.size()
42  << " Surfaces with PROXIES collected ... ");
43  for (auto& smg : mState.accumulatedMaterial) {
44  ACTS_VERBOSE(" -> Surface in with id " << smg.first);
45  }
46  return mState;
47 }
48 
50  State& mState, const TrackingVolume& tVolume) const {
51  ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
52  << "' for material surfaces.")
53 
54  ACTS_VERBOSE("- boundary surfaces ...");
55  // Check the boundary surfaces
56  for (auto& bSurface : tVolume.boundarySurfaces()) {
57  checkAndInsert(mState, bSurface->surfaceRepresentation());
58  }
59 
60  ACTS_VERBOSE("- confined layers ...");
61  // Check the confined layers
62  if (tVolume.confinedLayers() != nullptr) {
63  for (auto& cLayer : tVolume.confinedLayers()->arrayObjects()) {
64  // Take only layers that are not navigation layers
65  if (cLayer->layerType() != navigation) {
66  // Check the representing surface
67  checkAndInsert(mState, cLayer->surfaceRepresentation());
68  // Get the approach surfaces if present
69  if (cLayer->approachDescriptor() != nullptr) {
70  for (auto& aSurface :
71  cLayer->approachDescriptor()->containedSurfaces()) {
72  if (aSurface != nullptr) {
73  checkAndInsert(mState, *aSurface);
74  }
75  }
76  }
77  // Get the sensitive surface is present
78  if (cLayer->surfaceArray() != nullptr) {
79  // Sensitive surface loop
80  for (auto& sSurface : cLayer->surfaceArray()->surfaces()) {
81  if (sSurface != nullptr) {
82  checkAndInsert(mState, *sSurface);
83  }
84  }
85  }
86  }
87  }
88  }
89  // Step down into the sub volume
90  if (tVolume.confinedVolumes()) {
91  for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
92  // Recursive call
93  resolveMaterialSurfaces(mState, *sVolume);
94  }
95  }
96 }
97 
99  const Surface& surface) const {
100  auto surfaceMaterial = surface.surfaceMaterial();
101  // Check if the surface has a proxy
102  if (surfaceMaterial != nullptr) {
103  auto geoID = surface.geometryId();
104  size_t volumeID = geoID.volume();
105  ACTS_DEBUG("Material surface found with volumeID " << volumeID);
106  ACTS_DEBUG(" - surfaceID is " << geoID);
107 
108  // We need a dynamic_cast to either a surface material proxy or
109  // proper surface material
110  auto psm = dynamic_cast<const ProtoSurfaceMaterial*>(surfaceMaterial);
111 
112  // Get the bin utility: try proxy material first
113  const BinUtility* bu = (psm != nullptr) ? (&psm->binUtility()) : nullptr;
114  if (bu != nullptr) {
115  // Screen output for Binned Surface material
116  ACTS_DEBUG(" - (proto) binning is " << *bu);
117  // Now update
118  BinUtility buAdjusted = adjustBinUtility(*bu, surface);
119  // Screen output for Binned Surface material
120  ACTS_DEBUG(" - adjusted binning is " << buAdjusted);
121  mState.accumulatedMaterial[geoID] =
122  AccumulatedSurfaceMaterial(buAdjusted);
123  return;
124  }
125 
126  // Second attempt: binned material
127  auto bmp = dynamic_cast<const BinnedSurfaceMaterial*>(surfaceMaterial);
128  bu = (bmp != nullptr) ? (&bmp->binUtility()) : nullptr;
129  // Creaete a binned type of material
130  if (bu != nullptr) {
131  // Screen output for Binned Surface material
132  ACTS_DEBUG(" - binning is " << *bu);
133  mState.accumulatedMaterial[geoID] = AccumulatedSurfaceMaterial(*bu);
134  } else {
135  // Create a homogeneous type of material
136  ACTS_DEBUG(" - this is homogeneous material.");
138  }
139  }
140 }
141 
143  State& mState, const TrackingVolume& tVolume) const {
144  ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
145  << "' for material surfaces.")
146  ACTS_VERBOSE("- Insert Volume ...");
147  if (tVolume.volumeMaterial() != nullptr) {
148  mState.volumeMaterial[tVolume.geometryId()] =
149  tVolume.volumeMaterialSharedPtr();
150  }
151 
152  // Step down into the sub volume
153  if (tVolume.confinedVolumes()) {
154  ACTS_VERBOSE("- Check children volume ...");
155  for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
156  // Recursive call
157  collectMaterialVolumes(mState, *sVolume);
158  }
159  }
160  if (!tVolume.denseVolumes().empty()) {
161  for (auto& sVolume : tVolume.denseVolumes()) {
162  // Recursive call
163  collectMaterialVolumes(mState, *sVolume);
164  }
165  }
166 }
167 
169  // iterate over the map to call the total average
170  for (auto& accMaterial : mState.accumulatedMaterial) {
171  ACTS_DEBUG("Finalizing map for Surface " << accMaterial.first);
172  mState.surfaceMaterial[accMaterial.first] =
173  accMaterial.second.totalAverage();
174  }
175 }
176 
178  State& mState, RecordedMaterialTrack& mTrack) const {
180 
181  // Neutral curvilinear parameters
182  NeutralCurvilinearTrackParameters start(makeVector4(mTrack.first.first, 0),
183  mTrack.first.second,
184  1 / mTrack.first.second.norm());
185 
186  // Prepare Action list and abort list
187  using MaterialSurfaceCollector = SurfaceCollector<MaterialSurface>;
188  using MaterialVolumeCollector = VolumeCollector<MaterialVolume>;
189  using ActionList =
192 
193  auto propLogger = getDefaultLogger("SufMatMapProp", Logging::INFO);
195  mState.geoContext, mState.magFieldContext, LoggerWrapper{*propLogger});
196 
197  // Now collect the material layers by using the straight line propagator
198  const auto& result = m_propagator.propagate(start, options).value();
199  auto mcResult = result.get<MaterialSurfaceCollector::result_type>();
200  auto mvcResult = result.get<MaterialVolumeCollector::result_type>();
201 
202  auto mappingSurfaces = mcResult.collected;
203  auto mappingVolumes = mvcResult.collected;
204 
205  // Retrieve the recorded material from the recorded material track
206  auto& rMaterial = mTrack.second.materialInteractions;
207  std::map<GeometryIdentifier, unsigned int> assignedMaterial;
208  ACTS_VERBOSE("Retrieved " << rMaterial.size()
209  << " recorded material steps to map.")
210 
211  // These should be mapped onto the mapping surfaces found
212  ACTS_VERBOSE("Found " << mappingSurfaces.size()
213  << " mapping surfaces for this track.");
214  ACTS_VERBOSE("Mapping surfaces are :")
215  for (auto& mSurface : mappingSurfaces) {
216  ACTS_VERBOSE(" - Surface : " << mSurface.surface->geometryId()
217  << " at position = (" << mSurface.position.x()
218  << ", " << mSurface.position.y() << ", "
219  << mSurface.position.z() << ")");
220  assignedMaterial[mSurface.surface->geometryId()] = 0;
221  }
222 
223  // Run the mapping process, i.e. take the recorded material and map it
224  // onto the mapping surfaces:
225  // - material steps and surfaces are assumed to be ordered along the
226  // mapping ray
227  //- do not record the material inside a volume with material
228  auto rmIter = rMaterial.begin();
229  auto sfIter = mappingSurfaces.begin();
230  auto volIter = mappingVolumes.begin();
231 
232  // Use those to minimize the lookup
233  GeometryIdentifier lastID = GeometryIdentifier();
234  GeometryIdentifier currentID = GeometryIdentifier();
235  Vector3D currentPos(0., 0., 0);
236  double currentPathCorrection = 0.;
237  auto currentAccMaterial = mState.accumulatedMaterial.end();
238 
239  // To remember the bins of this event
240  using MapBin = std::pair<AccumulatedSurfaceMaterial*, std::array<size_t, 3>>;
241  std::multimap<AccumulatedSurfaceMaterial*, std::array<size_t, 3>>
242  touchedMapBins;
243 
244  // Assign the recorded ones, break if you hit an end
245  while (rmIter != rMaterial.end() && sfIter != mappingSurfaces.end()) {
246  // Material not inside current volume
247  if (volIter != mappingVolumes.end() &&
248  !volIter->volume->inside(rmIter->position)) {
249  double distVol = (volIter->position - mTrack.first.first).norm();
250  double distMat = (rmIter->position - mTrack.first.first).norm();
251  // Material past the entry point to the current volume
252  if (distMat - distVol > s_epsilon) {
253  // Switch to next material volume
254  ++volIter;
255  }
256  }
258  if (volIter != mappingVolumes.end() &&
259  volIter->volume->inside(rmIter->position)) {
260  ++rmIter;
261  continue;
262  }
263  if (sfIter != mappingSurfaces.end() - 1 &&
264  (rmIter->position - sfIter->position).norm() >
265  (rmIter->position - (sfIter + 1)->position).norm()) {
266  // Switch to next assignment surface
267  ++sfIter;
268  }
269  // get the current Surface ID
270  currentID = sfIter->surface->geometryId();
271  // We have work to do: the assignemnt surface has changed
272  if (not(currentID == lastID)) {
273  // Let's (re-)assess the information
274  lastID = currentID;
275  currentPos = (sfIter)->position;
276  currentPathCorrection = sfIter->surface->pathCorrection(
277  mState.geoContext, currentPos, sfIter->direction);
278  currentAccMaterial = mState.accumulatedMaterial.find(currentID);
279  }
280  // Now assign the material for the accumulation process
281  auto tBin = currentAccMaterial->second.accumulate(
282  currentPos, rmIter->materialSlab, currentPathCorrection);
283  touchedMapBins.insert(MapBin(&(currentAccMaterial->second), tBin));
284  ++assignedMaterial[currentID];
285  // Update the material interaction with the associated surface
286  rmIter->surface = sfIter->surface;
287  // Switch to next material
288  ++rmIter;
289  }
290 
291  ACTS_VERBOSE("Surfaces have following number of assigned hits :")
292  for (auto& [key, value] : assignedMaterial) {
293  ACTS_VERBOSE(" + Surface : " << key << " has " << value << " hits.");
294  }
295 
296  // After mapping this track, average the touched bins
297  for (auto tmapBin : touchedMapBins) {
298  std::vector<std::array<size_t, 3>> trackBins = {tmapBin.second};
299  tmapBin.first->trackAverage(trackBins);
300  }
301 
302  // After mapping this track, average the untouched but intersected bins
303  if (m_cfg.emptyBinCorrection) {
304  // Use the assignedMaterial map to account for empty hits, i.e.
305  // the material surface has been intersected by the mapping ray
306  // but no material step was assigned to this surface
307  for (auto& mSurface : mappingSurfaces) {
308  auto mgID = mSurface.surface->geometryId();
309  // Count an empty hit only if the surface does not appear in the
310  // list of assigned surfaces
311  if (assignedMaterial[mgID] == 0) {
312  auto missedMaterial = mState.accumulatedMaterial.find(mgID);
313  missedMaterial->second.trackAverage(mSurface.position, true);
314  }
315  }
316  }
317 }