Skip to content

Commit

Permalink
fix: and refactor geometric digitization (#2630)
Browse files Browse the repository at this point in the history
* fix: activation was only 2D path, but must be 3D path. Otherwise, an upright track would get 0 activation...
* refactor: rename `Channelizer` to `Segmentizer`, add `Channelizer` that ties together the things
* added unit test
  • Loading branch information
benjaminhuth authored Nov 13, 2023
1 parent 85a0fea commit a01f82a
Show file tree
Hide file tree
Showing 16 changed files with 533 additions and 344 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
#include "ActsExamples/Framework/ProcessCode.hpp"
#include "ActsExamples/Framework/RandomNumbers.hpp"
#include "ActsFatras/Digitization/Channelizer.hpp"
#include "ActsFatras/Digitization/PlanarSurfaceDrift.hpp"
#include "ActsFatras/Digitization/PlanarSurfaceMask.hpp"
#include "ActsFatras/Digitization/Segmentizer.hpp"
#include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp"

#include <cstddef>
Expand Down Expand Up @@ -69,20 +68,6 @@ class DigitizationAlgorithm final : public IAlgorithm {
const DigitizationConfig& config() const { return m_cfg; }

private:
/// Helper method for the geometric channelizing part
///
/// @param geoCfg is the geometric digitization configuration
/// @param hit the Simultated hit
/// @param surface the Surface on which this is supposed to happen
/// @param gctx the Geometry context
/// @param rng the Random number engine for the drift smearing
///
/// @return the list of channels
std::vector<ActsFatras::Channelizer::ChannelSegment> channelizing(
const GeometricConfig& geoCfg, const SimHit& hit,
const Acts::Surface& surface, const Acts::GeometryContext& gctx,
RandomEngine& rng) const;

/// Helper method for creating digitized parameters from clusters
///
/// @todo ADD random smearing
Expand All @@ -93,7 +78,7 @@ class DigitizationAlgorithm final : public IAlgorithm {
/// @return the list of digitized parameters
DigitizedParameters localParameters(
const GeometricConfig& geoCfg,
const std::vector<ActsFatras::Channelizer::ChannelSegment>& channels,
const std::vector<ActsFatras::Segmentizer::ChannelSegment>& channels,
RandomEngine& rng) const;

/// Nested smearer struct that holds geometric digitizer and smearing
Expand All @@ -113,9 +98,7 @@ class DigitizationAlgorithm final : public IAlgorithm {
DigitizationConfig m_cfg;
/// Digitizers within geometry hierarchy
Acts::GeometryHierarchyMap<Digitizer> m_digitizers;
/// Geometric digtizers
ActsFatras::PlanarSurfaceDrift m_surfaceDrift;
ActsFatras::PlanarSurfaceMask m_surfaceMask;
/// Geometric digtizer
ActsFatras::Channelizer m_channelizer;

ReadDataHandle<SimHitContainer> m_simContainerReadHandle{this,
Expand Down
36 changes: 10 additions & 26 deletions Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,16 +205,20 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute(
ACTS_VERBOSE("Configured to geometric digitize "
<< digitizer.geometric.indices.size()
<< " parameters.");
auto channels = channelizing(digitizer.geometric, simHit,
*surfacePtr, ctx.geoContext, rng);
if (channels.empty()) {
const auto& cfg = digitizer.geometric;
Acts::Vector3 driftDir = cfg.drift(simHit.position(), rng);
auto channelsRes = m_channelizer.channelize(
simHit, *surfacePtr, ctx.geoContext, driftDir,
cfg.segmentation, cfg.thickness);
if (!channelsRes.ok() || channelsRes->empty()) {
ACTS_DEBUG(
"Geometric channelization did not work, skipping this hit.")
continue;
}
ACTS_VERBOSE("Activated " << channels.size()
ACTS_VERBOSE("Activated " << channelsRes->size()
<< " channels for this hit.");
dParameters = localParameters(digitizer.geometric, channels, rng);
dParameters =
localParameters(digitizer.geometric, *channelsRes, rng);
}

// Smearing part - (optionally) rest
Expand Down Expand Up @@ -292,30 +296,10 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute(
return ProcessCode::SUCCESS;
}

std::vector<ActsFatras::Channelizer::ChannelSegment>
ActsExamples::DigitizationAlgorithm::channelizing(
const GeometricConfig& geoCfg, const SimHit& hit,
const Acts::Surface& surface, const Acts::GeometryContext& gctx,
RandomEngine& rng) const {
Acts::Vector3 driftDir = geoCfg.drift(hit.position(), rng);

auto driftedSegment =
m_surfaceDrift.toReadout(gctx, surface, geoCfg.thickness, hit.position(),
hit.direction(), driftDir);
auto maskedSegmentRes = m_surfaceMask.apply(surface, driftedSegment);
if (maskedSegmentRes.ok()) {
auto maskedSegment = maskedSegmentRes.value();
// Now Channelize
return m_channelizer.segments(gctx, surface, geoCfg.segmentation,
maskedSegment);
}
return {};
}

ActsExamples::DigitizedParameters
ActsExamples::DigitizationAlgorithm::localParameters(
const GeometricConfig& geoCfg,
const std::vector<ActsFatras::Channelizer::ChannelSegment>& channels,
const std::vector<ActsFatras::Segmentizer::ChannelSegment>& channels,
RandomEngine& rng) const {
DigitizedParameters dParameters;

Expand Down
4 changes: 2 additions & 2 deletions Examples/Framework/include/ActsExamples/EventData/Cluster.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@

#pragma once

#include "ActsFatras/Digitization/Channelizer.hpp"
#include "ActsFatras/Digitization/Segmentizer.hpp"

#include <vector>

namespace ActsExamples {

/// Simple struct holding cluster information.
struct Cluster {
using Cell = ActsFatras::Channelizer::ChannelSegment;
using Cell = ActsFatras::Segmentizer::ChannelSegment;
size_t sizeLoc0 = 0;
size_t sizeLoc1 = 0;
std::vector<Cell> channels;
Expand Down
4 changes: 2 additions & 2 deletions Examples/Io/Csv/src/CsvMeasurementReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ ActsExamples::ClusterContainer makeClusters(

for (auto it = begin; it != end; ++it) {
const auto& cellData = it->second;
ActsFatras::Channelizer::Segment2D dummySegment = {Acts::Vector2::Zero(),
ActsFatras::Segmentizer::Segment2D dummySegment = {Acts::Vector2::Zero(),
Acts::Vector2::Zero()};

ActsFatras::Channelizer::Bin2D bin{
ActsFatras::Segmentizer::Bin2D bin{
static_cast<unsigned int>(cellData.channel0),
static_cast<unsigned int>(cellData.channel1)};

Expand Down
6 changes: 3 additions & 3 deletions Examples/Io/EDM4hep/src/EDM4hepUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,12 @@ Measurement EDM4hepUtil::readMeasurement(
// TODO get EDM4hep fixed
// misusing some fields to store ACTS specific information
// don't ask ...
ActsFatras::Channelizer::Bin2D bin{
ActsFatras::Segmentizer::Bin2D bin{
static_cast<unsigned int>(c.getType()),
static_cast<unsigned int>(c.getQuality())};
ActsFatras::Channelizer::Segment2D path2D;
ActsFatras::Segmentizer::Segment2D path2D;
double activation = c.getTime();
ActsFatras::Channelizer::ChannelSegment cell{bin, path2D, activation};
ActsFatras::Segmentizer::ChannelSegment cell{bin, path2D, activation};

toCluster->channels.push_back(cell);
}
Expand Down
4 changes: 2 additions & 2 deletions Examples/Python/tests/root_file_hashes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ test_material_mapping__propagation-material.root: 84b04ebd5721550867f0f193b5eb4e
test_volume_material_mapping__material-map-volume_tracks.root: b95561a6247df9e3599a997daa6c1d76461e58f83059b82f2ec27229c9b35e6c
test_volume_material_mapping__propagation-volume-material.root: ba0a302a2973498d257b70b78dfa6252d595c17960ee7fa754bd310bfaa9e7e8
test_digitization_example[smeared]__measurements.root: 413d8a82904fe5ca9380eec309aa4b6c0a829450db92125457edaaff5a624e5a
test_digitization_example[geometric]__measurements.root: 29db434701433e30205a7a12fa3e026cd2f2e8c07d32644ef0a54350058d87c4
test_digitization_example[geometric]__measurements.root: dd6a2bf0101efccfd70ad01969d21e8340f6a407e2a61d4cd1415cafe71c128d
test_digitization_example_input[smeared]__particles.root: 8549ba6e20338004ab8ba299fc65e1ee5071985b46df8f77f887cb6fef56a8ec
test_digitization_example_input[smeared]__measurements.root: 2e4fd9d3e6244e53486496e024f147e9ab2dcadb07453aa926d7ebad473089a5
test_digitization_example_input[geometric]__particles.root: 8549ba6e20338004ab8ba299fc65e1ee5071985b46df8f77f887cb6fef56a8ec
test_digitization_example_input[geometric]__measurements.root: 2dfd1889028fe3a0964fe9f91bc617987fbecd122256a9bd07433da1931323bc
test_digitization_example_input[geometric]__measurements.root: 20128357c9238926d628d18b3b91a0a73947b2b5682762bf5d8fd94342faf976
test_ckf_tracks_example[generic-full_seeding]__trackstates_ckf.root: 51f24a1b054c6a3304340a4616ef8f3634ce5a36cc16688dac4dda601e11f76d
test_ckf_tracks_example[generic-full_seeding]__tracksummary_ckf.root: 317d50baa6c25d02accf4280c4c689a5a65aa8aa4269ee987dd4fb00d3b2a40d
test_ckf_tracks_example[generic-full_seeding]__performance_seeding_trees.root: 0e0676ffafdb27112fbda50d1cf627859fa745760f98073261dcf6db3f2f991e
Expand Down
2 changes: 1 addition & 1 deletion Fatras/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
add_library(
ActsFatras SHARED
src/Digitization/Channelizer.cpp
src/Digitization/Segmentizer.cpp
src/Digitization/DigitizationError.cpp
src/Digitization/PlanarSurfaceMask.cpp
src/Digitization/PlanarSurfaceDrift.cpp
Expand Down
128 changes: 47 additions & 81 deletions Fatras/include/ActsFatras/Digitization/Channelizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,97 +8,63 @@

#pragma once

#include "Acts/Definitions/Algebra.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
#include "ActsFatras/Digitization/PlanarSurfaceDrift.hpp"
#include "ActsFatras/Digitization/PlanarSurfaceMask.hpp"
#include "ActsFatras/Digitization/Segmentizer.hpp"
#include "ActsFatras/EventData/Hit.hpp"

#include <array>
#include <utility>
#include <vector>

namespace Acts {
class BinUtility;
class Surface;
} // namespace Acts
#include <numeric>

namespace ActsFatras {

/// The Channelizer splits a surface segment, i.e. after projection
/// onto the readout surface into channel segments.
///
struct Channelizer {
/// Shorthand for a 2D segment
using Segment2D = std::array<Acts::Vector2, 2>;
/// Shorthand for a 2D bin
using Bin2D = std::array<unsigned int, 2>;
/// shorthand for a 2D bin delta
using BinDelta2D = std::array<int, 2>;
/// @brief Class that ties the digitization modules together and produces the channels
class Channelizer {
PlanarSurfaceDrift m_surfaceDrift;
PlanarSurfaceMask m_surfaceMask;
Segmentizer m_segmentizer;

/// Nested struct for stepping from one channel to the next.
struct ChannelStep {
/// This is the delta to the last step in bins
BinDelta2D delta = {0, 0};
/// The intersection with the channel boundary
Acts::Vector2 intersect;
/// The patlength from the start
double path = 0.;
public:
/// Do the geometric channelizing
///
/// @param hit The hit we want to channelize
/// @param surface the surface on which the hit is
/// @param gctx the Geometry context
/// @param driftDir the drift direction
/// @param segmentation the segmentation of the surface
/// @param thickness the thickness of the surface
///
/// @return the list of channels
Acts::Result<std::vector<Segmentizer::ChannelSegment>> channelize(
const Hit& hit, const Acts::Surface& surface,
const Acts::GeometryContext& gctx, const Acts::Vector3& driftDir,
const Acts::BinUtility& segmentation, double thickness) const {
auto driftedSegment = m_surfaceDrift.toReadout(
gctx, surface, thickness, hit.position(), hit.direction(), driftDir);

/// Constructor with arguments for a ChannelStep.
///
/// @param delta_ The bin delta for this step
/// @param intersect_ The intersect with the channel boundary
/// @param start The start of the surface segment, for path from origin
ChannelStep(BinDelta2D delta_, Acts::Vector2 intersect_,
const Acts::Vector2& start)
: delta(delta_),
intersect(std::move(intersect_)),
path((intersect - start).norm()) {}
auto maskedSegmentRes = m_surfaceMask.apply(surface, driftedSegment);

/// Smaller operator for sorting the ChannelStep objects.
///
/// @param cstep The other ChannelStep to be compared
///
/// The ChannelStep objects can be compared with its path distance
/// from the start (surface segment origin)
bool operator<(const ChannelStep& cstep) const { return path < cstep.path; }
};
if (!maskedSegmentRes.ok()) {
return maskedSegmentRes.error();
}

/// Nested struct for representing channel steps.
struct ChannelSegment {
/// The bin of this segment
Bin2D bin = {0, 0};
/// The segment start, end points
Segment2D path2D;
/// The (clipped) value (uncorrected: path length)
double activation = 0.;
// Now Channelize
auto segments =
m_segmentizer.segments(gctx, surface, segmentation, *maskedSegmentRes);

/// Constructor with arguments
///
/// @param bin_ The bin corresponding to this step
/// @param path2D_ The start/end 2D position of the segement
/// @param activation_ The segment activation (clean: length) for this bin
ChannelSegment(Bin2D bin_, Segment2D path2D_, double activation_)
: bin(bin_), path2D(std::move(path2D_)), activation(activation_) {}
};
// Go from 2D-path to 3D-path by applying thickness
const auto path2D = std::accumulate(
segments.begin(), segments.end(), 0.0,
[](double sum, const auto& seg) { return sum + seg.activation; });

/// Divide the surface segment into channel segments.
///
/// @note Channelizing is done in cartesian coordinates (start/end)
/// @note The start and end cartesian vector is supposed to be inside
/// the surface bounds (pre-run through the SurfaceMasker)
/// @note The segmentation has to be 2-dimensional, even if the
/// actual readout is 1-dimensional, in latter case one bin in the
/// second coordinate direction is required.
///
/// @param geoCtx The geometry context for the localToGlobal, etc.
/// @param surface The surface for the channelizing
/// @param segmentation The segmentation for the channelizing
/// @param segment The surface segment (cartesian coordinates)
///
/// @return a vector of ChannelSegment objects
std::vector<ChannelSegment> segments(const Acts::GeometryContext& geoCtx,
const Acts::Surface& surface,
const Acts::BinUtility& segmentation,
const Segment2D& segment) const;
for (auto& seg : segments) {
auto r = path2D != 0.0 ? (seg.activation / path2D) : 1.0;
auto segThickness = r * thickness;

seg.activation = std::hypot(segThickness, seg.activation);
}

return segments;
}
};

} // namespace ActsFatras
2 changes: 2 additions & 0 deletions Fatras/include/ActsFatras/Digitization/PlanarSurfaceMask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#pragma once

#include "Acts/Definitions/Algebra.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/Surfaces/detail/IntersectionHelper2D.hpp"
Expand Down
Loading

0 comments on commit a01f82a

Please sign in to comment.