Skip to content
Open
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
15 changes: 14 additions & 1 deletion include/mesh/mesh_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,13 @@ class MeshBase : public ParallelObject
void allow_find_neighbors(bool allow) { _skip_find_neighbors = !allow; }
bool allow_find_neighbors() const { return !_skip_find_neighbors; }

/**
* If \p false is passed then this mesh will no longer work to detect
* interior parents when being prepared for use
*/
void allow_detect_interior_parents(bool allow) { _skip_detect_interior_parents = !allow; }
bool allow_detect_interior_parents() const { return !_skip_detect_interior_parents; }

/**
* If false is passed in then this mesh will no longer have remote
* elements deleted when being prepared for use; i.e. even a
Expand Down Expand Up @@ -1390,7 +1397,8 @@ class MeshBase : public ParallelObject
virtual void read (const std::string & name,
void * mesh_data=nullptr,
bool skip_renumber_nodes_and_elements=false,
bool skip_find_neighbors=false) = 0;
bool skip_find_neighbors=false,
bool skip_detect_interior_parents=false) = 0;
virtual void write (const std::string & name) const = 0;

/**
Expand Down Expand Up @@ -1986,6 +1994,11 @@ class MeshBase : public ParallelObject
*/
bool _skip_find_neighbors;

/**
* If this is \p true then we will skip \p detect_interior_parents in \p prepare_for_use
*/
bool _skip_detect_interior_parents;

/**
* If this is false then even on DistributedMesh remote elements
* will not be deleted during mesh preparation.
Expand Down
3 changes: 2 additions & 1 deletion include/mesh/unstructured_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ class UnstructuredMesh : public MeshBase
virtual void read (const std::string & name,
void * mesh_data=nullptr,
bool skip_renumber_nodes_and_elements=false,
bool skip_find_neighbors=false) override;
bool skip_find_neighbors=false,
bool skip_detect_interior_parents=false) override;
/**
* Write the file specified by \p name. Attempts to figure out the
* proper method by the file extension.
Expand Down
1 change: 1 addition & 0 deletions src/mesh/distributed_mesh.C
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ DistributedMesh::DistributedMesh (const MeshBase & other_mesh) :
this->copy_nodes_and_elements(other_mesh, true);

this->allow_find_neighbors(other_mesh.allow_find_neighbors());
this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());
this->allow_renumbering(other_mesh.allow_renumbering());
this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
this->skip_partitioning(other_mesh.skip_partitioning());
Expand Down
71 changes: 67 additions & 4 deletions src/mesh/mesh_base.C
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ MeshBase::MeshBase (const Parallel::Communicator & comm_in,
_skip_all_partitioning(libMesh::on_command_line("--skip-partitioning")),
_skip_renumber_nodes_and_elements(false),
_skip_find_neighbors(false),
_skip_detect_interior_parents(false),
_allow_remote_element_removal(true),
_allow_node_and_elem_unique_id_overlap(false),
_spatial_dimension(d),
Expand Down Expand Up @@ -114,6 +115,7 @@ MeshBase::MeshBase (const MeshBase & other_mesh) :
_skip_all_partitioning(other_mesh._skip_all_partitioning),
_skip_renumber_nodes_and_elements(other_mesh._skip_renumber_nodes_and_elements),
_skip_find_neighbors(other_mesh._skip_find_neighbors),
_skip_detect_interior_parents(other_mesh._skip_detect_interior_parents),
_allow_remote_element_removal(other_mesh._allow_remote_element_removal),
_allow_node_and_elem_unique_id_overlap(other_mesh._allow_node_and_elem_unique_id_overlap),
_elem_dims(other_mesh._elem_dims),
Expand Down Expand Up @@ -201,6 +203,7 @@ MeshBase& MeshBase::operator= (MeshBase && other_mesh)
_skip_all_partitioning = other_mesh.skip_partitioning();
_skip_renumber_nodes_and_elements = !(other_mesh.allow_renumbering());
_skip_find_neighbors = !(other_mesh.allow_find_neighbors());
_skip_detect_interior_parents = !(other_mesh.allow_detect_interior_parents());
_allow_remote_element_removal = other_mesh.allow_remote_element_removal();
_allow_node_and_elem_unique_id_overlap = other_mesh.allow_node_and_elem_unique_id_overlap();
_block_id_to_name = std::move(other_mesh._block_id_to_name);
Expand Down Expand Up @@ -305,6 +308,8 @@ bool MeshBase::locally_equals (const MeshBase & other_mesh) const
return false;
if (_skip_find_neighbors != other_mesh._skip_find_neighbors)
return false;
if (_skip_detect_interior_parents != other_mesh._skip_detect_interior_parents)
return false;
if (_allow_remote_element_removal != other_mesh._allow_remote_element_removal)
return false;
if (_allow_node_and_elem_unique_id_overlap != other_mesh._allow_node_and_elem_unique_id_overlap)
Expand Down Expand Up @@ -896,7 +901,8 @@ void MeshBase::prepare_for_use ()

// Search the mesh for elements that have a neighboring element
// of dim+1 and set that element as the interior parent
this->detect_interior_parents();
if (!_skip_detect_interior_parents)
this->detect_interior_parents();

// Fix up node unique ids in case mesh generation code didn't take
// exceptional care to do so.
Expand Down Expand Up @@ -1908,6 +1914,50 @@ void MeshBase::detect_interior_parents()
if (this->elem_dimensions().size() == 1)
return;

// In this function we find only +1 dimensional interior parents,
// (so, for a given element el, the interior parent p must satisfy p.dim() == el.dim() + 1).
// Therefore, we can avoid checking the existence of interior parents
// for all those elements el such there there is no p with p.dim() == el.dim() + 1.
// We store whether to skip any given dimension in the construction of interior parents
// inside the vector in dimensions_to_skip_for_interior_parents.
std::vector<bool> skip_dimension_for_interior_parents(LIBMESH_DIM+1); // all false by default
skip_dimension_for_interior_parents.back() = true;

// Moreover, in the following, we will build a node-to-elem map.
// It is among the elems of this map that we will look for interior parents.
// Therefore, we can skip all elems p such that there is no el with el.dim() == p.dim() - 1.
// We store whether to skip any given dimension in the construction of the node-to-elem map
// in the vector skip_dimensions_for_node_to_el_map.
std::vector<bool> skip_dimensions_for_node_to_el_map(LIBMESH_DIM+1); // all false by default
skip_dimensions_for_node_to_el_map[*this->elem_dimensions().begin()] = true;

// We also create a flag to know if all dimensions should be skipped,
// and if we should therefore return early.
bool skip_all_dimensions = true;

// Fill dimensions_to_skip_for_interior_parents and dimensions_to_skip_for_node_to_el_map.
{
const std::set<unsigned char> & elem_dimensions = this->elem_dimensions();

auto it = elem_dimensions.begin();
auto next = std::next(it);

for (; next != elem_dimensions.end(); ++it, ++next)
{
if (*it + 1 != *next) // note: elem_dimensions is already sorted
{
skip_dimension_for_interior_parents[*it] = true;
skip_dimensions_for_node_to_el_map[*next] = true;
}
else if (!skip_dimension_for_interior_parents[*it])
skip_all_dimensions = false;
}
}

// There is nothing to do if all dimensions should be skipped.
if (skip_all_dimensions)
return;

// Do we have interior parent pointers going to a different mesh?
// If so then we'll still check to make sure that's the only place
// they go, so we can libmesh_not_implemented() if not.
Expand All @@ -1918,6 +1968,10 @@ void MeshBase::detect_interior_parents()

for (const auto & elem : this->element_ptr_range())
{
// Ignore element if it cannot be interior parent of any other elem.
if (skip_dimensions_for_node_to_el_map[elem->dim()])
continue;

// Populating the node_to_elem map, same as MeshTools::build_nodes_to_elem_map
for (auto n : make_range(elem->n_vertices()))
{
Expand All @@ -1930,8 +1984,9 @@ void MeshBase::detect_interior_parents()
// Automatically set interior parents
for (const auto & element : this->element_ptr_range())
{
// Ignore an 3D element or an element that already has an interior parent
if (element->dim()>=LIBMESH_DIM || element->interior_parent())
// Ignore elements with dimensions to skip
// or elements that already have an interior parent.
if (skip_dimension_for_interior_parents[element->dim()] || element->interior_parent())
continue;

// Start by generating a SET of elements that are dim+1 to the current
Expand All @@ -1944,7 +1999,15 @@ void MeshBase::detect_interior_parents()

for (auto n : make_range(element->n_vertices()))
{
std::vector<dof_id_type> & element_ids = node_to_elem[element->node_id(n)];
auto it = node_to_elem.find(element->node_id(n));
// Check at first that this node is not isolated.
if (it == node_to_elem.end())
{
found_interior_parents = false;
break;
}

std::vector<dof_id_type> & element_ids = it->second;
for (const auto & eid : element_ids)
if (this->elem_ref(eid).dim() == element->dim()+1)
neighbors[n].insert(eid);
Expand Down
1 change: 1 addition & 0 deletions src/mesh/replicated_mesh.C
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ ReplicatedMesh::ReplicatedMesh (const MeshBase & other_mesh) :
this->copy_nodes_and_elements(other_mesh, true);

this->allow_find_neighbors(other_mesh.allow_find_neighbors());
this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());
this->allow_renumbering(other_mesh.allow_renumbering());
this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
this->skip_partitioning(other_mesh.skip_partitioning());
Expand Down
12 changes: 11 additions & 1 deletion src/mesh/unstructured_mesh.C
Original file line number Diff line number Diff line change
Expand Up @@ -834,9 +834,11 @@ void UnstructuredMesh::copy_nodes_and_elements(const MeshBase & other_mesh,
const bool allowed_renumbering = this->allow_renumbering();
const bool allowed_find_neighbors = this->allow_find_neighbors();
const bool allowed_elem_removal = this->allow_remote_element_removal();
const bool allowed_detect_detect_interior_parents = this->allow_detect_interior_parents();
this->allow_renumbering(false);
this->allow_remote_element_removal(false);
this->allow_find_neighbors(!skip_find_neighbors);
this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());

// We should generally be able to skip *all* partitioning here
// because we're only adding one already-consistent mesh to another.
Expand All @@ -848,6 +850,7 @@ void UnstructuredMesh::copy_nodes_and_elements(const MeshBase & other_mesh,

//But in the long term, don't change our policies.
this->allow_find_neighbors(allowed_find_neighbors);
this->allow_detect_interior_parents(allowed_detect_detect_interior_parents);
this->allow_renumbering(allowed_renumbering);
this->allow_remote_element_removal(allowed_elem_removal);
this->skip_partitioning(skipped_partitioning);
Expand Down Expand Up @@ -1272,7 +1275,8 @@ void UnstructuredMesh::find_neighbors (const bool reset_remote_elements,
void UnstructuredMesh::read (const std::string & name,
void *,
bool skip_renumber_nodes_and_elements,
bool skip_find_neighbors)
bool skip_find_neighbors,
bool skip_detect_interior_parents)
{
// Set the skip_renumber_nodes_and_elements flag on all processors
// if necessary.
Expand All @@ -1294,9 +1298,15 @@ void UnstructuredMesh::read (const std::string & name,

// Done reading the mesh. Now prepare it for use.
const bool old_allow_find_neighbors = this->allow_find_neighbors();
const bool old_allow_detect_interior_parents = this->allow_detect_interior_parents();

this->allow_find_neighbors(!skip_find_neighbors);
this->allow_detect_interior_parents(!skip_detect_interior_parents);

this->prepare_for_use();

this->allow_find_neighbors(old_allow_find_neighbors);
this->allow_detect_interior_parents(old_allow_detect_interior_parents);
}


Expand Down