File indexing completed on 2025-10-13 08:18:28
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Utilities/Any.hpp"
0010 #include "Acts/Utilities/AxisDefinitions.hpp"
0011 #include "Acts/Utilities/BinningData.hpp"
0012 #include "Acts/Utilities/CalibrationContext.hpp"
0013 #include "Acts/Utilities/Logger.hpp"
0014
0015 #include <type_traits>
0016
0017 #include <pybind11/eval.h>
0018 #include <pybind11/pybind11.h>
0019 #include <pybind11/stl.h>
0020
0021 namespace py = pybind11;
0022 using namespace pybind11::literals;
0023
0024 using namespace Acts;
0025
0026 namespace ActsPython {
0027
0028 class PythonLogger {
0029 public:
0030 PythonLogger(const std::string& name, Logging::Level level)
0031 : m_name{name}, m_logger{getDefaultLogger(m_name, level)} {}
0032
0033 void log(Logging::Level level, const std::string& message) const {
0034 m_logger->log(level, message);
0035 }
0036
0037 void setLevel(Logging::Level level) {
0038 m_logger = getDefaultLogger(m_name, level);
0039 }
0040
0041 private:
0042 std::string m_name;
0043 std::unique_ptr<const Logger> m_logger;
0044 };
0045
0046
0047
0048 void addUtilities(py::module_& m) {
0049 { py::class_<AnyBase<512>>(m, "AnyBase512").def(py::init<>()); }
0050
0051 { py::class_<CalibrationContext>(m, "CalibrationContext").def(py::init<>()); }
0052
0053
0054 {
0055 auto logging = m.def_submodule("logging", "");
0056
0057 auto levelEnum = py::enum_<Logging::Level>(logging, "Level")
0058 .value("VERBOSE", Logging::VERBOSE)
0059 .value("DEBUG", Logging::DEBUG)
0060 .value("INFO", Logging::INFO)
0061 .value("WARNING", Logging::WARNING)
0062 .value("ERROR", Logging::ERROR)
0063 .value("FATAL", Logging::FATAL)
0064 .value("MAX", Logging::MAX)
0065 .export_values();
0066
0067 levelEnum
0068 .def("__lt__", [](Logging::Level self,
0069 Logging::Level other) { return self < other; })
0070 .def("__gt__", [](Logging::Level self,
0071 Logging::Level other) { return self > other; })
0072 .def("__le__", [](Logging::Level self,
0073 Logging::Level other) { return self <= other; })
0074 .def("__ge__", [](Logging::Level self, Logging::Level other) {
0075 return self >= other;
0076 });
0077
0078 auto makeLogFunction = [](Logging::Level level) {
0079 return
0080 [level](PythonLogger& logger, const std::string& fmt, py::args args) {
0081 auto locals = py::dict();
0082 locals["args"] = args;
0083 locals["fmt"] = fmt;
0084 py::exec(R"(
0085 message = fmt % args
0086 )",
0087 py::globals(), locals);
0088
0089 auto message = locals["message"].cast<std::string>();
0090
0091 logger.log(level, message);
0092 };
0093 };
0094
0095 py::class_<Logger>(m, "Logger");
0096
0097 auto logger = py::class_<PythonLogger, std::shared_ptr<PythonLogger>>(
0098 logging, "Logger")
0099 .def("log", &PythonLogger::log)
0100 .def("verbose", makeLogFunction(Logging::VERBOSE))
0101 .def("debug", makeLogFunction(Logging::DEBUG))
0102 .def("info", makeLogFunction(Logging::INFO))
0103 .def("warning", makeLogFunction(Logging::WARNING))
0104 .def("error", makeLogFunction(Logging::ERROR))
0105 .def("fatal", makeLogFunction(Logging::FATAL))
0106 .def("setLevel", &PythonLogger::setLevel);
0107
0108 static std::unordered_map<std::string, std::shared_ptr<PythonLogger>>
0109 pythonLoggers = {
0110 {"root", std::make_shared<PythonLogger>("Python", Logging::INFO)}};
0111
0112 logging.def(
0113 "getLogger",
0114 [](const std::string& name) {
0115 if (!pythonLoggers.contains(name)) {
0116 pythonLoggers[name] =
0117 std::make_shared<PythonLogger>(name, Logging::INFO);
0118 }
0119 return pythonLoggers[name];
0120 },
0121 py::arg("name") = "root");
0122
0123 logging.def("setLevel", [](Logging::Level level) {
0124 pythonLoggers.at("root")->setLevel(level);
0125 });
0126
0127 auto makeModuleLogFunction = [](Logging::Level level) {
0128 return [level](const std::string& fmt, py::args args) {
0129 auto locals = py::dict();
0130 locals["args"] = args;
0131 locals["fmt"] = fmt;
0132 py::exec(R"(
0133 message = fmt % args
0134 )",
0135 py::globals(), locals);
0136
0137 auto message = locals["message"].cast<std::string>();
0138
0139 pythonLoggers.at("root")->log(level, message);
0140 };
0141 };
0142
0143 logging.def("setFailureThreshold", &Logging::setFailureThreshold);
0144 logging.def("getFailureThreshold", &Logging::getFailureThreshold);
0145
0146 struct ScopedFailureThresholdContextManager {
0147 std::optional<Logging::ScopedFailureThreshold> m_scopedFailureThreshold =
0148 std::nullopt;
0149 Logging::Level m_level;
0150
0151 explicit ScopedFailureThresholdContextManager(Logging::Level level)
0152 : m_level(level) {}
0153
0154 void enter() { m_scopedFailureThreshold.emplace(m_level); }
0155
0156 void exit(const py::object& , const py::object& ,
0157 const py::object& ) {
0158 m_scopedFailureThreshold.reset();
0159 }
0160 };
0161
0162 py::class_<ScopedFailureThresholdContextManager>(logging,
0163 "ScopedFailureThreshold")
0164 .def(py::init<Logging::Level>(), "level"_a)
0165 .def("__enter__", &ScopedFailureThresholdContextManager::enter)
0166 .def("__exit__", &ScopedFailureThresholdContextManager::exit);
0167
0168 static py::exception<Logging::ThresholdFailure> exc(
0169 logging, "ThresholdFailure", PyExc_RuntimeError);
0170
0171 py::register_exception_translator([](std::exception_ptr p) {
0172 try {
0173 if (p) {
0174 std::rethrow_exception(p);
0175 }
0176 } catch (const std::exception& e) {
0177 std::string what = e.what();
0178 if (what.find("ACTS_LOG_FAILURE_THRESHOLD") != std::string::npos) {
0179 py::set_error(exc, e.what());
0180 } else {
0181 std::rethrow_exception(p);
0182 }
0183 }
0184 });
0185
0186 logging.def("verbose", makeModuleLogFunction(Logging::VERBOSE));
0187 logging.def("debug", makeModuleLogFunction(Logging::DEBUG));
0188 logging.def("info", makeModuleLogFunction(Logging::INFO));
0189 logging.def("warning", makeModuleLogFunction(Logging::WARNING));
0190 logging.def("error", makeModuleLogFunction(Logging::ERROR));
0191 logging.def("fatal", makeModuleLogFunction(Logging::FATAL));
0192 }
0193
0194
0195 {
0196 auto binningValue = py::enum_<AxisDirection>(m, "AxisDirection")
0197 .value("AxisX", AxisDirection::AxisX)
0198 .value("AxisY", AxisDirection::AxisY)
0199 .value("AxisZ", AxisDirection::AxisZ)
0200 .value("AxisR", AxisDirection::AxisR)
0201 .value("AxisPhi", AxisDirection::AxisPhi)
0202 .value("AxisRPhi", AxisDirection::AxisRPhi)
0203 .value("AxisTheta", AxisDirection::AxisTheta)
0204 .value("AxisEta", AxisDirection::AxisEta)
0205 .value("AxisMag", AxisDirection::AxisMag);
0206
0207 auto boundaryType = py::enum_<AxisBoundaryType>(m, "AxisBoundaryType")
0208 .value("Bound", AxisBoundaryType::Bound)
0209 .value("Closed", AxisBoundaryType::Closed)
0210 .value("Open", AxisBoundaryType::Open);
0211
0212 auto axisType = py::enum_<AxisType>(m, "AxisType")
0213 .value("equidistant", AxisType::Equidistant)
0214 .value("variable", AxisType::Variable);
0215 }
0216
0217 {
0218
0219 py::class_<ProtoAxis>(m, "ProtoAxis")
0220 .def(py::init<AxisBoundaryType, const std::vector<double>&>(),
0221 "bType"_a, "e"_a)
0222 .def(py::init<AxisBoundaryType, double, double, std::size_t>(),
0223 "bType"_a, "minE"_a, "maxE"_a, "nbins"_a)
0224 .def(py::init<AxisBoundaryType, std::size_t>(), "bType"_a, "nbins"_a);
0225
0226 py::class_<DirectedProtoAxis>(m, "DirectedProtoAxis")
0227 .def(py::init<AxisDirection, AxisBoundaryType,
0228 const std::vector<double>&>(),
0229 "bValue"_a, "bType"_a, "e"_a)
0230 .def(py::init<AxisDirection, AxisBoundaryType, double, double,
0231 std::size_t>(),
0232 "bValue"_a, "bType"_a, "minE"_a, "maxE"_a, "nbins"_a)
0233 .def(py::init<AxisDirection, AxisBoundaryType, std::size_t>(),
0234 "bValue"_a, "bType"_a, "nbins"_a);
0235 }
0236 }
0237
0238 }