Line data Source code
1 : // SPDX-License-Identifier: BSD-3-Clause 2 : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp) 3 : /// @file 4 : /// @author Simon Heybrock 5 : #include <chrono> 6 : #include <iomanip> 7 : #include <set> 8 : 9 : #include "scipp/core/array_to_string.h" 10 : #include "scipp/core/eigen.h" 11 : #include "scipp/core/string.h" 12 : #include "scipp/core/tag_util.h" 13 : #include "scipp/variable/string.h" 14 : #include "scipp/variable/variable.h" 15 : 16 : namespace scipp::variable { 17 : 18 126 : std::ostream &operator<<(std::ostream &os, const Variable &variable) { 19 126 : return os << to_string(variable); 20 : } 21 : 22 : namespace { 23 : 24 972 : std::string make_dims_labels(const Variable &variable, 25 : const std::optional<Sizes> datasetSizes) { 26 972 : const auto &dims = variable.dims(); 27 972 : if (dims.empty()) 28 7 : return "()"; 29 965 : std::string diminfo = "("; 30 1930 : for (const auto &dim : dims.labels()) { 31 965 : diminfo += to_string(dim); 32 965 : if (datasetSizes) { 33 965 : if ((datasetSizes->contains(dim) ? (*datasetSizes)[dim] : 1) + 1 == 34 965 : dims[dim]) 35 0 : diminfo += " [bin-edge]"; 36 : } 37 965 : diminfo += ", "; 38 : } 39 965 : diminfo.resize(diminfo.size() - 2); 40 965 : diminfo += ")"; 41 965 : return diminfo; 42 965 : } 43 : 44 : template <class T> struct ValuesToString { 45 1605 : static std::string apply(const Variable &var) { 46 1605 : if (var.ndim() == 0) 47 193 : return core::scalar_array_to_string(var.template values<T>(), var.unit()); 48 1414 : return core::array_to_string(var.template values<T>(), var.unit()); 49 : } 50 : }; 51 : template <class T> struct VariancesToString { 52 212 : static std::string apply(const Variable &var) { 53 : if constexpr (core::canHaveVariances<T>()) { 54 212 : if (var.ndim() == 0) 55 : return core::scalar_array_to_string(var.template variances<T>(), 56 14 : var.unit()); 57 198 : return core::array_to_string(var.template variances<T>()); 58 : } else 59 0 : return std::string{}; 60 : } 61 : }; 62 : 63 : template <template <class> class Callable, class... Args> 64 1892 : auto apply(const DType dtype, Args &&...args) { 65 : // Note that formatting via registry ignores the Callable, but custom types 66 : // should typically not have variances, so Callable should always be 67 : // `ValuesToString` in this case. 68 1892 : if (formatterRegistry().contains(dtype)) 69 75 : return formatterRegistry().format(args...); 70 : return core::callDType<Callable>( 71 3634 : std::tuple<double, float, int64_t, int32_t, std::string, bool, 72 : scipp::core::time_point, Eigen::Vector3d, Eigen::Matrix3d, 73 : Variable, bucket<Variable>, scipp::index_pair, Eigen::Affine3d, 74 : scipp::core::Quaternion, scipp::core::Translation>{}, 75 3634 : dtype, std::forward<Args>(args)...); 76 : } 77 : } // namespace 78 : 79 245 : std::string format_variable_compact(const Variable &variable) { 80 245 : const auto s = to_string(variable.dtype()); 81 245 : if (variable.unit() == units::none) 82 0 : return s; 83 : else 84 490 : return s + '[' + variable.unit().name() + ']'; 85 245 : } 86 : 87 1681 : std::string format_variable(const Variable &variable, 88 : const std::optional<Sizes> &datasetSizes) { 89 1681 : if (!variable.is_valid()) 90 1 : return "invalid variable\n"; 91 1680 : std::stringstream s; 92 1680 : const std::string colSep(" "); 93 1680 : if (!datasetSizes) 94 708 : s << to_string(variable.dims()) << colSep; 95 1680 : s << std::setw(9) << to_string(variable.dtype()); 96 1680 : if (variable.unit() == units::none) 97 189 : s << colSep << std::setw(15) << "<no unit>"; 98 : else 99 1491 : s << colSep << std::setw(15) << '[' + variable.unit().name() + ']'; 100 1680 : if (datasetSizes) 101 972 : s << colSep << make_dims_labels(variable, datasetSizes); 102 1680 : s << colSep; 103 1680 : s << apply<ValuesToString>(variable.dtype(), variable); 104 1678 : if (variable.has_variances()) 105 212 : s << colSep << apply<VariancesToString>(variable.dtype(), variable); 106 1678 : return s.str(); 107 1682 : } 108 : 109 551 : std::string to_string(const Variable &variable) { 110 1100 : return std::string("<scipp.Variable> ") + format_variable(variable); 111 : } 112 : 113 0 : std::string to_string(const std::pair<Dim, Variable> &coord) { 114 : using units::to_string; 115 0 : return to_string(coord.first) + ":\n" + to_string(coord.second); 116 : } 117 : 118 0 : std::string to_string(const std::pair<std::string, Variable> &coord) { 119 0 : return coord.first + ":\n" + to_string(coord.second); 120 : } 121 : 122 29 : void FormatterRegistry::emplace(const DType key, 123 : std::unique_ptr<AbstractFormatter> formatter) { 124 29 : m_formatters.emplace(key, std::move(formatter)); 125 29 : } 126 : 127 1892 : bool FormatterRegistry::contains(const DType key) const noexcept { 128 1892 : return m_formatters.find(key) != m_formatters.end(); 129 : } 130 : 131 75 : std::string FormatterRegistry::format(const Variable &var) const { 132 150 : return m_formatters.at(var.dtype())->format(var); 133 : } 134 : 135 1996 : FormatterRegistry &formatterRegistry() { 136 1996 : static FormatterRegistry registry; 137 1996 : return registry; 138 : } 139 : 140 : } // namespace scipp::variable