Wildmeshing Toolkit
test_component_wildmeshing.cpp
Go to the documentation of this file.
1 #include <catch2/catch_test_macros.hpp>
2 #include <nlohmann/json.hpp>
3 #include <wmtk/TetMesh.hpp>
4 #include <wmtk/Types.hpp>
6 #include <wmtk/components/utils/Paths.hpp>
8 #include <wmtk/io/Cache.hpp>
11 #include <wmtk/utils/orient.hpp>
12 
15 #include <wmtk/utils/Logger.hpp>
16 
17 
18 #include <wmtk/Scheduler.hpp>
21 
34 
35 
40 
59 
60 #include <fstream>
61 
62 using namespace wmtk::components::utils;
63 using namespace wmtk;
64 using namespace simplex;
65 using namespace operations;
66 using namespace operations::tri_mesh;
67 using namespace operations::tet_mesh;
68 using namespace operations::composite;
69 using namespace wmtk::attribute;
70 using namespace function;
71 using namespace invariants;
72 
74 
75 const std::filesystem::path data_dir = WMTK_DATA_DIR;
76 
77 TEST_CASE("wildmeshing", "[components][wildmeshing][.]")
78 {
79  wmtk::io::Cache cache("wmtk_cache", ".");
80 
81  json input_component_json = {
82  {"name", "mesh"},
83  {"file", data_dir / "adaptive_tessellation_test" / "after_smooth_uv.msh"},
84  // {"file", data_dir / "2d" / "rect1.msh"},
85  {"ignore_z", true}};
86  wmtk::components::input(Paths(), input_component_json, cache);
87 
88 
89  json input =
90  R"({
91  "passes": 10,
92  "input": "mesh",
93  "target_edge_length": 0.01,
94  "intermediate_output": true,
95  "attributes": {"position": "vertices"},
96  "pass_through": [],
97  "output": "test"
98  })"_json;
99 
100  CHECK_NOTHROW(wmtk::components::wildmeshing(Paths(), input, cache));
101 }
102 
103 
104 TEST_CASE("wildmeshing_3d", "[components][wildmeshing][.]")
105 {
106  wmtk::io::Cache cache("wmtk_cache", ".");
107 
108  json input_component_json = {
109  {"name", "mesh"},
110  // {"input", data_dir / "sphere_coarse_.msh"},
111  // {"input", data_dir / "tet.msh"},
112  // {"file", data_dir / "sphere_coarse_005_.msh"},
113  {"file", data_dir / "cube_2.msh"},
114  {"ignore_z", false}};
115  wmtk::components::input(Paths(), input_component_json, cache);
116 
117  json attributes = {{"position", "vertices"}};
118 
119  json input = {
120  {"passes", 10},
121  {"input", "mesh"},
122  {"target_edge_length", 0.05},
123  {"intermediate_output", false},
124  {"output", "test_mm"},
125  {"pass_through", std::vector<int64_t>()},
126  {"attributes", attributes}};
127 
128 
129  CHECK_NOTHROW(wmtk::components::wildmeshing(Paths(), input, cache));
130 }
131 
132 TEST_CASE("wildmeshing_3d_multimesh", "[components][wildmeshing][.]")
133 {
134  wmtk::io::Cache cache("wmtk_cache", ".");
135 
136  json input_component_json = {
137  {"name", "mesh"},
138  // {"input", data_dir / "sphere_coarse_.msh"},
139  // {"input", data_dir / "tet.msh"},
140  {"file", data_dir / "sphere_coarse_005_.msh"},
141  {"ignore_z", false}};
142  wmtk::components::input(Paths(), input_component_json, cache);
143 
144  json attributes = {{"position", "vertices"}};
145 
146  json input = {
147  {"passes", 10},
148  {"input", "mesh"},
149  {"target_edge_length", 0.1},
150  {"intermediate_output", true},
151  {"output", "test_multimesh"},
152  {"pass_through", std::vector<int64_t>()},
153  {"attributes", attributes}};
154 
155 
156  CHECK_NOTHROW(wmtk::components::wildmeshing(Paths(), input, cache));
157 }
158 
159 void run_tetwild_test(
160  const std::string& path,
161  const std::string& name,
162  std::function<std::shared_ptr<Operation>(
163  Mesh&,
164  std::shared_ptr<Rounding>&,
167  std::vector<attribute::MeshAttributeHandle>&,
171  create_op)
172 {
173  // const double target_edge_length = 1.21271;
174  const double target_max_amips = 10;
175  const double min_edge_length = 0.001;
176  const double target_edge_length = 1.04; // for collapse
177  // const double target_edge_length = 0.59019; // for split and swap
178 
179  std::ifstream file(data_dir / path);
180  std::vector<Vector3r> vertices;
181  std::vector<Vector4l> tets;
182  std::string x, y, z, token;
183 
184  while (file.good()) {
185  std::string line;
186  std::getline(file, line);
187  std::istringstream iss(line);
188  iss >> token;
189  if (line[0] == 'v') {
190  int sx = line.find(' ', 2);
191  x = line.substr(2, sx - 2);
192 
193  int sy = line.find(' ', sx + 1);
194  y = line.substr(sx + 1, sy - (sx + 1));
195 
196  int sz = line.find(' ', sy + 1);
197  z = line.substr(sy + 1, sz - (sy + 1));
198 
199  vertices.emplace_back(x, y, z);
200  } else if (line[0] == 't') {
201  Vector4l f;
202  iss >> f[0] >> f[1] >> f[3] >> f[2];
203  tets.push_back(f);
204  }
205  }
206 
207  RowVectors3r v(vertices.size(), 3);
208  for (int64_t i = 0; i < vertices.size(); ++i) {
209  v.row(i) = vertices[i];
210  }
211 
212  RowVectors4l t(tets.size(), 4);
213  for (int64_t i = 0; i < tets.size(); ++i) {
214  t.row(i) = tets[i];
215  const auto ori = wmtk::utils::wmtk_orient3d(
216  v.row(t(i, 0)),
217  v.row(t(i, 1)),
218  v.row(t(i, 2)),
219  v.row(t(i, 3)));
220  CHECK(ori > 0);
221  }
222 
223  const Vector3d bbox_max(
224  v.col(0).cast<double>().maxCoeff(),
225  v.col(1).cast<double>().maxCoeff(),
226  v.col(2).cast<double>().maxCoeff());
227  const Vector3d bbox_min(
228  v.col(0).cast<double>().minCoeff(),
229  v.col(1).cast<double>().minCoeff(),
230  v.col(2).cast<double>().minCoeff());
231 
232  // std::cout << bbox_max << std::endl;
233  // std::cout << bbox_min << std::endl;
234 
235  double diag = (bbox_max - bbox_min).norm();
236  std::cout << diag << std::endl;
237  std::cout << 0.05 * diag << std::endl;
238 
239 
240  auto mesh = std::make_shared<TetMesh>();
241  mesh->initialize(t);
243  logger().info("Mesh has {} vertices {} tests", vertices.size(), tets.size());
244 
245 
247  auto pt_attribute = mesh->get_attribute_handle<Rational>("vertices", PrimitiveType::Vertex);
248  auto pt_accessor = mesh->create_accessor(pt_attribute.as<Rational>());
249 
250  auto amips_attribute =
251  mesh->register_attribute<double>("wildmeshing_amips", mesh->top_simplex_type(), 1);
252  auto amips_accessor = mesh->create_accessor(amips_attribute.as<double>());
253  // amips update
254  auto compute_amips = [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorXd {
255  assert(P.rows() == 2 || P.rows() == 3); // rows --> attribute dimension
256  assert(P.cols() == P.rows() + 1);
257  if (P.cols() == 3) {
258  // triangle
259  assert(P.rows() == 2);
260  std::array<double, 6> pts;
261  for (size_t i = 0; i < 3; ++i) {
262  for (size_t j = 0; j < 2; ++j) {
263  pts[2 * i + j] = P(j, i).to_double();
264  }
265  }
266  const double a = Tri_AMIPS_energy(pts);
267  return Eigen::VectorXd::Constant(1, a);
268  } else {
269  // tet
270  assert(P.rows() == 3);
271  std::array<double, 12> pts;
272  for (size_t i = 0; i < 4; ++i) {
273  for (size_t j = 0; j < 3; ++j) {
274  pts[3 * i + j] = P(j, i).to_double();
275  }
276  }
277  const double a = Tet_AMIPS_energy(pts);
278  return Eigen::VectorXd::Constant(1, a);
279  }
280  };
281  auto amips_update =
282  std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, Rational>>(
283  amips_attribute,
284  pt_attribute,
285  compute_amips);
286  amips_update->run_on_all();
287 
289  // Storing edge lengths
290  auto edge_length_attribute =
291  mesh->register_attribute<double>("edge_length", PrimitiveType::Edge, 1);
292  auto edge_length_accessor = mesh->create_accessor(edge_length_attribute.as<double>());
293  // Edge length update
294  auto compute_edge_length = [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorXd {
295  assert(P.cols() == 2);
296  assert(P.rows() == 2 || P.rows() == 3);
297  return Eigen::VectorXd::Constant(1, sqrt((P.col(0) - P.col(1)).squaredNorm().to_double()));
298  };
299  auto edge_length_update =
300  std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, Rational>>(
301  edge_length_attribute,
302  pt_attribute,
303  compute_edge_length);
304  edge_length_update->run_on_all();
305 
306  auto visited_edge_flag =
307  mesh->register_attribute<char>("visited_edge", PrimitiveType::Edge, 1, false, char(1));
308 
309  // auto target_edge_length_attribute = mesh->register_attribute<double>(
310  // "wildmeshing_target_edge_length",
311  // PrimitiveType::Edge,
312  // 1,
313  // false,
314  // target_edge_length); // defaults to target edge length
315 
316 
317  // auto compute_target_edge_length =
318  // [target_edge_length,
319  // target_max_amips,
320  // min_edge_length,
321  // target_edge_length_attribute,
322  // &mesh](const Eigen::MatrixXd& P, const std::vector<Tuple>& neighs) -> Eigen::VectorXd {
323  // auto target_edge_length_accessor =
324  // mesh->create_accessor(target_edge_length_attribute.as<double>());
325 
326  // assert(P.rows() == 1); // rows --> attribute dimension
327  // assert(!neighs.empty());
328  // assert(P.cols() == neighs.size());
329  // const double current_target_edge_length =
330  // target_edge_length_accessor.const_scalar_attribute(neighs[0]);
331  // const double max_amips = P.maxCoeff();
332 
333  // double new_target_edge_length = current_target_edge_length;
334  // if (max_amips > target_max_amips) {
335  // new_target_edge_length *= 0.5;
336  // } else {
337  // new_target_edge_length *= 1.5;
338  // }
339  // new_target_edge_length =
340  // std::min(new_target_edge_length, target_edge_length); // upper bound
341  // new_target_edge_length = std::max(new_target_edge_length, min_edge_length); // lower bound
342 
343  // return Eigen::VectorXd::Constant(1, new_target_edge_length);
344  // };
345  // auto target_edge_length_update =
346  // std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, double>>(
347  // target_edge_length_attribute,
348  // amips_attribute,
349  // compute_target_edge_length);
350  auto update_flag_func = [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorX<char> {
351  assert(P.cols() == 2);
352  assert(P.rows() == 2 || P.rows() == 3);
353  return Eigen::VectorX<char>::Constant(1, char(1));
354  };
355  auto flag_update =
356  std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<char, Rational>>(
357  visited_edge_flag,
358  pt_attribute,
359  update_flag_func);
360 
361 
362  std::vector<attribute::MeshAttributeHandle> pass_through_attributes;
363  pass_through_attributes.push_back(edge_length_attribute);
364  pass_through_attributes.push_back(amips_attribute);
365  // pass_through_attributes.push_back(target_edge_length_attribute);
366 
367  // ////////////////////////////////////////////////////
368 
369  auto inversion_invariant =
370  std::make_shared<SimplexInversionInvariant<Rational>>(*mesh, pt_attribute.as<Rational>());
371 
373 
374  auto rounding_pt_attribute =
375  mesh->get_attribute_handle_typed<Rational>("vertices", PrimitiveType::Vertex);
376  auto rounding = std::make_shared<Rounding>(*mesh, rounding_pt_attribute);
377  rounding->add_invariant(
378  std::make_shared<RoundedInvariant>(*mesh, pt_attribute.as<Rational>(), true));
379  rounding->add_invariant(inversion_invariant);
381 
382 
383  Scheduler scheduler;
384  int success = 10;
385  while (success > 0) {
386  auto stats = scheduler.run_operation_on_all(*rounding);
387  logger().info(
388  "Rounding, {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, "
389  "executing: {}. Total {}",
390  stats.number_of_performed_operations(),
391  stats.number_of_successful_operations(),
392  stats.number_of_failed_operations(),
393  stats.collecting_time,
394  stats.sorting_time,
395  stats.executing_time,
396  stats.total_time());
397 
398  success = stats.number_of_successful_operations();
399 
400  int64_t unrounded = 0;
401  for (const auto& v : mesh->get_all(PrimitiveType::Vertex)) {
402  const auto p = pt_accessor.vector_attribute(v);
403  for (int64_t d = 0; d < 3; ++d) {
404  if (!p[d].is_rounded()) {
405  ++unrounded;
406  break;
407  }
408  }
409  }
410 
411  logger().info("Mesh has {} unrounded vertices", unrounded);
412  }
413 
414  auto op = create_op(
415  *mesh,
416  rounding,
417  pt_attribute,
418  visited_edge_flag,
419  pass_through_attributes,
420  amips_update,
421  edge_length_update,
422  flag_update);
423 
424  auto stats = scheduler.run_operation_on_all(*op, visited_edge_flag.as<char>());
425  logger().info(
426  "{}, {} ops (S/F) {}/{}. Passes: {}. Time collecting: {}, sorting: {}, "
427  "executing: {}; total {}. Passes (avg) collecting: {}, sorting: {}, executing: {}",
428  name,
429  stats.number_of_performed_operations(),
430  stats.number_of_successful_operations(),
431  stats.number_of_failed_operations(),
432  stats.sub_stats.size(),
433  stats.collecting_time,
434  stats.sorting_time,
435  stats.executing_time,
436  stats.total_time(),
437  stats.avg_sub_collecting_time(),
438  stats.avg_sub_sorting_time(),
439  stats.avg_sub_executing_time());
440 
441  int64_t unrounded = 0;
442  for (const auto& v : mesh->get_all(PrimitiveType::Vertex)) {
443  const auto p = pt_accessor.vector_attribute(v);
444  for (int64_t d = 0; d < 3; ++d) {
445  if (!p[d].is_rounded()) {
446  ++unrounded;
447  break;
448  }
449  }
450  }
451 
452  logger().info("Mesh has {} unrounded vertices", unrounded);
453 
454  double max_energy = std::numeric_limits<double>::lowest();
455  double min_energy = std::numeric_limits<double>::max();
456  for (const auto& t : mesh->get_all(mesh->top_simplex_type())) {
457  // double e = amips->get_value(simplex::Simplex(mesh->top_simplex_type(), t));
458  double e = amips_accessor.scalar_attribute(t);
459  max_energy = std::max(max_energy, e);
460  min_energy = std::min(min_energy, e);
461  }
462 
463  logger().info("Max AMIPS Energy: {}, Min AMIPS Energy: {}", max_energy, min_energy);
464  logger().info(
465  "{} vertices, {} edges, {} tets",
466  mesh->get_all(PrimitiveType::Vertex).size(),
467  mesh->get_all(PrimitiveType::Edge).size(),
468  mesh->get_all(PrimitiveType::Tetrahedron).size());
469 
470  logger().info(
471  "Reference performance of original TetWild: split: 0.08s, collapse: 1.81525s, swap: 0.24s");
472 }
473 
474 
475 TEST_CASE("tetwild-split", "[components][wildmeshing][.]")
476 {
477  logger().set_level(spdlog::level::debug);
478 
480  "split_initial_state_test.obj",
481  "Split",
482  [](Mesh& mesh,
483  std::shared_ptr<Rounding>& rounding,
484  MeshAttributeHandle& pt_attribute,
485  MeshAttributeHandle& visited_edge_flag,
486  std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
488  amips_update,
490  edge_length_update,
492  tag_update) {
493  const double target_edge_length = 0.59019;
494  const double target_max_amips = 10;
495  const double min_edge_length = 0.001;
496 
497  auto target_edge_length_attribute = mesh.register_attribute<double>(
498  "wildmeshing_target_edge_length",
500  1,
501  false,
502  target_edge_length); // defaults to target edge length
503 
504 
505  auto compute_target_edge_length =
506  [target_edge_length,
507  target_max_amips,
508  min_edge_length,
509  target_edge_length_attribute,
510  &mesh](
511  const Eigen::MatrixXd& P,
512  const std::vector<Tuple>& neighs) -> Eigen::VectorXd {
513  auto target_edge_length_accessor =
514  mesh.create_accessor(target_edge_length_attribute.as<double>());
515 
516  assert(P.rows() == 1); // rows --> attribute dimension
517  assert(!neighs.empty());
518  assert(P.cols() == neighs.size());
519  const double current_target_edge_length =
520  target_edge_length_accessor.const_scalar_attribute(neighs[0]);
521  const double max_amips = P.maxCoeff();
522 
523  double new_target_edge_length = current_target_edge_length;
524  if (max_amips > target_max_amips) {
525  new_target_edge_length *= 0.5;
526  } else {
527  new_target_edge_length *= 1.5;
528  }
529  new_target_edge_length =
530  std::min(new_target_edge_length, target_edge_length); // upper bound
531  new_target_edge_length =
532  std::max(new_target_edge_length, min_edge_length); // lower bound
533 
534  return Eigen::VectorXd::Constant(1, new_target_edge_length);
535  };
536 
537  pass_through_attributes.push_back(target_edge_length_attribute);
538 
539  auto update_flag_func = [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorX<char> {
540  assert(P.cols() == 2);
541  assert(P.rows() == 2 || P.rows() == 3);
542  return Eigen::VectorX<char>::Constant(1, char(1));
543  };
544 
545  auto edge_length_attribute =
546  mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
547 
548  auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
549 
550  auto long_edges_first = [&](const simplex::Simplex& s) {
551  assert(s.primitive_type() == PrimitiveType::Edge);
552  return -edge_length_accessor.scalar_attribute(s);
553  };
554 
555  auto todo_larger = std::make_shared<TodoLargerInvariant>(
556  mesh,
557  edge_length_attribute.as<double>(),
558  target_edge_length_attribute.as<double>(),
559  4.0 / 3.0);
560 
561  auto split = std::make_shared<EdgeSplit>(mesh);
562  split->set_priority(long_edges_first);
563 
564  split->add_invariant(todo_larger);
565 
566  split->set_new_attribute_strategy(pt_attribute);
567  split->set_new_attribute_strategy(
568  visited_edge_flag,
571  for (const auto& attr : pass_through_attributes) {
572  split->set_new_attribute_strategy(attr);
573  }
574 
575  split->add_transfer_strategy(amips_update);
576  split->add_transfer_strategy(edge_length_update);
577  split->add_transfer_strategy(tag_update);
578 
579  auto split_then_round = std::make_shared<AndOperationSequence>(mesh);
580  split_then_round->add_operation(split);
581  split_then_round->add_operation(rounding);
582 
583  return split_then_round;
584  });
585 }
586 
587 TEST_CASE("tetwild-collapse", "[components][wildmeshing][.]")
588 {
589  // logger().set_level(spdlog::level::trace);
591  "collapse_initial_state_104985.obj",
592  "Collapse",
593  [](Mesh& mesh,
594  std::shared_ptr<Rounding>& rounding,
595  MeshAttributeHandle& pt_attribute,
596  MeshAttributeHandle& visited_edge_flag,
597  std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
599  amips_update,
601  edge_length_update,
603  tag_update) {
604  const double target_edge_length = 1.04;
605  const double target_max_amips = 10;
606  const double min_edge_length = 0.001;
607 
608  auto target_edge_length_attribute = mesh.register_attribute<double>(
609  "wildmeshing_target_edge_length",
611  1,
612  false,
613  target_edge_length); // defaults to target edge length
614 
615  pass_through_attributes.push_back(target_edge_length_attribute);
616 
617  auto edge_length_attribute =
618  mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
619 
620  auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
621 
622 
623  auto clps_strat =
624  std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
625  clps_strat->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
626  // clps_strat->set_strategy(CollapseBasicStrategy::Default);
627  clps_strat->set_strategy(CollapseBasicStrategy::CopyOther);
628 
629 
630  auto inversion_invariant = std::make_shared<SimplexInversionInvariant<Rational>>(
631  mesh,
632  pt_attribute.as<Rational>());
633  auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
634  auto invariant_separate_substructures =
635  std::make_shared<invariants::SeparateSubstructuresInvariant>(mesh);
636 
637  auto short_edges_first = [&](const simplex::Simplex& s) {
638  assert(s.primitive_type() == PrimitiveType::Edge);
639  return edge_length_accessor.scalar_attribute(s);
640  };
641 
642  auto todo_smaller = std::make_shared<TodoSmallerInvariant>(
643  mesh,
644  edge_length_attribute.as<double>(),
645  target_edge_length_attribute.as<double>(),
646  4.0 / 5.0);
647 
648  std::shared_ptr<function::PerSimplexFunction> amips =
649  std::make_shared<AMIPS>(mesh, pt_attribute);
650 
651  auto function_invariant = std::make_shared<MaxFunctionInvariant>(
652  mesh.top_simplex_type(),
653  amips,
654  pt_attribute.as<Rational>());
655 
657  // 2) EdgeCollapse
659  auto collapse = std::make_shared<EdgeCollapse>(mesh);
660  // THis triggers a segfault in release
661  // collapse->set_priority(short_edges_first);
662 
663  collapse->add_invariant(todo_smaller);
664  collapse->add_invariant(invariant_separate_substructures);
665  collapse->add_invariant(link_condition);
666  collapse->add_invariant(inversion_invariant);
667  collapse->add_invariant(function_invariant);
668  // collapse->add_invariant(envelope_invariant);
669 
670  collapse->set_new_attribute_strategy(pt_attribute, clps_strat);
671  collapse->add_transfer_strategy(tag_update);
672  collapse->set_new_attribute_strategy(
673  visited_edge_flag,
675  for (const auto& attr : pass_through_attributes) {
676  collapse->set_new_attribute_strategy(attr);
677  }
678 
679  collapse->add_transfer_strategy(amips_update);
680  collapse->add_transfer_strategy(edge_length_update);
681  // proj_collapse->add_transfer_strategy(target_edge_length_update);
682 
683  auto collapse_then_round = std::make_shared<AndOperationSequence>(mesh);
684  collapse_then_round->add_operation(collapse);
685  collapse_then_round->add_operation(rounding);
686 
687  return collapse_then_round;
688  });
689 }
690 
691 TEST_CASE("tetwild-collapse-twoway", "[components][wildmeshing][.]")
692 {
693  logger().set_level(spdlog::level::debug);
695  "collapse_initial_state_104985.obj",
696  "Collapse-Two",
697  [](Mesh& mesh,
698  std::shared_ptr<Rounding>& rounding,
699  MeshAttributeHandle& pt_attribute,
700  MeshAttributeHandle& visited_edge_flag,
701  std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
703  amips_update,
705  edge_length_update,
707  tag_update) {
708  const double target_edge_length = 1.04;
709  const double target_max_amips = 10;
710  const double min_edge_length = 0.001;
711 
712  auto target_edge_length_attribute = mesh.register_attribute<double>(
713  "wildmeshing_target_edge_length",
715  1,
716  false,
717  target_edge_length); // defaults to target edge length
718 
719  pass_through_attributes.push_back(target_edge_length_attribute);
720 
721  auto edge_length_attribute =
722  mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
723 
724  auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
725 
726 
727  auto clps_strat =
728  std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
729  clps_strat->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
730  // clps_strat->set_strategy(CollapseBasicStrategy::Default);
731  clps_strat->set_strategy(CollapseBasicStrategy::CopyOther);
732 
733 
734  auto inversion_invariant = std::make_shared<SimplexInversionInvariant<Rational>>(
735  mesh,
736  pt_attribute.as<Rational>());
737  auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
738  auto invariant_separate_substructures =
739  std::make_shared<invariants::SeparateSubstructuresInvariant>(mesh);
740 
741  auto short_edges_first = [&](const simplex::Simplex& s) {
742  assert(s.primitive_type() == PrimitiveType::Edge);
743  return edge_length_accessor.scalar_attribute(s);
744  };
745 
746  auto todo_smaller = std::make_shared<TodoSmallerInvariant>(
747  mesh,
748  edge_length_attribute.as<double>(),
749  target_edge_length_attribute.as<double>(),
750  4.0 / 5.0);
751 
752  std::shared_ptr<function::PerSimplexFunction> amips =
753  std::make_shared<AMIPS>(mesh, pt_attribute);
754 
755  auto function_invariant = std::make_shared<MaxFunctionInvariant>(
756  mesh.top_simplex_type(),
757  amips,
758  pt_attribute.as<Rational>());
759 
761  // 2) EdgeCollapse
763  auto clps_strat1 =
764  std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
765  clps_strat1->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
766  // clps_strat1->set_strategy(CollapseBasicStrategy::Default);
767  clps_strat1->set_strategy(CollapseBasicStrategy::CopyOther);
768 
769  auto clps_strat2 =
770  std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
771  clps_strat2->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
772  // clps_strat2->set_strategy(CollapseBasicStrategy::Default);
773  clps_strat2->set_strategy(CollapseBasicStrategy::CopyTuple);
774 
775  auto setup_collapse = [&](std::shared_ptr<EdgeCollapse>& collapse) {
776  collapse->add_invariant(invariant_separate_substructures);
777  collapse->add_invariant(link_condition);
778  collapse->add_invariant(inversion_invariant);
779  collapse->add_invariant(function_invariant);
780 
781 
782  collapse->set_new_attribute_strategy(
783  visited_edge_flag,
785 
786  collapse->add_transfer_strategy(tag_update);
787  for (const auto& attr : pass_through_attributes) {
788  collapse->set_new_attribute_strategy(attr);
789  }
790  // THis triggers a segfault in release
791  collapse->set_priority(short_edges_first);
792 
793  // collapse->add_invariant(envelope_invariant);
794 
795  collapse->add_transfer_strategy(amips_update);
796  collapse->add_transfer_strategy(edge_length_update);
797  // proj_collapse->add_transfer_strategy(target_edge_length_update);
798  };
799 
800  auto collapse1 = std::make_shared<EdgeCollapse>(mesh);
801  collapse1->set_new_attribute_strategy(pt_attribute, clps_strat1);
802  setup_collapse(collapse1);
803 
804  auto collapse2 = std::make_shared<EdgeCollapse>(mesh);
805  collapse2->set_new_attribute_strategy(pt_attribute, clps_strat2);
806  setup_collapse(collapse2);
807 
808  auto collapse = std::make_shared<OrOperationSequence>(mesh);
809  collapse->add_operation(collapse1);
810  collapse->add_operation(collapse2);
811  collapse->add_invariant(todo_smaller);
812 
813  auto collapse_then_round = std::make_shared<AndOperationSequence>(mesh);
814  collapse_then_round->add_operation(collapse);
815  collapse_then_round->add_operation(rounding);
816 
817  return collapse_then_round;
818  });
819 }
820 
821 TEST_CASE("tetwild-collapse-simulated", "[components][wildmeshing][.]")
822 {
823  logger().set_level(spdlog::level::debug);
825  "collapse_initial_state_104985.obj",
826  "Collapse-Two",
827  [](Mesh& mesh,
828  std::shared_ptr<Rounding>& rounding,
829  MeshAttributeHandle& pt_attribute,
830  MeshAttributeHandle& visited_edge_flag,
831  std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
833  amips_update,
835  edge_length_update,
837  tag_update) {
838  const double target_edge_length = 1.04;
839  const double target_max_amips = 10;
840  const double min_edge_length = 0.001;
841 
842  auto target_edge_length_attribute = mesh.register_attribute<double>(
843  "wildmeshing_target_edge_length",
845  1,
846  false,
847  target_edge_length); // defaults to target edge length
848 
849  pass_through_attributes.push_back(target_edge_length_attribute);
850 
851  auto edge_length_attribute =
852  mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
853 
854  auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
855 
856 
857  auto clps_strat =
858  std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
859  clps_strat->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
860  // clps_strat->set_strategy(CollapseBasicStrategy::Default);
861  clps_strat->set_strategy(CollapseBasicStrategy::CopyOther);
862 
863  auto inversion_invariant = std::make_shared<SimplexInversionInvariant<Rational>>(
864  mesh,
865  pt_attribute.as<Rational>());
866  auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
867  auto invariant_separate_substructures =
868  std::make_shared<invariants::SeparateSubstructuresInvariant>(mesh);
869 
870  auto short_edges_first = [&](const simplex::Simplex& s) {
871  assert(s.primitive_type() == PrimitiveType::Edge);
872  return edge_length_accessor.scalar_attribute(s);
873  };
874 
875  auto todo_smaller = std::make_shared<TodoSmallerInvariant>(
876  mesh,
877  edge_length_attribute.as<double>(),
878  target_edge_length_attribute.as<double>(),
879  4.0 / 5.0);
880 
881  std::shared_ptr<function::PerSimplexFunction> amips =
882  std::make_shared<AMIPS>(mesh, pt_attribute);
883 
884  auto function_invariant = std::make_shared<MaxFunctionInvariant>(
885  mesh.top_simplex_type(),
886  amips,
887  pt_attribute.as<Rational>());
888 
890  // 2) EdgeCollapse
892  auto clps_strat1 =
893  std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
894  clps_strat1->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
895  // clps_strat1->set_strategy(CollapseBasicStrategy::Default);
896  clps_strat1->set_strategy(CollapseBasicStrategy::CopyOther);
897 
898  auto clps_strat2 =
899  std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
900  clps_strat2->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
901  // clps_strat2->set_strategy(CollapseBasicStrategy::Default);
902  clps_strat2->set_strategy(CollapseBasicStrategy::CopyTuple);
903 
904  auto setup_collapse = [&](std::shared_ptr<EdgeCollapse>& collapse) {
905  collapse->add_invariant(invariant_separate_substructures);
906  collapse->add_invariant(link_condition);
907  collapse->add_invariant(inversion_invariant);
908  // collapse->add_invariant(function_invariant);
909 
910 
911  collapse->set_new_attribute_strategy(
912  visited_edge_flag,
914 
915  collapse->add_transfer_strategy(tag_update);
916  for (const auto& attr : pass_through_attributes) {
917  collapse->set_new_attribute_strategy(attr);
918  }
919  // THis triggers a segfault in release
920  collapse->set_priority(short_edges_first);
921 
922  // collapse->add_invariant(envelope_invariant);
923 
924  collapse->add_transfer_strategy(amips_update);
925  collapse->add_transfer_strategy(edge_length_update);
926  // proj_collapse->add_transfer_strategy(target_edge_length_update);
927  };
928 
929  auto amips_attribute =
930  mesh.get_attribute_handle<double>("wildmeshing_amips", PrimitiveType::Tetrahedron);
931 
932  auto collapse1 = std::make_shared<EdgeCollapse>(mesh);
933  collapse1->add_invariant(std::make_shared<CollapseEnergyBeforeInvariant>(
934  mesh,
935  pt_attribute.as<Rational>(),
936  amips_attribute.as<double>(),
937  1));
938  collapse1->set_new_attribute_strategy(pt_attribute, clps_strat1);
939  setup_collapse(collapse1);
940 
941  auto collapse2 = std::make_shared<EdgeCollapse>(mesh);
942  collapse2->add_invariant(std::make_shared<CollapseEnergyBeforeInvariant>(
943  mesh,
944  pt_attribute.as<Rational>(),
945  amips_attribute.as<double>(),
946  0));
947  collapse2->set_new_attribute_strategy(pt_attribute, clps_strat2);
948  setup_collapse(collapse2);
949 
950  auto collapse = std::make_shared<OrOperationSequence>(mesh);
951  collapse->add_operation(collapse1);
952  collapse->add_operation(collapse2);
953  collapse->add_invariant(todo_smaller);
954 
955  auto collapse_then_round = std::make_shared<AndOperationSequence>(mesh);
956  collapse_then_round->add_operation(collapse);
957  collapse_then_round->add_operation(rounding);
958 
959  return collapse_then_round;
960  });
961 }
962 
963 
964 TEST_CASE("tetwild-swap", "[components][wildmeshing][.]")
965 {
966  logger().set_level(spdlog::level::debug);
968  "swap_initial_state.obj",
969  "Swap",
970  [](Mesh& mesh,
971  std::shared_ptr<Rounding>& rounding,
972  MeshAttributeHandle& pt_attribute,
973  MeshAttributeHandle& visited_edge_flag,
974  std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
976  amips_update,
978  edge_length_update,
980  tag_update) {
981  const double target_edge_length = 0.59019;
982  const double target_max_amips = 10;
983  const double min_edge_length = 0.001;
984 
985  auto target_edge_length_attribute = mesh.register_attribute<double>(
986  "wildmeshing_target_edge_length",
988  1,
989  false,
990  target_edge_length); // defaults to target edge length
991 
992  pass_through_attributes.push_back(target_edge_length_attribute);
993 
994  auto edge_length_attribute =
995  mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
996 
997  auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
998 
999 
1000  auto clps_strat =
1001  std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
1002  clps_strat->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
1003  // clps_strat->set_strategy(CollapseBasicStrategy::Default);
1004  clps_strat->set_strategy(CollapseBasicStrategy::CopyOther);
1005 
1006 
1007  auto inversion_invariant = std::make_shared<SimplexInversionInvariant<Rational>>(
1008  mesh,
1009  pt_attribute.as<Rational>());
1010  auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
1011  auto invariant_separate_substructures =
1012  std::make_shared<invariants::SeparateSubstructuresInvariant>(mesh);
1013 
1014  auto long_edges_first = [&](const simplex::Simplex& s) {
1015  assert(s.primitive_type() == PrimitiveType::Edge);
1016  return -edge_length_accessor.scalar_attribute(s);
1017  };
1018 
1019  std::shared_ptr<function::PerSimplexFunction> amips =
1020  std::make_shared<AMIPS>(mesh, pt_attribute);
1021 
1023  // 3) Swap
1025 
1026  // swap56
1027 
1028  auto swap56 = std::make_shared<MinOperationSequence>(mesh);
1029  for (int i = 0; i < 5; ++i) {
1030  auto swap = std::make_shared<TetEdgeSwap>(mesh, i);
1031  swap->collapse().add_invariant(invariant_separate_substructures);
1032  swap->collapse().add_invariant(link_condition);
1033  swap->collapse().set_new_attribute_strategy(
1034  pt_attribute,
1035  CollapseBasicStrategy::CopyOther);
1036  swap->split().set_new_attribute_strategy(pt_attribute);
1037  swap->split().set_new_attribute_strategy(
1038  visited_edge_flag,
1041  swap->collapse().set_new_attribute_strategy(
1042  visited_edge_flag,
1044 
1045  swap->add_invariant(std::make_shared<Swap56EnergyBeforeInvariant>(
1046  mesh,
1047  pt_attribute.as<Rational>(),
1048  i));
1049 
1050  for (const auto& attr : pass_through_attributes) {
1051  swap->split().set_new_attribute_strategy(attr);
1052  swap->collapse().set_new_attribute_strategy(attr);
1053  }
1054 
1055  swap56->add_operation(swap);
1056  }
1057 
1058  auto swap56_energy_check = [&](int64_t idx, const simplex::Simplex& t) -> double {
1059  constexpr static PrimitiveType PV = PrimitiveType::Vertex;
1060  constexpr static PrimitiveType PE = PrimitiveType::Edge;
1061  constexpr static PrimitiveType PF = PrimitiveType::Triangle;
1062  constexpr static PrimitiveType PT = PrimitiveType::Tetrahedron;
1063 
1064  auto accessor = mesh.create_const_accessor(pt_attribute.as<Rational>());
1065 
1066  const Tuple e0 = t.tuple();
1067  const Tuple e1 = mesh.switch_tuple(e0, PV);
1068 
1069  std::array<Tuple, 5> v;
1070  auto iter_tuple = e0;
1071  for (int64_t i = 0; i < 5; ++i) {
1072  v[i] = mesh.switch_tuples(iter_tuple, {PE, PV});
1073  iter_tuple = mesh.switch_tuples(iter_tuple, {PF, PT});
1074  }
1075  if (iter_tuple != e0) return 0;
1076  assert(iter_tuple == e0);
1077 
1078  // five iterable vertices remap to 0-4 by m_collapse_index, 0: m_collapse_index, 5:
1079  // e0, 6: e1
1080  std::array<Eigen::Vector3<Rational>, 7> positions = {
1081  {accessor.const_vector_attribute(v[(idx + 0) % 5]),
1082  accessor.const_vector_attribute(v[(idx + 1) % 5]),
1083  accessor.const_vector_attribute(v[(idx + 2) % 5]),
1084  accessor.const_vector_attribute(v[(idx + 3) % 5]),
1085  accessor.const_vector_attribute(v[(idx + 4) % 5]),
1086  accessor.const_vector_attribute(e0),
1087  accessor.const_vector_attribute(e1)}};
1088 
1089  std::array<Eigen::Vector3d, 7> positions_double = {
1090  {positions[0].cast<double>(),
1091  positions[1].cast<double>(),
1092  positions[2].cast<double>(),
1093  positions[3].cast<double>(),
1094  positions[4].cast<double>(),
1095  positions[5].cast<double>(),
1096  positions[6].cast<double>()}};
1097 
1098  std::array<std::array<int, 4>, 6> new_tets = {
1099  {{{0, 1, 2, 5}},
1100  {{0, 2, 3, 5}},
1101  {{0, 3, 4, 5}},
1102  {{0, 1, 2, 6}},
1103  {{0, 2, 3, 6}},
1104  {{0, 3, 4, 6}}}};
1105 
1106  double new_energy_max = std::numeric_limits<double>::lowest();
1107 
1108  for (int i = 0; i < 6; ++i) {
1110  positions[new_tets[i][0]],
1111  positions[new_tets[i][1]],
1112  positions[new_tets[i][2]],
1113  positions[new_tets[i][3]]) > 0) {
1115  positions_double[new_tets[i][0]][0],
1116  positions_double[new_tets[i][0]][1],
1117  positions_double[new_tets[i][0]][2],
1118  positions_double[new_tets[i][1]][0],
1119  positions_double[new_tets[i][1]][1],
1120  positions_double[new_tets[i][1]][2],
1121  positions_double[new_tets[i][2]][0],
1122  positions_double[new_tets[i][2]][1],
1123  positions_double[new_tets[i][2]][2],
1124  positions_double[new_tets[i][3]][0],
1125  positions_double[new_tets[i][3]][1],
1126  positions_double[new_tets[i][3]][2],
1127  }});
1128 
1129 
1130  if (energy > new_energy_max) new_energy_max = energy;
1131  } else {
1133  positions_double[new_tets[i][1]][0],
1134  positions_double[new_tets[i][1]][1],
1135  positions_double[new_tets[i][1]][2],
1136  positions_double[new_tets[i][0]][0],
1137  positions_double[new_tets[i][0]][1],
1138  positions_double[new_tets[i][0]][2],
1139  positions_double[new_tets[i][2]][0],
1140  positions_double[new_tets[i][2]][1],
1141  positions_double[new_tets[i][2]][2],
1142  positions_double[new_tets[i][3]][0],
1143  positions_double[new_tets[i][3]][1],
1144  positions_double[new_tets[i][3]][2],
1145  }});
1146 
1147 
1148  if (energy > new_energy_max) new_energy_max = energy;
1149  }
1150  }
1151 
1152  return new_energy_max;
1153  };
1154 
1155  swap56->set_value_function(swap56_energy_check);
1156  swap56->add_invariant(std::make_shared<EdgeValenceInvariant>(mesh, 5));
1157 
1158  // swap44
1159 
1160  auto swap44 = std::make_shared<MinOperationSequence>(mesh);
1161  for (int i = 0; i < 2; ++i) {
1162  auto swap = std::make_shared<TetEdgeSwap>(mesh, i);
1163  swap->collapse().add_invariant(invariant_separate_substructures);
1164  swap->collapse().add_invariant(link_condition);
1165  swap->collapse().set_new_attribute_strategy(
1166  pt_attribute,
1167  CollapseBasicStrategy::CopyOther);
1168  swap->split().set_new_attribute_strategy(pt_attribute);
1169  swap->split().set_new_attribute_strategy(
1170  visited_edge_flag,
1173  swap->collapse().set_new_attribute_strategy(
1174  visited_edge_flag,
1176 
1177  swap->add_invariant(std::make_shared<Swap44EnergyBeforeInvariant>(
1178  mesh,
1179  pt_attribute.as<Rational>(),
1180  i));
1181 
1182  for (const auto& attr : pass_through_attributes) {
1183  swap->split().set_new_attribute_strategy(attr);
1184  swap->collapse().set_new_attribute_strategy(attr);
1185  }
1186 
1187  swap44->add_operation(swap);
1188  }
1189 
1190  auto swap44_energy_check = [&](int64_t idx, const simplex::Simplex& t) -> double {
1191  constexpr static PrimitiveType PV = PrimitiveType::Vertex;
1192  constexpr static PrimitiveType PE = PrimitiveType::Edge;
1193  constexpr static PrimitiveType PF = PrimitiveType::Triangle;
1194  constexpr static PrimitiveType PT = PrimitiveType::Tetrahedron;
1195 
1196  auto accessor = mesh.create_const_accessor(pt_attribute.as<Rational>());
1197 
1198  // get the coords of the vertices
1199  // input edge end points
1200  const Tuple e0 = t.tuple();
1201  const Tuple e1 = mesh.switch_tuple(e0, PV);
1202  // other four vertices
1203  std::array<Tuple, 4> v;
1204  auto iter_tuple = e0;
1205  for (int64_t i = 0; i < 4; ++i) {
1206  v[i] = mesh.switch_tuples(iter_tuple, {PE, PV});
1207  iter_tuple = mesh.switch_tuples(iter_tuple, {PF, PT});
1208  }
1209 
1210  if (iter_tuple != e0) return 0;
1211  assert(iter_tuple == e0);
1212 
1213  std::array<Eigen::Vector3<Rational>, 6> positions = {
1214  {accessor.const_vector_attribute(v[(idx + 0) % 4]),
1215  accessor.const_vector_attribute(v[(idx + 1) % 4]),
1216  accessor.const_vector_attribute(v[(idx + 2) % 4]),
1217  accessor.const_vector_attribute(v[(idx + 3) % 4]),
1218  accessor.const_vector_attribute(e0),
1219  accessor.const_vector_attribute(e1)}};
1220  std::array<Eigen::Vector3d, 6> positions_double = {
1221  {positions[0].cast<double>(),
1222  positions[1].cast<double>(),
1223  positions[2].cast<double>(),
1224  positions[3].cast<double>(),
1225  positions[4].cast<double>(),
1226  positions[5].cast<double>()}};
1227 
1228  std::array<std::array<int, 4>, 4> new_tets = {
1229  {{{0, 1, 2, 4}}, {{0, 2, 3, 4}}, {{0, 1, 2, 5}}, {{0, 2, 3, 5}}}};
1230 
1231  double new_energy_max = std::numeric_limits<double>::lowest();
1232 
1233  for (int i = 0; i < 4; ++i) {
1235  positions[new_tets[i][0]],
1236  positions[new_tets[i][1]],
1237  positions[new_tets[i][2]],
1238  positions[new_tets[i][3]]) > 0) {
1240  positions_double[new_tets[i][0]][0],
1241  positions_double[new_tets[i][0]][1],
1242  positions_double[new_tets[i][0]][2],
1243  positions_double[new_tets[i][1]][0],
1244  positions_double[new_tets[i][1]][1],
1245  positions_double[new_tets[i][1]][2],
1246  positions_double[new_tets[i][2]][0],
1247  positions_double[new_tets[i][2]][1],
1248  positions_double[new_tets[i][2]][2],
1249  positions_double[new_tets[i][3]][0],
1250  positions_double[new_tets[i][3]][1],
1251  positions_double[new_tets[i][3]][2],
1252  }});
1253 
1254  if (energy > new_energy_max) new_energy_max = energy;
1255  } else {
1257  positions_double[new_tets[i][1]][0],
1258  positions_double[new_tets[i][1]][1],
1259  positions_double[new_tets[i][1]][2],
1260  positions_double[new_tets[i][0]][0],
1261  positions_double[new_tets[i][0]][1],
1262  positions_double[new_tets[i][0]][2],
1263  positions_double[new_tets[i][2]][0],
1264  positions_double[new_tets[i][2]][1],
1265  positions_double[new_tets[i][2]][2],
1266  positions_double[new_tets[i][3]][0],
1267  positions_double[new_tets[i][3]][1],
1268  positions_double[new_tets[i][3]][2],
1269  }});
1270 
1271  if (energy > new_energy_max) new_energy_max = energy;
1272  }
1273  }
1274 
1275  return new_energy_max;
1276  };
1277 
1278  swap44->set_value_function(swap44_energy_check);
1279  swap44->add_invariant(std::make_shared<EdgeValenceInvariant>(mesh, 4));
1280 
1281  // swap 32
1282  auto swap32 = std::make_shared<TetEdgeSwap>(mesh, 0);
1283  swap32->add_invariant(std::make_shared<EdgeValenceInvariant>(mesh, 3));
1284  swap32->add_invariant(
1285  std::make_shared<Swap32EnergyBeforeInvariant>(mesh, pt_attribute.as<Rational>()));
1286 
1287  swap32->collapse().add_invariant(invariant_separate_substructures);
1288  swap32->collapse().add_invariant(link_condition);
1289  swap32->collapse().set_new_attribute_strategy(
1290  pt_attribute,
1291  CollapseBasicStrategy::CopyOther);
1292  swap32->split().set_new_attribute_strategy(pt_attribute);
1293  swap32->split().set_new_attribute_strategy(
1294  visited_edge_flag,
1297  swap32->collapse().set_new_attribute_strategy(
1298  visited_edge_flag,
1300 
1301  for (const auto& attr : pass_through_attributes) {
1302  swap32->split().set_new_attribute_strategy(attr);
1303  swap32->collapse().set_new_attribute_strategy(attr);
1304  }
1305 
1306  // all swaps
1307 
1308  auto swap_all = std::make_shared<OrOperationSequence>(mesh);
1309  // swap_all->add_invariant(std::make_shared<InteriorEdgeInvariant>(mesh));
1310  swap_all->add_operation(swap32);
1311  swap_all->add_operation(swap44);
1312  swap_all->add_operation(swap56);
1313  swap_all->add_transfer_strategy(tag_update);
1314 
1315  auto swap_then_round = std::make_shared<AndOperationSequence>(mesh);
1316  swap_then_round->add_operation(swap_all);
1317  // swap_then_round->add_operation(swap44);
1318  swap_then_round->add_invariant(std::make_shared<InteriorEdgeInvariant>(mesh));
1319  swap_then_round->add_operation(rounding);
1320 
1321 
1322  return swap_then_round;
1323  });
1324 }
attribute::MeshAttributeHandle register_attribute(const std::string &name, PrimitiveType type, int64_t size, bool replace=false, T default_value=T(0))
attribute::MeshAttributeHandle get_attribute_handle(const std::string &name, const PrimitiveType ptype) const
Definition: Mesh.hpp:917
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
auto as() const -> const held_handle_type< held_type_from_primitive< T >()> &
constexpr wmtk::PrimitiveType PT
constexpr wmtk::PrimitiveType PF
std::shared_ptr< Mesh > input(const std::filesystem::path &file, const bool ignore_z_if_zero, const std::vector< std::string > &tetrahedron_attributes)
Definition: input.cpp:12
std::vector< std::pair< std::shared_ptr< Mesh >, std::string > > wildmeshing(const WildMeshingOptions &option)
Definition: wildmeshing.cpp:10
auto amips(const Eigen::MatrixBase< Derived > &B)
Definition: amips.hpp:20
double Tet_AMIPS_energy(const std::array< double, 12 > &T)
Definition: amips.cpp:380
double Tet_AMIPS_energy(const std::array< double, 12 > &T)
Definition: AMIPS.cpp:375
double Tri_AMIPS_energy(const std::array< double, 6 > &T)
Definition: AMIPS.cpp:473
attribute::MeshAttributeHandle set_matrix_attribute(const Mat &data, const std::string &name, const PrimitiveType &type, Mesh &mesh)
Definition: mesh_utils.hpp:9
bool link_condition(const EdgeMesh &mesh, const Tuple &edge)
Check if the edge to collapse satisfying the link condition.
std::vector< Tuple > vertices(const Mesh &m, const Simplex &simplex)
int wmtk_orient3d(const Eigen::Ref< const Eigen::Vector3< Rational >> &p0, const Eigen::Ref< const Eigen::Vector3< Rational >> &p1, const Eigen::Ref< const Eigen::Vector3< Rational >> &p2, const Eigen::Ref< const Eigen::Vector3< Rational >> &p3)
Definition: orient.cpp:75
Definition: Accessor.hpp:6
constexpr PrimitiveType PV
RowVectors< int64_t, 4 > RowVectors4l
Definition: Types.hpp:48
spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:58
Vector< int64_t, 4 > Vector4l
Definition: Types.hpp:36
Vector< double, 3 > Vector3d
Definition: Types.hpp:39
RowVectors< Rational, 3 > RowVectors3r
Definition: Types.hpp:53
constexpr PrimitiveType PE
void run_tetwild_test(const std::string &path, const std::string &name, std::function< std::shared_ptr< Operation >(Mesh &, std::shared_ptr< Rounding > &, MeshAttributeHandle &, MeshAttributeHandle &, std::vector< attribute::MeshAttributeHandle > &, std::shared_ptr< wmtk::operations::SingleAttributeTransferStrategy< double, Rational >> &, std::shared_ptr< wmtk::operations::SingleAttributeTransferStrategy< double, Rational >> &, std::shared_ptr< wmtk::operations::SingleAttributeTransferStrategy< char, Rational >> &)> create_op)
const std::filesystem::path data_dir
TEST_CASE("wildmeshing", "[components][wildmeshing][.]")
nlohmann::json json
nlohmann::json json
Definition: input.cpp:9