// ------------------------------------------------------------ // DivaIO class members void DivaIO::write (const std::string & fname) { // We may need to gather a ParallelMesh to output it, making that // const qualifier in our constructor a dirty lie MeshSerializer serialize(const_cast<MeshBase &>(this->mesh()), !_is_parallel_format); // Open the output file stream std::ofstream out_file(fname.c_str()); // Make sure it opened correctly if (!out_file.good()) libmesh_file_error(fname.c_str()); this->write_stream (out_file); }
void XdrMGF::init (XdrMGF::XdrIO_TYPE t, const char* fn, const char*, int) { m_type=t; // Close old file if necessary if (mp_fp) this->fini(); // Open file switch (m_type) { #ifdef LIBMESH_HAVE_XDR case (XdrMGF::ENCODE): case (XdrMGF::DECODE): { mp_fp = fopen (fn, (m_type == ENCODE) ? "w" : "r"); // Make sure the file is ready for use if (!mp_fp) libmesh_error_msg("XDR Error: Accessing file: " << fn << " failed."); // Create the XDR handle mp_xdr_handle = new XDR; xdrstdio_create(mp_xdr_handle, mp_fp, ((m_type == ENCODE) ? XDR_ENCODE : XDR_DECODE)); break; } #endif case (XdrMGF::R_ASCII): { mp_in.open(fn, std::ios::in); // Make sure it opened correctly if (!mp_in.good()) libmesh_file_error(fn); break; } case (XdrMGF::W_ASCII): { mp_out.open(fn, std::ios::out); // Make sure it opened correctly if (!mp_out.good()) libmesh_file_error(fn); break; } default: libmesh_error_msg("Unrecognized file access type!"); } // Read/Write the file signature const int bufLen = 12; char buf[bufLen+1]; switch (m_type) { #ifdef LIBMESH_HAVE_XDR case (XdrMGF::ENCODE): { char* p = &buf[0]; const LegacyXdrIO::FileFormat orig = this->get_orig_flag(); std::ostringstream name; if (orig == LegacyXdrIO::DEAL) name << "DEAL 003:003"; else if (orig == LegacyXdrIO::MGF) name << "MGF 002:000"; else if (orig == LegacyXdrIO::LIBM) name << "LIBM " << this->get_num_levels(); else libmesh_error_msg("Unknown orig " << orig); // Fill the buffer std::sprintf(&buf[0], "%s", name.str().c_str()); xdr_string(mp_xdr_handle, &p, bufLen); // Writes binary signature break; } case (XdrMGF::DECODE): { char* p = &buf[0]; xdr_string(mp_xdr_handle, &p, bufLen); // Reads binary signature // Set the number of levels used in the mesh this->tokenize_first_line(p); break; } #endif case (XdrMGF::W_ASCII): { const LegacyXdrIO::FileFormat orig = this->get_orig_flag(); if (orig == LegacyXdrIO::DEAL) std::sprintf(&buf[0], "%s %03d:%03d", "DEAL", 3, 3); else if (orig == LegacyXdrIO::MGF) std::sprintf(&buf[0], "%s %03d:%03d", "MGF ", 2, 0); else if (orig == LegacyXdrIO::LIBM) std::sprintf(&buf[0], "%s %d", "LIBM", this->get_num_levels()); mp_out << buf << '\n'; break; } case (XdrMGF::R_ASCII): { #ifdef __HP_aCC // weirdly, _only_ here aCC // is not fond of mp_in.getline() // however, using mp_in.getline() // further below is ok... std::string buf_buf; std::getline (mp_in, buf_buf, '\n'); libmesh_assert_less_equal (buf_buf.size(), bufLen); buf_buf.copy (buf, std::string::npos); #else // Here we first use getline() to grab the very // first line of the file into a char buffer. Then // this line is tokenized to look for: // 1.) The name LIBM, which specifies the new Mesh style. // 2.) The number of levels in the Mesh which is being read. // Note that "buf" will be further processed below, here we // are just attempting to get the number of levels. mp_in.getline(buf, bufLen+1); #endif // Determine the number of levels in this mesh this->tokenize_first_line(buf); break; } default: libmesh_error_msg("Unknown m_type" << m_type); } // If you are reading or decoding, process the signature if ((m_type == R_ASCII) || (m_type == DECODE)) { char name[5]; std::strncpy(name, &buf[0], 4); name[4] = '\0'; if (std::strcmp (name, "DEAL") == 0) { this->orig_flag = LegacyXdrIO::DEAL; // 0 is the DEAL identifier by definition } else if (std::strcmp (name, "MGF ") == 0) { this->orig_flag = LegacyXdrIO::MGF; // 1 is the MGF identifier by definition } else if (std::strcmp (name, "LIBM") == 0) { this->orig_flag = LegacyXdrIO::LIBM; // the New and Improved XDA } else libmesh_error_msg("ERROR: No originating software can be determined for header string '" << name); } }
void PostscriptIO::write (const std::string& fname) { // We may need to gather a ParallelMesh to output it, making that // const qualifier in our constructor a dirty lie MeshSerializer serialize(const_cast<MeshBase&>(this->mesh()), !_is_parallel_format); if (this->mesh().processor_id() == 0) { // Get a constant reference to the mesh. const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh(); // Only works in 2D libmesh_assert_equal_to (the_mesh.mesh_dimension(), 2); // Create output file stream. // _out is now a private member of the class. _out.open(fname.c_str()); // Make sure it opened correctly if (!_out.good()) libmesh_file_error(fname.c_str()); // The mesh bounding box gives us info about what the // Postscript bounding box should be. MeshTools::BoundingBox bbox = MeshTools::bounding_box(the_mesh); // Add a little extra padding to the "true" bounding box so // that we can still see the boundary const Real percent_padding = 0.01; const Real dx=bbox.second(0)-bbox.first(0); libmesh_assert_greater (dx, 0.0); const Real dy=bbox.second(1)-bbox.first(1); libmesh_assert_greater (dy, 0.0); const Real x_min = bbox.first(0) - percent_padding*dx; const Real y_min = bbox.first(1) - percent_padding*dy; const Real x_max = bbox.second(0) + percent_padding*dx; const Real y_max = bbox.second(1) + percent_padding*dy; // Width of the output as given in postscript units. // This usually is given by the strange unit 1/72 inch. // A width of 300 represents a size of roughly 10 cm. const Real width = 300; _scale = width / (x_max-x_min); _offset(0) = x_min; _offset(1) = y_min; // Header writing stuff stolen from Deal.II std::time_t time1= std::time (0); std::tm *time = std::localtime(&time1); _out << "%!PS-Adobe-2.0 EPSF-1.2" << '\n' //<< "%!PS-Adobe-1.0" << '\n' // Lars' PS version << "%%Filename: " << fname << '\n' << "%%Title: LibMesh Output" << '\n' << "%%Creator: LibMesh: A C++ finite element library" << '\n' << "%%Creation Date: " << time->tm_year+1900 << "/" << time->tm_mon+1 << "/" << time->tm_mday << " - " << time->tm_hour << ":" << std::setw(2) << time->tm_min << ":" << std::setw(2) << time->tm_sec << '\n' << "%%BoundingBox: " // lower left corner << "0 0 " // upper right corner << static_cast<unsigned int>( rint((x_max-x_min) * _scale )) << ' ' << static_cast<unsigned int>( rint((y_max-y_min) * _scale )) << '\n'; // define some abbreviations to keep // the output small: // m=move turtle to // l=define a line // s=set rgb color // sg=set gray value // lx=close the line and plot the line // lf=close the line and fill the interior _out << "/m {moveto} bind def" << '\n' << "/l {lineto} bind def" << '\n' << "/s {setrgbcolor} bind def" << '\n' << "/sg {setgray} bind def" << '\n' << "/cs {curveto stroke} bind def" << '\n' << "/lx {lineto closepath stroke} bind def" << '\n' << "/lf {lineto closepath fill} bind def" << '\n'; _out << "%%EndProlog" << '\n'; // << '\n'; // Set line width in the postscript file. _out << line_width << " setlinewidth" << '\n'; // Set line cap and join options _out << "1 setlinecap" << '\n'; _out << "1 setlinejoin" << '\n'; // allow only five digits for output (instead of the default // six); this should suffice even for fine grids, but reduces // the file size significantly _out << std::setprecision (5); // Loop over the active elements, draw lines for the edges. We // draw even quadratic elements with straight sides, i.e. a straight // line sits between each pair of vertices. Also we draw every edge // for an element regardless of the fact that it may overlap with // another. This would probably be a useful optimization... MeshBase::const_element_iterator el = the_mesh.active_elements_begin(); const MeshBase::const_element_iterator end_el = the_mesh.active_elements_end(); for ( ; el != end_el; ++el) { //const Elem* elem = *el; this->plot_linear_elem(*el); //this->plot_quadratic_elem(*el); // Experimental } // Issue the showpage command, and we're done. _out << "showpage" << std::endl; } // end if (this->mesh().processor_id() == 0) }
void GnuPlotIO::write_solution(const std::string& fname, const std::vector<Number>* soln, const std::vector<std::string>* names) { // Even when writing on a serialized ParallelMesh, we expect // non-proc-0 help with calls like n_active_elem // libmesh_assert_equal_to (this->mesh().processor_id(), 0); const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh(); dof_id_type n_active_elem = the_mesh.n_active_elem(); if (this->mesh().processor_id() == 0) { std::stringstream data_stream_name; data_stream_name << fname << "_data"; const std::string data_file_name = data_stream_name.str(); // This class is designed only for use with 1D meshes libmesh_assert_equal_to (the_mesh.mesh_dimension(), 1); // Make sure we have a solution to plot libmesh_assert ((names != NULL) && (soln != NULL)); // Create an output stream for script file std::ofstream out_stream(fname.c_str()); // Make sure it opened correctly if (!out_stream.good()) libmesh_file_error(fname.c_str()); // The number of variables in the equation system const unsigned int n_vars = libmesh_cast_int<unsigned int>(names->size()); // Write header to stream out_stream << "# This file was generated by gnuplot_io.C\n" << "# Stores 1D solution data in GNUplot format\n" << "# Execute this by loading gnuplot and typing " << "\"call '" << fname << "'\"\n" << "reset\n" << "set title \"" << _title << "\"\n" << "set xlabel \"x\"\n" << "set xtics nomirror\n"; // Loop over the elements to find the minimum and maximum x values, // and also to find the element boundaries to write out as xtics // if requested. Real x_min=0., x_max=0.; // construct string for xtic positions at element edges std::stringstream xtics_stream; MeshBase::const_element_iterator it = the_mesh.active_elements_begin(); const MeshBase::const_element_iterator end_it = the_mesh.active_elements_end(); unsigned int count = 0; for( ; it != end_it; ++it) { const Elem* el = *it; // if el is the left edge of the mesh, print its left node position if(el->neighbor(0) == NULL) { x_min = (*(el->get_node(0)))(0); xtics_stream << "\"\" " << x_min << ", \\\n"; } if(el->neighbor(1) == NULL) { x_max = (*(el->get_node(1)))(0); } xtics_stream << "\"\" " << (*(el->get_node(1)))(0); if(count+1 != n_active_elem) { xtics_stream << ", \\\n"; } count++; } out_stream << "set xrange [" << x_min << ":" << x_max << "]\n"; if(_grid) out_stream << "set x2tics (" << xtics_stream.str() << ")\nset grid noxtics noytics x2tics\n"; if(_png_output) { out_stream << "set terminal png\n"; out_stream << "set output \"" << fname << ".png\"\n"; } out_stream << "plot " << axes_limits << " \"" << data_file_name << "\" using 1:2 title \"" << (*names)[0] << "\" with lines"; if(n_vars > 1) { for(unsigned int i=1; i<n_vars; i++) { out_stream << ", \\\n\"" << data_file_name << "\" using 1:" << i+2 << " title \"" << (*names)[i] << "\" with lines"; } } out_stream.close(); // Create an output stream for data file std::ofstream data(data_file_name.c_str()); if (!data.good()) { libMesh::err << "ERROR: opening output data file " << std::endl; libmesh_error(); } // get ordered nodal data using a map typedef std::pair<Real, std::vector<Number> > key_value_pair; typedef std::map<Real, std::vector<Number> > map_type; typedef map_type::iterator map_iterator; map_type node_map; it = the_mesh.active_elements_begin(); for ( ; it != end_it; ++it) { const Elem* elem = *it; for(unsigned int i=0; i<elem->n_nodes(); i++) { std::vector<Number> values; // Get the global id of the node dof_id_type global_id = elem->node(i); for(unsigned int c=0; c<n_vars; c++) { values.push_back( (*soln)[global_id*n_vars + c] ); } node_map[ the_mesh.point(global_id)(0) ] = values; } } map_iterator map_it = node_map.begin(); const map_iterator end_map_it = node_map.end(); for( ; map_it != end_map_it; ++map_it) { key_value_pair kvp = *map_it; std::vector<Number> values = kvp.second; data << kvp.first << "\t"; for(unsigned int i=0; i<values.size(); i++) { data << values[i] << "\t"; } data << "\n"; } data.close(); } }
void MEDITIO::write_ascii (const std::string & fname, const std::vector<Number> * vec, const std::vector<std::string> * solution_names) { // Current lacks in implementation: // (i) only 3D meshes. // (ii) only QUAD4, TRI3, TET4 elements, others are omitted ! // (iii) no distinction between materials. // (iv) no vector output, just first scalar as output // libmesh_assert three dimensions (should be extended later) libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().mesh_dimension(), 3); // Open the output file stream std::ofstream out_stream (fname.c_str()); // Make sure it opened correctly if (!out_stream.good()) libmesh_file_error(fname.c_str()); // Get a reference to the mesh const MeshBase & the_mesh = MeshOutput<MeshBase>::mesh(); // Begin interfacing with the MEdit data file { // header: out_stream << "MeshVersionFormatted 1\n"; out_stream << "Dimension 3\n"; out_stream << "# Mesh generated by libmesh\n\n"; // write the nodes: out_stream << "# Set of mesh vertices\n"; out_stream << "Vertices\n"; out_stream << the_mesh.n_nodes() << "\n"; for (unsigned int v=0; v<the_mesh.n_nodes(); v++) out_stream << the_mesh.point(v)(0) << " " << the_mesh.point(v)(1) << " " << the_mesh.point(v)(2) << " 0\n"; } { // write the connectivity: out_stream << "\n# Set of Polys\n\n"; // count occurrences of output elements: int n_tri3 = 0; int n_quad4 = 0; int n_tet4 = 0; for (const auto & elem : the_mesh.active_element_ptr_range()) { if (elem->type() == TRI3) n_tri3++; if (elem->type() == QUAD4) n_quad4++; if (elem->type() == QUAD9) n_quad4+=4; // (QUAD9 is written as 4 QUAD4.) if (elem->type() == TET4) n_tet4++; } // First: write out TRI3 elements: out_stream << "Triangles\n"; out_stream << n_tri3 << "\n"; for (const auto & elem : the_mesh.active_element_ptr_range()) if (elem->type() == TRI3) out_stream << elem->node_id(0)+1 << " " << elem->node_id(1)+1 << " " << elem->node_id(2)+1 << " 0\n"; // Second: write out QUAD4 elements: out_stream << "Quadrilaterals\n"; out_stream << n_quad4 << "\n"; for (const auto & elem : the_mesh.active_element_ptr_range()) { if (elem->type() == QUAD4) { out_stream << elem->node_id(0)+1 << " " << elem->node_id(1)+1 << " " << elem->node_id(2)+1 << " " << elem->node_id(3)+1 <<" 0\n"; } // if else if (elem->type() == QUAD9) { out_stream << elem->node_id(0)+1 << " " << elem->node_id(4)+1 << " " << elem->node_id(8)+1 << " " << elem->node_id(7)+1 <<" 0\n"; out_stream << elem->node_id(7)+1 << " " << elem->node_id(8)+1 << " " << elem->node_id(6)+1 << " " << elem->node_id(3)+1 <<" 0\n"; out_stream << elem->node_id(4)+1 << " " << elem->node_id(1)+1 << " " << elem->node_id(5)+1 << " " << elem->node_id(8)+1 <<" 0\n"; out_stream << elem->node_id(8)+1 << " " << elem->node_id(5)+1 << " " << elem->node_id(2)+1 << " " << elem->node_id(6)+1 <<" 0\n"; } } // Third: write out TET4 elements: out_stream << "Tetrahedra\n"; out_stream << n_tet4 << "\n"; for (const auto & elem : the_mesh.active_element_ptr_range()) if (elem->type() == TET4) { out_stream << elem->node_id(0)+1 << " " << elem->node_id(1)+1 << " " << elem->node_id(2)+1 << " " << elem->node_id(3)+1 <<" 0\n"; } } // end of the out file out_stream << '\n' << "# end of file\n"; // optionally write the data if ((solution_names != nullptr) && (vec != nullptr)) { // Open the ".bb" file stream std::size_t idx = fname.find_last_of("."); std::string bbname = fname.substr(0,idx) + ".bb"; std::ofstream bbout (bbname.c_str()); // Make sure it opened correctly if (!bbout.good()) libmesh_file_error(bbname.c_str()); // Header: 3: 3D mesh, 1: scalar output, 2: node-indexed const std::size_t n_vars = solution_names->size(); bbout << "3 1 " << the_mesh.n_nodes() << " 2\n"; for (dof_id_type n=0; n<the_mesh.n_nodes(); n++) bbout << std::setprecision(10) << (*vec)[n*n_vars + scalar_idx] << " "; bbout << "\n"; } // endif }
// ------------------------------------------------------------ // FroIO members void FroIO::write (const std::string & fname) { // We may need to gather a DistributedMesh to output it, making that // const qualifier in our constructor a dirty lie MeshSerializer serialize(const_cast<MeshBase &>(this->mesh()), !_is_parallel_format); if (this->mesh().processor_id() == 0) { // Open the output file stream std::ofstream out_stream (fname.c_str()); libmesh_assert (out_stream.good()); // Make sure it opened correctly if (!out_stream.good()) libmesh_file_error(fname.c_str()); // Get a reference to the mesh const MeshBase & the_mesh = MeshOutput<MeshBase>::mesh(); // Write the header out_stream << the_mesh.n_elem() << " " << the_mesh.n_nodes() << " " << "0 0 " << the_mesh.get_boundary_info().n_boundary_ids() << " 1\n"; // Write the nodes -- 1-based! for (unsigned int n=0; n<the_mesh.n_nodes(); n++) out_stream << n+1 << " \t" << std::scientific << std::setprecision(12) << the_mesh.point(n)(0) << " \t" << the_mesh.point(n)(1) << " \t" << 0. << '\n'; // Write the elements -- 1-based! unsigned int e = 0; for (const auto & elem : the_mesh.active_element_ptr_range()) { // .fro likes TRI3's if (elem->type() != TRI3) libmesh_error_msg("ERROR: .fro format only valid for triangles!\n" \ << " writing of " << fname << " aborted."); out_stream << ++e << " \t"; for (unsigned int n=0; n<elem->n_nodes(); n++) out_stream << elem->node_id(n)+1 << " \t"; // // LHS -> RHS Mapping, for inverted triangles // out_stream << elem->node_id(0)+1 << " \t"; // out_stream << elem->node_id(2)+1 << " \t"; // out_stream << elem->node_id(1)+1 << " \t"; out_stream << "1\n"; } // Write BCs. { const std::set<boundary_id_type> & bc_ids = the_mesh.get_boundary_info().get_boundary_ids(); std::vector<dof_id_type> el; std::vector<unsigned short int> sl; std::vector<boundary_id_type> il; the_mesh.get_boundary_info().build_side_list (el, sl, il); // Map the boundary ids into [1,n_bc_ids], // treat them one at a time. boundary_id_type bc_id=0; for (std::set<boundary_id_type>::const_iterator id = bc_ids.begin(); id != bc_ids.end(); ++id) { std::deque<dof_id_type> node_list; std::map<dof_id_type, dof_id_type> forward_edges, backward_edges; // Get all sides on this element with the relevant BC id. for (std::size_t e=0; e<el.size(); e++) if (il[e] == *id) { // need to build up node_list as a sorted array of edge nodes... // for the following: // a---b---c---d---e // node_list [ a b c d e]; // // the issue is just how to get this out of the elem/side based data structure. // the approach is to build up 'chain links' like this: // a---b b---c c---d d---e // and piece them together. // // so, for an arbitrary edge n0---n1, we build the // "forward_edges" map n0-->n1 // "backward_edges" map n1-->n0 // and then start with one chain link, and add on... // std::unique_ptr<const Elem> side = the_mesh.elem_ref(el[e]).build_side_ptr(sl[e]); const dof_id_type n0 = side->node_id(0), n1 = side->node_id(1); // insert into forward-edge set forward_edges.insert (std::make_pair(n0, n1)); // insert into backward-edge set backward_edges.insert (std::make_pair(n1, n0)); // go ahead and add one edge to the list -- this will give us the beginning of a // chain to work from! if (node_list.empty()) { node_list.push_front(n0); node_list.push_back (n1); } } // we now have the node_list with one edge, the forward_edges, and the backward_edges // the node_list will be filled when (node_list.size() == (n_edges+1)) // until that is the case simply add on to the beginning and end of the node_list, // building up a chain of ordered nodes... const std::size_t n_edges = forward_edges.size(); while (node_list.size() != (n_edges+1)) { const dof_id_type front_node = node_list.front(), back_node = node_list.back(); // look for front_pair in the backward_edges list { std::map<dof_id_type, dof_id_type>::iterator pos = backward_edges.find(front_node); if (pos != backward_edges.end()) { node_list.push_front(pos->second); backward_edges.erase(pos); } } // look for back_pair in the forward_edges list { std::map<dof_id_type, dof_id_type>::iterator pos = forward_edges.find(back_node); if (pos != forward_edges.end()) { node_list.push_back(pos->second); forward_edges.erase(pos); } } // libMesh::out << "node_list.size()=" << node_list.size() // << ", n_edges+1=" << n_edges+1 << std::endl; } out_stream << ++bc_id << " " << node_list.size() << '\n'; std::deque<dof_id_type>::iterator pos = node_list.begin(); for ( ; pos != node_list.end(); ++pos) out_stream << *pos+1 << " \t0\n"; } } } }
void TecplotIO::write_ascii (const std::string& fname, const std::vector<Number>* v, const std::vector<std::string>* solution_names) { // Should only do this on processor 0! libmesh_assert_equal_to (libMesh::processor_id(), 0); // Create an output stream std::ofstream out(fname.c_str()); // Make sure it opened correctly if (!out.good()) libmesh_file_error(fname.c_str()); // Get a constant reference to the mesh. const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); // Write header to stream { { // TODO: We used to print out the SVN revision here when we did keyword expansions... out << "# For a description of the Tecplot format see the Tecplot User's guide.\n" << "#\n"; } out << "Variables=x,y,z"; if (solution_names != NULL) for (unsigned int n=0; n<solution_names->size(); n++) { #ifdef LIBMESH_USE_REAL_NUMBERS // Write variable names for real variables out << "," << (*solution_names)[n]; #else // Write variable names for complex variables out << "," << "r_" << (*solution_names)[n] << "," << "i_" << (*solution_names)[n] << "," << "a_" << (*solution_names)[n]; #endif } out << '\n'; out << "Zone f=fepoint, n=" << mesh.n_nodes() << ", e=" << mesh.n_active_sub_elem(); if (mesh.mesh_dimension() == 1) out << ", et=lineseg"; else if (mesh.mesh_dimension() == 2) out << ", et=quadrilateral"; else if (mesh.mesh_dimension() == 3) out << ", et=brick"; else { // Dimension other than 1, 2, or 3? libmesh_error(); } // Use default mesh color = black out << ", c=black\n"; } // finished writing header for (unsigned int i=0; i<mesh.n_nodes(); i++) { // Print the point without a newline mesh.point(i).write_unformatted(out, false); if ((v != NULL) && (solution_names != NULL)) { const unsigned int n_vars = solution_names->size(); for (unsigned int c=0; c<n_vars; c++) { #ifdef LIBMESH_USE_REAL_NUMBERS // Write real data out << std::setprecision(this->ascii_precision()) << (*v)[i*n_vars + c] << " "; #else // Write complex data out << std::setprecision(this->ascii_precision()) << (*v)[i*n_vars + c].real() << " " << (*v)[i*n_vars + c].imag() << " " << std::abs((*v)[i*n_vars + c]) << " "; #endif } } // Write a new line after the data for this node out << '\n'; } // const_active_elem_iterator it (mesh.elements_begin()); // const const_active_elem_iterator end(mesh.elements_end()); MeshBase::const_element_iterator it = mesh.active_elements_begin(); const MeshBase::const_element_iterator end = mesh.active_elements_end(); for ( ; it != end; ++it) (*it)->write_connectivity(out, TECPLOT); }