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