$extrastylesheet
fro_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 
00020 // C++ includes
00021 #include <fstream>
00022 #include <iomanip>
00023 #include <iostream>
00024 #include <deque>
00025 #include <map>
00026 
00027 // Local includes
00028 #include "libmesh/libmesh_config.h"
00029 #include "libmesh/fro_io.h"
00030 #include "libmesh/mesh_base.h"
00031 #include "libmesh/boundary_info.h"
00032 #include "libmesh/elem.h"
00033 
00034 namespace libMesh
00035 {
00036 
00037 
00038 
00039 // ------------------------------------------------------------
00040 // FroIO  members
00041 void FroIO::write (const std::string& fname)
00042 {
00043   // We may need to gather a ParallelMesh to output it, making that
00044   // const qualifier in our constructor a dirty lie
00045   MeshSerializer serialize(const_cast<MeshBase&>(this->mesh()), !_is_parallel_format);
00046 
00047   if (this->mesh().processor_id() == 0)
00048     {
00049       // Open the output file stream
00050       std::ofstream out_stream (fname.c_str());
00051       libmesh_assert (out_stream.good());
00052 
00053       // Make sure it opened correctly
00054       if (!out_stream.good())
00055         libmesh_file_error(fname.c_str());
00056 
00057       // Get a reference to the mesh
00058       const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh();
00059 
00060       // Write the header
00061       out_stream << the_mesh.n_elem()  << " "
00062                  << the_mesh.n_nodes() << " "
00063                  << "0 0 "
00064                  << the_mesh.get_boundary_info().n_boundary_ids()  << " 1\n";
00065 
00066       // Write the nodes -- 1-based!
00067       for (unsigned int n=0; n<the_mesh.n_nodes(); n++)
00068         out_stream << n+1 << " \t"
00069                    << std::scientific
00070                    << std::setprecision(12)
00071                    << the_mesh.point(n)(0) << " \t"
00072                    << the_mesh.point(n)(1) << " \t"
00073                    << 0. << '\n';
00074 
00075       // Write the elements -- 1-based!
00076       MeshBase::const_element_iterator       it  = the_mesh.active_elements_begin();
00077       const MeshBase::const_element_iterator end = the_mesh.active_elements_end();
00078 
00079       for (unsigned int e=0 ; it != end; ++it)
00080         {
00081           // .fro likes TRI3's
00082           if ((*it)->type() != TRI3)
00083             libmesh_error_msg("ERROR:  .fro format only valid for triangles!\n" \
00084                               << "  writing of " << fname << " aborted.");
00085 
00086           out_stream << ++e << " \t";
00087 
00088           for (unsigned int n=0; n<(*it)->n_nodes(); n++)
00089             out_stream << (*it)->node(n)+1 << " \t";
00090 
00091           //   // LHS -> RHS Mapping, for inverted triangles
00092           //   out_stream << (*it)->node(0)+1 << " \t";
00093           //   out_stream << (*it)->node(2)+1 << " \t";
00094           //   out_stream << (*it)->node(1)+1 << " \t";
00095 
00096           out_stream << "1\n";
00097         }
00098 
00099       // Write BCs.
00100       {
00101         const std::set<boundary_id_type>& bc_ids =
00102           the_mesh.get_boundary_info().get_boundary_ids();
00103 
00104         std::vector<dof_id_type>        el;
00105         std::vector<unsigned short int> sl;
00106         std::vector<boundary_id_type>   il;
00107 
00108         the_mesh.get_boundary_info().build_side_list (el, sl, il);
00109 
00110 
00111         // Map the boundary ids into [1,n_bc_ids],
00112         // treat them one at a time.
00113         boundary_id_type bc_id=0;
00114         for (std::set<boundary_id_type>::const_iterator id = bc_ids.begin();
00115              id != bc_ids.end(); ++id)
00116           {
00117             std::deque<dof_id_type> node_list;
00118 
00119             std::map<dof_id_type, dof_id_type>
00120               forward_edges, backward_edges;
00121 
00122             // Get all sides on this element with the relevant BC id.
00123             for (std::size_t e=0; e<el.size(); e++)
00124               if (il[e] == *id)
00125                 {
00126                   // need to build up node_list as a sorted array of edge nodes...
00127                   // for the following:
00128                   // a---b---c---d---e
00129                   // node_list [ a b c d e];
00130                   //
00131                   // the issue is just how to get this out of the elem/side based data structure.
00132                   // the approach is to build up 'chain links' like this:
00133                   // a---b b---c c---d d---e
00134                   // and piece them together.
00135                   //
00136                   // so, for an arbitray edge n0---n1, we build the
00137                   // "forward_edges"  map n0-->n1
00138                   // "backward_edges" map n1-->n0
00139                   // and then start with one chain link, and add on...
00140                   //
00141                   UniquePtr<Elem> side = the_mesh.elem(el[e])->build_side(sl[e]);
00142 
00143                   const dof_id_type
00144                     n0 = side->node(0),
00145                     n1 = side->node(1);
00146 
00147                   // insert into forward-edge set
00148                   forward_edges.insert (std::make_pair(n0, n1));
00149 
00150                   // insert into backward-edge set
00151                   backward_edges.insert (std::make_pair(n1, n0));
00152 
00153                   // go ahead and add one edge to the list -- this will give us the beginning of a
00154                   // chain to work from!
00155                   if (node_list.empty())
00156                     {
00157                       node_list.push_front(n0);
00158                       node_list.push_back (n1);
00159                     }
00160                 }
00161 
00162             // we now have the node_list with one edge, the forward_edges, and the backward_edges
00163             // the node_list will be filled when (node_list.size() == (n_edges+1))
00164             // until that is the case simply add on to the beginning and end of the node_list,
00165             // building up a chain of ordered nodes...
00166             const std::size_t n_edges = forward_edges.size();
00167 
00168             while (node_list.size() != (n_edges+1))
00169               {
00170                 const dof_id_type
00171                   front_node = node_list.front(),
00172                   back_node  = node_list.back();
00173 
00174                 // look for front_pair in the backward_edges list
00175                 {
00176                   std::map<dof_id_type, dof_id_type>::iterator
00177                     pos = backward_edges.find(front_node);
00178 
00179                   if (pos != backward_edges.end())
00180                     {
00181                       node_list.push_front(pos->second);
00182 
00183                       backward_edges.erase(pos);
00184                     }
00185                 }
00186 
00187                 // look for back_pair in the forward_edges list
00188                 {
00189                   std::map<dof_id_type, dof_id_type>::iterator
00190                     pos = forward_edges.find(back_node);
00191 
00192                   if (pos != forward_edges.end())
00193                     {
00194                       node_list.push_back(pos->second);
00195 
00196                       forward_edges.erase(pos);
00197                     }
00198                 }
00199 
00200                 // libMesh::out << "node_list.size()=" << node_list.size()
00201                 //       << ", n_edges+1=" << n_edges+1 << std::endl;
00202               }
00203 
00204 
00205             out_stream << ++bc_id << " " << node_list.size() << '\n';
00206 
00207             std::deque<dof_id_type>::iterator pos = node_list.begin();
00208             for ( ; pos != node_list.end(); ++pos)
00209               out_stream << *pos+1 << " \t0\n";
00210           }
00211       }
00212     }
00213 }
00214 
00215 } // namespace libMesh