20#include <lagrange/utils/warnoff.h>
21#include <tbb/blocked_range.h>
22#include <tbb/parallel_for.h>
23#include <tbb/parallel_sort.h>
24#include <lagrange/utils/warnon.h>
27#include <lagrange/Mesh.h>
28#include <lagrange/MeshTrait.h>
29#include <lagrange/legacy/inline.h>
30#include <lagrange/utils/assert.h>
31#include <lagrange/utils/fmt/format.h>
32#include <lagrange/utils/range.h>
42template <
typename MeshType>
43void condense_indexed_attribute(
45 const std::string& attr_name,
46 const std::string& new_attr_name =
"")
48 static_assert(MeshTrait<MeshType>::is_mesh(),
"MeshType is not a mesh");
50 mesh.has_indexed_attribute(attr_name),
51 format(
"Missing attribute '{}'", attr_name));
53 using Index =
typename MeshType::Index;
54 using AttributeArray =
typename MeshType::AttributeArray;
55 using IndexArray =
typename MeshType::IndexArray;
56 static_assert(AttributeArray::IsRowMajor,
"Attribute array must be row major");
58 const auto num_vertices = mesh.get_num_vertices();
59 const auto num_facets = mesh.get_num_facets();
60 const auto& facets = mesh.get_facets();
61 const auto vertex_per_facet = mesh.get_vertex_per_facet();
63 const auto attr = mesh.get_indexed_attribute(attr_name);
64 const auto& attr_values = std::get<0>(attr);
65 const auto& attr_indices = std::get<1>(attr);
68 using IndexEntry = std::array<Index, 2>;
75 auto index_pair_comp = [&](
const IndexEntry& id0,
const IndexEntry& id1) {
76 const Index offset_0 = attr_indices(id0[0], id0[1]) * num_cols;
77 const Index offset_1 = attr_indices(id1[0], id1[1]) * num_cols;
78 const auto base_ptr = attr_values.data();
79 return std::lexicographical_compare(
81 base_ptr + offset_0 + num_cols,
83 base_ptr + offset_1 + num_cols);
89 auto index_pair_eq = [&](
const IndexEntry& id0,
const IndexEntry& id1) ->
bool {
90 return attr_values.row(attr_indices(id0[0], id0[1])) ==
91 attr_values.row(attr_indices(id1[0], id1[1]));
95 std::vector<Index> condensed_attr_values_index;
96 condensed_attr_values_index.reserve(attr_values.rows());
97 AttributeArray condensed_attr_values;
98 IndexArray condensed_attr_indices(num_facets, vertex_per_facet);
99 std::vector<IndexEntry> indices(num_facets * vertex_per_facet);
100 std::vector<Index> offsets(num_vertices + 2, 0);
102 for (
auto fi :
range(num_facets)) {
103 for (
auto ci :
range(vertex_per_facet)) {
104 offsets[facets(fi, ci) + 2]++;
107 std::partial_sum(offsets.begin(), offsets.end(), offsets.begin());
109 for (
auto fi :
range(num_facets)) {
110 for (
auto ci :
range(vertex_per_facet)) {
111 auto vi = facets(fi, ci);
112 indices[offsets[vi + 1]++] = {fi, ci};
117 tbb::blocked_range<Index>(0, num_vertices),
118 [&](
const tbb::blocked_range<Index>& tbb_range) {
119 for (
auto vi = tbb_range.begin(); vi != tbb_range.end(); vi++) {
121 indices.data() + offsets[vi],
122 indices.data() + offsets[vi + 1],
127 for (
auto vi :
range(num_vertices)) {
128 const IndexEntry* local_indices = indices.data() + offsets[vi];
129 const Index num_adj_facets =
safe_cast<Index>(offsets[vi + 1] - offsets[vi]);
130 for (Index i = 0; i < num_adj_facets; i++) {
131 const auto& curr_entry = local_indices[i];
132 condensed_attr_indices(curr_entry[0], curr_entry[1]) = count;
134 for (Index j = i; j < num_adj_facets; j++) {
135 const auto& next_entry = local_indices[j];
136 if (index_pair_eq(curr_entry, next_entry)) {
137 condensed_attr_indices(next_entry[0], next_entry[1]) = count;
143 condensed_attr_values_index.push_back(attr_indices(curr_entry[0], curr_entry[1]));
150 condensed_attr_values.resize(count, num_cols);
151 for (
auto i :
range(count)) {
152 condensed_attr_values.row(i) = attr_values.row(condensed_attr_values_index[i]);
155 if (new_attr_name ==
"" || new_attr_name == attr_name) {
156 mesh.import_indexed_attribute(attr_name, condensed_attr_values, condensed_attr_indices);
158 mesh.add_indexed_attribute(new_attr_name);
159 mesh.import_indexed_attribute(new_attr_name, condensed_attr_values, condensed_attr_indices);
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:175
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition range.h:176
constexpr auto safe_cast(SourceType value) -> std::enable_if_t<!std::is_same< SourceType, TargetType >::value, TargetType >
Perform safe cast from SourceType to TargetType, where "safe" means:
Definition safe_cast.h:51
Main namespace for Lagrange.