Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-21 08:03:27

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