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
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ int main (int argc, char** argv)
sync_obj);
}

// We'll need to update caches of subdomain ids too, to keep the
// mesh prepared.
mesh.cache_elem_data();

// Now we set the sources of the field: prism-shaped objects that are
// determined here by containing certain points:
auto p_pt_lctr = mesh.sub_point_locator();
Expand Down
2 changes: 1 addition & 1 deletion include/mesh/distributed_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class DistributedMesh : public UnstructuredMesh
* Shim to allow operator == (&) to behave like a virtual function
* without having to be one.
*/
virtual bool subclass_locally_equals (const MeshBase & other_mesh) const override;
virtual std::string_view subclass_first_difference_from (const MeshBase & other_mesh_base) const override;

/**
* Virtual copy-constructor, creates a copy of this mesh
Expand Down
39 changes: 36 additions & 3 deletions include/mesh/mesh_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class MeshBase : public ParallelObject
* ids).
*
* Though this method is non-virtual, its implementation calls the
* virtual function \p subclass_locally_equals() to test for
* virtual function \p subclass_first_difference_from() to test for
* equality of subclass-specific data as well.
*/
bool operator== (const MeshBase & other_mesh) const;
Expand All @@ -145,6 +145,14 @@ class MeshBase : public ParallelObject
return !(*this == other_mesh);
}

/**
* This behaves like libmesh_assert(*this == other_mesh), but gives
* a more useful accounting of the first difference found, if the
* assertion fails.
*/
void assert_equal_to (const MeshBase & other_mesh,
std::string_view failure_context) const;

/**
* This behaves the same as operator==, but only for the local and
* ghosted aspects of the mesh; i.e. operator== is true iff local
Expand Down Expand Up @@ -983,10 +991,17 @@ class MeshBase : public ParallelObject
*
* If \p assert_valid is left as true, then in dbg mode extensive
* consistency checking is performed before returning.
*
* If \p check_non_remote is set to false, then only sides which
* currently have remote neighbors are checked for possible local
* neighbors. This is intended to handle a corner case where
* ancestor neighbors are redistributed to a processor only by other
* processors who do not see that neighbor link.
*/
virtual void find_neighbors (const bool reset_remote_elements = false,
const bool reset_current_list = true,
const bool assert_valid = true) = 0;
const bool assert_valid = true,
const bool check_non_remote = true) = 0;

/**
* Removes any orphaned nodes, nodes not connected to any elements.
Expand Down Expand Up @@ -2061,6 +2076,18 @@ class MeshBase : public ParallelObject
has_reinit_ghosting_functors == other.has_reinit_ghosting_functors &&
has_boundary_id_sets == other.has_boundary_id_sets;
}

void libmesh_assert_consistent (const Parallel::Communicator & libmesh_dbg_var(comm)) {
libmesh_assert(comm.verify(is_partitioned));
libmesh_assert(comm.verify(has_synched_id_counts));
libmesh_assert(comm.verify(has_neighbor_ptrs));
libmesh_assert(comm.verify(has_cached_elem_data));
libmesh_assert(comm.verify(has_interior_parent_ptrs));
libmesh_assert(comm.verify(has_removed_remote_elements));
libmesh_assert(comm.verify(has_removed_orphaned_nodes));
libmesh_assert(comm.verify(has_reinit_ghosting_functors));
libmesh_assert(comm.verify(has_boundary_id_sets));
}
};

protected:
Expand Down Expand Up @@ -2101,14 +2128,20 @@ class MeshBase : public ParallelObject
* Shim to allow operator == (&) to behave like a virtual function
* without having to be one.
*/
virtual bool subclass_locally_equals (const MeshBase & other_mesh) const = 0;
virtual std::string_view subclass_first_difference_from (const MeshBase & other_mesh) const = 0;

/**
* Tests for equality of all elements and nodes in the mesh. Helper
* function for subclass_equals() in unstructured mesh subclasses.
*/
bool nodes_and_elements_equal(const MeshBase & other_mesh) const;

