Skip to content

Commit f66cb98

Browse files
authored
Merge pull request #4398 from roystgnr/fe_type_p_refinement
Add FEType::p_refinement
2 parents f8a1758 + 0cf959c commit f66cb98

11 files changed

Lines changed: 137 additions & 97 deletions

File tree

include/base/dof_map.h

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,8 +1764,9 @@ class DofMap : public DofMapBase,
17641764
bool use_condensed_system = false) const;
17651765

17661766
/**
1767-
* Describe whether the given variable group should be p-refined. If this API is not called with
1768-
* \p false, the default is to p-refine
1767+
* Set whether the given variable group should be p-refined on a
1768+
* p-refined Elem. This changes the FEType of the variable group to
1769+
* enable or disable p-refinement.
17691770
*/
17701771
void should_p_refine(unsigned int g, bool p_refine);
17711772

@@ -2257,11 +2258,6 @@ class DofMap : public DofMapBase,
22572258
* non-SCALAR variable v
22582259
*/
22592260
std::vector<dof_id_type> _first_old_scalar_df;
2260-
2261-
/**
2262-
* A container of variable groups that we should not p-refine
2263-
*/
2264-
std::unordered_set<unsigned int> _dont_p_refine;
22652261
#endif
22662262

22672263
#ifdef LIBMESH_ENABLE_CONSTRAINTS
@@ -2568,14 +2564,15 @@ inline
25682564
void DofMap::should_p_refine(const unsigned int g, const bool p_refine)
25692565
{
25702566
#ifdef LIBMESH_ENABLE_AMR
2571-
if (p_refine)
2572-
{
2573-
auto it = _dont_p_refine.find(g);
2574-
if (it != _dont_p_refine.end())
2575-
_dont_p_refine.erase(it);
2576-
}
2577-
else
2578-
_dont_p_refine.insert(g);
2567+
VariableGroup & var = _variable_groups[g];
2568+
var.type().p_refinement = p_refine;
2569+
2570+
for (auto v : make_range(var.first_scalar_number(0),
2571+
var.first_scalar_number(0) +
2572+
var.n_variables()))
2573+
this->_variables[v].type().p_refinement = p_refine;
2574+
2575+
25792576
#else
25802577
libmesh_ignore(g, p_refine);
25812578
#endif
@@ -2585,7 +2582,8 @@ inline
25852582
bool DofMap::should_p_refine(const unsigned int g) const
25862583
{
25872584
#ifdef LIBMESH_ENABLE_AMR
2588-
return !_dont_p_refine.count(g);
2585+
const VariableGroup & var = this->variable_group(g);
2586+
return var.type().p_refinement;
25892587
#else
25902588
libmesh_ignore(g);
25912589
return false;
@@ -2604,7 +2602,7 @@ bool DofMap::should_p_refine_var(const unsigned int var) const
26042602
{
26052603
#ifdef LIBMESH_ENABLE_AMR
26062604
const auto vg = this->var_group_from_var_number(var);
2607-
return !_dont_p_refine.count(vg);
2605+
return this->should_p_refine(vg);
26082606
#else
26092607
libmesh_ignore(var);
26102608
return false;
@@ -2640,12 +2638,7 @@ void DofMap::_dof_indices (const Elem & elem,
26402638

26412639
FEType fe_type = var.type();
26422640

2643-
const bool add_p_level =
2644-
#ifdef LIBMESH_ENABLE_AMR
2645-
!_dont_p_refine.count(vg);
2646-
#else
2647-
false;
2648-
#endif
2641+
const bool add_p_level = fe_type.p_refinement;
26492642

26502643
#ifdef DEBUG
26512644
// The number of dofs per element is non-static for subdivision FE

include/base/variable.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,18 @@ class Variable
188188
unsigned int _number;
189189
unsigned int _first_scalar_number;
190190
FEType _type;
191+
192+
private:
193+
/**
194+
* \returns The \p FEType for this variable. Altering this while
195+
* this Variable is already in use may be dangerous!
196+
*/
197+
FEType & type()
198+
{ return _type; }
199+
200+
// DofMap can change a VariableGroup type() to disable/enable
201+
// p-refinement post-variable-addition.
202+
friend class DofMap;
191203
};
192204

193205

include/fe/fe_type.h

Lines changed: 77 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -197,23 +197,30 @@ class FEType
197197
{
198198
public:
199199

200+
/**
201+
* The approximation order of the element (at 0 p-refinement level).
202+
*/
203+
OrderWrapper order;
204+
200205
#ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
201206

202207
/**
203-
* Constructor. Optionally takes the approximation \p Order
204-
* and the finite element family \p FEFamily
208+
* Constructor. Optionally takes the approximation \p Order,
209+
* the finite element family \p FEFamily.
210+
*
211+
* We can't set p_refinement in this argument list without
212+
* conflicting with the \p ro parameter in the InfFE-compatible
213+
* constructor version below, so we use the set_p_refinement API
214+
* below to potentially convert an FEType with p-refinement (the
215+
* default) to one without.
205216
*/
206217
FEType(const int o = 1,
207218
const FEFamily f = LAGRANGE) :
208219
order(o),
209-
family(f)
220+
family(f),
221+
p_refinement(true)
210222
{}
211223

212-
/**
213-
* The approximation order of the element.
214-
*/
215-
OrderWrapper order;
216-
217224
/**
218225
* The type of finite element. Valid types are \p LAGRANGE,
219226
* \p HIERARCHIC, etc...
@@ -230,24 +237,26 @@ class FEType
230237
* are the same, as with the \p family and \p base_family. It must
231238
* be so, otherwise what we switch on would change when infinite
232239
* elements are not compiled in.
240+
*
241+
* We can't set p_refinement in this argument list in a way
242+
* that matches the non-InfFE-enabled constructor version above, so
243+
* we use the set_p_refinement API below to potentially convert an
244+
* FEType with p-refinement (the default) to one without.
233245
*/
234246
FEType(const int o = 1,
235247
const FEFamily f = LAGRANGE,
236248
const int ro = THIRD,
237249
const FEFamily rf = JACOBI_20_00,
238-
const InfMapType im = CARTESIAN) :
250+
const InfMapType im = CARTESIAN
251+
) :
239252
order(o),
240253
radial_order(ro),
241254
family(f),
242255
radial_family(rf),
243-
inf_map(im)
256+
inf_map(im),
257+
p_refinement(true)
244258
{}
245259

246-
/**
247-
* The approximation order in the base of the infinite element.
248-
*/
249-
OrderWrapper order;
250-
251260
/**
252261
* The approximation order in radial direction of the infinite element.
253262
*/
@@ -276,13 +285,40 @@ class FEType
276285

277286
#endif // ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
278287

288+
/**
289+
* Whether or not the finite elements for this type increase their p
290+
* refinement level on geometric elements of increased p level.
291+
*/
292+
bool p_refinement;
293+
294+
/**
295+
* "Fluent API" for constructing a non-default p_refinement, for
296+
* easier compatibility between non-InfFE and InfFE code
297+
*/
298+
FEType set_p_refinement(bool p) &
299+
{
300+
this->p_refinement = p;
301+
return *this;
302+
}
303+
304+
/**
305+
* Specialization for rvalues so we don't return a dangling
306+
* reference to a temporary.
307+
*/
308+
FEType set_p_refinement(bool p) &&
309+
{
310+
this->p_refinement = p;
311+
return std::move(*this);
312+
}
313+
279314
/**
280315
* Tests equality
281316
*/
282317
bool operator== (const FEType & f2) const
283318
{
284319
return (order == f2.order
285320
&& family == f2.family
321+
&& p_refinement == f2.p_refinement
286322
#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
287323
&& radial_order == f2.radial_order
288324
&& radial_family == f2.radial_family
@@ -308,7 +344,8 @@ class FEType
308344
return (order < f2.order);
309345
if (family != f2.family)
310346
return (family < f2.family);
311-
347+
if (p_refinement != f2.p_refinement)
348+
return (p_refinement < f2.p_refinement);
312349
#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
313350
if (radial_order != f2.radial_order)
314351
return (radial_order < f2.radial_order);
@@ -321,16 +358,19 @@ class FEType
321358
}
322359

323360
/**
324-
* \returns The default quadrature order for this \p FEType. The
325-
* default quadrature order is calculated assuming a polynomial of
326-
* degree \p order and is based on integrating the mass matrix for
327-
* such an element exactly on affine elements.
361+
* \returns The default quadrature order for this \p FEType, on an
362+
* element without p refinement. The default quadrature order is
363+
* calculated assuming a polynomial of degree \p order and is based
364+
* on integrating the mass matrix for such an element exactly on
365+
* affine elements.
328366
*/
329367
Order default_quadrature_order () const;
330368

331369
/**
332370
* \returns A quadrature rule of appropriate type and order for this \p
333-
* FEType. The default quadrature rule is based on integrating the mass
371+
* FEType, on an element without p refinement.
372+
*
373+
* The default quadrature rule is based on integrating the mass
334374
* matrix for such an element exactly, with an additional power on
335375
* the basis order to help account for nonlinearities and/or
336376
* nonuniform coefficients. Higher or lower degree rules can be
@@ -341,7 +381,9 @@ class FEType
341381

342382
/**
343383
* \returns The default quadrature order for integrating unweighted
344-
* basis functions of this \p FEType.
384+
* basis functions of this \p FEType, on an element without p
385+
* refinement.
386+
*
345387
* The unweighted quadrature order is calculated assuming a
346388
* polynomial of degree \p order and is based on integrating the
347389
* shape functions for such an element exactly on affine elements.
@@ -350,10 +392,12 @@ class FEType
350392

351393
/**
352394
* \returns A quadrature rule of appropriate type and order for
353-
* unweighted integration of this \p FEType. The default quadrature
354-
* rule is based on integrating the shape functions on an affine
355-
* element exactly. Higher or lower degree rules can be chosen by
356-
* changing the extraorder parameter.
395+
* unweighted integration of this \p FEType, on an element without p
396+
* refinement
397+
*
398+
* The default quadrature rule is based on integrating the shape
399+
* functions on an affine element exactly. Higher or lower degree
400+
* rules can be chosen by changing the extraorder parameter.
357401
*/
358402
std::unique_ptr<QBase> unweighted_quadrature_rule (const unsigned int dim,
359403
const int extraorder=0) const;
@@ -392,7 +436,13 @@ struct hash<libMesh::FEType>
392436
// Old compiler versions seem to need the static_cast
393437
libMesh::boostcopy::hash_combine(seed, static_cast<int>(fe_type.family));
394438
libMesh::boostcopy::hash_combine(seed, fe_type.order._order);
395-
return seed;
439+
libMesh::boostcopy::hash_combine(seed, static_cast<int>(fe_type.p_refinement));
440+
#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
441+
libMesh::boostcopy::hash_combine(seed, static_cast<int>(fe_type.radial_family));
442+
libMesh::boostcopy::hash_combine(seed, fe_type.radial_order._order);
443+
libMesh::boostcopy::hash_combine(seed, static_cast<int>(fe_type.inf_map));
444+
#endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
445+
return seed;
396446
}
397447
};
398448
}

include/systems/generic_projector.h

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,9 +1628,7 @@ void GenericProjector<FFunctor, GFunctor, FValue, ProjectionAction>::SortAndCopy
16281628
if (!var.active_on_subdomain(elem->subdomain_id()))
16291629
continue;
16301630
const FEType fe_type = var.type();
1631-
const auto & dof_map = this->projector.system.get_dof_map();
1632-
const auto vg = dof_map.var_group_from_var_number(v_num);
1633-
const bool add_p_level = dof_map.should_p_refine(vg);
1631+
const bool add_p_level = fe_type.p_refinement;
16341632

16351633
// If we're trying to do projections on an isogeometric
16361634
// analysis mesh, only the finite element nodes constrained
@@ -2305,8 +2303,7 @@ void GenericProjector<FFunctor, GFunctor, FValue, ProjectionAction>::ProjectVert
23052303
base_fe_type,
23062304
&elem,
23072305
elem.get_node_index(&vertex),
2308-
this->projector.system.get_dof_map().should_p_refine(
2309-
this->projector.system.get_dof_map().var_group_from_var_number(var))),
2306+
base_fe_type.p_refinement),
23102307
(unsigned int)(1 + dim));
23112308

23122309
const FValue val =
@@ -2561,8 +2558,7 @@ void GenericProjector<FFunctor, GFunctor, FValue, ProjectionAction>::ProjectSide
25612558
continue;
25622559

25632560
FEType fe_type = base_fe_type;
2564-
const auto & dof_map = system.get_dof_map();
2565-
const bool add_p_level = dof_map.should_p_refine_var(var);
2561+
const bool add_p_level = base_fe_type.p_refinement;
25662562

25672563
// This may be a p refined element
25682564
fe_type.order = fe_type.order + add_p_level*elem.p_level();
@@ -2721,9 +2717,7 @@ void GenericProjector<FFunctor, GFunctor, FValue, ProjectionAction>::ProjectInte
27212717
context.get_element_fe( var, fe, dim );
27222718

27232719
FEType fe_type = base_fe_type;
2724-
const auto & dof_map = system.get_dof_map();
2725-
const auto vg = dof_map.var_group_from_var_number(var);
2726-
const bool add_p_level = dof_map.should_p_refine(vg);
2720+
const bool add_p_level = fe_type.p_refinement;
27272721

27282722
// This may be a p refined element
27292723
fe_type.order = fe_type.order + add_p_level * elem->p_level();

include/systems/system.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,12 +1189,15 @@ class System : public ReferenceCountedObject<System>,
11891189
* for this system. Same as before, but assumes \p LAGRANGE
11901190
* as default value for \p FEType.family. If \p active_subdomains is either
11911191
* \p nullptr (the default) or points to an empty set, then it will be assumed
1192-
* that \p var has no subdomain restrictions
1192+
* that \p var has no subdomain restrictions. If \p p_refinement is
1193+
* false, then even when on an \p Elem with non-zero \p p_level()
1194+
* this variable will not be p-refined.
11931195
*/
11941196
unsigned int add_variable (std::string_view var,
11951197
const Order order = FIRST,
11961198
const FEFamily = LAGRANGE,
1197-
const std::set<subdomain_id_type> * const active_subdomains = nullptr);
1199+
const std::set<subdomain_id_type> * const active_subdomains = nullptr,
1200+
const bool p_refinement = true);
11981201

11991202
/**
12001203
* Adds the variables \p vars to the list of variables
@@ -1235,12 +1238,15 @@ class System : public ReferenceCountedObject<System>,
12351238
* for this system. Same as before, but assumes \p LAGRANGE
12361239
* as default value for \p FEType.family. If \p active_subdomains is either
12371240
* \p nullptr (the default) or points to an empty set, then it will be assumed that
1238-
* \p var has no subdomain restrictions
1241+
* \p var has no subdomain restrictions. If \p p_refinement is
1242+
* false, then even when on an \p Elem with non-zero \p p_level()
1243+
* this variable will not be p-refined.
12391244
*/
12401245
unsigned int add_variables (const std::vector<std::string> & vars,
12411246
const Order order = FIRST,
12421247
const FEFamily = LAGRANGE,
1243-
const std::set<subdomain_id_type> * const active_subdomains = nullptr);
1248+
const std::set<subdomain_id_type> * const active_subdomains = nullptr,
1249+
const bool p_refinement = true);
12441250

12451251
/**
12461252
* Return a constant reference to \p Variable \p var.

0 commit comments

Comments
 (0)