vtk_io.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 // C++ includes 00020 #include <fstream> 00021 00022 // Local includes 00023 #include "libmesh/libmesh_config.h" 00024 #include "libmesh/vtk_io.h" 00025 #include "libmesh/mesh_base.h" 00026 #include "libmesh/equation_systems.h" 00027 #include "libmesh/cell_tet4.h" 00028 #include "libmesh/cell_tet10.h" 00029 #include "libmesh/cell_prism6.h" 00030 #include "libmesh/cell_pyramid5.h" 00031 #include "libmesh/cell_hex8.h" 00032 #include "libmesh/cell_hex20.h" 00033 #include "libmesh/numeric_vector.h" 00034 #include "libmesh/system.h" 00035 #include "libmesh/mesh_data.h" 00036 00037 #ifdef LIBMESH_HAVE_VTK 00038 00039 #include "libmesh/ignore_warnings.h" 00040 #include "vtkXMLUnstructuredGridReader.h" 00041 #include "vtkXMLUnstructuredGridWriter.h" 00042 #include "vtkXMLPUnstructuredGridWriter.h" 00043 #include "vtkUnstructuredGrid.h" 00044 #include "vtkGenericGeometryFilter.h" 00045 #include "vtkCellArray.h" 00046 #include "vtkConfigure.h" 00047 #include "vtkDoubleArray.h" 00048 #include "vtkPointData.h" 00049 #include "vtkPoints.h" 00050 #include "vtkSmartPointer.h" 00051 #include "libmesh/restore_warnings.h" 00052 00053 // A convenient macro for comparing VTK versions. Returns 1 if the 00054 // current VTK version is < major.minor.subminor and zero otherwise. 00055 // 00056 // It relies on the VTK version numbers detected during configure. Note that if 00057 // LIBMESH_HAVE_VTK is not defined, none of the LIBMESH_DETECTED_VTK_VERSION_* variables will 00058 // be defined either. 00059 #define VTK_VERSION_LESS_THAN(major,minor,subminor) \ 00060 ((LIBMESH_DETECTED_VTK_VERSION_MAJOR < (major) || \ 00061 (LIBMESH_DETECTED_VTK_VERSION_MAJOR == (major) && (LIBMESH_DETECTED_VTK_VERSION_MINOR < (minor) || \ 00062 (LIBMESH_DETECTED_VTK_VERSION_MINOR == (minor) && \ 00063 LIBMESH_DETECTED_VTK_VERSION_SUBMINOR < (subminor))))) ? 1 : 0) 00064 00065 00066 00067 00068 #endif //LIBMESH_HAVE_VTK 00069 00070 namespace libMesh 00071 { 00072 00073 #ifdef LIBMESH_HAVE_VTK // private functions 00074 vtkIdType VTKIO::get_elem_type(ElemType type) { 00075 vtkIdType celltype = VTK_EMPTY_CELL; // initialize to something to avoid compiler warning 00076 00077 switch(type) 00078 { 00079 case EDGE2: 00080 celltype = VTK_LINE; 00081 break; 00082 case EDGE3: 00083 celltype = VTK_QUADRATIC_EDGE; 00084 break;// 1 00085 case TRI3: 00086 celltype = VTK_TRIANGLE; 00087 break;// 3 00088 case TRI6: 00089 celltype = VTK_QUADRATIC_TRIANGLE; 00090 break;// 4 00091 case QUAD4: 00092 celltype = VTK_QUAD; 00093 break;// 5 00094 case QUAD8: 00095 celltype = VTK_QUADRATIC_QUAD; 00096 break;// 6 00097 case TET4: 00098 celltype = VTK_TETRA; 00099 break;// 8 00100 case TET10: 00101 celltype = VTK_QUADRATIC_TETRA; 00102 break;// 9 00103 case HEX8: 00104 celltype = VTK_HEXAHEDRON; 00105 break;// 10 00106 case HEX20: 00107 celltype = VTK_QUADRATIC_HEXAHEDRON; 00108 break;// 12 00109 case HEX27: 00110 celltype = VTK_TRIQUADRATIC_HEXAHEDRON; 00111 break; 00112 case PRISM6: 00113 celltype = VTK_WEDGE; 00114 break;// 13 00115 case PRISM15: 00116 celltype = VTK_QUADRATIC_WEDGE; 00117 break;// 14 00118 case PRISM18: 00119 celltype = VTK_BIQUADRATIC_QUADRATIC_WEDGE; 00120 break;// 15 00121 case PYRAMID5: 00122 celltype = VTK_PYRAMID; 00123 break;// 16 00124 #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) 00125 case QUAD9: 00126 celltype = VTK_BIQUADRATIC_QUAD; 00127 break; 00128 #else 00129 case QUAD9: 00130 #endif 00131 case EDGE4: 00132 case INFEDGE2: 00133 case INFQUAD4: 00134 case INFQUAD6: 00135 case INFHEX8: 00136 case INFHEX16: 00137 case INFHEX18: 00138 case INFPRISM6: 00139 case INFPRISM12: 00140 case NODEELEM: 00141 case INVALID_ELEM: 00142 default: 00143 { 00144 libMesh::err<<"element type "<<type<<" not implemented"<<std::endl; 00145 libmesh_error(); 00146 break; 00147 } 00148 } 00149 return celltype; 00150 } 00151 00152 00153 void VTKIO::nodes_to_vtk() 00154 { 00155 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 00156 00157 // containers for points and coordinates of points 00158 vtkSmartPointer<vtkPoints> points = vtkPoints::New(); 00159 vtkSmartPointer<vtkDoubleArray> pcoords = vtkDoubleArray::New(); 00160 pcoords->SetNumberOfComponents(LIBMESH_DIM); 00161 points->SetNumberOfPoints(mesh.n_local_nodes()); // it seems that it needs this to prevent a segfault 00162 00163 unsigned int local_node_counter = 0; 00164 00165 MeshBase::const_node_iterator nd = mesh.local_nodes_begin(); 00166 MeshBase::const_node_iterator nd_end = mesh.local_nodes_end(); 00167 for (; nd != nd_end; nd++, local_node_counter++) 00168 { 00169 Node* node = (*nd); 00170 00171 float pnt[LIBMESH_DIM]; 00172 for (unsigned int i = 0; i < LIBMESH_DIM; ++i) 00173 pnt[i] = (*node)(i); 00174 00175 // Fill mapping between global and local node numbers 00176 _local_node_map[node->id()] = local_node_counter; 00177 00178 // add point 00179 pcoords->InsertNextTuple(pnt); // SetTuple(node->id(),pnt); 00180 } 00181 00182 // add coordinates to points 00183 points->SetData(pcoords); 00184 pcoords->Delete(); 00185 // add points to grid 00186 _vtk_grid->SetPoints(points); 00187 points->Delete(); 00188 } 00189 00190 00191 void VTKIO::cells_to_vtk() 00192 { 00193 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 00194 00195 vtkSmartPointer<vtkCellArray> cells = vtkCellArray::New(); 00196 vtkSmartPointer<vtkIdList> pts = vtkIdList::New(); 00197 00198 std::vector<int> types(mesh.n_active_local_elem()); 00199 int active_element_counter = 0; 00200 00201 MeshBase::const_element_iterator it = mesh.active_local_elements_begin(); 00202 const MeshBase::const_element_iterator end = mesh.active_local_elements_end(); 00203 for (; it != end; it++, ++active_element_counter) 00204 { 00205 Elem *elem = *it; 00206 00207 pts->SetNumberOfIds(elem->n_nodes()); 00208 00209 // get the connectivity for this element 00210 std::vector<dof_id_type> conn; 00211 elem->connectivity(0, VTK, conn); 00212 00213 for (unsigned int i = 0; i < conn.size(); ++i) 00214 { 00215 if (_local_node_map.find(conn[i]) == _local_node_map.end()) 00216 { 00217 // Ghost node 00218 float pt[LIBMESH_DIM]; 00219 dof_id_type node = elem->node(i); 00220 for (unsigned int d = 0; d < LIBMESH_DIM; ++d) 00221 { 00222 pt[d] = mesh.node(node)(d); 00223 } 00224 vtkIdType local = _vtk_grid->GetPoints()->InsertNextPoint(pt); 00225 _local_node_map[node] = local; 00226 } 00227 pts->InsertId(i, _local_node_map[conn[i]]); 00228 } 00229 00230 cells->InsertNextCell(pts); 00231 types[active_element_counter] = this->get_elem_type(elem->type()); 00232 } // end loop over active elements 00233 pts->Delete(); 00234 _vtk_grid->SetCells(&types[0], cells); 00235 cells->Delete(); 00236 } 00237 00238 /* 00239 * FIXME now this is known to write nonsense on AMR meshes 00240 * and it strips the imaginary parts of complex Numbers 00241 */ 00242 void VTKIO::system_vectors_to_vtk(const EquationSystems& es,vtkUnstructuredGrid*& grid){ 00243 if (libMesh::processor_id() == 0){ 00244 00245 std::map<std::string,std::vector<Number> > vecs; 00246 for(unsigned int i=0;i<es.n_systems();++i){ 00247 const System& sys = es.get_system(i); 00248 System::const_vectors_iterator v_end = sys.vectors_end(); 00249 System::const_vectors_iterator it = sys.vectors_begin(); 00250 for(;it!= v_end;++it){ // for all vectors on this system 00251 std::vector<Number> values; 00252 // libMesh::out<<"it "<<it->first<<std::endl; 00253 00254 it->second->localize_to_one(values,0); 00255 // libMesh::out<<"finish localize"<<std::endl; 00256 vecs[it->first] = values; 00257 } 00258 } 00259 00260 00261 std::map<std::string,std::vector<Number> >::iterator it = vecs.begin(); 00262 00263 for(;it!=vecs.end();++it){ 00264 00265 vtkDoubleArray *data = vtkDoubleArray::New(); 00266 00267 data->SetName(it->first.c_str()); 00268 00269 libmesh_assert_equal_to (it->second.size(), es.get_mesh().n_nodes()); 00270 00271 data->SetNumberOfValues(it->second.size()); 00272 00273 for(unsigned int i=0;i<it->second.size();++i){ 00274 00275 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00276 libmesh_do_once (libMesh::err << "Only writing the real part for complex numbers!\n" 00277 << "if you need this support contact " << LIBMESH_PACKAGE_BUGREPORT 00278 << std::endl); 00279 data->SetValue(i,it->second[i].real()); 00280 #else 00281 data->SetValue(i,it->second[i]); 00282 #endif 00283 00284 } 00285 00286 grid->GetPointData()->AddArray(data); 00287 data->Delete(); 00288 } 00289 00290 } 00291 00292 } 00293 00294 /* 00295 // write out mesh data to the VTK file, this might come in handy to display 00296 // boundary conditions and material data 00297 inline void meshdata_to_vtk(const MeshData& meshdata, 00298 vtkUnstructuredGrid* grid){ 00299 vtkPointData* pointdata = vtkPointData::New(); 00300 00301 const unsigned int n_vn = meshdata.n_val_per_node(); 00302 const unsigned int n_dat = meshdata.n_node_data(); 00303 00304 pointdata->SetNumberOfTuples(n_dat); 00305 }*/ 00306 00307 #endif 00308 00309 00310 // ------------------------------------------------------------ 00311 // vtkIO class members 00312 // 00313 void VTKIO::read (const std::string& name) 00314 { 00315 // This is a serial-only process for now; 00316 // the Mesh should be read on processor 0 and 00317 // broadcast later 00318 libmesh_assert_equal_to (libMesh::processor_id(), 0); 00319 00320 // Keep track of what kinds of elements this file contains 00321 elems_of_dimension.clear(); 00322 elems_of_dimension.resize(4, false); 00323 00324 #ifndef LIBMESH_HAVE_VTK 00325 libMesh::err << "Cannot read VTK file: " << name 00326 << "\nYou must have VTK installed and correctly configured to read VTK meshes." 00327 << std::endl; 00328 libmesh_error(); 00329 00330 #else 00331 // libMesh::out<<"read "<<name <<std::endl; 00332 vtkXMLUnstructuredGridReader *reader = vtkXMLUnstructuredGridReader::New(); 00333 reader->SetFileName( name.c_str() ); 00334 //libMesh::out<<"force read"<<std::endl; 00335 // Force reading 00336 reader->Update(); 00337 00338 // read in the grid 00339 // vtkUnstructuredGrid *grid = reader->GetOutput(); 00340 _vtk_grid = reader->GetOutput(); 00341 _vtk_grid->Update(); 00342 reader->Delete(); 00343 00344 // Get a reference to the mesh 00345 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 00346 00347 // Clear out any pre-existing data from the Mesh 00348 mesh.clear(); 00349 00350 // always numbered nicely??, so we can loop like this 00351 // I'm pretty sure it is numbered nicely 00352 for (unsigned int i=0; i < static_cast<unsigned int>(_vtk_grid->GetNumberOfPoints()); ++i) 00353 { 00354 // add to the id map 00355 // and add the actual point 00356 double * pnt = _vtk_grid->GetPoint(static_cast<vtkIdType>(i)); 00357 Point xyz(pnt[0],pnt[1],pnt[2]); 00358 Node* newnode = mesh.add_point(xyz,i); 00359 00360 // Add node to the nodes vector & 00361 // tell the MeshData object the foreign node id. 00362 if (this->_mesh_data != NULL) 00363 this->_mesh_data->add_foreign_node_id (newnode, i); 00364 } 00365 00366 for (unsigned int i=0; i < static_cast<unsigned int>(_vtk_grid->GetNumberOfCells()); ++i) 00367 { 00368 vtkCell* cell = _vtk_grid->GetCell(i); 00369 Elem* elem = NULL; // Initialize to avoid compiler warning 00370 switch(cell->GetCellType()) 00371 { 00372 // FIXME - we're not supporting 2D VTK input yet!? [RHS] 00373 case VTK_TETRA: 00374 elem = new Tet4(); 00375 break; 00376 case VTK_WEDGE: 00377 elem = new Prism6(); 00378 break; 00379 case VTK_HEXAHEDRON: 00380 elem = new Hex8(); 00381 break; 00382 case VTK_PYRAMID: 00383 elem = new Pyramid5(); 00384 break; 00385 case VTK_QUADRATIC_HEXAHEDRON: 00386 elem = new Hex20(); 00387 break; 00388 case VTK_QUADRATIC_TETRA: 00389 elem = new Tet10(); 00390 break; 00391 default: 00392 libMesh::err << "element type not implemented in vtkinterface " << cell->GetCellType() << std::endl; 00393 libmesh_error(); 00394 break; 00395 } 00396 00397 // get the straightforward numbering from the VTK cells 00398 for(unsigned int j=0;j<elem->n_nodes();++j){ 00399 elem->set_node(j) = mesh.node_ptr(cell->GetPointId(j)); 00400 } 00401 // then get the connectivity 00402 std::vector<dof_id_type> conn; 00403 elem->connectivity(0,VTK,conn); 00404 // then reshuffle the nodes according to the connectivity, this 00405 // two-time-assign would evade the definition of the vtk_mapping 00406 for(unsigned int j=0;j<conn.size();++j){ 00407 elem->set_node(j) = mesh.node_ptr(conn[j]); 00408 } 00409 elem->set_id(i); 00410 00411 elems_of_dimension[elem->dim()] = true; 00412 00413 mesh.add_elem(elem); 00414 } // end loop over VTK cells 00415 _vtk_grid->Delete(); 00416 00417 // Set the mesh dimension to the largest encountered for an element 00418 for (unsigned int i=0; i!=4; ++i) 00419 if (elems_of_dimension[i]) 00420 mesh.set_mesh_dimension(i); 00421 00422 #if LIBMESH_DIM < 3 00423 if (mesh.mesh_dimension() > LIBMESH_DIM) 00424 { 00425 libMesh::err << "Cannot open dimension " << 00426 mesh.mesh_dimension() << 00427 " mesh file when configured without " << 00428 mesh.mesh_dimension() << "D support." << 00429 std::endl; 00430 libmesh_error(); 00431 } 00432 #endif 00433 00434 #endif // LIBMESH_HAVE_VTK 00435 } 00436 00437 00438 void VTKIO::write_nodal_data (const std::string& fname, 00439 #ifdef LIBMESH_HAVE_VTK 00440 const std::vector<Number>& soln, 00441 const std::vector<std::string>& names 00442 #else 00443 const std::vector<Number>&, 00444 const std::vector<std::string>& 00445 #endif 00446 ) 00447 { 00448 #ifndef LIBMESH_HAVE_VTK 00449 00450 libMesh::err << "Cannot write VTK file: " << fname 00451 << "\nYou must have VTK installed and correctly configured to read VTK meshes." 00452 << std::endl; 00453 libmesh_error(); 00454 00455 #else 00456 00457 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00458 00459 // check if the filename extension is pvtu 00460 libmesh_assert(fname.substr(fname.rfind("."),fname.size())==".pvtu"); 00461 00462 // we only use Unstructured grids 00463 _vtk_grid = vtkUnstructuredGrid::New(); 00464 vtkSmartPointer<vtkXMLPUnstructuredGridWriter> writer = vtkXMLPUnstructuredGridWriter::New(); 00465 00466 // add nodes to the grid and update _local_node_map 00467 _local_node_map.clear(); 00468 this->nodes_to_vtk(); 00469 00470 // add cells to the grid 00471 this->cells_to_vtk(); 00472 00473 // add nodal solutions to the grid, if solutions are given 00474 if (names.size() > 0) 00475 { 00476 std::size_t num_vars = names.size(); 00477 dof_id_type num_nodes = mesh.n_nodes(); 00478 00479 for (std::size_t variable = 0; variable < num_vars; ++variable) 00480 { 00481 vtkSmartPointer<vtkDoubleArray> data = vtkDoubleArray::New(); 00482 data->SetName(names[variable].c_str()); 00483 00484 // number of local and ghost nodes 00485 data->SetNumberOfValues(_local_node_map.size()); 00486 00487 // loop over all nodes and get the solution for the current 00488 // variable, if the node is in the current partition 00489 for (dof_id_type k = 0; k < num_nodes; ++k) 00490 { 00491 if (_local_node_map.find(k) == _local_node_map.end()) 00492 continue; // not a local node 00493 00494 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00495 libmesh_do_once (libMesh::err << "Only writing the real part for complex numbers!\n" 00496 << "if you need this support contact " << LIBMESH_PACKAGE_BUGREPORT 00497 << std::endl); 00498 data->SetValue(_local_node_map[k], soln[k*num_vars + variable].real()); 00499 #else 00500 data->SetValue(_local_node_map[k], soln[k*num_vars + variable]); 00501 #endif 00502 } 00503 _vtk_grid->GetPointData()->AddArray(data); 00504 data->Delete(); 00505 } 00506 } 00507 00508 // Tell the writer how many partitions exist and on which processor 00509 // we are currently 00510 writer->SetNumberOfPieces(libMesh::n_processors()); 00511 writer->SetStartPiece(libMesh::processor_id()); 00512 writer->SetEndPiece(libMesh::processor_id()); 00513 00514 // partitions overlap by one node 00515 // FIXME: According to this document 00516 // http://paraview.org/Wiki/images/5/51/SC07_tut107_ParaView_Handouts.pdf 00517 // the ghosts are cells rather than nodes. 00518 writer->SetGhostLevel(1); 00519 00520 writer->SetInput(_vtk_grid); 00521 writer->SetFileName(fname.c_str()); 00522 writer->SetDataModeToAscii(); 00523 00524 // compress the output, if desired (switches also to binary) 00525 if (this->_compress) 00526 { 00527 #if !VTK_VERSION_LESS_THAN(5,6,0) 00528 writer->SetCompressorTypeToZLib(); 00529 #else 00530 libmesh_do_once(libMesh::err << "Compression not implemented with old VTK libs!" << std::endl;); 00531 #endif 00532 } 00533 00534 writer->Write(); 00535 00536 _vtk_grid->Delete(); 00537 writer->Delete(); 00538 #endif 00539 } 00540 00544 void VTKIO::write (const std::string& name) { 00545 std::vector<Number> soln; 00546 std::vector<std::string> names; 00547 this->write_nodal_data(name, soln, names); 00548 } 00549 00550 } // namespace libMesh 00551 00552 // vim: sw=3 ts=3
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:49 UTC
Hosted By: