EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CsvPlanarClusterReader.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CsvPlanarClusterReader.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 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 
13 #include "Acts/Utilities/Units.hpp"
22 
23 #include <dfe/dfe_io_dsv.hpp>
24 
25 #include "TrackMlData.hpp"
26 
30  : m_cfg(cfg)
31  // TODO check that all files (hits,cells,truth) exists
32  ,
33  m_eventsRange(determineEventFilesRange(cfg.inputDir, "hits.csv")),
34  m_logger(Acts::getDefaultLogger("CsvPlanarClusterReader", lvl)) {
35  if (m_cfg.outputClusters.empty()) {
36  throw std::invalid_argument("Missing cluster output collection");
37  }
38  if (m_cfg.outputHitIds.empty()) {
39  throw std::invalid_argument("Missing hit id output collection");
40  }
41  if (m_cfg.outputHitParticlesMap.empty()) {
42  throw std::invalid_argument("Missing hit-particles map output collection");
43  }
44  if (m_cfg.outputSimulatedHits.empty()) {
45  throw std::invalid_argument("Missing simulated hits output collection");
46  }
47  if (not m_cfg.trackingGeometry) {
48  throw std::invalid_argument("Missing tracking geometry");
49  }
50  // fill the geo id to surface map once to speed up lookups later on
51  m_cfg.trackingGeometry->visitSurfaces([this](const Acts::Surface* surface) {
52  this->m_surfaces[surface->geometryId()] = surface;
53  });
54 }
55 
57  const {
58  return "CsvPlanarClusterReader";
59 }
60 
61 std::pair<size_t, size_t>
63  return m_eventsRange;
64 }
65 
66 namespace {
67 struct CompareHitId {
68  // support transparent comparision between identifiers and full objects
69  using is_transparent = void;
70  template <typename T>
71  constexpr bool operator()(const T& left, const T& right) const {
72  return left.hit_id < right.hit_id;
73  }
74  template <typename T>
75  constexpr bool operator()(uint64_t left_id, const T& right) const {
76  return left_id < right.hit_id;
77  }
78  template <typename T>
79  constexpr bool operator()(const T& left, uint64_t right_id) const {
80  return left.hit_id < right_id;
81  }
82 };
83 
85 inline Acts::GeometryIdentifier extractGeometryId(
86  const ActsExamples::HitData& data) {
87  // if available, use the encoded geometry directly
88  if (data.geometry_id != 0u) {
89  return data.geometry_id;
90  }
91  // otherwise, reconstruct it from the available components
93  geoId.setVolume(data.volume_id);
94  geoId.setLayer(data.layer_id);
95  geoId.setSensitive(data.module_id);
96  return geoId;
97 }
98 
99 struct CompareGeometryId {
100  bool operator()(const ActsExamples::HitData& left,
101  const ActsExamples::HitData& right) const {
102  auto leftId = extractGeometryId(left).value();
103  auto rightId = extractGeometryId(right).value();
104  return leftId < rightId;
105  }
106 };
107 
108 template <typename Data>
109 inline std::vector<Data> readEverything(
110  const std::string& inputDir, const std::string& filename,
111  const std::vector<std::string>& optionalColumns, size_t event) {
112  std::string path = ActsExamples::perEventFilepath(inputDir, filename, event);
113  dfe::NamedTupleCsvReader<Data> reader(path, optionalColumns);
114 
115  std::vector<Data> everything;
116  Data one;
117  while (reader.read(one)) {
118  everything.push_back(one);
119  }
120 
121  return everything;
122 }
123 
124 std::vector<ActsExamples::HitData> readHitsByGeometryId(
125  const std::string& inputDir, size_t event) {
126  // geometry_id and t are optional columns
127  auto hits = readEverything<ActsExamples::HitData>(
128  inputDir, "hits.csv", {"geometry_id", "t"}, event);
129  // sort same way they will be sorted in the output container
130  std::sort(hits.begin(), hits.end(), CompareGeometryId{});
131  return hits;
132 }
133 
134 std::vector<ActsExamples::CellData> readCellsByHitId(
135  const std::string& inputDir, size_t event) {
136  // timestamp is an optional element
137  auto cells = readEverything<ActsExamples::CellData>(inputDir, "cells.csv",
138  {"timestamp"}, event);
139  // sort for fast hit id look up
140  std::sort(cells.begin(), cells.end(), CompareHitId{});
141  return cells;
142 }
143 
144 std::vector<ActsExamples::TruthHitData> readTruthHitsByHitId(
145  const std::string& inputDir, size_t event) {
146  // define all optional columns
147  std::vector<std::string> optionalColumns = {
148  "geometry_id", "tt", "te", "deltapx",
149  "deltapy", "deltapz", "deltae", "index",
150  };
151  auto truths = readEverything<ActsExamples::TruthHitData>(
152  inputDir, "truth.csv", optionalColumns, event);
153  // sort for fast hit id look up
154  std::sort(truths.begin(), truths.end(), CompareHitId{});
155  return truths;
156 }
157 
158 } // namespace
159 
161  const ActsExamples::AlgorithmContext& ctx) {
162  // hit_id in the files is not required to be neither continuous nor
163  // monotonic. internally, we want continous indices within [0,#hits)
164  // to simplify data handling. to be able to perform this mapping we first
165  // read all data into memory before converting to the internal event data
166  // types.
167  auto hits = readHitsByGeometryId(m_cfg.inputDir, ctx.eventNumber);
168  auto cells = readCellsByHitId(m_cfg.inputDir, ctx.eventNumber);
169  auto truths = readTruthHitsByHitId(m_cfg.inputDir, ctx.eventNumber);
170 
171  // prepare containers for the hit data using the framework event data types
173  std::vector<uint64_t> hitIds;
174  IndexMultimap<ActsFatras::Barcode> hitParticlesMap;
175  SimHitContainer simHits;
176  clusters.reserve(hits.size());
177  hitIds.reserve(hits.size());
178  hitParticlesMap.reserve(truths.size());
179  simHits.reserve(truths.size());
180 
181  for (const HitData& hit : hits) {
182  Acts::GeometryIdentifier geoId = extractGeometryId(hit);
183 
184  // find associated truth/ simulation hits
185  std::vector<std::size_t> simHitIndices;
186  {
187  auto range = makeRange(std::equal_range(truths.begin(), truths.end(),
188  hit.hit_id, CompareHitId{}));
189  simHitIndices.reserve(range.size());
190  for (const auto& truth : range) {
191  const auto simGeometryId = Acts::GeometryIdentifier(truth.geometry_id);
192  // TODO validate geo id consistency
193  const auto simParticleId = ActsFatras::Barcode(truth.particle_id);
194  const auto simIndex = truth.index;
195  ActsFatras::Hit::Vector4 simPos4{
196  truth.tx * Acts::UnitConstants::mm,
197  truth.ty * Acts::UnitConstants::mm,
198  truth.tz * Acts::UnitConstants::mm,
199  truth.tt * Acts::UnitConstants::ns,
200  };
201  ActsFatras::Hit::Vector4 simMom4{
202  truth.tpx * Acts::UnitConstants::GeV,
203  truth.tpy * Acts::UnitConstants::GeV,
204  truth.tpz * Acts::UnitConstants::GeV,
205  truth.te * Acts::UnitConstants::GeV,
206  };
207  ActsFatras::Hit::Vector4 simDelta4{
208  truth.deltapx * Acts::UnitConstants::GeV,
209  truth.deltapy * Acts::UnitConstants::GeV,
210  truth.deltapz * Acts::UnitConstants::GeV,
211  truth.deltae * Acts::UnitConstants::GeV,
212  };
213 
214  // the cluster stores indices to the underlying simulation hits. thus
215  // their position in the container must be stable. the preordering of
216  // hits by geometry id should ensure that new sim hits are always added
217  // at the end and previously created ones rest at their existing
218  // locations.
219  auto inserted = simHits.emplace_hint(simHits.end(), simGeometryId,
220  simParticleId, simPos4, simMom4,
221  simMom4 + simDelta4, simIndex);
222  if (std::next(inserted) != simHits.end()) {
223  ACTS_FATAL("Truth hit sorting broke for input hit id " << hit.hit_id);
224  return ProcessCode::ABORT;
225  }
226  simHitIndices.push_back(simHits.index_of(inserted));
227  }
228  }
229 
230  // find matching pixel cell information
231  std::vector<Acts::DigitizationCell> digitizationCells;
232  {
233  auto range = makeRange(std::equal_range(cells.begin(), cells.end(),
234  hit.hit_id, CompareHitId{}));
235  for (const auto& c : range) {
236  digitizationCells.emplace_back(c.ch0, c.ch1, c.value);
237  }
238  }
239 
240  // identify hit surface
241  auto it = m_surfaces.find(geoId);
242  if (it == m_surfaces.end() or not it->second) {
243  ACTS_FATAL("Could not retrieve the surface for hit " << hit);
244  return ProcessCode::ABORT;
245  }
246  const Acts::Surface& surface = *(it->second);
247 
248  // transform global hit coordinates into local coordinates on the surface
250  hit.y * Acts::UnitConstants::mm,
251  hit.z * Acts::UnitConstants::mm);
252  double time = hit.t * Acts::UnitConstants::ns;
253  Acts::Vector3D mom(1, 1, 1); // fake momentum
254  Acts::Vector2D local(0, 0);
255  auto lpResult = surface.globalToLocal(ctx.geoContext, pos, mom);
256  if (not lpResult.ok()) {
257  ACTS_FATAL("Global to local transformation did not succeed.");
258  return ProcessCode::ABORT;
259  }
260  local = lpResult.value();
261 
262  // TODO what to use as cluster uncertainty?
264  // create the planar cluster
266  surface.getSharedPtr(),
267  Identifier(identifier_type(geoId.value()), std::move(simHitIndices)),
268  std::move(cov), local[0], local[1], time, std::move(digitizationCells));
269 
270  // due to the previous sorting of the raw hit data by geometry id, new
271  // clusters should always end up at the end of the container. previous
272  // elements were not touched; cluster indices remain stable and can
273  // be used to identify the hit.
274  auto inserted =
275  clusters.emplace_hint(clusters.end(), geoId, std::move(cluster));
276  if (std::next(inserted) != clusters.end()) {
277  ACTS_FATAL("Something went horribly wrong with the hit sorting");
278  return ProcessCode::ABORT;
279  }
280  auto hitIndex = clusters.index_of(inserted);
281  auto truthRange = makeRange(std::equal_range(truths.begin(), truths.end(),
282  hit.hit_id, CompareHitId{}));
283  for (const auto& truth : truthRange) {
284  hitParticlesMap.emplace_hint(hitParticlesMap.end(), hitIndex,
285  truth.particle_id);
286  }
287 
288  // map internal hit/cluster index back to original, non-monotonic hit id
289  hitIds.push_back(hit.hit_id);
290  }
291 
292  // write the data to the EventStore
293  ctx.eventStore.add(m_cfg.outputClusters, std::move(clusters));
294  ctx.eventStore.add(m_cfg.outputHitIds, std::move(hitIds));
295  ctx.eventStore.add(m_cfg.outputHitParticlesMap, std::move(hitParticlesMap));
296  ctx.eventStore.add(m_cfg.outputSimulatedHits, std::move(simHits));
297 
299 }