1 /* *****************************************************************
2     MESQUITE -- The Mesh Quality Improvement Toolkit
3 
4     Copyright 2006 Sandia National Laboratories.  Developed at the
5     University of Wisconsin--Madison under SNL contract number
6     624796.  The U.S. Government and the University of Wisconsin
7     retian certain rights to this software.
8 
9     This library is free software; you can redistribute it and/or
10     modify it under the terms of the GNU Lesser General Public
11     License as published by the Free Software Foundation; either
12     version 2.1 of the License, or (at your option) any later version.
13 
14     This library is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17     Lesser General Public License for more details.
18 
19     You should have received a copy of the GNU Lesser General Public License
20     (lgpl.txt) along with this library; if not, write to the Free Software
21     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 
23     (2010) kraftche@cae.wisc.edu
24 
25   ***************************************************************** */
26 
27 
28 /** \file HexLagrangeShapeTest.cpp
29  *  \brief
30  *  \author Jason Kraftcheck
31  */
32 
33 #include "Mesquite.hpp"
34 #include "HexLagrangeShape.hpp"
35 #include "TopologyInfo.hpp"
36 #include "MsqError.hpp"
37 #include "IdealElements.hpp"
38 #include "JacobianCalculator.hpp"
39 
40 #include "UnitUtil.hpp"
41 
42 #include <vector>
43 #include <algorithm>
44 #include <iostream>
45 #include <sstream>
46 
47 using namespace MBMesquite;
48 using namespace std;
49 const double epsilon = 1e-6;
50 #define ASSERT_VALUES_EQUAL( v1, v2, location ) \
51   ASSERT_MESSAGE( value_message( (location), (v1), (v2) ), test_value((v1), (v2)) )
52 
test_value(double v1,double v2)53 static bool test_value( double v1, double v2 )
54   { return fabs(v1 - v2) < epsilon; }
55 
value_message(unsigned location,double v1,double v2)56 static inline CppUnit::Message value_message( unsigned location, double v1, double v2 )
57 {
58   CppUnit::Message m( "equality assertion failed" );
59 
60   std::ostringstream buffer1;
61   buffer1 << "Expected : " << v1;
62    m.addDetail( buffer1.str() );
63 
64   std::ostringstream buffer2;
65   buffer2 << "Actual   : " << v2;
66   m.addDetail( buffer2.str() );
67 
68   std::ostringstream buffer3;
69   buffer3 << "Location : ";
70   if (location < 9)
71     buffer3 << "Corner " << location;
72   else if (location < 20)
73     buffer3 << "Edge " << location-8;
74   else if (location < 26)
75     buffer3 << "Face " << location-20;
76   else if (location == 26)
77     buffer3 << "Mid-element";
78   else
79     buffer3 << "INVALID!!";
80   m.addDetail( buffer3.str() );
81   return m;
82 }
83 
test_value(MsqVector<3> v1,MsqVector<3> v2)84 static bool test_value( MsqVector<3> v1, MsqVector<3> v2 )
85   { return length(v1 - v2) < epsilon; }
86 
value_message(unsigned location,MsqVector<3> v1,MsqVector<3> v2)87 static inline CppUnit::Message value_message( unsigned location,
88                                               MsqVector<3> v1,
89                                               MsqVector<3> v2 )
90 {
91   CppUnit::Message m( "equality assertion failed" );
92 
93   std::ostringstream buffer1;
94   buffer1 << "Expected : [" << v1[0] << ", " << v1[1] << ", " << v1[2] << "]";
95    m.addDetail( buffer1.str() );
96 
97   std::ostringstream buffer2;
98   buffer2 << "Actual   : [" << v2[0] << ", " << v2[1] << ", " << v2[2] << "]";
99   m.addDetail( buffer2.str() );
100 
101   std::ostringstream buffer3;
102   buffer3 << "Location : ";
103   if (location < 9)
104     buffer3 << "Corner " << location;
105   else if (location < 20)
106     buffer3 << "Edge " << location-8;
107   else if (location < 26)
108     buffer3 << "Face " << location-20;
109   else if (location == 26)
110     buffer3 << "Mid-element";
111   else
112     buffer3 << "INVALID!!";
113   m.addDetail( buffer3.str() );
114   return m;
115 }
116 
117 class HexLagrangeShapeTest : public CppUnit::TestFixture
118 {
119   private:
120     CPPUNIT_TEST_SUITE(HexLagrangeShapeTest);
121 
122     CPPUNIT_TEST(test_corners_coeff);
123     CPPUNIT_TEST(test_edges_coeff);
124     CPPUNIT_TEST(test_faces_coeff);
125     CPPUNIT_TEST(test_mid_coeff);
126 
127     CPPUNIT_TEST(test_corners_derivs);
128     CPPUNIT_TEST(test_edges_derivs);
129     CPPUNIT_TEST(test_faces_derivs);
130     CPPUNIT_TEST(test_mid_derivs);
131 
132     CPPUNIT_TEST(test_ideal_jacobian);
133 
134     CPPUNIT_TEST_SUITE_END();
135 
136     HexLagrangeShape sf;
137 
138   public:
139 
140     void test_corner_coeff( int corner );
141     void test_edge_coeff( int edge );
142     void test_face_coeff( int face );
143     void test_mid_coeff();
144 
145     void test_corner_derivs( int corner );
146     void test_edge_derivs( int edge );
147     void test_face_derivs( int face );
148     void test_mid_derivs();
149 
150     NodeSet allNodes;
setUp()151     void setUp() { allNodes.set_all_nodes( HEXAHEDRON ); }
152 
153     void test_corners_coeff();
154     void test_edges_coeff();
155     void test_faces_coeff();
156 
157     void test_corners_derivs();
158     void test_edges_derivs();
159     void test_faces_derivs();
160 
161     void test_ideal_jacobian();
162 };
163 
164 
165 
166 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(HexLagrangeShapeTest, "HexLagrangeShapeTest");
167 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(HexLagrangeShapeTest, "Unit");
168 
169 // Indices
170 enum { XI = 0, ETA = 1, ZETA = 2 };
171 // Parameter range
172 const double min_xi =  0;
173 const double max_xi =  1;
174 const double mid_xi = 0.5*(min_xi + max_xi);
175 
176 // Some lagrange polynomial terms
l21(double xi)177 static double l21( double xi ) { return (2 * xi - 1) * (xi - 1); }
l22(double xi)178 static double l22( double xi ) { return 4 * xi * (1 - xi); }
l23(double xi)179 static double l23( double xi ) { return xi * (2 * xi - 1); }
180 // First derivatives of lagrange polynomial terms
dl21(double xi)181 static double dl21( double xi ) { return 4 * xi - 3; }
dl22(double xi)182 static double dl22( double xi ) { return  4 - 8 * xi; }
dl23(double xi)183 static double dl23( double xi ) { return  4 * xi - 1; }
184 // Indexible polynomail terms
185 typedef double (*f_t)(double);
186 f_t l[4] = { 0, &l21, &l22, &l23 };
187 f_t dl[4] = { 0, &dl21, &dl22, &dl23 };
188 const int C[][3] = {
189    { 1, 1, 1 }, //   0
190    { 3, 1, 1 }, //   1
191    { 3, 3, 1 }, //   2
192    { 1, 3, 1 }, //   3
193 
194    { 1, 1, 3 }, //   4
195    { 3, 1, 3 }, //   5
196    { 3, 3, 3 }, //   6
197    { 1, 3, 3 }, //   7
198 
199    { 2, 1, 1 }, //   8
200    { 3, 2, 1 }, //   9
201    { 2, 3, 1 }, //  10
202    { 1, 2, 1 }, //  11
203 
204    { 1, 1, 2 }, //  12
205    { 3, 1, 2 }, //  13
206    { 3, 3, 2 }, //  14
207    { 1, 3, 2 }, //  15
208 
209    { 2, 1, 3 }, //  16
210    { 3, 2, 3 }, //  17
211    { 2, 3, 3 }, //  18
212    { 1, 2, 3 }, //  19
213 
214    { 2, 1, 2 }, //  20
215    { 3, 2, 2 }, //  21
216    { 2, 3, 2 }, //  22
217    { 1, 2, 2 }, //  23
218 
219    { 2, 2, 1 }, //  24
220    { 2, 2, 3 }, //  25
221 
222    { 2, 2, 2 }  //  26
223 };
224 
225 const double corners[8][3] = {
226   { min_xi, min_xi, min_xi },
227   { max_xi, min_xi, min_xi },
228   { max_xi, max_xi, min_xi },
229   { min_xi, max_xi, min_xi },
230   { min_xi, min_xi, max_xi },
231   { max_xi, min_xi, max_xi },
232   { max_xi, max_xi, max_xi },
233   { min_xi, max_xi, max_xi } };
234 
XI_corner(int i)235 static MsqVector<3> XI_corner( int i )
236   { return MsqVector<3>(corners[i]); }
237 
XI_edge(int i)238 static MsqVector<3> XI_edge( int i )
239   {
240     const unsigned* idx = TopologyInfo::edge_vertices( HEXAHEDRON, i );
241     return 0.5 * (XI_corner(idx[0]) + XI_corner(idx[1]));
242   }
243 
XI_face(int i)244 static MsqVector<3> XI_face( int i )
245   {
246     unsigned n;
247     const unsigned* idx = TopologyInfo::face_vertices( HEXAHEDRON, i, n );
248     MsqVector<3> result = XI_corner(idx[0]);
249     for (unsigned j = 1; j < n; ++j)
250       result += XI_corner(idx[j]);
251     result *= 1.0/n;
252     return result;
253   }
254 
XI_elem()255 static MsqVector<3> XI_elem()
256   {
257     const double vals[] = { mid_xi, mid_xi, mid_xi };
258     return MsqVector<3>(vals);
259   }
260 
N(int i,MsqVector<3> xi)261 static double N( int i, MsqVector<3> xi )
262 {
263   const int* c = C[i];
264   return l[c[XI]](xi[XI]) * l[c[ETA]](xi[ETA]) * l[c[ZETA]](xi[ZETA]);
265 }
266 
dN(int i,MsqVector<3> xi)267 static MsqVector<3> dN( int i, MsqVector<3> xi )
268 {
269   MsqVector<3> result;
270   const int* c = C[i];
271   result[XI  ] = dl[c[XI]](xi[XI]) *  l[c[ETA]](xi[ETA]) *  l[c[ZETA]](xi[ZETA]);
272   result[ETA ] =  l[c[XI]](xi[XI]) * dl[c[ETA]](xi[ETA]) *  l[c[ZETA]](xi[ZETA]);
273   result[ZETA] =  l[c[XI]](xi[XI]) *  l[c[ETA]](xi[ETA]) * dl[c[ZETA]](xi[ZETA]);
274   return result;
275 }
276 
get_coeffs(MsqVector<3> xi,double coeffs_out[27])277 static void get_coeffs( MsqVector<3> xi, double coeffs_out[27] )
278 {
279   for (int i = 0; i < 27; ++i)
280     coeffs_out[i] = N(i, xi);
281 }
282 
get_derivs(MsqVector<3> xi,MsqVector<3> derivs_out[27])283 static void get_derivs( MsqVector<3> xi, MsqVector<3> derivs_out[27] )
284 {
285   for (int i = 0; i < 27; ++i)
286     derivs_out[i] = dN(i, xi);
287 }
288 
289 
290 
check_valid_indices(const size_t * vertices,size_t num_vtx)291 static void check_valid_indices( const size_t* vertices, size_t num_vtx )
292 {
293     // check valid size of list (at least fout, at most all nodes)
294   CPPUNIT_ASSERT( num_vtx <= 27 );
295   CPPUNIT_ASSERT( num_vtx >= 4 );
296     // make sure vertex indices are valid (in [0,26])
297   size_t vertcopy[27];
298   std::copy( vertices, vertices+num_vtx, vertcopy );
299   std::sort( vertcopy, vertcopy+num_vtx );
300   CPPUNIT_ASSERT( vertcopy[num_vtx-1] <= 26 ); // max value less than 27
301     // make sure there are no duplicates in the list
302   const size_t* iter = std::unique( vertcopy, vertcopy+num_vtx );
303   CPPUNIT_ASSERT( iter == vertcopy+num_vtx );
304 }
305 
check_no_zeros(const MsqVector<3> * derivs,size_t num_vtx)306 static void check_no_zeros( const MsqVector<3>* derivs, size_t num_vtx )
307 {
308   for (unsigned i = 0; i < num_vtx; ++i) {
309     CPPUNIT_ASSERT( length(derivs[i]) > 1e-6 );
310   }
311 }
312 
compare_coefficients(const double * coeffs,const size_t * indices,size_t num_coeff,const double * expected_coeffs,unsigned loc)313 static void compare_coefficients( const double* coeffs,
314                                   const size_t* indices,
315                                   size_t num_coeff,
316                                   const double* expected_coeffs,
317                                   unsigned loc )
318 {
319     // find the location in the returned list for each node
320   size_t revidx[27];
321   double test_vals[27];
322   for (size_t i = 0; i < 27; ++i) {
323     revidx[i] = std::find( indices, indices+num_coeff, i ) - indices;
324     test_vals[i] = (revidx[i] == num_coeff) ? 0.0 : coeffs[revidx[i]];
325   }
326 
327     // compare expected and actual coefficient values
328   ASSERT_VALUES_EQUAL( expected_coeffs[0], test_vals[0], loc );
329   ASSERT_VALUES_EQUAL( expected_coeffs[1], test_vals[1], loc );
330   ASSERT_VALUES_EQUAL( expected_coeffs[2], test_vals[2], loc );
331   ASSERT_VALUES_EQUAL( expected_coeffs[3], test_vals[3], loc );
332   ASSERT_VALUES_EQUAL( expected_coeffs[4], test_vals[4], loc );
333   ASSERT_VALUES_EQUAL( expected_coeffs[5], test_vals[5], loc );
334   ASSERT_VALUES_EQUAL( expected_coeffs[6], test_vals[6], loc );
335   ASSERT_VALUES_EQUAL( expected_coeffs[7], test_vals[7], loc );
336   ASSERT_VALUES_EQUAL( expected_coeffs[8], test_vals[8], loc );
337   ASSERT_VALUES_EQUAL( expected_coeffs[9], test_vals[9], loc );
338   ASSERT_VALUES_EQUAL( expected_coeffs[10], test_vals[10], loc );
339   ASSERT_VALUES_EQUAL( expected_coeffs[11], test_vals[11], loc );
340   ASSERT_VALUES_EQUAL( expected_coeffs[12], test_vals[12], loc );
341   ASSERT_VALUES_EQUAL( expected_coeffs[13], test_vals[13], loc );
342   ASSERT_VALUES_EQUAL( expected_coeffs[14], test_vals[14], loc );
343   ASSERT_VALUES_EQUAL( expected_coeffs[15], test_vals[15], loc );
344   ASSERT_VALUES_EQUAL( expected_coeffs[16], test_vals[16], loc );
345   ASSERT_VALUES_EQUAL( expected_coeffs[17], test_vals[17], loc );
346   ASSERT_VALUES_EQUAL( expected_coeffs[18], test_vals[18], loc );
347   ASSERT_VALUES_EQUAL( expected_coeffs[19], test_vals[19], loc );
348   ASSERT_VALUES_EQUAL( expected_coeffs[20], test_vals[20], loc );
349   ASSERT_VALUES_EQUAL( expected_coeffs[21], test_vals[21], loc );
350   ASSERT_VALUES_EQUAL( expected_coeffs[22], test_vals[22], loc );
351   ASSERT_VALUES_EQUAL( expected_coeffs[23], test_vals[23], loc );
352   ASSERT_VALUES_EQUAL( expected_coeffs[24], test_vals[24], loc );
353   ASSERT_VALUES_EQUAL( expected_coeffs[25], test_vals[25], loc );
354   ASSERT_VALUES_EQUAL( expected_coeffs[26], test_vals[26], loc );
355 }
356 
compare_derivatives(const size_t * vertices,size_t num_vtx,const MsqVector<3> * actual,const MsqVector<3> * expected,unsigned loc)357 static void compare_derivatives( const size_t* vertices,
358                                  size_t num_vtx,
359                                  const MsqVector<3>* actual,
360                                  const MsqVector<3>* expected,
361                                  unsigned loc )
362 {
363   check_valid_indices( vertices, num_vtx );
364   check_no_zeros( actual, num_vtx );
365 
366     // Input has values in dxi & deta & dzeta only for nodes in 'vertices'
367     // Convert to values for every possible node, with zero's for
368     // nodes that are not present.
369   CPPUNIT_ASSERT(num_vtx <= 9);
370   MsqVector<3> expanded[27];
371   std::fill( expanded, expanded+27,MsqVector<3>(0.0) );
372   for (unsigned i = 0; i < num_vtx; ++i) {
373     CPPUNIT_ASSERT(vertices[i] <= 26);
374     expanded[vertices[i]] = actual[i];
375   }
376 
377   ASSERT_VALUES_EQUAL( expected[0], expanded[0], loc );
378   ASSERT_VALUES_EQUAL( expected[1], expanded[1], loc );
379   ASSERT_VALUES_EQUAL( expected[2], expanded[2], loc );
380   ASSERT_VALUES_EQUAL( expected[3], expanded[3], loc );
381   ASSERT_VALUES_EQUAL( expected[4], expanded[4], loc );
382   ASSERT_VALUES_EQUAL( expected[5], expanded[5], loc );
383   ASSERT_VALUES_EQUAL( expected[6], expanded[6], loc );
384   ASSERT_VALUES_EQUAL( expected[7], expanded[7], loc );
385   ASSERT_VALUES_EQUAL( expected[8], expanded[8], loc );
386   ASSERT_VALUES_EQUAL( expected[9], expanded[9], loc );
387   ASSERT_VALUES_EQUAL( expected[10], expanded[10], loc );
388   ASSERT_VALUES_EQUAL( expected[11], expanded[11], loc );
389   ASSERT_VALUES_EQUAL( expected[12], expanded[12], loc );
390   ASSERT_VALUES_EQUAL( expected[13], expanded[13], loc );
391   ASSERT_VALUES_EQUAL( expected[14], expanded[14], loc );
392   ASSERT_VALUES_EQUAL( expected[15], expanded[15], loc );
393   ASSERT_VALUES_EQUAL( expected[16], expanded[16], loc );
394   ASSERT_VALUES_EQUAL( expected[17], expanded[17], loc );
395   ASSERT_VALUES_EQUAL( expected[18], expanded[18], loc );
396   ASSERT_VALUES_EQUAL( expected[19], expanded[19], loc );
397   ASSERT_VALUES_EQUAL( expected[20], expanded[20], loc );
398   ASSERT_VALUES_EQUAL( expected[21], expanded[21], loc );
399   ASSERT_VALUES_EQUAL( expected[22], expanded[22], loc );
400   ASSERT_VALUES_EQUAL( expected[23], expanded[23], loc );
401   ASSERT_VALUES_EQUAL( expected[24], expanded[24], loc );
402   ASSERT_VALUES_EQUAL( expected[25], expanded[25], loc );
403   ASSERT_VALUES_EQUAL( expected[26], expanded[26], loc );
404 }
405 
test_corner_coeff(int corner)406 void HexLagrangeShapeTest::test_corner_coeff( int corner )
407 {
408   MsqPrintError err(std::cout);
409 
410   double expected[27];
411   get_coeffs( XI_corner(corner), expected );
412 
413   double coeff[100];
414   size_t num_coeff = 11, indices[100];
415   sf.coefficients( Sample(0, corner), allNodes, coeff, indices, num_coeff, err );
416   CPPUNIT_ASSERT( !err );
417 
418   compare_coefficients( coeff, indices, num_coeff, expected, corner );
419 }
420 
test_edge_coeff(int edge)421 void HexLagrangeShapeTest::test_edge_coeff( int edge )
422 {
423   MsqPrintError err(std::cout);
424 
425   double expected[27];
426   get_coeffs( XI_edge(edge), expected );
427 
428   double coeff[100];
429   size_t num_coeff = 11, indices[100];
430   sf.coefficients( Sample(1, edge), allNodes, coeff, indices, num_coeff, err );
431   CPPUNIT_ASSERT( !err );
432 
433   compare_coefficients( coeff, indices, num_coeff, expected, edge+8 );
434 }
435 
test_face_coeff(int face)436 void HexLagrangeShapeTest::test_face_coeff( int face )
437 {
438   MsqPrintError err(std::cout);
439 
440   double expected[27];
441   get_coeffs( XI_face(face), expected );
442 
443   double coeff[100];
444   size_t num_coeff = 11, indices[100];
445   sf.coefficients( Sample(2, face), allNodes, coeff, indices, num_coeff, err );
446   CPPUNIT_ASSERT( !err );
447 
448   compare_coefficients( coeff, indices, num_coeff, expected, face+20 );
449 }
450 
test_mid_coeff()451 void HexLagrangeShapeTest::test_mid_coeff()
452 {
453   MsqPrintError err(std::cout);
454 
455   double expected[27];
456   get_coeffs( XI_elem(), expected );
457 
458   double coeff[100];
459   size_t num_coeff = 11, indices[100];
460   sf.coefficients( Sample(3, 0), allNodes, coeff, indices, num_coeff, err );
461   CPPUNIT_ASSERT( !err );
462 
463   compare_coefficients( coeff, indices, num_coeff, expected, 26 );
464 }
465 
test_corner_derivs(int corner)466 void HexLagrangeShapeTest::test_corner_derivs( int corner )
467 {
468   MsqPrintError err(std::cout);
469 
470   MsqVector<3> expected[27];
471   get_derivs( XI_corner(corner), expected );
472 
473   size_t vertices[100], num_vtx = 23;
474   MsqVector<3> derivs[100];
475   sf.derivatives( Sample(0, corner), allNodes, vertices, derivs, num_vtx, err );
476   CPPUNIT_ASSERT( !err );
477 
478   compare_derivatives( vertices, num_vtx, derivs, expected, corner );
479 }
480 
test_edge_derivs(int edge)481 void HexLagrangeShapeTest::test_edge_derivs( int edge )
482 {
483   MsqPrintError err(std::cout);
484 
485   MsqVector<3> expected[27];
486   get_derivs( XI_edge(edge), expected );
487 
488   size_t vertices[100], num_vtx = 23;
489   MsqVector<3> derivs[100];
490   sf.derivatives( Sample(1, edge), allNodes, vertices, derivs, num_vtx, err );
491   CPPUNIT_ASSERT( !err );
492 
493   compare_derivatives( vertices, num_vtx, derivs, expected, edge+8 );
494 }
495 
test_face_derivs(int face)496 void HexLagrangeShapeTest::test_face_derivs( int face )
497 {
498   MsqPrintError err(std::cout);
499 
500   MsqVector<3> expected[27];
501   get_derivs( XI_face(face), expected );
502 
503   size_t vertices[100], num_vtx = 23;
504   MsqVector<3> derivs[100];
505   sf.derivatives( Sample(2, face), allNodes, vertices, derivs, num_vtx, err );
506   CPPUNIT_ASSERT( !err );
507 
508   compare_derivatives( vertices, num_vtx, derivs, expected, face+20 );
509 }
510 
test_mid_derivs()511 void HexLagrangeShapeTest::test_mid_derivs( )
512 {
513   MsqPrintError err(std::cout);
514 
515   MsqVector<3> expected[27];
516   get_derivs( XI_elem(), expected );
517 
518   size_t vertices[100], num_vtx = 23;
519   MsqVector<3> derivs[100];
520   sf.derivatives( Sample(3, 0), allNodes, vertices, derivs, num_vtx, err );
521   CPPUNIT_ASSERT( !err );
522 
523   compare_derivatives( vertices, num_vtx, derivs, expected, 26 );
524 }
525 
test_corners_coeff()526 void HexLagrangeShapeTest::test_corners_coeff()
527 {
528   for (unsigned i = 0; i < 8; ++i)
529     test_corner_coeff( i );
530 }
531 
test_edges_coeff()532 void HexLagrangeShapeTest::test_edges_coeff()
533 {
534   for (unsigned i = 0; i < 12; ++i)
535     test_edge_coeff( i );
536 }
537 
test_faces_coeff()538 void HexLagrangeShapeTest::test_faces_coeff()
539 {
540   for (unsigned i = 0; i < 6; ++i)
541     test_face_coeff( i );
542 }
543 
test_corners_derivs()544 void HexLagrangeShapeTest::test_corners_derivs()
545 {
546   for (unsigned i = 0; i < 8; ++i)
547     test_corner_derivs( i );
548 }
549 
test_edges_derivs()550 void HexLagrangeShapeTest::test_edges_derivs()
551 {
552   for (unsigned i = 0; i < 12; ++i)
553     test_edge_derivs( i );
554 }
555 
test_faces_derivs()556 void HexLagrangeShapeTest::test_faces_derivs()
557 {
558   for (unsigned i = 0; i < 6; ++i)
559     test_face_derivs( i );
560 }
561 
test_ideal_jacobian()562 void HexLagrangeShapeTest::test_ideal_jacobian()
563 {
564   MsqError err;
565   MsqMatrix<3,3> J_act, J_exp(1.0);
566   sf.ideal( Sample(3,0), J_act, err );
567   ASSERT_NO_ERROR(err);
568 
569     // Matrices should be a rotation of each other.
570     // First, calculate tentative rotation matrix
571   MsqMatrix<3,3> R = inverse(J_exp) * J_act;
572     // next check that it is a rotation
573   CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, det(R), 1e-6 ); // no scaling
574   ASSERT_MATRICES_EQUAL( transpose(R), inverse(R), 1e-6 ); // orthogonal
575 }
576