$extrastylesheet
exodusII_io.C
Go to the documentation of this file.
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