@@ -165,7 +165,7 @@ class MeshBase : public ParallelObject
165165 virtual ~MeshBase ();
166166
167167 /* *
168- * A partitioner to use at each prepare_for_use()
168+ * A partitioner to use at each partitioning
169169 */
170170 virtual std::unique_ptr<Partitioner> & partitioner () { return _partitioner; }
171171
@@ -194,25 +194,158 @@ class MeshBase : public ParallelObject
194194 * No Node is removed from the mesh, however even NodeElem elements
195195 * are deleted, so the remaining Nodes will be considered "unused"
196196 * and cleared unless they are reconnected to new elements before
197- * the next \p prepare_for_use()
197+ * the next preparation step.
198198 *
199199 * This does not affect BoundaryInfo data; any boundary information
200200 * associated elements should already be cleared.
201201 */
202202 virtual void clear_elems () = 0;
203203
204204 /* *
205- * \returns \p true if the mesh has been prepared via a call
206- * to \p prepare_for_use, \p false otherwise.
205+ * \returns \p true if the mesh is marked as having undergone all of
206+ * the preparation done in a call to \p prepare_for_use, \p false
207+ * otherwise.
207208 */
208209 bool is_prepared () const
209- { return _is_prepared ; }
210+ { return _preparation ; }
210211
211212 /* *
212- * Tells this we have done some operation where we should no longer consider ourself prepared
213+ * \returns the \p Preparation structure with details about in what
214+ * ways \p this mesh is currently prepared or unprepared. This
215+ * structure may change in the future when cache designs change.
216+ */
217+ struct Preparation ;
218+
219+ Preparation preparation () const
220+ { return _preparation; }
221+
222+ #ifdef LIBMESH_ENABLE_DEPRECATED
223+ /* *
224+ * Tells this we have done some operation where we should no longer
225+ * consider ourself prepared. This is a very coarse setting; it is
226+ * generally more efficient to mark finer-grained settings instead.
227+ *
228+ * This method name is now deprecated, in part to match the less
229+ * awkward unset_has_ names of the more fine-grained methods, in
230+ * part as a way to prompt older user codes to use the more
231+ * fine-grained methods where they can, to speed up the
232+ * complete_preparation() calls afterward.
213233 */
214234 void set_isnt_prepared ()
215- { _is_prepared = false ; }
235+ { libmesh_deprecated (); _preparation = false ; }
236+ #endif // LIBMESH_ENABLE_DEPRECATED
237+
238+ /* *
239+ * Tells this we have done some operation where we should no longer
240+ * consider ourself prepared. This is a very coarse setting; it is
241+ * generally more efficient to mark finer-grained settings instead.
242+ */
243+ void unset_is_prepared ()
244+ { _preparation = false ; }
245+
246+ /* *
247+ * Tells this we have done some operation creating unpartitioned
248+ * elements.
249+ *
250+ * User code which adds elements to this mesh must either partition
251+ * them too or call this method.
252+ */
253+ void unset_is_partitioned ()
254+ { _preparation.is_partitioned = false ; }
255+
256+ /* *
257+ * Tells this we have done some operation (e.g. adding objects to a
258+ * distributed mesh on one processor only) which can lose
259+ * synchronization of id counts.
260+ *
261+ * User code which does distributed additions of nodes or elements
262+ * must call either this method or \p update_parallel_id_counts().
263+ */
264+ void unset_has_synched_id_counts ()
265+ { _preparation.has_synched_id_counts = false ; }
266+
267+ /* *
268+ * Tells this we have done some operation (e.g. adding elements
269+ * without setting their neighbor pointers, or adding disjoint
270+ * neighbor boundary pairs) which requires neighbor pointers to be
271+ * determined later.
272+ *
273+ * User code which adds new elements to this mesh must call this
274+ * function or manually set neighbor pointer from and to those
275+ * elements.
276+ */
277+ void unset_has_neighbor_ptrs ()
278+ { _preparation.has_neighbor_ptrs = false ; }
279+
280+ /* *
281+ * Tells this we have done some operation (e.g. adding elements with
282+ * a new dimension or subdomain value) which may invalidate cached
283+ * summaries of element data.
284+ *
285+ * User code which adds new elements to this mesh must call this
286+ * function.
287+ */
288+ void unset_has_cached_elem_data ()
289+ { _preparation.has_cached_elem_data = false ; }
290+
291+ /* *
292+ * Tells this we have done some operation (e.g. refining elements
293+ * with interior parents) which requires interior parent pointers to
294+ * be found later.
295+ *
296+ * Most user code will not need to call this method; any user code
297+ * that manipulates interior parents or their boundary elements may
298+ * be an exception.
299+ */
300+ void unset_has_interior_parent_ptrs ()
301+ { _preparation.has_interior_parent_ptrs = false ; }
302+
303+ /* *
304+ * Tells this we have done some operation (e.g. repartitioning)
305+ * which may have left elements as ghosted which on a distributed
306+ * mesh should be remote.
307+ *
308+ * User code should probably never need to use this; we can set it
309+ * in Partitioner. Any user code which manually repartitions
310+ * elements on distributed meshes may need to call this manually, in
311+ * addition to manually communicating elements with newly-created
312+ * ghosting requirements.
313+ */
314+ void unset_has_removed_remote_elements ()
315+ { _preparation.has_removed_remote_elements = false ; }
316+
317+ /* *
318+ * Tells this we have done some operation (e.g. coarsening)
319+ * which may have left orphaned nodes in need of removal.
320+ *
321+ * Most user code should probably never need to use this; we can set
322+ * it in MeshRefinement. User code which deletes elements without
323+ * carefully deleting orphaned nodes should call this manually.
324+ */
325+ void unset_has_removed_orphaned_nodes ()
326+ { _preparation.has_removed_orphaned_nodes = false ; }
327+
328+ /* *
329+ * Tells this we have done some operation (e.g. adding or removing
330+ * elements) which may require a reinit() of custom ghosting
331+ * functors.
332+ *
333+ * User code which adds or removes elements should call this method.
334+ * User code which moves nodes ... should probably call this method,
335+ * in case ghosting functors depending on position exist?
336+ */
337+ void unset_has_reinit_ghosting_functors ()
338+ { _preparation.has_reinit_ghosting_functors = false ; }
339+
340+ /* *
341+ * Tells this we have done some operation which may have invalidated
342+ * our cached boundary id sets.
343+ *
344+ * User code which removes elements, or which adds or removes
345+ * boundary entries, should call this method.
346+ */
347+ void unset_has_boundary_id_sets ()
348+ { _preparation.has_boundary_id_sets = false ; }
216349
217350 /* *
218351 * \returns \p true if all elements and nodes of the mesh
@@ -260,7 +393,9 @@ class MeshBase : public ParallelObject
260393 * except for "ghosts" which touch a local element, and deletes
261394 * all nodes which are not part of a local or ghost element
262395 */
263- virtual void delete_remote_elements () {}
396+ virtual void delete_remote_elements () {
397+ _preparation.has_removed_remote_elements = true ;
398+ }
264399
265400 /* *
266401 * Loops over ghosting functors and calls mesh_reinit()
@@ -400,16 +535,17 @@ class MeshBase : public ParallelObject
400535 * higher dimensions is checked. Also, x-z and y-z planar meshes are
401536 * considered to have spatial dimension == 3.
402537 *
403- * The spatial dimension is updated during prepare_for_use() based
538+ * The spatial dimension is updated during mesh preparation based
404539 * on the dimensions of the various elements present in the Mesh,
405- * but is *never automatically decreased* by this function .
540+ * but is *never automatically decreased*.
406541 *
407542 * For example, if the user calls set_spatial_dimension(2) and then
408543 * later inserts 3D elements into the mesh,
409544 * Mesh::spatial_dimension() will return 3 after the next call to
410- * prepare_for_use(). On the other hand, if the user calls
411- * set_spatial_dimension(3) and then inserts only x-aligned 1D
412- * elements into the Mesh, mesh.spatial_dimension() will remain 3.
545+ * prepare_for_use() or complete_preparation(). On the other hand,
546+ * if the user calls set_spatial_dimension(3) and then inserts only
547+ * x-aligned 1D elements into the Mesh, mesh.spatial_dimension()
548+ * will remain 3.
413549 */
414550 unsigned int spatial_dimension () const ;
415551
@@ -742,7 +878,7 @@ class MeshBase : public ParallelObject
742878 * To ensure a specific element id, call e->set_id() before adding it;
743879 * only do this in parallel if you are manually keeping ids consistent.
744880 *
745- * Users should call MeshBase::prepare_for_use () after elements are
881+ * Users should call MeshBase::complete_preparation () after elements are
746882 * added to and/or deleted from the mesh.
747883 */
748884 virtual Elem * add_elem (Elem * e) = 0;
@@ -761,7 +897,7 @@ class MeshBase : public ParallelObject
761897 * Insert elem \p e to the element array, preserving its id
762898 * and replacing/deleting any existing element with the same id.
763899 *
764- * Users should call MeshBase::prepare_for_use () after elements are
900+ * Users should call MeshBase::complete_preparation () after elements are
765901 * added to and/or deleted from the mesh.
766902 */
767903 virtual Elem * insert_elem (Elem * e) = 0;
@@ -780,8 +916,8 @@ class MeshBase : public ParallelObject
780916 * Removes element \p e from the mesh. This method must be
781917 * implemented in derived classes in such a way that it does not
782918 * invalidate element iterators. Users should call
783- * MeshBase::prepare_for_use () after elements are added to and/or
784- * deleted from the mesh.
919+ * MeshBase::complete_preparation () after elements are added to
920+ * and/or deleted from the mesh.
785921 *
786922 * \note Calling this method may produce isolated nodes, i.e. nodes
787923 * not connected to any element.
@@ -848,7 +984,7 @@ class MeshBase : public ParallelObject
848984
849985 /* *
850986 * Removes any orphaned nodes, nodes not connected to any elements.
851- * Typically done automatically in prepare_for_use
987+ * Typically done automatically in a preparation step
852988 */
853989 void remove_orphaned_nodes ();
854990
@@ -1122,12 +1258,26 @@ class MeshBase : public ParallelObject
11221258 const std::vector<T> * default_values = nullptr );
11231259
11241260 /* *
1125- * Prepare a newly ecreated (or read) mesh for use.
1126- * This involves 4 steps:
1127- * 1.) call \p find_neighbors()
1128- * 2.) call \p partition()
1129- * 3.) call \p renumber_nodes_and_elements()
1130- * 4.) call \p cache_elem_data()
1261+ * Prepare a newly created (or read) mesh for use.
1262+ * This involves several steps:
1263+ * 1.) renumbering (if enabled)
1264+ * 2.) removing any orphaned nodes
1265+ * 3.) updating parallel id counts
1266+ * 4.) finding neighbor links
1267+ * 5.) caching summarized element data
1268+ * 6.) finding interior parent links
1269+ * 7.) clearing any old point locator
1270+ * 8.) calling reinit() on ghosting functors
1271+ * 9.) repartitioning (if enabled)
1272+ * 10.) removing any remote elements (if enabled)
1273+ * 11.) regenerating summarized boundary id sets
1274+ *
1275+ * For backwards compatibility, prepare_for_use() performs *all* those
1276+ * steps, regardless of the official preparation() state of the
1277+ * mesh. In codes which have maintained a valid preparation() state
1278+ * via methods such as unset_has_synched_id_counts(), calling
1279+ * complete_preparation() will result in a fully-prepared mesh at
1280+ * less cost.
11311281 *
11321282 * The argument to skip renumbering is now deprecated - to prevent a
11331283 * mesh from being renumbered, set allow_renumbering(false). The argument to skip
@@ -1144,6 +1294,15 @@ class MeshBase : public ParallelObject
11441294#endif // LIBMESH_ENABLE_DEPRECATED
11451295 void prepare_for_use ();
11461296
1297+ /*
1298+ * Prepare a newly created or modified mesh for use.
1299+ *
1300+ * Unlike \p prepare_for_use(), \p complete_preparation() performs
1301+ * *only* those preparatory steps that have been marked as
1302+ * necessary in the MeshBase::Preparation state.
1303+ */
1304+ void complete_preparation ();
1305+
11471306 /* *
11481307 * Call the default partitioner (currently \p metis_partition()).
11491308 */
@@ -1844,6 +2003,59 @@ class MeshBase : public ParallelObject
18442003 const boundary_id_type b2);
18452004#endif
18462005
2006+ /* *
2007+ * Flags indicating in what ways a mesh has been prepared for use.
2008+ */
2009+ struct Preparation
2010+ {
2011+ bool is_partitioned = false ,
2012+ has_synched_id_counts = false ,
2013+ has_neighbor_ptrs = false ,
2014+ has_cached_elem_data = false ,
2015+ has_interior_parent_ptrs = false ,
2016+ has_removed_remote_elements = false ,
2017+ has_removed_orphaned_nodes = false ,
2018+ has_boundary_id_sets = false ,
2019+ has_reinit_ghosting_functors = false ;
2020+
2021+ operator bool () const {
2022+ return is_partitioned &&
2023+ has_synched_id_counts &&
2024+ has_neighbor_ptrs &&
2025+ has_cached_elem_data &&
2026+ has_interior_parent_ptrs &&
2027+ has_removed_remote_elements &&
2028+ has_removed_orphaned_nodes &&
2029+ has_reinit_ghosting_functors &&
2030+ has_boundary_id_sets;
2031+ }
2032+
2033+ Preparation & operator = (bool set_all) {
2034+ is_partitioned = set_all;
2035+ has_synched_id_counts = set_all;
2036+ has_neighbor_ptrs = set_all;
2037+ has_cached_elem_data = set_all;
2038+ has_interior_parent_ptrs = set_all;
2039+ has_removed_remote_elements = set_all;
2040+ has_removed_orphaned_nodes = set_all;
2041+ has_reinit_ghosting_functors = set_all;
2042+ has_boundary_id_sets = set_all;
2043+
2044+ return *this ;
2045+ }
2046+
2047+ bool operator == (const Preparation & other) {
2048+ return is_partitioned == other.is_partitioned &&
2049+ has_synched_id_counts == other.has_synched_id_counts &&
2050+ has_neighbor_ptrs == other.has_neighbor_ptrs &&
2051+ has_cached_elem_data == other.has_cached_elem_data &&
2052+ has_interior_parent_ptrs == other.has_interior_parent_ptrs &&
2053+ has_removed_remote_elements == other.has_removed_remote_elements &&
2054+ has_removed_orphaned_nodes == other.has_removed_orphaned_nodes &&
2055+ has_reinit_ghosting_functors == other.has_reinit_ghosting_functors &&
2056+ has_boundary_id_sets == other.has_boundary_id_sets ;
2057+ }
2058+ };
18472059
18482060protected:
18492061
@@ -1923,9 +2135,9 @@ class MeshBase : public ParallelObject
19232135 unsigned char _default_mapping_data;
19242136
19252137 /* *
1926- * Flag indicating if the mesh has been prepared for use .
2138+ * Flags indicating in what ways \p this mesh has been prepared.
19272139 */
1928- bool _is_prepared ;
2140+ Preparation _preparation ;
19292141
19302142 /* *
19312143 * A \p PointLocator class for this mesh.
0 commit comments