MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 /* ***************************************************************** 00002 MESQUITE -- The Mesh Quality Improvement Toolkit 00003 00004 Copyright 2004 Sandia Corporation and Argonne National 00005 Laboratory. Under the terms of Contract DE-AC04-94AL85000 00006 with Sandia Corporation, the U.S. Government retains certain 00007 rights in this software. 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Lesser General Public 00011 License as published by the Free Software Foundation; either 00012 version 2.1 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License 00020 (lgpl.txt) along with this library; if not, write to the Free Software 00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 00023 [email protected], [email protected], [email protected], 00024 [email protected], [email protected], [email protected] 00025 00026 ***************************************************************** */ 00027 // -*- Mode : c++; tab-width: 2; c-tab-always-indent: t; indent-tabs-mode: nil; c-basic-offset: 2 00028 // -*- 00029 // 00030 /*! 00031 \file MeshInterface.hpp 00032 \brief 00033 00034 \author Thomas Leurent 00035 \date 2003-04-17 00036 */ 00037 00038 #include "meshfiles.h" 00039 00040 #include "Mesquite.hpp" 00041 #include "MsqError.hpp" 00042 #include "PatchData.hpp" 00043 #include "MeshImpl.hpp" 00044 #include "Vector3D.hpp" 00045 00046 #include "cppunit/extensions/HelperMacros.h" 00047 00048 #include <iostream> 00049 #include <algorithm> 00050 00051 using MBMesquite::arrptr; 00052 using std::cerr; 00053 using std::cout; 00054 using std::endl; 00055 00056 class MeshInterfaceTest : public CppUnit::TestFixture 00057 { 00058 private: 00059 CPPUNIT_TEST_SUITE( MeshInterfaceTest ); 00060 CPPUNIT_TEST( test_get_geometric_dimension ); 00061 CPPUNIT_TEST( test_vertices ); 00062 // CPPUNIT_TEST (test_vertices_are_on_boundary); 00063 /* Not implemented yet 00064 CPPUNIT_TEST (test_vertex_is_fixed); 00065 */ 00066 CPPUNIT_TEST( test_vertex_byte ); 00067 CPPUNIT_TEST( test_vertex_get_attached_elements ); 00068 CPPUNIT_TEST( test_elements ); 00069 CPPUNIT_TEST( test_elements_get_attached_vertices ); 00070 CPPUNIT_TEST( test_elements_get_topology ); 00071 CPPUNIT_TEST( test_element_get_attached_vertex_indices ); 00072 CPPUNIT_TEST_SUITE_END(); 00073 00074 private: 00075 MBMesquite::MeshImpl* mMesh; 00076 std::vector< MBMesquite::Mesh::VertexHandle > mConnectivity; 00077 std::vector< MBMesquite::Mesh::VertexHandle > mVertices; 00078 std::vector< MBMesquite::Mesh::ElementHandle > mElements; 00079 std::vector< size_t > mOffsets; 00080 MBMesquite::MsqError mErr; 00081 00082 public: 00083 MeshInterfaceTest() : mMesh( 0 ) {} 00084 00085 /* Automatically called by CppUnit before each test function. */ 00086 void setUp() 00087 { 00088 // Read a VTK file -- 1 triangle flanked by 1 quad on each side (1 tri + 3 quads) 00089 mMesh = new MBMesquite::MeshImpl; 00090 mMesh->read_vtk( MESH_FILES_DIR "2D/vtk/mixed/untangled/hybrid_3quad_1tri.vtk", mErr ); 00091 CPPUNIT_ASSERT( !mErr ); 00092 00093 // Get mesh data 00094 mMesh->get_all_elements( mElements, mErr ); 00095 CPPUNIT_ASSERT( !mErr ); 00096 mMesh->elements_get_attached_vertices( arrptr( mElements ), mElements.size(), mConnectivity, mOffsets, mErr ); 00097 CPPUNIT_ASSERT( !mErr ); 00098 00099 // Construct list of vertices w/out duplicates from 00100 // connectivity list. 00101 std::vector< MBMesquite::Mesh::VertexHandle >::iterator new_end; 00102 mVertices = mConnectivity; 00103 std::sort( mVertices.begin(), mVertices.end() ); 00104 new_end = std::unique( mVertices.begin(), mVertices.end() ); 00105 mVertices.resize( new_end - mVertices.begin() ); 00106 } 00107 00108 // Automatically called by CppUnit after each test function. 00109 void tearDown() 00110 { 00111 00112 delete mMesh; 00113 if( mErr ) cout << mErr << endl; 00114 mErr.clear(); 00115 } 00116 00117 public: 00118 void test_get_geometric_dimension() 00119 { 00120 int d = mMesh->get_geometric_dimension( mErr ); 00121 CPPUNIT_ASSERT_EQUAL( d, 3 ); 00122 } 00123 00124 void test_vertices() 00125 { 00126 size_t nbVert = mVertices.size(); 00127 CPPUNIT_ASSERT_EQUAL( 9, (int)nbVert ); 00128 00129 MBMesquite::MsqVertex correct_coords[9], coords[9]; 00130 correct_coords[0].set( 1, 0, 0 ); 00131 correct_coords[1].set( 0, 1.732, 0 ); 00132 correct_coords[2].set( -1, 0, 0 ); 00133 correct_coords[3].set( -1, -2, 0 ); 00134 correct_coords[4].set( 1, -2, 0 ); 00135 correct_coords[5].set( 2.732, 1, 0 ); 00136 correct_coords[6].set( 1.732, 2.732, 0 ); 00137 correct_coords[7].set( -1.732, 2.732, 0 ); 00138 correct_coords[8].set( -2.732, 1, 0 ); 00139 00140 mMesh->vertices_get_coordinates( arrptr( mVertices ), coords, nbVert, mErr ); 00141 CPPUNIT_ASSERT( !mErr ); 00142 for( size_t i = 0; i < nbVert; ++i ) 00143 { 00144 for( int j = 0; j < 3; ++j ) 00145 CPPUNIT_ASSERT_DOUBLES_EQUAL( coords[i][j], correct_coords[i][j], .01 ); 00146 } 00147 00148 coords[3].set( 2., 3., 4. ); 00149 mMesh->vertex_set_coordinates( mVertices[3], coords[3], mErr ); 00150 CPPUNIT_ASSERT( !mErr ); 00151 MBMesquite::MsqVertex coords_2; 00152 mMesh->vertices_get_coordinates( &mVertices[3], &coords_2, 1, mErr ); 00153 CPPUNIT_ASSERT( !mErr ); 00154 for( int j = 0; j < 3; ++j ) 00155 CPPUNIT_ASSERT_DOUBLES_EQUAL( coords[3][j], coords_2[j], 1e-6 ); 00156 } 00157 00158 // void test_vertices_are_on_boundary() 00159 // { 00160 // bool on_bnd[9]; 00161 // mMesh->vertices_are_on_boundary(mVertices, on_bnd, nbVert, mErr); 00162 // CPPUNIT_ASSERT(!mErr); 00163 // bool correct_boundary[9] = {false, false, false, true, true, true, true, true, true}; 00164 // for (size_t i=0; i<nbVert; ++i) { 00165 // CPPUNIT_ASSERT(on_bnd[i] == correct_boundary[i]); 00166 // } 00167 // } 00168 00169 void test_vertex_is_fixed() 00170 { 00171 size_t nbVert = mVertices.size(); 00172 bool correct_fixed[9] = { false, false, false, true, true, true, true, true, true }; 00173 std::vector< bool > fixed; 00174 mMesh->vertices_get_fixed_flag( arrptr( mVertices ), fixed, 9, mErr ); 00175 CPPUNIT_ASSERT( !mErr ); 00176 CPPUNIT_ASSERT_EQUAL( (size_t)8, fixed.size() ); 00177 for( size_t i = 0; i < nbVert; ++i ) 00178 { 00179 CPPUNIT_ASSERT_EQUAL( correct_fixed[i], (bool)fixed[i] ); 00180 } 00181 } 00182 00183 void test_vertex_byte() 00184 { 00185 size_t nbVert = mVertices.size(); 00186 size_t i; 00187 unsigned char* bytes = new unsigned char[nbVert]; 00188 mMesh->vertices_get_byte( arrptr( mVertices ), bytes, nbVert, mErr ); 00189 CPPUNIT_ASSERT( !mErr ); 00190 00191 // Asserts all vertex bytes are initialised to 0. 00192 for( i = 0; i < nbVert; ++i ) 00193 CPPUNIT_ASSERT( bytes[i] == 0 ); 00194 00195 // Test various vertex byte read / write routines. 00196 bytes[3] |= 4; 00197 mMesh->vertices_set_byte( arrptr( mVertices ), bytes, nbVert, mErr ); 00198 CPPUNIT_ASSERT( !mErr ); 00199 mMesh->vertex_set_byte( mVertices[5], 8, mErr ); 00200 CPPUNIT_ASSERT( !mErr ); 00201 unsigned char byte; 00202 mMesh->vertex_get_byte( mVertices[3], &byte, mErr ); 00203 CPPUNIT_ASSERT( !mErr ); 00204 CPPUNIT_ASSERT( byte == 4 ); 00205 mMesh->vertices_get_byte( arrptr( mVertices ), bytes, nbVert, mErr ); 00206 CPPUNIT_ASSERT( !mErr ); 00207 for( i = 0; i < nbVert; ++i ) 00208 { 00209 if( i == 3 ) 00210 CPPUNIT_ASSERT( bytes[i] == 4 ); 00211 else if( i == 5 ) 00212 CPPUNIT_ASSERT( bytes[i] == 8 ); 00213 else 00214 CPPUNIT_ASSERT( bytes[i] == 0 ); 00215 } 00216 00217 delete[] bytes; 00218 } 00219 00220 void test_vertex_get_attached_elements() 00221 { 00222 size_t i; 00223 const size_t nbVert = mVertices.size(); 00224 00225 std::vector< MBMesquite::Mesh::ElementHandle > elements; 00226 std::vector< size_t > offsets; 00227 mMesh->vertices_get_attached_elements( arrptr( mVertices ), mVertices.size(), elements, offsets, mErr ); 00228 CPPUNIT_ASSERT( !mErr ); 00229 CPPUNIT_ASSERT_EQUAL( offsets.size(), mVertices.size() + 1 ); 00230 00231 // checks we have 6 vertices contained in 1 element only 00232 // and 3 vertices contained in 3 elements. 00233 int n1 = 0; 00234 int n3 = 0; 00235 for( i = 1; i <= mVertices.size(); ++i ) 00236 { 00237 const size_t nev = offsets[i] - offsets[i - 1]; 00238 if( nev == 1 ) 00239 ++n1; 00240 else if( nev == 3 ) 00241 ++n3; 00242 else // failure. 00243 CPPUNIT_ASSERT( false ); 00244 } 00245 CPPUNIT_ASSERT( n1 == 6 ); 00246 CPPUNIT_ASSERT( n3 == 3 ); 00247 00248 // gets the index of a vertex in a corner 00249 int one_corner_vertex_index = 0; 00250 for( i = 0; i < nbVert; ++i ) 00251 { 00252 const size_t nev = offsets[i + 1] - offsets[i]; 00253 if( 1 == nev ) break; 00254 } 00255 CPPUNIT_ASSERT( i < nbVert ); 00256 one_corner_vertex_index = i; 00257 00258 // retrieve the attached element. 00259 // This is a poor test. We allow an element handle of zero, 00260 // and just testing that the function returned something isn't 00261 // that useful. - J.K. 00262 // MBMesquite::Mesh::ElementHandle elem=0; 00263 // mMesh->vertex_get_attached_elements(mVertices[one_corner_vertex_index], &elem, 1, mErr); 00264 // CPPUNIT_ASSERT(!mErr); 00265 // CPPUNIT_ASSERT(elem!=0); 00266 } 00267 00268 void test_elements() 00269 { 00270 CPPUNIT_ASSERT_EQUAL( 4, (int)mElements.size() ); 00271 } 00272 00273 void test_elements_get_attached_vertices() 00274 { 00275 const size_t nbElem = mElements.size(); 00276 00277 // checks we have 3 elements containing 4 vertices 00278 // and 1 element containing 3 vertices. 00279 int n3 = 0; 00280 int n4 = 0; 00281 size_t i; 00282 for( i = 0; i < nbElem; ++i ) 00283 { 00284 size_t nve = mOffsets[i + 1] - mOffsets[i]; 00285 if( nve == 3 ) 00286 ++n3; 00287 else if( nve == 4 ) 00288 ++n4; 00289 else // failure. 00290 CPPUNIT_ASSERT( false ); 00291 } 00292 CPPUNIT_ASSERT( n3 == 1 ); // 1 triangle 00293 CPPUNIT_ASSERT( n4 == 3 ); // 3 quads 00294 00295 // Make sure CSR data is valid 00296 std::map< MBMesquite::Mesh::VertexHandle, int > vtx_repeated_occurence; 00297 for( i = 0; i < mVertices.size(); ++i ) 00298 vtx_repeated_occurence[mVertices[i]] = 0; 00299 for( i = 0; i < mConnectivity.size(); ++i ) 00300 ++vtx_repeated_occurence[mConnectivity[i]]; 00301 for( i = 0; i < 9; ++i ) 00302 { 00303 CPPUNIT_ASSERT( vtx_repeated_occurence[mVertices[i]] <= 3 ); 00304 } 00305 00306 // Makes sure CSR offsets are valid 00307 CPPUNIT_ASSERT( mOffsets[0] == 0 ); 00308 CPPUNIT_ASSERT( mOffsets[1] >= 3 && mOffsets[1] <= 12 ); 00309 CPPUNIT_ASSERT( mOffsets[2] >= 3 && mOffsets[2] <= 12 ); 00310 CPPUNIT_ASSERT( mOffsets[3] >= 3 && mOffsets[3] <= 12 ); 00311 CPPUNIT_ASSERT( mOffsets[4] == 15 ); 00312 } 00313 00314 void test_elements_get_topology() 00315 { 00316 const size_t nbElem = mElements.size(); 00317 int nb_quads = 0; 00318 int nb_tri = 0; 00319 MBMesquite::EntityTopology* topos = new MBMesquite::EntityTopology[nbElem]; 00320 mMesh->elements_get_topologies( arrptr( mElements ), topos, nbElem, mErr ); 00321 CPPUNIT_ASSERT( !mErr ); 00322 for( size_t i = 0; i < nbElem; ++i ) 00323 { 00324 switch( topos[i] ) 00325 { 00326 case MBMesquite::TRIANGLE: 00327 ++nb_tri; 00328 break; 00329 case MBMesquite::QUADRILATERAL: 00330 ++nb_quads; 00331 break; 00332 default: 00333 CPPUNIT_FAIL( "Topology should be quad or Hex only." ); 00334 } 00335 } 00336 CPPUNIT_ASSERT_EQUAL( 1, nb_tri ); 00337 CPPUNIT_ASSERT_EQUAL( 3, nb_quads ); 00338 delete[] topos; 00339 } 00340 00341 void test_element_get_attached_vertex_indices() 00342 { 00343 // Find the index of the triangle 00344 MBMesquite::EntityTopology topo = Mesquite::MIXED; 00345 int tri_index = -1; 00346 while( topo != MBMesquite::TRIANGLE ) 00347 { 00348 ++tri_index; 00349 CPPUNIT_ASSERT( (unsigned)tri_index < mElements.size() ); 00350 MBMesquite::Mesh::ElementHandle handle = mElements[tri_index]; 00351 mMesh->elements_get_topologies( &handle, &topo, 1, mErr ); 00352 CPPUNIT_ASSERT( !mErr ); 00353 } 00354 00355 // creates list with correct vertices coordinates for the triangle 00356 std::vector< Mesquite::Vector3D > correct_coords; 00357 correct_coords.push_back( Mesquite::Vector3D( 1., 0., 0. ) ); 00358 correct_coords.push_back( Mesquite::Vector3D( 0., 1.732050807, 0. ) ); 00359 correct_coords.push_back( Mesquite::Vector3D( -1., 0., 0. ) ); 00360 00361 // Creates same list from the mesh implementation 00362 std::vector< MBMesquite::MsqVertex > tri_coords( 3 ); 00363 mMesh->vertices_get_coordinates( &mConnectivity[mOffsets[tri_index]], arrptr( tri_coords ), 3, mErr ); 00364 CPPUNIT_ASSERT( !mErr ); 00365 00366 // Makes sure both list contain the same elements (not necessarily in the same order). 00367 std::vector< Mesquite::Vector3D >::iterator correct_iter; 00368 std::vector< MBMesquite::MsqVertex >::iterator tri_iter; 00369 for( tri_iter = tri_coords.begin(); tri_iter != tri_coords.end(); ++tri_iter ) 00370 { 00371 for( correct_iter = correct_coords.begin(); correct_iter != correct_coords.end(); ++correct_iter ) 00372 { 00373 if( Mesquite::Vector3D::distance_between( *tri_iter, *correct_iter ) < 10e-4 ) break; 00374 } 00375 00376 // check if a match was found 00377 CPPUNIT_ASSERT( correct_iter != correct_coords.end() ); 00378 00379 // remove match from list 00380 correct_coords.erase( correct_iter ); 00381 } 00382 CPPUNIT_ASSERT( correct_coords.empty() ); 00383 } 00384 }; 00385 00386 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MeshInterfaceTest, "MeshInterfaceTest" ); 00387 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MeshInterfaceTest, "Unit" );