moab
WriteVtk.cpp
Go to the documentation of this file.
00001 
00017 #ifdef WIN32
00018 #ifdef _DEBUG
00019 // turn off warnings that say they debugging identifier has been truncated
00020 // this warning comes up when using some STL containers
00021 #pragma warning(disable : 4786)
00022 #endif
00023 #endif
00024 
00025 
00026 #include "WriteVtk.hpp"
00027 #include "VtkUtil.hpp"
00028 #include "SysUtil.hpp"
00029 
00030 #include <fstream>
00031 #include <iostream>
00032 #include <stdio.h>
00033 #include <assert.h>
00034 #include <vector>
00035 #include <set>
00036 #include <iterator>
00037 
00038 #include "moab/Interface.hpp"
00039 #include "moab/Range.hpp"
00040 #include "moab/CN.hpp"
00041 #include "MBTagConventions.hpp"
00042 #include "moab/WriteUtilIface.hpp"
00043 #include "Internals.hpp"
00044 #include "moab/FileOptions.hpp"
00045 #include "moab/Version.h"
00046 
00047 #define INS_ID(stringvar, prefix, id) \
00048 sprintf(stringvar, prefix, id)
00049 
00050 namespace moab {
00051 
00052 const int DEFAULT_PRECISION = 10;
00053 const bool DEFAULT_STRICT = true;
00054 
00055 WriterIface *WriteVtk::factory( Interface* iface )
00056   { return new WriteVtk( iface ); }
00057 
00058 WriteVtk::WriteVtk(Interface *impl) 
00059     : mbImpl(impl), writeTool(0), mStrict(DEFAULT_STRICT)
00060 {
00061   assert(impl != NULL);
00062 
00063   impl->query_interface( writeTool );
00064 }
00065 
00066 WriteVtk::~WriteVtk() 
00067 {
00068   mbImpl->release_interface(writeTool);
00069 }
00070 
00071 ErrorCode WriteVtk::write_file(const char *file_name, 
00072                                  const bool overwrite,
00073                                  const FileOptions& opts,
00074                                  const EntityHandle *output_list,
00075                                  const int num_sets,
00076                                  const std::vector<std::string>& ,
00077                                  const Tag* tag_list,
00078                                  int num_tags,
00079                                  int )
00080 {
00081   ErrorCode rval;
00082 
00083     // Get precision for node coordinates
00084   int precision;
00085   if (MB_SUCCESS != opts.get_int_option( "PRECISION", precision ))
00086     precision = DEFAULT_PRECISION;
00087   
00088   if (MB_SUCCESS == opts.get_null_option( "STRICT" ))
00089     mStrict = true;
00090   else if (MB_SUCCESS == opts.get_null_option( "RELAXED" ))
00091     mStrict = false;
00092   else
00093     mStrict = DEFAULT_STRICT;
00094   
00095     // Get entities to write
00096   Range nodes, elems;
00097   rval = gather_mesh( output_list, num_sets, nodes, elems );
00098   if (MB_SUCCESS != rval)
00099     return rval;
00100   
00101     // Honor overwrite flag
00102   if (!overwrite)
00103   {
00104     rval = writeTool->check_doesnt_exist( file_name );
00105     if (MB_SUCCESS != rval)
00106       return rval;
00107   }
00108   
00109     // Create file
00110   std::ofstream file( file_name );
00111   if (!file)
00112   {
00113     writeTool->report_error("Could not open file: %s\n", file_name );
00114     return MB_FILE_WRITE_ERROR;
00115   }
00116   file.precision( precision );
00117   
00118     // Write file
00119   if ((rval = write_header(file              )) != MB_SUCCESS ||
00120       (rval = write_nodes( file, nodes       )) != MB_SUCCESS ||
00121       (rval = write_elems( file, nodes, elems)) != MB_SUCCESS ||
00122       (rval = write_tags ( file, true,  nodes, tag_list, num_tags)) != MB_SUCCESS ||
00123       (rval = write_tags ( file, false, elems, tag_list, num_tags)) != MB_SUCCESS)
00124   {
00125     file.close();
00126     remove( file_name );
00127     return rval;
00128   } 
00129   
00130   return MB_SUCCESS;
00131 }
00132 
00133 
00134 ErrorCode WriteVtk::gather_mesh( const EntityHandle* set_list,
00135                                    int num_sets, 
00136                                    Range& nodes,
00137                                    Range& elems )
00138 {
00139   ErrorCode rval;
00140   int e;
00141   
00142   if (!set_list || !num_sets)
00143   {
00144     Range a;
00145     rval = mbImpl->get_entities_by_handle( 0, a );
00146     if (MB_SUCCESS != rval) return rval;
00147 
00148     Range::const_iterator node_i, elem_i, set_i;
00149     node_i = a.lower_bound( a.begin(), a.end(), CREATE_HANDLE(    MBVERTEX, 0, e ) );
00150     elem_i = a.lower_bound(    node_i, a.end(), CREATE_HANDLE(      MBEDGE, 0, e ) );
00151     set_i  = a.lower_bound(    elem_i, a.end(), CREATE_HANDLE( MBENTITYSET, 0, e ) );
00152     nodes.merge( node_i, elem_i );
00153     elems.merge( elem_i, set_i );
00154 
00155       // filter out unsupported element types
00156     EntityType et = MBEDGE;
00157     for (et++; et < MBENTITYSET; et++) {
00158       if (VtkUtil::get_vtk_type(et, CN::VerticesPerEntity(et))) continue;
00159       Range::iterator 
00160         eit = elems.lower_bound(elems.begin(), elems.end(), CREATE_HANDLE(et, 0, e)),
00161         ep1it = elems.lower_bound(elems.begin(), elems.end(), CREATE_HANDLE(et+1, 0, e));
00162       elems.erase(eit, ep1it);
00163     }
00164   }
00165   else
00166   {
00167     std::set<EntityHandle> visited;
00168     std::vector<EntityHandle> sets;
00169     sets.reserve(num_sets);
00170     std::copy( set_list, set_list + num_sets, std::back_inserter(sets) );
00171     while (!sets.empty()) {
00172         // get next set
00173       EntityHandle set = sets.back();
00174       sets.pop_back();
00175         // skip sets we've already done
00176       if (!visited.insert(set).second)
00177         continue;
00178       
00179       Range a;
00180       rval = mbImpl->get_entities_by_handle( set, a );
00181       if (MB_SUCCESS != rval) return rval;
00182       
00183       Range::const_iterator node_i, elem_i, set_i;
00184       node_i = a.lower_bound( a.begin(), a.end(), CREATE_HANDLE(    MBVERTEX, 0, e ) );
00185       elem_i = a.lower_bound(    node_i, a.end(), CREATE_HANDLE(      MBEDGE, 0, e ) );
00186       set_i  = a.lower_bound(    elem_i, a.end(), CREATE_HANDLE( MBENTITYSET, 0, e ) );
00187       nodes.merge( node_i, elem_i );
00188       elems.merge( elem_i, set_i );
00189       std::copy( set_i, a.end(), std::back_inserter(sets) );
00190       
00191       a.clear();
00192       rval = mbImpl->get_child_meshsets( set, a );
00193       std::copy( a.begin(), a.end(), std::back_inserter(sets) );
00194     }
00195     
00196     for (Range::const_iterator ei = elems.begin(); ei != elems.end(); ++ei)
00197     {
00198       std::vector<EntityHandle> connect;
00199       rval = mbImpl->get_connectivity( &(*ei), 1, connect );
00200       if (MB_SUCCESS != rval) return rval;
00201 
00202       for (unsigned int i = 0; i < connect.size(); ++i)
00203     nodes.insert( connect[i] );
00204     }
00205   }
00206 
00207   if (nodes.empty())
00208   {
00209     writeTool->report_error( "Nothing to write.\n" );
00210     return  MB_ENTITY_NOT_FOUND;
00211   }
00212   
00213   return MB_SUCCESS;
00214 }
00215 
00216 ErrorCode WriteVtk::write_header( std::ostream& stream )
00217 {
00218   stream << "# vtk DataFile Version 3.0" << std::endl;
00219   stream << MB_VERSION_STRING << std::endl;
00220   stream << "ASCII" << std::endl;
00221   stream << "DATASET UNSTRUCTURED_GRID" << std::endl;
00222   return MB_SUCCESS;
00223 }
00224 
00225 
00226 ErrorCode WriteVtk::write_nodes( std::ostream& stream, const Range& nodes )
00227 {
00228   ErrorCode rval;
00229   
00230   stream << "POINTS " << nodes.size() << " double" << std::endl;
00231   
00232   double coords[3];
00233   for (Range::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
00234     coords[1] = coords[2] = 0.0;
00235     rval = mbImpl->get_coords( &*i, 1, coords );
00236     if (MB_SUCCESS != rval)
00237       return rval;
00238     stream << coords[0] << ' ' << coords[1] << ' ' <<coords[2] << std::endl;
00239   }
00240   
00241   return MB_SUCCESS;
00242 }
00243 
00244 ErrorCode WriteVtk::write_elems( std::ostream& stream, 
00245                                    const Range& nodes,
00246                                    const Range& elems )
00247 {
00248   ErrorCode rval;
00249 
00250   // Get and write counts
00251   unsigned long num_elems, num_uses;
00252   num_elems = num_uses = elems.size();
00253   for (Range::const_iterator i = elems.begin(); i != elems.end(); ++i)
00254   {
00255     EntityType type = mbImpl->type_from_handle(*i);
00256     if (!VtkUtil::get_vtk_type(type, CN::VerticesPerEntity(type))) continue;
00257     
00258     std::vector<EntityHandle> connect;
00259     rval = mbImpl->get_connectivity( &(*i), 1, connect );
00260     
00261     if (MB_SUCCESS != rval)
00262       return rval;
00263 
00264     num_uses += connect.size();
00265   }
00266   stream << "CELLS " << num_elems << ' ' << num_uses << std::endl;
00267   
00268     // Write element connectivity
00269   std::vector<int> conn_data;
00270   std::vector<unsigned> vtk_types( elems.size() );
00271   std::vector<unsigned>::iterator t = vtk_types.begin();
00272   for (Range::const_iterator i = elems.begin(); i != elems.end(); ++i)
00273   {
00274       // Get type information for element
00275     EntityType type = TYPE_FROM_HANDLE(*i);
00276 
00277       // Get element connectivity
00278     std::vector<EntityHandle> connect;
00279     rval = mbImpl->get_connectivity( &(*i), 1, connect );
00280     int conn_len = connect.size();
00281 
00282     if (MB_SUCCESS != rval)
00283       return rval;
00284 
00285       // Get VTK type
00286     const VtkElemType* vtk_type = VtkUtil::get_vtk_type( type, conn_len );
00287     if (!vtk_type) {
00288         // try connectivity with 1 fewer node
00289       vtk_type = VtkUtil::get_vtk_type( type, conn_len-1 );
00290       if (vtk_type) conn_len--;
00291       else {
00292         writeTool->report_error( "Vtk file format does not support elements "
00293                                  "of type %s (%d) with %d nodes.\n", CN::EntityTypeName(type), 
00294                                  (int)type, conn_len);
00295         return MB_FAILURE;
00296       }
00297     }
00298 
00299       // Get IDs from vertex handles
00300     assert( conn_len > 0 );
00301     conn_data.resize( conn_len );
00302     for (int j = 0; j < conn_len; ++j)
00303       conn_data[j] = nodes.index( connect[j] );
00304     
00305       // Save VTK type index for later
00306     *t = vtk_type->vtk_type;
00307     ++t;
00308     
00309       // Write connectivity list
00310     stream << conn_len;
00311     if (vtk_type->node_order)
00312       for (int k = 0; k < conn_len; ++k)
00313         stream << ' ' << conn_data[vtk_type->node_order[k]];
00314     else
00315       for (int k = 0; k < conn_len; ++k)
00316         stream << ' ' << conn_data[k];
00317     stream << std::endl;
00318   }
00319    
00320     // Write element types
00321   stream << "CELL_TYPES " << num_elems << std::endl;
00322   for (std::vector<unsigned>::const_iterator i = vtk_types.begin(); i != vtk_types.end(); ++i)
00323     stream << *i << std::endl;
00324   
00325   return MB_SUCCESS;
00326 }
00327 
00328 
00329 
00330 ErrorCode WriteVtk::write_tags( std::ostream& stream, 
00331                                   bool nodes, 
00332                                   const Range& entities,
00333                                   const Tag* tag_list,
00334                                   int num_tags )
00335 {
00336   ErrorCode rval;
00337   
00338     // The #$%@#$% MOAB interface does not have a function to retreive
00339     // all entities with a tag, only all entities with a specified type
00340     // and tag.  Define types to loop over depending on the if vertex
00341     // or element tag data is being written.  It seems horribly inefficient
00342     // to have the implementation subdivide the results by type and have
00343     // to call that function once for each type just to recombine the results.
00344     // Unfortunamtely, there doesn't seem to be any other way.
00345   EntityType low_type, high_type;
00346   if (nodes) 
00347   {
00348     low_type = MBVERTEX;
00349     high_type = MBEDGE;
00350   }
00351   else
00352   {
00353     low_type = MBEDGE;
00354     high_type = MBENTITYSET;
00355   }
00356 
00357     // Get all defined tags
00358   std::vector<Tag> tags;
00359   std::vector<Tag>::iterator i;
00360   rval = writeTool->get_tag_list( tags, tag_list, num_tags, false );
00361   if (MB_SUCCESS != rval)
00362     return rval;
00363   
00364     // For each tag...  
00365   bool entities_have_tags = false;
00366   for (i = tags.begin(); i != tags.end(); ++i)
00367   {
00368       // Skip tags holding entity handles -- no way to save them
00369     DataType dtype;
00370     rval = mbImpl->tag_get_data_type( *i, dtype );
00371     if (MB_SUCCESS != rval)
00372       return rval;
00373     if (dtype == MB_TYPE_HANDLE)
00374       continue;
00375       
00376       // If in strict mode, don't write tags that do not fit in any 
00377       // attribute type (SCALAR : 1 to 4 values, VECTOR : 3 values, TENSOR : 9 values)
00378     if (mStrict) {
00379       int count;
00380       rval = mbImpl->tag_get_length( *i, count );
00381       if (MB_SUCCESS != rval)
00382         return rval;
00383       if (count < 1 || (count > 4 && count != 9))
00384         continue;
00385     }
00386           
00387     
00388       // Get subset of input entities that have the tag set
00389     Range tagged;
00390     for (EntityType type = low_type; type < high_type; ++type)
00391     {
00392       Range tmp_tagged;
00393       rval = mbImpl->get_entities_by_type_and_tag( 0, type, &*i, 0, 1, tmp_tagged );
00394       if (MB_SUCCESS != rval)
00395         return rval;
00396       tmp_tagged = intersect( tmp_tagged, entities );
00397       tagged.merge( tmp_tagged );
00398     }
00399 
00400       // If any entities were tadged
00401     if (!tagged.empty())
00402     {
00403         // If this is the first tag being written for the
00404         // entity type, write the label marking the beginning
00405         // of the tag data.
00406       if (!entities_have_tags)
00407       {
00408         entities_have_tags = true;
00409         stream << (nodes ? "POINT_DATA " : "CELL_DATA ") << entities.size() << std::endl;
00410       }
00411       
00412         // Write the tag 
00413       rval = write_tag( stream, *i, entities, tagged );
00414       if (MB_SUCCESS != rval)
00415         return rval;
00416     }
00417   }
00418   
00419   return MB_SUCCESS;
00420 }
00421 
00422 template <typename T>
00423 void WriteVtk::write_data( std::ostream& stream, 
00424                            const std::vector<T>& data,
00425                            unsigned vals_per_tag )
00426 {
00427   typename std::vector<T>::const_iterator d = data.begin();
00428   const unsigned long n = data.size() / vals_per_tag;
00429   
00430   for (unsigned long i = 0; i < n; ++i)
00431   {
00432     for (unsigned j = 0; j < vals_per_tag; ++j, ++d)
00433     {
00434       if (sizeof(T) == 1) 
00435         stream << (unsigned int)*d << ' ';
00436       else
00437         stream << *d << ' ';
00438     }
00439     stream << std::endl;
00440   }
00441 }
00442 
00443 //template <>
00444 //void WriteVtk::write_data<unsigned char>( std::ostream& stream, 
00445 //                                          const std::vector<unsigned char>& data,
00446 //                                          unsigned vals_per_tag )
00447 //{
00448 //  std::vector<unsigned char>::const_iterator d = data.begin();
00449 //  const unsigned long n = data.size() / vals_per_tag;
00450 //  
00451 //  for (unsigned long i = 0; i < n; ++i)
00452 //  {
00453 //    for (unsigned j = 0; j < vals_per_tag; ++j, ++d)
00454 //    {
00455 //      stream << (unsigned int)*d << ' ';
00456 //    }
00457 //    stream << std::endl;
00458 //  }
00459 //}
00460 
00461 
00462 template <typename T>
00463 ErrorCode WriteVtk::write_tag( std::ostream& stream, Tag tag, const Range& entities, const Range& tagged,
00464                                  const int)
00465 {
00466   ErrorCode rval;
00467   const unsigned long n = entities.size();
00468   
00469     // Get tag properties  
00470 
00471   std::string name;
00472   int vals_per_tag;
00473   if (MB_SUCCESS != mbImpl->tag_get_name( tag, name ) ||
00474       MB_SUCCESS != mbImpl->tag_get_length( tag, vals_per_tag ) )
00475     return MB_FAILURE;
00476   
00477     // Get a tag value for each entity.  Do this by initializing the
00478     // "data" vector with zero, and then filling in the values for
00479     // the entities that actually have the tag set.
00480   std::vector<T> data;
00481   data.resize( n * vals_per_tag, 0 );
00482   // if there is a default value for the tag, set the actual default value
00483   std::vector<T> def_value(vals_per_tag);
00484   rval = mbImpl-> tag_get_default_value( tag, &(def_value[0]));
00485   if (MB_SUCCESS==rval)
00486   {
00487      SysUtil::setmem(&(data[0]), &(def_value[0]), vals_per_tag*sizeof(T), n);
00488   }
00489   Range::const_iterator t = tagged.begin();
00490   typename std::vector<T>::iterator d = data.begin();
00491   for (Range::const_iterator i = entities.begin(); 
00492        i != entities.end() && t != tagged.end(); ++i, d += vals_per_tag)
00493   {
00494     if (*i == *t)
00495     {
00496       ++t;
00497       rval = mbImpl->tag_get_data( tag, &*i, 1, &*d );
00498       if (MB_SUCCESS != rval)
00499         return rval;
00500     }
00501   }
00502   
00503     // Write the tag values, one entity per line.
00504   write_data( stream, data, vals_per_tag );
00505   
00506   return MB_SUCCESS;
00507 }
00508 
00509 ErrorCode WriteVtk::write_bit_tag( std::ostream& stream, 
00510                                      Tag tag, 
00511                                      const Range& entities, 
00512                                      const Range& tagged )
00513 {
00514   ErrorCode rval;
00515   const unsigned long n = entities.size();
00516   
00517     // Get tag properties  
00518 
00519   std::string name;
00520   int vals_per_tag;
00521   if (MB_SUCCESS != mbImpl->tag_get_name( tag, name ) ||
00522       MB_SUCCESS != mbImpl->tag_get_length( tag, vals_per_tag ) )
00523     return MB_FAILURE;
00524 
00525   if (vals_per_tag > 8) {
00526     writeTool->report_error( "Invalid tag size for bit tag \"%s\"\n", name.c_str() );
00527     return MB_FAILURE;
00528   } 
00529   
00530     // Get a tag value for each entity.  
00531     // Get bits for each entity and unpack into
00532     // one integer in the 'data' array for each bit.
00533     // Initialise 'data' to zero because we will skip
00534     // those entities for which the tag is not set.
00535   std::vector<unsigned short> data;
00536   data.resize( n * vals_per_tag, 0 );
00537   Range::const_iterator t = tagged.begin();
00538   std::vector<unsigned short>::iterator d = data.begin();
00539   for (Range::const_iterator i = entities.begin(); 
00540        i != entities.end() && t != tagged.end(); ++i)
00541   {
00542     if (*i == *t)
00543     {
00544       ++t;
00545       unsigned char value;
00546       rval = mbImpl->tag_get_data( tag, &*i, 1, &value );
00547       for (int j = 0; j < vals_per_tag; ++j, ++d)
00548         *d = (unsigned short) (value & (1<<j) ? 1 : 0);
00549       if (MB_SUCCESS != rval)
00550         return rval;
00551     }
00552     else
00553     {
00554       // if tag is not set for entity, skip values in array
00555       d += vals_per_tag;
00556     }
00557   }
00558   
00559     // Write the tag values, one entity per line.
00560   write_data( stream, data, vals_per_tag );
00561   
00562   return MB_SUCCESS;
00563 }
00564 
00565 ErrorCode WriteVtk::write_tag( std::ostream& s, Tag tag,
00566                                  const Range& entities,
00567                                  const Range& tagged )
00568 {
00569     // Get tag properties
00570   std::string name;
00571   DataType type;
00572   int vals_per_tag;
00573   if (MB_SUCCESS != mbImpl->tag_get_name( tag, name ) ||
00574       MB_SUCCESS != mbImpl->tag_get_length( tag, vals_per_tag ) ||
00575       MB_SUCCESS != mbImpl->tag_get_data_type( tag, type ))
00576     return MB_FAILURE;
00577   
00578     // Skip tags of type ENTITY_HANDLE
00579   if (type == MB_TYPE_HANDLE)
00580     return MB_FAILURE;
00581   
00582     // Now that we're past the point where the name would be used in
00583     // an error message, remove any spaces to conform to VTK file.
00584   for (std::string::iterator i = name.begin(); i != name.end(); ++i)
00585     if (isspace(*i) || iscntrl(*i))
00586       *i = '_';
00587   
00588     // Write the tag desciption
00589   if (vals_per_tag == 3 && type == MB_TYPE_DOUBLE)
00590     s << "VECTORS " << name << ' ' << VtkUtil::vtkTypeNames[type] << std::endl;
00591   else if (vals_per_tag == 9)
00592     s << "TENSORS " << name << ' ' << VtkUtil::vtkTypeNames[type] << std::endl;
00593   else
00594     s << "SCALARS " << name << ' ' << VtkUtil::vtkTypeNames[type] << ' '
00595     << vals_per_tag << std::endl << "LOOKUP_TABLE default" << std::endl;
00596   
00597     // Write the tag data
00598   switch (type) 
00599   {
00600     case MB_TYPE_OPAQUE:  return write_tag<unsigned char>(s, tag, entities, tagged, 0 );
00601     case MB_TYPE_INTEGER: return write_tag<          int>(s, tag, entities, tagged, 0 );
00602     case MB_TYPE_DOUBLE:  return write_tag<       double>(s, tag, entities, tagged, 0 );
00603     case MB_TYPE_BIT:     return write_bit_tag(s, tag, entities, tagged );
00604     default:              return MB_FAILURE;
00605   }
00606 }
00607 
00608 } // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines