73 using namespace simplex;
74 using namespace operations;
75 using namespace operations::tri_mesh;
76 using namespace operations::tet_mesh;
77 using namespace operations::composite;
78 using namespace function;
79 using namespace invariants;
83 const std::string& out_dir,
84 const std::string& name,
85 const std::string& vname,
87 const bool intermediate_output);
91 const TypedAttributeHandle<double>& coordinate_handle,
92 const TypedAttributeHandle<double>& edge_length_handle,
93 const TypedAttributeHandle<double>& sizing_field_scalar_handle,
94 const TypedAttributeHandle<double>& energy_handle,
95 const TypedAttributeHandle<double>& target_edge_length_handle,
96 const TypedAttributeHandle<char>& visited_handle,
97 const double stop_energy,
98 const double current_max_energy,
99 const double initial_target_edge_length,
100 const double min_target_edge_length);
104 const TypedAttributeHandle<double>& coordinate_handle,
105 const TypedAttributeHandle<double>& energy_handle,
106 const TypedAttributeHandle<char>& energy_filter_handle,
107 const TypedAttributeHandle<char>& visited_handle,
108 const double stop_energy,
109 const double current_max_energy,
110 const double initial_target_edge_length);
116 const double target_edge_length,
117 const double max_amips_energy,
118 const int64_t passes,
119 const double envelope_size,
120 const bool intermediate_output,
121 std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
122 std::string output_dir,
125 auto position_handle =
127 auto surface_position_handle =
133 "periodic mesh #v: {}",
136 "position mesh #v: {}",
140 bmin.setConstant(std::numeric_limits<double>::max());
141 bmax.setConstant(std::numeric_limits<double>::lowest());
145 const auto p = position_accessor.vector_attribute(v);
146 for (int64_t d = 0; d < bmax.size(); ++d) {
147 bmin[d] = std::min(bmin[d], p[d]);
148 bmax[d] = std::max(bmax[d], p[d]);
152 const double bbdiag = (bmax - bmin).norm();
153 const double target_edge_length_abs = bbdiag * target_edge_length;
155 const double period_x = bmax[0] - bmin[0];
156 const double period_y = bmax[1] - bmin[1];
157 const double period_z = bmax[2] - bmin[2];
164 auto envelope_invariant = std::make_shared<EnvelopeInvariant>(
165 surface_position_handle,
166 std::sqrt(2) * envelope_size,
167 surface_position_handle);
169 auto propagate_to_child_position =
170 [](
const Eigen::MatrixX<double>& P) -> Eigen::VectorX<double> {
return P; };
172 auto propagate_to_parent_position =
173 [](
const Eigen::MatrixX<double>& P) -> Eigen::VectorX<double> {
174 assert(P.cols() == 1);
178 auto update_parent_position = std::make_shared<SingleAttributeTransferStrategy<double, double>>(
180 surface_position_handle,
181 propagate_to_parent_position);
183 auto update_child_position = std::make_shared<SingleAttributeTransferStrategy<double, double>>(
184 surface_position_handle,
186 propagate_to_child_position);
194 auto amips_accessor = position_mesh.
create_accessor(amips_handle.as<
double>());
196 auto compute_amips = [](
const Eigen::MatrixXd& P) -> Eigen::VectorXd {
198 std::array<double, 12> pts;
199 for (
size_t i = 0; i < 4; ++i) {
200 for (
size_t j = 0; j < 3; ++j) {
201 pts[3 * i + j] = P(j, i);
205 return Eigen::VectorXd::Constant(1, a);
208 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, double>>(
212 amips_update->run_on_all();
214 double max_amips = std::numeric_limits<double>::lowest();
215 double min_amips = std::numeric_limits<double>::max();
218 double e = amips_accessor.scalar_attribute(t);
219 max_amips = std::max(max_amips, e);
220 min_amips = std::min(min_amips, e);
223 logger().info(
"Initial Max AMIPS Energy: {}, Min AMIPS Energy: {}", max_amips, min_amips);
230 "target_edge_length",
234 target_edge_length_abs);
240 auto edge_length_handle =
242 auto edge_length_accessor = position_mesh.
create_accessor(edge_length_handle.as<
double>());
244 auto compute_edge_length = [](
const Eigen::MatrixXd& P) -> Eigen::VectorXd {
245 return Eigen::VectorXd::Constant(1, sqrt((P.col(0) - P.col(1)).squaredNorm()));
247 auto edge_length_update =
248 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, double>>(
251 compute_edge_length);
252 edge_length_update->run_on_all();
259 "sizing_field_scalar",
268 auto visited_vertex_flag_handle =
275 auto energy_filter_handle =
279 auto energy_filter_accessor = position_mesh.
create_accessor<
char>(energy_filter_handle);
281 auto update_energy_filter_func = [](
const Eigen::MatrixX<double>& P) -> Eigen::VectorX<char> {
282 return Eigen::VectorX<char>::Constant(1,
char(1));
284 auto energy_filter_update =
285 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<char, double>>(
286 energy_filter_handle,
288 update_energy_filter_func);
293 auto visited_edge_flag_handle =
297 auto update_flag_func = [](
const Eigen::MatrixX<double>& P) -> Eigen::VectorX<char> {
298 return Eigen::VectorX<char>::Constant(1,
char(1));
301 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<char, double>>(
302 visited_edge_flag_handle,
309 pass_through_attributes.push_back(edge_length_handle);
310 pass_through_attributes.push_back(amips_handle);
311 pass_through_attributes.push_back(visited_vertex_flag_handle);
312 pass_through_attributes.push_back(energy_filter_handle);
313 pass_through_attributes.push_back(surface_position_handle);
319 auto inversion_invariant = std::make_shared<SimplexInversionInvariant<double>>(
321 position_handle.as<
double>());
323 std::shared_ptr<function::PerSimplexFunction>
amips =
324 std::make_shared<AMIPS>(position_mesh, position_handle);
326 auto function_invariant =
329 auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(position_mesh);
331 auto todo_larger = std::make_shared<TodoLargerInvariant>(
333 edge_length_handle.as<
double>(),
334 target_edge_length_handle.as<
double>(),
337 auto todo_smaller = std::make_shared<TodoSmallerInvariant>(
339 edge_length_handle.as<
double>(),
340 target_edge_length_handle.as<
double>(),
343 auto valence_3 = std::make_shared<EdgeValenceInvariant>(position_mesh, 3);
344 auto valence_4 = std::make_shared<EdgeValenceInvariant>(position_mesh, 4);
345 auto valence_5 = std::make_shared<EdgeValenceInvariant>(position_mesh, 5);
347 auto invariant_separate_substructures =
348 std::make_shared<invariants::SeparateSubstructuresInvariant>(position_mesh);
354 std::vector<std::shared_ptr<Operation>> ops;
355 std::vector<std::string> ops_name;
359 return -edge_length_accessor.scalar_attribute(s.tuple());
363 return edge_length_accessor.scalar_attribute(s.tuple());
369 auto split = std::make_shared<EdgeSplit>(position_mesh);
370 split->set_priority(long_edges_first);
372 split->add_invariant(todo_larger);
373 split->add_invariant(
374 std::make_shared<EnergyFilterInvariant>(position_mesh, energy_filter_handle.as<
char>()));
375 split->add_invariant(inversion_invariant);
377 split->set_new_attribute_strategy(position_handle);
378 split->set_new_attribute_strategy(sizing_field_scalar_handle);
379 split->set_new_attribute_strategy(
380 visited_edge_flag_handle,
383 split->set_new_attribute_strategy(
384 target_edge_length_handle,
388 for (
const auto& attr : pass_through_attributes) {
389 split->set_new_attribute_strategy(
395 split->add_transfer_strategy(amips_update);
396 split->add_transfer_strategy(edge_length_update);
397 split->add_transfer_strategy(tag_update);
398 split->add_transfer_strategy(energy_filter_update);
399 split->add_transfer_strategy(update_child_position);
401 ops.emplace_back(split);
402 ops_name.emplace_back(
"SPLIT");
408 auto clps_strat1 = std::make_shared<CollapseNewAttributeStrategy<double>>(position_handle);
409 clps_strat1->set_strategy(CollapseBasicStrategy::CopyOther);
411 auto clps_strat2 = std::make_shared<CollapseNewAttributeStrategy<double>>(position_handle);
412 clps_strat2->set_strategy(CollapseBasicStrategy::CopyTuple);
414 auto setup_collapse = [&](std::shared_ptr<EdgeCollapse>& collapse) {
415 collapse->add_invariant(invariant_separate_substructures);
417 collapse->add_invariant(inversion_invariant);
418 collapse->add_invariant(envelope_invariant);
420 collapse->set_new_attribute_strategy(
421 visited_edge_flag_handle,
424 collapse->add_transfer_strategy(tag_update);
425 collapse->add_transfer_strategy(energy_filter_update);
426 for (
const auto& attr : pass_through_attributes) {
427 collapse->set_new_attribute_strategy(
431 collapse->set_new_attribute_strategy(
432 target_edge_length_handle,
435 collapse->add_transfer_strategy(amips_update);
436 collapse->add_transfer_strategy(edge_length_update);
438 collapse->add_transfer_strategy(update_child_position);
441 auto collapse1 = std::make_shared<EdgeCollapse>(position_mesh);
442 collapse1->add_invariant(std::make_shared<CollapseEnergyBeforeInvariantDouble>(
444 position_handle.as<
double>(),
445 amips_handle.as<
double>(),
448 collapse1->set_new_attribute_strategy(position_handle, clps_strat1);
449 collapse1->set_new_attribute_strategy(sizing_field_scalar_handle, clps_strat1);
450 setup_collapse(collapse1);
452 auto collapse2 = std::make_shared<EdgeCollapse>(position_mesh);
453 collapse2->add_invariant(std::make_shared<CollapseEnergyBeforeInvariantDouble>(
455 position_handle.as<
double>(),
456 amips_handle.as<
double>(),
459 collapse2->set_new_attribute_strategy(position_handle, clps_strat2);
460 collapse2->set_new_attribute_strategy(sizing_field_scalar_handle, clps_strat2);
461 setup_collapse(collapse2);
463 auto collapse = std::make_shared<OrOperationSequence>(position_mesh);
464 collapse->add_operation(collapse1);
465 collapse->add_operation(collapse2);
466 collapse->set_priority(short_edges_first);
467 collapse->add_invariant(
468 std::make_shared<EnergyFilterInvariant>(position_mesh, energy_filter_handle.as<
char>()));
469 collapse->add_invariant(todo_smaller);
471 collapse->add_transfer_strategy(update_child_position);
473 ops.emplace_back(collapse);
474 ops_name.emplace_back(
"COLLAPSE");
482 auto swap56 = std::make_shared<MinOperationSequence>(position_mesh);
483 for (
int i = 0; i < 5; ++i) {
484 auto swap = std::make_shared<TetEdgeSwap>(position_mesh, i);
485 swap->collapse().add_invariant(invariant_separate_substructures);
487 swap->collapse().set_new_attribute_strategy(
489 CollapseBasicStrategy::CopyOther);
490 swap->collapse().set_new_attribute_strategy(
491 sizing_field_scalar_handle,
492 CollapseBasicStrategy::CopyOther);
493 swap->split().set_new_attribute_strategy(position_handle);
494 swap->split().set_new_attribute_strategy(sizing_field_scalar_handle);
496 swap->split().set_new_attribute_strategy(
497 visited_edge_flag_handle,
500 swap->collapse().set_new_attribute_strategy(
501 visited_edge_flag_handle,
504 swap->split().set_new_attribute_strategy(
505 target_edge_length_handle,
508 swap->collapse().set_new_attribute_strategy(
509 target_edge_length_handle,
512 swap->add_invariant(std::make_shared<Swap56EnergyBeforeInvariantDouble>(
514 position_handle.as<
double>(),
517 swap->add_transfer_strategy(amips_update);
519 swap->collapse().add_invariant(inversion_invariant);
521 swap->collapse().add_invariant(envelope_invariant);
523 for (
const auto& attr : pass_through_attributes) {
524 swap->split().set_new_attribute_strategy(
528 swap->collapse().set_new_attribute_strategy(
533 swap56->add_operation(swap);
536 auto swap56_energy_check = [&](int64_t idx,
const simplex::Simplex& t) ->
double {
544 const Tuple e0 = t.tuple();
547 std::array<Tuple, 5> v;
548 auto iter_tuple = e0;
549 for (int64_t i = 0; i < 5; ++i) {
553 if (iter_tuple != e0)
return 0;
554 assert(iter_tuple == e0);
558 std::array<Eigen::Vector3<double>, 7> positions = {
559 {accessor.const_vector_attribute(v[(idx + 0) % 5]),
560 accessor.const_vector_attribute(v[(idx + 1) % 5]),
561 accessor.const_vector_attribute(v[(idx + 2) % 5]),
562 accessor.const_vector_attribute(v[(idx + 3) % 5]),
563 accessor.const_vector_attribute(v[(idx + 4) % 5]),
564 accessor.const_vector_attribute(e0),
565 accessor.const_vector_attribute(e1)}};
567 std::array<Eigen::Vector3d, 7> positions_double = {
576 std::array<std::array<int, 4>, 6> new_tets = {
584 double new_energy_max = std::numeric_limits<double>::lowest();
586 for (
int i = 0; i < 6; ++i) {
588 positions[new_tets[i][0]],
589 positions[new_tets[i][1]],
590 positions[new_tets[i][2]],
591 positions[new_tets[i][3]]) > 0) {
593 positions_double[new_tets[i][0]][0],
594 positions_double[new_tets[i][0]][1],
595 positions_double[new_tets[i][0]][2],
596 positions_double[new_tets[i][1]][0],
597 positions_double[new_tets[i][1]][1],
598 positions_double[new_tets[i][1]][2],
599 positions_double[new_tets[i][2]][0],
600 positions_double[new_tets[i][2]][1],
601 positions_double[new_tets[i][2]][2],
602 positions_double[new_tets[i][3]][0],
603 positions_double[new_tets[i][3]][1],
604 positions_double[new_tets[i][3]][2],
608 if (energy > new_energy_max) new_energy_max = energy;
611 positions_double[new_tets[i][1]][0],
612 positions_double[new_tets[i][1]][1],
613 positions_double[new_tets[i][1]][2],
614 positions_double[new_tets[i][0]][0],
615 positions_double[new_tets[i][0]][1],
616 positions_double[new_tets[i][0]][2],
617 positions_double[new_tets[i][2]][0],
618 positions_double[new_tets[i][2]][1],
619 positions_double[new_tets[i][2]][2],
620 positions_double[new_tets[i][3]][0],
621 positions_double[new_tets[i][3]][1],
622 positions_double[new_tets[i][3]][2],
626 if (energy > new_energy_max) new_energy_max = energy;
630 return new_energy_max;
633 swap56->set_value_function(swap56_energy_check);
634 swap56->add_invariant(std::make_shared<EdgeValenceInvariant>(position_mesh, 5));
638 auto swap44 = std::make_shared<MinOperationSequence>(position_mesh);
639 for (
int i = 0; i < 2; ++i) {
640 auto swap = std::make_shared<TetEdgeSwap>(position_mesh, i);
641 swap->collapse().add_invariant(invariant_separate_substructures);
643 swap->collapse().set_new_attribute_strategy(
645 CollapseBasicStrategy::CopyOther);
646 swap->collapse().set_new_attribute_strategy(
647 sizing_field_scalar_handle,
648 CollapseBasicStrategy::CopyOther);
649 swap->split().set_new_attribute_strategy(position_handle);
650 swap->split().set_new_attribute_strategy(sizing_field_scalar_handle);
651 swap->split().set_new_attribute_strategy(
652 visited_edge_flag_handle,
655 swap->collapse().set_new_attribute_strategy(
656 visited_edge_flag_handle,
659 swap->split().set_new_attribute_strategy(
660 target_edge_length_handle,
663 swap->collapse().set_new_attribute_strategy(
664 target_edge_length_handle,
667 swap->add_transfer_strategy(amips_update);
669 swap->add_invariant(std::make_shared<Swap44EnergyBeforeInvariantDouble>(
671 position_handle.as<
double>(),
675 swap->collapse().add_invariant(inversion_invariant);
677 swap->collapse().add_invariant(envelope_invariant);
679 for (
const auto& attr : pass_through_attributes) {
680 swap->split().set_new_attribute_strategy(
684 swap->collapse().set_new_attribute_strategy(
689 swap44->add_operation(swap);
692 auto swap44_energy_check = [&](int64_t idx,
const simplex::Simplex& t) ->
double {
702 const Tuple e0 = t.tuple();
705 std::array<Tuple, 4> v;
706 auto iter_tuple = e0;
707 for (int64_t i = 0; i < 4; ++i) {
712 if (iter_tuple != e0)
return 0;
713 assert(iter_tuple == e0);
715 std::array<Eigen::Vector3<double>, 6> positions = {
716 {accessor.const_vector_attribute(v[(idx + 0) % 4]),
717 accessor.const_vector_attribute(v[(idx + 1) % 4]),
718 accessor.const_vector_attribute(v[(idx + 2) % 4]),
719 accessor.const_vector_attribute(v[(idx + 3) % 4]),
720 accessor.const_vector_attribute(e0),
721 accessor.const_vector_attribute(e1)}};
722 std::array<Eigen::Vector3d, 6> positions_double = {
723 {positions[0], positions[1], positions[2], positions[3], positions[4], positions[5]}};
725 std::array<std::array<int, 4>, 4> new_tets = {
726 {{{0, 1, 2, 4}}, {{0, 2, 3, 4}}, {{0, 1, 2, 5}}, {{0, 2, 3, 5}}}};
728 double new_energy_max = std::numeric_limits<double>::lowest();
730 for (
int i = 0; i < 4; ++i) {
732 positions[new_tets[i][0]],
733 positions[new_tets[i][1]],
734 positions[new_tets[i][2]],
735 positions[new_tets[i][3]]) > 0) {
737 positions_double[new_tets[i][0]][0],
738 positions_double[new_tets[i][0]][1],
739 positions_double[new_tets[i][0]][2],
740 positions_double[new_tets[i][1]][0],
741 positions_double[new_tets[i][1]][1],
742 positions_double[new_tets[i][1]][2],
743 positions_double[new_tets[i][2]][0],
744 positions_double[new_tets[i][2]][1],
745 positions_double[new_tets[i][2]][2],
746 positions_double[new_tets[i][3]][0],
747 positions_double[new_tets[i][3]][1],
748 positions_double[new_tets[i][3]][2],
751 if (energy > new_energy_max) new_energy_max = energy;
754 positions_double[new_tets[i][1]][0],
755 positions_double[new_tets[i][1]][1],
756 positions_double[new_tets[i][1]][2],
757 positions_double[new_tets[i][0]][0],
758 positions_double[new_tets[i][0]][1],
759 positions_double[new_tets[i][0]][2],
760 positions_double[new_tets[i][2]][0],
761 positions_double[new_tets[i][2]][1],
762 positions_double[new_tets[i][2]][2],
763 positions_double[new_tets[i][3]][0],
764 positions_double[new_tets[i][3]][1],
765 positions_double[new_tets[i][3]][2],
768 if (energy > new_energy_max) new_energy_max = energy;
772 return new_energy_max;
775 swap44->set_value_function(swap44_energy_check);
776 swap44->add_invariant(std::make_shared<EdgeValenceInvariant>(position_mesh, 4));
779 auto swap32 = std::make_shared<TetEdgeSwap>(position_mesh, 0);
780 swap32->add_invariant(std::make_shared<EdgeValenceInvariant>(position_mesh, 3));
781 swap32->add_invariant(std::make_shared<Swap32EnergyBeforeInvariantDouble>(
783 position_handle.as<
double>()));
785 swap32->collapse().add_invariant(invariant_separate_substructures);
787 swap32->collapse().set_new_attribute_strategy(
789 CollapseBasicStrategy::CopyOther);
790 swap32->collapse().set_new_attribute_strategy(
791 sizing_field_scalar_handle,
792 CollapseBasicStrategy::CopyOther);
794 swap32->split().set_new_attribute_strategy(position_handle);
795 swap32->split().set_new_attribute_strategy(sizing_field_scalar_handle);
796 swap32->split().set_new_attribute_strategy(
797 visited_edge_flag_handle,
800 swap32->collapse().set_new_attribute_strategy(
801 visited_edge_flag_handle,
804 swap32->split().set_new_attribute_strategy(
805 target_edge_length_handle,
808 swap32->collapse().set_new_attribute_strategy(
809 target_edge_length_handle,
812 swap32->add_transfer_strategy(amips_update);
815 swap32->collapse().add_invariant(inversion_invariant);
816 swap32->collapse().add_invariant(envelope_invariant);
818 for (
const auto& attr : pass_through_attributes) {
819 swap32->split().set_new_attribute_strategy(
823 swap32->collapse().set_new_attribute_strategy(
828 auto swap_all = std::make_shared<OrOperationSequence>(position_mesh);
829 swap_all->add_operation(swap32);
830 swap_all->add_operation(swap44);
831 swap_all->add_operation(swap56);
832 swap_all->add_transfer_strategy(tag_update);
833 swap_all->add_transfer_strategy(energy_filter_update);
834 swap_all->add_invariant(
835 std::make_shared<EnergyFilterInvariant>(position_mesh, energy_filter_handle.as<
char>()));
836 swap_all->add_invariant(std::make_shared<InteriorEdgeInvariant>(position_mesh));
837 swap_all->add_invariant(std::make_shared<NoChildMeshAttachingInvariant>(position_mesh));
839 swap_all->set_priority(long_edges_first);
841 swap_all->add_transfer_strategy(update_child_position);
843 ops.push_back(swap_all);
844 ops_name.push_back(
"EDGE SWAP");
851 std::vector<MeshConstrainPair> mesh_constraint_pairs;
852 mesh_constraint_pairs.emplace_back(surface_position_handle, surface_position_handle);
854 auto smoothing = std::make_shared<AMIPSOptimizationSmoothingPeriodic>(
858 smoothing->add_invariant(inversion_invariant);
859 smoothing->add_transfer_strategy(update_child_position);
860 smoothing->use_random_priority() =
true;
862 smoothing->add_invariant(envelope_invariant);
863 smoothing->add_invariant(
864 std::make_shared<EnergyFilterInvariant>(position_mesh, energy_filter_handle.as<
char>()));
866 smoothing->add_transfer_strategy(amips_update);
867 smoothing->add_transfer_strategy(edge_length_update);
868 smoothing->add_transfer_strategy(update_child_position);
870 ops.push_back(smoothing);
871 ops_name.push_back(
"SMOOTHING");
950 write(position_mesh, output_dir,
output +
"_initial",
"vertices", 0, intermediate_output);
956 double old_max_energy = max_amips;
957 double old_avg_energy = 0;
959 for (int64_t i = 0; i < passes; ++i) {
960 logger().info(
"--------------------------- Pass {} ---------------------------", i);
965 for (
auto& op : ops) {
968 std::vector<Vector3d> pos;
969 for (
int i = 0; i <
vertices.size(); ++i) {
970 pos.push_back(position_accessor.const_vector_attribute(
vertices[i]));
976 logger().info(
"Executing {} ...", ops_name[jj]);
985 "Executed {}, {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, "
1064 double avg_energy = 0;
1065 double max_energy = std::numeric_limits<double>::lowest();
1066 double min_energy = std::numeric_limits<double>::max();
1068 double e = amips_accessor.scalar_attribute(t);
1069 max_energy = std::max(max_energy, e);
1070 min_energy = std::min(min_energy, e);
1078 "Max AMIPS Energy: {}, Min AMIPS Energy: {}, Avg AMIPS Energy: {}",
1087 "Executed {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, executing: {}",
1097 write(position_mesh, output_dir,
output,
"vertices", i + 1, intermediate_output);
1099 double max_energy = std::numeric_limits<double>::lowest();
1100 double min_energy = std::numeric_limits<double>::max();
1101 double avg_energy = 0;
1103 double e = amips_accessor.scalar_attribute(t);
1104 max_energy = std::max(max_energy, e);
1105 min_energy = std::min(min_energy, e);
1112 "Max AMIPS Energy: {}, Min AMIPS Energy: {}, Avg AMIPS Energy: {}",
1117 if (i > 0 && old_max_energy - max_energy < 5e-1 &&
1118 (old_avg_energy - avg_energy) / avg_energy < 0.1) {
1123 position_handle.as<
double>(),
1124 edge_length_handle.as<
double>(),
1125 sizing_field_scalar_handle.as<
double>(),
1126 amips_handle.as<
double>(),
1127 target_edge_length_handle.as<
double>(),
1128 visited_vertex_flag_handle.as<
char>(),
1134 wmtk::logger().info(
"adjusting sizing field finished");
1136 energy_filter_accessor.scalar_attribute(v) = char(1);
1153 old_max_energy = max_energy;
1154 old_avg_energy = avg_energy;
1163 const std::string& out_dir,
1164 const std::string& name,
1165 const std::string& vname,
1166 const int64_t index,
1167 const bool intermediate_output)
1169 if (intermediate_output) {
1171 const std::filesystem::path
data_dir =
"";
1173 data_dir / (name +
"_" + std::to_string(index)),
1193 const double stop_energy,
1194 const double current_max_energy,
1195 const double initial_target_edge_length,
1196 const double min_target_edge_length)
1200 std::cout <<
"in here" << std::endl;
1206 auto sizing_field_scalar_accessor = m.
create_accessor<
double>(sizing_field_scalar_handle);
1207 auto target_edge_length_accessor = m.
create_accessor<
double>(target_edge_length_handle);
1210 const double stop_filter_energy = stop_energy * 0.8;
1211 double filter_energy = std::max(current_max_energy / 100, stop_filter_energy);
1212 filter_energy = std::min(filter_energy, 100.0);
1214 const double recover_scalar = 1.5;
1215 const double refine_scalar = 0.5;
1216 const double min_refine_scalar = min_target_edge_length / initial_target_edge_length;
1219 int64_t v_cnt = vertices_all.size();
1221 std::vector<Vector3d> centroids;
1222 std::queue<Tuple> v_queue;
1228 if (energy_accessor.const_scalar_attribute(t) < filter_energy) {
1234 for (
int i = 0; i < 4; ++i) {
1235 c += coordinate_accessor.const_vector_attribute(
vertices[i]);
1238 centroids.emplace_back(c / 4.0);
1242 "filter energy: {}, low quality tets num: {}",
1246 const double R = initial_target_edge_length * 1.8;
1248 for (
const auto& v : vertices_all) {
1249 visited_accessor.scalar_attribute(v) = char(0);
1253 auto get_nearest_dist = [&](
const Tuple& v) ->
double {
1254 Tuple nearest_tuple;
1255 double min_dist = std::numeric_limits<double>::max();
1256 const Vector3d v_pos = coordinate_accessor.const_vector_attribute(v);
1257 for (
const auto& c_pos : centroids) {
1258 double dist = (c_pos - v_pos).norm();
1259 min_dist = std::min(min_dist, dist);
1264 while (!v_queue.empty()) {
1265 auto v = v_queue.front();
1268 if (visited_accessor.scalar_attribute(v) ==
char(1))
continue;
1269 visited_accessor.scalar_attribute(v) = char(1);
1271 double dist = std::max(0., get_nearest_dist(v));
1274 visited_accessor.scalar_attribute(v) = char(0);
1278 double scale_multiplier = std::min(
1280 dist / R * (1 - refine_scalar) + refine_scalar);
1282 auto new_scale = sizing_field_scalar_accessor.scalar_attribute(v) * scale_multiplier;
1283 if (new_scale > 1) {
1284 sizing_field_scalar_accessor.scalar_attribute(v) = 1;
1285 }
else if (new_scale < min_refine_scalar) {
1286 sizing_field_scalar_accessor.scalar_attribute(v) = min_refine_scalar;
1288 sizing_field_scalar_accessor.scalar_attribute(v) = new_scale;
1294 if (visited_accessor.scalar_attribute(v_one_ring) ==
char(1))
continue;
1295 v_queue.push(v_one_ring.tuple());
1300 for (
const auto& v : vertices_all) {
1301 if (visited_accessor.scalar_attribute(v) ==
char(1))
continue;
1302 auto new_scale = sizing_field_scalar_accessor.scalar_attribute(v) * 1.5;
1303 if (new_scale > 1) {
1304 sizing_field_scalar_accessor.scalar_attribute(v) = 1;
1305 }
else if (new_scale < min_refine_scalar) {
1306 sizing_field_scalar_accessor.scalar_attribute(v) = min_refine_scalar;
1308 sizing_field_scalar_accessor.scalar_attribute(v) = new_scale;
1314 target_edge_length_accessor.scalar_attribute(e) =
1315 initial_target_edge_length *
1316 (sizing_field_scalar_accessor.scalar_attribute(e) +
1317 sizing_field_scalar_accessor.scalar_attribute(
1329 const double stop_energy,
1330 const double current_max_energy,
1331 const double initial_target_edge_length)
1339 auto energy_filter_accessor = m.
create_accessor<
char>(energy_filter_handle);
1342 const double stop_filter_energy = stop_energy * 0.8;
1343 double filter_energy = std::max(current_max_energy / 100, stop_filter_energy);
1344 filter_energy = std::min(filter_energy, 100.0);
1348 for (
const auto& v : vertices_all) {
1349 visited_accessor.scalar_attribute(v) = char(0);
1350 energy_filter_accessor.scalar_attribute(v) = char(0);
1355 if (energy_accessor.const_scalar_attribute(t) < filter_energy) {
1361 energy_filter_accessor.scalar_attribute(v) = char(1);
1364 energy_filter_accessor.scalar_attribute(vv) = char(1);
virtual std::vector< Tuple > orient_vertices(const Tuple &t) const =0
attribute::MeshAttributeHandle register_attribute(const std::string &name, PrimitiveType type, int64_t size, bool replace=false, T default_value=T(0))
void serialize(MeshWriter &writer, const Mesh *local_root=nullptr) const
attribute::MeshAttributeHandle get_attribute_handle(const std::string &name, const PrimitiveType ptype) const
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.
Tuple switch_tuples(const Tuple &tuple, const ContainerType &op_sequence) const
virtual Tuple switch_tuple(const Tuple &tuple, PrimitiveType type) const =0
switch the orientation of the Tuple of the given dimension
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
PrimitiveType top_simplex_type() const
SchedulerStats run_operation_on_all(operations::Operation &op)
int64_t number_of_failed_operations() const
Returns the number of failed operations performed by the scheduler.
int64_t number_of_performed_operations() const
Returns the number of performed operations performed by the scheduler.
int64_t number_of_successful_operations() const
Returns the number of successful operations performed by the scheduler.
Handle that represents attributes for some mesh.
std::pair< attribute::MeshAttributeHandle, attribute::MeshAttributeHandle > MeshConstrainPair
static Simplex vertex(const Mesh &m, const Tuple &t)
constexpr wmtk::PrimitiveType PT
constexpr wmtk::PrimitiveType PF
void set_operation_energy_filter(Mesh &m, const TypedAttributeHandle< double > &coordinate_handle, const TypedAttributeHandle< double > &energy_handle, const TypedAttributeHandle< char > &energy_filter_handle, const TypedAttributeHandle< char > &visited_handle, const double stop_energy, const double current_max_energy, const double initial_target_edge_length)
void periodic_optimization(Mesh &periodic_mesh, Mesh &position_mesh, Mesh &surface_mesh, const double target_edge_length, const double max_amips_energy, const int64_t passes, const double envelope_size, const bool intermediate_output, std::vector< attribute::MeshAttributeHandle > &pass_through_attributes, std::string output_dir, std::string output)
void adjust_sizing_field(Mesh &m, const TypedAttributeHandle< double > &coordinate_handle, const TypedAttributeHandle< double > &edge_length_handle, const TypedAttributeHandle< double > &sizing_field_scalar_handle, const TypedAttributeHandle< double > &energy_handle, const TypedAttributeHandle< double > &target_edge_length_handle, const TypedAttributeHandle< char > &visited_handle, const double stop_energy, const double current_max_energy, const double initial_target_edge_length, const double min_target_edge_length)
void write(const Mesh &mesh, const std::string &out_dir, const std::string &name, const std::string &vname, const int64_t index, const bool intermediate_output)
void output(const Mesh &mesh, const std::filesystem::path &file, const std::string &position_attr_name)
Write the mesh to file.
auto amips(const Eigen::MatrixBase< Derived > &B)
double Tet_AMIPS_energy(const std::array< double, 12 > &T)
double Tet_AMIPS_energy(const std::array< double, 12 > &T)
void consolidate(Mesh &mesh)
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)
SimplexCollection link(const Mesh &mesh, const simplex::Simplex &simplex, const bool sort_and_clean)
SimplexCollection k_ring(const Mesh &mesh, const Simplex &simplex, int64_t k)
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)
constexpr PrimitiveType PV
spdlog::logger & logger()
Retrieves the current logger.
Vector< double, 3 > Vector3d
constexpr PrimitiveType PE
const std::filesystem::path data_dir