/**
*
*/
std::string_view first_difference_from(const MeshBase & other_mesh) const;


/**
* \returns A writable reference to the number of partitions.
*/
Expand Down
56 changes: 50 additions & 6 deletions include/mesh/mesh_tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,24 +394,35 @@ void clear_spline_nodes(MeshBase &);

/**
* A function for testing whether a mesh's cached is_prepared() setting
* is not a false positive. If the mesh is marked as not prepared, or
* if preparing the already-partitioned mesh (without any
* repartitioning or renumbering) does not change it, then we return
* true. If the mesh believes it is prepared but prepare_for_use()
* would change it, we return false.
* is not a false positive, and that its preparation() values are not
* false positives. If the mesh is marked as completely not prepared, or
* if preparing a already-prepared mesh (without any repartitioning or
* renumbering) or preparing after a complete_preparation() (likewise)
* does not change the mesh, then we return true. If the mesh believes it
* is prepared but prepare_for_use() would change it, or if the mesh
* believes it is partially prepared in a certain way but
* complete_preparation() does not completely prepare it, we return
* false.
*/
bool valid_is_prepared (const MeshBase & mesh);

///@{

/**
* The following functions, only available in builds with NDEBUG
* The following functions, no-ops except in builds with NDEBUG
* undefined, are for asserting internal consistency that we hope
* should never be broken in opt
*/

#ifndef NDEBUG

/**
* Like libmesh_assert(MeshTools::valid_is_prepared(mesh)), but
* provides more information on preparation incompleteness in case of
* an error.
*/
void libmesh_assert_valid_is_prepared (const MeshBase & mesh);

/**
* A function for testing that all DofObjects within a mesh
* have the same n_systems count
Expand Down Expand Up @@ -644,6 +655,39 @@ namespace Private {
void globally_renumber_nodes_and_elements (MeshBase &);
} // end namespace Private


// Declare inline no-ops for assertions with NDEBUG defined
#ifdef NDEBUG

inline void libmesh_assert_valid_is_prepared (const MeshBase &) {}

inline void libmesh_assert_equal_n_systems (const MeshBase &) {}

inline void libmesh_assert_old_dof_objects (const MeshBase &) {}

inline void libmesh_assert_valid_node_pointers (const MeshBase &) {}

inline void libmesh_assert_valid_remote_elems (const MeshBase &) {}

inline void libmesh_assert_valid_elem_ids (const MeshBase &) {}

inline void libmesh_assert_valid_amr_elem_ids (const MeshBase &) {}

inline void libmesh_assert_valid_amr_interior_parents (const MeshBase &) {}

inline void libmesh_assert_contiguous_dof_ids (const MeshBase &, unsigned int) {}

template <typename DofObjectSubclass>
inline void libmesh_assert_topology_consistent_procids (const MeshBase &) {}

inline void libmesh_assert_canonical_node_procids (const MeshBase &) {}

inline void libmesh_assert_valid_refinement_tree (const MeshBase &) {}

#endif // NDEBUG



} // end namespace MeshTools

} // namespace libMesh
Expand Down
2 changes: 1 addition & 1 deletion include/mesh/replicated_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class ReplicatedMesh : public UnstructuredMesh
* Shim to allow operator == (&) to behave like a virtual function
* without having to be one.
*/
virtual bool subclass_locally_equals (const MeshBase & other_mesh) const override;
virtual std::string_view subclass_first_difference_from (const MeshBase & other_mesh_base) const override;

/**
* Virtual copy-constructor, creates a copy of this mesh
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 @@ -294,7 +294,8 @@ class UnstructuredMesh : public MeshBase
*/
virtual void find_neighbors (const bool reset_remote_elements = false,
const bool reset_current_list = true,
const bool assert_valid = true) override;
const bool assert_valid = true,
const bool check_non_remote = true) override;

