exodusII_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 #include <cstring> 00022 00023 // Local includes 00024 #include "libmesh/exodusII_io.h" 00025 #include "libmesh/boundary_info.h" 00026 #include "libmesh/mesh_base.h" 00027 #include "libmesh/enum_elem_type.h" 00028 #include "libmesh/elem.h" 00029 #include "libmesh/equation_systems.h" 00030 #include "libmesh/libmesh_logging.h" 00031 #include "libmesh/system.h" 00032 #include "libmesh/numeric_vector.h" 00033 #include "libmesh/exodusII_io_helper.h" 00034 00035 namespace libMesh 00036 { 00037 00038 00039 00040 00041 00042 // ------------------------------------------------------------ 00043 // ExodusII_IO class members 00044 ExodusII_IO::ExodusII_IO (MeshBase& mesh) : 00045 MeshInput<MeshBase> (mesh), 00046 MeshOutput<MeshBase> (mesh), 00047 #ifdef LIBMESH_HAVE_EXODUS_API 00048 exio_helper(new ExodusII_IO_Helper), 00049 #endif 00050 _timestep(1), 00051 _verbose (false) 00052 { 00053 } 00054 00055 00056 00057 ExodusII_IO::~ExodusII_IO () 00058 { 00059 #ifndef LIBMESH_HAVE_EXODUS_API 00060 00061 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00062 << std::endl; 00063 libmesh_error(); 00064 00065 #else 00066 00067 exio_helper->close(); 00068 00069 delete exio_helper; 00070 00071 #endif 00072 } 00073 00074 00075 00076 void ExodusII_IO::verbose (bool set_verbosity) 00077 { 00078 _verbose = set_verbosity; 00079 00080 #ifdef LIBMESH_HAVE_EXODUS_API 00081 // Set the verbose flag in the helper object 00082 // as well. 00083 exio_helper->verbose(_verbose); 00084 #endif 00085 } 00086 00087 00088 00089 void ExodusII_IO::use_mesh_dimension_instead_of_spatial_dimension(bool val) 00090 { 00091 #ifdef LIBMESH_HAVE_EXODUS_API 00092 exio_helper->use_mesh_dimension_instead_of_spatial_dimension(val); 00093 #endif 00094 } 00095 00096 00097 00098 void ExodusII_IO::read (const std::string& fname) 00099 { 00100 // This is a serial-only process for now; 00101 // the Mesh should be read on processor 0 and 00102 // broadcast later 00103 // libmesh_assert_equal_to (libMesh::processor_id(), 0); 00104 00105 #ifndef LIBMESH_HAVE_EXODUS_API 00106 00107 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00108 << "Input file " << fname << " cannot be read" 00109 << std::endl; 00110 libmesh_error(); 00111 00112 #else 00113 00114 // Get a reference to the mesh we are reading 00115 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 00116 00117 // Clear any existing mesh data 00118 mesh.clear(); 00119 00120 // Keep track of what kinds of elements this file contains 00121 elems_of_dimension.clear(); 00122 elems_of_dimension.resize(4, false); 00123 00124 #ifdef DEBUG 00125 this->verbose(true); 00126 #endif 00127 00128 00129 ExodusII_IO_Helper::ElementMaps em; // Instantiate the ElementMaps interface 00130 00131 exio_helper->open(fname.c_str()); // Open the exodus file, if possible 00132 exio_helper->read_header(); // Get header information from exodus file 00133 exio_helper->print_header(); // Print header information 00134 00135 //assertion fails due to inconsistent mesh dimension 00136 // libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->get_num_dim()), mesh.mesh_dimension()); // Be sure number of dimensions 00137 // is equal to the number of 00138 // dimensions in the mesh supplied. 00139 00140 exio_helper->read_nodes(); // Read nodes from the exodus file 00141 mesh.reserve_nodes(exio_helper->get_num_nodes()); // Reserve space for the nodes. 00142 00143 // Loop over the nodes, create Nodes with local processor_id 0. 00144 for (int i=0; i<exio_helper->get_num_nodes(); i++) 00145 mesh.add_point (Point(exio_helper->get_x(i), 00146 exio_helper->get_y(i), 00147 exio_helper->get_z(i)), i); 00148 00149 libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->get_num_nodes()), mesh.n_nodes()); 00150 00151 exio_helper->read_block_info(); // Get information about all the blocks 00152 mesh.reserve_elem(exio_helper->get_num_elem()); // Reserve space for the elements 00153 00154 00155 // Read in the element connectivity for each block. 00156 int nelem_last_block = 0; 00157 00158 std::map<int, dof_id_type> exodus_id_to_mesh_id; 00159 00160 // Loop over all the blocks 00161 for (int i=0; i<exio_helper->get_num_elem_blk(); i++) 00162 { 00163 // Read the information for block i 00164 exio_helper->read_elem_in_block (i); 00165 int subdomain_id = exio_helper->get_block_id(i); 00166 00167 // populate the map of names 00168 mesh.subdomain_name(static_cast<subdomain_id_type>(subdomain_id)) = 00169 exio_helper->get_block_name(i); 00170 00171 // Set any relevant node/edge maps for this element 00172 const std::string type_str (exio_helper->get_elem_type()); 00173 const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(type_str); 00174 //if (_verbose) 00175 //libMesh::out << "Reading a block of " << type_str << " elements." << std::endl; 00176 00177 // Loop over all the faces in this block 00178 int jmax = nelem_last_block+exio_helper->get_num_elem_this_blk(); 00179 for (int j=nelem_last_block; j<jmax; j++) 00180 { 00181 Elem* elem = Elem::build (conv.get_canonical_type()).release(); 00182 libmesh_assert (elem); 00183 elem->subdomain_id() = static_cast<subdomain_id_type>(subdomain_id) ; 00184 //elem->set_id(j);// Don't try to second guess the Element ID setting scheme! 00185 00186 elems_of_dimension[elem->dim()] = true; 00187 00188 elem = mesh.add_elem (elem); // Catch the Elem pointer that the Mesh throws back 00189 00190 exodus_id_to_mesh_id[j+1] = elem->id(); 00191 00192 // Set all the nodes for this element 00193 for (int k=0; k<exio_helper->get_num_nodes_per_elem(); k++) 00194 { 00195 int gi = (j-nelem_last_block)*exio_helper->get_num_nodes_per_elem() + conv.get_node_map(k); // global index 00196 int node_number = exio_helper->get_connect(gi); // Global node number (1-based) 00197 elem->set_node(k) = mesh.node_ptr((node_number-1)); // Set node number 00198 // Subtract 1 since 00199 // exodus is internally 1-based 00200 } 00201 } 00202 00203 // running sum of # of elements per block, 00204 // (should equal total number of elements in the end) 00205 nelem_last_block += exio_helper->get_num_elem_this_blk(); 00206 } 00207 libmesh_assert_equal_to (static_cast<unsigned int>(nelem_last_block), mesh.n_elem()); 00208 00209 // Set the mesh dimension to the largest encountered for an element 00210 for (unsigned int i=0; i!=4; ++i) 00211 if (elems_of_dimension[i]) 00212 mesh.set_mesh_dimension(i); 00213 00214 // Read in sideset information -- this is useful for applying boundary conditions 00215 { 00216 exio_helper->read_sideset_info(); // Get basic information about ALL sidesets 00217 int offset=0; 00218 for (int i=0; i<exio_helper->get_num_side_sets(); i++) 00219 { 00220 offset += (i > 0 ? exio_helper->get_num_sides_per_set(i-1) : 0); // Compute new offset 00221 exio_helper->read_sideset (i, offset); 00222 00223 mesh.boundary_info->sideset_name(exio_helper->get_side_set_id(i)) = 00224 exio_helper->get_side_set_name(i); 00225 } 00226 00227 const std::vector<int>& elem_list = exio_helper->get_elem_list(); 00228 const std::vector<int>& side_list = exio_helper->get_side_list(); 00229 const std::vector<int>& id_list = exio_helper->get_id_list(); 00230 00231 for (unsigned int e=0; e<elem_list.size(); e++) 00232 { 00233 // Set any relevant node/edge maps for this element 00234 00235 Elem * elem = mesh.elem(exodus_id_to_mesh_id[elem_list[e]]); 00236 00237 const ExodusII_IO_Helper::Conversion conv = 00238 em.assign_conversion(elem->type()); 00239 00240 mesh.boundary_info->add_side (exodus_id_to_mesh_id[elem_list[e]], 00241 conv.get_side_map(side_list[e]-1), 00242 id_list[e]); 00243 } 00244 } 00245 00246 // Read nodeset info 00247 { 00248 exio_helper->read_nodeset_info(); 00249 00250 for (int nodeset=0; nodeset<exio_helper->get_num_node_sets(); nodeset++) 00251 { 00252 int nodeset_id = exio_helper->get_nodeset_id(nodeset); 00253 00254 mesh.boundary_info->nodeset_name(nodeset_id) = 00255 exio_helper->get_node_set_name(nodeset); 00256 00257 exio_helper->read_nodeset(nodeset); 00258 00259 const std::vector<int>& node_list = exio_helper->get_node_list(); 00260 00261 for(unsigned int node=0; node<node_list.size(); node++) 00262 mesh.boundary_info->add_node(node_list[node]-1, nodeset_id); 00263 } 00264 } 00265 00266 #if LIBMESH_DIM < 3 00267 if (mesh.mesh_dimension() > LIBMESH_DIM) 00268 { 00269 libMesh::err << "Cannot open dimension " << 00270 mesh.mesh_dimension() << 00271 " mesh file when configured without " << 00272 mesh.mesh_dimension() << "D support." << 00273 std::endl; 00274 libmesh_error(); 00275 } 00276 #endif 00277 00278 #endif 00279 } 00280 00281 00282 00283 #ifndef LIBMESH_HAVE_EXODUS_API 00284 00285 const std::vector<Real>& ExodusII_IO::get_time_steps() 00286 { 00287 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00288 << std::endl; 00289 libmesh_error(); 00290 } 00291 00292 #else 00293 00294 const std::vector<Real>& ExodusII_IO::get_time_steps() 00295 { 00296 return exio_helper->get_time_steps(); 00297 } 00298 00299 #endif 00300 00301 00302 00303 00304 void ExodusII_IO::copy_nodal_solution(System& system, std::string var_name, unsigned int timestep) 00305 { 00306 libmesh_deprecated(); 00307 copy_nodal_solution(system, var_name, var_name, timestep); 00308 } 00309 00310 00311 00312 #ifndef LIBMESH_HAVE_EXODUS_API 00313 00314 void ExodusII_IO::copy_nodal_solution(System&, std::string, std::string, unsigned int) 00315 { 00316 00317 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00318 << std::endl; 00319 libmesh_error(); 00320 } 00321 00322 #else 00323 00324 void ExodusII_IO::copy_nodal_solution(System& system, std::string system_var_name, std::string exodus_var_name, unsigned int timestep) 00325 { 00326 // FIXME: Do we need to call get_time_steps() at all? 00327 /*const std::vector<double>& time_steps = */ 00328 exio_helper->get_time_steps(); 00329 00330 const std::vector<Real> & nodal_values = exio_helper->get_nodal_var_values(exodus_var_name, timestep); 00331 00332 const unsigned int var_num = system.variable_number(system_var_name); 00333 00334 for (unsigned int i=0; i<nodal_values.size(); ++i) 00335 { 00336 const Node* node = MeshInput<MeshBase>::mesh().node_ptr(i); 00337 00338 if (!node) 00339 { 00340 libMesh::err << "Error! Mesh returned NULL pointer for node " << i << std::endl; 00341 libmesh_error(); 00342 } 00343 00344 dof_id_type dof_index = node->dof_number(system.number(), var_num, 0); 00345 00346 // If the dof_index is local to this processor, set the value 00347 if ((dof_index >= system.solution->first_local_index()) && (dof_index < system.solution->last_local_index())) 00348 system.solution->set (dof_index, nodal_values[i]); 00349 } 00350 00351 system.solution->close(); 00352 system.update(); 00353 } 00354 00355 #endif 00356 00357 00358 00359 00360 #ifndef LIBMESH_HAVE_EXODUS_API 00361 00362 void ExodusII_IO::write_element_data (const EquationSystems& es) 00363 { 00364 00365 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00366 << std::endl; 00367 libmesh_error(); 00368 } 00369 00370 #else 00371 00372 void ExodusII_IO::write_element_data (const EquationSystems & es) 00373 { 00374 // The first step is to collect the element data onto this processor. 00375 // We want the constant monomial data. 00376 00377 std::vector<Number> soln; 00378 std::vector<std::string> names; 00379 00380 // If _output_variables is populated we need to filter the monomials we output 00381 if (_output_variables.size()) 00382 { 00383 std::vector<std::string> monomials; 00384 const FEType type(CONSTANT, MONOMIAL); 00385 es.build_variable_names(monomials, &type); 00386 00387 for (std::vector<std::string>::iterator it = monomials.begin(); it != monomials.end(); ++it) 00388 if (std::find(_output_variables.begin(), _output_variables.end(), *it) != _output_variables.end()) 00389 names.push_back(*it); 00390 } 00391 00392 // If we pass in a list of names to "get_solution" it'll filter the variables comming back 00393 es.get_solution( soln, names ); 00394 00395 // The data must ultimately be written block by block. This means that this data 00396 // must be sorted appropriately. 00397 00398 if (!exio_helper->created()) 00399 { 00400 libMesh::err << "ERROR, ExodusII file must be initialized " 00401 << "before outputting element variables.\n" 00402 << std::endl; 00403 libmesh_error(); 00404 } 00405 00406 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00407 00408 exio_helper->initialize_element_variables( mesh, names ); 00409 exio_helper->write_element_values(mesh,soln,_timestep); 00410 } 00411 00412 #endif 00413 00414 00415 00416 #ifndef LIBMESH_HAVE_EXODUS_API 00417 00418 void ExodusII_IO::write_nodal_data (const std::string& , 00419 const std::vector<Number>& , 00420 const std::vector<std::string>& ) 00421 { 00422 00423 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00424 << std::endl; 00425 libmesh_error(); 00426 } 00427 00428 #else 00429 void ExodusII_IO::write_discontinuous_exodusII (const std::string& name, 00430 const EquationSystems& es) 00431 { 00432 std::vector<std::string> solution_names; 00433 std::vector<Number> v; 00434 00435 es.build_variable_names (solution_names); 00436 es.build_discontinuous_solution_vector (v); 00437 00438 this->write_nodal_data_discontinuous(name, v, solution_names); 00439 } 00440 00441 00442 void ExodusII_IO::write_nodal_data_discontinuous (const std::string& fname, 00443 const std::vector<Number>& soln, 00444 const std::vector<std::string>& names) 00445 { 00446 START_LOG("write_nodal_data_discontinuous()", "ExodusII_IO"); 00447 00448 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00449 00450 int num_vars = libmesh_cast_int<int>(names.size()); 00451 int num_nodes = 0; 00452 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00453 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00454 for ( ; it != end; ++it) 00455 num_nodes += (*it)->n_nodes(); 00456 00457 // FIXME: Will we ever _not_ need to do this? 00458 // DRG: Yes... when writing multiple timesteps to the same file. 00459 if (!exio_helper->created()) 00460 { 00461 exio_helper->create(fname); 00462 exio_helper->initialize_discontinuous(fname,mesh); 00463 exio_helper->write_nodal_coordinates_discontinuous(mesh); 00464 exio_helper->write_elements_discontinuous(mesh); 00465 exio_helper->write_sidesets(mesh); 00466 exio_helper->write_nodesets(mesh); 00467 exio_helper->initialize_nodal_variables(names); 00468 } 00469 00470 if (libMesh::processor_id() == 0) 00471 for (int c=0; c<num_vars; c++) 00472 { 00473 //Copy out this variable's solution 00474 std::vector<Number> cur_soln(num_nodes); 00475 00476 for(int i=0; i<num_nodes; i++) 00477 cur_soln[i] = soln[i*num_vars + c];//c*num_nodes+i]; 00478 00479 exio_helper->write_nodal_values(c+1,cur_soln,_timestep); 00480 } 00481 00482 STOP_LOG("write_nodal_data_discontinuous()", "ExodusII_IO"); 00483 } 00484 00485 void ExodusII_IO::write_nodal_data (const std::string& fname, 00486 const std::vector<Number>& soln, 00487 const std::vector<std::string>& names) 00488 { 00489 START_LOG("write_nodal_data()", "ExodusII_IO"); 00490 00491 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00492 00493 int num_vars = libmesh_cast_int<int>(names.size()); 00494 dof_id_type num_nodes = mesh.n_nodes(); 00495 00496 // The names of the variables to be output 00497 std::vector<std::string> output_names; 00498 00499 if(_output_variables.size()) 00500 output_names = _output_variables; 00501 else 00502 output_names = names; 00503 00504 // FIXME: Will we ever _not_ need to do this? 00505 // DRG: Yes... when writing multiple timesteps to the same file. 00506 if (!exio_helper->created()) 00507 { 00508 exio_helper->create(fname); 00509 exio_helper->initialize(fname,mesh); 00510 exio_helper->write_nodal_coordinates(mesh); 00511 exio_helper->write_elements(mesh); 00512 exio_helper->write_sidesets(mesh); 00513 exio_helper->write_nodesets(mesh); 00514 exio_helper->initialize_nodal_variables(output_names); 00515 } 00516 00517 // This will count the number of variables actually output 00518 for (int c=0; c<num_vars; c++) 00519 { 00520 std::vector<std::string>::iterator pos = 00521 std::find(output_names.begin(), output_names.end(), names[c]); 00522 if (pos == output_names.end()) 00523 continue; 00524 00525 unsigned int variable_name_position = 00526 libmesh_cast_int<unsigned int>(pos - output_names.begin()); 00527 00528 std::vector<Number> cur_soln(num_nodes); 00529 00530 //Copy out this variable's solution 00531 for(dof_id_type i=0; i<num_nodes; i++) 00532 cur_soln[i] = soln[i*num_vars + c];//c*num_nodes+i]; 00533 00534 exio_helper->write_nodal_values(variable_name_position+1,cur_soln,_timestep); 00535 } 00536 00537 STOP_LOG("write_nodal_data()", "ExodusII_IO"); 00538 } 00539 00540 #endif 00541 00542 #ifndef LIBMESH_HAVE_EXODUS_API 00543 00544 void ExodusII_IO::write_information_records ( const std::vector<std::string>& ) 00545 { 00546 00547 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00548 << std::endl; 00549 libmesh_error(); 00550 } 00551 00552 #else 00553 00554 void ExodusII_IO::write_information_records (const std::vector<std::string>& records) 00555 { 00556 if (!exio_helper->created()) 00557 { 00558 libMesh::err << "ERROR, ExodusII file must be initialized " 00559 << "before outputting information records.\n" 00560 << std::endl; 00561 libmesh_error(); 00562 } 00563 00564 exio_helper->write_information_records( records ); 00565 } 00566 00567 #endif 00568 00569 #ifndef LIBMESH_HAVE_EXODUS_API 00570 00571 void ExodusII_IO::write_global_data (const std::vector<Number>& , 00572 const std::vector<std::string>& ) 00573 { 00574 00575 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00576 << std::endl; 00577 libmesh_error(); 00578 } 00579 00580 #else 00581 00582 void ExodusII_IO::write_global_data (const std::vector<Number>& soln, 00583 const std::vector<std::string>& names) 00584 { 00585 if (!exio_helper->created()) 00586 { 00587 libMesh::err << "ERROR, ExodusII file must be initialized " 00588 << "before outputting global variables.\n" 00589 << std::endl; 00590 libmesh_error(); 00591 } 00592 00593 exio_helper->initialize_global_variables( names ); 00594 exio_helper->write_global_values( soln, _timestep ); 00595 } 00596 00597 #endif 00598 00599 00600 #ifndef LIBMESH_HAVE_EXODUS_API 00601 00602 void ExodusII_IO::write_timestep (const std::string& , 00603 const EquationSystems& , 00604 const int , 00605 const Real ) 00606 { 00607 00608 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00609 << std::endl; 00610 libmesh_error(); 00611 } 00612 00613 #else 00614 00615 void ExodusII_IO::write_timestep (const std::string& fname, 00616 const EquationSystems& es, 00617 const int timestep, 00618 const Real time) 00619 { 00620 _timestep=timestep; 00621 write_equation_systems(fname,es); 00622 00623 exio_helper->write_timestep(timestep, time); 00624 } 00625 00626 #endif 00627 00628 00629 00630 #ifndef LIBMESH_HAVE_EXODUS_API 00631 00632 void ExodusII_IO::write (const std::string& ) 00633 { 00634 libMesh::err << "ERROR, ExodusII API is not defined.\n" 00635 << std::endl; 00636 libmesh_error(); 00637 } 00638 00639 00640 #else 00641 00642 void ExodusII_IO::write (const std::string& fname) 00643 { 00644 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00645 00646 // We may need to gather a ParallelMesh to output it, making that 00647 // const qualifier in our constructor a dirty lie 00648 MeshSerializer serialize(const_cast<MeshBase&>(mesh), !MeshOutput<MeshBase>::_is_parallel_format); 00649 00650 libmesh_assert( !exio_helper->created() ); 00651 00652 exio_helper->create(fname); 00653 exio_helper->initialize(fname,mesh); 00654 exio_helper->write_nodal_coordinates(mesh); 00655 exio_helper->write_elements(mesh); 00656 exio_helper->write_sidesets(mesh); 00657 exio_helper->write_nodesets(mesh); 00658 // Note: the file is closed automatically by the ExodusII_IO destructor. 00659 } 00660 00661 #endif 00662 00663 } // namespace libMesh
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:46 UTC
Hosted By: