Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:10:05

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