Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
main.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file main.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2023 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 
9 // Local include(s).
10 #include "CommandLineArguments.hpp"
11 #include "ReadSeedFile.hpp"
12 #include "TestDeviceCuts.hpp"
13 #include "TestHostCuts.hpp"
14 #include "TestSpacePoint.hpp"
15 
16 // CUDA plugin include(s).
20 
21 // Acts include(s).
28 
29 // System include(s).
30 #include <cassert>
31 #include <chrono>
32 #include <iomanip>
33 #include <iostream>
34 #include <iterator>
35 #include <memory>
36 
37 using namespace Acts::UnitLiterals;
38 
39 int main(int argc, char* argv[]) {
40  // Interpret the command line arguments passed to the executable.
42  cmdl.interpret(argc, argv);
43 
44  // Read in the seeds from the input text file.
45  auto spacepoints = readSeedFile(cmdl.spFile, cmdl.filterDuplicates);
46  std::cout << "Read " << spacepoints.size()
47  << " spacepoints from file: " << cmdl.spFile << std::endl;
48 
49  // Create a "view vector" on top of them. This is necessary to be able to pass
50  // the objects to the Acts code. While the return type of readSeedFile(...) is
51  // useful for simplified memory management...
52  std::vector<const TestSpacePoint*> spView;
53  spView.reserve(spacepoints.size());
54  for (const auto& sp : spacepoints) {
55  spView.push_back(sp.get());
56  }
57 
58  int numPhiNeighbors = 1;
59 
60  std::vector<std::pair<int, int>> zBinNeighborsTop;
61  std::vector<std::pair<int, int>> zBinNeighborsBottom;
62 
63  // Create binned groups of these spacepoints.
64  auto bottomBinFinder = std::make_shared<Acts::BinFinder<TestSpacePoint>>(
65  zBinNeighborsBottom, numPhiNeighbors);
66  auto topBinFinder = std::make_shared<Acts::BinFinder<TestSpacePoint>>(
67  zBinNeighborsTop, numPhiNeighbors);
68 
69  // Set up the seedFinder configuration.
71  // silicon detector max
72  sfConfig.rMax = 160._mm;
73  sfConfig.deltaRMin = 5._mm;
74  sfConfig.deltaRMax = 160._mm;
75  sfConfig.collisionRegionMin = -250._mm;
76  sfConfig.collisionRegionMax = 250._mm;
77  sfConfig.zMin = -2800._mm;
78  sfConfig.zMax = 2800._mm;
79  sfConfig.maxSeedsPerSpM = 5;
80  // 2.7 eta
81  sfConfig.cotThetaMax = 7.40627;
82  sfConfig.sigmaScattering = 1.00000;
83  sfConfig.minPt = 500._MeV;
84  sfConfig.impactMax = 10._mm;
85  Acts::SeedFinderOptions sfOptions;
86  sfOptions.bFieldInZ = 1.99724_T;
87  sfOptions.beamPos = {-.5_mm, -.5_mm};
88 
89  // Use a size slightly smaller than what modern GPUs are capable of. This is
90  // because for debugging we can't use all available threads in a block, and
91  // because early testing shows that using this sort of block size results in
92  // better performance than using the maximal one. (It probably works better
93  // with the kind of branching that is present in the CUDA code.)
94  sfConfig.maxBlockSize = 256;
95 
96  sfConfig = sfConfig.toInternalUnits().calculateDerivedQuantities();
97 
98  // Set up the spacepoint grid configuration.
99  Acts::SpacePointGridConfig gridConfig;
100  gridConfig.minPt = sfConfig.minPt;
101  gridConfig.rMax = sfConfig.rMax;
102  gridConfig.zMax = sfConfig.zMax;
103  gridConfig.zMin = sfConfig.zMin;
104  gridConfig.deltaRMax = sfConfig.deltaRMax;
105  gridConfig.cotThetaMax = sfConfig.cotThetaMax;
106  gridConfig = gridConfig.toInternalUnits();
107  // Set up the spacepoint grid options
109  gridOpts.bFieldInZ = sfOptions.bFieldInZ;
110 
111  // Covariance tool, sets covariances per spacepoint as required.
112  auto ct = [=](const TestSpacePoint& sp, float, float,
113  float) -> std::pair<Acts::Vector3, Acts::Vector2> {
114  Acts::Vector3 position(sp.x(), sp.y(), sp.z());
116  return std::make_pair(position, covariance);
117  };
118 
119  // extent used to store r range for middle spacepoint
120  Acts::Extent rRangeSPExtent;
121 
122  const Acts::Range1D<float> rMiddleSPRange;
123 
124  // Create a grid with bin sizes according to the configured geometry, and
125  // split the spacepoints into groups according to that grid.
126  auto grid = Acts::SpacePointGridCreator::createGrid<TestSpacePoint>(
127  gridConfig, gridOpts);
129  spView.begin(), spView.end(), ct, bottomBinFinder, topBinFinder,
130  std::move(grid), rRangeSPExtent, sfConfig, sfOptions);
131  // Make a convenient iterator that will be used multiple times later on.
132  auto spGroup_end = spGroup.end();
133 
134  // Allocate memory on the selected CUDA device.
135  if (Acts::Cuda::Info::instance().devices().size() <=
136  static_cast<std::size_t>(cmdl.cudaDevice)) {
137  std::cerr << "Invalid CUDA device (" << cmdl.cudaDevice << ") requested"
138  << std::endl;
139  return 1;
140  }
141  static constexpr std::size_t MEGABYTES = 1024l * 1024l;
142  std::size_t deviceMemoryAllocation = cmdl.cudaDeviceMemory * MEGABYTES;
143  if (deviceMemoryAllocation == 0) {
144  deviceMemoryAllocation =
145  Acts::Cuda::Info::instance().devices()[cmdl.cudaDevice].totalMemory *
146  0.8;
147  }
148  std::cout << "Allocating " << deviceMemoryAllocation / MEGABYTES
149  << " MB memory on device:\n"
151  << std::endl;
152  Acts::Cuda::MemoryManager::instance().setMemorySize(deviceMemoryAllocation,
153  cmdl.cudaDevice);
154 
155  // Set up the seedFinder configuration objects.
156  TestHostCuts hostCuts;
157  Acts::SeedFilterConfig filterConfig;
158  filterConfig = filterConfig.toInternalUnits();
159  sfConfig.seedFilter = std::make_unique<Acts::SeedFilter<TestSpacePoint>>(
160  filterConfig, &hostCuts);
161  auto deviceCuts = testDeviceCuts();
162 
163  // Set up the seedFinder objects.
164  Acts::SeedFinder<TestSpacePoint> seedFinder_host(sfConfig);
165  Acts::Cuda::SeedFinder<TestSpacePoint> seedFinder_device(
166  sfConfig, sfOptions, filterConfig, deviceCuts, cmdl.cudaDevice);
167 
168  //
169  // Perform the seed finding on the host.
170  //
171 
172  // Record the start time.
173  auto start_host = std::chrono::system_clock::now();
174  // Create the result object.
175  std::vector<std::vector<Acts::Seed<TestSpacePoint>>> seeds_host;
176 
177  // Perform the seed finding.
178  if (!cmdl.onlyGPU) {
179  decltype(seedFinder_host)::SeedingState state;
180  for (std::size_t i = 0; i < cmdl.groupsToIterate; ++i) {
181  auto spGroup_itr = Acts::BinnedSPGroupIterator(spGroup, i);
182  if (spGroup_itr == spGroup.end()) {
183  break;
184  }
185  auto& group = seeds_host.emplace_back();
186  auto [bottom, middle, top] = *spGroup_itr;
187 
188  seedFinder_host.createSeedsForGroup(sfOptions, state, spGroup.grid(),
189  std::back_inserter(group), bottom,
190  middle, top, rMiddleSPRange);
191  }
192  }
193 
194  // Record the finish time.
195  auto end_host = std::chrono::system_clock::now();
196  double time_host = std::chrono::duration_cast<std::chrono::milliseconds>(
197  end_host - start_host)
198  .count() *
199  0.001;
200  if (!cmdl.onlyGPU) {
201  std::cout << "Done with the seedfinding on the host" << std::endl;
202  }
203 
204  //
205  // Perform the seed finding on the accelerator.
206  //
207 
208  // Record the start time.
209  auto start_device = std::chrono::system_clock::now();
210  // Create the result object.
211  std::vector<std::vector<Acts::Seed<TestSpacePoint>>> seeds_device;
212  Acts::SpacePointData spacePointData;
213  spacePointData.resize(spView.size());
214 
215  // Perform the seed finding.
216  for (std::size_t i = 0; i < cmdl.groupsToIterate; ++i) {
217  auto spGroup_itr = Acts::BinnedSPGroupIterator(spGroup, i);
218  if (spGroup_itr == spGroup_end) {
219  break;
220  }
221  auto [bottom, middle, top] = *spGroup_itr;
222  seeds_device.push_back(seedFinder_device.createSeedsForGroup(
223  spacePointData, spGroup.grid(), bottom, middle, top));
224  }
225 
226  // Record the finish time.
227  auto end_device = std::chrono::system_clock::now();
228  double time_device = std::chrono::duration_cast<std::chrono::milliseconds>(
229  end_device - start_device)
230  .count() *
231  0.001;
232  std::cout << "Done with the seedfinding on the device" << std::endl;
233 
234  //
235  // Print some summary about the seed finding.
236  //
237 
238  // Count the total number of reconstructed seeds.
239  std::size_t nSeeds_host = 0, nSeeds_device = 0;
240  for (const auto& seeds : seeds_host) {
241  nSeeds_host += seeds.size();
242  }
243  for (const auto& seeds : seeds_device) {
244  nSeeds_device += seeds.size();
245  }
246 
247  // Count how many seeds, reconstructed on the host, can be matched with seeds
248  // reconstructed on the accelerator.
249  std::size_t nMatch = 0;
250  double matchPercentage = 0.0;
251  if (!cmdl.onlyGPU) {
252  assert(seeds_host.size() == seeds_device.size());
253  for (size_t i = 0; i < seeds_host.size(); i++) {
254  // Access the seeds for this region.
255  const auto& seeds_in_host_region = seeds_host[i];
256  const auto& seeds_in_device_region = seeds_device[i];
257  // Loop over all seeds found on the host.
258  for (const auto& host_seed : seeds_in_host_region) {
259  assert(host_seed.sp().size() == 3);
260  // Try to find a matching seed that was found on the accelerator.
261  for (const auto& device_seed : seeds_in_device_region) {
262  assert(device_seed.sp().size() == 3);
263  if ((*(host_seed.sp()[0]) == *(device_seed.sp()[0])) &&
264  (*(host_seed.sp()[1]) == *(device_seed.sp()[1])) &&
265  (*(host_seed.sp()[2]) == *(device_seed.sp()[2]))) {
266  ++nMatch;
267  break;
268  }
269  }
270  }
271  }
272  matchPercentage = (100.0 * nMatch) / nSeeds_host;
273  }
274 
275  // Print the summary results.
276  std::cout << std::endl;
277  std::cout << "-------------------------- Results ---------------------------"
278  << std::endl;
279  std::cout << "| | Host | Device | Speedup/agreement |"
280  << std::endl;
281  std::cout << "--------------------------------------------------------------"
282  << std::endl;
283  std::cout << "| Time [s] | " << std::setw(10)
284  << (cmdl.onlyGPU ? "N/A " : std::to_string(time_host)) << " | "
285  << std::setw(10) << time_device << " | " << std::setw(10)
286  << (cmdl.onlyGPU ? "N/A "
287  : std::to_string(time_host / time_device))
288  << " |" << std::endl;
289  std::cout << "| Seeds | " << std::setw(10)
290  << (cmdl.onlyGPU ? "N/A " : std::to_string(nSeeds_host))
291  << " | " << std::setw(10) << nSeeds_device << " | "
292  << std::setw(10)
293  << (cmdl.onlyGPU ? "N/A " : std::to_string(matchPercentage))
294  << " |" << std::endl;
295  std::cout << "--------------------------------------------------------------"
296  << std::endl;
297  std::cout << std::endl;
298 
299  // Return gracefully.
300  return 0;
301 }