SHiP Field Service
Framework-agnostic C++20 library exposing SHiP magnetic field maps.
Loading...
Searching...
No Matches
ActsFieldAdapter.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 CERN for the benefit of the SHiP Collaboration
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4#pragma once
5
7
8#include <Acts/Definitions/Algebra.hpp>
9#include <Acts/Definitions/Units.hpp>
10#include <Acts/MagneticField/MagneticFieldContext.hpp>
11#include <Acts/MagneticField/MagneticFieldError.hpp>
12#include <Acts/MagneticField/MagneticFieldProvider.hpp>
13#include <Acts/Utilities/Result.hpp>
14#include <SHiP/Units.hpp>
15#include <array>
16#include <atomic>
17#include <cmath>
18#include <exception>
19#include <functional>
20#include <memory>
21#include <stdexcept>
22#include <string_view>
23#include <utility>
24
25namespace SHiP {
26
36class ActsFieldAdapter final : public Acts::MagneticFieldProvider {
37 public:
38 using ErrorHandler = std::function<void(std::string_view)>;
39
40 explicit ActsFieldAdapter(std::shared_ptr<IFieldEvaluator> eval, ErrorHandler on_error = {})
41 : eval_{std::move(eval)}, on_error_{std::move(on_error)} {
42 if (!eval_) {
43 throw std::invalid_argument("ActsFieldAdapter: null field evaluator");
44 }
45 }
46
47 [[nodiscard]] Cache makeCache(Acts::MagneticFieldContext const& /*mctx*/) const override {
48 return Cache{Empty{}};
49 }
50
51 [[nodiscard]] Acts::Result<Acts::Vector3> getField(Acts::Vector3 const& position,
52 Cache& /*cache*/) const override {
53 using Result = Acts::Result<Acts::Vector3>;
54 namespace si = mp_units::si;
55 if (!position.allFinite()) {
56 return fail("non-finite position queried");
57 }
58
59 std::array<IFieldEvaluator::field_q, 3> B{};
60 try {
61 B = eval_->at((position[0] / Acts::UnitConstants::mm) * si::milli<si::metre>,
62 (position[1] / Acts::UnitConstants::mm) * si::milli<si::metre>,
63 (position[2] / Acts::UnitConstants::mm) * si::milli<si::metre>);
64 } catch (std::exception const& e) {
65 return fail(e.what());
66 } catch (...) {
67 return fail("unknown exception from evaluator");
68 }
69
70 Acts::Vector3 const field{B[0].numerical_value_in(si::tesla) * Acts::UnitConstants::T,
71 B[1].numerical_value_in(si::tesla) * Acts::UnitConstants::T,
72 B[2].numerical_value_in(si::tesla) * Acts::UnitConstants::T};
73 if (!field.allFinite()) {
74 return fail("non-finite field value from evaluator");
75 }
76 return Result::success(field);
77 }
78
79 private:
80 struct Empty {};
81
82 [[nodiscard]] Acts::Result<Acts::Vector3> fail(std::string_view what) const {
83 if (on_error_ && !reported_.exchange(true)) {
84 on_error_(what);
85 }
86 return Acts::Result<Acts::Vector3>::failure(Acts::MagneticFieldError::OutOfBounds);
87 }
88
89 std::shared_ptr<IFieldEvaluator> eval_;
90 ErrorHandler on_error_;
91 mutable std::atomic<bool> reported_{false};
92};
93
94} // namespace SHiP
Acts::MagneticFieldProvider wrapping an IFieldEvaluator, the ACTS counterpart of G4MagFieldAdapter.
Definition ActsFieldAdapter.h:36
Cache makeCache(Acts::MagneticFieldContext const &) const override
Definition ActsFieldAdapter.h:47
Acts::Result< Acts::Vector3 > getField(Acts::Vector3 const &position, Cache &) const override
Definition ActsFieldAdapter.h:51
std::function< void(std::string_view)> ErrorHandler
Definition ActsFieldAdapter.h:38
ActsFieldAdapter(std::shared_ptr< IFieldEvaluator > eval, ErrorHandler on_error={})
Definition ActsFieldAdapter.h:40
Definition ActsFieldAdapter.h:25