$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 00019 // C++ includes 00020 #include <fstream> 00021 #include <cstring> 00022 #include <sstream> 00023 #include <map> 00024 00025 // Local includes 00026 #include "libmesh/exodusII_io.h" 00027 #include "libmesh/boundary_info.h" 00028 #include "libmesh/mesh_base.h" 00029 #include "libmesh/enum_elem_type.h" 00030 #include "libmesh/elem.h" 00031 #include "libmesh/equation_systems.h" 00032 #include "libmesh/libmesh_logging.h" 00033 #include "libmesh/system.h" 00034 #include "libmesh/numeric_vector.h" 00035 #include "libmesh/exodusII_io_helper.h" 00036 00037 namespace libMesh 00038 { 00039 00040 // ------------------------------------------------------------ 00041 // ExodusII_IO class members 00042 ExodusII_IO::ExodusII_IO (MeshBase& mesh, 00043 #ifdef LIBMESH_HAVE_EXODUS_API 00044 bool single_precision 00045 #else 00046 bool 00047 #endif 00048 ) : 00049 MeshInput<MeshBase> (mesh), 00050 MeshOutput<MeshBase> (mesh), 00051 ParallelObject(mesh), 00052 #ifdef LIBMESH_HAVE_EXODUS_API 00053 exio_helper(new ExodusII_IO_Helper(*this, false, true, single_precision)), 00054 #endif 00055 _timestep(1), 00056 _verbose(false), 00057 _append(false), 00058 _allow_empty_variables(false) 00059 { 00060 } 00061 00062 00063 void ExodusII_IO::set_output_variables(const std::vector<std::string>& output_variables, 00064 bool allow_empty) 00065 { 00066 _output_variables = output_variables; 00067 _allow_empty_variables = allow_empty; 00068 } 00069 00070 00071 00072 void ExodusII_IO::copy_nodal_solution(System& system, 00073 std::string var_name, 00074 unsigned int timestep) 00075 { 00076 libmesh_deprecated(); 00077 copy_nodal_solution(system, var_name, var_name, timestep); 00078 } 00079 00080 00081 00082 void ExodusII_IO::write_discontinuous_exodusII(const std::string& name, 00083 const EquationSystems& es, 00084 const std::set<std::string>* system_names) 00085 { 00086 std::vector<std::string> solution_names; 00087 std::vector<Number> v; 00088 00089 es.build_variable_names (solution_names, NULL, system_names); 00090 es.build_discontinuous_solution_vector (v, system_names); 00091 00092 this->write_nodal_data_discontinuous(name, v, solution_names); 00093 } 00094 00095 00096 00097 00098 // ------------------------------------------------------------ 00099 // When the Exodus API is present... 00100 #ifdef LIBMESH_HAVE_EXODUS_API 00101 00102 ExodusII_IO::~ExodusII_IO () 00103 { 00104 exio_helper->close(); 00105 delete exio_helper; 00106 } 00107 00108 00109 00110 void ExodusII_IO::read (const std::string& fname) 00111 { 00112 // Get a reference to the mesh we are reading 00113 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 00114 00115 // Clear any existing mesh data 00116 mesh.clear(); 00117 00118 // Keep track of what kinds of elements this file contains 00119 elems_of_dimension.clear(); 00120 elems_of_dimension.resize(4, false); 00121 00122 #ifdef DEBUG 00123 this->verbose(true); 00124 #endif 00125 00126 // Instantiate the ElementMaps interface 00127 ExodusII_IO_Helper::ElementMaps em; 00128 00129 // Open the exodus file in EX_READ mode 00130 exio_helper->open(fname.c_str(), /*read_only=*/true); 00131 00132 // Get header information from exodus file 00133 exio_helper->read_header(); 00134 00135 // Print header information 00136 exio_helper->print_header(); 00137 00138 // Read nodes from the exodus file 00139 exio_helper->read_nodes(); 00140 00141 // Reserve space for the nodes. 00142 mesh.reserve_nodes(exio_helper->num_nodes); 00143 00144 // Read the node number map from the Exodus file. This is 00145 // required if we want to preserve the numbering of nodes as it 00146 // exists in the Exodus file. If the Exodus file does not contain 00147 // a node_num_map, the identity map is returned by this call. 00148 exio_helper->read_node_num_map(); 00149 00150 // Loop over the nodes, create Nodes with local processor_id 0. 00151 for (int i=0; i<exio_helper->num_nodes; i++) 00152 { 00153 // Use the node_num_map to get the correct ID for Exodus 00154 int exodus_id = exio_helper->node_num_map[i]; 00155 00156 // Catch the node that was added to the mesh 00157 Node* added_node = mesh.add_point (Point(exio_helper->x[i], exio_helper->y[i], exio_helper->z[i]), exodus_id-1); 00158 00159 // If the Mesh assigned an ID different from what is in the 00160 // Exodus file, we should probably error. 00161 if (added_node->id() != static_cast<unsigned>(exodus_id-1)) 00162 libmesh_error_msg("Error! Mesh assigned node ID " \ 00163 << added_node->id() \ 00164 << " which is different from the (zero-based) Exodus ID " \ 00165 << exodus_id-1 \ 00166 << "!"); 00167 } 00168 00169 // This assert is no longer valid if the nodes are not numbered 00170 // sequentially starting from 1 in the Exodus file. 00171 // libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->num_nodes), mesh.n_nodes()); 00172 00173 // Get information about all the blocks 00174 exio_helper->read_block_info(); 00175 00176 // Reserve space for the elements 00177 mesh.reserve_elem(exio_helper->num_elem); 00178 00179 // Read the element number map from the Exodus file. This is 00180 // required if we want to preserve the numbering of elements as it 00181 // exists in the Exodus file. If the Exodus file does not contain 00182 // an elem_num_map, the identity map is returned by this call. 00183 exio_helper->read_elem_num_map(); 00184 00185 // Read in the element connectivity for each block. 00186 int nelem_last_block = 0; 00187 00188 // Loop over all the blocks 00189 for (int i=0; i<exio_helper->num_elem_blk; i++) 00190 { 00191 // Read the information for block i 00192 exio_helper->read_elem_in_block (i); 00193 int subdomain_id = exio_helper->get_block_id(i); 00194 00195 // populate the map of names 00196 std::string subdomain_name = exio_helper->get_block_name(i); 00197 if (!subdomain_name.empty()) 00198 mesh.subdomain_name(static_cast<subdomain_id_type>(subdomain_id)) = subdomain_name; 00199 00200 // Set any relevant node/edge maps for this element 00201 const std::string type_str (exio_helper->get_elem_type()); 00202 const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(type_str); 00203 00204 // Loop over all the faces in this block 00205 int jmax = nelem_last_block+exio_helper->num_elem_this_blk; 00206 for (int j=nelem_last_block; j<jmax; j++) 00207 { 00208 Elem* elem = Elem::build (conv.get_canonical_type()).release(); 00209 libmesh_assert (elem); 00210 elem->subdomain_id() = static_cast<subdomain_id_type>(subdomain_id) ; 00211 00212 // Use the elem_num_map to obtain the ID of this element in the Exodus file 00213 int exodus_id = exio_helper->elem_num_map[j]; 00214 00215 // Assign this element the same ID it had in the Exodus 00216 // file, but make it zero-based by subtracting 1. Note: 00217 // some day we could use 1-based numbering in libmesh and 00218 // thus match the Exodus numbering exactly, but at the 00219 // moment libmesh is zero-based. 00220 elem->set_id(exodus_id-1); 00221 00222 // Record that we have seen an element of dimension elem->dim() 00223 elems_of_dimension[elem->dim()] = true; 00224 00225 // Catch the Elem pointer that the Mesh throws back 00226 elem = mesh.add_elem (elem); 00227 00228 // If the Mesh assigned an ID different from what is in the 00229 // Exodus file, we should probably error. 00230 if (elem->id() != static_cast<unsigned>(exodus_id-1)) 00231 libmesh_error_msg("Error! Mesh assigned ID " \ 00232 << elem->id() \ 00233 << " which is different from the (zero-based) Exodus ID " \ 00234 << exodus_id-1 \ 00235 << "!"); 00236 00237 // Set all the nodes for this element 00238 for (int k=0; k<exio_helper->num_nodes_per_elem; k++) 00239 { 00240 // global index 00241 int gi = (j-nelem_last_block)*exio_helper->num_nodes_per_elem + conv.get_node_map(k); 00242 00243 // The entries in 'connect' are actually (1-based) 00244 // indices into the node_num_map, so to get the right 00245 // node ID we: 00246 // 1.) Subtract 1 from connect[gi] 00247 // 2.) Pass it through node_num_map to get the corresponding Exodus ID 00248 // 3.) Subtract 1 from that, since libmesh node numbering is "zero"-based, 00249 // even when the Exodus node numbering doesn't start with 1. 00250 int libmesh_node_id = exio_helper->node_num_map[exio_helper->connect[gi] - 1] - 1; 00251 00252 // Set the node pointer in the Elem 00253 elem->set_node(k) = mesh.node_ptr(libmesh_node_id); 00254 } 00255 } 00256 00257 // running sum of # of elements per block, 00258 // (should equal total number of elements in the end) 00259 nelem_last_block += exio_helper->num_elem_this_blk; 00260 } 00261 00262 // This assert isn't valid if the Exodus file's numbering doesn't 00263 // start with 1! For example, if Exodus's elem_num_map is 21, 22, 00264 // 23, 24, 25, 26, 27, 28, 29, 30, ... 84, then by the time you are 00265 // done with the loop above, mesh.n_elem() will report 84 and 00266 // nelem_last_block will be 64. 00267 // libmesh_assert_equal_to (static_cast<unsigned>(nelem_last_block), mesh.n_elem()); 00268 00269 // Set the mesh dimension to the largest encountered for an element 00270 for (unsigned char i=0; i!=4; ++i) 00271 if (elems_of_dimension[i]) 00272 mesh.set_mesh_dimension(i); 00273 00274 // Read in sideset information -- this is useful for applying boundary conditions 00275 { 00276 // Get basic information about all sidesets 00277 exio_helper->read_sideset_info(); 00278 int offset=0; 00279 for (int i=0; i<exio_helper->num_side_sets; i++) 00280 { 00281 // Compute new offset 00282 offset += (i > 0 ? exio_helper->num_sides_per_set[i-1] : 0); 00283 exio_helper->read_sideset (i, offset); 00284 00285 std::string sideset_name = exio_helper->get_side_set_name(i); 00286 if (!sideset_name.empty()) 00287 mesh.get_boundary_info().sideset_name 00288 (cast_int<boundary_id_type>(exio_helper->get_side_set_id(i))) 00289 = sideset_name; 00290 } 00291 00292 for (unsigned int e=0; e<exio_helper->elem_list.size(); e++) 00293 { 00294 // The numbers in the Exodus file sidesets should be thought 00295 // of as (1-based) indices into the elem_num_map array. So, 00296 // to get the right element ID we have to: 00297 // 1.) Subtract 1 from elem_list[e] (to get a zero-based index) 00298 // 2.) Pass it through elem_num_map (to get the corresponding Exodus ID) 00299 // 3.) Subtract 1 from that, since libmesh is "zero"-based, 00300 // even when the Exodus numbering doesn't start with 1. 00301 dof_id_type libmesh_elem_id = 00302 cast_int<dof_id_type>(exio_helper->elem_num_map[exio_helper->elem_list[e] - 1] - 1); 00303 00304 // Set any relevant node/edge maps for this element 00305 Elem * elem = mesh.elem(libmesh_elem_id); 00306 00307 const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(elem->type()); 00308 00309 // Add this (elem,side,id) triplet to the BoundaryInfo object. 00310 mesh.get_boundary_info().add_side 00311 (libmesh_elem_id, 00312 cast_int<unsigned short>(conv.get_side_map(exio_helper->side_list[e]-1)), 00313 cast_int<boundary_id_type>(exio_helper->id_list[e])); 00314 } 00315 } 00316 00317 // Read nodeset info 00318 { 00319 exio_helper->read_nodeset_info(); 00320 00321 for (int nodeset=0; nodeset<exio_helper->num_node_sets; nodeset++) 00322 { 00323 boundary_id_type nodeset_id = 00324 cast_int<boundary_id_type>(exio_helper->nodeset_ids[nodeset]); 00325 00326 std::string nodeset_name = exio_helper->get_node_set_name(nodeset); 00327 if (!nodeset_name.empty()) 00328 mesh.get_boundary_info().nodeset_name(nodeset_id) = nodeset_name; 00329 00330 exio_helper->read_nodeset(nodeset); 00331 00332 for (unsigned int node=0; node<exio_helper->node_list.size(); node++) 00333 { 00334 // As before, the entries in 'node_list' are 1-based 00335 // indcies into the node_num_map array, so we have to map 00336 // them. See comment above. 00337 int libmesh_node_id = exio_helper->node_num_map[exio_helper->node_list[node] - 1] - 1; 00338 mesh.get_boundary_info().add_node(cast_int<dof_id_type>(libmesh_node_id), 00339 nodeset_id); 00340 } 00341 } 00342 } 00343 00344 #if LIBMESH_DIM < 3 00345 if (mesh.mesh_dimension() > LIBMESH_DIM) 00346 libmesh_error_msg("Cannot open dimension " \ 00347 << mesh.mesh_dimension() \ 00348 << " mesh file when configured without " \ 00349 << mesh.mesh_dimension() \ 00350 << "D support."); 00351 #endif 00352 } 00353 00354 00355 00356 void ExodusII_IO::verbose (bool set_verbosity) 00357 { 00358 _verbose = set_verbosity; 00359 00360 // Set the verbose flag in the helper object as well. 00361 exio_helper->verbose = _verbose; 00362 } 00363 00364 00365 00366 void ExodusII_IO::use_mesh_dimension_instead_of_spatial_dimension(bool val) 00367 { 00368 exio_helper->use_mesh_dimension_instead_of_spatial_dimension(val); 00369 } 00370 00371 00372 00373 void ExodusII_IO::set_coordinate_offset(Point p) 00374 { 00375 libmesh_deprecated(); 00376 exio_helper->set_coordinate_offset(p); 00377 } 00378 00379 00380 00381 void ExodusII_IO::append(bool val) 00382 { 00383 _append = val; 00384 } 00385 00386 00387 00388 const std::vector<Real>& ExodusII_IO::get_time_steps() 00389 { 00390 if (!exio_helper->opened_for_reading) 00391 libmesh_error_msg("ERROR, ExodusII file must be opened for reading before calling ExodusII_IO::get_time_steps()!"); 00392 00393 exio_helper->read_time_steps(); 00394 return exio_helper->time_steps; 00395 } 00396 00397 00398 00399 int ExodusII_IO::get_num_time_steps() 00400 { 00401 if (!exio_helper->opened_for_reading && !exio_helper->opened_for_writing) 00402 libmesh_error_msg("ERROR, ExodusII file must be opened for reading or writing before calling ExodusII_IO::get_num_time_steps()!"); 00403 00404 exio_helper->read_num_time_steps(); 00405 return exio_helper->num_time_steps; 00406 } 00407 00408 00409 00410 void ExodusII_IO::copy_nodal_solution(System& system, 00411 std::string system_var_name, 00412 std::string exodus_var_name, 00413 unsigned int timestep) 00414 { 00415 if (!exio_helper->opened_for_reading) 00416 libmesh_error_msg("ERROR, ExodusII file must be opened for reading before copying a nodal solution!"); 00417 00418 exio_helper->read_nodal_var_values(exodus_var_name, timestep); 00419 00420 const unsigned int var_num = system.variable_number(system_var_name); 00421 00422 for (unsigned int i=0; i<exio_helper->nodal_var_values.size(); ++i) 00423 { 00424 const Node* node = MeshInput<MeshBase>::mesh().query_node_ptr(i); 00425 00426 if (!node) 00427 libmesh_error_msg("Error! Mesh returned NULL pointer for node " << i); 00428 00429 dof_id_type dof_index = node->dof_number(system.number(), var_num, 0); 00430 00431 // If the dof_index is local to this processor, set the value 00432 if ((dof_index >= system.solution->first_local_index()) && (dof_index < system.solution->last_local_index())) 00433 system.solution->set (dof_index, exio_helper->nodal_var_values[i]); 00434 } 00435 00436 system.solution->close(); 00437 system.update(); 00438 } 00439 00440 00441 00442 void ExodusII_IO::copy_elemental_solution(System& system, 00443 std::string system_var_name, 00444 std::string exodus_var_name, 00445 unsigned int timestep) 00446 { 00447 if (!exio_helper->opened_for_reading) 00448 libmesh_error_msg("ERROR, ExodusII file must be opened for reading before copying an elemental solution!"); 00449 00450 exio_helper->read_elemental_var_values(exodus_var_name, timestep); 00451 00452 const unsigned int var_num = system.variable_number(system_var_name); 00453 if (system.variable_type(var_num) != FEType(CONSTANT, MONOMIAL)) 00454 libmesh_error_msg("Error! Trying to copy elemental solution into a variable that is not of CONSTANT MONOMIAL type."); 00455 00456 for (unsigned int i=0; i<exio_helper->elem_var_values.size(); ++i) 00457 { 00458 const Elem * elem = MeshInput<MeshBase>::mesh().query_elem(i); 00459 00460 if (!elem) 00461 libmesh_error_msg("Error! Mesh returned NULL pointer for elem " << i); 00462 00463 dof_id_type dof_index = elem->dof_number(system.number(), var_num, 0); 00464 00465 // If the dof_index is local to this processor, set the value 00466 if ((dof_index >= system.solution->first_local_index()) && (dof_index < system.solution->last_local_index())) 00467 system.solution->set (dof_index, exio_helper->elem_var_values[i]); 00468 } 00469 00470 system.solution->close(); 00471 system.update(); 00472 } 00473 00474 00475 00476 void ExodusII_IO::write_element_data (const EquationSystems & es) 00477 { 00478 // Be sure the file has been opened for writing! 00479 if (MeshOutput<MeshBase>::mesh().processor_id() == 0 && !exio_helper->opened_for_writing) 00480 libmesh_error_msg("ERROR, ExodusII file must be initialized before outputting element variables."); 00481 00482 // This function currently only works on SerialMeshes. We rely on 00483 // having a reference to a non-const MeshBase object from our 00484 // MeshInput parent class to construct a MeshSerializer object, 00485 // similar to what is done in ExodusII_IO::write(). Note that 00486 // calling ExodusII_IO::write_timestep() followed by 00487 // ExodusII_IO::write_element_data() when the underlying Mesh is a 00488 // ParallelMesh will result in an unnecessary additional 00489 // serialization/re-parallelization step. 00490 MeshSerializer serialize(MeshInput<MeshBase>::mesh(), !MeshOutput<MeshBase>::_is_parallel_format); 00491 00492 // To be (possibly) filled with a filtered list of variable names to output. 00493 std::vector<std::string> names; 00494 00495 // If _output_variables is populated, only output the monomials which are 00496 // also in the _output_variables vector. 00497 if (_output_variables.size() > 0) 00498 { 00499 std::vector<std::string> monomials; 00500 const FEType type(CONSTANT, MONOMIAL); 00501 00502 // Create a list of monomial variable names 00503 es.build_variable_names(monomials, &type); 00504 00505 // Filter that list against the _output_variables list. Note: if names is still empty after 00506 // all this filtering, all the monomial variables will be gathered 00507 std::vector<std::string>::iterator it = monomials.begin(); 00508 for (; it!=monomials.end(); ++it) 00509 if (std::find(_output_variables.begin(), _output_variables.end(), *it) != _output_variables.end()) 00510 names.push_back(*it); 00511 } 00512 00513 // If we pass in a list of names to "get_solution" it'll filter the variables coming back 00514 std::vector<Number> soln; 00515 es.get_solution(soln, names); 00516 00517 if(soln.empty()) // If there is nothing to write just return 00518 return; 00519 00520 // The data must ultimately be written block by block. This means that this data 00521 // must be sorted appropriately. 00522 if(MeshOutput<MeshBase>::mesh().processor_id()) 00523 return; 00524 00525 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00526 00527 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00528 00529 std::vector<std::string> complex_names = exio_helper->get_complex_names(names); 00530 00531 exio_helper->initialize_element_variables(complex_names); 00532 00533 unsigned int num_values = soln.size(); 00534 unsigned int num_vars = names.size(); 00535 unsigned int num_elems = num_values / num_vars; 00536 00537 // This will contain the real and imaginary parts and the magnitude 00538 // of the values in soln 00539 std::vector<Real> complex_soln(3*num_values); 00540 00541 for (unsigned i=0; i<num_vars; ++i) 00542 { 00543 00544 for (unsigned int j=0; j<num_elems; ++j) 00545 { 00546 Number value = soln[i*num_vars + j]; 00547 complex_soln[3*i*num_elems + j] = value.real(); 00548 } 00549 for (unsigned int j=0; j<num_elems; ++j) 00550 { 00551 Number value = soln[i*num_vars + j]; 00552 complex_soln[3*i*num_elems + num_elems +j] = value.imag(); 00553 } 00554 for (unsigned int j=0; j<num_elems; ++j) 00555 { 00556 Number value = soln[i*num_vars + j]; 00557 complex_soln[3*i*num_elems + 2*num_elems + j] = std::abs(value); 00558 } 00559 } 00560 00561 exio_helper->write_element_values(mesh, complex_soln, _timestep); 00562 00563 #else 00564 exio_helper->initialize_element_variables(names); 00565 exio_helper->write_element_values(mesh, soln, _timestep); 00566 #endif 00567 } 00568 00569 00570 00571 void ExodusII_IO::write_nodal_data (const std::string& fname, 00572 const std::vector<Number>& soln, 00573 const std::vector<std::string>& names) 00574 { 00575 START_LOG("write_nodal_data()", "ExodusII_IO"); 00576 00577 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00578 00579 int num_vars = cast_int<int>(names.size()); 00580 dof_id_type num_nodes = mesh.n_nodes(); 00581 00582 // The names of the variables to be output 00583 std::vector<std::string> output_names; 00584 00585 if(_allow_empty_variables || !_output_variables.empty()) 00586 output_names = _output_variables; 00587 else 00588 output_names = names; 00589 00590 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00591 00592 std::vector<std::string> complex_names = exio_helper->get_complex_names(names); 00593 00594 // Call helper function for opening/initializing data, giving it the 00595 // complex variable names 00596 this->write_nodal_data_common(fname, complex_names, /*continuous=*/true); 00597 #else 00598 // Call helper function for opening/initializing data 00599 this->write_nodal_data_common(fname, output_names, /*continuous=*/true); 00600 #endif 00601 00602 if(mesh.processor_id()) 00603 { 00604 STOP_LOG("write_nodal_data()", "ExodusII_IO"); 00605 return; 00606 } 00607 00608 // This will count the number of variables actually output 00609 for (int c=0; c<num_vars; c++) 00610 { 00611 std::stringstream name_to_find; 00612 00613 std::vector<std::string>::iterator pos = 00614 std::find(output_names.begin(), output_names.end(), names[c]); 00615 if (pos == output_names.end()) 00616 continue; 00617 00618 unsigned int variable_name_position = 00619 cast_int<unsigned int>(pos - output_names.begin()); 00620 00621 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00622 std::vector<Real> real_parts(num_nodes); 00623 std::vector<Real> imag_parts(num_nodes); 00624 std::vector<Real> magnitudes(num_nodes); 00625 00626 for (unsigned int i=0; i<num_nodes; ++i) 00627 { 00628 real_parts[i] = soln[i*num_vars + c].real(); 00629 imag_parts[i] = soln[i*num_vars + c].imag(); 00630 magnitudes[i] = std::abs(soln[i*num_vars + c]); 00631 } 00632 exio_helper->write_nodal_values(3*variable_name_position+1,real_parts,_timestep); 00633 exio_helper->write_nodal_values(3*variable_name_position+2,imag_parts,_timestep); 00634 exio_helper->write_nodal_values(3*variable_name_position+3,magnitudes,_timestep); 00635 #else 00636 std::vector<Number> cur_soln(num_nodes); 00637 00638 // Copy out this variable's solution 00639 for (dof_id_type i=0; i<num_nodes; i++) 00640 cur_soln[i] = soln[i*num_vars + c]; 00641 exio_helper->write_nodal_values(variable_name_position+1,cur_soln,_timestep); 00642 #endif 00643 00644 } 00645 00646 STOP_LOG("write_nodal_data()", "ExodusII_IO"); 00647 } 00648 00649 00650 00651 00652 void ExodusII_IO::write_information_records (const std::vector<std::string>& records) 00653 { 00654 if(MeshOutput<MeshBase>::mesh().processor_id()) 00655 return; 00656 00657 if (!exio_helper->opened_for_writing) 00658 libmesh_error_msg("ERROR, ExodusII file must be initialized before outputting information records."); 00659 00660 exio_helper->write_information_records(records); 00661 } 00662 00663 00664 00665 void ExodusII_IO::write_global_data (const std::vector<Number>& soln, 00666 const std::vector<std::string>& names) 00667 { 00668 if(MeshOutput<MeshBase>::mesh().processor_id()) 00669 return; 00670 00671 if (!exio_helper->opened_for_writing) 00672 libmesh_error_msg("ERROR, ExodusII file must be initialized before outputting global variables."); 00673 00674 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00675 00676 std::vector<std::string> complex_names = exio_helper->get_complex_names(names); 00677 00678 exio_helper->initialize_global_variables(complex_names); 00679 00680 unsigned int num_values = soln.size(); 00681 unsigned int num_vars = names.size(); 00682 unsigned int num_elems = num_values / num_vars; 00683 00684 // This will contain the real and imaginary parts and the magnitude 00685 // of the values in soln 00686 std::vector<Real> complex_soln(3*num_values); 00687 00688 for (unsigned i=0; i<num_vars; ++i) 00689 { 00690 00691 for (unsigned int j=0; j<num_elems; ++j) 00692 { 00693 Number value = soln[i*num_vars + j]; 00694 complex_soln[3*i*num_elems + j] = value.real(); 00695 } 00696 for (unsigned int j=0; j<num_elems; ++j) 00697 { 00698 Number value = soln[i*num_vars + j]; 00699 complex_soln[3*i*num_elems + num_elems +j] = value.imag(); 00700 } 00701 for (unsigned int j=0; j<num_elems; ++j) 00702 { 00703 Number value = soln[i*num_vars + j]; 00704 complex_soln[3*i*num_elems + 2*num_elems + j] = std::abs(value); 00705 } 00706 } 00707 00708 exio_helper->write_global_values(complex_soln, _timestep); 00709 00710 #else 00711 exio_helper->initialize_global_variables(names); 00712 exio_helper->write_global_values(soln, _timestep); 00713 #endif 00714 } 00715 00716 00717 00718 void ExodusII_IO::write_timestep (const std::string& fname, 00719 const EquationSystems& es, 00720 const int timestep, 00721 const Real time) 00722 { 00723 _timestep = timestep; 00724 write_equation_systems(fname,es); 00725 00726 if(MeshOutput<MeshBase>::mesh().processor_id()) 00727 return; 00728 00729 exio_helper->write_timestep(timestep, time); 00730 } 00731 00732 00733 00734 void ExodusII_IO::write (const std::string& fname) 00735 { 00736 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00737 00738 // We may need to gather a ParallelMesh to output it, making that 00739 // const qualifier in our constructor a dirty lie 00740 MeshSerializer serialize(const_cast<MeshBase&>(mesh), !MeshOutput<MeshBase>::_is_parallel_format); 00741 00742 libmesh_assert( !exio_helper->opened_for_writing ); 00743 00744 // If the user has set the append flag here, it doesn't really make 00745 // sense: the intent of this function is to write a Mesh with no 00746 // data, while "appending" is really intended to add data to an 00747 // existing file. If we're verbose, print a message to this effect. 00748 if (_append && _verbose) 00749 libMesh::out << "Warning: Appending in ExodusII_IO::write() does not make sense.\n" 00750 << "Creating a new file instead!" 00751 << std::endl; 00752 00753 exio_helper->create(fname); 00754 exio_helper->initialize(fname,mesh); 00755 exio_helper->write_nodal_coordinates(mesh); 00756 exio_helper->write_elements(mesh); 00757 exio_helper->write_sidesets(mesh); 00758 exio_helper->write_nodesets(mesh); 00759 00760 if(MeshOutput<MeshBase>::mesh().processor_id()) 00761 return; 00762 00763 if( (mesh.get_boundary_info().n_edge_conds() > 0) && 00764 _verbose ) 00765 { 00766 libMesh::out << "Warning: Mesh contains edge boundary IDs, but these " 00767 << "are not supported by the ExodusII format." 00768 << std::endl; 00769 } 00770 } 00771 00772 00773 00774 void ExodusII_IO::write_nodal_data_discontinuous (const std::string& fname, 00775 const std::vector<Number>& soln, 00776 const std::vector<std::string>& names) 00777 { 00778 00779 START_LOG("write_nodal_data_discontinuous()", "ExodusII_IO"); 00780 00781 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00782 00783 int num_vars = cast_int<int>(names.size()); 00784 int num_nodes = 0; 00785 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00786 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00787 for ( ; it != end; ++it) 00788 num_nodes += (*it)->n_nodes(); 00789 00790 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00791 00792 std::vector<std::string> complex_names = exio_helper->get_complex_names(names); 00793 00794 // Call helper function for opening/initializing data, giving it the 00795 // complex variable names 00796 this->write_nodal_data_common(fname, complex_names, /*continuous=*/false); 00797 #else 00798 // Call helper function for opening/initializing data 00799 this->write_nodal_data_common(fname, names, /*continuous=*/false); 00800 #endif 00801 00802 if (mesh.processor_id()) 00803 { 00804 STOP_LOG("write_nodal_data_discontinuous()", "ExodusII_IO"); 00805 return; 00806 } 00807 00808 for (int c=0; c<num_vars; c++) 00809 { 00810 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 00811 std::vector<Real> real_parts(num_nodes); 00812 std::vector<Real> imag_parts(num_nodes); 00813 std::vector<Real> magnitudes(num_nodes); 00814 00815 for (int i=0; i<num_nodes; ++i) 00816 { 00817 real_parts[i] = soln[i*num_vars + c].real(); 00818 imag_parts[i] = soln[i*num_vars + c].imag(); 00819 magnitudes[i] = std::abs(soln[i*num_vars + c]); 00820 } 00821 exio_helper->write_nodal_values(3*c+1,real_parts,_timestep); 00822 exio_helper->write_nodal_values(3*c+2,imag_parts,_timestep); 00823 exio_helper->write_nodal_values(3*c+3,magnitudes,_timestep); 00824 #else 00825 // Copy out this variable's solution 00826 std::vector<Number> cur_soln(num_nodes); 00827 00828 for (int i=0; i<num_nodes; i++) 00829 cur_soln[i] = soln[i*num_vars + c]; 00830 00831 exio_helper->write_nodal_values(c+1,cur_soln,_timestep); 00832 #endif 00833 } 00834 00835 STOP_LOG("write_nodal_data_discontinuous()", "ExodusII_IO"); 00836 } 00837 00838 00839 00840 void ExodusII_IO::write_nodal_data_common(std::string fname, 00841 const std::vector<std::string>& names, 00842 bool continuous) 00843 { 00844 const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); 00845 00846 // This function can be called multiple times, we only want to open 00847 // the ExodusII file the first time it's called. 00848 if (!exio_helper->opened_for_writing) 00849 { 00850 // If we're appending, open() the file with read_only=false, 00851 // otherwise create() it and write the contents of the mesh to 00852 // it. 00853 if (_append) 00854 { 00855 exio_helper->open(fname.c_str(), /*read_only=*/false); 00856 // If we're appending, it's not valid to call exio_helper->initialize() 00857 // or exio_helper->initialize_nodal_variables(), but we do need to set up 00858 // certain aspects of the Helper object itself, such as the number of nodes 00859 // and elements. We do that by reading the header... 00860 exio_helper->read_header(); 00861 00862 // ...and reading the block info 00863 exio_helper->read_block_info(); 00864 } 00865 else 00866 { 00867 exio_helper->create(fname); 00868 00869 exio_helper->initialize(fname, mesh, !continuous); 00870 exio_helper->write_nodal_coordinates(mesh, !continuous); 00871 exio_helper->write_elements(mesh, !continuous); 00872 00873 exio_helper->write_sidesets(mesh); 00874 exio_helper->write_nodesets(mesh); 00875 00876 if( (mesh.get_boundary_info().n_edge_conds() > 0) && 00877 _verbose ) 00878 { 00879 libMesh::out << "Warning: Mesh contains edge boundary IDs, but these " 00880 << "are not supported by the ExodusII format." 00881 << std::endl; 00882 } 00883 00884 exio_helper->initialize_nodal_variables(names); 00885 } 00886 } 00887 else 00888 { 00889 // We are already open for writing, so check that the filename 00890 // passed to this function matches the filename currently in use 00891 // by the helper. 00892 if (fname != exio_helper->current_filename) 00893 libmesh_error_msg("Error! This ExodusII_IO object is already associated with file: " \ 00894 << exio_helper->current_filename \ 00895 << ", cannot use it with requested file: " \ 00896 << fname); 00897 } 00898 } 00899 00900 const std::vector<std::string> & ExodusII_IO::get_nodal_var_names() 00901 { 00902 exio_helper->read_var_names(ExodusII_IO_Helper::NODAL); 00903 return exio_helper->nodal_var_names; 00904 } 00905 00906 const std::vector<std::string> & ExodusII_IO::get_elem_var_names() 00907 { 00908 exio_helper->read_var_names(ExodusII_IO_Helper::ELEMENTAL); 00909 return exio_helper->elem_var_names; 00910 } 00911 00912 00913 // LIBMESH_HAVE_EXODUS_API is not defined, declare error() versions of functions... 00914 #else 00915 00916 00917 00918 ExodusII_IO::~ExodusII_IO () 00919 { 00920 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00921 } 00922 00923 00924 00925 void ExodusII_IO::read (const std::string&) 00926 { 00927 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00928 } 00929 00930 00931 00932 void ExodusII_IO::verbose (bool) 00933 { 00934 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00935 } 00936 00937 00938 00939 void ExodusII_IO::use_mesh_dimension_instead_of_spatial_dimension(bool) 00940 { 00941 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00942 } 00943 00944 00945 00946 void ExodusII_IO::set_coordinate_offset(Point) 00947 { 00948 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00949 } 00950 00951 00952 00953 void ExodusII_IO::append(bool) 00954 { 00955 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00956 } 00957 00958 00959 00960 const std::vector<Real>& ExodusII_IO::get_time_steps() 00961 { 00962 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00963 } 00964 00965 00966 00967 int ExodusII_IO::get_num_time_steps() 00968 { 00969 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00970 } 00971 00972 00973 void ExodusII_IO::copy_nodal_solution(System&, std::string, std::string, unsigned int) 00974 { 00975 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00976 } 00977 00978 00979 00980 void ExodusII_IO::copy_elemental_solution(System&, std::string, std::string, unsigned int) 00981 { 00982 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00983 } 00984 00985 00986 00987 void ExodusII_IO::write_element_data (const EquationSystems&) 00988 { 00989 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00990 } 00991 00992 00993 00994 void ExodusII_IO::write_nodal_data (const std::string&, const std::vector<Number>&, const std::vector<std::string>&) 00995 { 00996 libmesh_error_msg("ERROR, ExodusII API is not defined."); 00997 } 00998 00999 01000 01001 void ExodusII_IO::write_information_records (const std::vector<std::string>&) 01002 { 01003 libmesh_error_msg("ERROR, ExodusII API is not defined."); 01004 } 01005 01006 01007 01008 void ExodusII_IO::write_global_data (const std::vector<Number>&, const std::vector<std::string>&) 01009 { 01010 libmesh_error_msg("ERROR, ExodusII API is not defined."); 01011 } 01012 01013 01014 01015 void ExodusII_IO::write_timestep (const std::string&, const EquationSystems&, const int, const Real) 01016 { 01017 libmesh_error_msg("ERROR, ExodusII API is not defined."); 01018 } 01019 01020 01021 01022 void ExodusII_IO::write (const std::string&) 01023 { 01024 libmesh_error_msg("ERROR, ExodusII API is not defined."); 01025 } 01026 01027 01028 01029 void ExodusII_IO::write_nodal_data_discontinuous (const std::string&, const std::vector<Number>&, const std::vector<std::string>&) 01030 { 01031 libmesh_error_msg("ERROR, ExodusII API is not defined."); 01032 } 01033 01034 01035 01036 void ExodusII_IO::write_nodal_data_common(std::string, 01037 const std::vector<std::string>&, 01038 bool) 01039 { 01040 libmesh_error_msg("ERROR, ExodusII API is not defined."); 01041 } 01042 01043 01044 const std::vector<std::string> & ExodusII_IO::get_elem_var_names() 01045 { 01046 libmesh_error_msg("ERROR, ExodusII API is not defined."); 01047 } 01048 01049 const std::vector<std::string> & ExodusII_IO::get_nodal_var_names() 01050 { 01051 libmesh_error_msg("ERROR, ExodusII API is not defined."); 01052 } 01053 01054 #endif // LIBMESH_HAVE_EXODUS_API 01055 } // namespace libMesh