$extrastylesheet
unv_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 <iomanip>
00021 #include <algorithm> // for std::sort
00022 #include <fstream>
00023 #include <ctype.h> // isspace
00024 #include <sstream> // std::istringstream
00025 
00026 // Local includes
00027 #include "libmesh/libmesh_config.h"
00028 #include "libmesh/libmesh_logging.h"
00029 #include "libmesh/unv_io.h"
00030 #include "libmesh/mesh_data.h"
00031 #include "libmesh/mesh_base.h"
00032 #include "libmesh/edge_edge2.h"
00033 #include "libmesh/face_quad4.h"
00034 #include "libmesh/face_tri3.h"
00035 #include "libmesh/face_tri6.h"
00036 #include "libmesh/face_quad8.h"
00037 #include "libmesh/face_quad9.h"
00038 #include "libmesh/cell_tet4.h"
00039 #include "libmesh/cell_hex8.h"
00040 #include "libmesh/cell_hex20.h"
00041 #include "libmesh/cell_tet10.h"
00042 #include "libmesh/cell_prism6.h"
00043 
00044 #ifdef LIBMESH_HAVE_GZSTREAM
00045 # include "gzstream.h" // For reading/writing compressed streams
00046 #endif
00047 
00048 
00049 
00050 namespace libMesh
00051 {
00052 
00053 
00054 
00055 //-----------------------------------------------------------------------------
00056 // UNVIO class static members
00057 const std::string UNVIO::_nodes_dataset_label    = "2411";
00058 const std::string UNVIO::_elements_dataset_label = "2412";
00059 const std::string UNVIO::_groups_dataset_label   = "2467";
00060 
00061 
00062 
00063 // ------------------------------------------------------------
00064 // UNVIO class members
00065 
00066 UNVIO::UNVIO (MeshBase& mesh, MeshData* mesh_data) :
00067   MeshInput<MeshBase> (mesh),
00068   MeshOutput<MeshBase>(mesh),
00069   _verbose (false),
00070   _mesh_data (mesh_data)
00071 {
00072 }
00073 
00074 
00075 
00076 UNVIO::UNVIO (const MeshBase& mesh, MeshData* mesh_data) :
00077   MeshOutput<MeshBase> (mesh),
00078   _verbose (false),
00079   _mesh_data (mesh_data)
00080 {
00081 }
00082 
00083 
00084 
00085 UNVIO::~UNVIO ()
00086 {
00087 }
00088 
00089 
00090 
00091 bool & UNVIO::verbose ()
00092 {
00093   return _verbose;
00094 }
00095 
00096 
00097 
00098 void UNVIO::read (const std::string& file_name)
00099 {
00100   if (file_name.rfind(".gz") < file_name.size())
00101     {
00102 #ifdef LIBMESH_HAVE_GZSTREAM
00103 
00104       igzstream in_stream (file_name.c_str());
00105       this->read_implementation (in_stream);
00106 
00107 #else
00108 
00109       libmesh_error_msg("ERROR:  You must have the zlib.h header files and libraries to read and write compressed streams.");
00110 
00111 #endif
00112       return;
00113     }
00114 
00115   else
00116     {
00117       std::ifstream in_stream (file_name.c_str());
00118       this->read_implementation (in_stream);
00119       return;
00120     }
00121 }
00122 
00123 
00124 void UNVIO::read_implementation (std::istream& in_stream)
00125 {
00126   // Keep track of what kinds of elements this file contains
00127   elems_of_dimension.clear();
00128   elems_of_dimension.resize(4, false);
00129 
00130   {
00131     if ( !in_stream.good() )
00132       libmesh_error_msg("ERROR: Input file not good.");
00133 
00134     // Flags to be set when certain sections are encountered
00135     bool
00136       found_node  = false,
00137       found_elem  = false,
00138       found_group = false;
00139 
00140     // strings for reading the file line by line
00141     std::string
00142       old_line,
00143       current_line;
00144 
00145     while (true)
00146       {
00147         // Save off the old_line.  This will provide extra reliability
00148         // for detecting the beginnings of the different sections.
00149         old_line = current_line;
00150 
00151         // Try to read something.  This may set EOF!
00152         std::getline(in_stream, current_line);
00153 
00154         // If the stream is still "valid", parse the line
00155         if (in_stream)
00156           {
00157             // UNV files always have some amount of leading
00158             // whitespace, let's not rely on exactly how much...  This
00159             // command deletes it.
00160             current_line.erase(std::remove_if(current_line.begin(), current_line.end(), isspace),
00161                                current_line.end());
00162 
00163             // Parse the nodes section
00164             if (current_line == _nodes_dataset_label &&
00165                 old_line == "-1")
00166               {
00167                 found_node = true;
00168                 this->nodes_in(in_stream);
00169               }
00170 
00171             // Parse the elements section
00172             else if (current_line == _elements_dataset_label &&
00173                      old_line == "-1")
00174               {
00175                 // The current implementation requires the nodes to
00176                 // have been read before reaching the elements
00177                 // section.
00178                 if (!found_node)
00179                   libmesh_error_msg("ERROR: The Nodes section must come before the Elements section of the UNV file!");
00180 
00181                 found_elem = true;
00182                 this->elements_in(in_stream);
00183               }
00184 
00185             // Parse the groups section
00186             else if (current_line == _groups_dataset_label &&
00187                      old_line == "-1")
00188               {
00189                 // The current implementation requires the nodes and
00190                 // elements to have already been read before reaching
00191                 // the groups section.
00192                 if (!found_node || !found_elem)
00193                   libmesh_error_msg("ERROR: The Nodes and Elements sections must come before the Groups section of the UNV file!");
00194 
00195                 found_group = true;
00196                 this->groups_in(in_stream);
00197               }
00198 
00199             // We can stop reading once we've found the nodes, elements,
00200             // and group sections.
00201             if (found_node && found_elem && found_group)
00202               break;
00203 
00204             // If we made it here, we're not done yet, so keep reading
00205             continue;
00206           }
00207 
00208         // if (!in_stream) check to see if EOF was set.  If so, break out of while loop.
00209         if (in_stream.eof())
00210           break;
00211 
00212         // If !in_stream and !in_stream.eof(), stream is in a bad state!
00213         libmesh_error_msg("Stream is bad! Perhaps the file does not exist?");
00214       } // end while (true)
00215 
00216     // By now we better have found the datasets for nodes and elements,
00217     // otherwise the unv file is bad!
00218     if (!found_node)
00219       libmesh_error_msg("ERROR: Could not find nodes!");
00220 
00221     if (!found_elem)
00222       libmesh_error_msg("ERROR: Could not find elements!");
00223   }
00224 
00225 
00226 
00227   {
00228     // Set the mesh dimension to the largest element dimension encountered
00229     MeshInput<MeshBase>::mesh().set_mesh_dimension(max_elem_dimension_seen());
00230 
00231 #if LIBMESH_DIM < 3
00232     if (MeshInput<MeshBase>::mesh().mesh_dimension() > LIBMESH_DIM)
00233       libmesh_error_msg("Cannot open dimension "                        \
00234                         << MeshInput<MeshBase>::mesh().mesh_dimension() \
00235                         << " mesh file when configured without "        \
00236                         << MeshInput<MeshBase>::mesh().mesh_dimension() \
00237                         << "D support." );
00238 #endif
00239 
00240     // Possibly tell the MeshData object that we are finished
00241     // reading data.
00242     if (_mesh_data)
00243       _mesh_data->close_foreign_id_maps ();
00244 
00245     // Delete any lower-dimensional elements that might have been
00246     // added to the mesh stricly for setting BCs.
00247     {
00248       // Grab reference to the Mesh
00249       MeshBase& mesh = MeshInput<MeshBase>::mesh();
00250 
00251       unsigned char max_dim = this->max_elem_dimension_seen();
00252 
00253       MeshBase::const_element_iterator       el     = mesh.elements_begin();
00254       const MeshBase::const_element_iterator end_el = mesh.elements_end();
00255 
00256       for (; el != end_el; ++el)
00257         {
00258           Elem* elem = *el;
00259 
00260           if (elem->dim() < max_dim)
00261             mesh.delete_elem(elem);
00262         }
00263     }
00264 
00265     if (this->verbose())
00266       libMesh::out << "  Finished." << std::endl << std::endl;
00267   }
00268 }
00269 
00270 
00271 
00272 
00273 
00274 void UNVIO::write (const std::string& file_name)
00275 {
00276   if (file_name.rfind(".gz") < file_name.size())
00277     {
00278 #ifdef LIBMESH_HAVE_GZSTREAM
00279 
00280       ogzstream out_stream(file_name.c_str());
00281       this->write_implementation (out_stream);
00282 
00283 #else
00284 
00285       libmesh_error_msg("ERROR:  You must have the zlib.h header files and libraries to read and write compressed streams.");
00286 
00287 #endif
00288 
00289       return;
00290     }
00291 
00292   else
00293     {
00294       std::ofstream out_stream (file_name.c_str());
00295       this->write_implementation (out_stream);
00296       return;
00297     }
00298 }
00299 
00300 
00301 
00302 
00303 void UNVIO::write_implementation (std::ostream& out_file)
00304 {
00305   if ( !out_file.good() )
00306     libmesh_error_msg("ERROR: Output file not good.");
00307 
00308   // If we have a MeshData object, possibly set it to use "compatibility" mode.
00309   if (_mesh_data && !(_mesh_data->active()) && !(_mesh_data->compatibility_mode()))
00310     {
00311       libMesh::err << std::endl
00312                    << "*************************************************************************" << std::endl
00313                    << "* WARNING: MeshData neither active nor in compatibility mode.           *" << std::endl
00314                    << "*          Enable compatibility mode for MeshData.  Use this Universal  *" << std::endl
00315                    << "*          file with caution: libMesh node and element ids are used.    *" << std::endl
00316                    << "*************************************************************************" << std::endl
00317                    << std::endl;
00318       _mesh_data->enable_compatibility_mode();
00319     }
00320 
00321   // write the nodes, then the elements
00322   this->nodes_out    (out_file);
00323   this->elements_out (out_file);
00324 }
00325 
00326 
00327 
00328 
00329 void UNVIO::nodes_in (std::istream& in_file)
00330 {
00331   START_LOG("nodes_in()","UNVIO");
00332 
00333   if (this->verbose())
00334     libMesh::out << "  Reading nodes" << std::endl;
00335 
00336   MeshBase& mesh = MeshInput<MeshBase>::mesh();
00337 
00338   // node label, we use an int here so we can read in a -1
00339   int node_label;
00340 
00341   // always 3 coordinates in the UNV file, no matter
00342   // what LIBMESH_DIM is.
00343   Point xyz;
00344 
00345   // We'll just read the floating point values as strings even when
00346   // there are no "D" characters in the file.  This will make parsing
00347   // the file a bit slower but the logic to do so will all be
00348   // simplified and in one place...
00349   std::string line;
00350   std::istringstream coords_stream;
00351 
00352   // Continue reading nodes until there are none left
00353   unsigned ctr = 0;
00354   while (true)
00355     {
00356       // Read the node label
00357       in_file >> node_label;
00358 
00359       // Break out of the while loop when we hit -1
00360       if (node_label == -1)
00361         break;
00362 
00363       // Read and discard the the rest of the node data on this line
00364       // which we do not currently use:
00365       // .) exp_coord_sys_num
00366       // .) disp_coord_sys_num
00367       // .) color
00368       std::getline(in_file, line);
00369 
00370       // read the floating-point data
00371       std::getline(in_file, line);
00372 
00373       // Replace any "D" characters used for exponents with "E"
00374       size_t last_pos = 0;
00375       while (true)
00376         {
00377           last_pos = line.find("D", last_pos);
00378 
00379           if (last_pos != std::string::npos)
00380             line.replace(last_pos, 1, "E");
00381           else
00382             break;
00383         }
00384 
00385       // Construct a stream object from the current line and then
00386       // stream in the xyz values.
00387       coords_stream.str(line);
00388       coords_stream.clear(); // clear iostate bits!  Important!
00389       coords_stream >> xyz(0) >> xyz(1) >> xyz(2);
00390 
00391       // set up the id map
00392       _unv_node_id_to_libmesh_node_id[node_label] = ctr;
00393 
00394       // add node to the Mesh
00395       Node* added_node = mesh.add_point(xyz, ctr++);
00396 
00397       // tell the MeshData object the foreign node id
00398       if (_mesh_data)
00399         _mesh_data->add_foreign_node_id (added_node, node_label);
00400     }
00401 
00402   STOP_LOG("nodes_in()","UNVIO");
00403 }
00404 
00405 
00406 
00407 unsigned char UNVIO::max_elem_dimension_seen ()
00408 {
00409   unsigned char max_dim = 0;
00410 
00411   unsigned char elem_dimensions_size = cast_int<unsigned char>
00412     (elems_of_dimension.size());
00413   // The elems_of_dimension array is 1-based in the UNV reader
00414   for (unsigned char i=1; i<elem_dimensions_size; ++i)
00415     if (elems_of_dimension[i])
00416       max_dim = i;
00417 
00418   return max_dim;
00419 }
00420 
00421 
00422 
00423 void UNVIO::groups_in (std::istream& in_file)
00424 {
00425   // Grab reference to the Mesh, so we can add boundary info data to it
00426   MeshBase& mesh = MeshInput<MeshBase>::mesh();
00427 
00428   // Record the max and min element dimension seen while reading the file.
00429   unsigned char max_dim = this->max_elem_dimension_seen();
00430 
00431   // map from (node ids) to elem of lower dimensional elements that can provide boundary conditions
00432   typedef std::map<std::vector<dof_id_type>, Elem*> provide_bcs_t;
00433   provide_bcs_t provide_bcs;
00434 
00435   // Read groups until there aren't any more to read...
00436   while (true)
00437     {
00438       // If we read a -1, it means there is nothing else to read in this section.
00439       int group_number;
00440       in_file >> group_number;
00441 
00442       if (group_number == -1)
00443         break;
00444 
00445       // The first record consists of 8 entries:
00446       // Field 1 -- group number (that we just read)
00447       // Field 2 -- active constraint set no. for group
00448       // Field 3 -- active restraint set no. for group
00449       // Field 4 -- active load set no. for group
00450       // Field 5 -- active dof set no. for group
00451       // Field 6 -- active temperature set no. for group
00452       // Field 7 -- active contact set no. for group
00453       // Field 8 -- number of entities in group
00454       // Only the first and last of these are relevant to us...
00455       unsigned num_entities;
00456       std::string group_name;
00457       {
00458         unsigned dummy;
00459         in_file >> dummy >> dummy >> dummy >> dummy >> dummy >> dummy
00460                 >> num_entities;
00461 
00462         // The second record has 1 field, the group name
00463         in_file >> group_name;
00464       }
00465 
00466       // The dimension of the elements in the group will determine
00467       // whether this is a sideset group or a subdomain group.
00468       bool
00469         is_subdomain_group = false,
00470         is_sideset_group = false;
00471 
00472       // Each subsequent line has 8 entries, there are two entity type
00473       // codes and two tags per line that we need to read.  In all my
00474       // examples, the entity type code was always "8", which stands for
00475       // "finite elements" but it's possible that we could eventually
00476       // support other entity type codes...
00477       // Field 1 -- entity type code
00478       // Field 2 -- entity tag
00479       // Field 3 -- entity node leaf id.
00480       // Field 4 -- entity component/ ham id.
00481       // Field 5 -- entity type code
00482       // Field 6 -- entity tag
00483       // Field 7 -- entity node leaf id.
00484       // Field 8 -- entity component/ ham id.
00485       {
00486         unsigned entity_type_code, entity_tag, dummy;
00487         for (unsigned entity=0; entity<num_entities; ++entity)
00488           {
00489             in_file >> entity_type_code >> entity_tag >> dummy >> dummy;
00490 
00491             if (entity_type_code != 8)
00492               libMesh::err << "Warning, unrecognized entity type code = "
00493                            << entity_type_code
00494                            << " in group "
00495                            << group_name
00496                            << std::endl;
00497 
00498             // Try to find this ID in the map from UNV element ids to libmesh ids.
00499             std::map<unsigned, unsigned>::iterator it =
00500               _unv_elem_id_to_libmesh_elem_id.find(entity_tag);
00501 
00502             if (it != _unv_elem_id_to_libmesh_elem_id.end())
00503               {
00504                 unsigned libmesh_elem_id = it->second;
00505 
00506                 // Attempt to get a pointer to the elem listed in the group
00507                 Elem* group_elem = mesh.elem(libmesh_elem_id);
00508                 if (!group_elem)
00509                   libmesh_error_msg("Group referred to non-existent element with ID " << libmesh_elem_id);
00510 
00511                 // dim < max_dim means the Elem defines a boundary condition
00512                 if (group_elem->dim() < max_dim)
00513                   {
00514                     is_sideset_group = true;
00515 
00516                     // We can only handle elements that are *exactly*
00517                     // one dimension lower than the max element
00518                     // dimension.  Not sure if "edge" BCs in 3D
00519                     // actually make sense/are required...
00520                     if (group_elem->dim()+1 != max_dim)
00521                       libmesh_error_msg
00522                         ("ERROR: Expected boundary element of dimension " <<
00523                          max_dim-1 << " but got " << group_elem->dim());
00524 
00525                     // To be pushed into the provide_bcs data container
00526                     std::vector<dof_id_type> group_elem_node_ids(group_elem->n_nodes());
00527 
00528                     // Save node IDs in a local vector which will be used as a key for the map.
00529                     for (unsigned n=0; n<group_elem->n_nodes(); n++)
00530                       group_elem_node_ids[n] = group_elem->node(n);
00531 
00532                     // Set the current group number as the lower-dimensional element's subdomain ID.
00533                     // We will use this later to set a boundary ID.
00534                     group_elem->subdomain_id() =
00535                       cast_int<subdomain_id_type>(group_number);
00536 
00537                     // Sort before putting into the map
00538                     std::sort(group_elem_node_ids.begin(), group_elem_node_ids.end());
00539 
00540                     // Ensure that this key doesn't already exist when
00541                     // inserting it.  We would need to use a multimap if
00542                     // the same element appears in multiple group numbers!
00543                     // This actually seems like it could be relatively
00544                     // common, but I don't have a test for it at the
00545                     // moment...
00546                     std::pair<provide_bcs_t::iterator, bool> result =
00547                       provide_bcs.insert(std::make_pair(group_elem_node_ids, group_elem));
00548 
00549                     if (!result.second)
00550                       libmesh_error_msg("Boundary element " << group_elem->id() << " was not inserted, it was already in the map!");
00551                   }
00552 
00553                 // dim == max_dim means this group defines a subdomain ID
00554                 else if (group_elem->dim() == max_dim)
00555                   {
00556                     is_subdomain_group = true;
00557                     group_elem->subdomain_id() =
00558                       cast_int<subdomain_id_type>(group_number);
00559                   }
00560 
00561                 else
00562                   libmesh_error_msg("ERROR: Found an elem with dim="
00563                                     << group_elem->dim() << " > " <<
00564                                     "max_dim=" << +max_dim);
00565               }
00566             else
00567               libMesh::err << "WARNING: UNV Element " << entity_tag << " not found while parsing groups." << std::endl;
00568           } // end for (entity)
00569       } // end scope
00570 
00571       // Associate this group_number with the group_name in the BoundaryInfo object.
00572       if (is_sideset_group)
00573         mesh.get_boundary_info().sideset_name
00574           (cast_int<boundary_id_type>(group_number)) = group_name;
00575 
00576       if (is_subdomain_group)
00577         mesh.subdomain_name
00578           (cast_int<subdomain_id_type>(group_number)) = group_name;
00579 
00580     } // end while (true)
00581 
00582   // Loop over elements and try to assign boundary information
00583   {
00584     MeshBase::element_iterator       it  = mesh.active_elements_begin();
00585     const MeshBase::element_iterator end = mesh.active_elements_end();
00586     for ( ; it != end; ++it)
00587       {
00588         Elem* elem = *it;
00589 
00590         if (elem->dim() == max_dim)
00591           {
00592             // This is a max-dimension element that may require BCs.
00593             // For each of its sides, including internal sides, we'll
00594             // see if a lower-dimensional element provides boundary
00595             // information for it.  Note that we have not yet called
00596             // find_neighbors(), so we can't use elem->neighbor(sn) in
00597             // this algorithm...
00598             for (unsigned short sn=0; sn<elem->n_sides(); sn++)
00599               {
00600                 UniquePtr<Elem> side (elem->build_side(sn));
00601 
00602                 // Build up a node_ids vector, which is the key
00603                 std::vector<dof_id_type> node_ids(side->n_nodes());
00604                 for (unsigned n=0; n<side->n_nodes(); n++)
00605                   node_ids[n] = side->node(n);
00606 
00607                 // Sort the vector before using it as a key
00608                 std::sort(node_ids.begin(), node_ids.end());
00609 
00610                 // Look for this key in the provide_bcs map
00611                 provide_bcs_t::iterator iter = provide_bcs.find(node_ids);
00612 
00613                 if (iter != provide_bcs.end())
00614                   {
00615                     Elem* lower_dim_elem = iter->second;
00616 
00617                     // Add boundary information based on the lower-dimensional element's subdomain id.
00618                     mesh.get_boundary_info().add_side
00619                       (elem, sn, lower_dim_elem->subdomain_id());
00620                   }
00621               }
00622           }
00623       }
00624   }
00625 }
00626 
00627 
00628 
00629 void UNVIO::elements_in (std::istream& in_file)
00630 {
00631   START_LOG("elements_in()","UNVIO");
00632 
00633   if (this->verbose())
00634     libMesh::out << "  Reading elements" << std::endl;
00635 
00636   MeshBase& mesh = MeshInput<MeshBase>::mesh();
00637 
00638   // node label, we use an int here so we can read in a -1
00639   int element_label;
00640 
00641   unsigned
00642     n_nodes,           // number of nodes on element
00643     fe_descriptor_id,  // FE descriptor id
00644     phys_prop_tab_num, // physical property table number (not supported yet)
00645     mat_prop_tab_num,  // material property table number (not supported yet)
00646     color;             // color (not supported yet)
00647 
00648   // vector that temporarily holds the node labels defining element
00649   std::vector<unsigned int> node_labels (21);
00650 
00651   // vector that assigns element nodes to their correct position
00652   // for example:
00653   // 44:plane stress      | QUAD4
00654   // linear quadrilateral |
00655   // position in UNV-file | position in libmesh
00656   // assign_elem_node[1]   = 0
00657   // assign_elem_node[2]   = 3
00658   // assign_elem_node[3]   = 2
00659   // assign_elem_node[4]   = 1
00660   //
00661   // UNV is 1-based, we leave the 0th element of the vectors unused in order
00662   // to prevent confusion, this way we can store elements with up to 20 nodes
00663   unsigned int assign_elem_nodes[21];
00664 
00665   // Read elements until there are none left
00666   unsigned ctr = 0;
00667   while (true)
00668     {
00669       // read element label, break out when we read -1
00670       in_file >> element_label;
00671 
00672       if (element_label == -1)
00673         break;
00674 
00675       in_file >> fe_descriptor_id        // read FE descriptor id
00676               >> phys_prop_tab_num       // (not supported yet)
00677               >> mat_prop_tab_num        // (not supported yet)
00678               >> color                   // (not supported yet)
00679               >> n_nodes;                // read number of nodes on element
00680 
00681       // For "beam" type elements, the next three numbers are:
00682       // .) beam orientation node number
00683       // .) beam fore-end cross section number
00684       // .) beam aft-end cross section number
00685       // which we discard in libmesh.  The "beam" type elements:
00686       // 11  Rod
00687       // 21  Linear beam
00688       // 22  Tapered beam
00689       // 23  Curved beam
00690       // 24  Parabolic beam
00691       // all have fe_descriptor_id < 25.
00692       // http://www.sdrl.uc.edu/universal-file-formats-for-modal-analysis-testing-1/file-format-storehouse/unv_2412.htm
00693       if (fe_descriptor_id < 25)
00694         {
00695           unsigned dummy;
00696           in_file >> dummy >> dummy >> dummy;
00697         }
00698 
00699       // read node labels (1-based)
00700       for (unsigned int j=1; j<=n_nodes; j++)
00701         in_file >> node_labels[j];
00702 
00703       // element pointer, to be allocated
00704       Elem* elem = NULL;
00705 
00706       switch (fe_descriptor_id)
00707         {
00708         case 11: // Rod
00709           {
00710             elem = new Edge2;
00711 
00712             assign_elem_nodes[1]=0;
00713             assign_elem_nodes[2]=1;
00714             break;
00715           }
00716 
00717         case 41: // Plane Stress Linear Triangle
00718         case 91: // Thin Shell   Linear Triangle
00719           {
00720             elem = new Tri3;  // create new element
00721 
00722             assign_elem_nodes[1]=0;
00723             assign_elem_nodes[2]=2;
00724             assign_elem_nodes[3]=1;
00725             break;
00726           }
00727 
00728         case 42: // Plane Stress Quadratic Triangle
00729         case 92: // Thin Shell   Quadratic Triangle
00730           {
00731             elem = new Tri6;  // create new element
00732 
00733             assign_elem_nodes[1]=0;
00734             assign_elem_nodes[2]=5;
00735             assign_elem_nodes[3]=2;
00736             assign_elem_nodes[4]=4;
00737             assign_elem_nodes[5]=1;
00738             assign_elem_nodes[6]=3;
00739             break;
00740           }
00741 
00742         case 43: // Plane Stress Cubic Triangle
00743           libmesh_error_msg("ERROR: UNV-element type 43: Plane Stress Cubic Triangle not supported.");
00744 
00745         case 44: // Plane Stress Linear Quadrilateral
00746         case 94: // Thin Shell   Linear Quadrilateral
00747           {
00748             elem = new Quad4; // create new element
00749 
00750             assign_elem_nodes[1]=0;
00751             assign_elem_nodes[2]=3;
00752             assign_elem_nodes[3]=2;
00753             assign_elem_nodes[4]=1;
00754             break;
00755           }
00756 
00757         case 45: // Plane Stress Quadratic Quadrilateral
00758         case 95: // Thin Shell   Quadratic Quadrilateral
00759           {
00760             elem = new Quad8; // create new element
00761 
00762             assign_elem_nodes[1]=0;
00763             assign_elem_nodes[2]=7;
00764             assign_elem_nodes[3]=3;
00765             assign_elem_nodes[4]=6;
00766             assign_elem_nodes[5]=2;
00767             assign_elem_nodes[6]=5;
00768             assign_elem_nodes[7]=1;
00769             assign_elem_nodes[8]=4;
00770             break;
00771           }
00772 
00773         case 300: // Thin Shell   Quadratic Quadrilateral (nine nodes)
00774           {
00775             elem = new Quad9; // create new element
00776 
00777             assign_elem_nodes[1]=0;
00778             assign_elem_nodes[2]=7;
00779             assign_elem_nodes[3]=3;
00780             assign_elem_nodes[4]=6;
00781             assign_elem_nodes[5]=2;
00782             assign_elem_nodes[6]=5;
00783             assign_elem_nodes[7]=1;
00784             assign_elem_nodes[8]=4;
00785             assign_elem_nodes[9]=8;
00786             break;
00787           }
00788 
00789         case 46: // Plane Stress Cubic Quadrilateral
00790           libmesh_error_msg("ERROR: UNV-element type 46: Plane Stress Cubic Quadrilateral not supported.");
00791 
00792         case 111: // Solid Linear Tetrahedron
00793           {
00794             elem = new Tet4;  // create new element
00795 
00796             assign_elem_nodes[1]=0;
00797             assign_elem_nodes[2]=1;
00798             assign_elem_nodes[3]=2;
00799             assign_elem_nodes[4]=3;
00800             break;
00801           }
00802 
00803         case 112: // Solid Linear Prism
00804           {
00805             elem = new Prism6;  // create new element
00806 
00807             assign_elem_nodes[1]=0;
00808             assign_elem_nodes[2]=1;
00809             assign_elem_nodes[3]=2;
00810             assign_elem_nodes[4]=3;
00811             assign_elem_nodes[5]=4;
00812             assign_elem_nodes[6]=5;
00813             break;
00814           }
00815 
00816         case 115: // Solid Linear Brick
00817           {
00818             elem = new Hex8;  // create new element
00819 
00820             assign_elem_nodes[1]=0;
00821             assign_elem_nodes[2]=4;
00822             assign_elem_nodes[3]=5;
00823             assign_elem_nodes[4]=1;
00824             assign_elem_nodes[5]=3;
00825             assign_elem_nodes[6]=7;
00826             assign_elem_nodes[7]=6;
00827             assign_elem_nodes[8]=2;
00828             break;
00829           }
00830 
00831         case 116: // Solid Quadratic Brick
00832           {
00833             elem = new Hex20; // create new element
00834 
00835             assign_elem_nodes[1]=0;
00836             assign_elem_nodes[2]=12;
00837             assign_elem_nodes[3]=4;
00838             assign_elem_nodes[4]=16;
00839             assign_elem_nodes[5]=5;
00840             assign_elem_nodes[6]=13;
00841             assign_elem_nodes[7]=1;
00842             assign_elem_nodes[8]=8;
00843 
00844             assign_elem_nodes[9]=11;
00845             assign_elem_nodes[10]=19;
00846             assign_elem_nodes[11]=17;
00847             assign_elem_nodes[12]=9;
00848 
00849             assign_elem_nodes[13]=3;
00850             assign_elem_nodes[14]=15;
00851             assign_elem_nodes[15]=7;
00852             assign_elem_nodes[16]=18;
00853             assign_elem_nodes[17]=6;
00854             assign_elem_nodes[18]=14;
00855             assign_elem_nodes[19]=2;
00856             assign_elem_nodes[20]=10;
00857             break;
00858           }
00859 
00860         case 117: // Solid Cubic Brick
00861           libmesh_error_msg("Error: UNV-element type 117: Solid Cubic Brick not supported.");
00862 
00863         case 118: // Solid Quadratic Tetrahedron
00864           {
00865             elem = new Tet10; // create new element
00866 
00867             assign_elem_nodes[1]=0;
00868             assign_elem_nodes[2]=4;
00869             assign_elem_nodes[3]=1;
00870             assign_elem_nodes[4]=5;
00871             assign_elem_nodes[5]=2;
00872             assign_elem_nodes[6]=6;
00873             assign_elem_nodes[7]=7;
00874             assign_elem_nodes[8]=8;
00875             assign_elem_nodes[9]=9;
00876             assign_elem_nodes[10]=3;
00877             break;
00878           }
00879 
00880         default: // Unrecognized element type
00881           libmesh_error_msg("ERROR: UNV-element type " << fe_descriptor_id << " not supported.");
00882         }
00883 
00884       // nodes are being stored in element
00885       for (dof_id_type j=1; j<=n_nodes; j++)
00886         {
00887           // Map the UNV node ID to the libmesh node ID
00888           std::map<unsigned, unsigned>::iterator it =
00889             _unv_node_id_to_libmesh_node_id.find(node_labels[j]);
00890 
00891           if (it != _unv_node_id_to_libmesh_node_id.end())
00892             elem->set_node(assign_elem_nodes[j]) = mesh.node_ptr(it->second);
00893           else
00894             libmesh_error_msg("ERROR: UNV node " << node_labels[j] << " not found!");
00895         }
00896 
00897       elems_of_dimension[elem->dim()] = true;
00898 
00899       // Set the element's ID
00900       elem->set_id(ctr);
00901 
00902       // Maintain a map from the libmesh (0-based) numbering to the
00903       // UNV numbering.  This probably duplicates what the MeshData
00904       // object does, but hopefully the MeshData object will be going
00905       // away at some point...
00906       //_libmesh_elem_id_to_unv_elem_id[i] = element_label;
00907       _unv_elem_id_to_libmesh_elem_id[element_label] = ctr;
00908 
00909       // Add the element to the Mesh
00910       Elem* added_elem = mesh.add_elem(elem);
00911 
00912       // Tell the MeshData object the foreign elem id
00913       if (_mesh_data)
00914         _mesh_data->add_foreign_elem_id (added_elem, element_label);
00915 
00916       // Increment the counter for the next iteration
00917       ctr++;
00918     } // end while(true)
00919 
00920   STOP_LOG("elements_in()","UNVIO");
00921 }
00922 
00923 
00924 
00925 
00926 
00927 
00928 void UNVIO::nodes_out (std::ostream& out_file)
00929 {
00930   if (_mesh_data)
00931     libmesh_assert (_mesh_data->active() ||
00932                     _mesh_data->compatibility_mode());
00933 
00934   if (this->verbose())
00935     libMesh::out << "  Writing " << MeshOutput<MeshBase>::mesh().n_nodes() << " nodes" << std::endl;
00936 
00937   // Write beginning of dataset
00938   out_file << "    -1\n"
00939            << "  "
00940            << _nodes_dataset_label
00941            << '\n';
00942 
00943   unsigned int
00944     exp_coord_sys_dummy  = 0, // export coordinate sys. (not supported yet)
00945     disp_coord_sys_dummy = 0, // displacement coordinate sys. (not supp. yet)
00946     color_dummy          = 0; // color(not supported yet)
00947 
00948   // A reference to the parent class's mesh
00949   const MeshBase& mesh = MeshOutput<MeshBase>::mesh();
00950 
00951   // Use scientific notation with captial E and 16 digits for printing out the coordinates
00952   out_file << std::scientific << std::setprecision(16) << std::uppercase;
00953 
00954   MeshBase::const_node_iterator       nd  = mesh.nodes_begin();
00955   const MeshBase::const_node_iterator end = mesh.nodes_end();
00956 
00957   for (; nd != end; ++nd)
00958     {
00959       const Node* current_node = *nd;
00960 
00961       dof_id_type node_id = current_node->id();
00962 
00963       // If possible, use the MeshData object to get the right node ID.
00964       if (_mesh_data)
00965         node_id = _mesh_data->node_to_foreign_id(current_node);
00966 
00967       out_file << std::setw(10) << node_id
00968                << std::setw(10) << exp_coord_sys_dummy
00969                << std::setw(10) << disp_coord_sys_dummy
00970                << std::setw(10) << color_dummy
00971                << '\n';
00972 
00973       // The coordinates - always write out three coords regardless of LIBMESH_DIM
00974       Real x = (*current_node)(0);
00975       Real y = mesh.spatial_dimension() > 1 ? (*current_node)(1) : 0.0;
00976       Real z = mesh.spatial_dimension() > 2 ? (*current_node)(2) : 0.0;
00977 
00978       out_file << std::setw(25) << x
00979                << std::setw(25) << y
00980                << std::setw(25) << z
00981                << '\n';
00982     }
00983 
00984   // Write end of dataset
00985   out_file << "    -1\n";
00986 }
00987 
00988 
00989 
00990 
00991 
00992 
00993 void UNVIO::elements_out(std::ostream& out_file)
00994 {
00995   if (_mesh_data)
00996     libmesh_assert (_mesh_data->active() ||
00997                     _mesh_data->compatibility_mode());
00998 
00999   if (this->verbose())
01000     libMesh::out << "  Writing elements" << std::endl;
01001 
01002   // Write beginning of dataset
01003   out_file << "    -1\n"
01004            << "  "
01005            << _elements_dataset_label
01006            << "\n";
01007 
01008   unsigned
01009     fe_descriptor_id = 0,    // FE descriptor id
01010     phys_prop_tab_dummy = 2, // physical property (not supported yet)
01011     mat_prop_tab_dummy = 1,  // material property (not supported yet)
01012     color_dummy = 7;         // color (not supported yet)
01013 
01014   // vector that assigns element nodes to their correct position
01015   // currently only elements with up to 20 nodes
01016   //
01017   // Example:
01018   // QUAD4               | 44:plane stress
01019   //                     | linear quad
01020   // position in libMesh | UNV numbering
01021   // (note: 0-based)     | (note: 1-based)
01022   //
01023   // assign_elem_node[0]  = 0
01024   // assign_elem_node[1]  = 3
01025   // assign_elem_node[2]  = 2
01026   // assign_elem_node[3]  = 1
01027   unsigned int assign_elem_nodes[20];
01028 
01029   unsigned int n_elem_written=0;
01030 
01031   // A reference to the parent class's mesh
01032   const MeshBase& mesh = MeshOutput<MeshBase>::mesh();
01033 
01034   MeshBase::const_element_iterator it  = mesh.elements_begin();
01035   const MeshBase::const_element_iterator end = mesh.elements_end();
01036 
01037   for (; it != end; ++it)
01038     {
01039       const Elem* elem = *it;
01040 
01041       elem->n_nodes();
01042 
01043       switch (elem->type())
01044         {
01045 
01046         case TRI3:
01047           {
01048             fe_descriptor_id = 41; // Plane Stress Linear Triangle
01049             assign_elem_nodes[0] = 0;
01050             assign_elem_nodes[1] = 2;
01051             assign_elem_nodes[2] = 1;
01052             break;
01053           }
01054 
01055         case TRI6:
01056           {
01057             fe_descriptor_id = 42; // Plane Stress Quadratic Triangle
01058             assign_elem_nodes[0] = 0;
01059             assign_elem_nodes[1] = 5;
01060             assign_elem_nodes[2] = 2;
01061             assign_elem_nodes[3] = 4;
01062             assign_elem_nodes[4] = 1;
01063             assign_elem_nodes[5] = 3;
01064             break;
01065           }
01066 
01067         case QUAD4:
01068           {
01069             fe_descriptor_id = 44; // Plane Stress Linear Quadrilateral
01070             assign_elem_nodes[0] = 0;
01071             assign_elem_nodes[1] = 3;
01072             assign_elem_nodes[2] = 2;
01073             assign_elem_nodes[3] = 1;
01074             break;
01075           }
01076 
01077         case QUAD8:
01078           {
01079             fe_descriptor_id = 45; // Plane Stress Quadratic Quadrilateral
01080             assign_elem_nodes[0] = 0;
01081             assign_elem_nodes[1] = 7;
01082             assign_elem_nodes[2] = 3;
01083             assign_elem_nodes[3] = 6;
01084             assign_elem_nodes[4] = 2;
01085             assign_elem_nodes[5] = 5;
01086             assign_elem_nodes[6] = 1;
01087             assign_elem_nodes[7] = 4;
01088             break;
01089           }
01090 
01091         case QUAD9:
01092           {
01093             fe_descriptor_id = 300; // Plane Stress Quadratic Quadrilateral
01094             assign_elem_nodes[0] = 0;
01095             assign_elem_nodes[1] = 7;
01096             assign_elem_nodes[2] = 3;
01097             assign_elem_nodes[3] = 6;
01098             assign_elem_nodes[4] = 2;
01099             assign_elem_nodes[5] = 5;
01100             assign_elem_nodes[6] = 1;
01101             assign_elem_nodes[7] = 4;
01102             assign_elem_nodes[8] = 8;
01103             break;
01104           }
01105 
01106         case TET4:
01107           {
01108             fe_descriptor_id = 111; // Solid Linear Tetrahedron
01109             assign_elem_nodes[0] = 0;
01110             assign_elem_nodes[1] = 1;
01111             assign_elem_nodes[2] = 2;
01112             assign_elem_nodes[3] = 3;
01113             break;
01114           }
01115 
01116         case PRISM6:
01117           {
01118             fe_descriptor_id = 112; // Solid Linear Prism
01119             assign_elem_nodes[0] = 0;
01120             assign_elem_nodes[1] = 1;
01121             assign_elem_nodes[2] = 2;
01122             assign_elem_nodes[3] = 3;
01123             assign_elem_nodes[4] = 4;
01124             assign_elem_nodes[5] = 5;
01125             break;
01126           }
01127 
01128         case HEX8:
01129           {
01130             fe_descriptor_id = 115; // Solid Linear Brick
01131             assign_elem_nodes[0] = 0;
01132             assign_elem_nodes[1] = 4;
01133             assign_elem_nodes[2] = 5;
01134             assign_elem_nodes[3] = 1;
01135             assign_elem_nodes[4] = 3;
01136             assign_elem_nodes[5] = 7;
01137             assign_elem_nodes[6] = 6;
01138             assign_elem_nodes[7] = 2;
01139             break;
01140           }
01141 
01142         case HEX20:
01143           {
01144             fe_descriptor_id = 116; // Solid Quadratic Brick
01145             assign_elem_nodes[ 0] = 0;
01146             assign_elem_nodes[ 1] = 12;
01147             assign_elem_nodes[ 2] = 4;
01148             assign_elem_nodes[ 3] = 16;
01149             assign_elem_nodes[ 4] = 5;
01150             assign_elem_nodes[ 5] = 13;
01151             assign_elem_nodes[ 6] = 1;
01152             assign_elem_nodes[ 7] = 8;
01153 
01154             assign_elem_nodes[ 8] = 11;
01155             assign_elem_nodes[ 9] = 19;
01156             assign_elem_nodes[10] = 17;
01157             assign_elem_nodes[11] = 9;
01158 
01159             assign_elem_nodes[12] = 3;
01160             assign_elem_nodes[13] = 15;
01161             assign_elem_nodes[14] = 7;
01162             assign_elem_nodes[15] = 18;
01163             assign_elem_nodes[16] = 6;
01164             assign_elem_nodes[17] = 14;
01165             assign_elem_nodes[18] = 2;
01166             assign_elem_nodes[19] = 10;
01167 
01168 
01169             break;
01170           }
01171 
01172         case TET10:
01173           {
01174             fe_descriptor_id = 118; // Solid Quadratic Tetrahedron
01175             assign_elem_nodes[0] = 0;
01176             assign_elem_nodes[1] = 4;
01177             assign_elem_nodes[2] = 1;
01178             assign_elem_nodes[3] = 5;
01179             assign_elem_nodes[4] = 2;
01180             assign_elem_nodes[5] = 6;
01181             assign_elem_nodes[6] = 7;
01182             assign_elem_nodes[7] = 8;
01183             assign_elem_nodes[8] = 9;
01184             assign_elem_nodes[9] = 3;
01185             break;
01186           }
01187 
01188         default:
01189           libmesh_error_msg("ERROR: Element type = " << elem->type() << " not supported in " << "UNVIO!");
01190         }
01191 
01192       dof_id_type elem_id = elem->id();
01193 
01194       // If possible, use the MeshData object to get the right node ID.
01195       if (_mesh_data)
01196         _mesh_data->elem_to_foreign_id(elem);
01197 
01198       out_file << std::setw(10) << elem_id             // element ID
01199                << std::setw(10) << fe_descriptor_id    // type of element
01200                << std::setw(10) << phys_prop_tab_dummy // not supported
01201                << std::setw(10) << mat_prop_tab_dummy  // not supported
01202                << std::setw(10) << color_dummy         // not supported
01203                << std::setw(10) << elem->n_nodes()     // No. of nodes per element
01204                << '\n';
01205 
01206       for (unsigned int j=0; j<elem->n_nodes(); j++)
01207         {
01208           // assign_elem_nodes[j]-th node: i.e., j loops over the
01209           // libMesh numbering, and assign_elem_nodes[j] over the
01210           // UNV numbering.
01211           const Node* node_in_unv_order = elem->get_node(assign_elem_nodes[j]);
01212 
01213           // new record after 8 id entries
01214           if (j==8 || j==16)
01215             out_file << '\n';
01216 
01217           // Write foreign label for this node
01218           dof_id_type node_id = node_in_unv_order->id();
01219 
01220           // If possible, use the MeshData object to determine this
01221           if (_mesh_data)
01222             _mesh_data->node_to_foreign_id(node_in_unv_order);
01223 
01224           out_file << std::setw(10) << node_id;
01225         }
01226 
01227       out_file << '\n';
01228 
01229       n_elem_written++;
01230     }
01231 
01232   if (this->verbose())
01233     libMesh::out << "  Finished writing " << n_elem_written << " elements" << std::endl;
01234 
01235   // Write end of dataset
01236   out_file << "    -1\n";
01237 }
01238 
01239 } // namespace libMesh