LCOV - code coverage report
Current view: top level - python - unit.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 34 63 54.0 %
Date: 2024-11-17 01:47:58 Functions: 11 15 73.3 %

          Line data    Source code
       1             : // SPDX-License-Identifier: BSD-3-Clause
       2             : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
       3             : 
       4             : #include "unit.h"
       5             : 
       6             : #include "scipp/common/overloaded.h"
       7             : #include "scipp/core/bucket.h"
       8             : #include "scipp/core/dtype.h"
       9             : #include "scipp/core/eigen.h"
      10             : #include "scipp/core/time_point.h"
      11             : #include "scipp/units/string.h"
      12             : #include "scipp/variable/variable.h"
      13             : 
      14             : #include "dtype.h"
      15             : 
      16             : using namespace scipp;
      17             : namespace py = pybind11;
      18             : 
      19             : namespace {
      20         613 : bool temporal_or_dimensionless(const units::Unit unit) {
      21         613 :   return unit == units::one || unit.has_same_base(units::s);
      22             : }
      23             : } // namespace
      24             : 
      25             : std::tuple<units::Unit, int64_t>
      26           0 : get_time_unit(const std::optional<scipp::units::Unit> value_unit,
      27             :               const std::optional<scipp::units::Unit> dtype_unit,
      28             :               const units::Unit sc_unit) {
      29           0 :   if (!temporal_or_dimensionless(sc_unit)) {
      30           0 :     throw except::UnitError("Invalid unit for dtype=datetime64: " +
      31           0 :                             to_string(sc_unit));
      32             :   }
      33           0 :   if (dtype_unit.value_or(units::one) != units::one &&
      34           0 :       (sc_unit != units::one && *dtype_unit != sc_unit)) {
      35           0 :     throw std::invalid_argument(
      36           0 :         "dtype (datetime64[" + to_string(*dtype_unit) +
      37           0 :         "]) has a different time unit from 'unit' argument (" +
      38           0 :         to_string(sc_unit) + ")");
      39             :   }
      40           0 :   units::Unit actual_unit = units::one;
      41           0 :   if (sc_unit != units::one)
      42           0 :     actual_unit = sc_unit;
      43           0 :   else if (dtype_unit.value_or(units::one) != units::one)
      44           0 :     actual_unit = *dtype_unit;
      45           0 :   else if (value_unit.has_value())
      46           0 :     actual_unit = *value_unit;
      47             : 
      48             :   // TODO implement
      49           0 :   if (value_unit && value_unit != actual_unit) {
      50           0 :     throw std::runtime_error("Conversion of time units is not implemented.");
      51             :   }
      52             : 
      53           0 :   return {actual_unit, 1};
      54             : }
      55             : 
      56           0 : std::tuple<units::Unit, int64_t> get_time_unit(const py::buffer &value,
      57             :                                                const py::object &dtype,
      58             :                                                const units::Unit unit) {
      59             :   return get_time_unit(
      60           0 :       value.is_none() || value.attr("dtype").attr("kind").cast<char>() != 'M'
      61             :           ? std::optional<units::Unit>{}
      62           0 :           : parse_datetime_dtype(value),
      63           0 :       dtype.is_none() ? std::optional<units::Unit>{}
      64           0 :                       : parse_datetime_dtype(dtype),
      65           0 :       unit);
      66             : }
      67             : 
      68             : template <>
      69             : std::tuple<scipp::units::Unit, scipp::units::Unit>
      70         613 : common_unit<scipp::core::time_point>(const pybind11::object &values,
      71             :                                      const scipp::units::Unit unit) {
      72         613 :   if (!temporal_or_dimensionless(unit)) {
      73           1 :     throw except::UnitError("Invalid unit for dtype=datetime64: " +
      74           2 :                             to_string(unit));
      75             :   }
      76             : 
      77         612 :   if (values.is_none() || !has_datetime_dtype(values)) {
      78          49 :     return std::tuple{unit, unit};
      79             :   }
      80             : 
      81         563 :   const auto value_unit = parse_datetime_dtype(values);
      82         563 :   if (unit == units::one) {
      83         347 :     return std::tuple{value_unit, value_unit};
      84             :   } else {
      85         216 :     return std::tuple{value_unit, unit};
      86             :   }
      87             : }
      88             : 
      89         209 : std::string to_numpy_time_string(const scipp::units::Unit unit) {
      90         209 :   if (unit == units::m) {
      91             :     // Would be treated as minute otherwise.
      92           1 :     throw except::UnitError("Invalid time unit, got 'm' which means meter. "
      93           2 :                             "If you meant minute, use unit='min' instead.");
      94             :   }
      95         208 :   return unit == units::us            ? std::string("us")
      96         386 :          : unit == units::Unit("min") ? std::string("m")
      97         594 :                                       : to_string(unit);
      98             : }
      99             : 
     100          15 : std::string to_numpy_time_string(const ProtoUnit &unit) {
     101             :   return std::visit(
     102          13 :       overloaded{
     103           0 :           [](const scipp::units::Unit &u) { return to_numpy_time_string(u); },
     104          14 :           [](const std::string &u) {
     105          14 :             return to_numpy_time_string(scipp::units::Unit(u));
     106             :           },
     107           1 :           [](const auto &) { return std::string(); }},
     108          28 :       unit);
     109             : }
     110             : 
     111       52774 : scipp::units::Unit unit_or_default(const ProtoUnit &unit, const DType type) {
     112       52774 :   return std::visit(
     113      105545 :       overloaded{[type](DefaultUnit) {
     114        1753 :                    if (type == dtype<void>)
     115           0 :                      throw except::UnitError(
     116           0 :                          "Default unit requested but dtype unknown.");
     117        1753 :                    return variable::default_unit_for(type);
     118             :                  },
     119        1418 :                  [](const py::none &) { return units::none; },
     120       14016 :                  [](const std::string &u) { return units::Unit(u); },
     121       35587 :                  [](const units::Unit &u) { return u; }},
     122      105542 :       unit);
     123             : }

Generated by: LCOV version 1.14