$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 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 // Changes: 00019 // o no more subelements, all elements are written down to GMV directly 00020 // o Some nodes have to be left out, eg node 8 in QUAD9 00021 // o 00022 00023 00024 // C++ includes 00025 #include <iomanip> 00026 #include <fstream> 00027 #include <cstring> // for std::strcpy, std::memcpy 00028 #include <cstdio> // for std::sprintf 00029 #include <vector> 00030 00031 // Local includes 00032 #include "libmesh/libmesh_config.h" 00033 #include "libmesh/libmesh_logging.h" 00034 #include "libmesh/gmv_io.h" 00035 #include "libmesh/mesh_base.h" 00036 #include "libmesh/elem.h" 00037 #include "libmesh/equation_systems.h" 00038 #include "libmesh/numeric_vector.h" 00039 #include "libmesh/string_to_enum.h" 00040 00041 // Wrap everything in a GMVLib namespace and 00042 // use extern "C" to avoid name mangling. 00043 #ifdef LIBMESH_HAVE_GMV 00044 namespace GMVLib 00045 { 00046 extern "C" 00047 { 00048 #include "gmvread.h" 00049 } 00050 } 00051 #endif 00052 00053 // anonymous namespace to hold local data 00054 namespace 00055 { 00056 using namespace libMesh; 00057 00066 struct ElementDefinition { 00067 // GMV element name 00068 std::string label; 00069 00070 // Used to map libmesh nodes to GMV for writing 00071 std::vector<unsigned> node_map; 00072 }; 00073 00074 00075 // maps from a libMesh element type to the proper GMV 00076 // ElementDefinition. Placing the data structure here in this 00077 // anonymous namespace gives us the benefits of a global variable 00078 // without the nasty side-effects. 00079 std::map<ElemType, ElementDefinition> eletypes; 00080 00081 // Helper function to fill up eletypes map 00082 void add_eletype_entry(ElemType libmesh_elem_type, 00083 const unsigned* node_map, 00084 const std::string& gmv_label, 00085 unsigned nodes_size ) 00086 { 00087 // If map entry does not exist, this will create it 00088 ElementDefinition& map_entry = eletypes[libmesh_elem_type]; 00089 00090 // Set the label 00091 map_entry.label = gmv_label; 00092 00093 // Use the "swap trick" from Scott Meyer's "Effective STL" to swap 00094 // an unnamed temporary vector into the map_entry's vector. Note: 00095 // the vector(iter, iter) constructor is used. 00096 std::vector<unsigned int>(node_map, 00097 node_map+nodes_size).swap(map_entry.node_map); 00098 } 00099 00100 00101 // ------------------------------------------------------------ 00102 // helper function to initialize the eletypes map 00103 void init_eletypes () 00104 { 00105 if (eletypes.empty()) 00106 { 00107 // This should happen only once. The first time this method 00108 // is called the eletypes data struture will be empty, and 00109 // we will fill it. Any subsequent calls will find an initialized 00110 // eletypes map and will do nothing. 00111 00112 // EDGE2 00113 { 00114 const unsigned int node_map[] = {0,1}; 00115 add_eletype_entry(EDGE2, node_map, "line 2", 2); 00116 } 00117 00118 // LINE3 00119 { 00120 const unsigned int node_map[] = {0,1,2}; 00121 add_eletype_entry(EDGE3, node_map, "3line 3", 3); 00122 } 00123 00124 // TRI3 00125 { 00126 const unsigned int node_map[] = {0,1,2}; 00127 add_eletype_entry(TRI3, node_map, "tri3 3", 3); 00128 } 00129 00130 // TRI6 00131 { 00132 const unsigned int node_map[] = {0,1,2,3,4,5}; 00133 add_eletype_entry(TRI6, node_map, "6tri 6", 6); 00134 } 00135 00136 // QUAD4 00137 { 00138 const unsigned int node_map[] = {0,1,2,3}; 00139 add_eletype_entry(QUAD4, node_map, "quad 4", 4); 00140 } 00141 00142 // QUAD8, QUAD9 00143 { 00144 const unsigned int node_map[] = {0,1,2,3,4,5,6,7}; 00145 add_eletype_entry(QUAD8, node_map, "8quad 8", 8); 00146 00147 // QUAD9 was not supported by GMV but it gets the same entry, even the label (is that correct?) 00148 eletypes[QUAD9] = eletypes[QUAD8]; 00149 } 00150 00151 // HEX8 00152 { 00153 const unsigned int node_map[] = {0,1,2,3,4,5,6,7}; 00154 add_eletype_entry(HEX8, node_map, "phex8 8", 8); 00155 } 00156 00157 // HEX20, HEX27 00158 { 00159 // Note: This map is its own inverse 00160 const unsigned int node_map[] = {0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19,12,13,14,15}; 00161 add_eletype_entry(HEX20, node_map, "phex20 20", 20); 00162 00163 // HEX27 was not supported by GMV but it gets the same entry, even the label (is that correct?) 00164 eletypes[HEX27] = eletypes[HEX20]; 00165 } 00166 00167 // TET4 00168 { 00169 // This is correct, see write_ascii_old_impl() to confirm. 00170 // This map is also its own inverse. 00171 const unsigned node_map[] = {0,2,1,3}; 00172 add_eletype_entry(TET4, node_map, "tet 4", 4); 00173 } 00174 00175 // TET10 00176 { 00177 const unsigned int node_map[] = {0,1,2,3,4,5,6,7,8,9}; 00178 add_eletype_entry(TET10, node_map, "ptet10 10", 10); 00179 } 00180 00181 // PRISM6 00182 { 00183 const unsigned int node_map[] = {0,1,2,3,4,5}; 00184 add_eletype_entry(PRISM6, node_map, "pprism6 6", 6); 00185 } 00186 00187 // PRISM15, PRISM18 00188 { 00189 // Note: This map is its own inverse 00190 const unsigned int node_map[] = {0,1,2,3,4,5,6,7,8,12,13,14, 9,10,11}; 00191 add_eletype_entry(PRISM15, node_map, "pprism15 15", 15); 00192 00193 // PRISM18 was not supported by GMV but it gets the same entry, even the label (is that correct?) 00194 eletypes[PRISM18] = eletypes[PRISM15]; 00195 } 00196 //============================== 00197 } 00198 } 00199 00200 } // end anonymous namespace 00201 00202 00203 namespace libMesh 00204 { 00205 00206 // ------------------------------------------------------------ 00207 // GMVIO members 00208 void GMVIO::write (const std::string& fname) 00209 { 00210 if (this->binary()) 00211 this->write_binary (fname); 00212 else 00213 this->write_ascii_old_impl (fname); 00214 } 00215 00216 00217 00218 void GMVIO::write_nodal_data (const std::string& fname, 00219 const std::vector<Number>& soln, 00220 const std::vector<std::string>& names) 00221 { 00222 START_LOG("write_nodal_data()", "GMVIO"); 00223 00224 if (this->binary()) 00225 this->write_binary (fname, &soln, &names); 00226 else 00227 this->write_ascii_old_impl (fname, &soln, &names); 00228 00229 STOP_LOG("write_nodal_data()", "GMVIO"); 00230 } 00231 00232 00233 00234 void GMVIO::write_ascii_new_impl (const std::string& fname, 00235 const std::vector<Number>* v, 00236 const std::vector<std::string>* solution_names) 00237 { 00238 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00239 00240 libMesh::err << "WARNING: GMVIO::write_ascii_new_impl() not infinite-element aware!" 00241 << std::endl; 00242 libmesh_here(); 00243 00244 // Set it to our current precision 00245 this->write_ascii_old_impl (fname, v, solution_names); 00246 00247 #else 00248 00249 // Get a reference to the mesh 00250 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 00251 00252 // This is a parallel_only function 00253 const unsigned int n_active_elem = mesh.n_active_elem(); 00254 00255 if (MeshOutput<MeshBase>::mesh().processor_id() != 0) 00256 return; 00257 00258 // Open the output file stream 00259 std::ofstream out_stream (fname.c_str()); 00260 00261 out_stream << std::setprecision(this->ascii_precision()); 00262 00263 // Make sure it opened correctly 00264 if (!out_stream.good()) 00265 libmesh_file_error(fname.c_str()); 00266 00267 unsigned int mesh_max_p_level = 0; 00268 00269 // Begin interfacing with the GMV data file 00270 { 00271 out_stream << "gmvinput ascii\n\n"; 00272 00273 // write the nodes 00274 out_stream << "nodes " << mesh.n_nodes() << "\n"; 00275 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00276 out_stream << mesh.point(n)(0) << " "; 00277 out_stream << "\n"; 00278 00279 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00280 #if LIBMESH_DIM > 1 00281 out_stream << mesh.point(n)(1) << " "; 00282 #else 00283 out_stream << 0. << " "; 00284 #endif 00285 out_stream << "\n"; 00286 00287 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00288 #if LIBMESH_DIM > 2 00289 out_stream << mesh.point(n)(2) << " "; 00290 #else 00291 out_stream << 0. << " "; 00292 #endif 00293 out_stream << "\n\n"; 00294 } 00295 00296 { 00297 // write the connectivity 00298 out_stream << "cells " << n_active_elem << "\n"; 00299 00300 // initialize the eletypes map (eletypes is a file-global variable) 00301 init_eletypes(); 00302 00303 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00304 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00305 00306 for ( ; it != end; ++it) 00307 { 00308 const Elem* elem = *it; 00309 00310 mesh_max_p_level = std::max(mesh_max_p_level, 00311 elem->p_level()); 00312 00313 // Make sure we have a valid entry for 00314 // the current element type. 00315 libmesh_assert (eletypes.count(elem->type())); 00316 00317 const ElementDefinition& ele = eletypes[elem->type()]; 00318 00319 // The element mapper better not require any more nodes 00320 // than are present in the current element! 00321 libmesh_assert_less_equal (ele.node_map.size(), elem->n_nodes()); 00322 00323 out_stream << ele.label << "\n"; 00324 for (unsigned int i=0; i < ele.node_map.size(); i++) 00325 out_stream << elem->node(ele.node_map[i])+1 << " "; 00326 out_stream << "\n"; 00327 } 00328 out_stream << "\n"; 00329 } 00330 00331 // optionally write the partition information 00332 if (this->partitioning()) 00333 { 00334 if (this->write_subdomain_id_as_material()) 00335 libmesh_error_msg("Not yet supported in GMVIO::write_ascii_new_impl"); 00336 00337 else // write processor IDs as materials. This is the default 00338 { 00339 out_stream << "material " 00340 << mesh.n_partitions() 00341 // Note: GMV may give you errors like 00342 // Error, material for cell 1 is greater than 1 00343 // Error, material for cell 2 is greater than 1 00344 // Error, material for cell 3 is greater than 1 00345 // ... because you put the wrong number of partitions here. 00346 // To ensure you write the correct number of materials, call 00347 // mesh.recalculate_n_partitions() before writing out the 00348 // mesh. 00349 // Note: we can't call it now because the Mesh is const here and 00350 // it is a non-const function. 00351 << " 0\n"; 00352 00353 for (unsigned int proc=0; proc<mesh.n_partitions(); proc++) 00354 out_stream << "proc_" << proc << "\n"; 00355 00356 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00357 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00358 00359 // FIXME - don't we need to use an ElementDefinition here? - RHS 00360 for ( ; it != end; ++it) 00361 out_stream << (*it)->processor_id()+1 << "\n"; 00362 out_stream << "\n"; 00363 } 00364 } 00365 00366 // If there are *any* variables at all in the system (including 00367 // p level, or arbitrary cell-based data) 00368 // to write, the gmv file needs to contain the word "variable" 00369 // on a line by itself. 00370 bool write_variable = false; 00371 00372 // 1.) p-levels 00373 if (this->p_levels() && mesh_max_p_level) 00374 write_variable = true; 00375 00376 // 2.) solution data 00377 if ((solution_names != NULL) && (v != NULL)) 00378 write_variable = true; 00379 00380 // 3.) cell-centered data 00381 if ( !(this->_cell_centered_data.empty()) ) 00382 write_variable = true; 00383 00384 if (write_variable) 00385 out_stream << "variable\n"; 00386 00387 // if ((this->p_levels() && mesh_max_p_level) || 00388 // ((solution_names != NULL) && (v != NULL))) 00389 // out_stream << "variable\n"; 00390 00391 // optionally write the polynomial degree information 00392 if (this->p_levels() && mesh_max_p_level) 00393 { 00394 out_stream << "p_level 0\n"; 00395 00396 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00397 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00398 00399 for ( ; it != end; ++it) 00400 { 00401 const Elem* elem = *it; 00402 00403 const ElementDefinition& ele = eletypes[elem->type()]; 00404 00405 // The element mapper better not require any more nodes 00406 // than are present in the current element! 00407 libmesh_assert_less_equal (ele.node_map.size(), elem->n_nodes()); 00408 00409 for (unsigned int i=0; i < ele.node_map.size(); i++) 00410 out_stream << elem->p_level() << " "; 00411 } 00412 out_stream << "\n\n"; 00413 } 00414 00415 00416 // optionally write cell-centered data 00417 if ( !(this->_cell_centered_data.empty()) ) 00418 { 00419 std::map<std::string, const std::vector<Real>* >::iterator it = this->_cell_centered_data.begin(); 00420 const std::map<std::string, const std::vector<Real>* >::iterator end = this->_cell_centered_data.end(); 00421 00422 for (; it != end; ++it) 00423 { 00424 // write out the variable name, followed by a zero. 00425 out_stream << (*it).first << " 0\n"; 00426 00427 const std::vector<Real>* the_array = (*it).second; 00428 00429 // Loop over active elements, write out cell data. If second-order cells 00430 // are split into sub-elements, the sub-elements inherit their parent's 00431 // cell-centered data. 00432 MeshBase::const_element_iterator elem_it = mesh.active_elements_begin(); 00433 const MeshBase::const_element_iterator elem_end = mesh.active_elements_end(); 00434 00435 for (; elem_it != elem_end; ++elem_it) 00436 { 00437 const Elem* e = *elem_it; 00438 00439 // Use the element's ID to find the value. 00440 libmesh_assert_less (e->id(), the_array->size()); 00441 const Real the_value = the_array->operator[](e->id()); 00442 00443 if (this->subdivide_second_order()) 00444 for (unsigned int se=0; se < e->n_sub_elem(); se++) 00445 out_stream << the_value << " "; 00446 else 00447 out_stream << the_value << " "; 00448 } 00449 00450 out_stream << "\n\n"; 00451 } 00452 } 00453 00454 00455 // optionally write the data 00456 if ((solution_names != NULL) && (v != NULL)) 00457 { 00458 const unsigned int n_vars = solution_names->size(); 00459 00460 if (!(v->size() == mesh.n_nodes()*n_vars)) 00461 libMesh::err << "ERROR: v->size()=" << v->size() 00462 << ", mesh.n_nodes()=" << mesh.n_nodes() 00463 << ", n_vars=" << n_vars 00464 << ", mesh.n_nodes()*n_vars=" << mesh.n_nodes()*n_vars 00465 << "\n"; 00466 00467 libmesh_assert_equal_to (v->size(), mesh.n_nodes()*n_vars); 00468 00469 for (unsigned int c=0; c<n_vars; c++) 00470 { 00471 00472 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00473 00474 // in case of complex data, write _three_ data sets 00475 // for each component 00476 00477 // this is the real part 00478 out_stream << "r_" << (*solution_names)[c] << " 1\n"; 00479 00480 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00481 out_stream << (*v)[n*n_vars + c].real() << " "; 00482 00483 out_stream << "\n\n"; 00484 00485 // this is the imaginary part 00486 out_stream << "i_" << (*solution_names)[c] << " 1\n"; 00487 00488 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00489 out_stream << (*v)[n*n_vars + c].imag() << " "; 00490 00491 out_stream << "\n\n"; 00492 00493 // this is the magnitude 00494 out_stream << "a_" << (*solution_names)[c] << " 1\n"; 00495 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00496 out_stream << std::abs((*v)[n*n_vars + c]) << " "; 00497 00498 out_stream << "\n\n"; 00499 00500 #else 00501 00502 out_stream << (*solution_names)[c] << " 1\n"; 00503 00504 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00505 out_stream << (*v)[n*n_vars + c] << " "; 00506 00507 out_stream << "\n\n"; 00508 00509 #endif 00510 } 00511 00512 } 00513 00514 // If we wrote any variables, we have to close the variable section now 00515 if (write_variable) 00516 out_stream << "endvars\n"; 00517 00518 00519 // end of the file 00520 out_stream << "\nendgmv\n"; 00521 00522 #endif 00523 } 00524 00525 00526 00527 00528 00529 00530 void GMVIO::write_ascii_old_impl (const std::string& fname, 00531 const std::vector<Number>* v, 00532 const std::vector<std::string>* solution_names) 00533 { 00534 // Get a reference to the mesh 00535 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 00536 00537 // Use a MeshSerializer object to gather a parallel mesh before outputting it. 00538 // Note that we cast away constness here (which is bad), but the destructor of 00539 // the MeshSerializer object reparallelizes the Mesh, hopefully keeping it 00540 // "logically const" outside the context of this function... 00541 MeshSerializer serialize(const_cast<MeshBase&>(mesh), 00542 !MeshOutput<MeshBase>::_is_parallel_format); 00543 00544 // These are parallel_only functions 00545 const dof_id_type n_active_elem = mesh.n_active_elem(), 00546 n_active_sub_elem = mesh.n_active_sub_elem(); 00547 00548 if (MeshOutput<MeshBase>::mesh().processor_id() != 0) 00549 return; 00550 00551 // Open the output file stream 00552 std::ofstream out_stream (fname.c_str()); 00553 00554 // Set it to our current precision 00555 out_stream << std::setprecision(this->ascii_precision()); 00556 00557 // Make sure it opened correctly 00558 if (!out_stream.good()) 00559 libmesh_file_error(fname.c_str()); 00560 00561 // Make sure our nodes are contiguous and serialized 00562 libmesh_assert_equal_to (mesh.n_nodes(), mesh.max_node_id()); 00563 00564 // libmesh_assert (mesh.is_serial()); 00565 // if (!mesh.is_serial()) 00566 // { 00567 // if (MeshOutput<MeshBase>::mesh().processor_id() == 0) 00568 // libMesh::err << "Error: GMVIO cannot yet write a ParallelMesh solution" 00569 // << std::endl; 00570 // return; 00571 // } 00572 00573 unsigned int mesh_max_p_level = 0; 00574 00575 // Begin interfacing with the GMV data file 00576 00577 // FIXME - if subdivide_second_order() is off, 00578 // we probably should only be writing the 00579 // vertex nodes - RHS 00580 { 00581 // write the nodes 00582 00583 out_stream << "gmvinput ascii\n\n"; 00584 out_stream << "nodes " << mesh.n_nodes() << '\n'; 00585 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00586 out_stream << mesh.point(n)(0) << " "; 00587 00588 out_stream << '\n'; 00589 00590 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00591 #if LIBMESH_DIM > 1 00592 out_stream << mesh.point(n)(1) << " "; 00593 #else 00594 out_stream << 0. << " "; 00595 #endif 00596 00597 out_stream << '\n'; 00598 00599 for (unsigned int n=0; n<mesh.n_nodes(); n++) 00600 #if LIBMESH_DIM > 2 00601 out_stream << mesh.point(n)(2) << " "; 00602 #else 00603 out_stream << 0. << " "; 00604 #endif 00605 00606 out_stream << '\n' << '\n'; 00607 } 00608 00609 00610 00611 { 00612 // write the connectivity 00613 00614 out_stream << "cells "; 00615 if (this->subdivide_second_order()) 00616 out_stream << n_active_sub_elem; 00617 else 00618 out_stream << n_active_elem; 00619 out_stream << '\n'; 00620 00621 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00622 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00623 00624 switch (mesh.mesh_dimension()) 00625 { 00626 case 1: 00627 { 00628 // The same temporary storage will be used for each element 00629 std::vector<dof_id_type> conn; 00630 00631 for ( ; it != end; ++it) 00632 { 00633 mesh_max_p_level = std::max(mesh_max_p_level, 00634 (*it)->p_level()); 00635 00636 if (this->subdivide_second_order()) 00637 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 00638 { 00639 out_stream << "line 2\n"; 00640 (*it)->connectivity(se, TECPLOT, conn); 00641 for (unsigned int i=0; i<conn.size(); i++) 00642 out_stream << conn[i] << " "; 00643 00644 out_stream << '\n'; 00645 } 00646 else 00647 { 00648 out_stream << "line 2\n"; 00649 if ((*it)->default_order() == FIRST) 00650 (*it)->connectivity(0, TECPLOT, conn); 00651 else 00652 { 00653 UniquePtr<Elem> lo_elem = Elem::build(Elem::first_order_equivalent_type((*it)->type())); 00654 for (unsigned int i = 0; i != lo_elem->n_nodes(); ++i) 00655 lo_elem->set_node(i) = (*it)->get_node(i); 00656 lo_elem->connectivity(0, TECPLOT, conn); 00657 } 00658 for (unsigned int i=0; i<conn.size(); i++) 00659 out_stream << conn[i] << " "; 00660 00661 out_stream << '\n'; 00662 } 00663 } 00664 break; 00665 } 00666 00667 case 2: 00668 { 00669 // The same temporary storage will be used for each element 00670 std::vector<dof_id_type> conn; 00671 00672 for ( ; it != end; ++it) 00673 { 00674 mesh_max_p_level = std::max(mesh_max_p_level, 00675 (*it)->p_level()); 00676 00677 if (this->subdivide_second_order()) 00678 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 00679 { 00680 // Quad elements 00681 if (((*it)->type() == QUAD4) || 00682 ((*it)->type() == QUAD8) || // Note: QUAD8 will be output as one central quad and 00683 // four surrounding triangles (though they will be written 00684 // to GMV as QUAD4s). 00685 ((*it)->type() == QUAD9) 00686 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00687 || ((*it)->type() == INFQUAD4) 00688 || ((*it)->type() == INFQUAD6) 00689 #endif 00690 ) 00691 { 00692 out_stream << "quad 4\n"; 00693 (*it)->connectivity(se, TECPLOT, conn); 00694 for (unsigned int i=0; i<conn.size(); i++) 00695 out_stream << conn[i] << " "; 00696 } 00697 00698 // Triangle elements 00699 else if (((*it)->type() == TRI3) || 00700 ((*it)->type() == TRI6)) 00701 { 00702 out_stream << "tri 3\n"; 00703 (*it)->connectivity(se, TECPLOT, conn); 00704 for (unsigned int i=0; i<3; i++) 00705 out_stream << conn[i] << " "; 00706 } 00707 else 00708 libmesh_error_msg("Unsupported element type: " << Utility::enum_to_string((*it)->type())); 00709 } 00710 else // !this->subdivide_second_order() 00711 { 00712 // Quad elements 00713 if (((*it)->type() == QUAD4) 00714 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00715 || ((*it)->type() == INFQUAD4) 00716 #endif 00717 ) 00718 { 00719 (*it)->connectivity(0, TECPLOT, conn); 00720 out_stream << "quad 4\n"; 00721 for (unsigned int i=0; i<conn.size(); i++) 00722 out_stream << conn[i] << " "; 00723 } 00724 else if (((*it)->type() == QUAD8) || 00725 ((*it)->type() == QUAD9) 00726 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00727 || ((*it)->type() == INFQUAD6) 00728 #endif 00729 ) 00730 { 00731 UniquePtr<Elem> lo_elem = Elem::build(Elem::first_order_equivalent_type((*it)->type())); 00732 for (unsigned int i = 0; i != lo_elem->n_nodes(); ++i) 00733 lo_elem->set_node(i) = (*it)->get_node(i); 00734 lo_elem->connectivity(0, TECPLOT, conn); 00735 out_stream << "quad 4\n"; 00736 for (unsigned int i=0; i<conn.size(); i++) 00737 out_stream << conn[i] << " "; 00738 } 00739 else if ((*it)->type() == TRI3) 00740 { 00741 (*it)->connectivity(0, TECPLOT, conn); 00742 out_stream << "tri 3\n"; 00743 for (unsigned int i=0; i<3; i++) 00744 out_stream << conn[i] << " "; 00745 } 00746 else if ((*it)->type() == TRI6) 00747 { 00748 UniquePtr<Elem> lo_elem = Elem::build(Elem::first_order_equivalent_type((*it)->type())); 00749 for (unsigned int i = 0; i != lo_elem->n_nodes(); ++i) 00750 lo_elem->set_node(i) = (*it)->get_node(i); 00751 lo_elem->connectivity(0, TECPLOT, conn); 00752 out_stream << "tri 3\n"; 00753 for (unsigned int i=0; i<3; i++) 00754 out_stream << conn[i] << " "; 00755 } 00756 00757 out_stream << '\n'; 00758 } 00759 } 00760 00761 break; 00762 } 00763 00764 00765 case 3: 00766 { 00767 // The same temporary storage will be used for each element 00768 std::vector<dof_id_type> conn; 00769 00770 for ( ; it != end; ++it) 00771 { 00772 mesh_max_p_level = std::max(mesh_max_p_level, 00773 (*it)->p_level()); 00774 00775 if (this->subdivide_second_order()) 00776 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 00777 { 00778 00779 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS 00780 if (((*it)->type() == HEX8) || 00781 ((*it)->type() == HEX27)) 00782 { 00783 out_stream << "phex8 8\n"; 00784 (*it)->connectivity(se, TECPLOT, conn); 00785 for (unsigned int i=0; i<conn.size(); i++) 00786 out_stream << conn[i] << " "; 00787 } 00788 00789 else if ((*it)->type() == HEX20) 00790 { 00791 out_stream << "phex20 20\n"; 00792 out_stream << (*it)->node(0)+1 << " " 00793 << (*it)->node(1)+1 << " " 00794 << (*it)->node(2)+1 << " " 00795 << (*it)->node(3)+1 << " " 00796 << (*it)->node(4)+1 << " " 00797 << (*it)->node(5)+1 << " " 00798 << (*it)->node(6)+1 << " " 00799 << (*it)->node(7)+1 << " " 00800 << (*it)->node(8)+1 << " " 00801 << (*it)->node(9)+1 << " " 00802 << (*it)->node(10)+1 << " " 00803 << (*it)->node(11)+1 << " " 00804 << (*it)->node(16)+1 << " " 00805 << (*it)->node(17)+1 << " " 00806 << (*it)->node(18)+1 << " " 00807 << (*it)->node(19)+1 << " " 00808 << (*it)->node(12)+1 << " " 00809 << (*it)->node(13)+1 << " " 00810 << (*it)->node(14)+1 << " " 00811 << (*it)->node(15)+1 << " "; 00812 } 00813 #else 00814 /* 00815 * In case of infinite elements, HEX20 00816 * should be handled just like the 00817 * INFHEX16, since these connect to each other 00818 */ 00819 if (((*it)->type() == HEX8) || 00820 ((*it)->type() == HEX27) || 00821 ((*it)->type() == INFHEX8) || 00822 ((*it)->type() == INFHEX16) || 00823 ((*it)->type() == INFHEX18) || 00824 ((*it)->type() == HEX20)) 00825 { 00826 out_stream << "phex8 8\n"; 00827 (*it)->connectivity(se, TECPLOT, conn); 00828 for (unsigned int i=0; i<conn.size(); i++) 00829 out_stream << conn[i] << " "; 00830 } 00831 #endif 00832 00833 else if (((*it)->type() == TET4) || 00834 ((*it)->type() == TET10)) 00835 { 00836 out_stream << "tet 4\n"; 00837 // Tecplot connectivity returns 8 entries for 00838 // the Tet, enough to store it as a degenerate Hex. 00839 // For GMV we only pick out the four relevant node 00840 // indices. 00841 (*it)->connectivity(se, TECPLOT, conn); 00842 out_stream << conn[0] << " " // libmesh tet node 0 00843 << conn[2] << " " // libmesh tet node 2 00844 << conn[1] << " " // libmesh tet node 1 00845 << conn[4] << " "; // libmesh tet node 3 00846 } 00847 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS 00848 else if (((*it)->type() == PRISM6) || 00849 ((*it)->type() == PRISM15) || 00850 ((*it)->type() == PRISM18) || 00851 ((*it)->type() == PYRAMID5)) 00852 #else 00853 else if (((*it)->type() == PRISM6) || 00854 ((*it)->type() == PRISM15) || 00855 ((*it)->type() == PRISM18) || 00856 ((*it)->type() == PYRAMID5) || 00857 ((*it)->type() == INFPRISM6) || 00858 ((*it)->type() == INFPRISM12)) 00859 #endif 00860 { 00865 out_stream << "phex8 8\n"; 00866 (*it)->connectivity(se, TECPLOT, conn); 00867 for (unsigned int i=0; i<conn.size(); i++) 00868 out_stream << conn[i] << " "; 00869 } 00870 00871 else 00872 libmesh_error_msg("Encountered an unrecognized element " \ 00873 << "type: " << (*it)->type() \ 00874 << "\nPossibly a dim-1 dimensional " \ 00875 << "element? Aborting..."); 00876 00877 out_stream << '\n'; 00878 } 00879 else // !this->subdivide_second_order() 00880 { 00881 UniquePtr<Elem> lo_elem = Elem::build(Elem::first_order_equivalent_type((*it)->type())); 00882 for (unsigned int i = 0; i != lo_elem->n_nodes(); ++i) 00883 lo_elem->set_node(i) = (*it)->get_node(i); 00884 if ((lo_elem->type() == HEX8) 00885 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00886 || (lo_elem->type() == HEX27) 00887 #endif 00888 ) 00889 { 00890 out_stream << "phex8 8\n"; 00891 lo_elem->connectivity(0, TECPLOT, conn); 00892 for (unsigned int i=0; i<conn.size(); i++) 00893 out_stream << conn[i] << " "; 00894 } 00895 00896 else if (lo_elem->type() == TET4) 00897 { 00898 out_stream << "tet 4\n"; 00899 lo_elem->connectivity(0, TECPLOT, conn); 00900 out_stream << conn[0] << " " 00901 << conn[2] << " " 00902 << conn[1] << " " 00903 << conn[4] << " "; 00904 } 00905 else if ((lo_elem->type() == PRISM6) 00906 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00907 || (lo_elem->type() == INFPRISM6) 00908 #endif 00909 ) 00910 { 00915 out_stream << "phex8 8\n"; 00916 lo_elem->connectivity(0, TECPLOT, conn); 00917 for (unsigned int i=0; i<conn.size(); i++) 00918 out_stream << conn[i] << " "; 00919 } 00920 00921 else 00922 libmesh_error_msg("Encountered an unrecognized element " \ 00923 << "type. Possibly a dim-1 dimensional " \ 00924 << "element? Aborting..."); 00925 00926 out_stream << '\n'; 00927 } 00928 } 00929 00930 break; 00931 } 00932 00933 default: 00934 libmesh_error_msg("Unsupported mesh dimension: " << mesh.mesh_dimension()); 00935 } 00936 00937 out_stream << '\n'; 00938 } 00939 00940 00941 00942 // optionally write the partition information 00943 if (this->partitioning()) 00944 { 00945 if (this->write_subdomain_id_as_material()) 00946 { 00947 // Subdomain IDs can be non-contiguous and need not 00948 // necessarily start at 0. Furthermore, since the user is 00949 // free to define subdomain_id_type to be a signed type, we 00950 // can't even assume max(subdomain_id) >= # unique subdomain ids. 00951 00952 // We build a map<subdomain_id, unsigned> to associate to each 00953 // user-selected subdomain ID a unique, contiguous unsigned value 00954 // which we can write to file. 00955 std::map<subdomain_id_type, unsigned> sbdid_map; 00956 typedef std::map<subdomain_id_type, unsigned>::iterator sbdid_map_iter; 00957 { 00958 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00959 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00960 00961 for ( ; it != end; ++it) 00962 { 00963 // Try to insert with dummy value 00964 sbdid_map.insert( std::make_pair((*it)->subdomain_id(), 0) ); 00965 } 00966 } 00967 00968 // Map is created, iterate through it to set indices. They will be 00969 // used repeatedly below. 00970 { 00971 unsigned ctr=0; 00972 for (sbdid_map_iter it=sbdid_map.begin(); it != sbdid_map.end(); ++it) 00973 (*it).second = ctr++; 00974 } 00975 00976 out_stream << "material " 00977 << sbdid_map.size() 00978 << " 0\n"; 00979 00980 for (unsigned int sbdid=0; sbdid<sbdid_map.size(); sbdid++) 00981 out_stream << "proc_" << sbdid << "\n"; 00982 00983 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00984 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00985 00986 for ( ; it != end; ++it) 00987 { 00988 // Find the unique index for (*it)->subdomain_id(), print that to file 00989 sbdid_map_iter map_iter = sbdid_map.find( (*it)->subdomain_id() ); 00990 unsigned gmv_mat_number = (*map_iter).second; 00991 00992 if (this->subdivide_second_order()) 00993 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 00994 out_stream << gmv_mat_number+1 << '\n'; 00995 else 00996 out_stream << gmv_mat_number+1 << "\n"; 00997 } 00998 out_stream << '\n'; 00999 01000 } 01001 else // write processor IDs as materials. This is the default 01002 { 01003 out_stream << "material " 01004 << mesh.n_partitions() 01005 << " 0"<< '\n'; 01006 01007 for (unsigned int proc=0; proc<mesh.n_partitions(); proc++) 01008 out_stream << "proc_" << proc << '\n'; 01009 01010 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01011 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01012 01013 for ( ; it != end; ++it) 01014 if (this->subdivide_second_order()) 01015 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 01016 out_stream << (*it)->processor_id()+1 << '\n'; 01017 else 01018 out_stream << (*it)->processor_id()+1 << '\n'; 01019 01020 out_stream << '\n'; 01021 } 01022 } 01023 01024 01025 // If there are *any* variables at all in the system (including 01026 // p level, or arbitrary cell-based data) 01027 // to write, the gmv file needs to contain the word "variable" 01028 // on a line by itself. 01029 bool write_variable = false; 01030 01031 // 1.) p-levels 01032 if (this->p_levels() && mesh_max_p_level) 01033 write_variable = true; 01034 01035 // 2.) solution data 01036 if ((solution_names != NULL) && (v != NULL)) 01037 write_variable = true; 01038 01039 // 3.) cell-centered data 01040 if ( !(this->_cell_centered_data.empty()) ) 01041 write_variable = true; 01042 01043 if (write_variable) 01044 out_stream << "variable\n"; 01045 01046 01047 // optionally write the p-level information 01048 if (this->p_levels() && mesh_max_p_level) 01049 { 01050 out_stream << "p_level 0\n"; 01051 01052 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01053 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01054 01055 for ( ; it != end; ++it) 01056 if (this->subdivide_second_order()) 01057 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 01058 out_stream << (*it)->p_level() << " "; 01059 else 01060 out_stream << (*it)->p_level() << " "; 01061 out_stream << "\n\n"; 01062 } 01063 01064 01065 01066 01067 // optionally write cell-centered data 01068 if ( !(this->_cell_centered_data.empty()) ) 01069 { 01070 std::map<std::string, const std::vector<Real>* >::iterator it = this->_cell_centered_data.begin(); 01071 const std::map<std::string, const std::vector<Real>* >::iterator end = this->_cell_centered_data.end(); 01072 01073 for (; it != end; ++it) 01074 { 01075 // write out the variable name, followed by a zero. 01076 out_stream << (*it).first << " 0\n"; 01077 01078 const std::vector<Real>* the_array = (*it).second; 01079 01080 // Loop over active elements, write out cell data. If second-order cells 01081 // are split into sub-elements, the sub-elements inherit their parent's 01082 // cell-centered data. 01083 MeshBase::const_element_iterator elem_it = mesh.active_elements_begin(); 01084 const MeshBase::const_element_iterator elem_end = mesh.active_elements_end(); 01085 01086 for (; elem_it != elem_end; ++elem_it) 01087 { 01088 const Elem* e = *elem_it; 01089 01090 // Use the element's ID to find the value... 01091 libmesh_assert_less (e->id(), the_array->size()); 01092 const Real the_value = the_array->operator[](e->id()); 01093 01094 if (this->subdivide_second_order()) 01095 for (unsigned int se=0; se < e->n_sub_elem(); se++) 01096 out_stream << the_value << " "; 01097 else 01098 out_stream << the_value << " "; 01099 } 01100 01101 out_stream << "\n\n"; 01102 } 01103 } 01104 01105 01106 01107 01108 // optionally write the data 01109 if ((solution_names != NULL) && 01110 (v != NULL)) 01111 { 01112 const unsigned int n_vars = 01113 cast_int<unsigned int>(solution_names->size()); 01114 01115 if (!(v->size() == mesh.n_nodes()*n_vars)) 01116 libMesh::err << "ERROR: v->size()=" << v->size() 01117 << ", mesh.n_nodes()=" << mesh.n_nodes() 01118 << ", n_vars=" << n_vars 01119 << ", mesh.n_nodes()*n_vars=" << mesh.n_nodes()*n_vars 01120 << std::endl; 01121 01122 libmesh_assert_equal_to (v->size(), mesh.n_nodes()*n_vars); 01123 01124 for (unsigned int c=0; c<n_vars; c++) 01125 { 01126 01127 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 01128 01129 // in case of complex data, write _tree_ data sets 01130 // for each component 01131 01132 // this is the real part 01133 out_stream << "r_" << (*solution_names)[c] << " 1\n"; 01134 01135 for (unsigned int n=0; n<mesh.n_nodes(); n++) 01136 out_stream << (*v)[n*n_vars + c].real() << " "; 01137 01138 out_stream << '\n' << '\n'; 01139 01140 01141 // this is the imaginary part 01142 out_stream << "i_" << (*solution_names)[c] << " 1\n"; 01143 01144 for (unsigned int n=0; n<mesh.n_nodes(); n++) 01145 out_stream << (*v)[n*n_vars + c].imag() << " "; 01146 01147 out_stream << '\n' << '\n'; 01148 01149 // this is the magnitude 01150 out_stream << "a_" << (*solution_names)[c] << " 1\n"; 01151 for (unsigned int n=0; n<mesh.n_nodes(); n++) 01152 out_stream << std::abs((*v)[n*n_vars + c]) << " "; 01153 01154 out_stream << '\n' << '\n'; 01155 01156 #else 01157 01158 out_stream << (*solution_names)[c] << " 1\n"; 01159 01160 for (unsigned int n=0; n<mesh.n_nodes(); n++) 01161 out_stream << (*v)[n*n_vars + c] << " "; 01162 01163 out_stream << '\n' << '\n'; 01164 01165 #endif 01166 } 01167 01168 } 01169 01170 // If we wrote any variables, we have to close the variable section now 01171 if (write_variable) 01172 out_stream << "endvars\n"; 01173 01174 01175 // end of the file 01176 out_stream << "\nendgmv\n"; 01177 } 01178 01179 01180 01181 01182 01183 01184 01185 void GMVIO::write_binary (const std::string& fname, 01186 const std::vector<Number>* vec, 01187 const std::vector<std::string>* solution_names) 01188 { 01189 // Get a reference to the mesh 01190 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 01191 01192 // This is a parallel_only function 01193 const dof_id_type n_active_elem = mesh.n_active_elem(); 01194 01195 if (MeshOutput<MeshBase>::mesh().processor_id() != 0) 01196 return; 01197 01198 std::ofstream out_stream (fname.c_str()); 01199 01200 libmesh_assert (out_stream.good()); 01201 01202 unsigned int mesh_max_p_level = 0; 01203 01204 char buf[80]; 01205 01206 // Begin interfacing with the GMV data file 01207 { 01208 // write the nodes 01209 std::strcpy(buf, "gmvinput"); 01210 out_stream.write(buf, std::strlen(buf)); 01211 01212 std::strcpy(buf, "ieeei4r4"); 01213 out_stream.write(buf, std::strlen(buf)); 01214 } 01215 01216 01217 01218 // write the nodes 01219 { 01220 std::strcpy(buf, "nodes "); 01221 out_stream.write(buf, std::strlen(buf)); 01222 01223 unsigned int tempint = mesh.n_nodes(); 01224 01225 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01226 01227 out_stream.write(buf, sizeof(unsigned int)); 01228 01229 // write the x coordinate 01230 float *temp = new float[mesh.n_nodes()]; 01231 for (unsigned int v=0; v<mesh.n_nodes(); v++) 01232 temp[v] = static_cast<float>(mesh.point(v)(0)); 01233 out_stream.write(reinterpret_cast<char *>(temp), sizeof(float)*mesh.n_nodes()); 01234 01235 // write the y coordinate 01236 for (unsigned int v=0; v<mesh.n_nodes(); v++) 01237 #if LIBMESH_DIM > 1 01238 temp[v] = static_cast<float>(mesh.point(v)(1)); 01239 #else 01240 temp[v] = 0.; 01241 #endif 01242 out_stream.write(reinterpret_cast<char *>(temp), sizeof(float)*mesh.n_nodes()); 01243 01244 // write the z coordinate 01245 for (unsigned int v=0; v<mesh.n_nodes(); v++) 01246 #if LIBMESH_DIM > 2 01247 temp[v] = static_cast<float>(mesh.point(v)(2)); 01248 #else 01249 temp[v] = 0.; 01250 #endif 01251 out_stream.write(reinterpret_cast<char *>(temp), sizeof(float)*mesh.n_nodes()); 01252 01253 delete [] temp; 01254 } 01255 01256 01257 // write the connectivity 01258 { 01259 std::strcpy(buf, "cells "); 01260 out_stream.write(buf, std::strlen(buf)); 01261 01262 unsigned int tempint = n_active_elem; 01263 01264 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01265 01266 out_stream.write(buf, sizeof(unsigned int)); 01267 01268 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01269 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01270 01271 switch (mesh.mesh_dimension()) 01272 { 01273 01274 case 1: 01275 for ( ; it != end; ++it) 01276 { 01277 mesh_max_p_level = std::max(mesh_max_p_level, 01278 (*it)->p_level()); 01279 01280 for(unsigned se = 0; se < (*it)->n_sub_elem(); ++se) 01281 { 01282 std::strcpy(buf, "line "); 01283 out_stream.write(buf, std::strlen(buf)); 01284 01285 tempint = 2; 01286 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01287 out_stream.write(buf, sizeof(unsigned int)); 01288 01289 std::vector<dof_id_type> conn; 01290 (*it)->connectivity(se,TECPLOT,conn); 01291 01292 out_stream.write(reinterpret_cast<char*>(&conn[0]), sizeof(unsigned int)*tempint); 01293 } 01294 } 01295 break; 01296 01297 case 2: 01298 for ( ; it != end; ++it) 01299 { 01300 mesh_max_p_level = std::max(mesh_max_p_level, 01301 (*it)->p_level()); 01302 01303 for(unsigned se = 0; se < (*it)->n_sub_elem(); ++se) 01304 { 01305 std::strcpy(buf, "quad "); 01306 out_stream.write(buf, std::strlen(buf)); 01307 tempint = 4; 01308 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01309 out_stream.write(buf, sizeof(unsigned int)); 01310 std::vector<dof_id_type> conn; 01311 (*it)->connectivity(se,TECPLOT,conn); 01312 out_stream.write(reinterpret_cast<char*>(&conn[0]), sizeof(unsigned int)*tempint); 01313 } 01314 } 01315 break; 01316 case 3: 01317 for ( ; it != end; ++it) 01318 { 01319 mesh_max_p_level = std::max(mesh_max_p_level, 01320 (*it)->p_level()); 01321 01322 for(unsigned se = 0; se < (*it)->n_sub_elem(); ++se) 01323 { 01324 std::strcpy(buf, "phex8 "); 01325 out_stream.write(buf, std::strlen(buf)); 01326 tempint = 8; 01327 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01328 out_stream.write(buf, sizeof(unsigned int)); 01329 std::vector<dof_id_type> conn; 01330 (*it)->connectivity(se,TECPLOT,conn); 01331 out_stream.write(reinterpret_cast<char*>(&conn[0]), sizeof(unsigned int)*tempint); 01332 } 01333 } 01334 break; 01335 default: 01336 libmesh_error_msg("Unsupported mesh dimension: " << mesh.mesh_dimension()); 01337 01338 } 01339 } 01340 01341 01342 01343 // optionally write the partition information 01344 if (this->partitioning()) 01345 { 01346 if (this->write_subdomain_id_as_material()) 01347 libmesh_error_msg("Not yet supported in GMVIO::write_binary"); 01348 01349 else 01350 { 01351 std::strcpy(buf, "material"); 01352 out_stream.write(buf, std::strlen(buf)); 01353 01354 unsigned int tmpint = mesh.n_processors(); 01355 std::memcpy(buf, &tmpint, sizeof(unsigned int)); 01356 out_stream.write(buf, sizeof(unsigned int)); 01357 01358 tmpint = 0; // IDs are cell based 01359 std::memcpy(buf, &tmpint, sizeof(unsigned int)); 01360 out_stream.write(buf, sizeof(unsigned int)); 01361 01362 01363 for (unsigned int proc=0; proc<mesh.n_processors(); proc++) 01364 { 01365 std::sprintf(buf, "proc_%u", proc); 01366 out_stream.write(buf, 8); 01367 } 01368 01369 std::vector<unsigned int> proc_id (n_active_elem); 01370 01371 unsigned int n=0; 01372 01373 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01374 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01375 01376 for ( ; it != end; ++it) 01377 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 01378 proc_id[n++] = (*it)->processor_id()+1; 01379 01380 01381 out_stream.write(reinterpret_cast<char *>(&proc_id[0]), 01382 sizeof(unsigned int)*proc_id.size()); 01383 } 01384 } 01385 01386 // If there are *any* variables at all in the system (including 01387 // p level, or arbitrary cell-based data) 01388 // to write, the gmv file needs to contain the word "variable" 01389 // on a line by itself. 01390 bool write_variable = false; 01391 01392 // 1.) p-levels 01393 if (this->p_levels() && mesh_max_p_level) 01394 write_variable = true; 01395 01396 // 2.) solution data 01397 if ((solution_names != NULL) && (vec != NULL)) 01398 write_variable = true; 01399 01400 // // 3.) cell-centered data - unsupported 01401 // if ( !(this->_cell_centered_data.empty()) ) 01402 // write_variable = true; 01403 01404 if (write_variable) 01405 { 01406 std::strcpy(buf, "variable"); 01407 out_stream.write(buf, std::strlen(buf)); 01408 } 01409 01410 // optionally write the partition information 01411 if (this->p_levels() && mesh_max_p_level) 01412 { 01413 unsigned int n_floats = n_active_elem; 01414 for (unsigned int i=0; i != mesh.mesh_dimension(); ++i) 01415 n_floats *= 2; 01416 01417 float *temp = new float[n_floats]; 01418 01419 std::strcpy(buf, "p_level"); 01420 out_stream.write(buf, std::strlen(buf)); 01421 01422 unsigned int tempint = 0; // p levels are cell data 01423 01424 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01425 out_stream.write(buf, sizeof(unsigned int)); 01426 01427 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01428 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01429 unsigned int n=0; 01430 01431 for (; it != end; ++it) 01432 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 01433 temp[n++] = static_cast<float>( (*it)->p_level() ); 01434 01435 out_stream.write(reinterpret_cast<char *>(temp), 01436 sizeof(float)*n_floats); 01437 01438 delete [] temp; 01439 } 01440 01441 01442 // optionally write cell-centered data 01443 if ( !(this->_cell_centered_data.empty()) ) 01444 { 01445 libMesh::err << "Cell-centered data not (yet) supported in binary I/O mode!" << std::endl; 01446 01447 // std::map<std::string, const std::vector<Real>* >::iterator it = this->_cell_centered_data.begin(); 01448 // const std::map<std::string, const std::vector<Real>* >::iterator end = this->_cell_centered_data.end(); 01449 01450 // for (; it != end; ++it) 01451 // { 01452 // // Write out the variable name ... 01453 // std::strcpy(buf, (*it).first.c_str()); 01454 // out_stream.write(buf, std::strlen(buf)); 01455 01456 // // ... followed by a zero. 01457 // unsigned int tempint = 0; // 0 signifies cell data 01458 // std::memcpy(buf, &tempint, sizeof(unsigned int)); 01459 // out_stream.write(buf, sizeof(unsigned int)); 01460 01461 // // Get a pointer to the array of cell-centered data values 01462 // const std::vector<Real>* the_array = (*it).second; 01463 01464 // // Since the_array might contain zeros (for inactive elements) we need to 01465 // // make a copy of it containing just values for active elements. 01466 // const unsigned int n_floats = n_active_elem * (1<<mesh.mesh_dimension()); 01467 // float *temp = new float[n_floats]; 01468 01469 // MeshBase::const_element_iterator elem_it = mesh.active_elements_begin(); 01470 // const MeshBase::const_element_iterator elem_end = mesh.active_elements_end(); 01471 // unsigned int n=0; 01472 01473 // for (; elem_it != elem_end; ++elem_it) 01474 // { 01475 // // If there's a seg-fault, it will probably be here! 01476 // const float the_value = static_cast<float>(the_array->operator[]((*elem_it)->id())); 01477 01478 // for (unsigned int se=0; se<(*elem_it)->n_sub_elem(); se++) 01479 // temp[n++] = the_value; 01480 // } 01481 01482 01483 // // Write "the_array" directly to the file 01484 // out_stream.write(reinterpret_cast<char *>(temp), 01485 // sizeof(float)*n_floats); 01486 01487 // delete [] temp; 01488 // } 01489 } 01490 01491 01492 01493 01494 // optionally write the data 01495 if ((solution_names != NULL) && 01496 (vec != NULL)) 01497 { 01498 float *temp = new float[mesh.n_nodes()]; 01499 01500 const unsigned int n_vars = 01501 cast_int<unsigned int>(solution_names->size()); 01502 01503 for (unsigned int c=0; c<n_vars; c++) 01504 { 01505 01506 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 01507 // for complex data, write three datasets 01508 01509 01510 // Real part 01511 std::strcpy(buf, "r_"); 01512 out_stream.write(buf, 2); 01513 std::strcpy(buf, (*solution_names)[c].c_str()); 01514 out_stream.write(buf, 6); 01515 01516 unsigned int tempint = 1; // always do nodal data 01517 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01518 out_stream.write(buf, sizeof(unsigned int)); 01519 01520 for (unsigned int n=0; n<mesh.n_nodes(); n++) 01521 temp[n] = static_cast<float>( (*vec)[n*n_vars + c].real() ); 01522 01523 out_stream.write(reinterpret_cast<char *>(temp), sizeof(float)*mesh.n_nodes()); 01524 01525 01526 // imaginary part 01527 std::strcpy(buf, "i_"); 01528 out_stream.write(buf, 2); 01529 std::strcpy(buf, (*solution_names)[c].c_str()); 01530 out_stream.write(buf, 6); 01531 01532 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01533 out_stream.write(buf, sizeof(unsigned int)); 01534 01535 for (unsigned int n=0; n<mesh.n_nodes(); n++) 01536 temp[n] = static_cast<float>( (*vec)[n*n_vars + c].imag() ); 01537 01538 out_stream.write(reinterpret_cast<char *>(temp), sizeof(float)*mesh.n_nodes()); 01539 01540 // magnitude 01541 std::strcpy(buf, "a_"); 01542 out_stream.write(buf, 2); 01543 std::strcpy(buf, (*solution_names)[c].c_str()); 01544 out_stream.write(buf, 6); 01545 01546 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01547 out_stream.write(buf, sizeof(unsigned int)); 01548 01549 for (unsigned int n=0; n<mesh.n_nodes(); n++) 01550 temp[n] = static_cast<float>(std::abs((*vec)[n*n_vars + c])); 01551 01552 out_stream.write(reinterpret_cast<char *>(temp), sizeof(float)*mesh.n_nodes()); 01553 01554 #else 01555 01556 01557 std::strcpy(buf, (*solution_names)[c].c_str()); 01558 out_stream.write(buf, 8); 01559 01560 unsigned int tempint = 1; // always do nodal data 01561 std::memcpy(buf, &tempint, sizeof(unsigned int)); 01562 out_stream.write(buf, sizeof(unsigned int)); 01563 01564 for (unsigned int n=0; n<mesh.n_nodes(); n++) 01565 temp[n] = static_cast<float>((*vec)[n*n_vars + c]); 01566 01567 out_stream.write(reinterpret_cast<char *>(temp), sizeof(float)*mesh.n_nodes()); 01568 01569 01570 #endif 01571 01572 01573 } 01574 01575 delete [] temp; 01576 01577 } 01578 01579 // If we wrote any variables, we have to close the variable section now 01580 if (write_variable) 01581 { 01582 std::strcpy(buf, "endvars "); 01583 out_stream.write(buf, std::strlen(buf)); 01584 } 01585 01586 // end the file 01587 std::strcpy(buf, "endgmv "); 01588 out_stream.write(buf, std::strlen(buf)); 01589 } 01590 01591 01592 01593 01594 01595 01596 01597 01598 01599 void GMVIO::write_discontinuous_gmv (const std::string& name, 01600 const EquationSystems& es, 01601 const bool write_partitioning, 01602 const std::set<std::string>* system_names) const 01603 { 01604 std::vector<std::string> solution_names; 01605 std::vector<Number> v; 01606 01607 // Get a reference to the mesh 01608 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 01609 01610 es.build_variable_names (solution_names, NULL, system_names); 01611 es.build_discontinuous_solution_vector (v, system_names); 01612 01613 // These are parallel_only functions 01614 const unsigned int n_active_elem = mesh.n_active_elem(); 01615 01616 if (mesh.processor_id() != 0) 01617 return; 01618 01619 std::ofstream out_stream(name.c_str()); 01620 01621 libmesh_assert (out_stream.good()); 01622 01623 // Begin interfacing with the GMV data file 01624 { 01625 01626 // write the nodes 01627 out_stream << "gmvinput ascii" << std::endl << std::endl; 01628 01629 // Compute the total weight 01630 { 01631 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01632 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01633 01634 unsigned int tw=0; 01635 01636 for ( ; it != end; ++it) 01637 tw += (*it)->n_nodes(); 01638 01639 out_stream << "nodes " << tw << std::endl; 01640 } 01641 01642 01643 01644 // Write all the x values 01645 { 01646 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01647 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01648 01649 for ( ; it != end; ++it) 01650 for (unsigned int n=0; n<(*it)->n_nodes(); n++) 01651 out_stream << (*it)->point(n)(0) << " "; 01652 01653 out_stream << std::endl; 01654 } 01655 01656 01657 // Write all the y values 01658 { 01659 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01660 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01661 01662 for ( ; it != end; ++it) 01663 for (unsigned int n=0; n<(*it)->n_nodes(); n++) 01664 #if LIBMESH_DIM > 1 01665 out_stream << (*it)->point(n)(1) << " "; 01666 #else 01667 out_stream << 0. << " "; 01668 #endif 01669 01670 out_stream << std::endl; 01671 } 01672 01673 01674 // Write all the z values 01675 { 01676 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01677 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01678 01679 for ( ; it != end; ++it) 01680 for (unsigned int n=0; n<(*it)->n_nodes(); n++) 01681 #if LIBMESH_DIM > 2 01682 out_stream << (*it)->point(n)(2) << " "; 01683 #else 01684 out_stream << 0. << " "; 01685 #endif 01686 01687 out_stream << std::endl << std::endl; 01688 } 01689 } 01690 01691 01692 01693 { 01694 // write the connectivity 01695 01696 out_stream << "cells " << n_active_elem << std::endl; 01697 01698 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01699 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01700 01701 unsigned int nn=1; 01702 01703 switch (mesh.mesh_dimension()) 01704 { 01705 case 1: 01706 { 01707 for ( ; it != end; ++it) 01708 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 01709 { 01710 if (((*it)->type() == EDGE2) || 01711 ((*it)->type() == EDGE3) || 01712 ((*it)->type() == EDGE4) 01713 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 01714 || ((*it)->type() == INFEDGE2) 01715 #endif 01716 ) 01717 { 01718 out_stream << "line 2" << std::endl; 01719 for (unsigned int i=0; i<(*it)->n_nodes(); i++) 01720 out_stream << nn++ << " "; 01721 01722 } 01723 else 01724 libmesh_error_msg("Unsupported 1D element type: " << Utility::enum_to_string((*it)->type())); 01725 01726 out_stream << std::endl; 01727 } 01728 01729 break; 01730 } 01731 01732 case 2: 01733 { 01734 for ( ; it != end; ++it) 01735 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 01736 { 01737 if (((*it)->type() == QUAD4) || 01738 ((*it)->type() == QUAD8) || // Note: QUAD8 will be output as one central quad and 01739 // four surrounding triangles (though they will be written 01740 // to GMV as QUAD4s). 01741 ((*it)->type() == QUAD9) 01742 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 01743 || ((*it)->type() == INFQUAD4) 01744 || ((*it)->type() == INFQUAD6) 01745 #endif 01746 ) 01747 { 01748 out_stream << "quad 4" << std::endl; 01749 for (unsigned int i=0; i<(*it)->n_nodes(); i++) 01750 out_stream << nn++ << " "; 01751 01752 } 01753 else if (((*it)->type() == TRI3) || 01754 ((*it)->type() == TRI6)) 01755 { 01756 out_stream << "tri 3" << std::endl; 01757 for (unsigned int i=0; i<(*it)->n_nodes(); i++) 01758 out_stream << nn++ << " "; 01759 01760 } 01761 else 01762 libmesh_error_msg("Unsupported 2D element type: " << Utility::enum_to_string((*it)->type())); 01763 01764 out_stream << std::endl; 01765 } 01766 01767 break; 01768 } 01769 01770 01771 case 3: 01772 { 01773 for ( ; it != end; ++it) 01774 for (unsigned int se=0; se<(*it)->n_sub_elem(); se++) 01775 { 01776 if (((*it)->type() == HEX8) || 01777 ((*it)->type() == HEX20) || 01778 ((*it)->type() == HEX27) 01779 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 01780 || ((*it)->type() == INFHEX8) 01781 || ((*it)->type() == INFHEX16) 01782 || ((*it)->type() == INFHEX18) 01783 #endif 01784 ) 01785 { 01786 out_stream << "phex8 8" << std::endl; 01787 for (unsigned int i=0; i<(*it)->n_nodes(); i++) 01788 out_stream << nn++ << " "; 01789 } 01790 else if (((*it)->type() == PRISM6) || 01791 ((*it)->type() == PRISM15) || 01792 ((*it)->type() == PRISM18) 01793 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 01794 || ((*it)->type() == INFPRISM6) 01795 || ((*it)->type() == INFPRISM12) 01796 #endif 01797 ) 01798 { 01799 out_stream << "pprism6 6" << std::endl; 01800 for (unsigned int i=0; i<(*it)->n_nodes(); i++) 01801 out_stream << nn++ << " "; 01802 } 01803 else if (((*it)->type() == TET4) || 01804 ((*it)->type() == TET10)) 01805 { 01806 out_stream << "tet 4" << std::endl; 01807 for (unsigned int i=0; i<(*it)->n_nodes(); i++) 01808 out_stream << nn++ << " "; 01809 } 01810 else 01811 libmesh_error_msg("Unsupported 3D element type: " << Utility::enum_to_string((*it)->type())); 01812 01813 out_stream << std::endl; 01814 } 01815 01816 break; 01817 } 01818 01819 default: 01820 libmesh_error_msg("Unsupported mesh dimension: " << mesh.mesh_dimension()); 01821 } 01822 01823 out_stream << std::endl; 01824 } 01825 01826 01827 01828 // optionally write the partition information 01829 if (write_partitioning) 01830 { 01831 if (_write_subdomain_id_as_material) 01832 libmesh_error_msg("Not yet supported in GMVIO::write_discontinuous_gmv"); 01833 01834 else 01835 { 01836 out_stream << "material " 01837 << mesh.n_processors() 01838 << " 0"<< std::endl; 01839 01840 for (unsigned int proc=0; proc<mesh.n_processors(); proc++) 01841 out_stream << "proc_" << proc << std::endl; 01842 01843 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01844 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01845 01846 for ( ; it != end; ++it) 01847 out_stream << (*it)->processor_id()+1 << std::endl; 01848 01849 out_stream << std::endl; 01850 } 01851 } 01852 01853 01854 // Writing cell-centered data is not yet supported in discontinuous GMV files. 01855 if ( !(this->_cell_centered_data.empty()) ) 01856 { 01857 libMesh::err << "Cell-centered data not (yet) supported for discontinuous GMV files!" << std::endl; 01858 } 01859 01860 01861 01862 // write the data 01863 { 01864 const unsigned int n_vars = 01865 cast_int<unsigned int>(solution_names.size()); 01866 01867 // libmesh_assert_equal_to (v.size(), tw*n_vars); 01868 01869 out_stream << "variable" << std::endl; 01870 01871 01872 for (unsigned int c=0; c<n_vars; c++) 01873 { 01874 01875 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 01876 01877 // in case of complex data, write _tree_ data sets 01878 // for each component 01879 01880 // this is the real part 01881 out_stream << "r_" << solution_names[c] << " 1" << std::endl; 01882 { 01883 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01884 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01885 01886 for ( ; it != end; ++it) 01887 for (unsigned int n=0; n<(*it)->n_nodes(); n++) 01888 out_stream << v[(n++)*n_vars + c].real() << " "; 01889 } 01890 out_stream << std::endl << std::endl; 01891 01892 01893 // this is the imaginary part 01894 out_stream << "i_" << solution_names[c] << " 1" << std::endl; 01895 { 01896 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01897 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01898 01899 for ( ; it != end; ++it) 01900 for (unsigned int n=0; n<(*it)->n_nodes(); n++) 01901 out_stream << v[(n++)*n_vars + c].imag() << " "; 01902 } 01903 out_stream << std::endl << std::endl; 01904 01905 // this is the magnitude 01906 out_stream << "a_" << solution_names[c] << " 1" << std::endl; 01907 { 01908 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01909 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01910 01911 for ( ; it != end; ++it) 01912 for (unsigned int n=0; n<(*it)->n_nodes(); n++) 01913 out_stream << std::abs(v[(n++)*n_vars + c]) << " "; 01914 } 01915 out_stream << std::endl << std::endl; 01916 01917 #else 01918 01919 out_stream << solution_names[c] << " 1" << std::endl; 01920 { 01921 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01922 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01923 01924 unsigned int nn=0; 01925 01926 for ( ; it != end; ++it) 01927 for (unsigned int n=0; n<(*it)->n_nodes(); n++) 01928 out_stream << v[(nn++)*n_vars + c] << " "; 01929 } 01930 out_stream << std::endl << std::endl; 01931 01932 #endif 01933 01934 } 01935 01936 out_stream << "endvars" << std::endl; 01937 } 01938 01939 01940 // end of the file 01941 out_stream << std::endl << "endgmv" << std::endl; 01942 } 01943 01944 01945 01946 01947 01948 void GMVIO::add_cell_centered_data (const std::string& cell_centered_data_name, 01949 const std::vector<Real>* cell_centered_data_vals) 01950 { 01951 libmesh_assert(cell_centered_data_vals); 01952 01953 // Make sure there are *at least* enough entries for all the active elements. 01954 // There can also be entries for inactive elements, they will be ignored. 01955 // libmesh_assert_greater_equal (cell_centered_data_vals->size(), 01956 // MeshOutput<MeshBase>::mesh().n_active_elem()); 01957 this->_cell_centered_data[cell_centered_data_name] = cell_centered_data_vals; 01958 } 01959 01960 01961 01962 01963 01964 01965 void GMVIO::read (const std::string& name) 01966 { 01967 // This is a serial-only process for now; 01968 // the Mesh should be read on processor 0 and 01969 // broadcast later 01970 libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0); 01971 01972 _next_elem_id = 0; 01973 01974 libmesh_experimental(); 01975 01976 #ifndef LIBMESH_HAVE_GMV 01977 01978 libmesh_error_msg("Cannot read GMV file " << name << " without the GMV API."); 01979 01980 #else 01981 // We use the file-scope global variable eletypes for mapping nodes 01982 // from GMV to libmesh indices, so initialize that data now. 01983 init_eletypes(); 01984 01985 // Clear the mesh so we are sure to start from a pristeen state. 01986 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 01987 mesh.clear(); 01988 01989 // Keep track of what kinds of elements this file contains 01990 elems_of_dimension.clear(); 01991 elems_of_dimension.resize(4, false); 01992 01993 // It is apparently possible for gmv files to contain 01994 // a "fromfile" directive (?) But we currently don't make 01995 // any use of this feature in LibMesh. Nonzero return val 01996 // from any function usually means an error has occurred. 01997 int ierr = GMVLib::gmvread_open_fromfileskip(const_cast<char*>(name.c_str())); 01998 if (ierr != 0) 01999 libmesh_error_msg("GMVLib::gmvread_open_fromfileskip failed!"); 02000 02001 02002 // Loop through file until GMVEND. 02003 int iend = 0; 02004 while (iend == 0) 02005 { 02006 GMVLib::gmvread_data(); 02007 02008 /* Check for GMVEND. */ 02009 if (GMVLib::gmv_data.keyword == GMVEND) 02010 { 02011 iend = 1; 02012 GMVLib::gmvread_close(); 02013 break; 02014 } 02015 02016 /* Check for GMVERROR. */ 02017 if (GMVLib::gmv_data.keyword == GMVERROR) 02018 libmesh_error_msg("Encountered GMVERROR while reading!"); 02019 02020 /* Process the data. */ 02021 switch (GMVLib::gmv_data.keyword) 02022 { 02023 case NODES: 02024 { 02025 //libMesh::out << "Reading nodes." << std::endl; 02026 02027 if (GMVLib::gmv_data.num2 == NODES) 02028 this->_read_nodes(); 02029 02030 else if (GMVLib::gmv_data.num2 == NODE_V) 02031 libmesh_error_msg("Unsupported GMV data type NODE_V!"); 02032 02033 break; 02034 } 02035 02036 case CELLS: 02037 { 02038 // Read 1 cell at a time 02039 // libMesh::out << "\nReading one cell." << std::endl; 02040 this->_read_one_cell(); 02041 break; 02042 } 02043 02044 case MATERIAL: 02045 { 02046 // keyword == 6 02047 // These are the materials, which we use to specify the mesh 02048 // partitioning. 02049 this->_read_materials(); 02050 break; 02051 } 02052 02053 case VARIABLE: 02054 { 02055 // keyword == 8 02056 // This is a field variable. 02057 02058 // Check to see if we're done reading variables and break out. 02059 if (GMVLib::gmv_data.datatype == ENDKEYWORD) 02060 { 02061 // libMesh::out << "Done reading GMV variables." << std::endl; 02062 break; 02063 } 02064 02065 if (GMVLib::gmv_data.datatype == NODE) 02066 { 02067 // libMesh::out << "Reading node field data for variable " 02068 // << GMVLib::gmv_data.name1 << std::endl; 02069 this->_read_var(); 02070 break; 02071 } 02072 02073 else 02074 { 02075 libMesh::err << "Warning: Skipping variable: " 02076 << GMVLib::gmv_data.name1 02077 << " which is of unsupported GMV datatype " 02078 << GMVLib::gmv_data.datatype 02079 << ". Nodal field data is currently the only type currently supported." 02080 << std::endl; 02081 break; 02082 } 02083 02084 } 02085 02086 default: 02087 libmesh_error_msg("Encountered unknown GMV keyword " << GMVLib::gmv_data.keyword); 02088 02089 } // end switch 02090 } // end while 02091 02092 // Set the mesh dimension to the largest encountered for an element 02093 for (unsigned char i=0; i!=4; ++i) 02094 if (elems_of_dimension[i]) 02095 mesh.set_mesh_dimension(i); 02096 02097 #if LIBMESH_DIM < 3 02098 if (mesh.mesh_dimension() > LIBMESH_DIM) 02099 libmesh_error_msg("Cannot open dimension " \ 02100 << mesh.mesh_dimension() \ 02101 << " mesh file when configured without " \ 02102 << mesh.mesh_dimension() \ 02103 << "D support."); 02104 #endif 02105 02106 // Done reading in the mesh, now call find_neighbors, etc. 02107 // mesh.find_neighbors(); 02108 02109 // Pass true flag to skip renumbering nodes and elements 02110 mesh.prepare_for_use(true); 02111 #endif 02112 } 02113 02114 02115 02116 02117 void GMVIO::_read_var() 02118 { 02119 #ifdef LIBMESH_HAVE_GMV 02120 02121 // Copy all the variable's values into a local storage vector. 02122 _nodal_data.insert ( std::make_pair(std::string(GMVLib::gmv_data.name1), 02123 std::vector<Number>(GMVLib::gmv_data.doubledata1, GMVLib::gmv_data.doubledata1+GMVLib::gmv_data.num) ) ); 02124 #endif 02125 } 02126 02127 02128 02129 void GMVIO::_read_materials() 02130 { 02131 #ifdef LIBMESH_HAVE_GMV 02132 02133 // LibMesh assigns materials on a per-cell basis 02134 libmesh_assert_equal_to (GMVLib::gmv_data.datatype, CELL); 02135 02136 // // Material names: LibMesh has no use for these currently... 02137 // libMesh::out << "Number of material names=" 02138 // << GMVLib::gmv_data.num 02139 // << std::endl; 02140 02141 // for (int i = 0; i < GMVLib::gmv_data.num; i++) 02142 // { 02143 // // Build a 32-char string from the appropriate entries 02144 // std::string mat_string(&GMVLib::gmv_data.chardata1[i*33], 32); 02145 02146 // libMesh::out << "Material name " << i << ": " << mat_string << std::endl; 02147 // } 02148 02149 // // Material labels: These correspond to (1-based) CPU IDs, and 02150 // // there should be 1 of these for each element. 02151 // libMesh::out << "Number of material labels = " 02152 // << GMVLib::gmv_data.nlongdata1 02153 // << std::endl; 02154 02155 for (int i = 0; i < GMVLib::gmv_data.nlongdata1; i++) 02156 { 02157 // Debugging Info 02158 // libMesh::out << "Material ID " << i << ": " 02159 // << GMVLib::gmv_data.longdata1[i] 02160 // << std::endl; 02161 02162 MeshInput<MeshBase>::mesh().elem(i)->processor_id() = 02163 cast_int<processor_id_type>(GMVLib::gmv_data.longdata1[i]-1); 02164 } 02165 02166 #endif 02167 } 02168 02169 02170 02171 02172 void GMVIO::_read_nodes() 02173 { 02174 #ifdef LIBMESH_HAVE_GMV 02175 // // Debug Info 02176 // libMesh::out << "gmv_data.datatype=" 02177 // << GMVLib::gmv_data.datatype 02178 // << std::endl; 02179 02180 // LibMesh writes UNSTRUCT=100 node data 02181 libmesh_assert_equal_to (GMVLib::gmv_data.datatype, UNSTRUCT); 02182 02183 // The nodal data is stored in gmv_data.doubledata{1,2,3} 02184 // and is nnodes long 02185 for (int i = 0; i < GMVLib::gmv_data.num; i++) 02186 { 02187 // libMesh::out << "(x,y,z)=" 02188 // << "(" 02189 // << GMVLib::gmv_data.doubledata1[i] 02190 // << "," 02191 // << GMVLib::gmv_data.doubledata2[i] 02192 // << "," 02193 // << GMVLib::gmv_data.doubledata3[i] 02194 // << ")" 02195 // << std::endl; 02196 02197 // Add the point to the Mesh 02198 MeshInput<MeshBase>::mesh().add_point 02199 ( Point(GMVLib::gmv_data.doubledata1[i], 02200 GMVLib::gmv_data.doubledata2[i], 02201 GMVLib::gmv_data.doubledata3[i]), i); 02202 } 02203 #endif 02204 } 02205 02206 02207 void GMVIO::_read_one_cell() 02208 { 02209 #ifdef LIBMESH_HAVE_GMV 02210 // // Debug Info 02211 // libMesh::out << "gmv_data.datatype=" 02212 // << GMVLib::gmv_data.datatype 02213 // << std::endl; 02214 02215 // This is either a REGULAR=111 cell or 02216 // the ENDKEYWORD=207 of the cells 02217 #ifndef NDEBUG 02218 bool recognized = 02219 (GMVLib::gmv_data.datatype==REGULAR) || 02220 (GMVLib::gmv_data.datatype==ENDKEYWORD); 02221 #endif 02222 libmesh_assert (recognized); 02223 02224 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 02225 02226 if (GMVLib::gmv_data.datatype == REGULAR) 02227 { 02228 // libMesh::out << "Name of the cell is: " 02229 // << GMVLib::gmv_data.name1 02230 // << std::endl; 02231 02232 // libMesh::out << "Cell has " 02233 // << GMVLib::gmv_data.num2 02234 // << " vertices." 02235 // << std::endl; 02236 02237 // We need a mapping from GMV element types to LibMesh 02238 // ElemTypes. Basically the reverse of the eletypes 02239 // std::map above. 02240 // 02241 // FIXME: Since Quad9's apparently don't exist for GMV, and since 02242 // In general we write linear sub-elements to GMV files, we need 02243 // to be careful to read back in exactly what we wrote out... 02244 ElemType type = this->_gmv_elem_to_libmesh_elem(GMVLib::gmv_data.name1); 02245 02246 Elem* elem = Elem::build(type).release(); 02247 elem->set_id(_next_elem_id++); 02248 02249 // Get the ElementDefinition object for this element type 02250 const ElementDefinition& eledef = eletypes[type]; 02251 02252 // Print out the connectivity information for 02253 // this cell. 02254 for (int i=0; i<GMVLib::gmv_data.num2; i++) 02255 { 02256 // // Debugging info 02257 // libMesh::out << "Vertex " << i << " is node " 02258 // << GMVLib::gmv_data.longdata1[i] 02259 // << std::endl; 02260 02261 // Map index i to GMV's numbering scheme 02262 unsigned mapped_i = eledef.node_map[i]; 02263 02264 // Note: Node numbers (as stored in libmesh) are 1-based 02265 elem->set_node(i) = mesh.node_ptr 02266 (cast_int<dof_id_type>(GMVLib::gmv_data.longdata1[mapped_i]-1)); 02267 } 02268 02269 elems_of_dimension[elem->dim()] = true; 02270 02271 // Add the newly-created element to the mesh 02272 mesh.add_elem(elem); 02273 } 02274 02275 02276 if (GMVLib::gmv_data.datatype == ENDKEYWORD) 02277 { 02278 // There isn't a cell to read, so we just return 02279 return; 02280 } 02281 02282 #endif 02283 } 02284 02285 02286 ElemType GMVIO::_gmv_elem_to_libmesh_elem(const char* elemname) 02287 { 02288 // 02289 // Linear Elements 02290 // 02291 if (!std::strncmp(elemname,"line",4)) 02292 return EDGE2; 02293 02294 if (!std::strncmp(elemname,"tri",3)) 02295 return TRI3; 02296 02297 if (!std::strncmp(elemname,"quad",4)) 02298 return QUAD4; 02299 02300 // FIXME: tet or ptet4? 02301 if ((!std::strncmp(elemname,"tet",3)) || 02302 (!std::strncmp(elemname,"ptet4",5))) 02303 return TET4; 02304 02305 // FIXME: hex or phex8? 02306 if ((!std::strncmp(elemname,"hex",3)) || 02307 (!std::strncmp(elemname,"phex8",5))) 02308 return HEX8; 02309 02310 // FIXME: prism or pprism6? 02311 if ((!std::strncmp(elemname,"prism",5)) || 02312 (!std::strncmp(elemname,"pprism6",7))) 02313 return PRISM6; 02314 02315 // 02316 // Quadratic Elements 02317 // 02318 if (!std::strncmp(elemname,"phex20",6)) 02319 return HEX20; 02320 02321 if (!std::strncmp(elemname,"phex27",6)) 02322 return HEX27; 02323 02324 if (!std::strncmp(elemname,"pprism15",8)) 02325 return PRISM15; 02326 02327 if (!std::strncmp(elemname,"ptet10",6)) 02328 return TET10; 02329 02330 if (!std::strncmp(elemname,"6tri",4)) 02331 return TRI6; 02332 02333 if (!std::strncmp(elemname,"8quad",5)) 02334 return QUAD8; 02335 02336 if (!std::strncmp(elemname,"3line",5)) 02337 return EDGE3; 02338 02339 // Unsupported/Unused types 02340 // if (!std::strncmp(elemname,"vface2d",7)) 02341 // if (!std::strncmp(elemname,"vface3d",7)) 02342 // if (!std::strncmp(elemname,"pyramid",7)) 02343 // if (!std::strncmp(elemname,"ppyrmd5",7)) 02344 // if (!std::strncmp(elemname,"ppyrmd13",8)) 02345 02346 // If we didn't return yet, then we didn't find the right cell! 02347 libmesh_error_msg("Uknown/unsupported element: " << elemname << " was read."); 02348 } 02349 02350 02351 02352 02353 void GMVIO::copy_nodal_solution(EquationSystems& es) 02354 { 02355 // Check for easy return if there isn't any nodal data 02356 if (_nodal_data.empty()) 02357 { 02358 libMesh::err << "Unable to copy nodal solution: No nodal " 02359 << "solution has been read in from file." << std::endl; 02360 return; 02361 } 02362 02363 // Be sure there is at least one system 02364 libmesh_assert (es.n_systems()); 02365 02366 // Keep track of variable names which have been found and 02367 // copied already. This could be used to prevent us from 02368 // e.g. copying the same var into 2 different systems ... 02369 // but this seems unlikely. Also, it is used to tell if 02370 // any variables which were read in were not successfully 02371 // copied to the EquationSystems. 02372 std::set<std::string> vars_copied; 02373 02374 // For each entry in the nodal data map, try to find a system 02375 // that has the same variable key name. 02376 for (unsigned int sys=0; sys<es.n_systems(); ++sys) 02377 { 02378 // Get a generic refernence to the current System 02379 System& system = es.get_system(sys); 02380 02381 // And a reference to that system's dof_map 02382 // const DofMap & dof_map = system.get_dof_map(); 02383 02384 // For each var entry in the _nodal_data map, try to find 02385 // that var in the system 02386 std::map<std::string, std::vector<Number> >::iterator it = _nodal_data.begin(); 02387 const std::map<std::string, std::vector<Number> >::iterator end = _nodal_data.end(); 02388 for (; it != end; ++it) 02389 { 02390 std::string var_name = (*it).first; 02391 // libMesh::out << "Searching for var " << var_name << " in system " << sys << std::endl; 02392 02393 if (system.has_variable(var_name)) 02394 { 02395 // Check if there are as many nodes in the mesh as there are entries 02396 // in the stored nodal data vector 02397 libmesh_assert_equal_to ( (*it).second.size(), MeshInput<MeshBase>::mesh().n_nodes() ); 02398 02399 const unsigned int var_num = system.variable_number(var_name); 02400 02401 // libMesh::out << "Variable " 02402 // << var_name 02403 // << " is variable " 02404 // << var_num 02405 // << " in system " << sys << std::endl; 02406 02407 // The only type of nodal data we can read in from GMV is for 02408 // linear LAGRANGE type elements. 02409 const FEType& fe_type = system.variable_type(var_num); 02410 if ((fe_type.order != FIRST) || (fe_type.family != LAGRANGE)) 02411 { 02412 libMesh::err << "Only FIRST-order LAGRANGE variables can be read from GMV files. " 02413 << "Skipping variable " << var_name << std::endl; 02414 break; 02415 } 02416 02417 02418 // Loop over the stored vector's entries, inserting them into 02419 // the System's solution if appropriate. 02420 for (unsigned int i=0; i<(*it).second.size(); ++i) 02421 { 02422 // Since this var came from a GMV file, the index i corresponds to 02423 // the (single) DOF value of the current variable for node i. 02424 const unsigned int dof_index = 02425 MeshInput<MeshBase>::mesh().node_ptr(i)->dof_number(sys, /*system #*/ 02426 var_num, /*var # */ 02427 0); /*component #, always zero for LAGRANGE */ 02428 02429 // libMesh::out << "Value " << i << ": " 02430 // << (*it).second [i] 02431 // << ", dof index=" 02432 // << dof_index << std::endl; 02433 02434 // If the dof_index is local to this processor, set the value 02435 if ((dof_index >= system.solution->first_local_index()) && 02436 (dof_index < system.solution->last_local_index())) 02437 system.solution->set (dof_index, (*it).second [i]); 02438 } // end loop over my GMVIO's copy of the solution 02439 02440 // Add the most recently copied var to the set of copied vars 02441 vars_copied.insert (var_name); 02442 } // end if (system.has_variable) 02443 } // end for loop over _nodal_data 02444 02445 // Communicate parallel values before going to the next system. 02446 system.solution->close(); 02447 system.update(); 02448 02449 } // end loop over all systems 02450 02451 02452 02453 // Warn the user if any GMV variables were not successfully copied over to the EquationSystems object 02454 { 02455 std::map<std::string, std::vector<Number> >::iterator it = _nodal_data.begin(); 02456 const std::map<std::string, std::vector<Number> >::iterator end = _nodal_data.end(); 02457 02458 for (; it != end; ++it) 02459 { 02460 if (vars_copied.find( (*it).first ) == vars_copied.end()) 02461 { 02462 libMesh::err << "Warning: Variable " 02463 << (*it).first 02464 << " was not copied to the EquationSystems object." 02465 << std::endl; 02466 } 02467 } 02468 } 02469 02470 } 02471 02472 } // namespace libMesh