Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add simplicial embedding component. #850

Merged
merged 2 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions components/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ add_subdirectory("CDT/wmtk/components/CDT")

add_subdirectory("edge_insertion/wmtk/components/edge_insertion")

add_subdirectory("simplicial_embedding/wmtk/components/simplicial_embedding")

# add_component("export_cache")
# add_component("import_cache")
# add_component("mesh_info")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
set(COMPONENT_NAME simplicial_embedding)
add_component(${COMPONENT_NAME})

if(NOT ${WMTK_ENABLE_COMPONENT_${COMPONENT_NAME}})
return()
endif()

set(SRC_FILES
SimplicialEmbeddingOptions.hpp
internal/SimplicialEmbedding.hpp
internal/SimplicialEmbedding.cpp
simplicial_embedding.hpp
simplicial_embedding.cpp
)


target_sources(wmtk_${COMPONENT_NAME} PRIVATE ${SRC_FILES})

add_component_test(wmtk::${COMPONENT_NAME}
${PROJECT_SOURCE_DIR}/components/tests/simplicial_embedding/test_simplicial_embedding.cpp)
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <wmtk/Mesh.hpp>

namespace wmtk::components {

struct SimplicialEmbeddingOptions
{
/**
* All simplex dimensions must have an int64_t scalar attribute where the tags are stored.
*/
std::map<PrimitiveType, attribute::MeshAttributeHandle> tag_attributes;
/**
* The value that should be simplicially embedded.
*/
int64_t value;
/**
* Other attributes that should be processed with the default behavior.
*/
std::vector<attribute::MeshAttributeHandle> pass_through_attributes;
/**
* If false, this component forms a simplicial complex out of the tags, i.e., all faces of
* tagged simplices are also tagged.
*/
bool generate_simplicial_embedding = true;
};

} // namespace wmtk::components
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
#include "SimplicialEmbedding.hpp"

#include <wmtk/Scheduler.hpp>
#include <wmtk/invariants/SimplexInversionInvariant.hpp>
#include <wmtk/invariants/TodoInvariant.hpp>
#include <wmtk/operations/EdgeSplit.hpp>
#include <wmtk/operations/attribute_new/SplitNewAttributeStrategy.hpp>
#include <wmtk/operations/composite/TetCellSplit.hpp>
#include <wmtk/operations/composite/TriFaceSplit.hpp>
#include <wmtk/simplex/faces.hpp>
#include <wmtk/simplex/faces_single_dimension.hpp>
#include <wmtk/utils/Logger.hpp>
#include <wmtk/utils/primitive_range.hpp>

#include <deque>

namespace wmtk::components::internal {

namespace {

class TagAttribute
{
public:
wmtk::attribute::Accessor<int64_t> m_accessor;
PrimitiveType m_ptype;
int64_t m_val;

TagAttribute(
Mesh& m,
const attribute::MeshAttributeHandle& attribute,
PrimitiveType ptype,
int64_t val)
: m_accessor(m.create_accessor<int64_t>(attribute))
, m_ptype(ptype)
, m_val(val)
{}

TagAttribute(TagAttribute&) = delete;
};
} // namespace

SimplicialEmbedding::SimplicialEmbedding(
Mesh& mesh,
const std::vector<attribute::MeshAttributeHandle>& label_attributes,
const int64_t& value,
const std::vector<attribute::MeshAttributeHandle>& pass_through_attributes)
: m_mesh(mesh)
, m_label_attributes(label_attributes)
, m_value(value)
, m_pass_through_attributes(pass_through_attributes)
{}

void SimplicialEmbedding::regularize_tags(bool generate_simplicial_embedding)
{
using namespace operations;

std::vector<attribute::MeshAttributeHandle> todo_handles;
for (size_t i = 0; i < m_label_attributes.size(); ++i) {
attribute::MeshAttributeHandle todo_handle =
m_mesh.register_attribute<int64_t>("todo", m_label_attributes[i].primitive_type(), 1);
todo_handles.emplace_back(todo_handle);
}

std::deque<TagAttribute> tag_attributes;
for (size_t i = 0; i < m_label_attributes.size(); ++i) {
tag_attributes.emplace_back(
m_mesh,
m_label_attributes[i],
m_label_attributes[i].primitive_type(),
m_value);
}

// make sure tag vector is complete and sorted in descending order
for (size_t i = 0; i < tag_attributes.size(); ++i) {
TagAttribute& a = tag_attributes[i];
if (get_primitive_type_id(a.m_ptype) != m_mesh.top_cell_dimension() - i) {
log_and_throw_error("Tag array must be sorted in descending order starting with "

Check warning on line 77 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L77

Added line #L77 was not covered by tests
"the top simplex type up to vertex.");
}
}


// tag all faces of attributes
for (size_t attr_it = 0; attr_it < tag_attributes.size() - 1; ++attr_it) {
const TagAttribute& ta = tag_attributes[attr_it];
for (const Tuple& t : m_mesh.get_all(ta.m_ptype)) {
if (ta.m_accessor.const_scalar_attribute(t) != ta.m_val) {
continue; // t is not tagged
}

const PrimitiveType face_ptype =
get_primitive_type_from_id(get_primitive_type_id(ta.m_ptype) - 1);
const auto faces = simplex::faces_single_dimension_tuples(
m_mesh,
simplex::Simplex(m_mesh, ta.m_ptype, t),
face_ptype);

TagAttribute& face_ta = tag_attributes[attr_it + 1];
for (const Tuple& f : faces) {
face_ta.m_accessor.scalar_attribute(f) = face_ta.m_val;
}
}
}

if (!generate_simplicial_embedding) {
return;

Check warning on line 106 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L106

Added line #L106 was not covered by tests
}

// check for inversions
if (m_mesh.has_attribute<double>("vertices", PrimitiveType::Vertex)) {
const auto pos_handle =
m_mesh.get_attribute_handle<double>("vertices", PrimitiveType::Vertex);
if (pos_handle.dimension() == m_mesh.top_cell_dimension() - 1) {
SimplexInversionInvariant<double> inv(pos_handle.mesh(), pos_handle.as<double>());

Check warning on line 114 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L114

Added line #L114 was not covered by tests

if (!inv.after({}, m_mesh.get_all(m_mesh.top_simplex_type()))) {
logger().error("Mesh is not inversion free BEFORE simplicial embedding!");

Check warning on line 117 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L117

Added line #L117 was not covered by tests
}
}

Check warning on line 119 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L119

Added line #L119 was not covered by tests
}

// split untagged simplices that have only tagged faces
for (size_t attr_it = 0; attr_it < tag_attributes.size() - 1;) {
const TagAttribute& ta = tag_attributes[attr_it];

attribute::MeshAttributeHandle& todo_handle = todo_handles[attr_it];
auto todo_acc = m_mesh.create_accessor<int64_t>(todo_handle);

int64_t count_todos = 0;
for (const Tuple& t : m_mesh.get_all(ta.m_ptype)) {
if (ta.m_accessor.const_scalar_attribute(t) == ta.m_val) {
continue; // t is tagged
}

const PrimitiveType face_ptype =
get_primitive_type_from_id(get_primitive_type_id(ta.m_ptype) - 1);
const auto faces = simplex::faces_single_dimension_tuples(
m_mesh,
simplex::Simplex(m_mesh, ta.m_ptype, t),
face_ptype);

const TagAttribute& face_ta = tag_attributes[attr_it + 1];

bool all_faces_are_tagged = true;

for (const Tuple& f : faces) {
if (face_ta.m_accessor.const_scalar_attribute(f) != face_ta.m_val) {
all_faces_are_tagged = false;
break;
}
}

if (all_faces_are_tagged) {
todo_acc.scalar_attribute(t) = 1;
++count_todos;
}
}

// split simplex because all its faces are tagged
Scheduler scheduler;
int64_t count_done = 0;
switch (ta.m_ptype) {
case PrimitiveType::Edge: { // edge split
EdgeSplit op_split(m_mesh);
op_split.add_invariant(std::make_shared<TodoInvariant>(
m_mesh,
std::get<attribute::TypedAttributeHandle<int64_t>>(todo_handle.handle())));

// todos
for (const attribute::MeshAttributeHandle& h : todo_handles) {
op_split.set_new_attribute_strategy(
h,
SplitBasicStrategy::None,
SplitRibBasicStrategy::None);
}
// labels
for (const attribute::MeshAttributeHandle& h : m_label_attributes) {
op_split.set_new_attribute_strategy(
h,
SplitBasicStrategy::Copy,
SplitRibBasicStrategy::None);
}
// pass_through
for (const auto& attr : m_pass_through_attributes) {
op_split.set_new_attribute_strategy(attr);
}

logger().info("split {} edges", count_todos);
while (true) {
const auto stats = scheduler.run_operation_on_all(op_split);
count_done += stats.number_of_successful_operations();
if (stats.number_of_successful_operations() == 0) {
break;
}
}

break;
}
case PrimitiveType::Triangle: { // face split
composite::TriFaceSplit op_face_split(m_mesh);
op_face_split.add_invariant(std::make_shared<TodoInvariant>(
m_mesh,
std::get<attribute::TypedAttributeHandle<int64_t>>(todo_handle.handle())));

// todos
for (const attribute::MeshAttributeHandle& h : todo_handles) {
op_face_split.split().set_new_attribute_strategy(
h,
SplitBasicStrategy::None,
SplitRibBasicStrategy::None);
op_face_split.collapse().set_new_attribute_strategy(h, CollapseBasicStrategy::None);
}
// labels
for (const attribute::MeshAttributeHandle& h : m_label_attributes) {
op_face_split.split().set_new_attribute_strategy(
h,
SplitBasicStrategy::Copy,
SplitRibBasicStrategy::None);
op_face_split.collapse().set_new_attribute_strategy(h, CollapseBasicStrategy::None);
}
// pass_through
for (const auto& attr : m_pass_through_attributes) {
op_face_split.split().set_new_attribute_strategy(attr);
op_face_split.collapse().set_new_attribute_strategy(
attr,
CollapseBasicStrategy::None);
}


logger().info("split {} faces", count_todos);
while (true) {
const auto stats = scheduler.run_operation_on_all(op_face_split);
count_done += stats.number_of_successful_operations();
if (stats.number_of_successful_operations() == 0) {
break;
}
}

break;
}
case PrimitiveType::Tetrahedron: { // tet split
composite::TetCellSplit op_tet_split(m_mesh);
op_tet_split.add_invariant(std::make_shared<TodoInvariant>(

Check warning on line 243 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L241-L243

Added lines #L241 - L243 were not covered by tests
m_mesh,
std::get<attribute::TypedAttributeHandle<int64_t>>(todo_handle.handle())));

Check warning on line 245 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L245

Added line #L245 was not covered by tests

// todos
for (const attribute::MeshAttributeHandle& h : todo_handles) {
op_tet_split.split().set_new_attribute_strategy(

Check warning on line 249 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L249

Added line #L249 was not covered by tests
h,
SplitBasicStrategy::None,
SplitRibBasicStrategy::None);
op_tet_split.collapse().set_new_attribute_strategy(h, CollapseBasicStrategy::None);

Check warning on line 253 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L251-L253

Added lines #L251 - L253 were not covered by tests
}
// labels
for (const attribute::MeshAttributeHandle& h : m_label_attributes) {
op_tet_split.split().set_new_attribute_strategy(

Check warning on line 257 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L257

Added line #L257 was not covered by tests
h,
SplitBasicStrategy::Copy,
SplitRibBasicStrategy::None);
op_tet_split.collapse().set_new_attribute_strategy(h, CollapseBasicStrategy::None);

Check warning on line 261 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L259-L261

Added lines #L259 - L261 were not covered by tests
}
// pass_through
for (const auto& attr : m_pass_through_attributes) {
op_tet_split.split().set_new_attribute_strategy(attr);
op_tet_split.collapse().set_new_attribute_strategy(

Check warning on line 266 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L265-L266

Added lines #L265 - L266 were not covered by tests
attr,
CollapseBasicStrategy::None);

Check warning on line 268 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L268

Added line #L268 was not covered by tests
}

logger().info("split {} tetrahedra", count_todos);
while (true) {
const auto stats = scheduler.run_operation_on_all(op_tet_split);
count_done += stats.number_of_successful_operations();

Check warning on line 274 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L271-L274

Added lines #L271 - L274 were not covered by tests
if (stats.number_of_successful_operations() == 0) {
break;
}
}

Check warning on line 278 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L278

Added line #L278 was not covered by tests

break;
}
default: log_and_throw_error("unknown primitive type"); break;

Check warning on line 282 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L280-L282

Added lines #L280 - L282 were not covered by tests
}

if (count_done == count_todos) {
++attr_it;
} else {
logger().info(

Check warning on line 288 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L288

Added line #L288 was not covered by tests
"{} remain. Regularize same primitive type once more.",
count_todos - count_done);

Check warning on line 290 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L290

Added line #L290 was not covered by tests
}
}

// check for inversions
if (m_mesh.has_attribute<double>("vertices", PrimitiveType::Vertex)) {
const auto pos_handle =
m_mesh.get_attribute_handle<double>("vertices", PrimitiveType::Vertex);
SimplexInversionInvariant<double> inv(pos_handle.mesh(), pos_handle.as<double>());

if (pos_handle.dimension() == m_mesh.top_cell_dimension() - 1) {
SimplexInversionInvariant<double> inv(pos_handle.mesh(), pos_handle.as<double>());

Check warning on line 301 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L301

Added line #L301 was not covered by tests

if (!inv.after({}, m_mesh.get_all(m_mesh.top_simplex_type()))) {
logger().error("Mesh is not inversion free after simplicial embedding!");

Check warning on line 304 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L304

Added line #L304 was not covered by tests
}
}

Check warning on line 306 in components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp

View check run for this annotation

Codecov / codecov/patch

components/simplicial_embedding/wmtk/components/simplicial_embedding/internal/SimplicialEmbedding.cpp#L306

Added line #L306 was not covered by tests
}
}


} // namespace wmtk::components::internal
Loading
Loading