#ifdef LIBMESH_ENABLE_AMR
/**
Expand Down
56 changes: 32 additions & 24 deletions src/mesh/distributed_mesh.C
Original file line number Diff line number Diff line change
Expand Up @@ -95,48 +95,52 @@ MeshBase & DistributedMesh::assign(MeshBase && other_mesh)
return *this;
}

bool DistributedMesh::subclass_locally_equals(const MeshBase & other_mesh_base) const
std::string_view DistributedMesh::subclass_first_difference_from (const MeshBase & other_mesh_base) const
{
const DistributedMesh * dist_mesh_ptr =
dynamic_cast<const DistributedMesh *>(&other_mesh_base);
if (!dist_mesh_ptr)
return false;
return "DistributedMesh class";
const DistributedMesh & other_mesh = *dist_mesh_ptr;

if (_is_serial != other_mesh._is_serial ||
_is_serial_on_proc_0 != other_mesh._is_serial_on_proc_0 ||
_deleted_coarse_elements != other_mesh._deleted_coarse_elements ||
_n_nodes != other_mesh._n_nodes ||
_n_elem != other_mesh._n_elem ||
_max_node_id != other_mesh._max_node_id ||
_max_elem_id != other_mesh._max_elem_id ||
// We expect these things to change in a prepare_for_use();
// they're conceptually "mutable"...
#define CHECK_MEMBER(member_name) \
if (member_name != other_mesh.member_name) \
return #member_name;

CHECK_MEMBER(_is_serial);
CHECK_MEMBER(_is_serial_on_proc_0);
CHECK_MEMBER(_deleted_coarse_elements);
CHECK_MEMBER(_n_nodes);
CHECK_MEMBER(_n_elem);
CHECK_MEMBER(_max_node_id);
CHECK_MEMBER(_max_elem_id);
// We expect these things to change in a prepare_for_use();
// they're conceptually "mutable"...
/*
_next_free_local_node_id != other_mesh._next_free_local_node_id ||
_next_free_local_elem_id != other_mesh._next_free_local_elem_id ||
_next_free_unpartitioned_node_id != other_mesh._next_free_unpartitioned_node_id ||
_next_free_unpartitioned_elem_id != other_mesh._next_free_unpartitioned_elem_id ||
CHECK_MEMBER(_next_free_local_node_id);
CHECK_MEMBER(_next_free_local_elem_id);
CHECK_MEMBER(_next_free_unpartitioned_node_id);
CHECK_MEMBER(_next_free_unpartitioned_elem_id);
#ifdef LIBMESH_ENABLE_UNIQUE_ID
_next_unpartitioned_unique_id != other_mesh._next_unpartitioned_unique_id ||
CHECK_MEMBER(_next_unpartitioned_unique_id);
#endif
*/
!this->nodes_and_elements_equal(other_mesh))
return false;
if (!this->nodes_and_elements_equal(other_mesh))
return "nodes and/or elements";

if (_extra_ghost_elems.size() !=
other_mesh._extra_ghost_elems.size())
return false;
return "_extra_ghost_elems size";
for (auto & elem : _extra_ghost_elems)
{
libmesh_assert(this->query_elem_ptr(elem->id()) == elem);
const Elem * other_elem = other_mesh.query_elem_ptr(elem->id());
if (!other_elem ||
!other_mesh._extra_ghost_elems.count(const_cast<Elem *>(other_elem)))
return false;
return "_extra_ghost_elems entry";
}

return true;
return "";
}

DistributedMesh::~DistributedMesh ()
Expand Down Expand Up @@ -1037,9 +1041,13 @@ void DistributedMesh::redistribute ()

this->update_parallel_id_counts();

// We ought to still have valid neighbor links; we communicate
// them for newly-redistributed elements
// this->find_neighbors();
// We communicate valid neighbor links for newly-redistributed
// elements, but we may still have remote_elem links that should
// be corrected but whose correction wasn't communicated.
this->find_neighbors(/*reset_remote_elements*/ false,
/*reset_current_list*/ false /*non-default*/,
/*assert_valid*/ false,
/*check_non_remote*/ false /*non-default!*/);

// Is this necessary? If we are called from prepare_for_use(), this will be called
// anyway... but users can always call partition directly, in which case we do need
Expand Down
Loading