@@ -34,6 +34,25 @@ Number trilinear_function (const Point & p,
3434}
3535
3636
37+ Number bilinear_function (const Point & p ,
38+ const Parameters & ,
39+ const std ::string & ,
40+ const std ::string & )
41+ {
42+ return 8 * p (0 ) + 80 * p (1 );
43+ }
44+
45+
46+ Number biquadratic_function (const Point & p ,
47+ const Parameters & ,
48+ const std ::string & ,
49+ const std ::string & )
50+ {
51+ return 7.5 * p (0 )* p (0 ) + 75 * p (1 )* p (1 ) + 0.75 * p (1 )* p (0 );
52+ }
53+
54+
55+
3756class MeshFunctionTest : public CppUnit ::TestCase
3857{
3958 /**
@@ -44,6 +63,10 @@ public:
4463
4564#if LIBMESH_DIM > 1
4665 CPPUNIT_TEST ( test_subdomain_id_sets );
66+ CPPUNIT_TEST ( test_bad_gradient_var_with_out_of_mesh_value );
67+ #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
68+ CPPUNIT_TEST ( test_bad_hessian_var_with_out_of_mesh_value );
69+ #endif
4770#ifdef LIBMESH_HAVE_PETSC
4871 CPPUNIT_TEST ( vectorMeshFunctionLagrange );
4972 CPPUNIT_TEST ( vectorMeshFunctionNedelec );
@@ -154,6 +177,144 @@ public:
154177 }
155178 }
156179
180+ void test_bad_gradient_var_with_out_of_mesh_value ()
181+ {
182+ LOG_UNIT_TEST ;
183+
184+ ReplicatedMesh mesh (* TestCommWorld );
185+
186+ MeshTools ::Generation ::build_square (mesh ,
187+ 4 , 4 ,
188+ 0. , 1. ,
189+ 0. , 1. ,
190+ QUAD4 );
191+
192+ EquationSystems es (mesh );
193+ System & sys = es .add_system < System > ("SimpleSystem" );
194+ unsigned int u_var = sys .add_variable ("u" , FIRST , LAGRANGE );
195+
196+ es .init ();
197+ sys .project_solution (bilinear_function , nullptr , es .parameters );
198+
199+ std ::vector < unsigned int > variables {u_var , libMesh ::invalid_uint };
200+ MeshFunction mesh_function (es ,
201+ * sys .current_local_solution ,
202+ sys .get_dof_map (),
203+ variables );
204+ mesh_function .init ();
205+
206+ DenseVector < Number > out_of_mesh_value (2 );
207+ out_of_mesh_value (0 ) = -99.0 ;
208+ out_of_mesh_value (1 ) = 5.25 ;
209+ mesh_function .enable_out_of_mesh_mode (out_of_mesh_value );
210+
211+ std ::vector < Gradient > gradients ;
212+ const Point p (0.4 , 0.6 , 0.0 );
213+
214+ // On a distributed mesh not every processor may have every
215+ // element
216+ const Elem * elem = (* mesh .sub_point_locator ())(p );
217+ bool someone_found_elem = elem ;
218+ mesh .comm ().max (someone_found_elem );
219+ CPPUNIT_ASSERT (someone_found_elem );
220+
221+ mesh_function .gradient (p , 0.0 , gradients );
222+
223+ // Let's only test our evaluation where we know we can evaluate, in parallel
224+ if (!elem || elem -> processor_id () != mesh .processor_id ())
225+ return ;
226+
227+ CPPUNIT_ASSERT_EQUAL (std ::size_t (2 ), gradients .size ());
228+
229+ LIBMESH_ASSERT_NUMBERS_EQUAL (8.0 , gradients [0 ](0 ), TOLERANCE * TOLERANCE );
230+ LIBMESH_ASSERT_NUMBERS_EQUAL (80.0 , gradients [0 ](1 ), TOLERANCE * TOLERANCE );
231+ if (LIBMESH_DIM > 2 )
232+ LIBMESH_ASSERT_NUMBERS_EQUAL (0.0 , gradients [0 ](2 ), TOLERANCE * TOLERANCE );
233+
234+ LIBMESH_ASSERT_NUMBERS_EQUAL (out_of_mesh_value (1 ),
235+ gradients [1 ](0 ),
236+ TOLERANCE * TOLERANCE );
237+ for (unsigned int d = 1 ; d < LIBMESH_DIM ; ++ d )
238+ LIBMESH_ASSERT_NUMBERS_EQUAL (0 , gradients [1 ](d ),
239+ TOLERANCE * TOLERANCE );
240+ }
241+
242+ #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
243+ void test_bad_hessian_var_with_out_of_mesh_value ()
244+ {
245+ LOG_UNIT_TEST ;
246+
247+ // Hessian calculations are a little weaker in FP on some systems
248+ const Real tol = TOLERANCE * std ::sqrt (TOLERANCE );
249+
250+ ReplicatedMesh mesh (* TestCommWorld );
251+
252+ MeshTools ::Generation ::build_square (mesh ,
253+ 4 , 4 ,
254+ 0. , 1. ,
255+ 0. , 1. ,
256+ QUAD9 );
257+
258+ EquationSystems es (mesh );
259+ System & sys = es .add_system < System > ("SimpleSystem" );
260+ unsigned int u_var = sys .add_variable ("u" , SECOND , LAGRANGE );
261+
262+ es .init ();
263+ sys .project_solution (biquadratic_function , nullptr , es .parameters );
264+
265+ std ::vector < unsigned int > variables {u_var , libMesh ::invalid_uint };
266+ MeshFunction mesh_function (es ,
267+ * sys .current_local_solution ,
268+ sys .get_dof_map (),
269+ variables );
270+ mesh_function .init ();
271+
272+ DenseVector < Number > out_of_mesh_value (2 );
273+ out_of_mesh_value (0 ) = -99.0 ;
274+ out_of_mesh_value (1 ) = 5.25 ;
275+ mesh_function .enable_out_of_mesh_mode (out_of_mesh_value );
276+
277+ std ::vector < Tensor > hessians ;
278+ const Point p (0.4 , 0.6 , 0.0 );
279+
280+ // On a distributed mesh not every processor may have every
281+ // element
282+ const Elem * elem = (* mesh .sub_point_locator ())(p );
283+ bool someone_found_elem = elem ;
284+ mesh .comm ().max (someone_found_elem );
285+ CPPUNIT_ASSERT (someone_found_elem );
286+
287+ mesh_function .hessian (p , 0.0 , hessians );
288+
289+ // Let's only test our evaluation where we know we can evaluate, in parallel
290+ if (!elem || elem -> processor_id () != mesh .processor_id ())
291+ return ;
292+
293+ CPPUNIT_ASSERT_EQUAL (std ::size_t (2 ), hessians .size ());
294+
295+ LIBMESH_ASSERT_NUMBERS_EQUAL (15.0 , hessians [0 ](0 ,0 ), tol );
296+ LIBMESH_ASSERT_NUMBERS_EQUAL (0.75 , hessians [0 ](0 ,1 ), tol );
297+ LIBMESH_ASSERT_NUMBERS_EQUAL (0.75 , hessians [0 ](1 ,0 ), tol );
298+ LIBMESH_ASSERT_NUMBERS_EQUAL (150.0 , hessians [0 ](1 ,1 ), tol );
299+
300+ if (LIBMESH_DIM > 2 )
301+ for (unsigned int d = 0 ; d < LIBMESH_DIM ; ++ d )
302+ for (unsigned int d2 = 0 ; d2 < LIBMESH_DIM ; ++ d2 )
303+ if (d > 1 || d2 > 1 )
304+ LIBMESH_ASSERT_NUMBERS_EQUAL (0 , hessians [1 ](d ,d2 ),
305+ tol );
306+
307+ LIBMESH_ASSERT_NUMBERS_EQUAL (out_of_mesh_value (1 ),
308+ hessians [1 ](0 ,0 ),
309+ tol );
310+ for (unsigned int d = 0 ; d < LIBMESH_DIM ; ++ d )
311+ for (unsigned int d2 = 0 ; d2 < LIBMESH_DIM ; ++ d2 )
312+ if (d || d2 )
313+ LIBMESH_ASSERT_NUMBERS_EQUAL (0 , hessians [1 ](d ,d2 ),
314+ tol );
315+ }
316+ #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
317+
157318 // test that mesh function works correctly with non-zero
158319 // Elem::p_level() values.
159320#ifdef LIBMESH_ENABLE_AMR
0 commit comments