Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:12:06

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Plugins/Python/Utilities.hpp"
0010 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0011 #include "ActsExamples/Framework/IAlgorithm.hpp"
0012 #include "ActsExamples/Framework/IReader.hpp"
0013 #include "ActsExamples/Framework/IWriter.hpp"
0014 #include "ActsExamples/Framework/ProcessCode.hpp"
0015 #include "ActsExamples/Framework/RandomNumbers.hpp"
0016 #include "ActsExamples/Framework/SequenceElement.hpp"
0017 #include "ActsExamples/Framework/Sequencer.hpp"
0018 #include "ActsExamples/Framework/WhiteBoard.hpp"
0019 
0020 #include <pybind11/pybind11.h>
0021 #include <pybind11/stl.h>
0022 
0023 namespace py = pybind11;
0024 using namespace py::literals;
0025 using namespace ActsExamples;
0026 using namespace Acts::Python;
0027 
0028 namespace {
0029 #if defined(__clang__)
0030 #pragma clang diagnostic push
0031 #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
0032 #endif
0033 class PySequenceElement : public SequenceElement {
0034  public:
0035   using SequenceElement::SequenceElement;
0036 
0037   std::string name() const override {
0038     py::gil_scoped_acquire acquire{};
0039     PYBIND11_OVERRIDE_PURE(std::string, SequenceElement, name);
0040   }
0041 
0042   ProcessCode internalExecute(const AlgorithmContext& ctx) override {
0043     py::gil_scoped_acquire acquire{};
0044     PYBIND11_OVERRIDE_PURE(ProcessCode, SequenceElement, sysExecute, ctx);
0045   }
0046 
0047   ProcessCode initialize() override {
0048     py::gil_scoped_acquire acquire{};
0049     PYBIND11_OVERRIDE_PURE(ProcessCode, SequenceElement, initialize);
0050   }
0051 
0052   ProcessCode finalize() override {
0053     py::gil_scoped_acquire acquire{};
0054     PYBIND11_OVERRIDE_PURE(ProcessCode, SequenceElement, finalize);
0055   }
0056 };
0057 #if defined(__clang__)
0058 #pragma clang diagnostic pop
0059 #endif
0060 
0061 class PyIAlgorithm : public IAlgorithm {
0062  public:
0063   using IAlgorithm::IAlgorithm;
0064 
0065   ProcessCode execute(const AlgorithmContext& ctx) const override {
0066     py::gil_scoped_acquire acquire{};
0067     try {
0068       PYBIND11_OVERRIDE_PURE(ProcessCode, IAlgorithm, execute, ctx);
0069     } catch (py::error_already_set& e) {
0070       throw;  // Error from python, handle in python.
0071     } catch (std::runtime_error& e) {
0072       throw py::type_error("Python algorithm did not conform to interface");
0073     }
0074   }
0075 
0076   std::string_view typeName() const override { return "Algorithm"; }
0077 };
0078 
0079 void trigger_divbyzero() {
0080   volatile float j = 0.0;
0081   volatile float r = 123 / j;  // MARK: divbyzero
0082   (void)r;
0083 }
0084 
0085 void trigger_overflow() {
0086   volatile float j = std::numeric_limits<float>::max();
0087   volatile float r = j * j;  // MARK: overflow
0088   (void)r;
0089 }
0090 
0091 void trigger_invalid() {
0092   volatile float j = -1;
0093   volatile float r = std::sqrt(j);  // MARK: invalid
0094   (void)r;
0095 }
0096 
0097 }  // namespace
0098 
0099 namespace Acts::Python {
0100 void addFramework(Context& ctx) {
0101   auto [m, mex] = ctx.get("main", "examples");
0102 
0103   py::class_<ActsExamples::IWriter, std::shared_ptr<ActsExamples::IWriter>>(
0104       mex, "IWriter");
0105 
0106   py::class_<ActsExamples::IReader, std::shared_ptr<ActsExamples::IReader>>(
0107       mex, "IReader");
0108 
0109   py::enum_<ProcessCode>(mex, "ProcessCode")
0110       .value("SUCCESS", ProcessCode::SUCCESS)
0111       .value("ABORT", ProcessCode::ABORT)
0112       .value("END", ProcessCode::END);
0113 
0114   py::class_<WhiteBoard>(mex, "WhiteBoard")
0115       .def(py::init([](Acts::Logging::Level level, const std::string& name) {
0116              return std::make_unique<WhiteBoard>(
0117                  Acts::getDefaultLogger(name, level));
0118            }),
0119            py::arg("level"), py::arg("name") = "WhiteBoard")
0120       .def("exists", &WhiteBoard::exists)
0121       .def_property_readonly("keys", &WhiteBoard::getKeys);
0122 
0123   py::class_<AlgorithmContext>(mex, "AlgorithmContext")
0124       .def(py::init<std::size_t, std::size_t, WhiteBoard&, std::size_t>(),
0125            "alg"_a, "event"_a, "store"_a, "thread"_a)
0126       .def_readonly("algorithmNumber", &AlgorithmContext::algorithmNumber)
0127       .def_readonly("eventNumber", &AlgorithmContext::eventNumber)
0128       .def_property_readonly("eventStore",
0129                              [](const AlgorithmContext& self) -> WhiteBoard& {
0130                                return self.eventStore;
0131                              })
0132       .def_readonly("threadId", &AlgorithmContext::threadId)
0133       .def_readonly("magFieldContext", &AlgorithmContext::magFieldContext)
0134       .def_readonly("geoContext", &AlgorithmContext::geoContext)
0135       .def_readonly("calibContext", &AlgorithmContext::calibContext)
0136       .def_readwrite("fpeMonitor", &AlgorithmContext::fpeMonitor);
0137 
0138   auto pySequenceElement =
0139       py::class_<ActsExamples::SequenceElement, PySequenceElement,
0140                  std::shared_ptr<ActsExamples::SequenceElement>>(
0141           mex, "SequenceElement")
0142           .def("internalExecute", &SequenceElement::internalExecute)
0143           .def("name", &SequenceElement::name);
0144 
0145   auto bareAlgorithm =
0146       py::class_<ActsExamples::IAlgorithm,
0147                  std::shared_ptr<ActsExamples::IAlgorithm>, SequenceElement,
0148                  PyIAlgorithm>(mex, "IAlgorithm")
0149           .def(py::init_alias<const std::string&, Acts::Logging::Level>(),
0150                py::arg("name"), py::arg("level"))
0151           .def("execute", &IAlgorithm::execute);
0152 
0153   using ActsExamples::Sequencer;
0154   using Config = Sequencer::Config;
0155   auto sequencer =
0156       py::class_<Sequencer>(mex, "_Sequencer")
0157           .def(py::init([](Config cfg) {
0158             cfg.iterationCallback = []() {
0159               py::gil_scoped_acquire gil;
0160               if (PyErr_CheckSignals() != 0) {
0161                 throw py::error_already_set{};
0162               }
0163             };
0164             return std::make_unique<Sequencer>(cfg);
0165           }))
0166           .def("run",
0167                [](Sequencer& self) {
0168                  py::gil_scoped_release gil;
0169                  int res = self.run();
0170                  if (res != EXIT_SUCCESS) {
0171                    throw std::runtime_error{"Sequencer terminated abnormally"};
0172                  }
0173                })
0174           .def("addContextDecorator", &Sequencer::addContextDecorator)
0175           .def("addAlgorithm", &Sequencer::addAlgorithm, py::keep_alive<1, 2>())
0176           .def("addReader", &Sequencer::addReader)
0177           .def("addWriter", &Sequencer::addWriter)
0178           .def("addWhiteboardAlias", &Sequencer::addWhiteboardAlias)
0179           .def_property_readonly("config", &Sequencer::config)
0180           .def_property_readonly("fpeResult", &Sequencer::fpeResult)
0181           .def_property_readonly_static(
0182               "_sourceLocation",
0183               [](py::object /*self*/) { return std::string{__FILE__}; });
0184 
0185   auto c = py::class_<Config>(sequencer, "Config").def(py::init<>());
0186 
0187   ACTS_PYTHON_STRUCT(c, skip, events, logLevel, numThreads, outputDir,
0188                      outputTimingFile, trackFpes, fpeMasks, failOnFirstFpe,
0189                      fpeStackTraceLength);
0190 
0191   auto fpem =
0192       py::class_<Sequencer::FpeMask>(sequencer, "_FpeMask")
0193           .def(py::init<>())
0194           .def(py::init<std::string, std::pair<unsigned int, unsigned int>,
0195                         Acts::FpeType, std::size_t>())
0196           .def("__repr__", [](const Sequencer::FpeMask& self) {
0197             std::stringstream ss;
0198             ss << self;
0199             return ss.str();
0200           });
0201 
0202   ACTS_PYTHON_STRUCT(fpem, file, lines, type, count);
0203 
0204   struct FpeMonitorContext {
0205     std::optional<Acts::FpeMonitor> mon;
0206   };
0207 
0208   auto fpe = py::class_<Acts::FpeMonitor>(m, "FpeMonitor")
0209                  .def_static("_trigger_divbyzero", &trigger_divbyzero)
0210                  .def_static("_trigger_overflow", &trigger_overflow)
0211                  .def_static("_trigger_invalid", &trigger_invalid)
0212                  .def_static("context", []() { return FpeMonitorContext(); });
0213 
0214   fpe.def_property_readonly("result",
0215                             py::overload_cast<>(&Acts::FpeMonitor::result),
0216                             py::return_value_policy::reference_internal)
0217       .def("rearm", &Acts::FpeMonitor::rearm);
0218 
0219   py::class_<Acts::FpeMonitor::Result>(fpe, "Result")
0220       .def("merged", &Acts::FpeMonitor::Result::merged)
0221       .def("merge", &Acts::FpeMonitor::Result::merge)
0222       .def("count", &Acts::FpeMonitor::Result::count)
0223       .def("__str__", [](const Acts::FpeMonitor::Result& result) {
0224         std::stringstream os;
0225         result.summary(os);
0226         return os.str();
0227       });
0228 
0229   py::class_<FpeMonitorContext>(m, "_FpeMonitorContext")
0230       .def(py::init([]() { return std::make_unique<FpeMonitorContext>(); }))
0231       .def(
0232           "__enter__",
0233           [](FpeMonitorContext& fm) -> Acts::FpeMonitor& {
0234             fm.mon.emplace();
0235             return fm.mon.value();
0236           },
0237           py::return_value_policy::reference_internal)
0238       .def("__exit__", [](FpeMonitorContext& fm, py::object /*exc_type*/,
0239                           py::object /*exc_value*/,
0240                           py::object /*traceback*/) { fm.mon.reset(); });
0241 
0242   py::enum_<Acts::FpeType>(m, "FpeType")
0243       .value("INTDIV", Acts::FpeType::INTDIV)
0244       .value("INTOVF", Acts::FpeType::INTOVF)
0245       .value("FLTDIV", Acts::FpeType::FLTDIV)
0246       .value("FLTOVF", Acts::FpeType::FLTOVF)
0247       .value("FLTUND", Acts::FpeType::FLTUND)
0248       .value("FLTRES", Acts::FpeType::FLTRES)
0249       .value("FLTINV", Acts::FpeType::FLTINV)
0250       .value("FLTSUB", Acts::FpeType::FLTSUB)
0251 
0252       .def_property_readonly_static(
0253           "values", [](py::object /*self*/) -> const auto& {
0254             static const std::vector<Acts::FpeType> values = {
0255                 Acts::FpeType::INTDIV, Acts::FpeType::INTOVF,
0256                 Acts::FpeType::FLTDIV, Acts::FpeType::FLTOVF,
0257                 Acts::FpeType::FLTUND, Acts::FpeType::FLTRES,
0258                 Acts::FpeType::FLTINV, Acts::FpeType::FLTSUB};
0259             return values;
0260           });
0261 
0262   py::register_exception<ActsExamples::FpeFailure>(m, "FpeFailure",
0263                                                    PyExc_RuntimeError);
0264 
0265   using ActsExamples::RandomNumbers;
0266   auto randomNumbers =
0267       py::class_<RandomNumbers, std::shared_ptr<RandomNumbers>>(mex,
0268                                                                 "RandomNumbers")
0269           .def(py::init<const RandomNumbers::Config&>());
0270 
0271   py::class_<ActsExamples::RandomEngine>(mex, "RandomEngine").def(py::init<>());
0272 
0273   py::class_<RandomNumbers::Config>(randomNumbers, "Config")
0274       .def(py::init<>())
0275       .def_readwrite("seed", &RandomNumbers::Config::seed);
0276 }
0277 
0278 }  // namespace Acts::Python