LCOV - code coverage report
Current view: top level - src/mesh - unv_io.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 180 553 32.5 %
Date: 2025-08-19 19:27:09 Functions: 12 19 63.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : // Local includes
      20             : #include "libmesh/libmesh_config.h"
      21             : #include "libmesh/libmesh_logging.h"
      22             : #include "libmesh/unv_io.h"
      23             : #include "libmesh/mesh_base.h"
      24             : #include "libmesh/edge_edge2.h"
      25             : #include "libmesh/face_quad4.h"
      26             : #include "libmesh/face_tri3.h"
      27             : #include "libmesh/face_tri6.h"
      28             : #include "libmesh/face_quad8.h"
      29             : #include "libmesh/face_quad9.h"
      30             : #include "libmesh/cell_tet4.h"
      31             : #include "libmesh/cell_hex8.h"
      32             : #include "libmesh/cell_hex20.h"
      33             : #include "libmesh/cell_tet10.h"
      34             : #include "libmesh/cell_prism6.h"
      35             : #include "libmesh/utility.h"
      36             : #include "libmesh/boundary_info.h"
      37             : #include "libmesh/enum_to_string.h"
      38             : 
      39             : // C++ includes
      40             : #include <array>
      41             : #include <iomanip>
      42             : #include <algorithm> // for std::sort
      43             : #include <fstream>
      44             : #include <cctype>  // isspace
      45             : #include <sstream> // std::istringstream
      46             : #include <unordered_map>
      47             : 
      48             : #ifdef LIBMESH_HAVE_GZSTREAM
      49             : # include "gzstream.h" // For reading/writing compressed streams
      50             : #endif
      51             : 
      52             : 
      53             : 
      54             : namespace libMesh
      55             : {
      56             : 
      57             : //-----------------------------------------------------------------------------
      58             : // UNVIO class static members
      59             : const std::string UNVIO::_nodes_dataset_label    = "2411";
      60             : const std::string UNVIO::_elements_dataset_label = "2412";
      61             : const std::string UNVIO::_groups_dataset_label   = "2467";
      62             : 
      63             : 
      64             : 
      65             : // ------------------------------------------------------------
      66             : // UNVIO class members
      67             : 
      68          13 : UNVIO::UNVIO (MeshBase & mesh) :
      69             :   MeshInput<MeshBase> (mesh),
      70             :   MeshOutput<MeshBase>(mesh),
      71          13 :   _verbose (false)
      72             : {
      73          13 : }
      74             : 
      75             : 
      76             : 
      77           0 : UNVIO::UNVIO (const MeshBase & mesh) :
      78             :   MeshOutput<MeshBase> (mesh),
      79           0 :   _verbose (false)
      80             : {
      81           0 : }
      82             : 
      83             : 
      84             : 
      85          11 : UNVIO::~UNVIO () = default;
      86             : 
      87             : 
      88             : 
      89          39 : bool & UNVIO::verbose ()
      90             : {
      91          39 :   return _verbose;
      92             : }
      93             : 
      94             : 
      95             : 
      96          13 : void UNVIO::read (const std::string & file_name)
      97             : {
      98          13 :   if (Utility::contains(file_name, ".gz"))
      99             :     {
     100             : #ifdef LIBMESH_HAVE_GZSTREAM
     101             : 
     102           0 :       igzstream in_stream (file_name.c_str());
     103           0 :       this->read_implementation (in_stream);
     104             : 
     105             : #else
     106             : 
     107             :       libmesh_error_msg("ERROR:  You must have the zlib.h header files and libraries to read and write compressed streams.");
     108             : 
     109             : #endif
     110           0 :       return;
     111           0 :     }
     112             : 
     113             :   else
     114             :     {
     115          14 :       std::ifstream in_stream (file_name.c_str());
     116          13 :       this->read_implementation (in_stream);
     117           1 :       return;
     118          11 :     }
     119             : }
     120             : 
     121             : 
     122          13 : void UNVIO::read_implementation (std::istream & in_stream)
     123             : {
     124             :   // Keep track of what kinds of elements this file contains
     125          13 :   elems_of_dimension.clear();
     126          13 :   elems_of_dimension.resize(4, false);
     127             : 
     128             :   {
     129          14 :     libmesh_error_msg_if(!in_stream.good(), "ERROR: Input file not good.");
     130             : 
     131             :     // Flags to be set when certain sections are encountered
     132             :     bool
     133           1 :       found_node  = false,
     134           1 :       found_elem  = false,
     135           1 :       found_group = false;
     136             : 
     137             :     // strings for reading the file line by line
     138             :     std::string
     139           2 :       old_line,
     140           2 :       current_line;
     141             : 
     142             :     while (true)
     143             :       {
     144             :         // Save off the old_line.  This will provide extra reliability
     145             :         // for detecting the beginnings of the different sections.
     146           8 :         old_line = current_line;
     147             : 
     148             :         // Try to read something.  This may set EOF!
     149         103 :         std::getline(in_stream, current_line);
     150             : 
     151             :         // If the stream is still "valid", parse the line
     152         111 :         if (in_stream)
     153             :           {
     154             :             // UNV files always have some amount of leading
     155             :             // whitespace, let's not rely on exactly how much...  This
     156             :             // command deletes it.
     157          76 :             current_line.erase(std::remove_if(current_line.begin(), current_line.end(),
     158         302 :                                               [](unsigned char const c){return std::isspace(c);}),
     159          21 :                                current_line.end());
     160             : 
     161             :             // Parse the nodes section
     162          96 :             if (current_line == _nodes_dataset_label &&
     163           1 :                 old_line == "-1")
     164             :               {
     165           1 :                 found_node = true;
     166          13 :                 this->nodes_in(in_stream);
     167             :               }
     168             : 
     169             :             // Parse the elements section
     170          84 :             else if (current_line == _elements_dataset_label &&
     171           1 :                      old_line == "-1")
     172             :               {
     173             :                 // The current implementation requires the nodes to
     174             :                 // have been read before reaching the elements
     175             :                 // section.
     176          13 :                 libmesh_error_msg_if(!found_node,
     177             :                                      "ERROR: The Nodes section must come before the Elements section of the UNV file!");
     178             : 
     179           1 :                 found_elem = true;
     180          13 :                 this->elements_in(in_stream);
     181             :               }
     182             : 
     183             :             // Parse the groups section
     184          59 :             else if (current_line == _groups_dataset_label &&
     185           0 :                      old_line == "-1")
     186             :               {
     187             :                 // The current implementation requires the nodes and
     188             :                 // elements to have already been read before reaching
     189             :                 // the groups section.
     190           0 :                 libmesh_error_msg_if(!found_node || !found_elem,
     191             :                                      "ERROR: The Nodes and Elements sections must come before the Groups section of the UNV file!");
     192             : 
     193           0 :                 found_group = true;
     194           0 :                 this->groups_in(in_stream);
     195             :               }
     196             : 
     197             :             // We can stop reading once we've found the nodes, elements,
     198             :             // and group sections.
     199          90 :             if (found_node && found_elem && found_group)
     200           0 :               break;
     201             : 
     202             :             // If we made it here, we're not done yet, so keep reading
     203           7 :             continue;
     204          76 :           }
     205             : 
     206             :         // if (!in_stream) check to see if EOF was set.  If so, break out of while loop.
     207          13 :         if (in_stream.eof())
     208           1 :           break;
     209             : 
     210             :         // If !in_stream and !in_stream.eof(), stream is in a bad state!
     211           0 :         libmesh_error_msg("Stream is bad! Perhaps the file does not exist?");
     212          83 :       } // end while (true)
     213             : 
     214             :     // By now we better have found the datasets for nodes and elements,
     215             :     // otherwise the unv file is bad!
     216          13 :     libmesh_error_msg_if(!found_node, "ERROR: Could not find nodes!");
     217          13 :     libmesh_error_msg_if(!found_elem, "ERROR: Could not find elements!");
     218             :   }
     219             : 
     220             : 
     221             : 
     222             :   {
     223             :     // Set the mesh dimension to the largest element dimension encountered
     224          13 :     MeshInput<MeshBase>::mesh().set_mesh_dimension(max_elem_dimension_seen());
     225             : 
     226             : #if LIBMESH_DIM < 3
     227             :     libmesh_error_msg_if(MeshInput<MeshBase>::mesh().mesh_dimension() > LIBMESH_DIM,
     228             :                          "Cannot open dimension "
     229             :                          << MeshInput<MeshBase>::mesh().mesh_dimension()
     230             :                          << " mesh file when configured without "
     231             :                          << MeshInput<MeshBase>::mesh().mesh_dimension()
     232             :                          << "D support." );
     233             : #endif
     234             : 
     235             :     // Delete any lower-dimensional elements that might have been
     236             :     // added to the mesh strictly for setting BCs.
     237             :     {
     238             :       // Grab reference to the Mesh
     239          13 :       MeshBase & mesh = MeshInput<MeshBase>::mesh();
     240             : 
     241          13 :       unsigned char max_dim = this->max_elem_dimension_seen();
     242             : 
     243       78065 :       for (const auto & elem : mesh.element_ptr_range())
     244       42540 :         if (elem->dim() < max_dim)
     245          11 :           mesh.delete_elem(elem);
     246             :     }
     247             : 
     248          13 :     if (this->verbose())
     249           0 :       libMesh::out << "  Finished." << std::endl << std::endl;
     250             :   }
     251          13 : }
     252             : 
     253             : 
     254             : 
     255             : 
     256             : 
     257           0 : void UNVIO::write (const std::string & file_name)
     258             : {
     259           0 :   if (Utility::contains(file_name, ".gz"))
     260             :     {
     261             : #ifdef LIBMESH_HAVE_GZSTREAM
     262             : 
     263           0 :       ogzstream out_stream(file_name.c_str());
     264           0 :       this->write_implementation (out_stream);
     265             : 
     266             : #else
     267             : 
     268             :       libmesh_error_msg("ERROR:  You must have the zlib.h header files and libraries to read and write compressed streams.");
     269             : 
     270             : #endif
     271             : 
     272           0 :       return;
     273           0 :     }
     274             : 
     275             :   else
     276             :     {
     277           0 :       std::ofstream out_stream (file_name.c_str());
     278           0 :       this->write_implementation (out_stream);
     279           0 :       return;
     280           0 :     }
     281             : }
     282             : 
     283             : 
     284             : 
     285             : 
     286           0 : void UNVIO::write_implementation (std::ostream & out_file)
     287             : {
     288           0 :   libmesh_error_msg_if(!out_file.good(), "ERROR: Output file not good.");
     289             : 
     290             :   // write the nodes, then the elements
     291           0 :   this->nodes_out    (out_file);
     292           0 :   this->elements_out (out_file);
     293           0 : }
     294             : 
     295             : 
     296             : 
     297             : 
     298          13 : void UNVIO::nodes_in (std::istream & in_file)
     299             : {
     300           2 :   LOG_SCOPE("nodes_in()","UNVIO");
     301             : 
     302          13 :   if (this->verbose())
     303           0 :     libMesh::out << "  Reading nodes" << std::endl;
     304             : 
     305          13 :   MeshBase & mesh = MeshInput<MeshBase>::mesh();
     306             : 
     307             :   // node label, we use an int here so we can read in a -1
     308             :   int node_label;
     309             : 
     310             :   // We'll just read the floating point values as strings even when
     311             :   // there are no "D" characters in the file.  This will make parsing
     312             :   // the file a bit slower but the logic to do so will all be
     313             :   // simplified and in one place...
     314           2 :   std::string line;
     315          14 :   std::istringstream coords_stream;
     316             : 
     317             :   // Continue reading nodes until there are none left
     318           1 :   unsigned ctr = 0;
     319             :   while (true)
     320             :     {
     321             :       // Read the node label
     322       49018 :       in_file >> node_label;
     323             : 
     324             :       // Break out of the while loop when we hit -1
     325       49018 :       if (node_label == -1)
     326           1 :         break;
     327             : 
     328             :       // Read and discard the the rest of the node data on this line
     329             :       // which we do not currently use:
     330             :       // .) exp_coord_sys_num
     331             :       // .) disp_coord_sys_num
     332             :       // .) color
     333       49005 :       std::getline(in_file, line);
     334             : 
     335             :       // read the floating-point data
     336       49005 :       std::getline(in_file, line);
     337             : 
     338             :       // Replace any "D" characters used for exponents with "E"
     339        3977 :       size_t last_pos = 0;
     340             :       while (true)
     341             :         {
     342      176269 :           last_pos = line.find("D", last_pos);
     343             : 
     344      192177 :           if (last_pos != std::string::npos)
     345      143172 :             line.replace(last_pos, 1, "E");
     346             :           else
     347        3977 :             break;
     348             :         }
     349             : 
     350             :       // Construct a stream object from the current line and then
     351             :       // stream in the xyz values.
     352        3977 :       coords_stream.str(line);
     353       49005 :       coords_stream.clear(); // clear iostate bits!  Important!
     354             : 
     355             :       // always 3 coordinates in the UNV file, no matter
     356             :       // what LIBMESH_DIM is.
     357             :       std::array<Real, 3> xyz;
     358             : 
     359        3977 :       coords_stream >> xyz[0] >> xyz[1] >> xyz[2];
     360             : 
     361       49005 :       Point p(xyz[0]);
     362             : #if LIBMESH_DIM > 1
     363       49005 :       p(1) = xyz[1];
     364             : #else
     365             :       libmesh_assert_equal_to(xyz[1], 0);
     366             : #endif
     367             : #if LIBMESH_DIM > 2
     368       49005 :       p(2) = xyz[2];
     369             : #else
     370             :       libmesh_assert_equal_to(xyz[2], 0);
     371             : #endif
     372             : 
     373             :       // Add node to the Mesh, bump the counter.
     374       49005 :       Node * added_node = mesh.add_point(p, ctr++);
     375             : 
     376             :       // Maintain the mapping between UNV node ids and libmesh Node
     377             :       // pointers.
     378       49005 :       _unv_node_id_to_libmesh_node_ptr[node_label] = added_node;
     379       49005 :     }
     380          24 : }
     381             : 
     382             : 
     383             : 
     384          26 : unsigned char UNVIO::max_elem_dimension_seen ()
     385             : {
     386           2 :   unsigned char max_dim = 0;
     387             : 
     388             :   unsigned char elem_dimensions_size = cast_int<unsigned char>
     389           2 :     (elems_of_dimension.size());
     390             :   // The elems_of_dimension array is 1-based in the UNV reader
     391         104 :   for (unsigned char i=1; i<elem_dimensions_size; ++i)
     392          84 :     if (elems_of_dimension[i])
     393           2 :       max_dim = i;
     394             : 
     395          26 :   return max_dim;
     396             : }
     397             : 
     398             : 
     399             : 
     400         160 : bool UNVIO::need_D_to_e (std::string & number)
     401             : {
     402             :   // find "D" in string, start looking at 6th element since dont expect a "D" earlier.
     403         160 :   std::string::size_type position = number.find("D", 6);
     404             : 
     405         160 :   if (position != std::string::npos)
     406             :     {
     407             :       // replace "D" in string
     408           0 :       number.replace(position, 1, "e");
     409           0 :       return true;
     410             :     }
     411             :   else
     412           0 :     return false;
     413             : }
     414             : 
     415             : 
     416             : 
     417           0 : void UNVIO::groups_in (std::istream & in_file)
     418             : {
     419             :   // Grab reference to the Mesh, so we can add boundary info data to it
     420           0 :   MeshBase & mesh = MeshInput<MeshBase>::mesh();
     421             : 
     422             :   // Record the max and min element dimension seen while reading the file.
     423           0 :   unsigned char max_dim = this->max_elem_dimension_seen();
     424             : 
     425             :   // Container which stores lower-dimensional elements (based on
     426             :   // Elem::key()) for later assignment of boundary conditions.  We
     427             :   // could use e.g. an unordered_set with Elems as keys for this, but
     428             :   // this turns out to be much slower on the search side, since we
     429             :   // have to build an entire side in order to search, rather than just
     430             :   // calling elem->key(side) to compute a key.
     431             :   typedef std::unordered_multimap<dof_id_type, Elem *> map_type;
     432           0 :   map_type provide_bcs;
     433             : 
     434             :   // Read groups until there aren't any more to read...
     435             :   while (true)
     436             :     {
     437             :       // If we read a -1, it means there is nothing else to read in this section.
     438             :       int group_number;
     439           0 :       in_file >> group_number;
     440             : 
     441           0 :       if (group_number == -1)
     442           0 :         break;
     443             : 
     444             :       // The first record consists of 8 entries:
     445             :       // Field 1 -- group number (that we just read)
     446             :       // Field 2 -- active constraint set no. for group
     447             :       // Field 3 -- active restraint set no. for group
     448             :       // Field 4 -- active load set no. for group
     449             :       // Field 5 -- active dof set no. for group
     450             :       // Field 6 -- active temperature set no. for group
     451             :       // Field 7 -- active contact set no. for group
     452             :       // Field 8 -- number of entities in group
     453             :       // Only the first and last of these are relevant to us...
     454             :       unsigned num_entities;
     455           0 :       std::string group_name;
     456             :       {
     457             :         unsigned dummy;
     458           0 :         in_file >> dummy >> dummy >> dummy >> dummy >> dummy >> dummy
     459           0 :                 >> num_entities;
     460             : 
     461             :         // The second record has 1 field, the group name
     462           0 :         in_file >> group_name;
     463             :       }
     464             : 
     465             :       // The dimension of the elements in the group will determine
     466             :       // whether this is a sideset group or a subdomain group.
     467             :       bool
     468           0 :         is_subdomain_group = false,
     469           0 :         is_sideset_group = false;
     470             : 
     471             :       // Each subsequent line has 8 entries, there are two entity type
     472             :       // codes and two tags per line that we need to read.  In all my
     473             :       // examples, the entity type code was always "8", which stands for
     474             :       // "finite elements" but it's possible that we could eventually
     475             :       // support other entity type codes...
     476             :       // Field 1 -- entity type code
     477             :       // Field 2 -- entity tag
     478             :       // Field 3 -- entity node leaf id.
     479             :       // Field 4 -- entity component/ ham id.
     480             :       // Field 5 -- entity type code
     481             :       // Field 6 -- entity tag
     482             :       // Field 7 -- entity node leaf id.
     483             :       // Field 8 -- entity component/ ham id.
     484             :       {
     485             :         unsigned entity_type_code, entity_tag, dummy;
     486           0 :         for (unsigned entity=0; entity<num_entities; ++entity)
     487             :           {
     488           0 :             in_file >> entity_type_code >> entity_tag >> dummy >> dummy;
     489             : 
     490           0 :             if (entity_type_code != 8)
     491           0 :               libMesh::err << "Warning, unrecognized entity type code = "
     492           0 :                            << entity_type_code
     493           0 :                            << " in group "
     494           0 :                            << group_name
     495           0 :                            << std::endl;
     496             : 
     497             :             // Try to find this ID in the map from UNV element ids to libmesh ids.
     498           0 :             if (const auto it = _unv_elem_id_to_libmesh_elem_id.find(entity_tag);
     499           0 :                 it != _unv_elem_id_to_libmesh_elem_id.end())
     500             :               {
     501           0 :                 unsigned libmesh_elem_id = it->second;
     502             : 
     503             :                 // Attempt to get a pointer to the elem listed in the group
     504           0 :                 Elem * group_elem = mesh.elem_ptr(libmesh_elem_id);
     505             : 
     506             :                 // dim < max_dim means the Elem defines a boundary condition
     507           0 :                 if (group_elem->dim() < max_dim)
     508             :                   {
     509           0 :                     is_sideset_group = true;
     510             : 
     511             :                     // We can only handle elements that are *exactly*
     512             :                     // one dimension lower than the max element
     513             :                     // dimension.  Not sure if "edge" BCs in 3D
     514             :                     // actually make sense/are required...
     515           0 :                     libmesh_error_msg_if(group_elem->dim()+1 != max_dim,
     516             :                                          "ERROR: Expected boundary element of dimension "
     517             :                                          << max_dim-1 << " but got " << group_elem->dim());
     518             : 
     519             :                     // Set the current group number as the lower-dimensional element's subdomain ID.
     520             :                     // We will use this later to set a boundary ID.
     521           0 :                     group_elem->subdomain_id() =
     522           0 :                       cast_int<subdomain_id_type>(group_number);
     523             : 
     524             :                     // Store the lower-dimensional element in the provide_bcs container.
     525           0 :                     provide_bcs.emplace(group_elem->key(), group_elem);
     526             :                   }
     527             : 
     528             :                 // dim == max_dim means this group defines a subdomain ID
     529           0 :                 else if (group_elem->dim() == max_dim)
     530             :                   {
     531           0 :                     is_subdomain_group = true;
     532           0 :                     group_elem->subdomain_id() =
     533           0 :                       cast_int<subdomain_id_type>(group_number);
     534             :                   }
     535             : 
     536             :                 else
     537           0 :                   libmesh_error_msg("ERROR: Found an elem with dim=" \
     538             :                                     << group_elem->dim() << " > " << "max_dim=" << +max_dim);
     539             :               }
     540             :             else
     541           0 :               libMesh::err << "WARNING: UNV Element " << entity_tag << " not found while parsing groups." << std::endl;
     542             :           } // end for (entity)
     543             :       } // end scope
     544             : 
     545             :       // Associate this group_number with the group_name in the BoundaryInfo object.
     546           0 :       if (is_sideset_group)
     547           0 :         mesh.get_boundary_info().sideset_name
     548           0 :           (cast_int<boundary_id_type>(group_number)) = group_name;
     549             : 
     550           0 :       if (is_subdomain_group)
     551             :         mesh.subdomain_name
     552           0 :           (cast_int<subdomain_id_type>(group_number)) = group_name;
     553             : 
     554           0 :     } // end while (true)
     555             : 
     556             :   // Loop over elements and try to assign boundary information
     557           0 :   for (auto & elem : mesh.active_element_ptr_range())
     558           0 :     if (elem->dim() == max_dim)
     559           0 :       for (auto sn : elem->side_index_range())
     560           0 :         for (const auto & pr : as_range(provide_bcs.equal_range (elem->key(sn))))
     561             :           {
     562             :             // This is a max-dimension element that may require BCs.
     563             :             // For each of its sides, including internal sides, we'll
     564             :             // see if a lower-dimensional element provides boundary
     565             :             // information for it.  Note that we have not yet called
     566             :             // find_neighbors(), so we can't use elem->neighbor(sn) in
     567             :             // this algorithm...
     568             : 
     569             :             // Build a side to confirm the hash mapped to the correct side.
     570           0 :             std::unique_ptr<Elem> side (elem->build_side_ptr(sn));
     571             : 
     572             :             // Get a pointer to the lower-dimensional element
     573           0 :             Elem * lower_dim_elem = pr.second;
     574             : 
     575             :             // This was a hash, so it might not be perfect.  Let's verify...
     576           0 :             if (*lower_dim_elem == *side)
     577           0 :               mesh.get_boundary_info().add_side(elem, sn, lower_dim_elem->subdomain_id());
     578           0 :           }
     579           0 : }
     580             : 
     581             : 
     582             : 
     583          13 : void UNVIO::elements_in (std::istream & in_file)
     584             : {
     585           2 :   LOG_SCOPE("elements_in()","UNVIO");
     586             : 
     587          13 :   if (this->verbose())
     588           0 :     libMesh::out << "  Reading elements" << std::endl;
     589             : 
     590          13 :   MeshBase & mesh = MeshInput<MeshBase>::mesh();
     591             : 
     592             :   // node label, we use an int here so we can read in a -1
     593             :   int element_label;
     594             : 
     595             :   unsigned
     596             :     n_nodes,           // number of nodes on element
     597             :     fe_descriptor_id,  // FE descriptor id
     598             :     phys_prop_tab_num, // physical property table number (not supported yet)
     599             :     mat_prop_tab_num,  // material property table number (not supported yet)
     600             :     color;             // color (not supported yet)
     601             : 
     602             :   // vector that temporarily holds the node labels defining element
     603          13 :   std::vector<unsigned int> node_labels (21);
     604             : 
     605             :   // vector that assigns element nodes to their correct position
     606             :   // for example:
     607             :   // 44:plane stress      | QUAD4
     608             :   // linear quadrilateral |
     609             :   // position in UNV-file | position in libmesh
     610             :   // assign_elem_node[1]   = 0
     611             :   // assign_elem_node[2]   = 3
     612             :   // assign_elem_node[3]   = 2
     613             :   // assign_elem_node[4]   = 1
     614             :   //
     615             :   // UNV is 1-based, we leave the 0th element of the vectors unused in order
     616             :   // to prevent confusion, this way we can store elements with up to 20 nodes
     617             :   unsigned int assign_elem_nodes[21];
     618             : 
     619             :   // Read elements until there are none left
     620           1 :   unsigned ctr = 0;
     621             :   while (true)
     622             :     {
     623             :       // read element label, break out when we read -1
     624       42553 :       in_file >> element_label;
     625             : 
     626       42553 :       if (element_label == -1)
     627           1 :         break;
     628             : 
     629        3520 :       in_file >> fe_descriptor_id        // read FE descriptor id
     630        3520 :               >> phys_prop_tab_num       // (not supported yet)
     631        3520 :               >> mat_prop_tab_num        // (not supported yet)
     632        3520 :               >> color                   // (not supported yet)
     633        3520 :               >> n_nodes;                // read number of nodes on element
     634             : 
     635             :       // For "beam" type elements, the next three numbers are:
     636             :       // .) beam orientation node number
     637             :       // .) beam fore-end cross section number
     638             :       // .) beam aft-end cross section number
     639             :       // which we discard in libmesh.  The "beam" type elements:
     640             :       // 11  Rod
     641             :       // 21  Linear beam
     642             :       // 22  Tapered beam
     643             :       // 23  Curved beam
     644             :       // 24  Parabolic beam
     645             :       // all have fe_descriptor_id < 25.
     646             :       // http://www.sdrl.uc.edu/universal-file-formats-for-modal-analysis-testing-1/file-format-storehouse/unv_2412.htm
     647       42540 :       if (fe_descriptor_id < 25)
     648             :         {
     649             :           unsigned dummy;
     650           0 :           in_file >> dummy >> dummy >> dummy;
     651             :         }
     652             : 
     653             :       // read node labels (1-based)
     654      371640 :       for (unsigned int j=1; j<=n_nodes; j++)
     655      329100 :         in_file >> node_labels[j];
     656             : 
     657             :       // element pointer, to be allocated
     658       35500 :       std::unique_ptr<Elem> elem;
     659             : 
     660       42540 :       switch (fe_descriptor_id)
     661             :         {
     662           0 :         case 11: // Rod
     663             :           {
     664           0 :             elem = Elem::build(EDGE2);
     665             : 
     666           0 :             assign_elem_nodes[1]=0;
     667           0 :             assign_elem_nodes[2]=1;
     668           0 :             break;
     669             :           }
     670             : 
     671           0 :         case 41: // Plane Stress Linear Triangle
     672             :         case 91: // Thin Shell   Linear Triangle
     673             :           {
     674           0 :             elem = Elem::build(TRI3);  // create new element
     675             : 
     676           0 :             assign_elem_nodes[1]=0;
     677           0 :             assign_elem_nodes[2]=2;
     678           0 :             assign_elem_nodes[3]=1;
     679           0 :             break;
     680             :           }
     681             : 
     682           0 :         case 42: // Plane Stress Quadratic Triangle
     683             :         case 92: // Thin Shell   Quadratic Triangle
     684             :           {
     685           0 :             elem = Elem::build(TRI6);  // create new element
     686             : 
     687           0 :             assign_elem_nodes[1]=0;
     688           0 :             assign_elem_nodes[2]=5;
     689           0 :             assign_elem_nodes[3]=2;
     690           0 :             assign_elem_nodes[4]=4;
     691           0 :             assign_elem_nodes[5]=1;
     692           0 :             assign_elem_nodes[6]=3;
     693           0 :             break;
     694             :           }
     695             : 
     696           0 :         case 43: // Plane Stress Cubic Triangle
     697           0 :           libmesh_error_msg("ERROR: UNV-element type 43: Plane Stress Cubic Triangle not supported.");
     698             : 
     699           0 :         case 44: // Plane Stress Linear Quadrilateral
     700             :         case 94: // Thin Shell   Linear Quadrilateral
     701             :           {
     702           0 :             elem = Elem::build(QUAD4); // create new element
     703             : 
     704           0 :             assign_elem_nodes[1]=0;
     705           0 :             assign_elem_nodes[2]=3;
     706           0 :             assign_elem_nodes[3]=2;
     707           0 :             assign_elem_nodes[4]=1;
     708           0 :             break;
     709             :           }
     710             : 
     711           0 :         case 45: // Plane Stress Quadratic Quadrilateral
     712             :         case 95: // Thin Shell   Quadratic Quadrilateral
     713             :           {
     714           0 :             elem = Elem::build(QUAD8); // create new element
     715             : 
     716           0 :             assign_elem_nodes[1]=0;
     717           0 :             assign_elem_nodes[2]=7;
     718           0 :             assign_elem_nodes[3]=3;
     719           0 :             assign_elem_nodes[4]=6;
     720           0 :             assign_elem_nodes[5]=2;
     721           0 :             assign_elem_nodes[6]=5;
     722           0 :             assign_elem_nodes[7]=1;
     723           0 :             assign_elem_nodes[8]=4;
     724           0 :             break;
     725             :           }
     726             : 
     727         300 :         case 300: // Thin Shell   Quadratic Quadrilateral (nine nodes)
     728             :           {
     729         600 :             elem = Elem::build(QUAD9); // create new element
     730             : 
     731         300 :             assign_elem_nodes[1]=0;
     732         300 :             assign_elem_nodes[2]=7;
     733         300 :             assign_elem_nodes[3]=3;
     734         300 :             assign_elem_nodes[4]=6;
     735         300 :             assign_elem_nodes[5]=2;
     736         300 :             assign_elem_nodes[6]=5;
     737         300 :             assign_elem_nodes[7]=1;
     738         300 :             assign_elem_nodes[8]=4;
     739         300 :             assign_elem_nodes[9]=8;
     740         300 :             break;
     741             :           }
     742             : 
     743           0 :         case 46: // Plane Stress Cubic Quadrilateral
     744           0 :           libmesh_error_msg("ERROR: UNV-element type 46: Plane Stress Cubic Quadrilateral not supported.");
     745             : 
     746           0 :         case 111: // Solid Linear Tetrahedron
     747             :           {
     748           0 :             elem = Elem::build(TET4);  // create new element
     749             : 
     750           0 :             assign_elem_nodes[1]=0;
     751           0 :             assign_elem_nodes[2]=1;
     752           0 :             assign_elem_nodes[3]=2;
     753           0 :             assign_elem_nodes[4]=3;
     754           0 :             break;
     755             :           }
     756             : 
     757        5760 :         case 112: // Solid Linear Prism
     758             :           {
     759       10560 :             elem = Elem::build(PRISM6);  // create new element
     760             : 
     761        5760 :             assign_elem_nodes[1]=0;
     762        5760 :             assign_elem_nodes[2]=1;
     763        5760 :             assign_elem_nodes[3]=2;
     764        5760 :             assign_elem_nodes[4]=3;
     765        5760 :             assign_elem_nodes[5]=4;
     766        5760 :             assign_elem_nodes[6]=5;
     767        5760 :             break;
     768             :           }
     769             : 
     770       36480 :         case 115: // Solid Linear Brick
     771             :           {
     772       66880 :             elem = Elem::build(HEX8);  // create new element
     773             : 
     774       36480 :             assign_elem_nodes[1]=0;
     775       36480 :             assign_elem_nodes[2]=4;
     776       36480 :             assign_elem_nodes[3]=5;
     777       36480 :             assign_elem_nodes[4]=1;
     778       36480 :             assign_elem_nodes[5]=3;
     779       36480 :             assign_elem_nodes[6]=7;
     780       36480 :             assign_elem_nodes[7]=6;
     781       36480 :             assign_elem_nodes[8]=2;
     782       36480 :             break;
     783             :           }
     784             : 
     785           0 :         case 116: // Solid Quadratic Brick
     786             :           {
     787           0 :             elem = Elem::build(HEX20); // create new element
     788             : 
     789           0 :             assign_elem_nodes[1]=0;
     790           0 :             assign_elem_nodes[2]=12;
     791           0 :             assign_elem_nodes[3]=4;
     792           0 :             assign_elem_nodes[4]=16;
     793           0 :             assign_elem_nodes[5]=5;
     794           0 :             assign_elem_nodes[6]=13;
     795           0 :             assign_elem_nodes[7]=1;
     796           0 :             assign_elem_nodes[8]=8;
     797             : 
     798           0 :             assign_elem_nodes[9]=11;
     799           0 :             assign_elem_nodes[10]=19;
     800           0 :             assign_elem_nodes[11]=17;
     801           0 :             assign_elem_nodes[12]=9;
     802             : 
     803           0 :             assign_elem_nodes[13]=3;
     804           0 :             assign_elem_nodes[14]=15;
     805           0 :             assign_elem_nodes[15]=7;
     806           0 :             assign_elem_nodes[16]=18;
     807           0 :             assign_elem_nodes[17]=6;
     808           0 :             assign_elem_nodes[18]=14;
     809           0 :             assign_elem_nodes[19]=2;
     810           0 :             assign_elem_nodes[20]=10;
     811           0 :             break;
     812             :           }
     813             : 
     814           0 :         case 117: // Solid Cubic Brick
     815           0 :           libmesh_error_msg("Error: UNV-element type 117: Solid Cubic Brick not supported.");
     816             : 
     817           0 :         case 118: // Solid Quadratic Tetrahedron
     818             :           {
     819           0 :             elem = Elem::build(TET10); // create new element
     820             : 
     821           0 :             assign_elem_nodes[1]=0;
     822           0 :             assign_elem_nodes[2]=4;
     823           0 :             assign_elem_nodes[3]=1;
     824           0 :             assign_elem_nodes[4]=5;
     825           0 :             assign_elem_nodes[5]=2;
     826           0 :             assign_elem_nodes[6]=6;
     827           0 :             assign_elem_nodes[7]=7;
     828           0 :             assign_elem_nodes[8]=8;
     829           0 :             assign_elem_nodes[9]=9;
     830           0 :             assign_elem_nodes[10]=3;
     831           0 :             break;
     832             :           }
     833             : 
     834           0 :         default: // Unrecognized element type
     835           0 :           libmesh_error_msg("ERROR: UNV-element type " << fe_descriptor_id << " not supported.");
     836             :         }
     837             : 
     838             :       // nodes are being stored in element
     839      371640 :       for (dof_id_type j=1; j<=n_nodes; j++)
     840             :         {
     841             :           // Map the UNV node ID to the libmesh node ID
     842             :           auto & node_ptr =
     843      356300 :             libmesh_map_find(_unv_node_id_to_libmesh_node_ptr, node_labels[j]);
     844             : 
     845      329100 :           elem->set_node(assign_elem_nodes[j], node_ptr);
     846             :         }
     847             : 
     848       42540 :       elems_of_dimension[elem->dim()] = true;
     849             : 
     850             :       // Set the element's ID
     851       35200 :       elem->set_id(ctr);
     852             : 
     853             :       // Maintain a map from the libmesh (0-based) numbering to the
     854             :       // UNV numbering.
     855       42540 :       _unv_elem_id_to_libmesh_elem_id[element_label] = ctr;
     856             : 
     857             :       // Add the element to the Mesh
     858       46060 :       mesh.add_elem(std::move(elem));
     859             : 
     860             :       // Increment the counter for the next iteration
     861       42540 :       ctr++;
     862       42540 :     } // end while (true)
     863          13 : }
     864             : 
     865             : 
     866             : 
     867             : 
     868             : 
     869             : 
     870           0 : void UNVIO::nodes_out (std::ostream & out_file)
     871             : {
     872           0 :   if (this->verbose())
     873           0 :     libMesh::out << "  Writing " << MeshOutput<MeshBase>::mesh().n_nodes() << " nodes" << std::endl;
     874             : 
     875             :   // Write beginning of dataset
     876             :   out_file << "    -1\n"
     877             :            << "  "
     878             :            << _nodes_dataset_label
     879           0 :            << '\n';
     880             : 
     881             :   unsigned int
     882           0 :     exp_coord_sys_dummy  = 0, // export coordinate sys. (not supported yet)
     883           0 :     disp_coord_sys_dummy = 0, // displacement coordinate sys. (not supp. yet)
     884           0 :     color_dummy          = 0; // color(not supported yet)
     885             : 
     886             :   // A reference to the parent class's mesh
     887           0 :   const MeshBase & mesh = MeshOutput<MeshBase>::mesh();
     888             : 
     889             :   // Use scientific notation with capital E and default 17 digits for printing out the coordinates
     890           0 :   out_file << std::scientific << std::setprecision(this->ascii_precision()) << std::uppercase;
     891             : 
     892           0 :   for (const auto & current_node : mesh.node_ptr_range())
     893             :     {
     894           0 :       dof_id_type node_id = current_node->id();
     895             : 
     896           0 :       out_file << std::setw(10) << node_id
     897           0 :                << std::setw(10) << exp_coord_sys_dummy
     898           0 :                << std::setw(10) << disp_coord_sys_dummy
     899           0 :                << std::setw(10) << color_dummy
     900           0 :                << '\n';
     901             : 
     902             :       // The coordinates - always write out three coords regardless of LIBMESH_DIM
     903           0 :       Real x = (*current_node)(0);
     904             : 
     905             : #if LIBMESH_DIM > 1
     906           0 :       Real y = (*current_node)(1);
     907             : #else
     908             :       Real y = 0.;
     909             : #endif
     910             : 
     911             : #if LIBMESH_DIM > 2
     912           0 :       Real z = (*current_node)(2);
     913             : #else
     914             :       Real z = 0.;
     915             : #endif
     916             : 
     917           0 :       out_file << std::setw(25) << x
     918           0 :                << std::setw(25) << y
     919           0 :                << std::setw(25) << z
     920           0 :                << '\n';
     921           0 :     }
     922             : 
     923             :   // Write end of dataset
     924           0 :   out_file << "    -1\n";
     925           0 : }
     926             : 
     927             : 
     928             : 
     929             : 
     930             : 
     931             : 
     932           0 : void UNVIO::elements_out(std::ostream & out_file)
     933             : {
     934           0 :   if (this->verbose())
     935           0 :     libMesh::out << "  Writing elements" << std::endl;
     936             : 
     937             :   // Write beginning of dataset
     938             :   out_file << "    -1\n"
     939             :            << "  "
     940             :            << _elements_dataset_label
     941           0 :            << "\n";
     942             : 
     943             :   unsigned
     944           0 :     fe_descriptor_id = 0,    // FE descriptor id
     945           0 :     phys_prop_tab_dummy = 2, // physical property (not supported yet)
     946           0 :     mat_prop_tab_dummy = 1,  // material property (not supported yet)
     947           0 :     color_dummy = 7;         // color (not supported yet)
     948             : 
     949             :   // vector that assigns element nodes to their correct position
     950             :   // currently only elements with up to 20 nodes
     951             :   //
     952             :   // Example:
     953             :   // QUAD4               | 44:plane stress
     954             :   //                     | linear quad
     955             :   // position in libMesh | UNV numbering
     956             :   // (note: 0-based)     | (note: 1-based)
     957             :   //
     958             :   // assign_elem_node[0]  = 0
     959             :   // assign_elem_node[1]  = 3
     960             :   // assign_elem_node[2]  = 2
     961             :   // assign_elem_node[3]  = 1
     962             :   unsigned int assign_elem_nodes[20];
     963             : 
     964           0 :   unsigned int n_elem_written=0;
     965             : 
     966             :   // A reference to the parent class's mesh
     967           0 :   const MeshBase & mesh = MeshOutput<MeshBase>::mesh();
     968             : 
     969           0 :   for (const auto & elem : mesh.element_ptr_range())
     970             :     {
     971           0 :       switch (elem->type())
     972             :         {
     973             : 
     974           0 :         case TRI3:
     975             :           {
     976           0 :             fe_descriptor_id = 41; // Plane Stress Linear Triangle
     977           0 :             assign_elem_nodes[0] = 0;
     978           0 :             assign_elem_nodes[1] = 2;
     979           0 :             assign_elem_nodes[2] = 1;
     980           0 :             break;
     981             :           }
     982             : 
     983           0 :         case TRI6:
     984             :           {
     985           0 :             fe_descriptor_id = 42; // Plane Stress Quadratic Triangle
     986           0 :             assign_elem_nodes[0] = 0;
     987           0 :             assign_elem_nodes[1] = 5;
     988           0 :             assign_elem_nodes[2] = 2;
     989           0 :             assign_elem_nodes[3] = 4;
     990           0 :             assign_elem_nodes[4] = 1;
     991           0 :             assign_elem_nodes[5] = 3;
     992           0 :             break;
     993             :           }
     994             : 
     995           0 :         case QUAD4:
     996             :           {
     997           0 :             fe_descriptor_id = 44; // Plane Stress Linear Quadrilateral
     998           0 :             assign_elem_nodes[0] = 0;
     999           0 :             assign_elem_nodes[1] = 3;
    1000           0 :             assign_elem_nodes[2] = 2;
    1001           0 :             assign_elem_nodes[3] = 1;
    1002           0 :             break;
    1003             :           }
    1004             : 
    1005           0 :         case QUAD8:
    1006             :           {
    1007           0 :             fe_descriptor_id = 45; // Plane Stress Quadratic Quadrilateral
    1008           0 :             assign_elem_nodes[0] = 0;
    1009           0 :             assign_elem_nodes[1] = 7;
    1010           0 :             assign_elem_nodes[2] = 3;
    1011           0 :             assign_elem_nodes[3] = 6;
    1012           0 :             assign_elem_nodes[4] = 2;
    1013           0 :             assign_elem_nodes[5] = 5;
    1014           0 :             assign_elem_nodes[6] = 1;
    1015           0 :             assign_elem_nodes[7] = 4;
    1016           0 :             break;
    1017             :           }
    1018             : 
    1019           0 :         case QUAD9:
    1020             :           {
    1021           0 :             fe_descriptor_id = 300; // Plane Stress Quadratic Quadrilateral
    1022           0 :             assign_elem_nodes[0] = 0;
    1023           0 :             assign_elem_nodes[1] = 7;
    1024           0 :             assign_elem_nodes[2] = 3;
    1025           0 :             assign_elem_nodes[3] = 6;
    1026           0 :             assign_elem_nodes[4] = 2;
    1027           0 :             assign_elem_nodes[5] = 5;
    1028           0 :             assign_elem_nodes[6] = 1;
    1029           0 :             assign_elem_nodes[7] = 4;
    1030           0 :             assign_elem_nodes[8] = 8;
    1031           0 :             break;
    1032             :           }
    1033             : 
    1034           0 :         case TET4:
    1035             :           {
    1036           0 :             fe_descriptor_id = 111; // Solid Linear Tetrahedron
    1037           0 :             assign_elem_nodes[0] = 0;
    1038           0 :             assign_elem_nodes[1] = 1;
    1039           0 :             assign_elem_nodes[2] = 2;
    1040           0 :             assign_elem_nodes[3] = 3;
    1041           0 :             break;
    1042             :           }
    1043             : 
    1044           0 :         case PRISM6:
    1045             :           {
    1046           0 :             fe_descriptor_id = 112; // Solid Linear Prism
    1047           0 :             assign_elem_nodes[0] = 0;
    1048           0 :             assign_elem_nodes[1] = 1;
    1049           0 :             assign_elem_nodes[2] = 2;
    1050           0 :             assign_elem_nodes[3] = 3;
    1051           0 :             assign_elem_nodes[4] = 4;
    1052           0 :             assign_elem_nodes[5] = 5;
    1053           0 :             break;
    1054             :           }
    1055             : 
    1056           0 :         case HEX8:
    1057             :           {
    1058           0 :             fe_descriptor_id = 115; // Solid Linear Brick
    1059           0 :             assign_elem_nodes[0] = 0;
    1060           0 :             assign_elem_nodes[1] = 4;
    1061           0 :             assign_elem_nodes[2] = 5;
    1062           0 :             assign_elem_nodes[3] = 1;
    1063           0 :             assign_elem_nodes[4] = 3;
    1064           0 :             assign_elem_nodes[5] = 7;
    1065           0 :             assign_elem_nodes[6] = 6;
    1066           0 :             assign_elem_nodes[7] = 2;
    1067           0 :             break;
    1068             :           }
    1069             : 
    1070           0 :         case HEX20:
    1071             :           {
    1072           0 :             fe_descriptor_id = 116; // Solid Quadratic Brick
    1073           0 :             assign_elem_nodes[ 0] = 0;
    1074           0 :             assign_elem_nodes[ 1] = 12;
    1075           0 :             assign_elem_nodes[ 2] = 4;
    1076           0 :             assign_elem_nodes[ 3] = 16;
    1077           0 :             assign_elem_nodes[ 4] = 5;
    1078           0 :             assign_elem_nodes[ 5] = 13;
    1079           0 :             assign_elem_nodes[ 6] = 1;
    1080           0 :             assign_elem_nodes[ 7] = 8;
    1081             : 
    1082           0 :             assign_elem_nodes[ 8] = 11;
    1083           0 :             assign_elem_nodes[ 9] = 19;
    1084           0 :             assign_elem_nodes[10] = 17;
    1085           0 :             assign_elem_nodes[11] = 9;
    1086             : 
    1087           0 :             assign_elem_nodes[12] = 3;
    1088           0 :             assign_elem_nodes[13] = 15;
    1089           0 :             assign_elem_nodes[14] = 7;
    1090           0 :             assign_elem_nodes[15] = 18;
    1091           0 :             assign_elem_nodes[16] = 6;
    1092           0 :             assign_elem_nodes[17] = 14;
    1093           0 :             assign_elem_nodes[18] = 2;
    1094           0 :             assign_elem_nodes[19] = 10;
    1095             : 
    1096             : 
    1097           0 :             break;
    1098             :           }
    1099             : 
    1100           0 :         case TET10:
    1101             :           {
    1102           0 :             fe_descriptor_id = 118; // Solid Quadratic Tetrahedron
    1103           0 :             assign_elem_nodes[0] = 0;
    1104           0 :             assign_elem_nodes[1] = 4;
    1105           0 :             assign_elem_nodes[2] = 1;
    1106           0 :             assign_elem_nodes[3] = 5;
    1107           0 :             assign_elem_nodes[4] = 2;
    1108           0 :             assign_elem_nodes[5] = 6;
    1109           0 :             assign_elem_nodes[6] = 7;
    1110           0 :             assign_elem_nodes[7] = 8;
    1111           0 :             assign_elem_nodes[8] = 9;
    1112           0 :             assign_elem_nodes[9] = 3;
    1113           0 :             break;
    1114             :           }
    1115             : 
    1116           0 :         default:
    1117           0 :           libmesh_error_msg("ERROR: Element type = " << Utility::enum_to_string(elem->type()) << " not supported in " << "UNVIO!");
    1118             :         }
    1119             : 
    1120           0 :       dof_id_type elem_id = elem->id();
    1121             : 
    1122           0 :       out_file << std::setw(10) << elem_id             // element ID
    1123           0 :                << std::setw(10) << fe_descriptor_id    // type of element
    1124           0 :                << std::setw(10) << phys_prop_tab_dummy // not supported
    1125           0 :                << std::setw(10) << mat_prop_tab_dummy  // not supported
    1126           0 :                << std::setw(10) << color_dummy         // not supported
    1127           0 :                << std::setw(10) << elem->n_nodes()     // No. of nodes per element
    1128           0 :                << '\n';
    1129             : 
    1130           0 :       for (auto j : elem->node_index_range())
    1131             :         {
    1132             :           // assign_elem_nodes[j]-th node: i.e., j loops over the
    1133             :           // libMesh numbering, and assign_elem_nodes[j] over the
    1134             :           // UNV numbering.
    1135           0 :           const Node * node_in_unv_order = elem->node_ptr(assign_elem_nodes[j]);
    1136             : 
    1137             :           // new record after 8 id entries
    1138           0 :           if (j==8 || j==16)
    1139           0 :             out_file << '\n';
    1140             : 
    1141             :           // Write foreign label for this node
    1142           0 :           dof_id_type node_id = node_in_unv_order->id();
    1143             : 
    1144           0 :           out_file << std::setw(10) << node_id;
    1145             :         }
    1146             : 
    1147           0 :       out_file << '\n';
    1148             : 
    1149           0 :       n_elem_written++;
    1150           0 :     }
    1151             : 
    1152           0 :   if (this->verbose())
    1153           0 :     libMesh::out << "  Finished writing " << n_elem_written << " elements" << std::endl;
    1154             : 
    1155             :   // Write end of dataset
    1156           0 :   out_file << "    -1\n";
    1157           0 : }
    1158             : 
    1159             : 
    1160             : 
    1161           1 : void UNVIO::read_dataset(std::string file_name)
    1162             : {
    1163           1 :   std::ifstream in_stream(file_name.c_str());
    1164             : 
    1165           1 :   libmesh_error_msg_if(!in_stream.good(), "Error opening UNV data file.");
    1166             : 
    1167           0 :   std::string olds, news, dummy;
    1168             : 
    1169             :   while (true)
    1170             :     {
    1171           2 :       in_stream >> olds >> news;
    1172             : 
    1173             :       // A "-1" followed by a number means the beginning of a dataset.
    1174           4 :       while (((olds != "-1") || (news == "-1")) && !in_stream.eof())
    1175             :         {
    1176           0 :           olds = news;
    1177           0 :           in_stream >> news;
    1178             :         }
    1179             : 
    1180           2 :       if (in_stream.eof())
    1181           0 :         break;
    1182             : 
    1183             :       // We only support reading datasets in the "2414" format.
    1184           1 :       if (news == "2414")
    1185             :         {
    1186             :           // Ignore the rest of the current line and the next two
    1187             :           // lines that contain analysis dataset label and name.
    1188           4 :           for (unsigned int i=0; i<3; i++)
    1189           3 :             std::getline(in_stream, dummy);
    1190             : 
    1191             :           // Read the dataset location, where
    1192             :           // 1: Data at nodes
    1193             :           // 2: Data on elements
    1194             :           // Currently only data on nodes is supported.
    1195             :           unsigned int dataset_location;
    1196           0 :           in_stream >> dataset_location;
    1197             : 
    1198             :           // Currently only nodal datasets are supported.
    1199           1 :           libmesh_error_msg_if(dataset_location != 1, "ERROR: Currently only Data at nodes is supported.");
    1200             : 
    1201             :           // Ignore the rest of this line and the next five records.
    1202           7 :           for (unsigned int i=0; i<6; i++)
    1203           6 :             std::getline(in_stream, dummy);
    1204             : 
    1205             :           // These data are all of no interest to us...
    1206             :           unsigned int
    1207             :             model_type,
    1208             :             analysis_type,
    1209             :             data_characteristic,
    1210             :             result_type;
    1211             : 
    1212             :           // The type of data (complex, real, float, double etc, see
    1213             :           // below).
    1214             :           unsigned int data_type;
    1215             : 
    1216             :           // The number of floating-point values per entity.
    1217             :           unsigned int num_vals_per_node;
    1218             : 
    1219           0 :           in_stream >> model_type           // not used here
    1220           0 :                     >> analysis_type        // not used here
    1221           0 :                     >> data_characteristic  // not used here
    1222           0 :                     >> result_type          // not used here
    1223           0 :                     >> data_type
    1224           0 :                     >> num_vals_per_node;
    1225             : 
    1226             :           // Ignore the rest of record 9, and records 10-13.
    1227           6 :           for (unsigned int i=0; i<5; i++)
    1228           5 :             std::getline(in_stream, dummy);
    1229             : 
    1230             :           // Now get the foreign (aka UNV node) node number and
    1231             :           // the respective nodal data.
    1232             :           int f_n_id;
    1233           0 :           std::vector<Number> values;
    1234             : 
    1235             :           while (true)
    1236             :             {
    1237         161 :               in_stream >> f_n_id;
    1238             : 
    1239             :               // If -1 then we have reached the end of the dataset.
    1240         161 :               if (f_n_id == -1)
    1241           0 :                 break;
    1242             : 
    1243             :               // Resize the values vector (usually data in three
    1244             :               // principle directions, i.e. num_vals_per_node = 3).
    1245         160 :               values.resize(num_vals_per_node);
    1246             : 
    1247             :               // Read the values for the respective node.
    1248         320 :               for (unsigned int data_cnt=0; data_cnt<num_vals_per_node; data_cnt++)
    1249             :                 {
    1250             :                   // Check what data type we are reading.
    1251             :                   // 2,4: Real
    1252             :                   // 5,6: Complex
    1253             :                   // other data types are not supported yet.
    1254             :                   // As again, these floats may also be written
    1255             :                   // using a 'D' instead of an 'e'.
    1256         160 :                   if (data_type == 2 || data_type == 4)
    1257             :                     {
    1258           0 :                       std::string buf;
    1259           0 :                       in_stream >> buf;
    1260           0 :                       this->need_D_to_e(buf);
    1261             : #ifdef LIBMESH_USE_COMPLEX_NUMBERS
    1262           0 :                       values[data_cnt] = Complex(std::atof(buf.c_str()), 0.);
    1263             : #else
    1264           0 :                       values[data_cnt] = std::atof(buf.c_str());
    1265             : #endif
    1266             :                     }
    1267             : 
    1268         160 :                   else if (data_type == 5 || data_type == 6)
    1269             :                     {
    1270             : #ifdef LIBMESH_USE_COMPLEX_NUMBERS
    1271             :                       Real re_val, im_val;
    1272             : 
    1273             :                       std::string buf;
    1274         160 :                       in_stream >> buf;
    1275             : 
    1276         160 :                       if (this->need_D_to_e(buf))
    1277             :                         {
    1278             :                           re_val = std::atof(buf.c_str());
    1279           0 :                           in_stream >> buf;
    1280           0 :                           this->need_D_to_e(buf);
    1281           0 :                           im_val = std::atof(buf.c_str());
    1282             :                         }
    1283             :                       else
    1284             :                         {
    1285             :                           re_val = std::atof(buf.c_str());
    1286             :                           in_stream >> im_val;
    1287             :                         }
    1288             : 
    1289         160 :                       values[data_cnt] = Complex(re_val,im_val);
    1290             : #else
    1291             : 
    1292           0 :                       libmesh_error_msg("ERROR: Complex data only supported when libMesh is configured with --enable-complex!");
    1293             : #endif
    1294             :                     }
    1295             : 
    1296             :                   else
    1297           0 :                     libmesh_error_msg("ERROR: Data type not supported.");
    1298             : 
    1299             :                 } // end loop data_cnt
    1300             : 
    1301             :               // Get a pointer to the Node associated with the UNV node id.
    1302         160 :               auto & node_ptr = libmesh_map_find(_unv_node_id_to_libmesh_node_ptr, f_n_id);
    1303             : 
    1304             :               // Store the nodal values in our map which uses the
    1305             :               // libMesh Node* as the key.  We use operator[] here
    1306             :               // because we want to create an empty vector if the
    1307             :               // entry does not already exist.
    1308         160 :               _node_data[node_ptr] = values;
    1309           0 :             } // end while (true)
    1310             :         } // end if (news == "2414")
    1311           0 :     } // end while (true)
    1312           1 : }
    1313             : 
    1314             : 
    1315             : 
    1316             : const std::vector<Number> *
    1317        1281 : UNVIO::get_data (Node * node) const
    1318             : {
    1319        1281 :   if (const auto it = _node_data.find(node);
    1320           0 :       it == _node_data.end())
    1321           0 :     return nullptr;
    1322             :   else
    1323         160 :     return &(it->second);
    1324             : }
    1325             : 
    1326             : 
    1327             : } // namespace libMesh

Generated by: LCOV version 1.14