moab
|
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