14#include "PyAttribute.h"
16#include <lagrange/Attribute.h>
17#include <lagrange/AttributeValueType.h>
18#include <lagrange/Logger.h>
19#include <lagrange/internal/string_from_scalar.h>
20#include <lagrange/python/tensor_utils.h>
21#include <lagrange/utils/Error.h>
22#include <lagrange/utils/assert.h>
23#include <lagrange/utils/invalid.h>
26#include <lagrange/utils/warnoff.h>
27#include <nanobind/nanobind.h>
28#include <nanobind/stl/optional.h>
29#include <lagrange/utils/warnon.h>
32namespace lagrange::python {
34void bind_attribute(nanobind::module_& m)
36 namespace nb = nanobind;
37 using namespace nb::literals;
39 auto attr_class = nb::class_<PyAttribute>(m,
"Attribute",
"Mesh attribute");
40 attr_class.def_prop_ro(
42 [](PyAttribute& self) {
return self->get_element_type(); },
43 "Element type of the attribute.");
44 attr_class.def_prop_ro(
46 [](PyAttribute& self) {
return self->get_usage(); },
47 "Usage of the attribute.");
48 attr_class.def_prop_ro(
50 [](PyAttribute& self) {
return self->get_num_channels(); },
51 "Number of channels in the attribute.");
53 attr_class.def_prop_rw(
55 [](PyAttribute& self) {
56 return self.process([](
auto& attr) {
return nb::cast(attr.get_default_value()); });
58 [](PyAttribute& self,
double val) {
59 self.process([&](
auto& attr) {
60 using ValueType =
typename std::decay_t<
decltype(attr)>::ValueType;
61 attr.set_default_value(
static_cast<ValueType
>(val));
64 "Default value of the attribute.");
65 attr_class.def_prop_rw(
67 [](PyAttribute& self) {
68 return self.process([](
auto& attr) {
return attr.get_growth_policy(); });
71 self.process([&](
auto& attr) { attr.set_growth_policy(policy); });
73 "Growth policy of the attribute.");
74 attr_class.def_prop_rw(
76 [](PyAttribute& self) {
77 return self.process([](
auto& attr) {
return attr.get_shrink_policy(); });
80 self.process([&](
auto& attr) { attr.set_shrink_policy(policy); });
82 "Shrink policy of the attribute.");
83 attr_class.def_prop_rw(
85 [](PyAttribute& self) {
86 return self.process([](
auto& attr) {
return attr.get_write_policy(); });
89 self.process([&](
auto& attr) { attr.set_write_policy(policy); });
91 "Write policy of the attribute.");
92 attr_class.def_prop_rw(
94 [](PyAttribute& self) {
95 return self.process([](
auto& attr) {
return attr.get_copy_policy(); });
98 self.process([&](
auto& attr) { attr.set_copy_policy(policy); });
100 "Copy policy of the attribute.");
101 attr_class.def_prop_rw(
103 [](PyAttribute& self) {
104 return self.process([](
auto& attr) {
return attr.get_cast_policy(); });
107 self.process([&](
auto& attr) { attr.set_cast_policy(policy); });
109 "Copy policy of the attribute.");
111 "create_internal_copy",
112 [](PyAttribute& self) { self.process([](
auto& attr) { attr.create_internal_copy(); }); },
113 "Create an internal copy of the attribute.");
116 [](PyAttribute& self) { self.process([](
auto& attr) { attr.clear(); }); },
117 "Clear the attribute so it has no elements.");
120 [](PyAttribute& self,
size_t s) {
121 self.process([=](
auto& attr) { attr.reserve_entries(s); });
124 R
"(Reserve enough memory for `num_entries` entries.
126:param num_entries: Number of entries to reserve. It does not need to be a multiple of `num_channels`.)");
129 [](PyAttribute& self,
size_t num_elements) {
130 self.process([=](
auto& attr) { attr.insert_elements(num_elements); });
133 R
"(Insert new elements with default value to the attribute.
135:param num_elements: Number of elements to insert.)");
138 [](PyAttribute& self, nb::object value) {
139 auto insert_elements = [&](
auto& attr) {
140 using ValueType =
typename std::decay_t<
decltype(attr)>::ValueType;
141 GenericTensor tensor;
142 std::vector<ValueType> buffer;
143 if (nb::try_cast(value, tensor)) {
144 if (tensor.dtype() != nb::dtype<ValueType>()) {
145 throw nb::type_error(fmt::format(
146 "Tensor has a unexpected dtype. Expecting {}.",
147 internal::string_from_scalar<ValueType>())
150 Tensor<ValueType> local_tensor(tensor.handle());
151 auto [data, shape, stride] = tensor_to_span(local_tensor);
153 attr.insert_elements(data);
154 }
else if (nb::try_cast(value, buffer)) {
155 attr.insert_elements({buffer.data(), buffer.size()});
157 throw nb::type_error(
"Argument `value` must be either list or np.ndarray.");
160 self.process(insert_elements);
163 R
"(Insert new elements to the attribute.
165:param tensor: A tensor with shape (num_elements, num_channels) or (num_elements,).)");
168 [](PyAttribute& self) {
return self.process([](
auto& attr) {
return attr.empty(); }); },
169 "Return true if the attribute is empty.");
170 attr_class.def_prop_ro(
172 [](PyAttribute& self) {
173 return self.process([](
auto& attr) {
return attr.get_num_elements(); });
175 "Number of elements in the attribute.");
176 attr_class.def_prop_ro(
178 [](PyAttribute& self) {
179 return self.process([](
auto& attr) {
return attr.is_external(); });
181 "Return true if the attribute wraps external buffer.");
182 attr_class.def_prop_ro(
184 [](PyAttribute& self) {
185 return self.process([](
auto& attr) {
return attr.is_read_only(); });
187 "Return true if the attribute is read-only.");
188 attr_class.def_prop_rw(
190 [](PyAttribute& self) {
191 return self.process([&](
auto& attr) {
192 auto tensor = attribute_to_tensor(attr, nb::find(&self));
193 return nb::cast(tensor, nb::rv_policy::reference_internal);
196 [](PyAttribute& self, nb::object value) {
197 auto wrap_tensor = [&](
auto& attr) {
198 using ValueType =
typename std::decay_t<
decltype(attr)>::ValueType;
199 GenericTensor tensor;
200 std::vector<ValueType> buffer;
201 if (nb::try_cast(value, tensor)) {
202 if (tensor.dtype() != nb::dtype<ValueType>()) {
203 throw nb::type_error(fmt::format(
204 "Tensor has a unexpected dtype. Expecting {}.",
205 internal::string_from_scalar<ValueType>())
208 Tensor<ValueType> local_tensor(tensor.handle());
209 auto [data, shape, stride] = tensor_to_span(local_tensor);
213 shape.size() == 2 ? shape[1] == attr.get_num_channels() :
true);
214 const size_t num_elements = shape[0];
216 auto owner = std::make_shared<nb::object>(nb::find(tensor));
218 }
else if (nb::try_cast(value, buffer)) {
220 attr.insert_elements({buffer.data(), buffer.size()});
222 throw nb::type_error(
"Attribute.data must be either list or np.ndarray.");
225 self.process(wrap_tensor);
227 nb::for_getter(nb::sig(
"def data(self, /) -> numpy.typing.NDArray")),
228 "Raw data buffer of the attribute.");
229 attr_class.def_prop_ro(
231 [](PyAttribute& self) -> std::optional<nb::type_object> {
232 auto np = nb::module_::import_(
"numpy");
233 switch (self.ptr()->get_value_type()) {
234 case AttributeValueType::e_int8_t:
return np.attr(
"int8");
235 case AttributeValueType::e_int16_t:
return np.attr(
"int16");
236 case AttributeValueType::e_int32_t:
return np.attr(
"int32");
237 case AttributeValueType::e_int64_t:
return np.attr(
"int64");
238 case AttributeValueType::e_uint8_t:
return np.attr(
"uint8");
239 case AttributeValueType::e_uint16_t:
return np.attr(
"uint16");
240 case AttributeValueType::e_uint32_t:
return np.attr(
"uint32");
241 case AttributeValueType::e_uint64_t:
return np.attr(
"uint64");
242 case AttributeValueType::e_float:
return np.attr(
"float32");
243 case AttributeValueType::e_double:
return np.attr(
"float64");
244 default:
logger().warn(
"Attribute has an unknown dtype.");
return std::nullopt;
247 "Value type of the attribute.");
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:40
AttributeShrinkPolicy
Policy for shrinking external attribute buffers.
Definition: AttributeFwd.h:117
AttributeGrowthPolicy
Policy for growing external attribute buffers.
Definition: AttributeFwd.h:96
AttributeCopyPolicy
Policy for copying attribute that are views onto external buffers.
Definition: AttributeFwd.h:161
AttributeWritePolicy
Policy for attempting to write to read-only external buffers.
Definition: AttributeFwd.h:138
AttributeCastPolicy
Policy for remapping invalid values when casting to a different value type.
Definition: AttributeFwd.h:182
SurfaceMesh< ToScalar, ToIndex > cast(const SurfaceMesh< FromScalar, FromIndex > &source_mesh, const AttributeFilter &convertible_attributes={}, std::vector< std::string > *converted_attributes_names=nullptr)
Cast a mesh to a mesh of different scalar and/or index type.
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
SharedSpan< T > make_shared_span(const std::shared_ptr< Y > &r, T *element_ptr, size_t size)
Created a SharedSpan object around an internal buffer of a parent object.
Definition: SharedSpan.h:101