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
29#ifdef LIBMESH_ENABLE_AMR
30
32 : ConsoleStreamInterface(fe_problem.getMooseApp()),
33 PerfGraphInterface(fe_problem.getMooseApp().perfGraph(), "Adaptivity"),
34 ParallelObject(fe_problem.getMooseApp()),
35 _fe_problem(fe_problem),
36 _mesh(_fe_problem.mesh()),
37 _mesh_refinement_on(false),
38 _initialized(false),
39 _initial_steps(0),
40 _steps(0),
41 _print_mesh_changed(false),
42 _t(_fe_problem.time()),
43 _step(_fe_problem.timeStep()),
44 _interval(1),
45 _start_time(-std::numeric_limits<Real>::max()),
46 _stop_time(std::numeric_limits<Real>::max()),
47 _controls_allow_adaptivity(nullptr),
48 _cycles_per_step(1),
49 _use_new_system(false),
50 _adaptivity_type(AdaptivityType::H),
51 _max_h_level(0),
52 _recompute_markers_during_cycles(false)
53{
54}
55
57
58void
59Adaptivity::init(const unsigned int steps,
60 const unsigned int initial_steps,
61 const AdaptivityType adaptivity_type)
62{
63 // Get the pointer to the DisplacedProblem, this cannot be done at construction because
64 // DisplacedProblem
65 // does not exist at that point.
67
68 _mesh_refinement = std::make_unique<libMesh::MeshRefinement>(_mesh);
69 _error = std::make_unique<libMesh::ErrorVector>();
70
71 EquationSystems & es = _fe_problem.es();
72 es.parameters.set<bool>("adaptivity") = true;
73
74 _initial_steps = initial_steps;
75 _steps = steps;
76
77 _adaptivity_type = adaptivity_type;
78
80
83
85 {
87 mooseError("HP adaptivity doesn't support multiple solver systems because currently only the "
88 "zeroth solver system solution is analyzed for determining whether to toggle "
89 "h-refinement flags to p-refinement flags");
90
91 _sibling_coupling = std::make_unique<libMesh::SiblingCoupling>();
94 }
95
96 _mesh_refinement->set_periodic_boundaries_ptr(
98
100 {
101 EquationSystems & displaced_es = _displaced_problem->es();
102 displaced_es.parameters.set<bool>("adaptivity") = true;
103
106 std::make_unique<libMesh::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<libMesh::KellyErrorEstimator>();
128 else if (error_estimator_name == "LaplacianErrorEstimator")
129 _error_estimator = std::make_unique<libMesh::LaplacianErrorEstimator>();
130 else if (error_estimator_name == "PatchRecoveryErrorEstimator")
131 _error_estimator = std::make_unique<libMesh::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<libMesh::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 libMesh::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 libMesh::MeshRefinement mesh_refinement(_mesh);
335 unsigned int level = _mesh.uniformRefineLevel();
336 libMesh::MeshRefinement displaced_mesh_refinement(_displaced_problem ? _displaced_problem->mesh()
337 : _mesh);
338
339 // we have to go step by step so EquationSystems::reinit() won't freak out
340 for (unsigned int i = 0; i < level; i++)
341 {
342 // See comment above about why refining the displaced mesh is potentially unsafe.
344 _displaced_problem->undisplaceMesh();
345
346 mesh_refinement.uniformly_refine(1);
347
349 displaced_mesh_refinement.uniformly_refine(1);
351 /*intermediate_step=*/false, /*contract_mesh=*/true, /*clean_refinement_flags=*/true);
352 }
353}
354
355void
357{
358 // check if Adaptivity has been initialized before turning on
359 if (state == true && !_initialized)
360 mooseError("Mesh adaptivity system not available");
361
362 _mesh_refinement_on = state;
363}
364
365void
366Adaptivity::setTimeActive(Real start_time, Real stop_time)
367{
368 _start_time = start_time;
369 _stop_time = stop_time;
370}
371
372void
373Adaptivity::setAdaptivityControlFlag(const bool * adapt_control_flag)
374{
375 mooseAssert(adapt_control_flag, "adapt_control_flag was null");
376 _controls_allow_adaptivity = adapt_control_flag;
377}
378
379void
384
385void
386Adaptivity::setMarkerVariableName(std::string marker_field)
387{
388 _marker_variable_name = marker_field;
389}
390
391void
393{
394 _initial_marker_variable_name = marker_field;
395}
396
398Adaptivity::getErrorVector(const std::string & indicator_field)
399{
400 // Insert or retrieve error vector
401 auto insert_pair = moose_try_emplace(
402 _indicator_field_to_error_vector, indicator_field, std::make_unique<libMesh::ErrorVector>());
403 return *insert_pair.first->second;
404}
405
406void
408{
409 TIME_SECTION("updateErrorVectors", 5, "Updating Error Vectors");
410
411 // Resize all of the ErrorVectors in case the mesh has changed
412 for (const auto & it : _indicator_field_to_error_vector)
413 {
414 libMesh::ErrorVector & vec = *(it.second);
415 vec.assign(_mesh.getMesh().max_elem_id(), 0);
416 }
417
418 // Fill the vectors with the local contributions
421
422 // Now sum across all processors
423 for (const auto & it : _indicator_field_to_error_vector)
424 _fe_problem.comm().sum((std::vector<float> &)*(it.second));
425}
426
427bool
429{
430 bool adapt_due =
433 adapt_due &= *_controls_allow_adaptivity;
434 return adapt_due;
435}
436
437#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:59
std::unique_ptr< libMesh::SiblingCoupling > _sibling_coupling
Sibling coupling object for HP adaptivity for evaluating data on elements' siblings in HPCoarsenTest.
Definition Adaptivity.h:340
unsigned int _initial_steps
the number of adaptivity steps to do at the beginning of simulation
Definition Adaptivity.h:298
std::string _marker_variable_name
Name of the marker variable if using the new adaptivity system.
Definition Adaptivity.h:324
FEProblemBase & _fe_problem
Definition Adaptivity.h:278
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:346
MooseMesh & _mesh
Definition Adaptivity.h:279
void setUseNewSystem()
Tells this object we're using the "new" adaptivity system.
Definition Adaptivity.C:380
Real _start_time
When adaptivity start.
Definition Adaptivity.h:312
Real & _t
Time.
Definition Adaptivity.h:306
void setTimeActive(Real start_time, Real stop_time)
Sets the time when the adaptivity is active.
Definition Adaptivity.C:366
std::unique_ptr< libMesh::ErrorVector > _error
Error vector for use with the error estimator.
Definition Adaptivity.h:290
bool _mesh_refinement_on
on/off flag reporting if the adaptivity is being used
Definition Adaptivity.h:282
Real _stop_time
When adaptivity stops.
Definition Adaptivity.h:314
unsigned int _max_h_level
The maximum number of refinement levels.
Definition Adaptivity.h:333
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:386
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:308
void setAdaptivityOn(bool state)
Allow adaptivity to be toggled programatically.
Definition Adaptivity.C:356
bool _use_new_system
Whether or not to use the "new" adaptivity system.
Definition Adaptivity.h:321
std::unique_ptr< libMesh::MeshRefinement > _displaced_mesh_refinement
A mesh refinement object for displaced mesh.
Definition Adaptivity.h:295
static void uniformRefine(MooseMesh *mesh, unsigned int level=libMesh::invalid_uint)
Performs uniform refinement of the passed Mesh object.
Definition Adaptivity.C:301
void setAdaptivityControlFlag(const bool *adapt_control_flag)
Sets the boolean control flag to enable / disable adaptivity.
Definition Adaptivity.C:373
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:392
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:398
std::unique_ptr< libMesh::ErrorEstimator > _error_estimator
Error estimator to be used by the apps.
Definition Adaptivity.h:288
std::unique_ptr< libMesh::MeshRefinement > _mesh_refinement
A mesh refinement object to be used either with initial refinement or with Adaptivity.
Definition Adaptivity.h:286
AdaptivityType _adaptivity_type
Type of mesh adaptivity.
Definition Adaptivity.h:327
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:428
std::shared_ptr< DisplacedProblem > _displaced_problem
Definition Adaptivity.h:292
virtual ~Adaptivity()
Definition Adaptivity.C:56
Adaptivity(FEProblemBase &fe_problem)
Definition Adaptivity.C:31
std::unique_ptr< libMesh::HPCoarsenTest > _hp_coarsen_test
Object for HP adaptivity.
Definition Adaptivity.h:343
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:407
bool _initialized
on/off flag reporting if the adaptivity system has been initialized
Definition Adaptivity.h:284
const bool * _controls_allow_adaptivity
If adaptivity is allowed by the control system.
Definition Adaptivity.h:316
unsigned int _steps
steps of adaptivity to perform
Definition Adaptivity.h:300
bool _print_mesh_changed
True if we want to print out info when mesh has changed.
Definition Adaptivity.h:303
unsigned int _interval
intreval between adaptivity runs
Definition Adaptivity.h:310
std::string _initial_marker_variable_name
Name of the initial marker variable if using the new adaptivity system.
Definition Adaptivity.h:330
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:3571
unsigned int uniformRefineLevel() const
Returns the level of uniform refinement requested (zero if AMR is disabled).
Definition MooseMesh.C:3325
virtual Elem * elemPtr(const dof_id_type i)
Definition MooseMesh.C:3222
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3557
void doingPRefinement(bool doing_p_refinement)
Indicate whether the kind of adaptivity we're doing includes p-refinement.
Definition MooseMesh.h:1502
const libMesh::ConstElemRange * getActiveLocalElementRange()
Return pointers to range objects for various types of ranges (local nodes, boundary elems,...
Definition MooseMesh.C:1245
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 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())
const unsigned int invalid_uint