mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-11 04:17:15 +02:00
Nanosecond times in Python (#522)
* initital implementation * datetime replaces with sls::Duration in Python C bindings * using custom type caster * fix for conversion to seconds * added set_count in python * common header for pybind11 includes authored-by: Erik Frojdh <erik.frojdh@psi.ch>
This commit is contained in:
26
python/src/DurationWrapper.cpp
Normal file
26
python/src/DurationWrapper.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "DurationWrapper.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace sls{
|
||||
|
||||
DurationWrapper::DurationWrapper(double seconds){
|
||||
ns_tick = std::round(seconds*1e9);
|
||||
}
|
||||
|
||||
uint64_t DurationWrapper::count() const{
|
||||
return ns_tick;
|
||||
}
|
||||
|
||||
void DurationWrapper::set_count(uint64_t ns_count){
|
||||
ns_tick = ns_count;
|
||||
}
|
||||
|
||||
bool DurationWrapper::operator==(const DurationWrapper& other)const{
|
||||
return ns_tick == other.ns_tick;
|
||||
}
|
||||
|
||||
double DurationWrapper::total_seconds()const{
|
||||
return static_cast<double>(ns_tick)/1e9;
|
||||
}
|
||||
|
||||
}
|
26
python/src/DurationWrapper.h
Normal file
26
python/src/DurationWrapper.h
Normal file
@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace sls{
|
||||
/*
|
||||
Wrapper for nanoseconds stored in uint64_t, used for conversion between
|
||||
std::chrono::nanoseconds and python (float or sls::DurationWrapper)
|
||||
*/
|
||||
|
||||
class DurationWrapper{
|
||||
uint64_t ns_tick{0};
|
||||
|
||||
public:
|
||||
DurationWrapper() = default;
|
||||
explicit DurationWrapper(double seconds);
|
||||
~DurationWrapper() = default;
|
||||
|
||||
bool operator==(const DurationWrapper& other) const;
|
||||
uint64_t count() const;
|
||||
void set_count(uint64_t count);
|
||||
double total_seconds() const;
|
||||
};
|
||||
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include <pybind11/chrono.h>
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
// #include "sls/Pattern.h"
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,13 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include <pybind11/chrono.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "typecaster.h"
|
||||
|
||||
#include "sls/TimeHelper.h"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
namespace py = pybind11;
|
||||
@ -23,7 +19,7 @@ void init_det(py::module &m) {
|
||||
using sls::Result;
|
||||
|
||||
py::class_<Detector> CppDetectorApi(m, "CppDetectorApi");
|
||||
CppDetectorApi.def(py::init<int>())
|
||||
CppDetectorApi.def(py::init<int>());
|
||||
|
||||
[[FUNCTIONS]]
|
||||
}
|
||||
|
21
python/src/duration.cpp
Normal file
21
python/src/duration.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "DurationWrapper.h"
|
||||
#include <sstream>
|
||||
namespace py = pybind11;
|
||||
using sls::DurationWrapper;
|
||||
|
||||
void init_duration(py::module &m) {
|
||||
py::class_<DurationWrapper>(m, "DurationWrapper")
|
||||
.def(py::init())
|
||||
.def(py::init<double>())
|
||||
.def("total_seconds", &DurationWrapper::total_seconds)
|
||||
.def("count", &DurationWrapper::count)
|
||||
.def("set_count", &DurationWrapper::set_count)
|
||||
.def("__repr__", [](const DurationWrapper &self) {
|
||||
std::stringstream ss;
|
||||
ss << "sls::DurationWrapper(total_seconds: " << self.total_seconds()
|
||||
<< " count: " << self.count() << ")";
|
||||
return ss.str();
|
||||
});
|
||||
}
|
@ -3,11 +3,7 @@
|
||||
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include <pybind11/chrono.h>
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "sls/Pattern.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
@ -1,10 +1,6 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include <pybind11/chrono.h>
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "sls/Pattern.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
@ -1,9 +1,6 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include <pybind11/chrono.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "mythenFileIO.h"
|
||||
#include "sls/Detector.h"
|
||||
@ -11,8 +8,6 @@
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
|
||||
#include "typecaster.h"
|
||||
|
||||
using ds = std::chrono::duration<double>;
|
||||
|
||||
namespace py = pybind11;
|
||||
@ -23,6 +18,7 @@ void init_network(py::module &);
|
||||
void init_pattern(py::module &);
|
||||
void init_scan(py::module &);
|
||||
void init_source(py::module &);
|
||||
void init_duration(py::module &);
|
||||
PYBIND11_MODULE(_slsdet, m) {
|
||||
m.doc() = R"pbdoc(
|
||||
C/C++ API
|
||||
@ -40,6 +36,7 @@ PYBIND11_MODULE(_slsdet, m) {
|
||||
init_pattern(m);
|
||||
init_scan(m);
|
||||
init_source(m);
|
||||
init_duration(m);
|
||||
// init_experimental(m);
|
||||
|
||||
py::module io = m.def_submodule("io", "Submodule for io");
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
#include "py_headers.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
@ -9,9 +10,6 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
namespace py = pybind11;
|
||||
|
||||
template <size_t bit_index0, size_t bit_index1>
|
||||
|
@ -4,11 +4,7 @@
|
||||
This file contains Python bindings for the IpAddr and MacAddr
|
||||
classes.
|
||||
*/
|
||||
|
||||
#include <pybind11/chrono.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "sls/network_utils.h"
|
||||
namespace py = pybind11;
|
||||
|
@ -1,10 +1,6 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include <pybind11/chrono.h>
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "sls/Pattern.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
14
python/src/py_headers.h
Normal file
14
python/src/py_headers.h
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
/*
|
||||
Single common header file to make sure the pybind includes are the
|
||||
same and ordered in the same way in all files. Needed to avoid
|
||||
ODR warnings
|
||||
*/
|
||||
#pragma once
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/numpy.h>
|
||||
#include "typecaster.h"
|
@ -1,11 +1,8 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "py_headers.h"
|
||||
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include <pybind11/chrono.h>
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <sstream>
|
||||
namespace py = pybind11;
|
||||
void init_scan(py::module &m) {
|
||||
|
@ -1,13 +1,92 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
#include "sls/Result.h"
|
||||
#include <pybind11/pybind11.h>
|
||||
// Add type_typecaster to pybind for our wrapper type
|
||||
#include <datetime.h>
|
||||
|
||||
#include "sls/Result.h"
|
||||
#include "DurationWrapper.h"
|
||||
|
||||
namespace py = pybind11;
|
||||
namespace pybind11 {
|
||||
namespace detail {
|
||||
template <typename Type, typename Alloc>
|
||||
struct type_caster<sls::Result<Type, Alloc>>
|
||||
: list_caster<sls::Result<Type, Alloc>, Type> {};
|
||||
|
||||
|
||||
// Based on the typecaster in pybind11/chrono.h
|
||||
template <> struct type_caster<std::chrono::nanoseconds> {
|
||||
public:
|
||||
PYBIND11_TYPE_CASTER(std::chrono::nanoseconds, const_name("DurationWrapper"));
|
||||
|
||||
// signed 25 bits required by the standard.
|
||||
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;
|
||||
|
||||
/**
|
||||
* Conversion part 1 (Python->C++): convert a PyObject into std::chrono::nanoseconds
|
||||
* try datetime.timedelta, floats and our DurationWrapper wrapper
|
||||
*/
|
||||
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) {
|
||||
PyDateTime_IMPORT;
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
// If invoked with datetime.delta object, same as in chrono.h
|
||||
if (PyDelta_Check(src.ptr())) {
|
||||
value = duration_cast<nanoseconds>(
|
||||
days(PyDateTime_DELTA_GET_DAYS(src.ptr())) +
|
||||
seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) +
|
||||
microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))
|
||||
|
||||
);
|
||||
return true;
|
||||
}
|
||||
// If invoked with a float we assume it is seconds and convert, same as in chrono.h
|
||||
if (PyFloat_Check(src.ptr())) {
|
||||
value = duration_cast<nanoseconds>(duration<double>(PyFloat_AsDouble(src.ptr())));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Lastly if we were actually called with a DurationWrapper object we get
|
||||
// the number of nanoseconds and create a std::chrono::nanoseconds from it
|
||||
py::object py_cls = py::module::import("_slsdet").attr("DurationWrapper");
|
||||
if (py::isinstance(src, py_cls)){
|
||||
sls::DurationWrapper *cls = src.cast<sls::DurationWrapper *>();
|
||||
value = nanoseconds(cls->count());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion part 2 (C++ -> Python)
|
||||
* import the module to get a handle to the wrapped class
|
||||
* Default construct an object of (wrapped) DurationWrapper
|
||||
* set the count from chrono::nanoseconds and return
|
||||
*/
|
||||
static handle cast(std::chrono::nanoseconds src, return_value_policy /* policy */, handle /* parent */) {
|
||||
py::object py_cls = py::module::import("_slsdet").attr("DurationWrapper");
|
||||
py::object* obj = new py::object;
|
||||
*obj = py_cls();
|
||||
sls::DurationWrapper *dur = obj->cast<sls::DurationWrapper *>();
|
||||
dur->set_count(src.count());
|
||||
return *obj;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace pybind11
|
Reference in New Issue
Block a user