Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:21:37

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 #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 /// @brief This adds the classes from Core/Utilities to the python module
0048 /// @param m the pybind11 core module
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   // Add l ogging infrastructure
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& /*exc_type*/, const py::object& /*exc_value*/,
0158                 const py::object& /*traceback*/) {
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     // NOLINTNEXTLINE(performance-unnecessary-value-param)
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   // Add axis related classes
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     // Be able to construct a proto binning
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 }  // namespace ActsPython