1+ #include " SimplicialEmbedding.hpp"
2+
3+ #include < wmtk/Scheduler.hpp>
4+ #include < wmtk/invariants/SimplexInversionInvariant.hpp>
5+ #include < wmtk/invariants/TodoInvariant.hpp>
6+ #include < wmtk/operations/EdgeSplit.hpp>
7+ #include < wmtk/operations/attribute_new/SplitNewAttributeStrategy.hpp>
8+ #include < wmtk/operations/composite/TetCellSplit.hpp>
9+ #include < wmtk/operations/composite/TriFaceSplit.hpp>
10+ #include < wmtk/simplex/faces.hpp>
11+ #include < wmtk/simplex/faces_single_dimension.hpp>
12+ #include < wmtk/utils/Logger.hpp>
13+ #include < wmtk/utils/primitive_range.hpp>
14+
15+ #include < deque>
16+
17+ namespace wmtk ::components::internal {
18+
19+ namespace {
20+
21+ class TagAttribute
22+ {
23+ public:
24+ wmtk::attribute::Accessor<int64_t > m_accessor;
25+ PrimitiveType m_ptype;
26+ int64_t m_val;
27+
28+ TagAttribute (
29+ Mesh& m,
30+ const attribute::MeshAttributeHandle& attribute,
31+ PrimitiveType ptype,
32+ int64_t val)
33+ : m_accessor(m.create_accessor<int64_t >(attribute))
34+ , m_ptype(ptype)
35+ , m_val(val)
36+ {}
37+
38+ TagAttribute (TagAttribute&) = delete ;
39+ };
40+ } // namespace
41+
42+ SimplicialEmbedding::SimplicialEmbedding (
43+ Mesh& mesh,
44+ const std::vector<attribute::MeshAttributeHandle>& label_attributes,
45+ const int64_t & value,
46+ const std::vector<attribute::MeshAttributeHandle>& pass_through_attributes)
47+ : m_mesh(mesh)
48+ , m_label_attributes(label_attributes)
49+ , m_value(value)
50+ , m_pass_through_attributes(pass_through_attributes)
51+ {}
52+
53+ void SimplicialEmbedding::regularize_tags (bool generate_simplicial_embedding)
54+ {
55+ using namespace operations ;
56+
57+ std::vector<attribute::MeshAttributeHandle> todo_handles;
58+ for (size_t i = 0 ; i < m_label_attributes.size (); ++i) {
59+ attribute::MeshAttributeHandle todo_handle =
60+ m_mesh.register_attribute <int64_t >(" todo" , m_label_attributes[i].primitive_type (), 1 );
61+ todo_handles.emplace_back (todo_handle);
62+ }
63+
64+ std::deque<TagAttribute> tag_attributes;
65+ for (size_t i = 0 ; i < m_label_attributes.size (); ++i) {
66+ tag_attributes.emplace_back (
67+ m_mesh,
68+ m_label_attributes[i],
69+ m_label_attributes[i].primitive_type (),
70+ m_value);
71+ }
72+
73+ // make sure tag vector is complete and sorted in descending order
74+ for (size_t i = 0 ; i < tag_attributes.size (); ++i) {
75+ TagAttribute& a = tag_attributes[i];
76+ if (get_primitive_type_id (a.m_ptype ) != m_mesh.top_cell_dimension () - i) {
77+ log_and_throw_error (" Tag array must be sorted in descending order starting with "
78+ " the top simplex type up to vertex." );
79+ }
80+ }
81+
82+
83+ // tag all faces of attributes
84+ for (size_t attr_it = 0 ; attr_it < tag_attributes.size () - 1 ; ++attr_it) {
85+ const TagAttribute& ta = tag_attributes[attr_it];
86+ for (const Tuple& t : m_mesh.get_all (ta.m_ptype )) {
87+ if (ta.m_accessor .const_scalar_attribute (t) != ta.m_val ) {
88+ continue ; // t is not tagged
89+ }
90+
91+ const PrimitiveType face_ptype =
92+ get_primitive_type_from_id (get_primitive_type_id (ta.m_ptype ) - 1 );
93+ const auto faces = simplex::faces_single_dimension_tuples (
94+ m_mesh,
95+ simplex::Simplex (m_mesh, ta.m_ptype , t),
96+ face_ptype);
97+
98+ TagAttribute& face_ta = tag_attributes[attr_it + 1 ];
99+ for (const Tuple& f : faces) {
100+ face_ta.m_accessor .scalar_attribute (f) = face_ta.m_val ;
101+ }
102+ }
103+ }
104+
105+ if (!generate_simplicial_embedding) {
106+ return ;
107+ }
108+
109+ // check for inversions
110+ if (m_mesh.has_attribute <double >(" vertices" , PrimitiveType::Vertex)) {
111+ const auto pos_handle =
112+ m_mesh.get_attribute_handle <double >(" vertices" , PrimitiveType::Vertex);
113+ if (pos_handle.dimension () == m_mesh.top_cell_dimension () - 1 ) {
114+ SimplexInversionInvariant<double > inv (pos_handle.mesh (), pos_handle.as <double >());
115+
116+ if (!inv.after ({}, m_mesh.get_all (m_mesh.top_simplex_type ()))) {
117+ logger ().error (" Mesh is not inversion free BEFORE simplicial embedding!" );
118+ }
119+ }
120+ }
121+
122+ // split untagged simplices that have only tagged faces
123+ for (size_t attr_it = 0 ; attr_it < tag_attributes.size () - 1 ;) {
124+ const TagAttribute& ta = tag_attributes[attr_it];
125+
126+ attribute::MeshAttributeHandle& todo_handle = todo_handles[attr_it];
127+ auto todo_acc = m_mesh.create_accessor <int64_t >(todo_handle);
128+
129+ int64_t count_todos = 0 ;
130+ for (const Tuple& t : m_mesh.get_all (ta.m_ptype )) {
131+ if (ta.m_accessor .const_scalar_attribute (t) == ta.m_val ) {
132+ continue ; // t is tagged
133+ }
134+
135+ const PrimitiveType face_ptype =
136+ get_primitive_type_from_id (get_primitive_type_id (ta.m_ptype ) - 1 );
137+ const auto faces = simplex::faces_single_dimension_tuples (
138+ m_mesh,
139+ simplex::Simplex (m_mesh, ta.m_ptype , t),
140+ face_ptype);
141+
142+ const TagAttribute& face_ta = tag_attributes[attr_it + 1 ];
143+
144+ bool all_faces_are_tagged = true ;
145+
146+ for (const Tuple& f : faces) {
147+ if (face_ta.m_accessor .const_scalar_attribute (f) != face_ta.m_val ) {
148+ all_faces_are_tagged = false ;
149+ break ;
150+ }
151+ }
152+
153+ if (all_faces_are_tagged) {
154+ todo_acc.scalar_attribute (t) = 1 ;
155+ ++count_todos;
156+ }
157+ }
158+
159+ // split simplex because all its faces are tagged
160+ Scheduler scheduler;
161+ int64_t count_done = 0 ;
162+ switch (ta.m_ptype ) {
163+ case PrimitiveType::Edge: { // edge split
164+ EdgeSplit op_split (m_mesh);
165+ op_split.add_invariant (std::make_shared<TodoInvariant>(
166+ m_mesh,
167+ std::get<attribute::TypedAttributeHandle<int64_t >>(todo_handle.handle ())));
168+
169+ // todos
170+ for (const attribute::MeshAttributeHandle& h : todo_handles) {
171+ op_split.set_new_attribute_strategy (
172+ h,
173+ SplitBasicStrategy::None,
174+ SplitRibBasicStrategy::None);
175+ }
176+ // labels
177+ for (const attribute::MeshAttributeHandle& h : m_label_attributes) {
178+ op_split.set_new_attribute_strategy (
179+ h,
180+ SplitBasicStrategy::Copy,
181+ SplitRibBasicStrategy::None);
182+ }
183+ // pass_through
184+ for (const auto & attr : m_pass_through_attributes) {
185+ op_split.set_new_attribute_strategy (attr);
186+ }
187+
188+ logger ().info (" split {} edges" , count_todos);
189+ while (true ) {
190+ const auto stats = scheduler.run_operation_on_all (op_split);
191+ count_done += stats.number_of_successful_operations ();
192+ if (stats.number_of_successful_operations () == 0 ) {
193+ break ;
194+ }
195+ }
196+
197+ break ;
198+ }
199+ case PrimitiveType::Triangle: { // face split
200+ composite::TriFaceSplit op_face_split (m_mesh);
201+ op_face_split.add_invariant (std::make_shared<TodoInvariant>(
202+ m_mesh,
203+ std::get<attribute::TypedAttributeHandle<int64_t >>(todo_handle.handle ())));
204+
205+ // todos
206+ for (const attribute::MeshAttributeHandle& h : todo_handles) {
207+ op_face_split.split ().set_new_attribute_strategy (
208+ h,
209+ SplitBasicStrategy::None,
210+ SplitRibBasicStrategy::None);
211+ op_face_split.collapse ().set_new_attribute_strategy (h, CollapseBasicStrategy::None);
212+ }
213+ // labels
214+ for (const attribute::MeshAttributeHandle& h : m_label_attributes) {
215+ op_face_split.split ().set_new_attribute_strategy (
216+ h,
217+ SplitBasicStrategy::Copy,
218+ SplitRibBasicStrategy::None);
219+ op_face_split.collapse ().set_new_attribute_strategy (h, CollapseBasicStrategy::None);
220+ }
221+ // pass_through
222+ for (const auto & attr : m_pass_through_attributes) {
223+ op_face_split.split ().set_new_attribute_strategy (attr);
224+ op_face_split.collapse ().set_new_attribute_strategy (
225+ attr,
226+ CollapseBasicStrategy::None);
227+ }
228+
229+
230+ logger ().info (" split {} faces" , count_todos);
231+ while (true ) {
232+ const auto stats = scheduler.run_operation_on_all (op_face_split);
233+ count_done += stats.number_of_successful_operations ();
234+ if (stats.number_of_successful_operations () == 0 ) {
235+ break ;
236+ }
237+ }
238+
239+ break ;
240+ }
241+ case PrimitiveType::Tetrahedron: { // tet split
242+ composite::TetCellSplit op_tet_split (m_mesh);
243+ op_tet_split.add_invariant (std::make_shared<TodoInvariant>(
244+ m_mesh,
245+ std::get<attribute::TypedAttributeHandle<int64_t >>(todo_handle.handle ())));
246+
247+ // todos
248+ for (const attribute::MeshAttributeHandle& h : todo_handles) {
249+ op_tet_split.split ().set_new_attribute_strategy (
250+ h,
251+ SplitBasicStrategy::None,
252+ SplitRibBasicStrategy::None);
253+ op_tet_split.collapse ().set_new_attribute_strategy (h, CollapseBasicStrategy::None);
254+ }
255+ // labels
256+ for (const attribute::MeshAttributeHandle& h : m_label_attributes) {
257+ op_tet_split.split ().set_new_attribute_strategy (
258+ h,
259+ SplitBasicStrategy::Copy,
260+ SplitRibBasicStrategy::None);
261+ op_tet_split.collapse ().set_new_attribute_strategy (h, CollapseBasicStrategy::None);
262+ }
263+ // pass_through
264+ for (const auto & attr : m_pass_through_attributes) {
265+ op_tet_split.split ().set_new_attribute_strategy (attr);
266+ op_tet_split.collapse ().set_new_attribute_strategy (
267+ attr,
268+ CollapseBasicStrategy::None);
269+ }
270+
271+ logger ().info (" split {} tetrahedra" , count_todos);
272+ while (true ) {
273+ const auto stats = scheduler.run_operation_on_all (op_tet_split);
274+ count_done += stats.number_of_successful_operations ();
275+ if (stats.number_of_successful_operations () == 0 ) {
276+ break ;
277+ }
278+ }
279+
280+ break ;
281+ }
282+ default : log_and_throw_error (" unknown primitive type" ); break ;
283+ }
284+
285+ if (count_done == count_todos) {
286+ ++attr_it;
287+ } else {
288+ logger ().info (
289+ " {} remain. Regularize same primitive type once more." ,
290+ count_todos - count_done);
291+ }
292+ }
293+
294+ // check for inversions
295+ if (m_mesh.has_attribute <double >(" vertices" , PrimitiveType::Vertex)) {
296+ const auto pos_handle =
297+ m_mesh.get_attribute_handle <double >(" vertices" , PrimitiveType::Vertex);
298+ SimplexInversionInvariant<double > inv (pos_handle.mesh (), pos_handle.as <double >());
299+
300+ if (pos_handle.dimension () == m_mesh.top_cell_dimension () - 1 ) {
301+ SimplexInversionInvariant<double > inv (pos_handle.mesh (), pos_handle.as <double >());
302+
303+ if (!inv.after ({}, m_mesh.get_all (m_mesh.top_simplex_type ()))) {
304+ logger ().error (" Mesh is not inversion free after simplicial embedding!" );
305+ }
306+ }
307+ }
308+ }
309+
310+
311+ } // namespace wmtk::components::internal
0 commit comments