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