Skip to content

Commit

Permalink
feat: Add covfie magnetic field plugin
Browse files Browse the repository at this point in the history
This commit adds a new Acts plugin that adds support for magnetic fields
implemented using the covfie library.

Co-authored-by: Stephen Nicholas Swatman <[email protected]>
  • Loading branch information
fredevb and stephenswat committed Aug 22, 2024
1 parent 5c46e0d commit 4cd2105
Show file tree
Hide file tree
Showing 16 changed files with 695 additions and 3 deletions.
7 changes: 7 additions & 0 deletions Examples/Python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,13 @@ else()
target_sources(ActsPythonBindings PRIVATE src/OnnxNeuralCalibratorStub.cpp)
endif()

if(ACTS_BUILD_PLUGIN_TRACCC)
target_link_libraries(ActsPythonBindings PUBLIC ActsPluginCovfie)
target_sources(ActsPythonBindings PRIVATE src/Covfie.cpp)
else()
target_sources(ActsPythonBindings PRIVATE src/CovfieStub.cpp)
endif()

configure_file(setup.sh.in ${_python_dir}/setup.sh @ONLY)
install(FILES ${_python_dir}/setup.sh DESTINATION "python")

Expand Down
62 changes: 62 additions & 0 deletions Examples/Python/src/Covfie.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// This file is part of the Acts project.
//
// Copyright (C) 2021 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/.

#include "Acts/Plugins/Covfie/FieldConversion.hpp"
#include "Acts/Plugins/Python/Utilities.hpp"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;
using namespace pybind11::literals;

namespace Acts::Python {

namespace {

template <typename field_t>
typename field_t::view_t newView(const field_t& field) {
typename field_t::view_t view(field);
return view;
}

template <typename field_t>
void declareCovfieField(py::module& m, const std::string& fieldName) {
using view_t = typename field_t::view_t;
m.def("newView", static_cast<view_t (*)(const field_t&)>(&newView));
py::class_<field_t, std::shared_ptr<field_t>>(m, fieldName.c_str());
py::class_<view_t, std::shared_ptr<view_t>>(
m, (fieldName + std::string("View")).c_str())
.def("at", &view_t::template at<float, float, float>);
}

} // namespace
void addCovfie(Context& ctx) {
auto main = ctx.get("main");
auto m = main.def_submodule("covfie", "Submodule for covfie conversion");

declareCovfieField<Acts::CovfiePlugin::ConstantField>(m,
"CovfieConstantField");
declareCovfieField<Acts::CovfiePlugin::InterpolatedField>(
m, "CovfieAffineLinearStridedField");

m.def("covfieField",
py::overload_cast<const Acts::InterpolatedMagneticField&>(
&Acts::CovfiePlugin::covfieField));
m.def("covfieField", py::overload_cast<const Acts::ConstantBField&>(
&Acts::CovfiePlugin::covfieField));
m.def(
"covfieField",
py::overload_cast<const Acts::MagneticFieldProvider&,
Acts::MagneticFieldProvider::Cache&,
const std::vector<std::size_t>&,
const std::vector<double>&, const std::vector<double>&>(
&Acts::CovfiePlugin::covfieField));
}

} // namespace Acts::Python
20 changes: 20 additions & 0 deletions Examples/Python/src/CovfieStub.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This file is part of the Acts project.
//
// Copyright (C) 2021 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/.

#include "Acts/Plugins/Python/Utilities.hpp"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;
using namespace pybind11::literals;

namespace Acts::Python {
void addCovfie(Context& /* ctx */) {}

} // namespace Acts::Python
16 changes: 15 additions & 1 deletion Examples/Python/src/MagneticField.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,26 @@ using namespace pybind11::literals;

