@@ -42,8 +42,9 @@ namespace {
42
42
namespace libMesh
43
43
{
44
44
// ------------------------------------------------------------
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
47
48
static const bool * caching = nullptr ;
48
49
49
50
class CachingSetup : public Singleton ::Setup
@@ -148,6 +149,50 @@ void FE<Dim,T>::dofs_on_edge(const Elem * const elem,
148
149
149
150
150
151
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
+
151
196
template < unsigned int Dim , FEFamily T >
152
197
void FE < Dim ,T > ::reinit (const Elem * elem ,
153
198
const std ::vector < Point > * const pts ,
@@ -162,7 +207,7 @@ void FE<Dim,T>::reinit(const Elem * elem,
162
207
163
208
// Try to avoid calling init_shape_functions
164
209
// even when shapes_need_reinit
165
- bool cached_nodes_still_fit = false;
210
+ bool cached_elem_still_fits = false;
166
211
167
212
// Most of the hard work happens when we have an actual element
168
213
if (elem )
@@ -215,6 +260,7 @@ void FE<Dim,T>::reinit(const Elem * elem,
215
260
this -> _elem_type = elem -> type ();
216
261
this -> _elem_p_level = elem -> p_level ();
217
262
this -> _p_level = this -> _add_p_level_in_reinit * elem -> p_level ();
263
+
218
264
// Initialize the shape functions
219
265
this -> _fe_map -> template init_reference_to_physical_map < Dim >
220
266
(this -> qrule -> get_points (), elem );
@@ -223,27 +269,22 @@ void FE<Dim,T>::reinit(const Elem * elem,
223
269
else
224
270
{
225
271
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
+
231
276
// 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 )
233
278
{
234
279
this -> _fe_map -> template init_reference_to_physical_map < Dim >
235
280
(this -> qrule -> get_points (), elem );
236
281
this -> init_shape_functions (this -> qrule -> get_points (), elem );
237
282
}
238
283
}
239
284
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 );
247
288
248
289
// The shape functions correspond to the qrule
249
290
this -> shapes_on_quadrature = true;
@@ -300,7 +341,7 @@ void FE<Dim,T>::reinit(const Elem * elem,
300
341
301
342
// Compute the shape functions and the derivatives at all of the
302
343
// quadrature points.
303
- if (!cached_nodes_still_fit )
344
+ if (!cached_elem_still_fits )
304
345
{
305
346
if (pts != nullptr )
306
347
this -> compute_shape_functions (elem ,* pts );
0 commit comments