diff --git a/include/mesh/mesh_base.h b/include/mesh/mesh_base.h index b1c40a44ee..f0e659c640 100644 --- a/include/mesh/mesh_base.h +++ b/include/mesh/mesh_base.h @@ -165,7 +165,7 @@ class MeshBase : public ParallelObject virtual ~MeshBase (); /** - * A partitioner to use at each prepare_for_use() + * A partitioner to use at each partitioning */ virtual std::unique_ptr & partitioner() { return _partitioner; } @@ -194,7 +194,7 @@ class MeshBase : public ParallelObject * No Node is removed from the mesh, however even NodeElem elements * are deleted, so the remaining Nodes will be considered "unused" * and cleared unless they are reconnected to new elements before - * the next \p prepare_for_use() + * the next preparation step. * * This does not affect BoundaryInfo data; any boundary information * associated elements should already be cleared. @@ -202,17 +202,134 @@ class MeshBase : public ParallelObject virtual void clear_elems () = 0; /** - * \returns \p true if the mesh has been prepared via a call - * to \p prepare_for_use, \p false otherwise. + * \returns \p true if the mesh is marked as having undergone all of + * the preparation done in a call to \p prepare_for_use, \p false + * otherwise. */ bool is_prepared () const - { return _is_prepared; } + { return _preparation; } /** - * Tells this we have done some operation where we should no longer consider ourself prepared + * \returns the \p Preparation structure with details about in what + * ways \p this mesh is currently prepared or unprepared. This + * structure may change in the future when cache designs change. + */ + struct Preparation; + + Preparation preparation () const + { return _preparation; } + + /** + * Tells this we have done some operation where we should no longer + * consider ourself prepared. This is a very coarse setting; it is + * generally more efficient to mark finer-grained settings instead. */ void set_isnt_prepared() - { _is_prepared = false; } + { _preparation = false; } + + /** + * Tells this we have done some operation creating unpartitioned + * elements. + * + * User code which adds elements to this mesh must either partition + * them too or call this method. + */ + void set_isnt_partitioned() + { _preparation.is_partitioned = false; } + + /** + * Tells this we have done some operation (e.g. adding objects to a + * distributed mesh on one processor only) which can lose + * synchronization of id counts. + * + * User code which does distributed additions of nodes or elements + * must call either this method or \p update_parallel_id_counts(). + */ + void set_hasnt_synched_id_counts() + { _preparation.has_synched_id_counts = false; } + + /** + * Tells this we have done some operation (e.g. adding elements + * without setting their neighbor pointers, or adding disjoint + * neighbor boundary pairs) which requires neighbor pointers to be + * determined later. + * + * User code which adds new elements to this mesh must call this + * function or manually set neighbor pointer from and to those + * elements. + */ + void set_hasnt_neighbor_ptrs() + { _preparation.has_neighbor_ptrs = false; } + + /** + * Tells this we have done some operation (e.g. adding elements with + * a new dimension or subdomain value) which may invalidate cached + * summaries of element data. + * + * User code which adds new elements to this mesh must call this + * function. + */ + void set_hasnt_cached_elem_data() + { _preparation.has_cached_elem_data = false; } + + /** + * Tells this we have done some operation (e.g. refining elements + * with interior parents) which requires interior parent pointers to + * be found later. + * + * Most user code will not need to call this method; any user code + * that manipulates interior parents or their boundary elements may + * be an exception. + */ + void set_hasnt_interior_parent_ptrs() + { _preparation.has_interior_parent_ptrs = false; } + + /** + * Tells this we have done some operation (e.g. repartitioning) + * which may have left elements as ghosted which on a distributed + * mesh should be remote. + * + * User code should probably never need to use this; we can set it + * in Partitioner. Any user code which manually repartitions + * elements on distributed meshes may need to call this manually, in + * addition to manually communicating elements with newly-created + * ghosting requirements. + */ + void set_hasnt_removed_remote_elements() + { _preparation.has_removed_remote_elements = false; } + + /** + * Tells this we have done some operation (e.g. coarsening) + * which may have left orphaned nodes in need of removal. + * + * Most user code should probably never need to use this; we can set + * it in MeshRefinement. User code which deletes elements without + * carefully deleting orphaned nodes should call this manually. + */ + void set_hasnt_removed_orphaned_nodes() + { _preparation.has_removed_orphaned_nodes = false; } + + /** + * Tells this we have done some operation (e.g. adding or removing + * elements) which may require a reinit() of custom ghosting + * functors. + * + * User code which adds or removes elements should call this method. + * User code which moves nodes ... should probably call this method, + * in case ghosting functors depending on position exist? + */ + void hasnt_reinit_ghosting_functors() + { _preparation.has_reinit_ghosting_functors = false; } + + /** + * Tells this we have done some operation which may have invalidated + * our cached boundary id sets. + * + * User code which removes elements, or which adds or removes + * boundary entries, should call this method. + */ + void set_hasnt_boundary_id_sets() + { _preparation.has_boundary_id_sets = false; } /** * \returns \p true if all elements and nodes of the mesh @@ -260,7 +377,9 @@ class MeshBase : public ParallelObject * except for "ghosts" which touch a local element, and deletes * all nodes which are not part of a local or ghost element */ - virtual void delete_remote_elements () {} + virtual void delete_remote_elements () { + _preparation.has_removed_remote_elements = true; + } /** * Loops over ghosting functors and calls mesh_reinit() @@ -400,16 +519,17 @@ class MeshBase : public ParallelObject * higher dimensions is checked. Also, x-z and y-z planar meshes are * considered to have spatial dimension == 3. * - * The spatial dimension is updated during prepare_for_use() based + * The spatial dimension is updated during mesh preparation based * on the dimensions of the various elements present in the Mesh, - * but is *never automatically decreased* by this function. + * but is *never automatically decreased*. * * For example, if the user calls set_spatial_dimension(2) and then * later inserts 3D elements into the mesh, * Mesh::spatial_dimension() will return 3 after the next call to - * prepare_for_use(). On the other hand, if the user calls - * set_spatial_dimension(3) and then inserts only x-aligned 1D - * elements into the Mesh, mesh.spatial_dimension() will remain 3. + * prepare_for_use() or complete_preparation(). On the other hand, + * if the user calls set_spatial_dimension(3) and then inserts only + * x-aligned 1D elements into the Mesh, mesh.spatial_dimension() + * will remain 3. */ unsigned int spatial_dimension () const; @@ -742,7 +862,7 @@ class MeshBase : public ParallelObject * To ensure a specific element id, call e->set_id() before adding it; * only do this in parallel if you are manually keeping ids consistent. * - * Users should call MeshBase::prepare_for_use() after elements are + * Users should call MeshBase::complete_preparation() after elements are * added to and/or deleted from the mesh. */ virtual Elem * add_elem (Elem * e) = 0; @@ -761,7 +881,7 @@ class MeshBase : public ParallelObject * Insert elem \p e to the element array, preserving its id * and replacing/deleting any existing element with the same id. * - * Users should call MeshBase::prepare_for_use() after elements are + * Users should call MeshBase::complete_preparation() after elements are * added to and/or deleted from the mesh. */ virtual Elem * insert_elem (Elem * e) = 0; @@ -780,8 +900,8 @@ class MeshBase : public ParallelObject * Removes element \p e from the mesh. This method must be * implemented in derived classes in such a way that it does not * invalidate element iterators. Users should call - * MeshBase::prepare_for_use() after elements are added to and/or - * deleted from the mesh. + * MeshBase::complete_preparation() after elements are added to + * and/or deleted from the mesh. * * \note Calling this method may produce isolated nodes, i.e. nodes * not connected to any element. @@ -848,7 +968,7 @@ class MeshBase : public ParallelObject /** * Removes any orphaned nodes, nodes not connected to any elements. - * Typically done automatically in prepare_for_use + * Typically done automatically in a preparation step */ void remove_orphaned_nodes (); @@ -1122,12 +1242,26 @@ class MeshBase : public ParallelObject const std::vector * default_values = nullptr); /** - * Prepare a newly ecreated (or read) mesh for use. - * This involves 4 steps: - * 1.) call \p find_neighbors() - * 2.) call \p partition() - * 3.) call \p renumber_nodes_and_elements() - * 4.) call \p cache_elem_data() + * Prepare a newly created (or read) mesh for use. + * This involves several steps: + * 1.) renumbering (if enabled) + * 2.) removing any orphaned nodes + * 3.) updating parallel id counts + * 4.) finding neighbor links + * 5.) caching summarized element data + * 6.) finding interior parent links + * 7.) clearing any old point locator + * 8.) calling reinit() on ghosting functors + * 9.) repartitioning (if enabled) + * 10.) removing any remote elements (if enabled) + * 11.) regenerating summarized boundary id sets + * + * For backwards compatibility, prepare_for_use() performs *all* those + * steps, regardless of the official preparation() state of the + * mesh. In codes which have maintained a valid preparation() state + * via methods such as set_hasnt_synched_id_counts(), calling + * complete_preparation() will result in a fully-prepared mesh at + * less cost. * * The argument to skip renumbering is now deprecated - to prevent a * mesh from being renumbered, set allow_renumbering(false). The argument to skip @@ -1144,6 +1278,15 @@ class MeshBase : public ParallelObject #endif // LIBMESH_ENABLE_DEPRECATED void prepare_for_use (); + /* + * Prepare a newly created or modified mesh for use. + * + * Unlike \p prepare_for_use(), \p complete_preparation() performs + * *only* those preparatory steps that have been marked as + * necessary in the MeshBase::Preparation state. + */ + void complete_preparation(); + /** * Call the default partitioner (currently \p metis_partition()). */ @@ -1844,6 +1987,58 @@ class MeshBase : public ParallelObject const boundary_id_type b2); #endif + /** + * Flags indicating in what ways a mesh has been prepared for use. + */ + struct Preparation { + bool is_partitioned = false, + has_synched_id_counts = false, + has_neighbor_ptrs = false, + has_cached_elem_data = false, + has_interior_parent_ptrs = false, + has_removed_remote_elements = false, + has_removed_orphaned_nodes = false, + has_boundary_id_sets = false, + has_reinit_ghosting_functors = false; + + operator bool() const { + return is_partitioned && + has_synched_id_counts && + has_neighbor_ptrs && + has_cached_elem_data && + has_interior_parent_ptrs && + has_removed_remote_elements && + has_removed_orphaned_nodes && + has_reinit_ghosting_functors && + has_boundary_id_sets; + } + + Preparation & operator= (bool set_all) { + is_partitioned = set_all; + has_synched_id_counts = set_all; + has_neighbor_ptrs = set_all; + has_cached_elem_data = set_all; + has_interior_parent_ptrs = set_all; + has_removed_remote_elements = set_all; + has_removed_orphaned_nodes = set_all; + has_reinit_ghosting_functors = set_all; + has_boundary_id_sets = set_all; + + return *this; + } + + bool operator== (const Preparation & other) { + return is_partitioned == other.is_partitioned && + has_synched_id_counts == other.has_synched_id_counts && + has_neighbor_ptrs == other.has_neighbor_ptrs && + has_cached_elem_data == other.has_cached_elem_data && + has_interior_parent_ptrs == other.has_interior_parent_ptrs && + has_removed_remote_elements == other.has_removed_remote_elements && + has_removed_orphaned_nodes == other.has_removed_orphaned_nodes && + has_reinit_ghosting_functors == other.has_reinit_ghosting_functors && + has_boundary_id_sets == other.has_boundary_id_sets; + } + }; protected: @@ -1923,9 +2118,9 @@ class MeshBase : public ParallelObject unsigned char _default_mapping_data; /** - * Flag indicating if the mesh has been prepared for use. + * Flags indicating in what ways \p this mesh has been prepared. */ - bool _is_prepared; + Preparation _preparation; /** * A \p PointLocator class for this mesh. diff --git a/src/mesh/boundary_info.C b/src/mesh/boundary_info.C index b1878f510d..a50323ed7e 100644 --- a/src/mesh/boundary_info.C +++ b/src/mesh/boundary_info.C @@ -435,6 +435,8 @@ void BoundaryInfo::synchronize_global_id_set() libmesh_assert(_mesh); if (!_mesh->is_serial()) _communicator.set_union(_global_boundary_ids); + + _mesh->_preparation.has_boundary_id_sets = true; } diff --git a/src/mesh/distributed_mesh.C b/src/mesh/distributed_mesh.C index 24e352322d..5a15a04814 100644 --- a/src/mesh/distributed_mesh.C +++ b/src/mesh/distributed_mesh.C @@ -205,7 +205,7 @@ DistributedMesh::DistributedMesh (const MeshBase & other_mesh) : this->copy_constraint_rows(other_mesh); - this->_is_prepared = other_mesh.is_prepared(); + this->_preparation = other_mesh.preparation(); auto & this_boundary_info = this->get_boundary_info(); const auto & other_boundary_info = other_mesh.get_boundary_info(); @@ -291,6 +291,8 @@ void DistributedMesh::update_parallel_id_counts() ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) * (this->n_processors() + 1) + this->processor_id(); #endif + + this->_preparation.has_synched_id_counts = true; } @@ -1611,6 +1613,8 @@ void DistributedMesh::renumber_nodes_and_elements () } } + this->_preparation.has_removed_orphaned_nodes = true; + if (_skip_renumber_nodes_and_elements) { this->update_parallel_id_counts(); @@ -1776,6 +1780,8 @@ void DistributedMesh::delete_remote_elements() this->libmesh_assert_valid_parallel_ids(); this->libmesh_assert_valid_parallel_flags(); #endif + + this->_preparation.has_removed_remote_elements = true; } diff --git a/src/mesh/mesh_base.C b/src/mesh/mesh_base.C index 535117af6b..5b68208387 100644 --- a/src/mesh/mesh_base.C +++ b/src/mesh/mesh_base.C @@ -66,7 +66,7 @@ MeshBase::MeshBase (const Parallel::Communicator & comm_in, _n_parts (1), _default_mapping_type(LAGRANGE_MAP), _default_mapping_data(0), - _is_prepared (false), + _preparation (), _point_locator (), _count_lower_dim_elems_in_point_locator(true), _partitioner (), @@ -99,7 +99,7 @@ MeshBase::MeshBase (const MeshBase & other_mesh) : _n_parts (other_mesh._n_parts), _default_mapping_type(other_mesh._default_mapping_type), _default_mapping_data(other_mesh._default_mapping_data), - _is_prepared (other_mesh._is_prepared), + _preparation (other_mesh._preparation), _point_locator (), _count_lower_dim_elems_in_point_locator(other_mesh._count_lower_dim_elems_in_point_locator), _partitioner (), @@ -187,7 +187,7 @@ MeshBase& MeshBase::operator= (MeshBase && other_mesh) _n_parts = other_mesh.n_partitions(); _default_mapping_type = other_mesh.default_mapping_type(); _default_mapping_data = other_mesh.default_mapping_data(); - _is_prepared = other_mesh.is_prepared(); + _preparation = other_mesh._preparation; _point_locator = std::move(other_mesh._point_locator); _count_lower_dim_elems_in_point_locator = other_mesh.get_count_lower_dim_elems_in_point_locator(); #ifdef LIBMESH_ENABLE_UNIQUE_ID @@ -283,7 +283,7 @@ bool MeshBase::locally_equals (const MeshBase & other_mesh) const return false; if (_default_mapping_data != other_mesh._default_mapping_data) return false; - if (_is_prepared != other_mesh._is_prepared) + if (_preparation != other_mesh._preparation) return false; if (_count_lower_dim_elems_in_point_locator != other_mesh._count_lower_dim_elems_in_point_locator) @@ -794,6 +794,8 @@ void MeshBase::remove_orphaned_nodes () for (const auto & node : this->node_ptr_range()) if (!connected_nodes.count(node)) this->delete_node(node); + + _preparation.has_removed_orphaned_nodes = true; } @@ -834,9 +836,23 @@ void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements) + void MeshBase::prepare_for_use () { - LOG_SCOPE("prepare_for_use()", "MeshBase"); + // Mark everything as unprepared, except for those things we've been + // told we don't need to prepare, for backwards compatibility + this->clear_point_locator(); + _preparation = false; + _preparation.has_neighbor_ptrs = _skip_find_neighbors; + _preparation.has_removed_remote_elements = !_allow_remote_element_removal; + + this->complete_preparation(); +} + + +void MeshBase::complete_preparation() +{ + LOG_SCOPE("complete_preparation()", "MeshBase"); parallel_object_only(); @@ -871,15 +887,21 @@ void MeshBase::prepare_for_use () // using, but our partitioner might need that consistency and/or // might be confused by orphaned nodes. if (!_skip_renumber_nodes_and_elements) - this->renumber_nodes_and_elements(); + { + if (!_preparation.has_removed_orphaned_nodes || + !_preparation.has_synched_id_counts) + this->renumber_nodes_and_elements(); + } else { - this->remove_orphaned_nodes(); - this->update_parallel_id_counts(); + if (!_preparation.has_removed_orphaned_nodes) + this->remove_orphaned_nodes(); + if (!_preparation.has_synched_id_counts) + this->update_parallel_id_counts(); } // Let all the elements find their neighbors - if (!_skip_find_neighbors) + if (!_skip_find_neighbors && !_preparation.has_neighbor_ptrs) this->find_neighbors(); // The user may have set boundary conditions. We require that the @@ -892,11 +914,13 @@ void MeshBase::prepare_for_use () // Search the mesh for all the dimensions of the elements // and cache them. - this->cache_elem_data(); + if (!_preparation.has_cached_elem_data) + this->cache_elem_data(); // 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 (!_preparation.has_interior_parent_ptrs) + this->detect_interior_parents(); // Fix up node unique ids in case mesh generation code didn't take // exceptional care to do so. @@ -908,39 +932,49 @@ void MeshBase::prepare_for_use () MeshTools::libmesh_assert_valid_unique_ids(*this); #endif - // Reset our PointLocator. Any old locator is invalidated any time - // the elements in the underlying elements in the mesh have changed, - // so we clear it here. - this->clear_point_locator(); - // Allow our GhostingFunctor objects to reinit if necessary. // Do this before partitioning and redistributing, and before // deleting remote elements. - this->reinit_ghosting_functors(); + if (!_preparation.has_reinit_ghosting_functors) + this->reinit_ghosting_functors(); // Partition the mesh unless *all* partitioning is to be skipped. // If only noncritical partitioning is to be skipped, the // partition() call will still check for orphaned nodes. - if (!skip_partitioning()) + if (!skip_partitioning() && !_preparation.is_partitioned) this->partition(); + else if (!this->n_unpartitioned_elem() && + !this->n_unpartitioned_nodes()) + _preparation.is_partitioned = true; // If we're using DistributedMesh, we'll probably want it // parallelized. - if (this->_allow_remote_element_removal) + if (this->_allow_remote_element_removal && + !_preparation.has_removed_remote_elements) this->delete_remote_elements(); + else + _preparation.has_removed_remote_elements = true; // Much of our boundary info may have been for now-remote parts of the mesh, // in which case we don't want to keep local copies of data meant to be // local. On the other hand we may have deleted, or the user may have added in // a distributed fashion, boundary data that is meant to be global. So we // handle both of those scenarios here - this->get_boundary_info().regenerate_id_sets(); + if (!_preparation.has_boundary_id_sets) + this->get_boundary_info().regenerate_id_sets(); if (!_skip_renumber_nodes_and_elements) this->renumber_nodes_and_elements(); - // The mesh is now prepared for use. - _is_prepared = true; + // The mesh is now prepared for use, with the possible exception of + // partitioning that was supposed to be skipped, and it should know + // it. +#ifndef NDEBUG + Preparation completed_preparation = _preparation; + if (skip_partitioning()) + completed_preparation.is_partitioned = true; + libmesh_assert(completed_preparation); +#endif #ifdef DEBUG MeshTools::libmesh_assert_valid_boundary_ids(*this); @@ -958,6 +992,8 @@ MeshBase::reinit_ghosting_functors() libmesh_assert(gf); gf->mesh_reinit(); } + + _preparation.has_reinit_ghosting_functors = true; } void MeshBase::clear () @@ -965,8 +1001,8 @@ void MeshBase::clear () // Reset the number of partitions _n_parts = 1; - // Reset the _is_prepared flag - _is_prepared = false; + // Reset the preparation flags + _preparation = false; // Clear boundary information if (boundary_info) @@ -1683,6 +1719,8 @@ void MeshBase::partition (const unsigned int n_parts) // Make sure any other locally cached data is correct this->update_post_partitioning(); } + + _preparation.is_partitioned = true; } void MeshBase::all_second_order (const bool full_ordered) @@ -1886,6 +1924,8 @@ void MeshBase::cache_elem_data() #endif } } + + _preparation.has_cached_elem_data = true; } @@ -1903,10 +1943,16 @@ void MeshBase::detect_interior_parents() // This requires an inspection on every processor parallel_object_only(); + // This requires up-to-date mesh dimensions in cache + libmesh_assert(_preparation.has_cached_elem_data); + // Check if the mesh contains mixed dimensions. If so, then we may // have interior parents to set. Otherwise return. if (this->elem_dimensions().size() == 1) - return; + { + _preparation.has_interior_parent_ptrs = true; + 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 @@ -2002,6 +2048,8 @@ void MeshBase::detect_interior_parents() ("interior_parent() values in multiple meshes are unsupported."); } } + + _preparation.has_interior_parent_ptrs = true; } diff --git a/src/mesh/mesh_modification.C b/src/mesh/mesh_modification.C index a7429475e5..6015b81385 100644 --- a/src/mesh/mesh_modification.C +++ b/src/mesh/mesh_modification.C @@ -215,6 +215,10 @@ void MeshTools::Modification::distort (MeshBase & mesh, #endif } } + + // We haven't changed any topology, but just changing geometry could + // have invalidated a point locator. + mesh.clear_point_locator(); } @@ -302,6 +306,10 @@ void MeshTools::Modification::redistribute (MeshBase & mesh, (*node)(2) = output_vec(2); #endif } + + // We haven't changed any topology, but just changing geometry could + // have invalidated a point locator. + mesh.clear_point_locator(); } @@ -315,6 +323,10 @@ void MeshTools::Modification::translate (MeshBase & mesh, for (auto & node : mesh.node_ptr_range()) *node += p; + + // We haven't changed any topology, but just changing geometry could + // have invalidated a point locator. + mesh.clear_point_locator(); } @@ -346,6 +358,10 @@ MeshTools::Modification::rotate (MeshBase & mesh, const Real theta, const Real psi) { + // We won't change any topology, but just changing geometry could + // invalidate a point locator. + mesh.clear_point_locator(); + #if LIBMESH_DIM == 3 const auto R = RealTensorValue::intrinsic_rotation_matrix(phi, theta, psi); @@ -402,6 +418,10 @@ void MeshTools::Modification::scale (MeshBase & mesh, for (auto & node : mesh.node_ptr_range()) (*node)(2) *= z_scale; + + // We haven't changed any topology, but just changing geometry could + // have invalidated a point locator. + mesh.clear_point_locator(); } @@ -1425,8 +1445,6 @@ void MeshTools::Modification::all_tri (MeshBase & mesh) MeshCommunication().make_nodes_parallel_consistent (mesh); } - - // Prepare the newly created mesh for use. mesh.prepare_for_use(); @@ -1585,6 +1603,10 @@ void MeshTools::Modification::smooth (MeshBase & mesh, } } // refinement_level loop } // end iteration + + // We haven't changed any topology, but just changing geometry could + // have invalidated a point locator. + mesh.clear_point_locator(); } @@ -1741,6 +1763,10 @@ void MeshTools::Modification::change_subdomain_id (MeshBase & mesh, if (elem->subdomain_id() == old_id) elem->subdomain_id() = new_id; } + + // We just invalidated mesh.get_subdomain_ids(), but it might not be + // efficient to fix that here. + mesh.set_hasnt_cached_elem_data(); } diff --git a/src/mesh/mesh_smoother_vsmoother.C b/src/mesh/mesh_smoother_vsmoother.C index 5cbc842996..5efb135c9e 100644 --- a/src/mesh/mesh_smoother_vsmoother.C +++ b/src/mesh/mesh_smoother_vsmoother.C @@ -88,6 +88,16 @@ void VariationalMeshSmoother::setup() // Create a new mesh, EquationSystems, and System _mesh_copy = std::make_unique(_mesh); + + // If the _mesh wasn't prepared, that's fine (we'll just be moving + // its nodes), but we do need the copy to be prepared before our + // solve does things like looking at neighbors. We'll disable + // repartitioning and renumbering first to make sure that we can + // transfer our geometry changes back to the original mesh. + _mesh_copy->allow_renumbering(false); + _mesh_copy->skip_partitioning(true); + _mesh_copy->complete_preparation(); + _equation_systems = std::make_unique(*_mesh_copy); _system = &(_equation_systems->add_system("variational_smoother_system")); diff --git a/src/mesh/mesh_tools.C b/src/mesh/mesh_tools.C index 7e98732dcb..7fdcf9406a 100644 --- a/src/mesh/mesh_tools.C +++ b/src/mesh/mesh_tools.C @@ -1227,7 +1227,7 @@ void clear_spline_nodes(MeshBase & mesh) bool valid_is_prepared (const MeshBase & mesh) { - LOG_SCOPE("libmesh_assert_valid_is_prepared()", "MeshTools"); + LOG_SCOPE("valid_is_prepared()", "MeshTools"); if (!mesh.is_prepared()) return true; diff --git a/src/mesh/replicated_mesh.C b/src/mesh/replicated_mesh.C index 059d3fcbe7..b58d941156 100644 --- a/src/mesh/replicated_mesh.C +++ b/src/mesh/replicated_mesh.C @@ -115,7 +115,7 @@ ReplicatedMesh::ReplicatedMesh (const MeshBase & other_mesh) : this->copy_constraint_rows(other_mesh); - this->_is_prepared = other_mesh.is_prepared(); + this->_preparation = other_mesh.preparation(); auto & this_boundary_info = this->get_boundary_info(); const auto & other_boundary_info = other_mesh.get_boundary_info(); @@ -643,6 +643,8 @@ void ReplicatedMesh::update_parallel_id_counts() #ifdef LIBMESH_ENABLE_UNIQUE_ID _next_unique_id = this->parallel_max_unique_id(); #endif + + this->_preparation.has_synched_id_counts = true; } @@ -820,6 +822,8 @@ void ReplicatedMesh::renumber_nodes_and_elements () } } + this->_preparation.has_removed_orphaned_nodes = true; + libmesh_assert_equal_to (next_free_elem, _elements.size()); libmesh_assert_equal_to (next_free_node, _nodes.size()); diff --git a/src/mesh/unstructured_mesh.C b/src/mesh/unstructured_mesh.C index 935780b5dd..ac9da962c8 100644 --- a/src/mesh/unstructured_mesh.C +++ b/src/mesh/unstructured_mesh.C @@ -1298,15 +1298,15 @@ void UnstructuredMesh::find_neighbors (const bool reset_remote_elements, libmesh_assert(current_elem->interior_parent()); } } - #endif // AMR - #ifdef DEBUG MeshTools::libmesh_assert_valid_neighbors(*this, !reset_remote_elements); MeshTools::libmesh_assert_valid_amr_interior_parents(*this); #endif + + this->_preparation.has_neighbor_ptrs = true; }