namespace Acts::Python {

/// @brief Get the field value without needing a cache.
/// @note Does not return an Acts::Result, so will throw an error if the lookup fails.
Acts::Vector3 getField(Acts::MagneticFieldProvider& self,
const Acts::Vector3& position) {
Acts::MagneticFieldContext mctx;
Acts::MagneticFieldProvider::Cache cache = self.makeCache(mctx);
auto lookupResult = self.getField(position, cache);
if (!lookupResult.ok()) {
throw std::runtime_error{"Field lookup failure"};
}
return *lookupResult;
}

void addMagneticField(Context& ctx) {
auto [m, mex, prop] = ctx.get("main", "examples", "propagation");

py::class_<Acts::MagneticFieldProvider,
std::shared_ptr<Acts::MagneticFieldProvider>>(
m, "MagneticFieldProvider");
m, "MagneticFieldProvider")
.def("getField", &getField);

py::class_<Acts::InterpolatedMagneticField,
std::shared_ptr<Acts::InterpolatedMagneticField>>(
Expand Down
2 changes: 2 additions & 0 deletions Examples/Python/src/ModuleEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ void addSvg(Context& ctx);
void addObj(Context& ctx);
void addOnnx(Context& ctx);
void addOnnxNeuralCalibrator(Context& ctx);
void addCovfie(Context& ctx);

} // namespace Acts::Python

Expand Down Expand Up @@ -146,4 +147,5 @@ PYBIND11_MODULE(ActsPythonBindings, m) {
addSvg(ctx);
addOnnx(ctx);
addOnnxNeuralCalibrator(ctx);
addCovfie(ctx);
}
7 changes: 7 additions & 0 deletions Examples/Python/tests/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@
except ImportError:
onnxEnabled = False

try:
import acts.examples.covfie

covfieEnabled = True
except ImportError:
covfieEnabled = False


try:
import acts.examples
Expand Down
60 changes: 60 additions & 0 deletions Examples/Python/tests/test_covfie.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import pathlib, acts, acts.examples
import pytest

from helpers import covfieEnabled


@pytest.mark.skipif(not covfieEnabled, reason="Covfie plugin not available")
def test_constant_field_conversion():
from acts import covfie

v = acts.Vector3(1, 2, 3)
af = acts.ConstantBField(v)
cf = covfie.covfieField(af)
view = covfie.newView(cf)
points = [(0, 0, 1), (1, 1, 1), (1, 0, 2)]
for x, y, z in points:
assert view.at(x, y, z) == [1, 2, 3]


@pytest.mark.skipif(not covfieEnabled, reason="Covfie plugin not available")
def test_root_field_conversion():
from acts import covfie

current_file_path = pathlib.Path(__file__).resolve().parent
p = (
current_file_path.parent.parent.parent
/ "thirdparty"
/ "OpenDataDetector"
/ "data"
/ "odd-bfield.root"
)

af = acts.examples.MagneticFieldMapXyz(str(p))
cf = covfie.covfieField(af)
view = covfie.newView(cf)
points = [
(9300.0, 4700.0, 11200.0),
(9999.0, 9999.0, 14300.0),
(-2900.0, -4700.0, 5200.0),
(-2900.0, -4800.0, 9100.0),
(-2900.0, -5200.0, -8800.0),
(-4400.0, 4800.0, -12700.0),
(-6600.0, 1900.0, 7700.0),
(-9700.0, -900.0, 12700.0),
(-9999.0, -9999.0, -13000.0),
(9999.0, 0, 14900.0),
]

error_margin_half_width = 0.0001
for x, y, z in points:
val = af.getField(acts.Vector3(x, y, z))
Bx1, By1, Bz1 = val[0], val[1], val[2]

Bx2, By2, Bz2 = tuple(view.at(x, y, z))

assert (
abs(Bx1 - Bx2) < error_margin_half_width
and abs(By1 - By2) < error_margin_half_width
and abs(Bz1 - Bz2) < error_margin_half_width
)
1 change: 1 addition & 0 deletions Plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_component_if(Legacy PluginLegacy ACTS_BUILD_PLUGIN_LEGACY)
add_component_if(Onnx PluginOnnx ACTS_BUILD_PLUGIN_ONNX)
add_component_if(ExaTrkX PluginExaTrkX ACTS_BUILD_PLUGIN_EXATRKX)
add_component_if(Detray PluginDetray ACTS_BUILD_PLUGIN_TRACCC)
add_component_if(Covfie PluginCovfie ACTS_BUILD_PLUGIN_TRACCC)

# dependent plugins. depend either on a independent plugins or on one another
add_component_if(TGeo PluginTGeo ACTS_BUILD_PLUGIN_TGEO)
Expand Down
16 changes: 16 additions & 0 deletions Plugins/Covfie/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
add_library(ActsPluginCovfie SHARED src/FieldConversion.cpp)

target_include_directories(
ActsPluginCovfie
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(ActsPluginCovfie PUBLIC ActsCore covfie::core)

install(
TARGETS ActsPluginCovfie
EXPORT ActsPluginCovfieTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(DIRECTORY include/Acts DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
64 changes: 64 additions & 0 deletions Plugins/Covfie/include/Acts/Plugins/Covfie/FieldConversion.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 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 <covfie/core/algebra/affine.hpp>
#include <covfie/core/backend/primitive/array.hpp>
#include <covfie/core/backend/primitive/constant.hpp>
#include <covfie/core/backend/transformer/affine.hpp>
#include <covfie/core/backend/transformer/clamp.hpp>
#include <covfie/core/backend/transformer/linear.hpp>
#include <covfie/core/backend/transformer/strided.hpp>
#include <covfie/core/field.hpp>
#include <covfie/core/field_view.hpp>
#include <covfie/core/parameter_pack.hpp>

// acts includes
#include "Acts/MagneticField/BFieldMapUtils.hpp"
#include "Acts/MagneticField/ConstantBField.hpp"
#include "Acts/MagneticField/MagneticFieldProvider.hpp"

namespace Acts::CovfiePlugin {

using BuilderBackend =
covfie::backend::strided<covfie::vector::size3,
covfie::backend::array<covfie::vector::float3>>;

using InterpolatedField = covfie::field<covfie::backend::clamp<
covfie::backend::affine<covfie::backend::linear<BuilderBackend>>>>;

using ConstantField = covfie::field<
covfie::backend::constant<covfie::vector::float3, covfie::vector::float3>>;

/// @brief Creates a covfie field from an interpolated magnetic field.
/// @param magneticField The acts interpolated magnetic field.
/// @return An affine linear strided covfie field.
InterpolatedField covfieField(
const Acts::InterpolatedMagneticField& magneticField);

/// @brief Creates a covfie field from a constant B field.
/// @param magneticField The acts constant magnetic field.
/// @return A constant covfie field.
ConstantField covfieField(const Acts::ConstantBField& magneticField);

/// @brief Creates a covfie field from a magnetic field provider by sampling it.
/// The field must be defined within min (inclusive) and max (inclusive).
/// @param magneticField The acts magnetic field provider.
/// @param cache The acts cache.
/// @param nBins 3D array of containing the number of bins for each axis.
/// @param min (min_x, min_y, min_z)
/// @param max (max_x, max_y, max_z)
/// @return An affine linear strided covfie field.
InterpolatedField covfieField(const Acts::MagneticFieldProvider& magneticField,
Acts::MagneticFieldProvider::Cache& cache,
const std::vector<std::size_t>& nBins,
const std::vector<double>& min,
const std::vector<double>& max);

} // namespace Acts::CovfiePlugin
Loading

0 comments on commit 4cd2105

Please sign in to comment.