forked from acts-project/acts
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSurfaceArray.hpp
More file actions
583 lines (500 loc) · 22.7 KB
/
SurfaceArray.hpp
File metadata and controls
583 lines (500 loc) · 22.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
// This file is part of the ACTS project.
//
// Copyright (C) 2016 CERN for the benefit of the ACTS project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
#pragma once
#include "Acts/Definitions/Algebra.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/Surfaces/BoundaryTolerance.hpp"
#include "Acts/Surfaces/CylinderBounds.hpp"
#include "Acts/Surfaces/RegularSurface.hpp"
#include "Acts/Surfaces/Surface.hpp"
#include "Acts/Utilities/AnyGridView.hpp"
#include "Acts/Utilities/AxisDefinitions.hpp"
#include "Acts/Utilities/Grid.hpp"
#include "Acts/Utilities/IAxis.hpp"
#include "Acts/Utilities/Intersection.hpp"
#include <iostream>
#include <limits>
#include <vector>
namespace Acts {
using SurfaceVector = std::vector<const Surface*>;
/// @brief Provides Surface binning in 2 dimensions
///
/// Uses @c Grid under the hood to implement the storage and lookup
/// Contains a lookup struct which talks to the @c Grid
/// and performs utility actions. This struct needs to be initialised
/// externally and passed to @c SurfaceArray on construction.
class SurfaceArray {
public:
/// @brief Base interface for all surface lookups.
struct ISurfaceGridLookup {
/// @brief Fill provided surfaces into the contained @c Grid.
/// @param gctx The current geometry context object, e.g. alignment
/// @param surfaces Input surface pointers
virtual void fill(const GeometryContext& gctx,
const SurfaceVector& surfaces) = 0;
/// @brief Performs lookup at @c pos and returns bin content as const
/// reference
/// @param position Lookup position
/// @param direction Lookup direction
/// @return @c SurfaceVector at given bin
virtual const SurfaceVector& lookup(const Vector3& position,
const Vector3& direction) const = 0;
/// @brief Performs lookup at global bin and returns bin content as
/// reference
/// @param bin Global lookup bin
/// @return @c SurfaceVector at given bin
virtual SurfaceVector& lookup(std::size_t bin) = 0;
/// @brief Performs lookup at global bin and returns bin content as const
/// reference
/// @param bin Global lookup bin
/// @return @c SurfaceVector at given bin
virtual const SurfaceVector& lookup(std::size_t bin) const = 0;
/// @brief Performs a lookup at @c pos, but returns neighbors as well
///
/// @param position Lookup position
/// @param direction Lookup direction
/// @return @c SurfaceVector at given bin. Copy of all bins selected
virtual const SurfaceVector& neighbors(const Vector3& position,
const Vector3& direction) const = 0;
/// @brief Returns the total size of the grid (including under/overflow
/// bins)
/// @return Size of the grid data structure
virtual std::size_t size() const = 0;
/// @brief Gets the center position of bin @c bin in global coordinates
/// @param bin the global bin index
/// @return The bin center
virtual Vector3 getBinCenter(std::size_t bin) const = 0;
/// @brief Returns copies of the axes used in the grid as @c AnyAxis
/// @return The axes
/// @note This returns copies. Use for introspection and querying.
virtual std::vector<const IAxis*> getAxes() const = 0;
/// @brief Get a view of the grid for inspection
/// @return Optional grid view containing surface vectors
virtual std::optional<AnyGridConstView<SurfaceVector>> getGridView()
const = 0;
/// @brief Get the representative surface used for this lookup
/// @return Surface pointer
virtual const Surface* surfaceRepresentation() const = 0;
/// @brief Checks if global bin is valid
/// @param bin the global bin index
/// @return bool if the bin is valid
/// @note Valid means that the index points to a bin which is not a under
/// or overflow bin or out of range in any axis.
virtual bool isValidBin(std::size_t bin) const = 0;
/// @brief The binning values described by this surface grid lookup
/// They are in order of the axes (optional) and empty for eingle lookups
/// @return Vector of axis directions for binning
virtual std::vector<AxisDirection> binningValues() const { return {}; };
/// Pure virtual destructor
virtual ~ISurfaceGridLookup() = 0;
};
/// @brief Lookup helper which encapsulates a @c Grid
/// @tparam Axes The axes used for the grid
template <class Axis1, class Axis2>
struct SurfaceGridLookup : ISurfaceGridLookup {
/// Grid type storing surface vectors with two axes
using Grid_t = Grid<SurfaceVector, Axis1, Axis2>;
/// Construct a surface grid lookup
/// @param representative The surface which is used as representative
/// @param tolerance The tolerance used for intersection checks
/// @param axes The axes used for the grid
/// @param bValues Optional vector of axis directions for binning
SurfaceGridLookup(std::shared_ptr<RegularSurface> representative,
double tolerance, std::tuple<Axis1, Axis2> axes,
std::vector<AxisDirection> bValues = {})
: m_representative(std::move(representative)),
m_tolerance(tolerance),
m_grid(std::move(axes)),
m_binValues(std::move(bValues)) {
m_neighborMap.resize(m_grid.size());
}
/// @brief Fill provided surfaces into the contained @c Grid.
///
/// This is done by iterating, accessing the referencePosition, lookup
/// and append.
/// Also populates the neighbor map by combining the filled bins of
/// all bins around a given one.
///
/// @param gctx The current geometry context object, e.g. alignment
/// @param surfaces Input surface pointers
void fill(const GeometryContext& gctx,
const SurfaceVector& surfaces) override {
for (const Surface* surface : surfaces) {
const std::size_t globalBin = fillSurfaceToBinMapping(gctx, *surface);
if (globalBin == 0) {
continue;
}
fillBinToSurfaceMapping(gctx, *surface, globalBin);
}
populateNeighborCache();
}
const SurfaceVector& lookup(const Vector3& position,
const Vector3& direction) const override {
return m_grid.at(findGlobalBin(position, direction,
std::numeric_limits<double>::infinity()));
}
/// @brief Performs lookup at global bin and returns bin content as
/// reference
/// @param bin Global lookup bin
/// @return @c SurfaceVector at given bin
SurfaceVector& lookup(std::size_t bin) override { return m_grid.at(bin); }
/// @brief Performs lookup at global bin and returns bin content as const
/// reference
/// @param bin Global lookup bin
/// @return @c SurfaceVector at given bin
const SurfaceVector& lookup(std::size_t bin) const override {
return m_grid.at(bin);
}
/// @brief Performs a lookup at @c pos, but returns neighbors as well
///
/// @param position Lookup position
/// @param direction Lookup direction
/// @return @c SurfaceVector at given bin. Copy of all bins selected
const SurfaceVector& neighbors(const Vector3& position,
const Vector3& direction) const override {
return m_neighborMap.at(findGlobalBin(
position, direction, std::numeric_limits<double>::infinity()));
}
/// @brief Returns the total size of the grid (including under/overflow
/// bins)
/// @return Size of the grid data structure
std::size_t size() const override { return m_grid.size(); }
/// @brief The binning values described by this surface grid lookup
/// They are in order of the axes
/// @return Vector of axis directions for binning
std::vector<AxisDirection> binningValues() const override {
return m_binValues;
}
/// @brief Gets the center position of bin @c bin in global coordinates
/// @param bin the global bin index
/// @return The bin center
Vector3 getBinCenter(std::size_t bin) const override {
auto gctx = GeometryContext::dangerouslyDefaultConstruct();
return getBinCenterImpl(gctx, bin);
}
/// @brief Returns copies of the axes used in the grid as @c AnyAxis
/// @return The axes
/// @note This returns copies. Use for introspection and querying.
std::vector<const IAxis*> getAxes() const override {
auto arr = m_grid.axes();
return std::vector<const IAxis*>(arr.begin(), arr.end());
}
std::optional<AnyGridConstView<SurfaceVector>> getGridView()
const override {
return AnyGridConstView<SurfaceVector>{m_grid};
}
const Surface* surfaceRepresentation() const override {
return m_representative.get();
}
/// @brief Checks if global bin is valid
/// @param bin the global bin index
/// @return bool if the bin is valid
/// @note Valid means that the index points to a bin which is not a under
/// or overflow bin or out of range in any axis.
bool isValidBin(std::size_t bin) const override {
std::array<std::size_t, 2> indices = m_grid.localBinsFromGlobalBin(bin);
std::array<std::size_t, 2> nBins = m_grid.numLocalBins();
for (std::size_t i = 0; i < indices.size(); ++i) {
std::size_t idx = indices.at(i);
if (idx <= 0 || idx >= nBins.at(i) + 1) {
return false;
}
}
return true;
}
private:
/// map surface center to grid
std::size_t fillSurfaceToBinMapping(const GeometryContext& gctx,
const Surface& surface) {
const Vector3 pos = surface.referencePosition(gctx, AxisDirection::AxisR);
const Vector3 normal = m_representative->normal(gctx, pos);
const std::size_t globalBin = findGlobalBin(pos, normal, m_tolerance);
if (globalBin != 0) {
m_grid.at(globalBin).push_back(&surface);
}
return globalBin;
};
/// flood fill neighboring bins given a starting bin
void fillBinToSurfaceMapping(const GeometryContext& gctx,
const Surface& surface, std::size_t startBin) {
const std::array<std::size_t, 2> startIndices =
m_grid.localBinsFromGlobalBin(startBin);
const auto startNeighborIndices =
m_grid.neighborHoodIndices(startIndices, 1u);
std::set<std::size_t> visited({startBin});
std::vector<std::size_t> queue(startNeighborIndices.begin(),
startNeighborIndices.end());
while (!queue.empty()) {
const std::size_t current = queue.back();
queue.pop_back();
if (visited.contains(current)) {
continue;
}
const std::array<std::size_t, 2> currentIndices =
m_grid.localBinsFromGlobalBin(current);
visited.insert(current);
const std::array<double, 2> gridLocal =
m_grid.binCenter(currentIndices);
const Vector2 surfaceLocal = gridToSurfaceLocal(gridLocal);
const Vector3 normal = m_representative->normal(gctx, surfaceLocal);
const Vector3 global =
m_representative->localToGlobal(gctx, surfaceLocal, normal);
const Intersection3D intersection =
surface.intersect(gctx, global, normal, BoundaryTolerance::None())
.closest();
if (!intersection.isValid() ||
std::abs(intersection.pathLength()) > m_tolerance) {
continue;
}
m_grid.at(current).push_back(&surface);
const auto neighborIndices =
m_grid.neighborHoodIndices(currentIndices, 1u);
queue.insert(queue.end(), neighborIndices.begin(),
neighborIndices.end());
}
};
void populateNeighborCache() {
// calculate neighbors for every bin and store in map
for (std::size_t i = 0; i < m_grid.size(); i++) {
if (!isValidBin(i)) {
continue;
}
const std::array<std::size_t, 2> indices =
m_grid.localBinsFromGlobalBin(i);
std::vector<const Surface*>& neighbors = m_neighborMap.at(i);
neighbors.clear();
for (std::size_t idx : m_grid.neighborHoodIndices(indices, 1u)) {
const std::vector<const Surface*>& binContent = m_grid.at(idx);
std::copy(binContent.begin(), binContent.end(),
std::back_inserter(neighbors));
}
std::ranges::sort(neighbors);
auto last = std::ranges::unique(neighbors);
neighbors.erase(last.begin(), last.end());
neighbors.shrink_to_fit();
}
}
Vector3 getBinCenterImpl(const GeometryContext& gctx,
std::size_t bin) const {
const std::array<double, 2> gridLocal =
m_grid.binCenter(m_grid.localBinsFromGlobalBin(bin));
const Vector2 surfaceLocal = gridToSurfaceLocal(gridLocal);
return m_representative->localToGlobal(gctx, surfaceLocal);
}
const CylinderBounds* getCylinderBounds() const {
return dynamic_cast<const CylinderBounds*>(&m_representative->bounds());
}
Vector2 gridToSurfaceLocal(std::array<double, 2> gridLocal) const {
Vector2 surfaceLocal = Eigen::Map<Vector2>(gridLocal.data());
if (const CylinderBounds* bounds = getCylinderBounds();
bounds != nullptr) {
surfaceLocal[0] *= bounds->get(CylinderBounds::eR);
}
return surfaceLocal;
}
std::array<double, 2> surfaceToGridLocal(Vector2 local) const {
std::array<double, 2> gridLocal = {local[0], local[1]};
if (const CylinderBounds* bounds = getCylinderBounds();
bounds != nullptr) {
gridLocal[0] /= bounds->get(CylinderBounds::eR);
}
return gridLocal;
}
std::size_t findGlobalBin(const Vector3& position, const Vector3& direction,
double tolerance) const {
auto gctx = GeometryContext::dangerouslyDefaultConstruct();
const Intersection3D intersection =
m_representative
->intersect(gctx, position, direction,
BoundaryTolerance::Infinite())
.closest();
if (!intersection.isValid() ||
std::abs(intersection.pathLength()) > tolerance) {
return 0; // overflow bin
}
const Vector2 surfaceLocal =
m_representative
->globalToLocal(gctx, intersection.position(), direction)
.value();
const std::array<double, 2> gridLocal = surfaceToGridLocal(surfaceLocal);
return m_grid.globalBinFromPosition(gridLocal);
}
std::shared_ptr<RegularSurface> m_representative;
double m_tolerance{};
Grid_t m_grid;
std::vector<AxisDirection> m_binValues;
std::vector<SurfaceVector> m_neighborMap;
};
/// @brief Lookup implementation which wraps one element and always returns
/// this element when lookup is called
struct SingleElementLookup : ISurfaceGridLookup {
/// @brief Default constructor.
/// @param element the one and only element.
explicit SingleElementLookup(SurfaceVector::value_type element)
: m_element({element}) {}
/// @brief Default constructor.
/// @param elements the surfaces that are provided through a single lookup
explicit SingleElementLookup(const SurfaceVector& elements)
: m_element(elements) {}
/// @brief Lookup, always returns @c element
/// @return reference to vector containing only @c element
const SurfaceVector& lookup(const Vector3& /*position*/,
const Vector3& /*direction*/) const override {
return m_element;
}
/// @brief Lookup, always returns @c element
/// @return reference to vector containing only @c element
SurfaceVector& lookup(std::size_t /*bin*/) override { return m_element; }
/// @brief Lookup, always returns @c element
/// @return reference to vector containing only @c element
const SurfaceVector& lookup(std::size_t /*bin*/) const override {
return m_element;
}
/// @brief Lookup, always returns @c element
/// @return reference to vector containing only @c element
const SurfaceVector& neighbors(
const Vector3& /*position*/,
const Vector3& /*direction*/) const override {
return m_element;
}
/// @brief returns 1
/// @return 1
std::size_t size() const override { return 1; }
/// @brief Gets the bin center, but always returns (0, 0, 0)
/// @return (0, 0, 0)
Vector3 getBinCenter(std::size_t /*bin*/) const override {
return Vector3(0, 0, 0);
}
/// @brief Returns an empty vector of @c AnyAxis
/// @return empty vector
std::vector<const IAxis*> getAxes() const override { return {}; }
std::optional<AnyGridConstView<SurfaceVector>> getGridView()
const override {
return std::nullopt;
}
const Surface* surfaceRepresentation() const override { return nullptr; }
/// @brief Comply with concept and provide fill method
/// @note Does nothing
void fill(const GeometryContext& /*gctx*/,
const SurfaceVector& /*surfaces*/) override {}
/// @brief Returns if the bin is valid (it is)
/// @return always true
bool isValidBin(std::size_t /*bin*/) const override { return true; }
private:
SurfaceVector m_element;
};
/// @brief Default constructor which takes a @c SurfaceLookup and a vector of
/// surfaces
/// @param gridLookup The grid storage. @c SurfaceArray does not fill it on
/// its own
/// @param surfaces The input vector of surfaces. This is only for
/// bookkeeping, so we can ask
/// @param transform Optional additional transform for this SurfaceArray
explicit SurfaceArray(std::unique_ptr<ISurfaceGridLookup> gridLookup,
std::vector<std::shared_ptr<const Surface>> surfaces,
const Transform3& transform = Transform3::Identity());
/// @brief Constructor with a single surface
/// @param srf The one and only surface
explicit SurfaceArray(std::shared_ptr<const Surface> srf);
/// @brief Get all surfaces in bin given by position @p pos.
/// @param position the lookup position
/// @param direction the lookup direction
/// @return const reference to @c SurfaceVector contained in bin at that
/// position
const SurfaceVector& at(const Vector3& position,
const Vector3& direction) const {
return p_gridLookup->lookup(position, direction);
}
/// @brief Get all surfaces in bin given by global bin index @p bin.
/// @param bin the global bin index
/// @return reference to @c SurfaceVector contained in bin
SurfaceVector& at(std::size_t bin) { return p_gridLookup->lookup(bin); }
/// @brief Get all surfaces in bin given by global bin index.
/// @param bin the global bin index
/// @return const reference to @c SurfaceVector contained in bin
const SurfaceVector& at(std::size_t bin) const {
return p_gridLookup->lookup(bin);
}
/// @brief Get all surfaces in bin at @p pos and its neighbors
/// @param position The position to lookup
/// @param direction The direction to lookup
/// @return Merged @c SurfaceVector of neighbors and nominal
/// @note The @c SurfaceVector will be combined. For technical reasons, the
/// different bin content vectors have to be copied, so the resulting
/// vector contains copies.
const SurfaceVector& neighbors(const Vector3& position,
const Vector3& direction) const {
return p_gridLookup->neighbors(position, direction);
}
/// @brief Get the size of the underlying grid structure including
/// under/overflow bins
/// @return the size
std::size_t size() const { return p_gridLookup->size(); }
/// @brief Get the center of the bin identified by global bin index @p bin
/// @param bin the global bin index
/// @return Center position of the bin in global coordinates
Vector3 getBinCenter(std::size_t bin) const {
return p_gridLookup->getBinCenter(bin);
}
/// @brief Get all surfaces attached to this @c SurfaceArray
/// @return Reference to @c SurfaceVector containing all surfaces
/// @note This does not reflect the actual state of the grid. It only
/// returns what was given in the constructor, without any checks
/// if that is actually what's in the grid.
const SurfaceVector& surfaces() const { return m_surfacesRawPointers; }
/// @brief Get vector of axes spanning the grid as @c AnyAxis
/// @return vector of @c AnyAxis
/// @note The axes in the vector are copies. Only use for introspection and
/// querying.
std::vector<const IAxis*> getAxes() const { return p_gridLookup->getAxes(); }
/// @brief Checks if global bin is valid
/// @param bin the global bin index
/// @return bool if the bin is valid
/// @note Valid means that the index points to a bin which is not a under
/// or overflow bin or out of range in any axis.
bool isValidBin(std::size_t bin) const {
return p_gridLookup->isValidBin(bin);
}
/// Get the transform of this surface array.
/// @return Reference to the transformation matrix
const Transform3& transform() const { return m_transform; }
/// @brief The binning values described by this surface grid lookup
/// They are in order of the axes
/// @return Vector of axis directions for binning
std::vector<AxisDirection> binningValues() const {
return p_gridLookup->binningValues();
};
/// @brief String representation of this @c SurfaceArray
/// @param gctx The current geometry context object, e.g. alignment
/// @param sl Output stream to write to
/// @return the output stream given as @p sl
std::ostream& toStream(const GeometryContext& gctx, std::ostream& sl) const;
/// Return the lookup object
/// @return Reference to the surface grid lookup interface
const ISurfaceGridLookup& gridLookup() const { return *p_gridLookup; }
private:
/// Check consistency between provided surfaces and grid contents.
///
/// Iterates over all local grid bins, collects every surface pointer seen in
/// the bins, and compares that set against the surfaces provided to this
/// array. Throws if the sets differ (e.g. a provided surface is not present
/// in the grid).
///
/// @param grid The grid to check
void checkGrid(AnyGridConstView<SurfaceVector> grid);
std::unique_ptr<ISurfaceGridLookup> p_gridLookup;
// this vector makes sure we have shared ownership over the surfaces
std::vector<std::shared_ptr<const Surface>> m_surfaces;
// this vector is returned, so that (expensive) copying of the shared_ptr
// vector does not happen by default
SurfaceVector m_surfacesRawPointers;
// this is only used to keep info on transform applied
// by l2g and g2l
Transform3 m_transform;
};
} // namespace Acts