File indexing completed on 2025-08-05 08:10:04
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Definitions/Algebra.hpp"
0010 #include "Acts/Definitions/PdgParticle.hpp"
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Plugins/Python/Utilities.hpp"
0013 #include "Acts/Utilities/BinningData.hpp"
0014 #include "Acts/Utilities/Logger.hpp"
0015 #include "Acts/Utilities/detail/AxisFwd.hpp"
0016
0017 #include <array>
0018 #include <exception>
0019 #include <memory>
0020 #include <string>
0021 #include <unordered_map>
0022
0023 #include <pybind11/eval.h>
0024 #include <pybind11/pybind11.h>
0025 #include <pybind11/stl.h>
0026
0027 namespace py = pybind11;
0028 using namespace pybind11::literals;
0029
0030 namespace Acts::Python {
0031
0032 void addUnits(Context& ctx) {
0033 auto& m = ctx.get("main");
0034 auto u = m.def_submodule("UnitConstants");
0035
0036 #define UNIT(x) u.attr(#x) = Acts::UnitConstants::x;
0037
0038 UNIT(fm)
0039 UNIT(pm)
0040 UNIT(um)
0041 UNIT(nm)
0042 UNIT(mm)
0043 UNIT(cm)
0044 UNIT(m)
0045 UNIT(km)
0046 UNIT(mm2)
0047 UNIT(cm2)
0048 UNIT(m2)
0049 UNIT(mm3)
0050 UNIT(cm3)
0051 UNIT(m3)
0052 UNIT(s)
0053 UNIT(fs)
0054 UNIT(ps)
0055 UNIT(ns)
0056 UNIT(us)
0057 UNIT(ms)
0058 UNIT(min)
0059 UNIT(h)
0060 UNIT(mrad)
0061 UNIT(rad)
0062 UNIT(degree)
0063 UNIT(eV)
0064 UNIT(keV)
0065 UNIT(MeV)
0066 UNIT(GeV)
0067 UNIT(TeV)
0068 UNIT(J)
0069 UNIT(u)
0070 UNIT(g)
0071 UNIT(kg)
0072 UNIT(e)
0073 UNIT(T)
0074 UNIT(Gauss)
0075 UNIT(kGauss)
0076 UNIT(mol)
0077
0078 #undef UNIT
0079 }
0080
0081 class PythonLogger {
0082 public:
0083 PythonLogger(const std::string& name, Acts::Logging::Level level)
0084 : m_name{name}, m_logger{Acts::getDefaultLogger(m_name, level)} {}
0085
0086 void log(Acts::Logging::Level level, const std::string& message) const {
0087 m_logger->log(level, message);
0088 }
0089
0090 void setLevel(Acts::Logging::Level level) {
0091 m_logger = Acts::getDefaultLogger(m_name, level);
0092 }
0093
0094 private:
0095 std::string m_name;
0096 std::unique_ptr<const Logger> m_logger;
0097 };
0098
0099 void addLogging(Acts::Python::Context& ctx) {
0100 auto& m = ctx.get("main");
0101 auto logging = m.def_submodule("logging", "");
0102
0103 auto levelEnum = py::enum_<Acts::Logging::Level>(logging, "Level")
0104 .value("VERBOSE", Acts::Logging::VERBOSE)
0105 .value("DEBUG", Acts::Logging::DEBUG)
0106 .value("INFO", Acts::Logging::INFO)
0107 .value("WARNING", Acts::Logging::WARNING)
0108 .value("ERROR", Acts::Logging::ERROR)
0109 .value("FATAL", Acts::Logging::FATAL)
0110 .value("MAX", Acts::Logging::MAX)
0111 .export_values();
0112
0113 levelEnum
0114 .def("__lt__", [](Acts::Logging::Level self,
0115 Acts::Logging::Level other) { return self < other; })
0116 .def("__gt__", [](Acts::Logging::Level self,
0117 Acts::Logging::Level other) { return self > other; })
0118 .def("__le__", [](Acts::Logging::Level self,
0119 Acts::Logging::Level other) { return self <= other; })
0120 .def("__ge__", [](Acts::Logging::Level self, Acts::Logging::Level other) {
0121 return self >= other;
0122 });
0123
0124 auto makeLogFunction = [](Acts::Logging::Level level) {
0125 return
0126 [level](PythonLogger& logger, const std::string& fmt, py::args args) {
0127 auto locals = py::dict();
0128 locals["args"] = args;
0129 locals["fmt"] = fmt;
0130 py::exec(R"(
0131 message = fmt % args
0132 )",
0133 py::globals(), locals);
0134
0135 auto message = locals["message"].cast<std::string>();
0136
0137 logger.log(level, message);
0138 };
0139 };
0140
0141 auto logger =
0142 py::class_<PythonLogger, std::shared_ptr<PythonLogger>>(logging, "Logger")
0143 .def("log", &PythonLogger::log)
0144 .def("verbose", makeLogFunction(Acts::Logging::VERBOSE))
0145 .def("debug", makeLogFunction(Acts::Logging::DEBUG))
0146 .def("info", makeLogFunction(Acts::Logging::INFO))
0147 .def("warning", makeLogFunction(Acts::Logging::WARNING))
0148 .def("error", makeLogFunction(Acts::Logging::ERROR))
0149 .def("fatal", makeLogFunction(Acts::Logging::FATAL))
0150 .def("setLevel", &PythonLogger::setLevel);
0151
0152 static std::unordered_map<std::string, std::shared_ptr<PythonLogger>>
0153 pythonLoggers = {{"root", std::make_shared<PythonLogger>(
0154 "Python", Acts::Logging::INFO)}};
0155
0156 logging.def(
0157 "getLogger",
0158 [](const std::string& name) {
0159 if (pythonLoggers.find(name) == pythonLoggers.end()) {
0160 pythonLoggers[name] =
0161 std::make_shared<PythonLogger>(name, Acts::Logging::INFO);
0162 }
0163 return pythonLoggers[name];
0164 },
0165 py::arg("name") = "root");
0166
0167 logging.def("setLevel", [](Acts::Logging::Level level) {
0168 pythonLoggers.at("root")->setLevel(level);
0169 });
0170
0171 auto makeModuleLogFunction = [](Acts::Logging::Level level) {
0172 return [level](const std::string& fmt, py::args args) {
0173 auto locals = py::dict();
0174 locals["args"] = args;
0175 locals["fmt"] = fmt;
0176 py::exec(R"(
0177 message = fmt % args
0178 )",
0179 py::globals(), locals);
0180
0181 auto message = locals["message"].cast<std::string>();
0182
0183 pythonLoggers.at("root")->log(level, message);
0184 };
0185 };
0186
0187 logging.def("setFailureThreshold", &Logging::setFailureThreshold);
0188 logging.def("getFailureThreshold", &Logging::getFailureThreshold);
0189
0190 static py::exception<Logging::ThresholdFailure> exc(
0191 logging, "ThresholdFailure", PyExc_RuntimeError);
0192
0193 py::register_exception_translator([](std::exception_ptr p) {
0194 try {
0195 if (p) {
0196 std::rethrow_exception(p);
0197 }
0198 } catch (const std::exception& e) {
0199 std::string what = e.what();
0200 if (what.find("ACTS_LOG_FAILURE_THRESHOLD") != std::string::npos) {
0201 exc(e.what());
0202 } else {
0203 std::rethrow_exception(p);
0204 }
0205 }
0206 });
0207
0208 logging.def("verbose", makeModuleLogFunction(Acts::Logging::VERBOSE));
0209 logging.def("debug", makeModuleLogFunction(Acts::Logging::DEBUG));
0210 logging.def("info", makeModuleLogFunction(Acts::Logging::INFO));
0211 logging.def("warning", makeModuleLogFunction(Acts::Logging::WARNING));
0212 logging.def("error", makeModuleLogFunction(Acts::Logging::ERROR));
0213 logging.def("fatal", makeModuleLogFunction(Acts::Logging::FATAL));
0214 }
0215
0216 void addPdgParticle(Acts::Python::Context& ctx) {
0217 auto& m = ctx.get("main");
0218 py::enum_<Acts::PdgParticle>(m, "PdgParticle")
0219 .value("eInvalid", Acts::PdgParticle::eInvalid)
0220 .value("eElectron", Acts::PdgParticle::eElectron)
0221 .value("eAntiElectron", Acts::PdgParticle::eAntiElectron)
0222 .value("ePositron", Acts::PdgParticle::ePositron)
0223 .value("eMuon", Acts::PdgParticle::eMuon)
0224 .value("eAntiMuon", Acts::PdgParticle::eAntiMuon)
0225 .value("eTau", Acts::PdgParticle::eTau)
0226 .value("eAntiTau", Acts::PdgParticle::eAntiTau)
0227 .value("eGamma", Acts::PdgParticle::eGamma)
0228 .value("ePionZero", Acts::PdgParticle::ePionZero)
0229 .value("ePionPlus", Acts::PdgParticle::ePionPlus)
0230 .value("ePionMinus", Acts::PdgParticle::ePionMinus)
0231 .value("eKaonPlus", Acts::PdgParticle::eKaonPlus)
0232 .value("eKaonMinus", Acts::PdgParticle::eKaonMinus)
0233 .value("eNeutron", Acts::PdgParticle::eNeutron)
0234 .value("eAntiNeutron", Acts::PdgParticle::eAntiNeutron)
0235 .value("eProton", Acts::PdgParticle::eProton)
0236 .value("eAntiProton", Acts::PdgParticle::eAntiProton)
0237 .value("eLead", Acts::PdgParticle::eLead);
0238 }
0239
0240 void addAlgebra(Acts::Python::Context& ctx) {
0241 auto& m = ctx.get("main");
0242
0243 py::class_<Acts::Vector2>(m, "Vector2")
0244 .def(py::init<double, double>())
0245 .def(py::init([](std::array<double, 2> a) {
0246 Acts::Vector2 v;
0247 v << a[0], a[1];
0248 return v;
0249 }))
0250 .def("__getitem__",
0251 [](const Acts::Vector2& self, Eigen::Index i) { return self[i]; });
0252
0253 py::class_<Acts::Vector3>(m, "Vector3")
0254 .def(py::init<double, double, double>())
0255 .def(py::init([](std::array<double, 3> a) {
0256 Acts::Vector3 v;
0257 v << a[0], a[1], a[2];
0258 return v;
0259 }))
0260 .def("__getitem__",
0261 [](const Acts::Vector3& self, Eigen::Index i) { return self[i]; });
0262
0263 py::class_<Acts::Vector4>(m, "Vector4")
0264 .def(py::init<double, double, double, double>())
0265 .def(py::init([](std::array<double, 4> a) {
0266 Acts::Vector4 v;
0267 v << a[0], a[1], a[2], a[3];
0268 return v;
0269 }))
0270 .def("__getitem__",
0271 [](const Acts::Vector4& self, Eigen::Index i) { return self[i]; });
0272
0273 py::class_<Acts::Transform3>(m, "Transform3")
0274 .def(py::init([](std::array<double, 3> translation) {
0275 Acts::Transform3 t = Acts::Transform3::Identity();
0276 t.pretranslate(
0277 Acts::Vector3(translation[0], translation[1], translation[2]));
0278 return t;
0279 }))
0280 .def("getTranslation", [](const Acts::Transform3& self) {
0281 return Vector3(self.translation());
0282 });
0283 }
0284
0285 void addBinning(Context& ctx) {
0286 auto& m = ctx.get("main");
0287 auto binning = m.def_submodule("Binning", "");
0288
0289 auto binningValue = py::enum_<Acts::BinningValue>(binning, "BinningValue")
0290 .value("x", Acts::BinningValue::binX)
0291 .value("y", Acts::BinningValue::binY)
0292 .value("z", Acts::BinningValue::binZ)
0293 .value("r", Acts::BinningValue::binR)
0294 .value("phi", Acts::BinningValue::binPhi)
0295 .export_values();
0296
0297 auto boundaryType =
0298 py::enum_<Acts::detail::AxisBoundaryType>(binning, "AxisBoundaryType")
0299 .value("bound", Acts::detail::AxisBoundaryType::Bound)
0300 .value("closed", Acts::detail::AxisBoundaryType::Closed)
0301 .value("open", Acts::detail::AxisBoundaryType::Open)
0302 .export_values();
0303
0304 auto axisType = py::enum_<Acts::detail::AxisType>(binning, "AxisType")
0305 .value("equidistant", Acts::detail::AxisType::Equidistant)
0306 .value("variable", Acts::detail::AxisType::Variable)
0307 .export_values();
0308 }
0309
0310 }