moab
ReadVtk.cpp
Go to the documentation of this file.
00001 
00022 #include <assert.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 
00026 #include "ReadVtk.hpp"
00027 #include "moab/Range.hpp"
00028 #include "Internals.hpp"
00029 #include "moab/Interface.hpp"
00030 #include "moab/ReadUtilIface.hpp"
00031 #include "moab/FileOptions.hpp"
00032 #include "FileTokenizer.hpp"
00033 #include "VtkUtil.hpp"
00034 
00035 #define MB_VTK_MATERIAL_SETS
00036 #ifdef MB_VTK_MATERIAL_SETS
00037 #  include "MBTagConventions.hpp"
00038 #  include <map>
00039 
00040 namespace moab {
00041 
00042 class Hash
00043 {
00044 public:
00045   unsigned long value;
00046 
00047   Hash()
00048     {
00049     this->value = 5381L;
00050     }
00051   Hash( const unsigned char* bytes, size_t len )
00052     { // djb2, a hash by dan bernstein presented on comp.lang.c for hashing strings.
00053     this->value = 5381L;
00054     for ( ; len ; -- len, ++ bytes )
00055       this->value = this->value * 33 + ( *bytes );
00056     }
00057   Hash( bool duh )
00058     {
00059     this->value = duh; // hashing a single bit with a long is stupid but easy.
00060     }
00061   Hash( const Hash& src )
00062     {
00063     this->value = src.value;
00064     }
00065   Hash& operator = ( const Hash& src )
00066     {
00067     this->value = src.value;
00068     return *this;
00069     }
00070   bool operator < ( const Hash& other ) const
00071     {
00072     return this->value < other.value;
00073     }
00074 };
00075 
00076 // Pass this class opaque data + a handle and it adds the handle to a set
00077 // whose opaque data has the same hash. If no set exists for the hash,
00078 // it creates one. Each set is tagged with the opaque data.
00079 // When entities with different opaque data have the same hash, they
00080 // will be placed into the same set.
00081 // There will be no collisions when the opaque data is shorter than an
00082 // unsigned long, and this is really the only case we need to support.
00083 // The rest is bonus. Hash does quite well with strings, even those
00084 // with identical prefixes.
00085 class Modulator : public std::map<Hash,EntityHandle>
00086 {
00087 public:
00088   Modulator( Interface* iface, std::string tag_name, DataType mb_type, size_t sz, size_t per_elem )
00089     {
00090     this->mesh = iface;
00091     std::vector<unsigned char> default_val;
00092     default_val.resize( sz * per_elem );
00093     this->mesh->tag_get_handle( tag_name.c_str(), per_elem, mb_type, this->tag,
00094                             MB_TAG_SPARSE|MB_TAG_BYTES|MB_TAG_CREAT, 
00095                             &default_val[0] );
00096     }
00097   void add_entity( EntityHandle ent, const unsigned char* bytes, size_t len )
00098     {
00099     Hash h( bytes, len );
00100     EntityHandle mset = this->congruence_class( h, bytes );
00101     this->mesh->add_entities( mset, &ent, 1 );
00102     }
00103   void add_entities( Range& range, const unsigned char* bytes, size_t bytes_per_ent )
00104     {
00105     for( Range::iterator it = range.begin(); it != range.end(); ++ it, bytes += bytes_per_ent )
00106       {
00107       Hash h( bytes, bytes_per_ent );
00108       EntityHandle mset = this->congruence_class( h, bytes );
00109       this->mesh->add_entities( mset, &*it, 1 );
00110       }
00111     }
00112   EntityHandle congruence_class( const Hash& h, const void* tag_data )
00113     {
00114     std::map<Hash,EntityHandle>::iterator it = this->find( h );
00115     if ( it == this->end() )
00116       {
00117       EntityHandle mset;
00118       Range preexist;
00119       this->mesh->get_entities_by_type_and_tag( 0, MBENTITYSET, &this->tag, &tag_data, 1, preexist );
00120       if ( preexist.size() )
00121         {
00122         mset = *preexist.begin();
00123         }
00124       else
00125         {
00126         this->mesh->create_meshset( MESHSET_SET, mset );
00127         this->mesh->tag_set_data( this->tag, &mset, 1, tag_data );
00128         }
00129       (*this)[h] = mset;
00130       return mset;
00131       }
00132     return it->second;
00133     }
00134 
00135   Interface* mesh;
00136   Tag tag;
00137 };
00138 #endif // MB_VTK_MATERIAL_SETS
00139 
00140 ReaderIface* ReadVtk::factory( Interface* iface )
00141   { return new ReadVtk( iface ); }
00142 
00143 ReadVtk::ReadVtk(Interface* impl)
00144     : mdbImpl(impl), mPartitionTagName(MATERIAL_SET_TAG_NAME)
00145 {
00146   mdbImpl->query_interface(readMeshIface);
00147 }
00148 
00149 ReadVtk::~ReadVtk()
00150 {
00151   if (readMeshIface) {
00152     mdbImpl->release_interface(readMeshIface);
00153     readMeshIface = 0;
00154   }
00155 }
00156 
00157 const char* const vtk_type_names[] = { "bit",
00158                                        "char",
00159                                        "unsigned_char",
00160                                        "short",
00161                                        "unsigned_short",
00162                                        "int",
00163                                        "unsigned_int",
00164                                        "long",
00165                                        "unsigned_long",
00166                                        "float",
00167                                        "double",
00168                                        "vtkIdType",
00169                                        0 };
00170 
00171 
00172 ErrorCode ReadVtk::read_tag_values( const char* /* file_name */,
00173                                     const char* /* tag_name */,
00174                                     const FileOptions& /* opts */,
00175                                     std::vector<int>& /* tag_values_out */,
00176                                     const SubsetList* /* subset_list */ )
00177 {
00178   return MB_NOT_IMPLEMENTED;
00179 }
00180 
00181 
00182 ErrorCode ReadVtk::load_file( const char *filename,
00183                               const EntityHandle* ,
00184                               const FileOptions& opts,
00185                               const ReaderIface::SubsetList* subset_list,
00186                               const Tag* file_id_tag) 
00187 {
00188   ErrorCode result;
00189 
00190   int major, minor;
00191   char vendor_string[257];
00192   std::vector<Range> element_list;
00193   Range vertices;
00194   
00195   if (subset_list) {
00196     readMeshIface->report_error( "Reading subset of files not supported for VTK." );
00197     return MB_UNSUPPORTED_OPERATION;
00198   }
00199 
00200   // Does the caller want a field to be used for partitioning the entities?
00201   // If not, we'll assume any scalar integer field named MATERIAL_SET specifies partitions.
00202   std::string partition_tag_name;
00203   result = opts.get_option( "PARTITION", partition_tag_name );
00204   if ( result == MB_SUCCESS )
00205     mPartitionTagName = partition_tag_name;
00206 
00207   FILE* file = fopen( filename, "r" );
00208   if (!file)
00209   {
00210     return MB_FILE_DOES_NOT_EXIST;
00211   }
00212   
00213     // Read file header
00214     
00215   if (!fgets( vendor_string, sizeof(vendor_string), file ))
00216   {
00217     fclose( file );
00218     return MB_FAILURE;
00219   }
00220   
00221   if (!strchr( vendor_string, '\n' ) ||
00222       2 != sscanf( vendor_string, "# vtk DataFile Version %d.%d", &major, &minor ))
00223   {
00224     fclose( file );
00225     return MB_FAILURE;
00226   }
00227   
00228   if (!fgets( vendor_string, sizeof(vendor_string), file )) 
00229   {
00230     fclose( file );
00231     return MB_FAILURE;
00232   }
00233   
00234     // VTK spec says this should not exceed 256 chars.
00235   if (!strchr( vendor_string, '\n' ))
00236   {
00237     readMeshIface->report_error( "Vendor string (line 2) exceeds 256 characters." );
00238     fclose( file );
00239     return MB_FAILURE;
00240   }
00241   
00242   
00243     // Check file type
00244   
00245   FileTokenizer tokens( file, readMeshIface );
00246   const char* const file_type_names[] = { "ASCII", "BINARY", 0 };
00247   int filetype = tokens.match_token( file_type_names );
00248   switch (filetype) {
00249     case 2:  // BINARY
00250       readMeshIface->report_error( "Cannot read BINARY VTK files" );
00251     default: // ERROR 
00252       return MB_FAILURE;
00253     case 1:  // ASCII
00254       break;
00255   }
00256 
00257     // Read the mesh
00258   if (!tokens.match_token( "DATASET" ))
00259     return MB_FAILURE;
00260   result = vtk_read_dataset( tokens, vertices, element_list );
00261   if (MB_SUCCESS != result) 
00262     return result;
00263   
00264   if (file_id_tag) {
00265     result = store_file_ids( *file_id_tag, vertices, element_list );
00266     if (MB_SUCCESS != result)
00267       return result;
00268   }
00269   
00270     // Count the number of elements read
00271   long elem_count = 0;
00272   for (std::vector<Range>::iterator it = element_list.begin(); it != element_list.end(); ++it )
00273     elem_count += it->size();
00274   
00275     // Read attribute data until end of file.
00276   const char* const block_type_names[] = { "POINT_DATA", "CELL_DATA", 0 };
00277   std::vector<Range> vertex_list(1);
00278   vertex_list[0] = vertices;
00279   int blocktype = 0;
00280   while (!tokens.eof())
00281   {
00282       // get POINT_DATA or CELL_DATA
00283     int new_block_type = tokens.match_token( block_type_names, false );
00284     if (tokens.eof())
00285       break;
00286 
00287     if (!new_block_type)
00288     {
00289         // If next token was neither POINT_DATA nor CELL_DATA,
00290         // then there's another attribute under the current one.
00291       if (blocktype)
00292         tokens.unget_token();
00293       else
00294         break;
00295     }
00296     else
00297     {
00298       blocktype = new_block_type;
00299       long count;
00300       if (!tokens.get_long_ints( 1, &count ))
00301         return MB_FAILURE;
00302       
00303       if (blocktype == 1 && (unsigned long)count != vertices.size())
00304       {
00305         readMeshIface->report_error(
00306               "Count inconsistent with number of vertices at line %d.", 
00307               tokens.line_number());
00308         return MB_FAILURE;
00309       }
00310       else if (blocktype == 2 && count != elem_count)
00311       {
00312         readMeshIface->report_error(
00313               "Count inconsistent with number of elements at line %d.", 
00314               tokens.line_number());
00315         return MB_FAILURE;
00316       }
00317     }
00318       
00319    
00320     if (blocktype == 1)
00321       result = vtk_read_attrib_data( tokens, vertex_list );
00322     else
00323       result = vtk_read_attrib_data( tokens, element_list );
00324     
00325     if (MB_SUCCESS != result)
00326       return result;
00327   }
00328   
00329   return MB_SUCCESS;
00330 }
00331 
00332 ErrorCode ReadVtk::allocate_vertices( long num_verts,
00333                                         EntityHandle& start_handle_out,
00334                                         double*& x_coord_array_out,
00335                                         double*& y_coord_array_out,
00336                                         double*& z_coord_array_out )
00337 {
00338   ErrorCode result;
00339   
00340     // Create vertices
00341   std::vector<double*> arrays;
00342   start_handle_out = 0;
00343   result = readMeshIface->get_node_coords( 3, num_verts, MB_START_ID,
00344                                            start_handle_out, arrays );
00345   if (MB_SUCCESS != result)
00346     return result;
00347     
00348   x_coord_array_out = arrays[0];
00349   y_coord_array_out = arrays[1];
00350   z_coord_array_out = arrays[2];
00351   
00352   return MB_SUCCESS;
00353 }
00354 
00355 ErrorCode ReadVtk::read_vertices( FileTokenizer& tokens,
00356                                     long num_verts, 
00357                                     EntityHandle& start_handle_out )
00358 {
00359   ErrorCode result;
00360   double *x, *y, *z;
00361   
00362   result = allocate_vertices( num_verts, start_handle_out, x, y, z );
00363   if (MB_SUCCESS != result)
00364     return result;
00365 
00366     // Read vertex coordinates
00367   for (long vtx = 0; vtx < num_verts; ++vtx)
00368   {
00369     if (!tokens.get_doubles( 1, x++ ) ||
00370         !tokens.get_doubles( 1, y++ ) ||
00371         !tokens.get_doubles( 1, z++ ))
00372       return MB_FAILURE;
00373   }
00374   
00375   return MB_SUCCESS;
00376 }
00377 
00378 ErrorCode ReadVtk::allocate_elements( long num_elements,
00379                                         int vert_per_element,
00380                                         EntityType type,
00381                                         EntityHandle& start_handle_out,
00382                                         EntityHandle*& conn_array_out,
00383                                         std::vector<Range>& append_to_this )
00384 {
00385   ErrorCode result;
00386   
00387   start_handle_out = 0;
00388   result = readMeshIface->get_element_connect( num_elements,
00389                                              vert_per_element,
00390                                              type,
00391                                              MB_START_ID,
00392                                              start_handle_out,
00393                                              conn_array_out );
00394   if (MB_SUCCESS != result)
00395     return result;
00396   
00397   Range range(start_handle_out, start_handle_out+num_elements-1);
00398   append_to_this.push_back( range );
00399   return MB_SUCCESS;
00400 }
00401 
00402 ErrorCode ReadVtk::vtk_read_dataset( FileTokenizer& tokens,
00403                                        Range& vertex_list,
00404                                        std::vector<Range>& element_list )
00405 {
00406   const char* const data_type_names[] = { "STRUCTURED_POINTS",
00407                                           "STRUCTURED_GRID",
00408                                           "UNSTRUCTURED_GRID",
00409                                           "POLYDATA",
00410                                           "RECTILINEAR_GRID",
00411                                           "FIELD",
00412                                           0 };
00413   int datatype = tokens.match_token( data_type_names );
00414   switch( datatype )
00415   {
00416     case 1:  return vtk_read_structured_points( tokens, vertex_list, element_list );
00417     case 2:  return vtk_read_structured_grid  ( tokens, vertex_list, element_list );
00418     case 3:  return vtk_read_unstructured_grid( tokens, vertex_list, element_list );
00419     case 4:  return vtk_read_polydata         ( tokens, vertex_list, element_list );
00420     case 5:  return vtk_read_rectilinear_grid ( tokens, vertex_list, element_list );
00421     case 6:  return vtk_read_field            ( tokens );
00422     default: return MB_FAILURE;
00423   }
00424   
00425 }
00426 
00427 
00428 ErrorCode ReadVtk::vtk_read_structured_points( FileTokenizer& tokens, 
00429                                                  Range& vertex_list,
00430                                                  std::vector<Range>& elem_list )
00431 {
00432   long i, j, k;
00433   long dims[3];
00434   double origin[3], space[3];
00435   ErrorCode result;
00436  
00437   if (!tokens.match_token( "DIMENSIONS" ) || 
00438       !tokens.get_long_ints( 3, dims ) ||
00439       !tokens.get_newline( ))
00440     return MB_FAILURE; 
00441   
00442   if (dims[0] < 1 || dims[1] < 1 || dims[2] < 1)
00443   {
00444     readMeshIface->report_error( "Invalid dimension at line %d", 
00445                                  tokens.line_number());
00446     return MB_FAILURE;
00447   }
00448   
00449   if (!tokens.match_token( "ORIGIN" )  ||
00450       !tokens.get_doubles( 3, origin ) ||
00451       !tokens.get_newline( ))
00452     return MB_FAILURE;           
00453   
00454   const char* const spacing_names[] = { "SPACING", "ASPECT_RATIO", 0 };
00455   if (!tokens.match_token( spacing_names ) ||
00456       !tokens.get_doubles( 3, space )      ||
00457       !tokens.get_newline())
00458     return MB_FAILURE;
00459   
00460     // Create vertices
00461   double *x, *y, *z;
00462   EntityHandle start_handle = 0;
00463   long num_verts = dims[0]*dims[1]*dims[2];
00464   result = allocate_vertices( num_verts, start_handle, x, y, z );
00465   if (MB_SUCCESS != result)
00466     return result;
00467   vertex_list.insert( start_handle, start_handle + num_verts - 1 );
00468   
00469   for (k = 0; k < dims[2]; ++k)
00470     for (j = 0; j < dims[1]; ++j)
00471       for (i = 0; i < dims[0]; ++i)
00472       {
00473         *x = origin[0] + i*space[0]; ++x;
00474         *y = origin[1] + j*space[1]; ++y;
00475         *z = origin[2] + k*space[2]; ++z;
00476       }
00477 
00478   return vtk_create_structured_elems( dims, start_handle, elem_list );
00479 }
00480 
00481 ErrorCode ReadVtk::vtk_read_structured_grid( FileTokenizer& tokens, 
00482                                                Range& vertex_list,
00483                                                std::vector<Range>& elem_list )
00484 {
00485   long num_verts, dims[3];
00486   ErrorCode result;
00487  
00488   if (!tokens.match_token( "DIMENSIONS" ) ||
00489       !tokens.get_long_ints( 3, dims )    ||
00490       !tokens.get_newline( ) )
00491     return MB_FAILURE;            
00492   
00493   if (dims[0] < 1 || dims[1] < 1 || dims[2] < 1)
00494   {
00495     readMeshIface->report_error( "Invalid dimension at line %d", 
00496                                  tokens.line_number());
00497     return MB_FAILURE;
00498   }
00499   
00500   if (!tokens.match_token( "POINTS" )        ||
00501       !tokens.get_long_ints( 1, &num_verts ) ||
00502       !tokens.match_token( vtk_type_names )  ||
00503       !tokens.get_newline())
00504     return MB_FAILURE;                
00505   
00506   if (num_verts != (dims[0] * dims[1] * dims[2]))
00507   {
00508     readMeshIface->report_error(                     
00509       "Point count not consistent with dimensions at line %d", 
00510       tokens.line_number() );
00511     return MB_FAILURE;
00512   }
00513   
00514     // Create and read vertices
00515   EntityHandle start_handle = 0;
00516   result = read_vertices( tokens, num_verts, start_handle );
00517   if (MB_SUCCESS != result)
00518     return result;
00519   vertex_list.insert( start_handle, start_handle + num_verts - 1 );
00520  
00521   return vtk_create_structured_elems( dims, start_handle, elem_list );
00522 }
00523 
00524 ErrorCode ReadVtk::vtk_read_rectilinear_grid( FileTokenizer& tokens, 
00525                                                 Range& vertex_list,
00526                                                 std::vector<Range>& elem_list )
00527 {
00528   int i, j, k;
00529   long dims[3];
00530   const char* labels[] = { "X_COORDINATES", "Y_COORDINATES", "Z_COORDINATES" };
00531   std::vector<double> coords[3];
00532   ErrorCode result;
00533   
00534   if (!tokens.match_token( "DIMENSIONS" )||
00535       !tokens.get_long_ints( 3, dims )   ||
00536       !tokens.get_newline( ))
00537     return MB_FAILURE;
00538   
00539   if (dims[0] < 1 || dims[1] < 1 || dims[2] < 1)
00540   {
00541     readMeshIface->report_error( "Invalid dimension at line %d", 
00542                                  tokens.line_number());
00543     return MB_FAILURE;
00544   }
00545 
00546   for (i = 0; i < 3; i++)
00547   {
00548     long count;
00549     if (!tokens.match_token( labels[i] )      ||
00550         !tokens.get_long_ints( 1, &count )    ||
00551         !tokens.match_token( vtk_type_names ))
00552       return MB_FAILURE;
00553     
00554     if (count != dims[i])
00555     {
00556       readMeshIface->report_error(                     
00557         "Coordinate count inconsistent with dimensions at line %d", 
00558         tokens.line_number() );
00559       return MB_FAILURE;
00560     }
00561     
00562     coords[i].resize(count);
00563     if (!tokens.get_doubles( count, &coords[i][0] ))
00564       return MB_FAILURE;
00565   }
00566   
00567     // Create vertices
00568   double *x, *y, *z;
00569   EntityHandle start_handle = 0;
00570   long num_verts = dims[0]*dims[1]*dims[2];
00571   result = allocate_vertices( num_verts, start_handle, x, y, z );
00572   if (MB_SUCCESS != result)
00573     return result;
00574   vertex_list.insert( start_handle, start_handle + num_verts - 1 );
00575   
00576     // Calculate vertex coordinates
00577   for (k = 0; k < dims[2]; ++k)
00578     for (j = 0; j < dims[1]; ++j)
00579       for (i = 0; i < dims[0]; ++i)
00580       {
00581         *x = coords[0][i]; ++x;
00582         *y = coords[1][j]; ++y;
00583         *z = coords[2][k]; ++z;
00584       }
00585   
00586   
00587   return vtk_create_structured_elems( dims, start_handle, elem_list );
00588 }
00589 
00590 ErrorCode ReadVtk::vtk_read_polydata( FileTokenizer& tokens, 
00591                                         Range& vertex_list,
00592                                         std::vector<Range>& elem_list )
00593 {
00594   ErrorCode result;
00595   long num_verts;
00596   std::vector<int> connectivity;
00597   const char* const poly_data_names[] = { "VERTICES",
00598                                           "LINES",
00599                                           "POLYGONS",
00600                                           "TRIANGLE_STRIPS", 
00601                                           0 };
00602   
00603   if (!tokens.match_token( "POINTS" )        ||
00604       !tokens.get_long_ints( 1, &num_verts ) ||
00605       !tokens.match_token( vtk_type_names )  ||
00606       !tokens.get_newline( ))
00607     return MB_FAILURE;
00608   
00609   if (num_verts < 1)
00610   {
00611     readMeshIface->report_error( "Invalid point count at line %d", 
00612                                  tokens.line_number());
00613     return MB_FAILURE;
00614   }
00615   
00616     // Create vertices and read coordinates
00617   EntityHandle start_handle = 0;
00618   result = read_vertices( tokens, num_verts, start_handle );
00619   if (MB_SUCCESS != result)
00620     return result;
00621   vertex_list.insert( start_handle, start_handle + num_verts - 1 );
00622 
00623   int poly_type = tokens.match_token( poly_data_names );
00624   switch (poly_type)
00625   {
00626     case 0:
00627       result = MB_FAILURE;
00628       break;
00629     case 1:
00630       readMeshIface->report_error( 
00631                        "Vertex element type at line %d",
00632                        tokens.line_number() );
00633       result = MB_FAILURE;
00634       break;
00635     case 2:
00636       readMeshIface->report_error( 
00637                "Unsupported type: polylines at line %d",
00638                tokens.line_number() );
00639       result = MB_FAILURE;
00640       break;
00641     case 3:
00642       result = vtk_read_polygons( tokens, start_handle, elem_list );
00643       break;
00644     case 4:
00645       readMeshIface->report_error( 
00646                "Unsupported type: triangle strips at line %d",
00647                tokens.line_number() );
00648       result = MB_FAILURE;
00649       break;
00650   }
00651   
00652   return result;
00653 }
00654 
00655 ErrorCode ReadVtk::vtk_read_polygons( FileTokenizer& tokens,
00656                                         EntityHandle first_vtx, 
00657                                         std::vector<Range>& elem_list )
00658 {
00659   ErrorCode result;
00660   long size[2];
00661   
00662   if (!tokens.get_long_ints( 2, size ) ||
00663       !tokens.get_newline( ))
00664     return MB_FAILURE;
00665 
00666   const Range empty;
00667   std::vector<EntityHandle> conn_hdl;
00668   std::vector<long> conn_idx;
00669   EntityHandle first = 0, prev = 0, handle;
00670   for (int i = 0; i < size[0]; ++i) {
00671     long count;
00672     if (!tokens.get_long_ints( 1, &count ))
00673       return MB_FAILURE;
00674     conn_idx.resize(count);
00675     conn_hdl.resize(count);
00676     if (!tokens.get_long_ints( count, &conn_idx[0]))
00677       return MB_FAILURE;
00678     
00679     for (long j = 0; j < count; ++j)
00680       conn_hdl[j] = first_vtx + conn_idx[j];
00681     
00682     result = mdbImpl->create_element( MBPOLYGON, &conn_hdl[0], count, handle );
00683     if (MB_SUCCESS != result)
00684       return result;
00685     
00686     if (prev +1 != handle) {
00687       if (first) { // true except for first iteration (first == 0)
00688         if (first < elem_list.back().front()) // only need new range if order would get mixed up
00689           elem_list.push_back( empty );
00690         elem_list.back().insert( first, prev );
00691       }
00692       first = handle;
00693     }
00694     prev = handle;
00695   }
00696   if (first) { // true unless no elements (size[0] == 0)
00697     if (first < elem_list.back().front()) // only need new range if order would get mixed up
00698       elem_list.push_back( empty );
00699     elem_list.back().insert( first, prev );
00700   }
00701   
00702   return MB_SUCCESS;
00703 }
00704 
00705 
00706 
00707 ErrorCode ReadVtk::vtk_read_unstructured_grid( FileTokenizer& tokens,
00708                                                  Range& vertex_list,
00709                                                  std::vector<Range>& elem_list  )
00710 {
00711   ErrorCode result;
00712   long i, num_verts, num_elems[2];
00713   EntityHandle tmp_conn_list[27];
00714 
00715     // Poorly formatted VTK legacy format document seems to
00716     // lead many to think that a FIELD block can occur within
00717     // an UNSTRUCTURED_GRID dataset rather than as its own data 
00718     // set.  So allow for field data between other blocks of
00719     // data.  
00720     
00721   const char* pts_str[] = { "FIELD", "POINTS", 0 };
00722   while (1 == (i = tokens.match_token(pts_str))) {
00723     result = vtk_read_field(tokens);
00724     if (MB_SUCCESS != result)
00725       return result;
00726   }    
00727   if (i != 2)
00728     return MB_FAILURE;
00729 
00730   if (!tokens.get_long_ints( 1, &num_verts ) ||
00731       !tokens.match_token( vtk_type_names)   ||
00732       !tokens.get_newline( ))
00733     return MB_FAILURE;
00734   
00735   if (num_verts < 1)
00736   {
00737     readMeshIface->report_error( "Invalid point count at line %d", tokens.line_number());
00738     return MB_FAILURE;
00739   }
00740   
00741     // Create vertices and read coordinates
00742   EntityHandle first_vertex = 0;
00743   result = read_vertices( tokens, num_verts, first_vertex );
00744   if (MB_SUCCESS != result)
00745     return result;
00746   vertex_list.insert( first_vertex, first_vertex + num_verts - 1 );
00747     
00748   const char* cell_str[] = { "FIELD", "CELLS", 0 };
00749   while (1 == (i = tokens.match_token(cell_str))) {
00750     result = vtk_read_field(tokens);
00751     if (MB_SUCCESS != result)
00752       return result;
00753   }    
00754   if (i != 2)
00755     return MB_FAILURE;
00756   
00757   if (!tokens.get_long_ints( 2, num_elems ) ||
00758       !tokens.get_newline( ))
00759     return MB_FAILURE;
00760   
00761     // Read element connectivity for all elements
00762   std::vector<long> connectivity( num_elems[1] );
00763   if (!tokens.get_long_ints( num_elems[1], &connectivity[0] ))
00764     return MB_FAILURE;
00765   
00766   if (!tokens.match_token( "CELL_TYPES" )      ||
00767       !tokens.get_long_ints( 1, &num_elems[1]) ||
00768       !tokens.get_newline( ))
00769     return MB_FAILURE;
00770 
00771     // Read element types
00772   std::vector<long> types( num_elems[0] );
00773   if (!tokens.get_long_ints( num_elems[0], &types[0] ))
00774     return MB_FAILURE;
00775   
00776     // Create elements in blocks of the same type
00777     // It is important to preserve the order in 
00778     // which the elements were read for later reading
00779     // attribute data.
00780   long id = 0;
00781   std::vector<long>::iterator conn_iter = connectivity.begin();
00782   while (id < num_elems[0])
00783   {
00784     unsigned vtk_type = types[id];
00785     if (vtk_type >= VtkUtil::numVtkElemType)
00786       return MB_FAILURE;
00787       
00788     EntityType type = VtkUtil::vtkElemTypes[vtk_type].mb_type;
00789     if (type == MBMAXTYPE) {
00790       readMeshIface->report_error( "Unsupported VTK element type: %s (%d)\n",
00791                                    VtkUtil::vtkElemTypes[vtk_type].name, vtk_type );
00792       return MB_FAILURE;
00793     }
00794     
00795     int num_vtx = *conn_iter;
00796     if (type != MBPOLYGON && num_vtx != (int)VtkUtil::vtkElemTypes[vtk_type].num_nodes) {
00797       readMeshIface->report_error(
00798         "Cell %ld is of type '%s' but has %u vertices.\n",
00799         id, VtkUtil::vtkElemTypes[vtk_type].name, num_vtx );
00800       return MB_FAILURE;
00801     }
00802     
00803       // Find any subsequent elements of the same type
00804     std::vector<long>::iterator conn_iter2 = conn_iter + num_vtx + 1;
00805     long end_id = id + 1; 
00806     while ( end_id < num_elems[0] && 
00807             (unsigned)types[end_id] == vtk_type &&
00808             *conn_iter2 == num_vtx) {
00809       ++end_id;
00810       conn_iter2 += num_vtx + 1;
00811     }
00812     
00813       // Allocate element block
00814     long num_elem = end_id - id;
00815     EntityHandle start_handle = 0;
00816     EntityHandle* conn_array;
00817     
00818     result = allocate_elements( num_elem, num_vtx, type, start_handle,
00819                                 conn_array, elem_list );
00820     if (MB_SUCCESS != result)
00821       return result;
00822 
00823     EntityHandle *conn_sav = conn_array;
00824     
00825       // Store element connectivity
00826     for ( ; id < end_id; ++id)
00827     {
00828       if (conn_iter == connectivity.end()) 
00829       {
00830         readMeshIface->report_error( 
00831            "Connectivity data truncated at cell %ld\n", id );
00832         return MB_FAILURE;
00833       }
00834 
00835         // make sure connectivity length is correct.
00836       if (*conn_iter != num_vtx)
00837       {
00838         readMeshIface->report_error(
00839           "Cell %ld is of type '%s' but has %u vertices.\n",
00840           id, VtkUtil::vtkElemTypes[vtk_type].name, num_vtx );
00841         return MB_FAILURE;
00842       }
00843       ++conn_iter;
00844 
00845       for (i = 0; i < num_vtx; ++i, ++conn_iter)
00846       {
00847         if (conn_iter == connectivity.end()) 
00848         {
00849           readMeshIface->report_error( 
00850              "Connectivity data truncated at cell %ld\n", id );
00851           return MB_FAILURE;
00852         }
00853 
00854         conn_array[i] = *conn_iter + first_vertex;
00855       }
00856 
00857       const unsigned* order = VtkUtil::vtkElemTypes[vtk_type].node_order;
00858       if ( order )
00859       {
00860         assert( num_vtx * sizeof(EntityHandle) <= sizeof(tmp_conn_list) );
00861         memcpy( tmp_conn_list, conn_array, num_vtx * sizeof(EntityHandle) );
00862         for (int j = 0; j < num_vtx; ++j)
00863           conn_array[order[j]] = tmp_conn_list[j];
00864       }       
00865 
00866       conn_array += num_vtx;
00867     }
00868     
00869       // notify MOAB of the new elements
00870     result = readMeshIface->update_adjacencies(start_handle, num_elem,
00871                                                num_vtx, conn_sav);
00872     if (MB_SUCCESS != result) return result;
00873   }      
00874 
00875   return MB_SUCCESS;
00876 }
00877 
00878 ErrorCode ReadVtk::vtk_create_structured_elems( const long* dims, 
00879                                             EntityHandle first_vtx,
00880                                             std::vector<Range>& elem_list )
00881 {
00882   ErrorCode result;
00883   //int non_zero[3] = {0,0,0};  // True if dim > 0 for x, y, z respectively
00884   long elem_dim = 0;          // Element dimension (2->quad, 3->hex)
00885   long num_elems = 1;         // Total number of elements
00886   long vert_per_elem;         // Element connectivity length
00887   long edims[3] = { 1, 1, 1 };// Number of elements in each grid direction
00888   
00889     // Populate above data
00890   for (int d = 0; d < 3; d++) 
00891     if (dims[d] > 1)
00892     {
00893       //non_zero[elem_dim] = d;
00894       ++elem_dim;
00895       edims[d] = dims[d] - 1;
00896       num_elems *= edims[d];
00897     }
00898   vert_per_elem = 1 << elem_dim;
00899   
00900     // Get element type from element dimension
00901   EntityType type;
00902   switch( elem_dim )
00903   {
00904     case 1: type = MBEDGE; break;
00905     case 2: type = MBQUAD; break;
00906     case 3: type = MBHEX;  break;
00907     default:
00908       readMeshIface->report_error( "Invalid dimension for structured elements: %ld\n",
00909                                    elem_dim );
00910       return MB_FAILURE;
00911   }
00912 
00913     // Allocate storage for elements
00914   EntityHandle start_handle = 0;
00915   EntityHandle* conn_array;
00916   result = allocate_elements( num_elems, vert_per_elem, type, start_handle,
00917                               conn_array, elem_list );
00918   if (MB_SUCCESS != result)
00919     return MB_FAILURE;
00920 
00921   EntityHandle *conn_sav = conn_array;
00922   
00923     // Offsets of element vertices in grid relative to corner closest to origin 
00924   long k = dims[0]*dims[1];
00925   const long corners[8] = { 0, 1, 1+dims[0], dims[0], k, k+1, k+1+dims[0], k+dims[0] };
00926                              
00927     // Populate element list
00928   for (long z = 0; z < edims[2]; ++z)
00929     for (long y = 0; y < edims[1]; ++y)
00930       for (long x = 0; x < edims[0]; ++x)
00931       {
00932         const long index = x + y*dims[0] + z*(dims[0]*dims[1]);
00933         for (long j = 0; j < vert_per_elem; ++j, ++conn_array)
00934           *conn_array = index + corners[j] + first_vtx;
00935       }
00936   
00937     // notify MOAB of the new elements
00938   result = readMeshIface->update_adjacencies(start_handle, num_elems,
00939                                              vert_per_elem, conn_sav);
00940   if (MB_SUCCESS != result) return result;
00941 
00942   return MB_SUCCESS;
00943 }
00944 
00945 ErrorCode ReadVtk::vtk_read_field( FileTokenizer& tokens )
00946 {
00947     // This is not supported yet.
00948     // Parse the data but throw it away because
00949     // Mesquite has no internal representation for it.
00950   
00951     // Could save this in tags, but the only useful thing that
00952     // could be done with the data is to write it back out
00953     // with the modified mesh.  As there's no way to save the
00954     // type of a tag in Mesquite, it cannot be written back
00955     // out correctly either.
00956     // FIXME: Don't know what to do with this data.
00957     // For now, read it and throw it out.
00958 
00959   long num_arrays;
00960   if (!tokens.get_string() || // name
00961       !tokens.get_long_ints( 1, &num_arrays ))
00962     return MB_FAILURE;
00963   
00964   for (long i = 0; i < num_arrays; ++i)
00965   {
00966     /*const char* name =*/ tokens.get_string( );
00967     
00968     long dims[2];
00969     if (!tokens.get_long_ints( 2, dims ) ||
00970         !tokens.match_token( vtk_type_names ))
00971       return MB_FAILURE;
00972     
00973     long num_vals = dims[0] * dims[1];
00974     
00975     for (long j = 0; j < num_vals; j++)
00976     {
00977       double junk;
00978       if (!tokens.get_doubles( 1, &junk ))
00979         return MB_FAILURE;
00980     }
00981   }
00982   
00983   return MB_SUCCESS;
00984 }
00985 
00986 ErrorCode ReadVtk::vtk_read_attrib_data( FileTokenizer& tokens, 
00987                                            std::vector<Range>& entities )
00988 {
00989   const char* const type_names[] = { "SCALARS",
00990                                      "COLOR_SCALARS",
00991                                      "VECTORS",
00992                                      "NORMALS",
00993                                      "TEXTURE_COORDINATES",
00994                                      "TENSORS",
00995                                      "FIELD",
00996                                      0 };
00997 
00998   int type = tokens.match_token( type_names );
00999   const char* tmp_name = tokens.get_string( );
01000   if (!type || !tmp_name)
01001     return MB_FAILURE;
01002   
01003   std::string name_alloc( tmp_name );
01004   const char* name = name_alloc.c_str();
01005   switch( type )
01006   {
01007     case 1: return vtk_read_scalar_attrib ( tokens, entities, name ); 
01008     case 2: return vtk_read_color_attrib  ( tokens, entities, name ); 
01009     case 3: return vtk_read_vector_attrib ( tokens, entities, name );
01010     case 4: return vtk_read_vector_attrib ( tokens, entities, name ); 
01011     case 5: return vtk_read_texture_attrib( tokens, entities, name ); 
01012     case 6: return vtk_read_tensor_attrib ( tokens, entities, name ); 
01013     case 7: return vtk_read_field_attrib  ( tokens, entities, name );
01014   }
01015 
01016   return MB_FAILURE;
01017 }
01018 
01019 ErrorCode ReadVtk::vtk_read_tag_data( FileTokenizer& tokens, 
01020                                         int type, 
01021                                         size_t per_elem, 
01022                                         std::vector<Range>& entities,
01023                                         const char* name )
01024 {
01025   ErrorCode result;
01026   DataType mb_type;
01027   size_t size;
01028   if (type == 1)
01029   {
01030     mb_type = MB_TYPE_BIT;
01031     size = sizeof(bool);
01032   }
01033   else if (type >= 2 && type <= 9)
01034   {
01035     mb_type = MB_TYPE_INTEGER;
01036     size = sizeof(int);
01037   }
01038   else if (type == 10 || type == 11)
01039   {
01040     mb_type = MB_TYPE_DOUBLE;
01041     size = sizeof(double);
01042   }
01043   else if ( type == 12 )
01044   {
01045     mb_type = MB_TYPE_INTEGER;
01046     size = 4; // could be 4 or 8, but we don't know. Hope it's 4 because MOAB doesn't support 64-bit ints.
01047   }
01048   else
01049   {
01050     return MB_FAILURE;
01051   }
01052 
01053 #ifdef MB_VTK_MATERIAL_SETS
01054   Modulator materialMap( this->mdbImpl, this->mPartitionTagName, mb_type, size, per_elem );
01055   bool isMaterial =
01056     size * per_elem <= 4 &&                            // must have int-sized values (ParallelComm requires it)
01057     ! this->mPartitionTagName.empty() &&               // must have a non-empty field name...
01058     ! strcmp( name, this->mPartitionTagName.c_str() ); // ... that matches our spec.
01059 #endif // MB_VTK_MATERIAL_SETS
01060   
01061     // get/create tag
01062   Tag handle;
01063   result = mdbImpl->tag_get_handle( name, per_elem, mb_type, handle, MB_TAG_DENSE|MB_TAG_CREAT );
01064   if (MB_SUCCESS != result) {
01065     readMeshIface->report_error( 
01066       "Tag name conflict for attribute \"%s\" at line %d\n",
01067       name, tokens.line_number() );
01068     return result;
01069   }
01070  
01071     // Count number of entities
01072   long count = 0;
01073   std::vector<Range>::iterator iter;
01074   for (iter = entities.begin(); iter != entities.end(); ++iter)
01075     count += iter->size();
01076 
01077   if (type == 1)
01078   {
01079     for (iter = entities.begin(); iter != entities.end(); ++iter)
01080     {
01081       bool *data = new bool[iter->size() * per_elem];
01082       if (!tokens.get_booleans( per_elem*iter->size(), data ))
01083       {
01084         delete [] data;
01085         return MB_FAILURE;
01086       }
01087       
01088       bool* data_iter = data;
01089       Range::iterator ent_iter = iter->begin();
01090       for ( ; ent_iter != iter->end(); ++ent_iter)
01091       {
01092         unsigned char bits = 0;
01093         for (unsigned j = 0; j < per_elem; ++j, ++data_iter)
01094           bits |= (unsigned char)(*data_iter << j);
01095 #ifdef MB_VTK_MATERIAL_SETS
01096         if ( isMaterial )
01097           materialMap.add_entity( *ent_iter, &bits, 1 );
01098 #endif // MB_VTK_MATERIAL_SETS
01099         result = mdbImpl->tag_set_data( handle, &*ent_iter, 1, &bits );
01100         if (MB_SUCCESS != result)
01101         {
01102           delete [] data;
01103           return result;
01104         }
01105       } 
01106       delete [] data;
01107     }
01108   }
01109   else if ((type >= 2 && type <= 9) || type == 12)
01110   {
01111     std::vector<int> data;
01112     for (iter = entities.begin(); iter != entities.end(); ++iter)
01113     {
01114       data.resize( iter->size() * per_elem );
01115       if (!tokens.get_integers( iter->size() * per_elem, &data[0] ))
01116         return MB_FAILURE;
01117 #ifdef MB_VTK_MATERIAL_SETS
01118       if ( isMaterial )
01119         materialMap.add_entities( *iter, (unsigned char*) &data[0], per_elem * size );
01120 #endif // MB_VTK_MATERIAL_SETS
01121       result = mdbImpl->tag_set_data( handle, *iter, &data[0] );
01122       if (MB_SUCCESS != result)
01123         return result;
01124     }
01125   }
01126   else if (type == 10 || type == 11)
01127   {
01128     std::vector<double> data;
01129     for (iter = entities.begin(); iter != entities.end(); ++iter)
01130     {
01131       data.resize( iter->size() * per_elem );
01132       if (!tokens.get_doubles( iter->size() * per_elem, &data[0] ))
01133         return MB_FAILURE;
01134 #ifdef MB_VTK_MATERIAL_SETS
01135       if ( isMaterial )
01136         materialMap.add_entities( *iter, (unsigned char*) &data[0], per_elem * size );
01137 #endif // MB_VTK_MATERIAL_SETS
01138       result = mdbImpl->tag_set_data( handle, *iter, &data[0] );
01139       if (MB_SUCCESS != result)
01140         return result;
01141     }
01142   }
01143   else
01144   {
01145     return MB_FAILURE;
01146   }
01147   
01148   return MB_SUCCESS;
01149 }
01150   
01151 
01152 ErrorCode ReadVtk::vtk_read_scalar_attrib( FileTokenizer& tokens, 
01153                                              std::vector<Range>& entities,
01154                                              const char* name)
01155 {
01156   int type = tokens.match_token( vtk_type_names );
01157   if (!type)
01158     return MB_FAILURE;
01159     
01160   long size;
01161   const char* tok = tokens.get_string( );
01162   if (!tok)
01163     return MB_FAILURE;
01164     
01165   const char* end = 0;
01166   size = strtol( tok, (char**)&end, 0 );
01167   if (*end)
01168   {
01169     size = 1;
01170     tokens.unget_token();
01171   }
01172   
01173     // VTK spec says cannot be greater than 4--do we care?
01174   if (size < 1) //|| size > 4)
01175   {
01176     readMeshIface->report_error(
01177                     "Scalar count out of range [1,4]" 
01178                     " at line %d", tokens.line_number());
01179     return MB_FAILURE;
01180   }
01181   
01182   if (!tokens.match_token("LOOKUP_TABLE") ||
01183       !tokens.match_token("default"))
01184     return MB_FAILURE;
01185   
01186   return vtk_read_tag_data( tokens, type, size, entities, name );
01187 }
01188 
01189 
01190 ErrorCode ReadVtk::vtk_read_color_attrib( FileTokenizer& tokens, 
01191                                             std::vector<Range>& entities,
01192                                             const char* name)
01193 {
01194   long size;
01195   if (!tokens.get_long_ints( 1, &size ) || size < 1)
01196     return MB_FAILURE;
01197 
01198   return vtk_read_tag_data( tokens, 10, size, entities, name );
01199 }
01200 
01201 ErrorCode ReadVtk::vtk_read_vector_attrib( FileTokenizer& tokens, 
01202                                              std::vector<Range>& entities,
01203                                              const char* name)
01204 {
01205   int type = tokens.match_token( vtk_type_names );
01206   if (!type)
01207     return MB_FAILURE;
01208     
01209   return vtk_read_tag_data( tokens, type, 3, entities, name );
01210 }
01211 
01212 ErrorCode ReadVtk::vtk_read_texture_attrib( FileTokenizer& tokens,
01213                                               std::vector<Range>& entities,
01214                                               const char* name)
01215 {
01216   int type, dim;
01217   if (!tokens.get_integers( 1, &dim ) ||
01218       !(type = tokens.match_token( vtk_type_names )))
01219     return MB_FAILURE;
01220     
01221   if (dim < 1 || dim > 3)
01222   {
01223     readMeshIface->report_error( "Invalid dimension (%d) at line %d.",
01224                      dim, tokens.line_number() );
01225     return MB_FAILURE;
01226   }
01227   
01228   return vtk_read_tag_data( tokens, type, dim, entities, name );
01229 }
01230 
01231 ErrorCode ReadVtk::vtk_read_tensor_attrib( FileTokenizer& tokens,
01232                                              std::vector<Range>& entities,
01233                                              const char* name ) 
01234 {
01235   int type = tokens.match_token( vtk_type_names );
01236   if (!type)
01237     return MB_FAILURE;
01238     
01239   return vtk_read_tag_data( tokens, type, 9, entities, name );
01240 }  
01241 
01242 ErrorCode ReadVtk::vtk_read_field_attrib( FileTokenizer& tokens, 
01243                                             std::vector<Range>& entities,
01244                                             const char* )
01245 {
01246   long num_fields;
01247   if (!tokens.get_long_ints(1, &num_fields))
01248     return MB_FAILURE;
01249 
01250   long i;
01251   for ( i = 0; i < num_fields; ++ i )
01252     {
01253     const char* tok = tokens.get_string( );
01254     if ( ! tok )
01255       return MB_FAILURE;
01256 
01257     std::string name_alloc( tok );
01258 
01259     long num_comp;
01260     if (!tokens.get_long_ints( 1, &num_comp))
01261       return MB_FAILURE;
01262 
01263     long num_tuples;
01264     if (!tokens.get_long_ints( 1, &num_tuples))
01265       return MB_FAILURE;
01266 
01267     int type = tokens.match_token( vtk_type_names );
01268     if (!type)
01269       return MB_FAILURE;
01270 
01271     ErrorCode result;
01272     if ( ( result = vtk_read_tag_data( tokens, type, num_comp, entities, name_alloc.c_str() ) ) != MB_SUCCESS )
01273       {
01274       readMeshIface->report_error(
01275         "Error reading data for field \"%s\" (%ld components, %ld tuples, type %d) at line %d",
01276         name_alloc.c_str(), num_comp, num_tuples, (int)type, tokens.line_number());
01277       return result;
01278       }
01279     }
01280 
01281   return MB_SUCCESS;
01282 }
01283 
01284 ErrorCode ReadVtk::store_file_ids( Tag tag, const Range& verts,
01285                                      const std::vector<Range>& elems )
01286 {
01287   ErrorCode rval;
01288   
01289   rval = readMeshIface->assign_ids( tag, verts );
01290   if (MB_SUCCESS != rval)
01291     return rval;
01292 
01293   int id = 0;
01294   for (size_t i = 0; i < elems.size(); ++i) {
01295     rval = readMeshIface->assign_ids( tag, elems[i], id );
01296     id += elems[i].size();
01297   }
01298   
01299   return MB_SUCCESS;
01300 }
01301 
01302 } // namespace moab
01303 
01304     
01305     
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines