Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RootPlanarClusterWriter.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file RootPlanarClusterWriter.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017 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 
31 
32 #include <cstdint>
33 #include <ios>
34 #include <ostream>
35 #include <stdexcept>
36 #include <utility>
37 
38 #include <TFile.h>
39 #include <TTree.h>
40 
44  : WriterT(config.inputClusters, "RootPlanarClusterWriter", level),
45  m_cfg(config) {
46  // inputClusters is already checked by base constructor
47  if (m_cfg.inputSimHits.empty()) {
48  throw std::invalid_argument("Missing simulated hits input collection");
49  }
50 
52 
53  if (m_cfg.treeName.empty()) {
54  throw std::invalid_argument("Missing tree name");
55  }
56  if (not m_cfg.trackingGeometry) {
57  throw std::invalid_argument("Missing tracking geometry");
58  }
59  // Setup ROOT I/O
60  m_outputFile = TFile::Open(m_cfg.filePath.c_str(), m_cfg.fileMode.c_str());
61  if (m_outputFile == nullptr) {
62  throw std::ios_base::failure("Could not open '" + m_cfg.filePath);
63  }
64  m_outputFile->cd();
65  m_outputTree = new TTree(m_cfg.treeName.c_str(), m_cfg.treeName.c_str());
66  if (m_outputTree == nullptr) {
67  throw std::bad_alloc();
68  }
69 
70  // Set the branches
71  m_outputTree->Branch("event_nr", &m_eventNr);
72  m_outputTree->Branch("volume_id", &m_volumeID);
73  m_outputTree->Branch("layer_id", &m_layerID);
74  m_outputTree->Branch("surface_id", &m_surfaceID);
75  m_outputTree->Branch("g_x", &m_x);
76  m_outputTree->Branch("g_y", &m_y);
77  m_outputTree->Branch("g_z", &m_z);
78  m_outputTree->Branch("g_t", &m_t);
79  m_outputTree->Branch("l_x", &m_lx);
80  m_outputTree->Branch("l_y", &m_ly);
81  m_outputTree->Branch("cov_l_x", &m_cov_lx);
82  m_outputTree->Branch("cov_l_y", &m_cov_ly);
83  m_outputTree->Branch("cell_ID_x", &m_cell_IDx);
84  m_outputTree->Branch("cell_ID_y", &m_cell_IDy);
85  m_outputTree->Branch("cell_l_x", &m_cell_lx);
86  m_outputTree->Branch("cell_l_y", &m_cell_ly);
87  m_outputTree->Branch("cell_data", &m_cell_data);
88  m_outputTree->Branch("truth_g_x", &m_t_gx);
89  m_outputTree->Branch("truth_g_y", &m_t_gy);
90  m_outputTree->Branch("truth_g_z", &m_t_gz);
91  m_outputTree->Branch("truth_g_t", &m_t_gt);
92  m_outputTree->Branch("truth_l_x", &m_t_lx);
93  m_outputTree->Branch("truth_l_y", &m_t_ly);
94  m_outputTree->Branch("truth_barcode", &m_t_barcode);
95 }
96 
98  if (m_outputFile != nullptr) {
99  m_outputFile->Close();
100  }
101 }
102 
104  // Write the tree
105  m_outputFile->cd();
106  m_outputTree->Write();
107  m_outputFile->Close();
108 
109  ACTS_INFO("Wrote clusters to tree '" << m_cfg.treeName << "' in '"
110  << m_cfg.filePath << "'");
111 
112  return ProcessCode::SUCCESS;
113 }
114 
116  const AlgorithmContext& ctx,
118  clusters) {
119  // retrieve simulated hits
120  const auto& simHits = m_inputSimHits(ctx);
121 
122  // Exclusive access to the tree while writing
123  std::lock_guard<std::mutex> lock(m_writeMutex);
124  // Get the event number
125  m_eventNr = ctx.eventNumber;
126 
127  // Loop over the planar clusters in this event
128  for (auto [moduleGeoId, moduleClusters] : groupByModule(clusters)) {
129  const Acts::Surface* surfacePtr =
130  m_cfg.trackingGeometry->findSurface(moduleGeoId);
131  if (surfacePtr == nullptr) {
132  ACTS_ERROR("Could not find surface for " << moduleGeoId);
133  return ProcessCode::ABORT;
134  }
135  const Acts::Surface& surface = *surfacePtr;
136 
137  // geometry identification is the same for all clusters on this module
138  m_volumeID = moduleGeoId.volume();
139  m_layerID = moduleGeoId.layer();
140  m_surfaceID = moduleGeoId.sensitive();
141 
142  for (const auto& entry : moduleClusters) {
143  const Acts::PlanarModuleCluster& cluster = entry.second;
144  // local cluster information: position, @todo coveraiance
145  auto parameters = cluster.parameters();
148 
150  Acts::Vector3 mom(1, 1, 1);
151  // transform local into global position information
152  Acts::Vector3 pos = surface.localToGlobal(ctx.geoContext, local, mom);
153  m_x = pos.x();
154  m_y = pos.y();
155  m_z = pos.z();
157  m_lx = local.x();
158  m_ly = local.y();
159  m_cov_lx = 0.; // @todo fill in
160  m_cov_ly = 0.; // @todo fill in
161  // get the cells and run through them
162  const auto& cells = cluster.digitizationCells();
163  auto detectorElement =
164  dynamic_cast<const Acts::IdentifiedDetectorElement*>(
165  surface.associatedDetectorElement());
166  for (auto& cell : cells) {
167  // cell identification
168  m_cell_IDx.push_back(cell.channel0);
169  m_cell_IDy.push_back(cell.channel1);
170  m_cell_data.push_back(cell.data);
171  // for more we need the digitization module
172  if ((detectorElement != nullptr) &&
173  detectorElement->digitizationModule()) {
174  auto digitationModule = detectorElement->digitizationModule();
175  const Acts::Segmentation& segmentation =
176  digitationModule->segmentation();
177  // get the cell positions
178  auto cellLocalPosition = segmentation.cellPosition(cell);
179  m_cell_lx.push_back(cellLocalPosition.x());
180  m_cell_ly.push_back(cellLocalPosition.y());
181  }
182  }
183  // write hit-particle truth association
184  // each hit can have multiple particles, e.g. in a dense environment
185  const auto& sl = cluster.sourceLink().get<Acts::DigitizationSourceLink>();
186  for (auto idx : sl.indices()) {
187  auto it = simHits.nth(idx);
188  if (it == simHits.end()) {
189  ACTS_FATAL("Simulation hit with index " << idx << " does not exist");
190  return ProcessCode::ABORT;
191  }
192  const auto& simHit = *it;
193 
194  // local position to be calculated
195  Acts::Vector2 lPosition{0., 0.};
196  auto lpResult = surface.globalToLocal(ctx.geoContext, simHit.position(),
197  simHit.direction());
198  if (not lpResult.ok()) {
199  ACTS_FATAL("Global to local transformation did not succeed.");
200  return ProcessCode::ABORT;
201  }
202  lPosition = lpResult.value();
203  // fill the variables
204  m_t_gx.push_back(simHit.position().x());
205  m_t_gy.push_back(simHit.position().y());
206  m_t_gz.push_back(simHit.position().z());
207  m_t_gt.push_back(simHit.time());
208  m_t_lx.push_back(lPosition.x());
209  m_t_ly.push_back(lPosition.y());
210  m_t_barcode.push_back(simHit.particleId().value());
211  }
212  // fill the tree
213  m_outputTree->Fill();
214  // now reset
215  m_cell_IDx.clear();
216  m_cell_IDy.clear();
217  m_cell_lx.clear();
218  m_cell_ly.clear();
219  m_cell_data.clear();
220  m_t_gx.clear();
221  m_t_gy.clear();
222  m_t_gz.clear();
223  m_t_gt.clear();
224  m_t_lx.clear();
225  m_t_ly.clear();
226  m_t_barcode.clear();
227  }
228  }
230 }