Wildmeshing Toolkit
longest_edge_split.cpp
Go to the documentation of this file.
1 #include "longest_edge_split.hpp"
2 
3 #include <wmtk/Mesh.hpp>
4 #include <wmtk/Scheduler.hpp>
15 #include <wmtk/utils/Logger.hpp>
16 
18 
19 void longest_edge_split(Mesh& mesh_in, const LongestEdgeSplitOptions& options)
20 {
21  if (mesh_in.top_simplex_type() != PrimitiveType::Edge &&
25  "logest edge split works only for edge, triangle, or tet meshes: {}",
27  }
28 
29  if (!mesh_in.is_multi_mesh_root()) {
30  log_and_throw_error("The mesh passed in longest_edge_split must be the root mesh");
31  }
32 
33  attribute::MeshAttributeHandle position_handle = options.position_handle;
34  std::vector<attribute::MeshAttributeHandle> other_position_handles =
35  options.other_position_handles;
36 
37  Mesh& mesh = position_handle.mesh();
38 
39  std::vector<attribute::MeshAttributeHandle> pass_through_attributes =
41 
42  for (auto& h : other_position_handles) {
43  pass_through_attributes.emplace_back(h);
44  }
45 
47 
48  auto visited_edge_flag =
49  mesh.register_attribute<char>("visited_edge", PrimitiveType::Edge, 1, false, char(1));
50 
51  auto update_flag_func = [](Eigen::Ref<const Eigen::MatrixXd> P) -> Eigen::VectorX<char> {
52  assert(P.cols() == 2);
53  assert(P.rows() == 2 || P.rows() == 3);
54  return Eigen::VectorX<char>::Constant(1, char(1));
55  };
56  auto tag_update =
57  std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<char, double>>(
58  visited_edge_flag,
59  position_handle,
60  update_flag_func);
61 
63  // Storing edge lengths
64  auto edge_length_attribute =
65  mesh.register_attribute<double>("edge_length", PrimitiveType::Edge, 1);
66  auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
67  // Edge length update
68  auto compute_edge_length = [](Eigen::Ref<const Eigen::MatrixXd> P) -> Eigen::VectorXd {
69  assert(P.cols() == 2);
70  assert(P.rows() == 2 || P.rows() == 3);
71  return Eigen::VectorXd::Constant(1, (P.col(0) - P.col(1)).norm());
72  };
73  auto edge_length_update =
74  std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, double>>(
75  edge_length_attribute,
76  position_handle,
77  compute_edge_length);
78  edge_length_update->run_on_all();
79 
81  // computing bbox diagonal
82  Eigen::VectorXd bmin(position_handle.dimension());
83  bmin.setConstant(std::numeric_limits<double>::max());
84  Eigen::VectorXd bmax(position_handle.dimension());
85  bmax.setConstant(std::numeric_limits<double>::lowest());
86 
87  auto pt_accessor = mesh.create_const_accessor<double>(position_handle);
88 
89  const auto vertices = mesh.get_all(PrimitiveType::Vertex);
90  for (const auto& v : vertices) {
91  const auto p = pt_accessor.vector_attribute(v);
92  for (int64_t d = 0; d < bmax.size(); ++d) {
93  bmin[d] = std::min(bmin[d], p[d]);
94  bmax[d] = std::max(bmax[d], p[d]);
95  }
96  }
97 
98  const double bbdiag = (bmax - bmin).norm();
99 
100  const double length_abs = bbdiag * options.length_rel;
101 
102  wmtk::logger().info(
103  "bbox max {}, bbox min {}, diag {}, target edge length {}",
104  bmax,
105  bmin,
106  bbdiag,
107  length_abs);
108 
109  auto long_edges_first_priority = [&](const simplex::Simplex& s) {
110  assert(s.primitive_type() == PrimitiveType::Edge);
111  return -edge_length_accessor.const_scalar_attribute(s.tuple());
112  };
113  pass_through_attributes.push_back(edge_length_attribute);
114  auto todo =
115  std::make_shared<TodoLargerInvariant>(mesh, edge_length_attribute.as<double>(), length_abs);
116 
118  auto invariant_interior_edge = std::make_shared<invariants::InvariantCollection>(mesh);
119  auto invariant_interior_vertex = std::make_shared<invariants::InvariantCollection>(mesh);
120 
121  auto set_all_invariants = [&](auto&& m) {
122  invariant_interior_edge->add(
123  std::make_shared<invariants::InteriorSimplexInvariant>(m, PrimitiveType::Edge));
124  invariant_interior_vertex->add(
125  std::make_shared<invariants::InteriorSimplexInvariant>(m, PrimitiveType::Vertex));
126  };
127  wmtk::multimesh::MultiMeshVisitor visitor(set_all_invariants);
128  visitor.execute_from_root(mesh);
129 
130  auto invariant_mm_map = std::make_shared<MultiMeshMapValidInvariant>(mesh);
131 
133  std::vector<attribute::MeshAttributeHandle> position_handles;
134  position_handles.emplace_back(position_handle);
135 
137  // split
138  auto split = std::make_shared<wmtk::operations::EdgeSplit>(mesh);
139  split->add_invariant(todo);
140 
141  split->set_new_attribute_strategy(
142  visited_edge_flag,
145  split->add_transfer_strategy(tag_update);
146 
147  split->set_priority(long_edges_first_priority);
148  split->add_transfer_strategy(edge_length_update);
149 
150 
151  for (const auto& pos_handle : position_handles) {
152  split->set_new_attribute_strategy(pos_handle);
153  }
154 
155  for (const auto& attr : pass_through_attributes) {
156  split->set_new_attribute_strategy(attr);
157  }
158 
159  auto propagate_position = [](const Eigen::MatrixXd& P) -> Eigen::VectorXd { return P; };
160  for (auto& h : other_position_handles) {
161  auto transfer_position =
162  std::make_shared<operations::SingleAttributeTransferStrategy<double, double>>(
163  h,
164  position_handle,
165  propagate_position);
166  split->add_transfer_strategy(transfer_position);
167  }
168 
169 
171  Scheduler scheduler;
172  SchedulerStats pass_stats =
173  scheduler.run_operation_on_all(*split, visited_edge_flag.as<char>());
174 
175  logger().info(
176  "Executed {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, executing: {}",
177  pass_stats.number_of_performed_operations(),
178  pass_stats.number_of_successful_operations(),
179  pass_stats.number_of_failed_operations(),
180  pass_stats.collecting_time,
181  pass_stats.sorting_time,
182  pass_stats.executing_time);
183 
185 }
186 
188  Mesh& mesh,
189  const attribute::MeshAttributeHandle& position_handle,
190  const double length_rel,
191  const std::vector<attribute::MeshAttributeHandle>& pass_through)
192 {
193  LongestEdgeSplitOptions options;
194  options.position_handle = position_handle;
195  options.length_rel = length_rel;
196 
197  options.pass_through_attributes = pass_through;
198  longest_edge_split(mesh, options);
199 }
200 } // namespace wmtk::components::longest_edge_split
attribute::MeshAttributeHandle register_attribute(const std::string &name, PrimitiveType type, int64_t size, bool replace=false, T default_value=T(0))
const attribute::Accessor< T, Mesh, D > create_const_accessor(const attribute::MeshAttributeHandle &handle) const
std::vector< Tuple > get_all(PrimitiveType type) const
Generate a vector of Tuples from global vertex/edge/triangle/tetrahedron index.
Definition: Mesh.cpp:18
bool is_multi_mesh_root() const
return true if this mesh is the root of a multimesh tree
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
PrimitiveType top_simplex_type() const
Definition: Mesh.hpp:996
SchedulerStats run_operation_on_all(operations::Operation &op)
Definition: Scheduler.cpp:33
int64_t number_of_failed_operations() const
Returns the number of failed operations performed by the scheduler.
Definition: Scheduler.hpp:23
int64_t number_of_performed_operations() const
Returns the number of performed operations performed by the scheduler.
Definition: Scheduler.hpp:30
int64_t number_of_successful_operations() const
Returns the number of successful operations performed by the scheduler.
Definition: Scheduler.hpp:16
void longest_edge_split(Mesh &mesh_in, const LongestEdgeSplitOptions &options)
Perform longes-edge split on a mesh.
void consolidate(Mesh &mesh)
Definition: consolidate.cpp:13
std::vector< Tuple > vertices(const Mesh &m, const Simplex &simplex)
std::string_view primitive_type_name(PrimitiveType t)
void log_and_throw_error(const std::string &msg)
Definition: Logger.cpp:101
spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:58
std::vector< attribute::MeshAttributeHandle > pass_through_attributes
Any other attribute goes here.
double length_rel
The desired edge length relative to the AABB.
attribute::MeshAttributeHandle position_handle
vertex positions (double)
std::vector< attribute::MeshAttributeHandle > other_position_handles
If this mesh is part of a multimesh, specify the vertex positions of all other meshes here,...