Skip to content

Commit 7a2389c

Browse files
committed
Check orientation when caching for required families
1 parent 34e20ee commit 7a2389c

File tree

4 files changed

+97
-19
lines changed

4 files changed

+97
-19
lines changed

include/fe/fe.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -790,10 +790,23 @@ class FE : public FEGenericBase<typename FEOutputType<T>::type>
790790
const unsigned vdim = 1);
791791

792792
/**
793-
* An array of the node locations on the last
794-
* element we computed on
793+
* Vectors holding the node locations, edge and
794+
* face orientations of the last element we cached.
795795
*/
796796
std::vector<Point> cached_nodes;
797+
std::vector<bool> cached_edges, cached_faces;
798+
799+
/**
800+
* Repopulate the element cache with the node locations,
801+
* edge and face orientations of the element \p elem.
802+
*/
803+
void cache(const Elem * elem);
804+
805+
/**
806+
* Check if the node locations, edge and face orientations
807+
* held in the element cache match those of element \p elem.
808+
*/
809+
bool match(const Elem * elem);
797810

798811
/**
799812
* The last side and last edge we did a reinit on

include/fe/fe_interface.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,11 @@ class FEInterface
845845
*/
846846
static FEFieldType field_type (const FEFamily & fe_family);
847847

848+
/**
849+
* \returns Whether the element's shape functions are orientation-dependent.
850+
*/
851+
static bool orientation_dependent (const FEFamily & fe_family);
852+
848853
/**
849854
* \returns The number of components of a vector-valued element.
850855
* Scalar-valued elements return 1.

src/fe/fe.C

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ namespace {
4242
namespace libMesh
4343
{
4444
// ------------------------------------------------------------
45-
// Whether we cache the node locations on the last element we computed on
46-
// to try to avoid calling init_shape_functions and compute_shape_functions
45+
// Whether we cache the node locations, edge and face orientations of the last
46+
// element we computed on as needed to avoid calling init_shape_functions and
47+
// compute_shape_functions
4748
static const bool * caching = nullptr;
4849

4950
class CachingSetup: public Singleton::Setup
@@ -148,6 +149,50 @@ void FE<Dim,T>::dofs_on_edge(const Elem * const elem,
148149

149150

150151

152+
template <unsigned int Dim, FEFamily T>
153+
void FE<Dim,T>::cache(const Elem * elem)
154+
{
155+
cached_nodes.resize(elem->n_nodes());
156+
for (auto n : elem->node_index_range())
157+
cached_nodes[n] = elem->point(n);
158+
159+
if (FEInterface::orientation_dependent(T))
160+
{
161+
cached_edges.resize(elem->n_edges());
162+
for (auto n : elem->edge_index_range())
163+
cached_edges[n] = elem->positive_edge_orientation(n);
164+
165+
cached_faces.resize(elem->n_faces());
166+
for (auto n : elem->face_index_range())
167+
cached_faces[n] = elem->positive_face_orientation(n);
168+
}
169+
}
170+
171+
172+
173+
template <unsigned int Dim, FEFamily T>
174+
bool FE<Dim,T>::match(const Elem * elem)
175+
{
176+
bool m = cached_nodes.size() == elem->n_nodes();
177+
for (unsigned n = 1; m && n < elem->n_nodes(); n++)
178+
m = (elem->point(n) - elem->point(0)).relative_fuzzy_equals(cached_nodes[n] - cached_nodes[0]);
179+
180+
if (FEInterface::orientation_dependent(T))
181+
{
182+
m &= cached_edges.size() == elem->n_edges();
183+
for (unsigned n = 0; m && n < elem->n_edges(); n++)
184+
m = elem->positive_edge_orientation(n) == cached_edges[n];
185+
186+
m &= cached_faces.size() == elem->n_faces();
187+
for (unsigned n = 0; m && n < elem->n_faces(); n++)
188+
m = elem->positive_face_orientation(n) == cached_faces[n];
189+
}
190+
191+
return m;
192+
}
193+
194+
195+
151196
template <unsigned int Dim, FEFamily T>
152197
void FE<Dim,T>::reinit(const Elem * elem,
153198
const std::vector<Point> * const pts,
@@ -162,7 +207,7 @@ void FE<Dim,T>::reinit(const Elem * elem,
162207

163208
// Try to avoid calling init_shape_functions
164209
// even when shapes_need_reinit
165-
bool cached_nodes_still_fit = false;
210+
bool cached_elem_still_fits = false;
166211

167212
// Most of the hard work happens when we have an actual element
168213
if (elem)
@@ -215,6 +260,7 @@ void FE<Dim,T>::reinit(const Elem * elem,
215260
this->_elem_type = elem->type();
216261
this->_elem_p_level = elem->p_level();
217262
this->_p_level = this->_add_p_level_in_reinit * elem->p_level();
263+
218264
// Initialize the shape functions
219265
this->_fe_map->template init_reference_to_physical_map<Dim>
220266
(this->qrule->get_points(), elem);
@@ -223,27 +269,22 @@ void FE<Dim,T>::reinit(const Elem * elem,
223269
else
224270
{
225271
this->_elem = elem;
226-
// Check if cached elem geometry is sufficiently similar
227-
cached_nodes_still_fit = cached_nodes.size() == elem->n_nodes();
228-
for (unsigned n = 1; cached_nodes_still_fit && n < elem->n_nodes(); n++)
229-
cached_nodes_still_fit = (elem->point(n) - elem->point(0)).relative_fuzzy_equals
230-
(cached_nodes[n] - cached_nodes[0]);
272+
273+
// Check if cached element's nodes, edge and face orientations still fit
274+
cached_elem_still_fits = this->match(elem);
275+
231276
// Initialize the shape functions if needed
232-
if (this->shapes_need_reinit() && !cached_nodes_still_fit)
277+
if (this->shapes_need_reinit() && !cached_elem_still_fits)
233278
{
234279
this->_fe_map->template init_reference_to_physical_map<Dim>
235280
(this->qrule->get_points(), elem);
236281
this->init_shape_functions (this->qrule->get_points(), elem);
237282
}
238283
}
239284

240-
// Replace cached nodes if no longer fitting
241-
if (this->shapes_need_reinit() && !cached_nodes_still_fit && *caching)
242-
{
243-
cached_nodes.resize(elem->n_nodes());
244-
for (auto n : elem->node_index_range())
245-
cached_nodes[n] = elem->point(n);
246-
}
285+
// Replace cached nodes, edge and face orientations if no longer fitting
286+
if (this->shapes_need_reinit() && !cached_elem_still_fits && *caching)
287+
this->cache(elem);
247288

248289
// The shape functions correspond to the qrule
249290
this->shapes_on_quadrature = true;
@@ -300,7 +341,7 @@ void FE<Dim,T>::reinit(const Elem * elem,
300341

301342
// Compute the shape functions and the derivatives at all of the
302343
// quadrature points.
303-
if (!cached_nodes_still_fit)
344+
if (!cached_elem_still_fits)
304345
{
305346
if (pts != nullptr)
306347
this->compute_shape_functions (elem,*pts);

src/fe/fe_interface.C

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2655,6 +2655,25 @@ FEFieldType FEInterface::field_type (const FEFamily & fe_family)
26552655
}
26562656
}
26572657

2658+
bool FEInterface::orientation_dependent (const FEFamily & fe_family)
2659+
{
2660+
switch (fe_family)
2661+
{
2662+
case HIERARCHIC:
2663+
case L2_HIERARCHIC:
2664+
case HIERARCHIC_VEC:
2665+
case L2_HIERARCHIC_VEC:
2666+
case BERNSTEIN:
2667+
case RATIONAL_BERNSTEIN:
2668+
case SZABAB:
2669+
case NEDELEC_ONE:
2670+
case RAVIART_THOMAS:
2671+
return true;
2672+
default:
2673+
return false;
2674+
}
2675+
}
2676+
26582677
unsigned int FEInterface::n_vec_dim (const MeshBase & mesh,
26592678
const FEType & fe_type)
26602679
{

0 commit comments

Comments
 (0)