Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-13 08:18:28

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
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 /// @brief This adds the classes from Core/Utilities to the python module
0047 /// @param m the pybind11 core module
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   // Add l ogging infrastructure
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& /*exc_type*/, const py::object& /*exc_value*/,
0157                 const py::object& /*traceback*/) {
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     // NOLINTNEXTLINE(performance-unnecessary-value-param)
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   // Add axis related classes
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     // Be able to construct a proto binning
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 }  // namespace ActsPython