https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Adaptivity.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "Adaptivity.h"
11
12#include "AuxiliarySystem.h"
13#include "DisplacedProblem.h"
14#include "FEProblem.h"
15#include "FlagElementsThread.h"
16#include "MooseMesh.h"
17#include "NonlinearSystemBase.h"
19
20// libMesh
21#include "libmesh/equation_systems.h"
22#include "libmesh/kelly_error_estimator.h"
23#include "libmesh/patch_recovery_error_estimator.h"
24#include "libmesh/fourth_error_estimators.h"
25#include "libmesh/parallel.h"
26#include "libmesh/error_vector.h"
27#include "libmesh/distributed_mesh.h"
28
29using namespace libMesh;
30
31#ifdef LIBMESH_ENABLE_AMR
32
34 : ConsoleStreamInterface(fe_problem.getMooseApp()),
35 PerfGraphInterface(fe_problem.getMooseApp().perfGraph(), "Adaptivity"),
36 ParallelObject(fe_problem.getMooseApp()),
37 _fe_problem(fe_problem),
38 _mesh(_fe_problem.mesh()),
39 _mesh_refinement_on(false),
40 _initialized(false),
41 _initial_steps(0),
42 _steps(0),
43 _print_mesh_changed(false),
44 _t(_fe_problem.time()),
45 _step(_fe_problem.timeStep()),
46 _interval(1),
47 _start_time(-std::numeric_limits<Real>::max()),
48 _stop_time(std::numeric_limits<Real>::max()),
49 _cycles_per_step(1),
50 _use_new_system(false),
51 _adaptivity_type(AdaptivityType::H),
52 _max_h_level(0),
53 _recompute_markers_during_cycles(false)
54{
55}
56
58
59void
60Adaptivity::init(const unsigned int steps,
61 const unsigned int initial_steps,
62 const AdaptivityType adaptivity_type)
63{
64 // Get the pointer to the DisplacedProblem, this cannot be done at construction because
65 // DisplacedProblem
66 // does not exist at that point.
68
69 _mesh_refinement = std::make_unique<MeshRefinement>(_mesh);
70 _error = std::make_unique<ErrorVector>();
71
73 es.parameters.set<bool>("adaptivity") = true;
74
75 _initial_steps = initial_steps;
76 _steps = steps;
77
78 _adaptivity_type = adaptivity_type;
79
81
84
86 {
88 mooseError("HP adaptivity doesn't support multiple solver systems because currently only the "
89 "zeroth solver system solution is analyzed for determining whether to toggle "
90 "h-refinement flags to p-refinement flags");
91
92 _sibling_coupling = std::make_unique<SiblingCoupling>();
95 }
96
97 _mesh_refinement->set_periodic_boundaries_ptr(
99
101 {
102 EquationSystems & displaced_es = _displaced_problem->es();
103 displaced_es.parameters.set<bool>("adaptivity") = true;
104
106 _displaced_mesh_refinement = std::make_unique<MeshRefinement>(_displaced_problem->mesh());
107
108 // The periodic boundaries pointer allows the MeshRefinement
109 // object to determine elements which are "topological" neighbors,
110 // i.e. neighbors across periodic boundaries, for the purposes of
111 // refinement.
112 _displaced_mesh_refinement->set_periodic_boundaries_ptr(
114
115 // TODO: This is currently an empty function on the DisplacedProblem... could it be removed?
116 _displaced_problem->initAdaptivity();
117 }
118
119 // indicate the Adaptivity system has been initialized
120 _initialized = true;
121}
122
123void
124Adaptivity::setErrorEstimator(const MooseEnum & error_estimator_name)
125{
126 if (error_estimator_name == "KellyErrorEstimator")
127 _error_estimator = std::make_unique<KellyErrorEstimator>();
128 else if (error_estimator_name == "LaplacianErrorEstimator")
129 _error_estimator = std::make_unique<LaplacianErrorEstimator>();
130 else if (error_estimator_name == "PatchRecoveryErrorEstimator")
131 _error_estimator = std::make_unique<PatchRecoveryErrorEstimator>();
132 else
133 mooseError(std::string("Unknown error_estimator selection: ") +
134 std::string(error_estimator_name));
135}
136
137void
139{
140 mooseAssert(_error_estimator, "error_estimator not initialized. Did you call init_adaptivity()?");
141 _error_estimator->error_norm = sys_norm;
142}
143
144bool
145Adaptivity::adaptMesh(std::string marker_name /*=std::string()*/)
146{
147 TIME_SECTION("adaptMesh", 3, "Adapting Mesh");
148
149 // If the marker name is supplied, use it. Otherwise, use the one in _marker_variable_name
150 if (marker_name.empty())
151 marker_name = _marker_variable_name;
152
153 bool mesh_changed = false;
154
155 // If mesh adaptivity is carried out in a distributed (scalable) way
156 bool distributed_adaptivity = false;
157
158 if (_use_new_system)
159 {
160 if (!marker_name.empty()) // Only flag if a marker variable name has been set
161 {
162 _mesh_refinement->clean_refinement_flags();
163
164 std::vector<Number> serialized_solution;
165
166 auto distributed_mesh = dynamic_cast<DistributedMesh *>(&_fe_problem.mesh().getMesh());
167
168 // Element range
169 std::unique_ptr<ConstElemRange> all_elems;
170 // If the mesh is distributed and we do not do "gather to zero" or "allgather".
171 // Then it is safe to not serialize solution.
172 // Some output idiom (Exodus) will do "gather to zero". That being said,
173 // if you have exodus output on, mesh adaptivty is not scalable.
174 if (distributed_mesh && !distributed_mesh->is_serial_on_zero())
175 {
176 // We update here to make sure local solution is up-to-date
178 distributed_adaptivity = true;
179
180 // We can not assume that geometric and algebraic ghosting functors cover
181 // the same set of elements/nodes. That being said, in general,
182 // we would expect G(e) > A(e). Here G(e) is the set of elements reserved
183 // by the geometric ghosting functors, and A(e) corresponds to
184 // the one covered by the algebraic ghosting functors.
185 // Therefore, we have to work only on local elements instead of
186 // ghosted + local elements. The ghosted solution might not be enough
187 // for ghosted+local elements. But it is always sufficient for local elements.
188 // After we set markers for all local elements, we will do a global
189 // communication to sync markers for ghosted elements from their owners.
190 all_elems = std::make_unique<ConstElemRange>(
191 _fe_problem.mesh().getMesh().active_local_elements_begin(),
192 _fe_problem.mesh().getMesh().active_local_elements_end());
193 }
194 else // This is not scalable but it might be useful for small-size problems
195 {
197 _fe_problem.getAuxiliarySystem().solution().localize(serialized_solution);
198 distributed_adaptivity = false;
199
200 // For a replicated mesh or a serialized distributed mesh, the solution
201 // is serialized to everyone. Then we update markers for all active elements.
202 // In this case, we can avoid a global communication to update mesh.
203 // I do not know if it is a good idea, but it the old code behavior.
204 // We might not care about much since a replicated mesh
205 // or a serialized distributed mesh is not scalable anyway.
206 all_elems =
207 std::make_unique<ConstElemRange>(_fe_problem.mesh().getMesh().active_elements_begin(),
208 _fe_problem.mesh().getMesh().active_elements_end());
209 }
210
212 _fe_problem, serialized_solution, _max_h_level, marker_name, !distributed_adaptivity);
213 Threads::parallel_reduce(*all_elems, fet);
215 }
216 }
217 else
218 {
220 mooseError("The old adaptivity system based on libMesh error estimators does not currently "
221 "support multiple solver systems because we currently only use the zeroth solver "
222 "system solution for estimating errors");
223
224 // Compute the error for each active element
225 _error_estimator->estimate_error(_fe_problem.getSolverSystem(/*nl_sys=*/0).system(), *_error);
226
227 // Flag elements to be refined and coarsened
228 _mesh_refinement->flag_elements_by_error_fraction(*_error);
229 }
230
231 // Moving some of h flagged elements to p flagged based on the
232 // local smoothness and prior h & p error estimates
234 {
235 _hp_coarsen_test = std::make_unique<HPCoarsenTest>();
236 _hp_coarsen_test->select_refinement(_fe_problem.getSolverSystem(/*nl_sys=*/0).system());
237 }
238
239 // If the DisplacedProblem is active, undisplace the DisplacedMesh
240 // in preparation for refinement. We can't safely refine the
241 // DisplacedMesh directly, since the Hilbert keys computed on the
242 // inconsistenly-displaced Mesh are different on different
243 // processors, leading to inconsistent Hilbert keys. We must do
244 // this before the undisplaced Mesh is refined, so that the
245 // element and node numbering is still consistent.
247 _displaced_problem->undisplaceMesh();
248
249 // If markers are added to only local elements,
250 // we sync them here.
251 if (distributed_adaptivity)
252 _mesh_refinement->make_flags_parallel_consistent();
253
254 // Sync flags from the reference mesh
256 for (auto * const displaced_elem :
257 _displaced_problem->mesh().getMesh().active_element_ptr_range())
258 {
259 const auto * const reference_elem = _fe_problem.mesh().elemPtr(displaced_elem->id());
260 displaced_elem->set_refinement_flag(reference_elem->refinement_flag());
261 displaced_elem->set_p_refinement_flag(reference_elem->p_refinement_flag());
262 }
263
265 _mesh_refinement->switch_h_to_p_refinement();
266
267 // Perform refinement and coarsening
268 mesh_changed = _mesh_refinement->refine_and_coarsen_elements();
269
270 if (_displaced_problem && mesh_changed)
271 {
273 _displaced_mesh_refinement->switch_h_to_p_refinement();
274
275#ifndef NDEBUG
276 bool displaced_mesh_changed =
277#endif
278 _displaced_mesh_refinement->refine_and_coarsen_elements();
279
280 // Since the undisplaced mesh changed, the displaced mesh better have changed!
281 mooseAssert(displaced_mesh_changed, "Undisplaced mesh changed, but displaced mesh did not!");
282 }
283
284 if (mesh_changed && _print_mesh_changed)
285 {
286 _console << "\nMesh Changed:\n";
288 _console << std::flush;
289 }
290
291 return mesh_changed;
292}
293
294bool
299
300void
301Adaptivity::uniformRefine(MooseMesh * mesh, unsigned int level /*=libMesh::invalid_uint*/)
302{
303 mooseAssert(mesh, "Mesh pointer must not be NULL");
304
305 // NOTE: we are using a separate object here, since adaptivity may not be on, but we need to be
306 // able to do refinements
307 MeshRefinement mesh_refinement(*mesh);
308 if (level == libMesh::invalid_uint)
309 level = mesh->uniformRefineLevel();
310
311 // Skip deletion and repartition will make uniform refinements run more
312 // efficiently, but at the same time, there might be extra ghosting elements.
313 // The number of layers of additional ghosting elements depends on the number
314 // of uniform refinement levels. This should happen only when you have a "fine enough"
315 // coarse mesh and want to refine the mesh by a few levels. Otherwise, it might
316 // introduce an unbalanced workload and too large ghosting domain.
317 if (mesh->skipDeletionRepartitionAfterRefine())
318 {
319 mesh->getMesh().skip_partitioning(true);
320 mesh->getMesh().allow_remote_element_removal(false);
321 mesh->needsRemoteElemDeletion(false);
322 }
323
324 mesh_refinement.uniformly_refine(level);
325}
326
327void
329{
330 TIME_SECTION("uniformRefineWithProjection", 2, "Uniformly Refining and Reprojecting");
331
332 // NOTE: we are using a separate object here, since adaptivity may not be on, but we need to be
333 // able to do refinements
334 MeshRefinement mesh_refinement(_mesh);
335 unsigned int level = _mesh.uniformRefineLevel();
336 MeshRefinement displaced_mesh_refinement(_displaced_problem ? _displaced_problem->mesh() : _mesh);
337
338 // we have to go step by step so EquationSystems::reinit() won't freak out
339 for (unsigned int i = 0; i < level; i++)
340 {
341 // See comment above about why refining the displaced mesh is potentially unsafe.
343 _displaced_problem->undisplaceMesh();
344
345 mesh_refinement.uniformly_refine(1);
346
348 displaced_mesh_refinement.uniformly_refine(1);
350 /*intermediate_step=*/false, /*contract_mesh=*/true, /*clean_refinement_flags=*/true);
351 }
352}
353
354void
356{
357 // check if Adaptivity has been initialized before turning on
358 if (state == true && !_initialized)
359 mooseError("Mesh adaptivity system not available");
360
361 _mesh_refinement_on = state;
362}
363
364void
365Adaptivity::setTimeActive(Real start_time, Real stop_time)
366{
367 _start_time = start_time;
368 _stop_time = stop_time;
369}
370
371void
376
377void
378Adaptivity::setMarkerVariableName(std::string marker_field)
379{
380 _marker_variable_name = marker_field;
381}
382
383void
385{
386 _initial_marker_variable_name = marker_field;
387}
388
390Adaptivity::getErrorVector(const std::string & indicator_field)
391{
392 // Insert or retrieve error vector
393 auto insert_pair = moose_try_emplace(
394 _indicator_field_to_error_vector, indicator_field, std::make_unique<ErrorVector>());
395 return *insert_pair.first->second;
396}
397
398void
400{
401 TIME_SECTION("updateErrorVectors", 5, "Updating Error Vectors");
402
403 // Resize all of the ErrorVectors in case the mesh has changed
404 for (const auto & it : _indicator_field_to_error_vector)
405 {
406 ErrorVector & vec = *(it.second);
407 vec.assign(_mesh.getMesh().max_elem_id(), 0);
408 }
409
410 // Fill the vectors with the local contributions
413
414 // Now sum across all processors
415 for (const auto & it : _indicator_field_to_error_vector)
416 _fe_problem.comm().sum((std::vector<float> &)*(it.second));
417}
418
419bool
424
425#endif // LIBMESH_ENABLE_AMR
AdaptivityType
Defines types of mesh adaptivity options available.
Definition Adaptivity.h:51
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
std::pair< typename M::iterator, bool > moose_try_emplace(M &m, const typename M::key_type &k, Args &&... args)
Function to mirror the behavior of the C++17 std::map::try_emplace() method (no hint).
Definition Moose.h:103
void init(const unsigned int steps, const unsigned int initial_steps, const AdaptivityType adaptivity_type)
Initialize and turn on adaptivity for the simulation.
Definition Adaptivity.C:60
std::unique_ptr< libMesh::SiblingCoupling > _sibling_coupling
Sibling coupling object for HP adaptivity for evaluating data on elements' siblings in HPCoarsenTest.
Definition Adaptivity.h:331
unsigned int _initial_steps
the number of adaptivity steps to do at the beginning of simulation
Definition Adaptivity.h:291
std::string _marker_variable_name
Name of the marker variable if using the new adaptivity system.
Definition Adaptivity.h:315
FEProblemBase & _fe_problem
Definition Adaptivity.h:271
libMesh::ErrorVector & getErrorVector(const std::string &indicator_field)
Get an ErrorVector that will be filled up with values corresponding to the indicator field name passe...
Definition Adaptivity.C:390
std::map< std::string, std::unique_ptr< libMesh::ErrorVector > > _indicator_field_to_error_vector
Stores pointers to ErrorVectors associated with indicator field names.
Definition Adaptivity.h:337
MooseMesh & _mesh
Definition Adaptivity.h:272
void setUseNewSystem()
Tells this object we're using the "new" adaptivity system.
Definition Adaptivity.C:372
Real _start_time
When adaptivity start.
Definition Adaptivity.h:305
Real & _t
Time.
Definition Adaptivity.h:299
void setTimeActive(Real start_time, Real stop_time)
Sets the time when the adaptivity is active.
Definition Adaptivity.C:365
std::unique_ptr< libMesh::ErrorVector > _error
Error vector for use with the error estimator.
Definition Adaptivity.h:283
bool _mesh_refinement_on
on/off flag reporting if the adaptivity is being used
Definition Adaptivity.h:275
Real _stop_time
When adaptivity stops.
Definition Adaptivity.h:307
unsigned int _max_h_level
The maximum number of refinement levels.
Definition Adaptivity.h:324
void setMarkerVariableName(std::string marker_field)
Sets the name of the field variable to actually use to flag elements for refinement / coarsening.
Definition Adaptivity.C:378
bool initialAdaptMesh()
Used during initial adaptivity.
Definition Adaptivity.C:295
void uniformRefineWithProjection()
Performs uniform refinement on the meshes in the current object.
Definition Adaptivity.C:328
void setErrorNorm(libMesh::SystemNorm &sys_norm)
Set the error norm (FIXME: improve description)
Definition Adaptivity.C:138
int & _step
Time Step.
Definition Adaptivity.h:301
void setAdaptivityOn(bool state)
Allow adaptivity to be toggled programatically.
Definition Adaptivity.C:355
bool _use_new_system
Whether or not to use the "new" adaptivity system.
Definition Adaptivity.h:312
std::unique_ptr< libMesh::MeshRefinement > _displaced_mesh_refinement
A mesh refinement object for displaced mesh.
Definition Adaptivity.h:288
static void uniformRefine(MooseMesh *mesh, unsigned int level=libMesh::invalid_uint)
Performs uniform refinement of the passed Mesh object.
Definition Adaptivity.C:301
void setInitialMarkerVariableName(std::string marker_field)
Sets the name of the field variable to actually use to flag elements for initial refinement / coarsen...
Definition Adaptivity.C:384
std::unique_ptr< libMesh::ErrorEstimator > _error_estimator
Error estimator to be used by the apps.
Definition Adaptivity.h:281
std::unique_ptr< libMesh::MeshRefinement > _mesh_refinement
A mesh refinement object to be used either with initial refinement or with Adaptivity.
Definition Adaptivity.h:279
AdaptivityType _adaptivity_type
Type of mesh adaptivity.
Definition Adaptivity.h:318
bool adaptMesh(std::string marker_name=std::string())
Adapts the mesh based on the error estimator used.
Definition Adaptivity.C:145
bool isAdaptivityDue()
Query if an adaptivity step should be performed at the current time / time step.
Definition Adaptivity.C:420
std::shared_ptr< DisplacedProblem > _displaced_problem
Definition Adaptivity.h:285
virtual ~Adaptivity()
Definition Adaptivity.C:57
Adaptivity(FEProblemBase &fe_problem)
Definition Adaptivity.C:33
std::unique_ptr< libMesh::HPCoarsenTest > _hp_coarsen_test
Object for HP adaptivity.
Definition Adaptivity.h:334
void setErrorEstimator(const MooseEnum &error_estimator_name)
Set the error estimator.
Definition Adaptivity.C:124
void updateErrorVectors()
Update the ErrorVectors that have been requested through calls to getErrorVector().
Definition Adaptivity.C:399
bool _initialized
on/off flag reporting if the adaptivity system has been initialized
Definition Adaptivity.h:277
unsigned int _steps
steps of adaptivity to perform
Definition Adaptivity.h:293
bool _print_mesh_changed
True if we want to print out info when mesh has changed.
Definition Adaptivity.h:296
unsigned int _interval
intreval between adaptivity runs
Definition Adaptivity.h:303
std::string _initial_marker_variable_name
Name of the initial marker variable if using the new adaptivity system.
Definition Adaptivity.h:321
An inteface for the _console for outputting to the Console object.
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
virtual libMesh::EquationSystems & es() override
AuxiliarySystem & getAuxiliarySystem()
virtual std::size_t numSolverSystems() const override
virtual std::shared_ptr< const DisplacedProblem > getDisplacedProblem() const
virtual MooseMesh & mesh() override
SolverSystem & getSolverSystem(unsigned int sys_num)
Get non-constant reference to a solver system.
virtual void meshChanged(bool intermediate_change, bool contract_mesh, bool clean_refinement_flags)
Update data after a mesh change.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition MooseMesh.h:95
void printInfo(std::ostream &os=libMesh::out, const unsigned int verbosity=0) const
Calls print_info() on the underlying Mesh.
Definition MooseMesh.C:3563
unsigned int uniformRefineLevel() const
Returns the level of uniform refinement requested (zero if AMR is disabled).
Definition MooseMesh.C:3317
virtual Elem * elemPtr(const dof_id_type i)
Definition MooseMesh.C:3214
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3549
void doingPRefinement(bool doing_p_refinement)
Indicate whether the kind of adaptivity we're doing includes p-refinement.
Definition MooseMesh.h:1504
const libMesh::ConstElemRange * getActiveLocalElementRange()
Return pointers to range objects for various types of ranges (local nodes, boundary elems,...
Definition MooseMesh.C:1242
Interface for objects interacting with the PerfGraph.
virtual libMesh::DofMap & dofMap()
Gets writeable reference to the dof map.
NumericVector< Number > & solution()
Definition SystemBase.h:203
void update()
Update the system (doing libMesh magic)
virtual libMesh::System & system()=0
Get the reference to the libMesh system.
PeriodicBoundaries * get_periodic_boundaries()
void add_algebraic_ghosting_functor(GhostingFunctor &evaluable_functor, bool to_mesh=true)
void set_refinement_flag(const RefinementState rflag)
void allow_remote_element_removal(bool allow)
virtual dof_id_type max_elem_id() const=0
void skip_partitioning(bool skip)
void uniformly_refine(unsigned int n=1)
virtual void close()=0
virtual void localize(std::vector< T > &v_local) const=0
const Parallel::Communicator & comm() const
T & set(const std::string &)
const DofMap & get_dof_map() const
MeshBase & mesh
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
const unsigned int invalid_uint
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real