1 /* *****************************************************************
2     MESQUITE -- The Mesh Quality Improvement Toolkit
3 
4     Copyright 2006 Lawrence Livermore National Laboratory.  Under
5     the terms of Contract B545069 with the University of Wisconsin --
6     Madison, Lawrence Livermore National Laboratory retains certain
7     rights in 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     (2006) kraftche@cae.wisc.edu
24 
25   ***************************************************************** */
26 
27 
28 /** \file CachingTargetTest.cpp
29  *  \brief Unit tests for CachingTargetCalculator class
30  *  \author Jason Kraftcheck
31  */
32 
33 #include "Mesquite.hpp"
34 #include "CachingTargetCalculator.hpp"
35 #include "PatchData.hpp"
36 #include "UnitUtil.hpp"
37 #include "PatchDataInstances.hpp"
38 #include <cppunit/extensions/HelperMacros.h>
39 #include <algorithm>
40 
41 using namespace MBMesquite;
42 
43 class CachedTargetCalculator;
44 
45 class CachingTargetTest : public CppUnit::TestFixture
46 {
47 private:
48   CPPUNIT_TEST_SUITE(CachingTargetTest);
49   CPPUNIT_TEST (test_surface_orient_flag);
50   CPPUNIT_TEST (test_3d_targets_cached);
51   CPPUNIT_TEST (test_2d_targets_cached);
52   CPPUNIT_TEST (test_surface_targets_cached);
53   CPPUNIT_TEST (test_3d_target_values);
54   CPPUNIT_TEST (test_2d_target_values);
55   CPPUNIT_TEST (test_surface_target_values);
56   CPPUNIT_TEST (test_3d_target_subpatch);
57   CPPUNIT_TEST (test_2d_target_subpatch);
58   CPPUNIT_TEST (test_surface_target_subpatch);
59   CPPUNIT_TEST (test_cache_cleared);
60   CPPUNIT_TEST_SUITE_END();
61 
62   PatchData patch_3d, patch_2d;
63   CachedTargetCalculator* cached;
64   CachingTargetCalculator* cacher;
65 
66   unsigned request_all_targets_3d();
67   unsigned request_all_targets_2d();
68   unsigned request_all_targets_surf();
69 
70 public:
71 
72   void setUp();
73   void tearDown();
74 
75   void test_surface_orient_flag();
76   void test_3d_targets_cached();
77   void test_2d_targets_cached();
78   void test_surface_targets_cached();
79   void test_3d_target_values();
80   void test_2d_target_values();
81   void test_surface_target_values();
82   void test_3d_target_subpatch();
83   void test_2d_target_subpatch();
84   void test_surface_target_subpatch();
85   void test_cache_cleared();
86 
87 };
88 
89 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CachingTargetTest, "CachingTargetTest");
90 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CachingTargetTest, "Unit");
91 
92 class CachedTargetCalculator : public TargetCalculator
93 {
94   private:
95     unsigned called_3d, called_2d, called_surf;
96     bool surfOrientFlag;
97 
98   public:
99 
100     static MsqMatrix<3,3> make_3d( size_t elem, Sample sample );
101     static MsqMatrix<2,2> make_2d( size_t elem, Sample sample );
102     static MsqMatrix<3,2> make_surf( size_t elem, Sample sample );
103 
CachedTargetCalculator()104     CachedTargetCalculator()
105       : called_3d(0), called_2d(0), called_surf(0), surfOrientFlag(true) {}
106 
get_3D_target(PatchData &,size_t elem,Sample sample,MsqMatrix<3,3> & result,MsqError &)107     virtual bool get_3D_target( PatchData&, size_t elem, Sample sample, MsqMatrix<3,3>& result, MsqError& )
108       { ++called_3d; result = make_3d( elem, sample); return true; }
109 
get_2D_target(PatchData &,size_t elem,Sample sample,MsqMatrix<2,2> & result,MsqError &)110     virtual bool get_2D_target( PatchData&, size_t elem, Sample sample, MsqMatrix<2,2>& result, MsqError& )
111       { ++called_2d; result = make_2d( elem, sample); return true; }
112 
get_surface_target(PatchData &,size_t elem,Sample sample,MsqMatrix<3,2> & result,MsqError &)113     virtual bool get_surface_target( PatchData&, size_t elem, Sample sample, MsqMatrix<3,2>& result, MsqError& )
114       { ++called_surf; result = make_surf( elem, sample); return true; }
115 
clear()116     void clear()
117       { called_3d = 0; called_2d = 0; called_surf = 0; }
118 
calls_3d() const119     unsigned calls_3d() const
120       { return called_3d; }
121 
calls_2d() const122     unsigned calls_2d() const
123       { return called_2d; }
124 
calls_surf() const125     unsigned calls_surf() const
126       { return called_surf; }
127 
surf_orient(bool value)128     void surf_orient( bool value )
129       { surfOrientFlag = value; }
130 
have_surface_orient() const131     virtual bool have_surface_orient() const
132       { return surfOrientFlag; }
133 };
134 
make_3d(size_t elem,Sample sample)135 MsqMatrix<3,3> CachedTargetCalculator::make_3d( size_t elem, Sample sample )
136 {
137   double v = 100. * elem + 4 * sample.number + sample.dimension + 1;
138   const double values[] = { v, 0, 0,
139                             0, v, 0,
140                             0, 0, 1/v };
141   return MsqMatrix<3,3>(values);
142 }
143 
make_2d(size_t elem,Sample sample)144 MsqMatrix<2,2> CachedTargetCalculator::make_2d( size_t elem, Sample sample )
145 {
146   double v = 100. * elem + 4 * sample.number + sample.dimension + 1;
147   const double values[] = { v, 0,
148                             0, 1/v };
149   return MsqMatrix<2,2>(values);
150 }
151 
make_surf(size_t elem,Sample sample)152 MsqMatrix<3,2> CachedTargetCalculator::make_surf( size_t elem, Sample sample )
153 {
154   double v = 100. * elem + 4 * sample.number + sample.dimension + 1;
155   const double values[] = { v, 0,
156                             0, v,
157                             0.5*v, 0.5*v };
158   return MsqMatrix<3,2>(values);
159 }
160 
setUp()161 void CachingTargetTest::setUp()
162 {
163     // make sure these are null so that if we fail within setUp,
164     // tearDown doesn't try to delete stale pointers
165   cached = 0;
166   cacher = 0;
167 
168   MsqError err;
169   create_four_quads_patch( patch_2d, err ); CPPUNIT_ASSERT(!err);
170   create_qm_two_hex_patch( patch_3d, err ); CPPUNIT_ASSERT(!err);
171 
172   cached = new CachedTargetCalculator( );
173   cacher = new CachingTargetCalculator( cached );
174 }
175 
request_all_targets_3d()176 unsigned CachingTargetTest::request_all_targets_3d()
177 {
178   unsigned total = 0;
179   MsqMatrix<3,3> W;
180   MsqPrintError err(std::cout);
181   std::vector<Sample> locations;
182 
183   for (size_t i = 0; i < patch_3d.num_elements(); ++i)
184   {
185     patch_3d.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
186     total += locations.size();
187     for (unsigned j = 0; j < locations.size(); ++j)
188     {
189       bool rval = cacher->get_3D_target( patch_3d, i, locations[j], W, err );
190       CPPUNIT_ASSERT(rval);
191       CPPUNIT_ASSERT(!err);
192     }
193   }
194   return total;
195 }
196 
request_all_targets_2d()197 unsigned CachingTargetTest::request_all_targets_2d()
198 {
199   unsigned total = 0;
200   MsqMatrix<2,2> W;
201   MsqPrintError err(std::cout);
202   std::vector<Sample> locations;
203 
204   for (size_t i = 0; i < patch_2d.num_elements(); ++i)
205   {
206     patch_2d.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
207     total += locations.size();
208     for (unsigned j = 0; j < locations.size(); ++j)
209     {
210       bool rval = cacher->get_2D_target( patch_2d, i, locations[j], W, err );
211       CPPUNIT_ASSERT(rval);
212       CPPUNIT_ASSERT(!err);
213     }
214   }
215   return total;
216 }
217 
request_all_targets_surf()218 unsigned CachingTargetTest::request_all_targets_surf()
219 {
220   unsigned total = 0;
221   MsqMatrix<3,2> W;
222   MsqPrintError err(std::cout);
223   std::vector<Sample> locations;
224 
225   for (size_t i = 0; i < patch_2d.num_elements(); ++i)
226   {
227     patch_2d.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
228     total += locations.size();
229     for (unsigned j = 0; j < locations.size(); ++j)
230     {
231       bool rval = cacher->get_surface_target( patch_2d, i, locations[j], W, err );
232       CPPUNIT_ASSERT(rval);
233       CPPUNIT_ASSERT(!err);
234     }
235   }
236   return total;
237 }
238 
tearDown()239 void CachingTargetTest::tearDown()
240 {
241   delete cacher;
242   delete cached;
243 }
244 
test_surface_orient_flag()245 void CachingTargetTest::test_surface_orient_flag()
246 {
247   cached->surf_orient(true);
248   CPPUNIT_ASSERT( cacher->have_surface_orient() );
249   cached->surf_orient(false);
250   CPPUNIT_ASSERT( !cacher->have_surface_orient() );
251 }
252 
test_3d_targets_cached()253 void CachingTargetTest::test_3d_targets_cached()
254 {
255   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), 0u );
256   CPPUNIT_ASSERT_EQUAL( cached->calls_surf(), 0u );
257   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), 0u );
258   unsigned count = request_all_targets_3d();
259   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), count );
260   CPPUNIT_ASSERT_EQUAL( cached->calls_surf(), 0u );
261   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), 0u );
262   cached->clear();
263   request_all_targets_3d();
264   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), 0u );
265 }
266 
test_2d_targets_cached()267 void CachingTargetTest::test_2d_targets_cached()
268 {
269   cached->surf_orient(false);
270   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), 0u );
271   CPPUNIT_ASSERT_EQUAL( cached->calls_surf(), 0u );
272   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), 0u );
273   unsigned count = request_all_targets_2d();
274   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), count );
275   CPPUNIT_ASSERT_EQUAL( cached->calls_surf(), 0u );
276   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), 0u );
277   cached->clear();
278   request_all_targets_2d();
279   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), 0u );
280 }
281 
test_surface_targets_cached()282 void CachingTargetTest::test_surface_targets_cached()
283 {
284   cached->surf_orient(true);
285   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), 0u );
286   CPPUNIT_ASSERT_EQUAL( cached->calls_surf(), 0u );
287   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), 0u );
288   unsigned count = request_all_targets_surf();
289   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), 0u );
290   CPPUNIT_ASSERT_EQUAL( cached->calls_surf(), count );
291   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), 0u );
292   cached->clear();
293   request_all_targets_surf();
294   CPPUNIT_ASSERT_EQUAL( cached->calls_surf(), 0u );
295 }
296 
test_3d_target_values()297 void CachingTargetTest::test_3d_target_values()
298 {
299   MsqPrintError err(std::cout);
300   std::vector<Sample> locations;
301 
302     // evaluate all once to make sure we test the cached values
303   request_all_targets_3d();
304 
305     // test each value
306   for (size_t i = 0; i < patch_3d.num_elements(); ++i)
307   {
308     patch_3d.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
309     for (unsigned j = 0; j < locations.size(); ++j)
310     {
311       MsqMatrix<3,3> W;
312       bool rval = cacher->get_3D_target( patch_3d, i, locations[j], W, err );
313       CPPUNIT_ASSERT(rval && !err);
314 
315       MsqMatrix<3,3> M = CachedTargetCalculator::make_3d( i, locations[j] );
316       ASSERT_MATRICES_EQUAL( W, M, DBL_EPSILON );
317     }
318   }
319 }
320 
test_2d_target_values()321 void CachingTargetTest::test_2d_target_values()
322 {
323   MsqPrintError err(std::cout);
324   std::vector<Sample> locations;
325 
326     // evaluate all once to make sure we test the cached values
327   cached->surf_orient(false);
328   request_all_targets_2d();
329 
330     // test each value
331   for (size_t i = 0; i < patch_2d.num_elements(); ++i)
332   {
333     patch_2d.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
334     for (unsigned j = 0; j < locations.size(); ++j)
335     {
336       MsqMatrix<2,2> W;
337       bool rval = cacher->get_2D_target( patch_2d, i, locations[j], W, err );
338       CPPUNIT_ASSERT(rval && !err);
339 
340       MsqMatrix<2,2> M = CachedTargetCalculator::make_2d( i, locations[j] );
341       ASSERT_MATRICES_EQUAL( W, M, DBL_EPSILON );
342     }
343   }
344 }
345 
test_surface_target_values()346 void CachingTargetTest::test_surface_target_values()
347 {
348   MsqPrintError err(std::cout);
349   std::vector<Sample> locations;
350 
351     // evaluate all once to make sure we test the cached values
352   cached->surf_orient(true);
353   request_all_targets_surf();
354 
355     // test each value
356   for (size_t i = 0; i < patch_2d.num_elements(); ++i)
357   {
358     patch_2d.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
359     for (unsigned j = 0; j < locations.size(); ++j)
360     {
361       MsqMatrix<3,2> W;
362       bool rval = cacher->get_surface_target( patch_2d, i, locations[j], W, err );
363       CPPUNIT_ASSERT(rval && !err);
364 
365       MsqMatrix<3,2> M = CachedTargetCalculator::make_surf( i, locations[j] );
366       ASSERT_MATRICES_EQUAL( W, M, DBL_EPSILON );
367     }
368   }
369 }
370 
test_3d_target_subpatch()371 void CachingTargetTest::test_3d_target_subpatch()
372 {
373   MsqPrintError err(std::cout);
374   std::vector<Sample> locations;
375 
376     // cache some values on the main patch
377   request_all_targets_3d();
378 
379     // clear the count so we know if any additional
380     // evalutions of the base target calculator are
381     // done during subpatch creation.
382   cached->clear();
383 
384     // create a sub-patch
385   CPPUNIT_ASSERT( patch_3d.num_nodes() > 1 );
386   PatchData subpatch;
387   patch_3d.get_subpatch( 1, 1, subpatch, err );
388   CPPUNIT_ASSERT( !err );
389 
390     // make sure we copied the cached values onto the subpatch
391   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), 0u );
392 
393     // Test the values for each cached matrix on the subpatch
394     // NOTE:  This test takes advantange of the fact that the
395     // "handles" in the subpatch are indices into the main patch.
396 
397     // test each value
398   for (size_t i = 0; i < subpatch.num_elements(); ++i)
399   {
400     subpatch.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
401     for (unsigned j = 0; j < locations.size(); ++j)
402     {
403       MsqMatrix<3,3> W;
404       bool rval = cacher->get_3D_target( subpatch, i, locations[j], W, err );
405       CPPUNIT_ASSERT(rval && !err);
406 
407       Mesh::ElementHandle h = subpatch.get_element_handles_array()[i];
408       Mesh::ElementHandle* old_h = patch_3d.get_element_handles_array();
409       size_t old_idx = std::find( old_h, old_h + patch_3d.num_elements(), h ) - old_h;
410       CPPUNIT_ASSERT(old_idx < patch_3d.num_elements());
411       MsqMatrix<3,3> M = CachedTargetCalculator::make_3d( old_idx, locations[j]);
412       ASSERT_MATRICES_EQUAL( W, M, DBL_EPSILON );
413     }
414   }
415 }
416 
test_2d_target_subpatch()417 void CachingTargetTest::test_2d_target_subpatch()
418 {
419   MsqPrintError err(std::cout);
420   std::vector<Sample> locations;
421 
422     // cache some values on the main patch
423   cached->surf_orient(false);
424   request_all_targets_2d();
425 
426     // clear the count so we know if any additional
427     // evalutions of the base target calculator are
428     // done during subpatch creation.
429   cached->clear();
430 
431     // create a sub-patch
432   CPPUNIT_ASSERT( patch_2d.num_nodes() > 1 );
433   PatchData subpatch;
434   patch_2d.get_subpatch( 1, 1, subpatch, err );
435   CPPUNIT_ASSERT( !err );
436 
437     // make sure we copied the cached values onto the subpatch
438   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), 0u );
439 
440     // Test the values for each cached matrix on the subpatch
441     // NOTE:  This test takes advantange of the fact that the
442     // "handles" in the subpatch are indices into the main patch.
443 
444     // test each value
445   for (size_t i = 0; i < subpatch.num_elements(); ++i)
446   {
447     subpatch.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
448     for (unsigned j = 0; j < locations.size(); ++j)
449     {
450       MsqMatrix<2,2> W;
451       bool rval = cacher->get_2D_target( subpatch, i, locations[j], W, err );
452       CPPUNIT_ASSERT(rval && !err);
453 
454       Mesh::ElementHandle h = subpatch.get_element_handles_array()[i];
455       Mesh::ElementHandle* old_h = patch_2d.get_element_handles_array();
456       size_t old_idx = std::find( old_h, old_h + patch_2d.num_elements(), h ) - old_h;
457       CPPUNIT_ASSERT(old_idx < patch_2d.num_elements());
458       MsqMatrix<2,2> M = CachedTargetCalculator::make_2d( old_idx, locations[j] );
459       ASSERT_MATRICES_EQUAL( W, M, DBL_EPSILON );
460     }
461   }
462 }
463 
test_surface_target_subpatch()464 void CachingTargetTest::test_surface_target_subpatch()
465 {
466   MsqPrintError err(std::cout);
467   std::vector<Sample> locations;
468 
469     // cache some values on the main patch
470   cached->surf_orient(true);
471   request_all_targets_surf();
472 
473     // clear the count so we know if any additional
474     // evalutions of the base target calculator are
475     // done during subpatch creation.
476   cached->clear();
477 
478     // create a sub-patch
479   CPPUNIT_ASSERT( patch_2d.num_nodes() > 1 );
480   PatchData subpatch;
481   patch_2d.get_subpatch( 1, 1, subpatch, err );
482   CPPUNIT_ASSERT( !err );
483 
484     // make sure we copied the cached values onto the subpatch
485   CPPUNIT_ASSERT_EQUAL( cached->calls_2d(), 0u );
486 
487     // Test the values for each cached matrix on the subpatch
488     // NOTE:  This test takes advantange of the fact that the
489     // "handles" in the subpatch are indices into the main patch.
490 
491     // test each value
492   for (size_t i = 0; i < subpatch.num_elements(); ++i)
493   {
494     subpatch.get_samples( i, locations, err ); ASSERT_NO_ERROR(err);
495     for (unsigned j = 0; j < locations.size(); ++j)
496     {
497       MsqMatrix<3,2> W;
498       bool rval = cacher->get_surface_target( subpatch, i, locations[j], W, err );
499       CPPUNIT_ASSERT(rval && !err);
500 
501       Mesh::ElementHandle h = subpatch.get_element_handles_array()[i];
502       Mesh::ElementHandle* old_h = patch_2d.get_element_handles_array();
503       size_t old_idx = std::find( old_h, old_h + patch_2d.num_elements(), h ) - old_h;
504       CPPUNIT_ASSERT(old_idx < patch_2d.num_elements());
505       MsqMatrix<3,2> M = CachedTargetCalculator::make_surf( old_idx, locations[j] );
506       ASSERT_MATRICES_EQUAL( W, M, DBL_EPSILON );
507     }
508   }
509 }
510 
test_cache_cleared()511 void CachingTargetTest::test_cache_cleared()
512 {
513   MsqPrintError err(std::cout);
514 
515     // cache some values on the main patch
516   request_all_targets_3d();
517 
518     // clear the count so we know if any additional
519     // evalutions of the base target calculator are
520     // done.
521   cached->clear();
522 
523     // now re-create the patch, which should result in the
524     // cached data being notified that the mesh has changed
525   create_twelve_hex_patch( patch_3d, err );
526   CPPUNIT_ASSERT(!err);
527 
528     // now get cached values for each element
529   unsigned count = request_all_targets_3d();
530 
531     // and check that they were all re-calculated
532   CPPUNIT_ASSERT_EQUAL( cached->calls_3d(), count );
533 }
534 
535 
536