Skip to content

Commit

Permalink
feat: Introduce particle hypothesis (#2254)
Browse files Browse the repository at this point in the history
In this PR I introduce the concept of a particle hypothesis which will later be used by the track parameters.

I also refactored the Charge interface a bit. This is the foundation for upcoming refactor PRs for the particle hypothesis.

Pulled out from #2181.

Co-authored-by: Paul Gessinger <1058585+paulgessinger@users.noreply.github.com>
  • Loading branch information
andiwand and paulgessinger committed Jul 28, 2023
1 parent 75b6eb2 commit a2d0eb5
Show file tree
Hide file tree
Showing 7 changed files with 597 additions and 44 deletions.
162 changes: 126 additions & 36 deletions Core/include/Acts/EventData/Charge.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#pragma once

#include "Acts/Definitions/Units.hpp"
#include "Acts/EventData/ChargeConcept.hpp"
#include "Acts/Utilities/Concepts.hpp"

#include <cassert>
#include <cmath>
Expand Down Expand Up @@ -51,26 +53,36 @@ namespace Acts {

/// Charge and momentum interpretation for neutral particles.
struct Neutral {
Neutral() = default;
constexpr Neutral() = default;

// TODO remove this method after grad refactor; currently track parameters
// depend on it
/// Construct and verify the input charge magnitude (in debug builds).
///
/// This constructor is only provided to allow consistent construction.
template <typename T>
constexpr Neutral(T absQ) noexcept {
assert((absQ == static_cast<T>(0)) and "Input charge must be zero");
// suppress `unused variable` warning in non-debug builds
(void)(absQ);
constexpr Neutral(float absQ) noexcept {
assert((absQ == 0) and "Input charge must be zero");
(void)absQ;
}

constexpr float absQ() const noexcept { return 0; }

template <typename T>
constexpr T extractCharge(T /* pInv */) const noexcept {
return 0;
constexpr auto extractCharge(T /*qOverP*/) const noexcept {
return 0.0f;
}

template <typename T>
constexpr T extractMomentum(T pInv) const noexcept {
// the abs is not strictly needed. it is added to protect against invalid,
// i.e. negative, 1/p values to ensure that the output is still correct.
return std::abs(1 / pInv);
constexpr auto extractMomentum(T qOverP) const noexcept {
assert(qOverP >= 0 && "qOverP cannot be negative");
return 1.0f / qOverP;
}

template <typename P, typename Q>
constexpr auto qOverP(P momentum, Q signedQ) const noexcept {
assert((signedQ != 0) and "charge must be 0");
(void)signedQ;
return 1.0f / momentum;
}

/// Compare for equality.
Expand All @@ -82,27 +94,43 @@ struct Neutral {
}
};

ACTS_STATIC_CHECK_CONCEPT(ChargeConcept, Neutral);

/// Charge and momentum interpretation for particles with +-e charge.
struct SinglyCharged {
SinglyCharged() = default;
constexpr SinglyCharged() = default;

// TODO remove this method after grad refactor; currently track parameters
// depend on it
/// Construct and verify the input charge magnitude (in debug builds).
///
/// This constructor is only provided to allow consistent construction.
template <typename T>
constexpr SinglyCharged(T absQ) noexcept {
assert((absQ == static_cast<T>(UnitConstants::e)) and
"Input charge magnitude must be e");
// suppress `unused variable` warning in non-debug builds
(void)(absQ);
constexpr SinglyCharged(float absQ) noexcept {
assert((absQ == UnitConstants::e) and "Input charge magnitude must be e");
(void)absQ;
}

constexpr float absQ() const noexcept { return UnitConstants::e; }

template <typename T>
constexpr T extractCharge(T qOverP) const noexcept {
return std::copysign(static_cast<T>(UnitConstants::e), qOverP);
constexpr auto extractCharge(T qOverP) const noexcept {
// using because of autodiff
using std::copysign;
return copysign(UnitConstants::e, qOverP);
}

template <typename T>
constexpr T extractMomentum(T qOverP) const noexcept {
return std::abs(static_cast<T>(UnitConstants::e) / qOverP);
constexpr auto extractMomentum(T qOverP) const noexcept {
// using because of autodiff
using std::abs;
return extractCharge(qOverP) / qOverP;
}

template <typename P, typename Q>
constexpr auto qOverP(P momentum, Q signedQ) const noexcept {
using std::abs;
assert((abs(signedQ) == UnitConstants::e) && "absolute charge must be e");
return signedQ / momentum;
}

/// Compare for equality.
Expand All @@ -115,41 +143,103 @@ struct SinglyCharged {
}
};

ACTS_STATIC_CHECK_CONCEPT(ChargeConcept, SinglyCharged);

/// Charge and momentum interpretation for arbitrarily charged but not neutral
/// particles.
class NonNeutralCharge {
public:
/// Construct with the magnitude of the input charge.
constexpr NonNeutralCharge(float absQ) noexcept : m_absQ{absQ} {
assert((0 < absQ) and "Input charge magnitude must be positive");
}
constexpr NonNeutralCharge(SinglyCharged /*unused*/) noexcept
: m_absQ{UnitConstants::e} {}

constexpr float absQ() const noexcept { return m_absQ; }

template <typename T>
constexpr auto extractCharge(T qOverP) const noexcept {
// using because of autodiff
using std::copysign;
return copysign(m_absQ, qOverP);
}
template <typename T>
constexpr auto extractMomentum(T qOverP) const noexcept {
// using because of autodiff
using std::abs;
return extractCharge(qOverP) / qOverP;
}

template <typename P, typename Q>
constexpr auto qOverP(P momentum, Q signedQ) const noexcept {
// using because of autodiff
using std::abs;
assert(abs(signedQ) == m_absQ && "inconsistent charge");
return signedQ / momentum;
}

/// Compare for equality.
friend constexpr bool operator==(NonNeutralCharge lhs,
NonNeutralCharge rhs) noexcept {
return lhs.m_absQ == rhs.m_absQ;
}

private:
float m_absQ{};
};

ACTS_STATIC_CHECK_CONCEPT(ChargeConcept, NonNeutralCharge);

/// Charge and momentum interpretation for arbitrarily charged particles.
///
/// Only a charge magnitude identical to zero is interpreted as representing a
/// neutral particle. This avoids ambiguities that might arise from using an
/// approximate comparison with an arbitrary epsilon.
class AnyCharge {
public:
/// Delete default constructor to ensure charge is always explicitly given.
AnyCharge() = delete;
/// Construct with the magnitude of the input charge.
template <typename T>
constexpr AnyCharge(T absQ) noexcept : m_magnitude(std::abs(absQ)) {
constexpr AnyCharge(float absQ) noexcept : m_absQ{absQ} {
assert((0 <= absQ) and "Input charge magnitude must be zero or positive");
}
constexpr AnyCharge(SinglyCharged /*unused*/) noexcept
: m_absQ{UnitConstants::e} {}
constexpr AnyCharge(Neutral /*unused*/) noexcept {}

constexpr float absQ() const noexcept { return m_absQ; }

template <typename T>
constexpr T extractCharge(T qOverP) const noexcept {
return std::copysign(static_cast<T>(m_magnitude), qOverP);
constexpr auto extractCharge(T qOverP) const noexcept {
// using because of autodiff
using std::copysign;
return copysign(m_absQ, qOverP);
}
template <typename T>
constexpr T extractMomentum(T qOverP) const noexcept {
return (m_magnitude != 0.0f)
? std::abs(static_cast<T>(m_magnitude) / qOverP)
: std::abs(1 / qOverP);
constexpr auto extractMomentum(T qOverP) const noexcept {
// using because of autodiff
using std::abs;
return (m_absQ != 0.0f) ? extractCharge(qOverP) / qOverP : 1.0f / qOverP;
}

private:
float m_magnitude;
template <typename P, typename Q>
constexpr auto qOverP(P momentum, Q signedQ) const noexcept {
// using because of autodiff
using std::abs;
assert(abs(signedQ) == m_absQ && "inconsistent charge");
return (m_absQ != 0.0f) ? signedQ / momentum : 1.0f / momentum;
}

/// Compare for equality.
friend constexpr bool operator==(AnyCharge lhs, AnyCharge rhs) noexcept {
return lhs.m_magnitude == rhs.m_magnitude;
return lhs.m_absQ == rhs.m_absQ;
}

private:
float m_absQ{};
};

ACTS_STATIC_CHECK_CONCEPT(ChargeConcept, AnyCharge);

/// @}

} // namespace Acts
44 changes: 44 additions & 0 deletions Core/include/Acts/EventData/ChargeConcept.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// This file is part of the Acts project.
//
// Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/.

#pragma once

#include "Acts/Definitions/TrackParametrization.hpp"
#include "Acts/EventData/Types.hpp"
#include "Acts/Surfaces/Surface.hpp"
#include "Acts/Utilities/HashedString.hpp"

#include <any>
#include <type_traits>

#if defined(ACTS_CONCEPTS_SUPPORTED)
#include <concepts>

namespace Acts {

template <typename C>
concept ChargeConcept = requires(C c, float f, double d) {
{C{f}};
{ c.absQ() } -> std::same_as<float>;

{ c.extractCharge(f) } -> std::convertible_to<float>;
{ c.extractCharge(d) } -> std::convertible_to<float>;

{ c.extractMomentum(f) } -> std::convertible_to<float>;
{ c.extractMomentum(d) } -> std::convertible_to<float>;

{ c.qOverP(f, f) } -> std::same_as<float>;
{ c.qOverP(d, d) } -> std::same_as<double>;

{ c == c } -> std::same_as<bool>;
{ c != c } -> std::same_as<bool>;
};

} // namespace Acts

#endif

0 comments on commit a2d0eb5

Please sign in to comment.