File indexing completed on 2025-01-18 09:12:02
0001
0002
0003
0004
0005
0006
0007
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;
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;
0079 (void)r;
0080 }
0081
0082 void trigger_overflow() {
0083 volatile float j = std::numeric_limits<float>::max();
0084 volatile float r = j * j;
0085 (void)r;
0086 }
0087
0088 void trigger_invalid() {
0089 volatile float j = -1;
0090 volatile float r = std::sqrt(j);
0091 (void)r;
0092 }
0093
0094 }
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_<AlgorithmContext>(mex, "AlgorithmContext")
0120 .def(py::init<std::size_t, std::size_t, WhiteBoard&>())
0121 .def_readonly("algorithmNumber", &AlgorithmContext::algorithmNumber)
0122 .def_readonly("eventNumber", &AlgorithmContext::eventNumber)
0123 .def_property_readonly("eventStore",
0124 [](const AlgorithmContext& self) -> WhiteBoard& {
0125 return self.eventStore;
0126 })
0127 .def_readonly("magFieldContext", &AlgorithmContext::magFieldContext)
0128 .def_readonly("geoContext", &AlgorithmContext::geoContext)
0129 .def_readonly("calibContext", &AlgorithmContext::calibContext)
0130 .def_readwrite("fpeMonitor", &AlgorithmContext::fpeMonitor);
0131
0132 auto pySequenceElement =
0133 py::class_<ActsExamples::SequenceElement, PySequenceElement,
0134 std::shared_ptr<ActsExamples::SequenceElement>>(
0135 mex, "SequenceElement")
0136 .def(py::init_alias<>())
0137 .def("internalExecute", &SequenceElement::internalExecute)
0138 .def("name", &SequenceElement::name);
0139
0140 auto bareAlgorithm =
0141 py::class_<ActsExamples::IAlgorithm,
0142 std::shared_ptr<ActsExamples::IAlgorithm>, SequenceElement,
0143 PyIAlgorithm>(mex, "IAlgorithm")
0144 .def(py::init_alias<const std::string&, Acts::Logging::Level>(),
0145 py::arg("name"), py::arg("level"))
0146 .def("execute", &IAlgorithm::execute);
0147
0148 using ActsExamples::Sequencer;
0149 using Config = Sequencer::Config;
0150 auto sequencer =
0151 py::class_<Sequencer>(mex, "_Sequencer")
0152 .def(py::init([](Config cfg) {
0153 cfg.iterationCallback = []() {
0154 py::gil_scoped_acquire gil;
0155 if (PyErr_CheckSignals() != 0) {
0156 throw py::error_already_set{};
0157 }
0158 };
0159 return std::make_unique<Sequencer>(cfg);
0160 }))
0161 .def("run",
0162 [](Sequencer& self) {
0163 py::gil_scoped_release gil;
0164 int res = self.run();
0165 if (res != EXIT_SUCCESS) {
0166 throw std::runtime_error{"Sequencer terminated abnormally"};
0167 }
0168 })
0169 .def("addContextDecorator", &Sequencer::addContextDecorator)
0170 .def("addAlgorithm", &Sequencer::addAlgorithm, py::keep_alive<1, 2>())
0171 .def("addReader", &Sequencer::addReader)
0172 .def("addWriter", &Sequencer::addWriter)
0173 .def("addWhiteboardAlias", &Sequencer::addWhiteboardAlias)
0174 .def_property_readonly("config", &Sequencer::config)
0175 .def_property_readonly("fpeResult", &Sequencer::fpeResult)
0176 .def_property_readonly_static(
0177 "_sourceLocation",
0178 [](py::object ) { return std::string{__FILE__}; });
0179
0180 auto c = py::class_<Config>(sequencer, "Config").def(py::init<>());
0181
0182 ACTS_PYTHON_STRUCT_BEGIN(c, Config);
0183 ACTS_PYTHON_MEMBER(skip);
0184 ACTS_PYTHON_MEMBER(events);
0185 ACTS_PYTHON_MEMBER(logLevel);
0186 ACTS_PYTHON_MEMBER(numThreads);
0187 ACTS_PYTHON_MEMBER(outputDir);
0188 ACTS_PYTHON_MEMBER(outputTimingFile);
0189 ACTS_PYTHON_MEMBER(trackFpes);
0190 ACTS_PYTHON_MEMBER(fpeMasks);
0191 ACTS_PYTHON_MEMBER(failOnFirstFpe);
0192 ACTS_PYTHON_MEMBER(fpeStackTraceLength);
0193 ACTS_PYTHON_STRUCT_END();
0194
0195 auto fpem =
0196 py::class_<Sequencer::FpeMask>(sequencer, "_FpeMask")
0197 .def(py::init<>())
0198 .def(py::init<std::string, std::pair<unsigned int, unsigned int>,
0199 Acts::FpeType, std::size_t>())
0200 .def("__repr__", [](const Sequencer::FpeMask& self) {
0201 std::stringstream ss;
0202 ss << self;
0203 return ss.str();
0204 });
0205
0206 ACTS_PYTHON_STRUCT_BEGIN(fpem, Sequencer::FpeMask);
0207 ACTS_PYTHON_MEMBER(file);
0208 ACTS_PYTHON_MEMBER(lines);
0209 ACTS_PYTHON_MEMBER(type);
0210 ACTS_PYTHON_MEMBER(count);
0211 ACTS_PYTHON_STRUCT_END();
0212
0213 struct FpeMonitorContext {
0214 std::optional<Acts::FpeMonitor> mon;
0215 };
0216
0217 auto fpe = py::class_<Acts::FpeMonitor>(m, "FpeMonitor")
0218 .def_static("_trigger_divbyzero", &trigger_divbyzero)
0219 .def_static("_trigger_overflow", &trigger_overflow)
0220 .def_static("_trigger_invalid", &trigger_invalid)
0221 .def_static("context", []() { return FpeMonitorContext(); });
0222
0223 fpe.def_property_readonly("result",
0224 py::overload_cast<>(&Acts::FpeMonitor::result),
0225 py::return_value_policy::reference_internal)
0226 .def("rearm", &Acts::FpeMonitor::rearm);
0227
0228 py::class_<Acts::FpeMonitor::Result>(fpe, "Result")
0229 .def("merged", &Acts::FpeMonitor::Result::merged)
0230 .def("merge", &Acts::FpeMonitor::Result::merge)
0231 .def("count", &Acts::FpeMonitor::Result::count)
0232 .def("__str__", [](const Acts::FpeMonitor::Result& result) {
0233 std::stringstream os;
0234 result.summary(os);
0235 return os.str();
0236 });
0237
0238 py::class_<FpeMonitorContext>(m, "_FpeMonitorContext")
0239 .def(py::init([]() { return std::make_unique<FpeMonitorContext>(); }))
0240 .def(
0241 "__enter__",
0242 [](FpeMonitorContext& fm) -> Acts::FpeMonitor& {
0243 fm.mon.emplace();
0244 return fm.mon.value();
0245 },
0246 py::return_value_policy::reference_internal)
0247 .def("__exit__", [](FpeMonitorContext& fm, py::object ,
0248 py::object ,
0249 py::object ) { fm.mon.reset(); });
0250
0251 py::enum_<Acts::FpeType>(m, "FpeType")
0252 .value("INTDIV", Acts::FpeType::INTDIV)
0253 .value("INTOVF", Acts::FpeType::INTOVF)
0254 .value("FLTDIV", Acts::FpeType::FLTDIV)
0255 .value("FLTOVF", Acts::FpeType::FLTOVF)
0256 .value("FLTUND", Acts::FpeType::FLTUND)
0257 .value("FLTRES", Acts::FpeType::FLTRES)
0258 .value("FLTINV", Acts::FpeType::FLTINV)
0259 .value("FLTSUB", Acts::FpeType::FLTSUB)
0260
0261 .def_property_readonly_static(
0262 "values", [](py::object ) -> const auto& {
0263 static const std::vector<Acts::FpeType> values = {
0264 Acts::FpeType::INTDIV, Acts::FpeType::INTOVF,
0265 Acts::FpeType::FLTDIV, Acts::FpeType::FLTOVF,
0266 Acts::FpeType::FLTUND, Acts::FpeType::FLTRES,
0267 Acts::FpeType::FLTINV, Acts::FpeType::FLTSUB};
0268 return values;
0269 });
0270
0271 py::register_exception<ActsExamples::FpeFailure>(m, "FpeFailure",
0272 PyExc_RuntimeError);
0273
0274 using ActsExamples::RandomNumbers;
0275 auto randomNumbers =
0276 py::class_<RandomNumbers, std::shared_ptr<RandomNumbers>>(mex,
0277 "RandomNumbers")
0278 .def(py::init<const RandomNumbers::Config&>());
0279
0280 py::class_<ActsExamples::RandomEngine>(mex, "RandomEngine").def(py::init<>());
0281
0282 py::class_<RandomNumbers::Config>(randomNumbers, "Config")
0283 .def(py::init<>())
0284 .def_readwrite("seed", &RandomNumbers::Config::seed);
0285 }
0286
0287 }