$extrastylesheet
libMesh::AbaqusIO Class Reference

#include <abaqus_io.h>

Inheritance diagram for libMesh::AbaqusIO:

List of all members.

Public Member Functions

 AbaqusIO (MeshBase &mesh)
virtual ~AbaqusIO ()
virtual void read (const std::string &name)

Public Attributes

bool build_sidesets_from_nodesets

Protected Member Functions

MeshBasemesh ()
void set_n_partitions (unsigned int n_parts)
void skip_comment_lines (std::istream &in, const char comment_start)

Protected Attributes

std::vector< bool > elems_of_dimension

Private Types

typedef std::map< std::string,
std::vector< dof_id_type > > 
container_t
typedef std::map< std::string,
std::vector< std::pair
< dof_id_type, unsigned > > > 
sideset_container_t

Private Member Functions

void read_nodes (std::string nset_name)
void read_elements (std::string upper, std::string elset_name)
std::string parse_label (std::string line, std::string label_name)
void read_ids (std::string set_name, container_t &container)
void assign_subdomain_ids ()
void read_sideset (std::string sideset_name, sideset_container_t &container)
void assign_boundary_node_ids ()
void assign_sideset_ids ()
void process_and_discard_comments ()
unsigned char max_elem_dimension_seen ()

Private Attributes

container_t _nodeset_ids
container_t _elemset_ids
sideset_container_t _sideset_ids
std::ifstream _in
std::set< ElemType_elem_types
std::map< dof_id_type,
dof_id_type
_abaqus_to_libmesh_elem_mapping
std::map< dof_id_type,
dof_id_type
_abaqus_to_libmesh_node_mapping
bool _already_seen_part

Detailed Description

The AbaqusIO class is a preliminary implementation for reading Abaqus mesh files in ASCII format.

Author:
John W. Peterson, 2011.

Definition at line 38 of file abaqus_io.h.


Member Typedef Documentation

typedef std::map<std::string, std::vector<dof_id_type> > libMesh::AbaqusIO::container_t [private]

The type of data structure used to store Node and Elemset IDs.

Definition at line 68 of file abaqus_io.h.

typedef std::map<std::string, std::vector<std::pair<dof_id_type, unsigned> > > libMesh::AbaqusIO::sideset_container_t [private]

Type of the data structure for storing the (elem ID, side) pairs defining sidesets. These come from the *Surface sections of the input file.

Definition at line 75 of file abaqus_io.h.


Constructor & Destructor Documentation

libMesh::AbaqusIO::AbaqusIO ( MeshBase mesh) [explicit]

Constructor. Takes a writeable reference to a mesh object.

Definition at line 187 of file abaqus_io.C.

Destructor.

Definition at line 197 of file abaqus_io.C.

{
}

Member Function Documentation

This function assigns boundary IDs to node sets based on the alphabetical order in which the sets are labelled in the Abaqus file. We choose the alphabetical ordering simply because Abaqus does not provide a numerical one within the file.

Definition at line 847 of file abaqus_io.C.

References _abaqus_to_libmesh_node_mapping, _nodeset_ids, libMesh::BoundaryInfo::add_node(), libMesh::MeshBase::get_boundary_info(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::MeshBase::node_ptr(), and libMesh::BoundaryInfo::nodeset_name().

Referenced by read().

{
  // Get a reference to the mesh we are reading
  MeshBase& the_mesh = MeshInput<MeshBase>::mesh();

  // Iterate over the container of nodesets
  container_t::iterator it = _nodeset_ids.begin();
  for (unsigned short current_id=0; it != _nodeset_ids.end(); ++it, ++current_id)
    {
      // Associate current_id with the name we determined earlier
      the_mesh.get_boundary_info().nodeset_name(current_id) = it->first;

      // Get a reference to the current vector of nodeset ID values
      std::vector<dof_id_type>& nodeset_ids = it->second;

      for (std::size_t i=0; i<nodeset_ids.size(); ++i)
        {
          // Map the Abaqus global node ID to the libmesh node ID
          dof_id_type libmesh_global_node_id = _abaqus_to_libmesh_node_mapping[nodeset_ids[i]];

          // Get node pointer from the mesh
          Node* node = the_mesh.node_ptr(libmesh_global_node_id);

          if (node == NULL)
            libmesh_error_msg("Error! Mesh returned NULL node pointer!");

          // Add this node with the current_id (which is determined by the
          // alphabetical ordering of the map) to the BoundaryInfo object
          the_mesh.get_boundary_info().add_node(node, current_id);
        }
    }
}

Called at the end of the read() function, assigns any sideset IDs found when reading the file to the BoundaryInfo object.

Definition at line 883 of file abaqus_io.C.

References _abaqus_to_libmesh_elem_mapping, _elemset_ids, _sideset_ids, libMesh::MeshBase::active_elements_begin(), libMesh::MeshBase::active_elements_end(), libMesh::BoundaryInfo::add_side(), libMesh::Elem::build_side(), libMesh::Elem::dim(), libMesh::MeshBase::elem(), end, libMesh::Utility::enum_to_string(), libMesh::MeshBase::get_boundary_info(), max_elem_dimension_seen(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::Elem::n_nodes(), libMesh::Elem::n_sides(), libMesh::Elem::node(), side, libMesh::BoundaryInfo::sideset_name(), and libMesh::Elem::type().

Referenced by read().

{
  // Get a reference to the mesh we are reading
  MeshBase& the_mesh = MeshInput<MeshBase>::mesh();

  // initialize the eletypes map (eletypes is a file-global variable)
  init_eletypes();

  // Iterate over the container of sidesets
  {
    sideset_container_t::iterator it = _sideset_ids.begin();
    for (unsigned short current_id=0; it != _sideset_ids.end(); ++it, ++current_id)
      {
        // Associate current_id with the name we determined earlier
        the_mesh.get_boundary_info().sideset_name(current_id) = it->first;

        // Get a reference to the current vector of nodeset ID values
        std::vector<std::pair<dof_id_type,unsigned> >& sideset_ids = it->second;

        for (std::size_t i=0; i<sideset_ids.size(); ++i)
          {
            // sideset_ids is a vector of pairs (elem id, side id).  Pull them out
            // now to make the code below more readable.
            dof_id_type  abaqus_elem_id = sideset_ids[i].first;
            unsigned abaqus_side_number = sideset_ids[i].second;

            // Map the Abaqus element ID to LibMesh numbering
            dof_id_type libmesh_elem_id = _abaqus_to_libmesh_elem_mapping[ abaqus_elem_id ];

            // Get pointer to that element
            Elem* elem = the_mesh.elem(libmesh_elem_id);

            // Check that the pointer returned from the Mesh is non-NULL
            if (elem == NULL)
              libmesh_error_msg("Mesh returned NULL pointer for Elem " << libmesh_elem_id);

            // Grab a reference to the element definition for this element type
            const ElementDefinition& eledef = eletypes[elem->type()];

            // If the element definition was not found, the call above would have
            // created one with an uninitialized struct.  Check for that here...
            if (eledef.abaqus_zero_based_side_id_to_libmesh_side_id.size() == 0)
              libmesh_error_msg("No Abaqus->LibMesh mapping information for ElemType " \
                                << Utility::enum_to_string(elem->type())  \
                                << "!");

            // Add this node with the current_id (which is determined by the
            // alphabetical ordering of the map).  Side numbers in Abaqus are 1-based,
            // so we subtract 1 here before passing the abaqus side number to the
            // mapping array
            the_mesh.get_boundary_info().add_side
              (elem,
               eledef.abaqus_zero_based_side_id_to_libmesh_side_id[abaqus_side_number-1],
               current_id);
          }
      }
  }


  // Some elsets (if they contain lower-dimensional elements) also
  // define sidesets.  So loop over them and build a searchable data
  // structure we can use to assign sidesets.
  {
    unsigned char max_dim = this->max_elem_dimension_seen();

    // multimap from "vector-of-lower-dimensional-element-node-ids" to subdomain ID which should be applied.
    // We use a multimap because the lower-dimensional elements can belong to more than 1 sideset.
    typedef std::multimap<std::vector<dof_id_type>, unsigned> provide_bcs_t;
    provide_bcs_t provide_bcs;

    // The elemset_id counter assigns a logical numbering to the _elemset_ids keys
    container_t::iterator it = _elemset_ids.begin();
    for (unsigned short elemset_id=0; it != _elemset_ids.end(); ++it, ++elemset_id)
      {
        // Grab a reference to the vector of IDs
        std::vector<dof_id_type>& id_vector = it->second;

        // Loop over this vector
        for (std::size_t i=0; i<id_vector.size(); ++i)
          {
            // Map the id_vector[i]'th element ID (Abaqus numbering) to LibMesh numbering
            dof_id_type libmesh_elem_id = _abaqus_to_libmesh_elem_mapping[ id_vector[i] ];

            // Get pointer to that element
            Elem* elem = the_mesh.elem(libmesh_elem_id);

            if (elem == NULL)
              libmesh_error_msg("Mesh returned NULL pointer for Elem " << libmesh_elem_id);

            // If the element dimension is equal to the maximum
            // dimension seen, we can break out of this for loop --
            // this elset does not contain sideset information.
            if (elem->dim() == max_dim)
              break;

            // We can only handle elements that are *exactly*
            // one dimension lower than the max element
            // dimension.  Not sure if "edge" BCs in 3D
            // actually make sense/are required...
            if (elem->dim()+1 != max_dim)
              libmesh_error_msg("ERROR: Expected boundary element of dimension " << max_dim-1 << " but got " << elem->dim());

            // To be pushed into the provide_bcs data container
            std::vector<dof_id_type> elem_node_ids(elem->n_nodes());

            // Save node IDs in a local vector which will be used as a key for the map.
            for (unsigned n=0; n<elem->n_nodes(); n++)
              elem_node_ids[n] = elem->node(n);

            // Sort before putting into the map
            std::sort(elem_node_ids.begin(), elem_node_ids.end());

            // Insert the (key, id) pair into the multimap
            provide_bcs.insert(std::make_pair(elem_node_ids, elemset_id));

            // Associate the name of this sideset with the ID we've
            // chosen.  It's not necessary to do this for every
            // element in the set, but it's convenient to do it here
            // since we have all the necessary information...
            the_mesh.get_boundary_info().sideset_name(elemset_id) = it->first;
          }
      }

    // Loop over elements and try to assign boundary information
    {
      MeshBase::element_iterator       e_it  = the_mesh.active_elements_begin();
      const MeshBase::element_iterator end = the_mesh.active_elements_end();
      for ( ; e_it != end; ++e_it)
        {
          Elem* elem = *e_it;

          if (elem->dim() == max_dim)
            {
              // This is a max-dimension element that may require BCs.
              // For each of its sides, including internal sides, we'll
              // see if a lower-dimensional element provides boundary
              // information for it.  Note that we have not yet called
              // find_neighbors(), so we can't use elem->neighbor(sn) in
              // this algorithm...
              for (unsigned short sn=0; sn<elem->n_sides(); sn++)
                {
                  UniquePtr<Elem> side (elem->build_side(sn));

                  // Build up a node_ids vector, which is the key
                  std::vector<dof_id_type> node_ids(side->n_nodes());
                  for (unsigned n=0; n<side->n_nodes(); n++)
                    node_ids[n] = side->node(n);

                  // Sort the vector before using it as a key
                  std::sort(node_ids.begin(), node_ids.end());

                  // Look for this key in the provide_bcs multimap
                  std::pair<provide_bcs_t::const_iterator, provide_bcs_t::const_iterator>
                    range = provide_bcs.equal_range (node_ids);

                  // Add boundary information for each side in the range.
                  for (provide_bcs_t::const_iterator s_it = range.first;
                       s_it != range.second; ++s_it)
                    the_mesh.get_boundary_info().add_side
                      (elem, sn, cast_int<unsigned short>(s_it->second));
                }
            }
        }
    }
  }
}

This function is called after all the elements have been read and assigns element subdomain IDs.

The IDs are simply chosen in the order in which the elset labels are stored in the map (roughly alphabetically). To make this easy on people who are planning to use Exodus output, we'll assign different geometric elements to different (but related) subdomains, i.e. assuming there are E elemsets:

Elemset 0, Geometric Type 0: ID 0 Elemset 0, Geometric Type 1: ID 0+E ... Elemset 0, Geometric Type N: ID 0+N*E -------------------------------------- Elemset 1, Geometric Type 0: ID 1 Elemset 1, Geometric Type 1: ID 1+E ... Elemset 1, Geometric Type N: ID 1+N*E etc.

Definition at line 775 of file abaqus_io.C.

References _abaqus_to_libmesh_elem_mapping, _elem_types, _elemset_ids, libMesh::Elem::dim(), libMesh::MeshBase::elem(), libMesh::Utility::enum_to_string(), max_elem_dimension_seen(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::Elem::subdomain_id(), libMesh::MeshBase::subdomain_name(), and libMesh::Elem::type().

Referenced by read().

{
  // Get a reference to the mesh we are reading
  MeshBase& the_mesh = MeshInput<MeshBase>::mesh();

  // The number of elemsets we've found while reading
  std::size_t n_elemsets = _elemset_ids.size();

  // Fill in a temporary map with (ElemType, index) pairs based on the _elem_types set.  This
  // will allow us to easily look up this index in the loop below.
  std::map<ElemType, unsigned> elem_types_map;
  {
    unsigned ctr=0;
    for (std::set<ElemType>::iterator it=_elem_types.begin(); it!=_elem_types.end(); ++it)
      elem_types_map[*it] = ctr++;
  }

  // Loop over each Elemset and assign subdomain IDs to Mesh elements
  {
    // The maximum element dimension seen while reading the Mesh
    unsigned char max_dim = this->max_elem_dimension_seen();

    // The elemset_id counter assigns a logical numbering to the _elemset_ids keys
    container_t::iterator it = _elemset_ids.begin();
    for (unsigned elemset_id=0; it != _elemset_ids.end(); ++it, ++elemset_id)
      {
        // Grab a reference to the vector of IDs
        std::vector<dof_id_type>& id_vector = it->second;

        // Loop over this vector
        for (std::size_t i=0; i<id_vector.size(); ++i)
          {
            // Map the id_vector[i]'th element ID (Abaqus numbering) to LibMesh numbering
            dof_id_type libmesh_elem_id = _abaqus_to_libmesh_elem_mapping[ id_vector[i] ];

            // Get pointer to that element
            Elem* elem = the_mesh.elem(libmesh_elem_id);

            if (elem == NULL)
              libmesh_error_msg("Mesh returned NULL pointer for Elem " << libmesh_elem_id);

            // We won't assign subdomain ids to lower-dimensional
            // elements, as they are assumed to represent boundary
            // conditions.  Since lower-dimensional elements can
            // appear in multiple sidesets, it doesn't make sense to
            // assign them a single subdomain id... only the last one
            // assigned would actually "stick".
            if (elem->dim() < max_dim)
              break;

            // Compute the proper subdomain ID, based on the formula in the
            // documentation for this function.
            subdomain_id_type computed_id = cast_int<subdomain_id_type>
              (elemset_id + (elem_types_map[elem->type()] * n_elemsets));

            // Assign this ID to the element in question
            elem->subdomain_id() = computed_id;

            // We will also assign a unique name to the computed_id,
            // which is created by appending the geometric element
            // name to the elset name provided by the user in the
            // Abaqus file.
            std::string computed_name = it->first + "_" + Utility::enum_to_string(elem->type());
            the_mesh.subdomain_name(computed_id) = computed_name;
          }
      }
  }
}
unsigned char libMesh::AbaqusIO::max_elem_dimension_seen ( ) [private]

Returns the maximum geometric element dimension encountered while reading the Mesh. Only valid after the elements have been read in and the elems_of_dimension array has been populated.

Definition at line 1095 of file abaqus_io.C.

References libMesh::MeshInput< MeshBase >::elems_of_dimension.

Referenced by assign_sideset_ids(), assign_subdomain_ids(), and read().

{
  unsigned char max_dim = 0;

  unsigned char elem_dimensions_size = cast_int<unsigned char>
    (elems_of_dimension.size());
  // The elems_of_dimension array is 1-based in the UNV reader
  for (unsigned char i=1; i<elem_dimensions_size; ++i)
    if (elems_of_dimension[i])
      max_dim = i;

  return max_dim;
}
MeshBase & libMesh::MeshInput< MeshBase >::mesh ( ) [protected, inherited]

Returns the object as a writeable reference.

Referenced by libMesh::GMVIO::_read_materials(), libMesh::GMVIO::_read_nodes(), libMesh::GMVIO::_read_one_cell(), assign_boundary_node_ids(), assign_sideset_ids(), assign_subdomain_ids(), libMesh::VTKIO::cells_to_vtk(), libMesh::ExodusII_IO::copy_elemental_solution(), libMesh::ExodusII_IO::copy_nodal_solution(), libMesh::GMVIO::copy_nodal_solution(), libMesh::TetGenIO::element_in(), libMesh::UNVIO::elements_in(), libMesh::UNVIO::elements_out(), libMesh::UNVIO::groups_in(), libMesh::TetGenIO::node_in(), libMesh::UNVIO::nodes_in(), libMesh::UNVIO::nodes_out(), libMesh::VTKIO::nodes_to_vtk(), read(), libMesh::NameBasedIO::read(), libMesh::TetGenIO::read(), libMesh::Nemesis_IO::read(), libMesh::ExodusII_IO::read(), libMesh::GMVIO::read(), libMesh::CheckpointIO::read(), libMesh::XdrIO::read(), libMesh::VTKIO::read(), libMesh::LegacyXdrIO::read_ascii(), libMesh::CheckpointIO::read_bcs(), libMesh::CheckpointIO::read_connectivity(), read_elements(), libMesh::UCDIO::read_implementation(), libMesh::UNVIO::read_implementation(), libMesh::GmshIO::read_mesh(), libMesh::LegacyXdrIO::read_mesh(), read_nodes(), libMesh::CheckpointIO::read_nodes(), libMesh::CheckpointIO::read_nodesets(), libMesh::XdrIO::read_serialized_bcs(), libMesh::XdrIO::read_serialized_connectivity(), libMesh::XdrIO::read_serialized_nodes(), libMesh::XdrIO::read_serialized_nodesets(), libMesh::XdrIO::read_serialized_subdomain_names(), libMesh::OFFIO::read_stream(), libMesh::MatlabIO::read_stream(), libMesh::CheckpointIO::read_subdomain_names(), libMesh::NameBasedIO::write(), libMesh::TetGenIO::write(), libMesh::Nemesis_IO::write(), libMesh::ExodusII_IO::write(), libMesh::CheckpointIO::write(), libMesh::XdrIO::write(), libMesh::GMVIO::write_ascii_new_impl(), libMesh::GMVIO::write_ascii_old_impl(), libMesh::CheckpointIO::write_bcs(), libMesh::GMVIO::write_binary(), libMesh::CheckpointIO::write_connectivity(), libMesh::GMVIO::write_discontinuous_gmv(), libMesh::ExodusII_IO::write_element_data(), libMesh::UCDIO::write_implementation(), libMesh::GmshIO::write_mesh(), libMesh::LegacyXdrIO::write_mesh(), libMesh::UCDIO::write_nodal_data(), libMesh::VTKIO::write_nodal_data(), libMesh::Nemesis_IO::write_nodal_data(), libMesh::NameBasedIO::write_nodal_data(), libMesh::ExodusII_IO::write_nodal_data(), libMesh::ExodusII_IO::write_nodal_data_common(), libMesh::ExodusII_IO::write_nodal_data_discontinuous(), libMesh::CheckpointIO::write_nodes(), libMesh::CheckpointIO::write_nodesets(), libMesh::XdrIO::write_parallel(), libMesh::GmshIO::write_post(), libMesh::XdrIO::write_serialized_bcs(), libMesh::XdrIO::write_serialized_connectivity(), libMesh::XdrIO::write_serialized_nodes(), libMesh::XdrIO::write_serialized_nodesets(), libMesh::XdrIO::write_serialized_subdomain_names(), libMesh::LegacyXdrIO::write_soln(), and libMesh::CheckpointIO::write_subdomain_names().

std::string libMesh::AbaqusIO::parse_label ( std::string  line,
std::string  label_name 
) [private]

This function parses a label of the form foo=bar from a comma-delimited line of the form ..., foo=bar, ... The input to the function in this case would be foo, the output would be bar

Definition at line 652 of file abaqus_io.C.

References end.

Referenced by read().

{
  // Handle files which have weird line endings from e.g. windows.
  // You can check what kind of line endings you have with 'cat -vet'.
  // For example, some files may have two kinds of line endings like:
  //
  // 4997,^I496,^I532,^I487,^I948^M$
  //
  // and we don't want to deal with this when extracting a label, so
  // just remove all the space characters, which should include all
  // kinds of remaining newlines.  (I don't think Abaqus allows
  // whitespace in label names.)
  line.erase(std::remove_if(line.begin(), line.end(), isspace), line.end());

  // Do all string comparisons in upper-case
  std::string
    upper_line(line),
    upper_label_name(label_name);
  std::transform(upper_line.begin(), upper_line.end(), upper_line.begin(), ::toupper);
  std::transform(upper_label_name.begin(), upper_label_name.end(), upper_label_name.begin(), ::toupper);

  // Get index of start of "label="
  size_t label_index = upper_line.find(upper_label_name + "=");

  if (label_index != std::string::npos)
    {
      // Location of the first comma following "label="
      size_t comma_index = upper_line.find(",", label_index);

      // Construct iterators from which to build the sub-string.
      // Note: The +1 while initializing beg is to skip past the "=" which follows the label name
      std::string::iterator
        beg = line.begin() + label_name.size() + 1 + label_index,
        end = (comma_index == std::string::npos) ? line.end() : line.begin() + comma_index;

      return std::string(beg, end);
    }

  // The label index was not found, return the empty string
  return std::string("");
}

Any of the various sections can start with some number of lines of comments, which start with "**". This function discards any lines of comments that it finds from the stream, leaving trailing data intact.

Definition at line 1052 of file abaqus_io.C.

References _in.

Referenced by read().

{
  std::string dummy;
  while (true)
    {
      // We assume we are at the beginning of a line that may be
      // comments or may be data.  We need to only discard the line if
      // it begins with **, but we must avoid calling std::getline()
      // since there's no way to put that back.
      if (_in.peek() == '*')
        {
          // The first character was a star, so actually read it from the stream.
          _in.get();

          // Peek at the next character...
          if (_in.peek() == '*')
            {
              // OK, second character was star also, by definition this
              // line must be a comment!  Read the rest of the line and discard!
              std::getline(_in, dummy);
            }
          else
            {
              // The second character was _not_ a star, so put back the first star
              // we pulled out so that the line can be parsed correctly by somebody
              // else!
              _in.unget();

              // Finally, break out of the while loop, we are done parsing comments
              break;
            }
        }
      else
        {
          // First character was not *, so this line must be data! Break out of the
          // while loop!
          break;
        }
    }
}
void libMesh::AbaqusIO::read ( const std::string &  name) [virtual]

This method implements reading a mesh from a specified file.

Implements libMesh::MeshInput< MeshBase >.

Definition at line 204 of file abaqus_io.C.

References _already_seen_part, _elemset_ids, _in, _nodeset_ids, _sideset_ids, assign_boundary_node_ids(), assign_sideset_ids(), assign_subdomain_ids(), libMesh::BoundaryInfo::build_side_list_from_node_list(), build_sidesets_from_nodesets, libMesh::MeshBase::clear(), libMesh::MeshBase::delete_elem(), libMesh::Elem::dim(), libMesh::MeshBase::elements_begin(), libMesh::MeshBase::elements_end(), libMesh::MeshInput< MeshBase >::elems_of_dimension, libMesh::MeshBase::get_boundary_info(), libMesh::libmesh_assert(), max_elem_dimension_seen(), libMesh::MeshInput< MeshBase >::mesh(), parse_label(), process_and_discard_comments(), read_elements(), read_ids(), read_nodes(), read_sideset(), and libMesh::MeshBase::set_mesh_dimension().

Referenced by libMesh::NameBasedIO::read().

{
  // Get a reference to the mesh we are reading
  MeshBase& the_mesh = MeshInput<MeshBase>::mesh();

  // Clear any existing mesh data
  the_mesh.clear();

  // Open stream for reading
  _in.open(fname.c_str());
  libmesh_assert(_in.good());

  // Initialize the elems_of_dimension array.  We will use this in a
  // "1-based" manner so that elems_of_dimension[d]==true means
  // elements of dimension d have been seen.
  elems_of_dimension.resize(4, false);

  // Read file line-by-line... this is based on a set of different
  // test input files.  I have not looked at the full input file
  // specs for Abaqus.
  std::string s;
  while (true)
    {
      // Try to read something.  This may set EOF!
      std::getline(_in, s);

      if (_in)
        {
          // Process s...
          //
          // There are many sections in Abaqus files, we read some
          // but others are just ignored...  Some sections may occur
          // more than once.  For example for a hybrid grid, you
          // will have multiple *Element sections...

          // Some Abaqus files use all upper-case for section names,
          // so we will just convert s to uppercase
          std::string upper(s);
          std::transform(upper.begin(), upper.end(), upper.begin(), ::toupper);

          // 0.) Look for the "*Part" section
          if (upper.find("*PART") == static_cast<std::string::size_type>(0))
            {
              if (_already_seen_part)
                libmesh_error_msg("We currently don't support reading Abaqus files with multiple PART sections");

              _already_seen_part = true;
            }

          // 1.) Look for the "*Nodes" section
          if (upper.find("*NODE") == static_cast<std::string::size_type>(0))
            {
              // Some sections that begin with *NODE are actually
              // "*NODE OUTPUT" sections which we want to skip.  I
              // have only seen this with a single space, but it would
              // probably be more robust to remove whitespace before
              // making this check.
              if (upper.find("*NODE OUTPUT") == static_cast<std::string::size_type>(0))
                continue;

              // Some *Node sections also specify an Nset name on the same line.
              // Look for one here.
              std::string nset_name = this->parse_label(s, "nset");

              // Process any lines of comments that may be present
              this->process_and_discard_comments();

              // Read a block of nodes
              this->read_nodes(nset_name);
            }



          // 2.) Look for the "*Element" section
          else if (upper.find("*ELEMENT,") == static_cast<std::string::size_type>(0))
            {
              // Some sections that begin with *ELEMENT are actually
              // "*ELEMENT OUTPUT" sections which we want to skip.  I
              // have only seen this with a single space, but it would
              // probably be more robust to remove whitespace before
              // making this check.
              if (upper.find("*ELEMENT OUTPUT") == static_cast<std::string::size_type>(0))
                continue;

              // Some *Element sections also specify an Elset name on the same line.
              // Look for one here.
              std::string elset_name = this->parse_label(s, "elset");

              // Process any lines of comments that may be present
              this->process_and_discard_comments();

              // Read a block of elements
              this->read_elements(upper, elset_name);
            }



          // 3.) Look for a Nodeset section
          else if (upper.find("*NSET") == static_cast<std::string::size_type>(0))
            {
              std::string nset_name = this->parse_label(s, "nset");

              // I haven't seen an unnamed nset yet, but let's detect it
              // just in case...
              if (nset_name == "")
                libmesh_error_msg("Unnamed nset encountered!");

              // Process any lines of comments that may be present
              this->process_and_discard_comments();

              // Read the IDs, storing them in _nodeset_ids
              this->read_ids(nset_name, _nodeset_ids);
            } // *Nodeset



          // 4.) Look for an Elset section
          else if (upper.find("*ELSET") == static_cast<std::string::size_type>(0))
            {
              std::string elset_name = this->parse_label(s, "elset");

              // I haven't seen an unnamed elset yet, but let's detect it
              // just in case...
              if (elset_name == "")
                libmesh_error_msg("Unnamed elset encountered!");

              // Process any lines of comments that may be present
              this->process_and_discard_comments();

              // Read the IDs, storing them in _elemset_ids
              this->read_ids(elset_name, _elemset_ids);
            } // *Elset



          // 5.) Look for a Surface section.  Need to be a little
          // careful, since there are also "surface interaction"
          // sections we don't want to read here.
          else if (upper.find("*SURFACE,") == static_cast<std::string::size_type>(0))
            {
              // Get the name from the Name=Foo label.  This will be the map key.
              std::string sideset_name = this->parse_label(s, "name");

              // Process any lines of comments that may be present
              this->process_and_discard_comments();

              // Read the sideset IDs
              this->read_sideset(sideset_name, _sideset_ids);
            }

          continue;
        } // if (_in)

      // If !file, check to see if EOF was set.  If so, break out
      // of while loop.
      if (_in.eof())
        break;

      // If !in and !in.eof(), stream is in a bad state!
      libmesh_error_msg("Stream is bad! Perhaps the file: " << fname << " does not exist?");
    } // while

  // Set the Mesh dimension based on the highest dimension element seen.
  the_mesh.set_mesh_dimension(this->max_elem_dimension_seen());

  // Set element IDs based on the element sets.
  this->assign_subdomain_ids();

  // Assign nodeset values to the BoundaryInfo object
  this->assign_boundary_node_ids();

  // Assign sideset values in the BoundaryInfo object
  this->assign_sideset_ids();

  // Abaqus files only contain nodesets by default.  To be useful in
  // applying most types of BCs in libmesh, we will definitely need
  // sidesets.  So we can call the new BoundaryInfo function which
  // generates sidesets from nodesets.
  if (build_sidesets_from_nodesets)
    the_mesh.get_boundary_info().build_side_list_from_node_list();

  // Delete lower-dimensional elements from the Mesh.  We assume these
  // were only used for setting BCs, and aren't part of the actual
  // Mesh.
  {
    unsigned char max_dim = this->max_elem_dimension_seen();

    MeshBase::element_iterator       el     = the_mesh.elements_begin();
    const MeshBase::element_iterator end_el = the_mesh.elements_end();

    for (; el != end_el; ++el)
      {
        Elem* elem = *el;

        if (elem->dim() < max_dim)
          the_mesh.delete_elem(elem);
      }
  }
}
void libMesh::AbaqusIO::read_elements ( std::string  upper,
std::string  elset_name 
) [private]

This function parses a block of elements in the Abaqus file. You must pass it an upper-cased version of the string declaring this section, which is typically something like: *ELEMENT, TYPE=CPS3 so that it can determine the type of elements to read.

Definition at line 481 of file abaqus_io.C.

References _abaqus_to_libmesh_elem_mapping, _abaqus_to_libmesh_node_mapping, _elem_types, _elemset_ids, _in, libMesh::MeshBase::add_elem(), libMesh::Elem::build(), libMesh::EDGE2, libMesh::MeshInput< MeshBase >::elems_of_dimension, libMesh::Utility::enum_to_string(), libMesh::HEX20, libMesh::HEX8, libMesh::DofObject::id(), libMesh::INVALID_ELEM, libMesh::MeshInput< MeshBase >::mesh(), libMesh::MeshBase::node_ptr(), libMesh::PRISM15, libMesh::PRISM6, libMesh::QUAD4, libMesh::Elem::set_node(), libMesh::TET10, libMesh::TET4, and libMesh::TRI3.

Referenced by read().

{
  // Get a reference to the mesh we are reading
  MeshBase& the_mesh = MeshInput<MeshBase>::mesh();

  // initialize the eletypes map (eletypes is a file-global variable)
  init_eletypes();

  ElemType elem_type = INVALID_ELEM;
  unsigned n_nodes_per_elem = 0;

  // Within s, we should have "type=XXXX"
  if (upper.find("T3D2") != std::string::npos)
    {
      elem_type = EDGE2;
      n_nodes_per_elem = 2;
      elems_of_dimension[1] = true;
    }
  else if (upper.find("CPE4") != std::string::npos ||
           upper.find("CPS4") != std::string::npos)
    {
      elem_type = QUAD4;
      n_nodes_per_elem = 4;
      elems_of_dimension[2] = true;
    }
  else if (upper.find("CPS3") != std::string::npos ||
           upper.find("S3R") != std::string::npos)
    {
      elem_type = TRI3;
      n_nodes_per_elem = 3;
      elems_of_dimension[2] = true;
    }
  else if (upper.find("C3D8") != std::string::npos)
    {
      elem_type = HEX8;
      n_nodes_per_elem = 8;
      elems_of_dimension[3] = true;
    }
  else if (upper.find("C3D4") != std::string::npos)
    {
      elem_type = TET4;
      n_nodes_per_elem = 4;
      elems_of_dimension[3] = true;
    }
  else if (upper.find("C3D20") != std::string::npos)
    {
      elem_type = HEX20;
      n_nodes_per_elem = 20;
      elems_of_dimension[3] = true;
    }
  else if (upper.find("C3D6") != std::string::npos)
    {
      elem_type = PRISM6;
      n_nodes_per_elem = 6;
      elems_of_dimension[3] = true;
    }
  else if (upper.find("C3D15") != std::string::npos)
    {
      elem_type = PRISM15;
      n_nodes_per_elem = 15;
      elems_of_dimension[3] = true;
    }
  else if (upper.find("C3D10") != std::string::npos)
    {
      elem_type = TET10;
      n_nodes_per_elem = 10;
      elems_of_dimension[3] = true;
    }
  else
    libmesh_error_msg("Unrecognized element type: " << upper);

  // Insert the elem type we detected into the set of all elem types for this mesh
  _elem_types.insert(elem_type);

  // Grab a reference to the element definition for this element type
  const ElementDefinition& eledef = eletypes[elem_type];

  // If the element definition was not found, the call above would have
  // created one with an uninitialized struct.  Check for that here...
  if (eledef.abaqus_zero_based_node_id_to_libmesh_node_id.size() == 0)
    libmesh_error_msg("No Abaqus->LibMesh mapping information for ElemType " \
                      << Utility::enum_to_string(elem_type)             \
                      << "!");

  // We will read elements until the next line begins with *, since that will be the
  // next section.
  while (_in.peek() != '*' && _in.peek() != EOF)
    {
      // Read the element ID, it is the first number on each line.  It is
      // followed by a comma, so read that also.  We will need this ID later
      // when we try to assign subdomain IDs
      dof_id_type abaqus_elem_id = 0;
      char c;
      _in >> abaqus_elem_id >> c;

      // Add an element of the appropriate type to the Mesh.
      Elem* elem = the_mesh.add_elem(Elem::build(elem_type).release());

      // Associate the ID returned from libmesh with the abaqus element ID
      //_libmesh_to_abaqus_elem_mapping[elem->id()] = abaqus_elem_id;
      _abaqus_to_libmesh_elem_mapping[abaqus_elem_id] = elem->id();

      // The count of the total number of IDs read for the current element.
      unsigned id_count=0;

      // Continue reading line-by-line until we have read enough nodes for this element
      while (id_count < n_nodes_per_elem)
        {
          // Read entire line (up to carriage return) of comma-separated values
          std::string csv_line;
          std::getline(_in, csv_line);

          // Create a stream object out of the current line
          std::stringstream line_stream(csv_line);

          // Process the comma-separated values
          std::string cell;
          while (std::getline(line_stream, cell, ','))
            {
              // FIXME: factor out this strtol stuff into a utility function.
              char* endptr;
              dof_id_type abaqus_global_node_id = cast_int<dof_id_type>
                (std::strtol(cell.c_str(), &endptr, /*base=*/10));

              if (abaqus_global_node_id!=0 || cell.c_str() != endptr)
                {
                  // Use the global node number mapping to determine the corresponding libmesh global node id
                  dof_id_type libmesh_global_node_id = _abaqus_to_libmesh_node_mapping[abaqus_global_node_id];

                  // Grab the node pointer from the mesh for this ID
                  Node* node = the_mesh.node_ptr(libmesh_global_node_id);

                  // If node_ptr() returns NULL, it may mean we have not yet read the
                  // *Nodes section, though I assumed that always came before the *Elements section...
                  if (node == NULL)
                    libmesh_error_msg("Error!  Mesh returned NULL Node pointer.  Either no node exists with ID " \
                                      << libmesh_global_node_id         \
                                      << " or perhaps this input file has *Elements defined before *Nodes?");

                  // Note: id_count is the zero-based abaqus (elem local) node index.  We therefore map
                  // it to a libmesh elem local node index using the element definition map
                  unsigned libmesh_elem_local_node_id =
                    eledef.abaqus_zero_based_node_id_to_libmesh_node_id[id_count];

                  // Set this node pointer within the element.
                  elem->set_node(libmesh_elem_local_node_id) = node;

                  // Increment the count of IDs read for this element
                  id_count++;
                } // end if strtol success
            } // end while getline(',')
        } // end while (id_count)

      // Ensure that we read *exactly* as many nodes as we were expecting to, no more.
      if (id_count != n_nodes_per_elem)
        libmesh_error_msg("Error: Needed to read " \
                          << n_nodes_per_elem      \
                          << " nodes, but read "   \
                          << id_count              \
                          << " instead!");

      // If we are recording Elset IDs, add this element to the correct set for later processing.
      // Make sure to add it with the Abaqus ID, not the libmesh one!
      if (elset_name != "")
        _elemset_ids[elset_name].push_back(abaqus_elem_id);
    } // end while (peek)
}
void libMesh::AbaqusIO::read_ids ( std::string  set_name,
container_t container 
) [private]

This function reads all the IDs for the current node or element set of the given name, storing them in the passed map using the name as key.

Definition at line 697 of file abaqus_io.C.

References _in.

Referenced by read().

{
  // Grab a reference to a vector that will hold all the IDs
  std::vector<dof_id_type>& id_storage = container[set_name];

  // Read until the start of another section is detected, or EOF is encountered
  while (_in.peek() != '*' && _in.peek() != EOF)
    {
      // Read entire comma-separated line into a string
      std::string csv_line;
      std::getline(_in, csv_line);

      // On that line, use std::getline again to parse each
      // comma-separated entry.
      std::string cell;
      std::stringstream line_stream(csv_line);
      while (std::getline(line_stream, cell, ','))
        {
          // If no conversion can be performed by strtol, 0 is returned.
          //
          // If endptr is not NULL, strtol() stores the address of the
          // first invalid character in *endptr.  If there were no
          // digits at all, however, strtol() stores the original
          // value of str in *endptr.
          char* endptr;

          // FIXME - this needs to be updated for 64-bit inputs
          dof_id_type id = cast_int<dof_id_type>
            (std::strtol(cell.c_str(), &endptr, /*base=*/10));

          // Note that lists of comma-separated values in abaqus also
          // *end* with a comma, so the last call to getline on a given
          // line will get an empty string, which we must detect.
          if (id != 0 || cell.c_str() != endptr)
            {
              // 'cell' is now a string with an integer id in it
              id_storage.push_back( id );
            }
        }
    }
}
void libMesh::AbaqusIO::read_nodes ( std::string  nset_name) [private]

This function parses a block of nodes in the Abaqus file once such a block has been found. If the *NODE section specifies an NSET name, also pass that to this function.

Definition at line 410 of file abaqus_io.C.

References _abaqus_to_libmesh_node_mapping, _in, _nodeset_ids, libMesh::MeshBase::add_point(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::MeshBase::n_nodes(), libMesh::Real, and libMesh::x.

Referenced by read().

{
  // Get a reference to the mesh we are reading
  MeshBase& the_mesh = MeshInput<MeshBase>::mesh();

  // In the input files I have, Abaqus neither tells what
  // the mesh dimension is nor how many nodes it has...
  //
  // The node line format is:
  // id, x, y, z
  // and you do have to parse out the commas.
  // The z-coordinate will only be present for 3D meshes

  // Temporary variables for parsing lines of text
  char c;
  std::string dummy;

  // Defines the sequential node numbering used by libmesh.  Since
  // there can be multiple *NODE sections in an Abaqus file, we always
  // start our numbering with the number of nodes currently in the
  // Mesh.
  dof_id_type libmesh_node_id = the_mesh.n_nodes();

  // We need to duplicate some of the read_ids code if this *NODE
  // section also defines an NSET.  We'll set up the id_storage
  // pointer and push back IDs into this vector in the loop below...
  std::vector<dof_id_type>* id_storage = NULL;
  if (nset_name != "")
    id_storage = &(_nodeset_ids[nset_name]);

  // We will read nodes until the next line begins with *, since that will be the
  // next section.
  // TODO: Is Abaqus guaranteed to start the line with '*' or can there be leading white space?
  while (_in.peek() != '*' && _in.peek() != EOF)
    {
      // Re-Initialize variables to be read in from file
      dof_id_type abaqus_node_id=0;
      Real x=0, y=0, z=0;

      // Note: we assume *at least* 2D points here, should we worry about
      // trying to read 1D Abaqus meshes?
      _in >> abaqus_node_id >> c >> x >> c >> y;

      // Peek at the next character.  If it is a comma, then there is another
      // value to read!
      if (_in.peek() == ',')
        _in >> c >> z;

      // Read (and discard) the rest of the line, including the newline.
      // This is required so that our 'peek()' at the beginning of this
      // loop doesn't read the newline character, for example.
      std::getline(_in, dummy);

      // If this *NODE section defines an NSET, also store the abaqus ID in id_storage
      if (id_storage)
        id_storage->push_back(abaqus_node_id);

      // Set up the abaqus -> libmesh node mapping.  This is usually just the
      // "off-by-one" map.
      _abaqus_to_libmesh_node_mapping[abaqus_node_id] = libmesh_node_id;

      // Add the point to the mesh using libmesh's numbering,
      // and post-increment the libmesh node counter.
      the_mesh.add_point(Point(x,y,z), libmesh_node_id++);
    } // while
}
void libMesh::AbaqusIO::read_sideset ( std::string  sideset_name,
sideset_container_t container 
) [private]

This function reads a sideset from the input file. This is defined by a "*Surface" section in the file, and then a list of element ID and side IDs for the set.

Definition at line 742 of file abaqus_io.C.

References _in.

Referenced by read().

{
  // Grab a reference to a vector that will hold all the IDs
  std::vector<std::pair<dof_id_type, unsigned> >& id_storage = container[sideset_name];

  // Variables for storing values read in from file
  dof_id_type elem_id=0;
  unsigned side_id=0;
  char c;
  std::string dummy;

  // Read until the start of another section is detected, or EOF is encountered
  while (_in.peek() != '*' && _in.peek() != EOF)
    {
      // The strings are of the form: "391, S2"

      // Read the element ID and the leading comma
      _in >> elem_id >> c;

      // Read another character (the 'S') and finally the side ID
      _in >> c >> side_id;

      // Store this pair of data in the vector
      id_storage.push_back( std::make_pair(elem_id, side_id) );

      // Extract remaining characters on line including newline
      std::getline(_in, dummy);
    } // while
}
void libMesh::MeshInput< MeshBase >::set_n_partitions ( unsigned int  n_parts) [inline, protected, inherited]

Sets the number of partitions in the mesh. Typically this gets done by the partitioner, but some parallel file formats begin "pre-partitioned".

Definition at line 94 of file mesh_input.h.

References libMesh::MeshInput< MT >::mesh().

Referenced by libMesh::Nemesis_IO::read(), and libMesh::XdrIO::read().

{ this->mesh().set_n_partitions() = n_parts; }
void libMesh::MeshInput< MeshBase >::skip_comment_lines ( std::istream &  in,
const char  comment_start 
) [protected, inherited]

Reads input from in, skipping all the lines that start with the character comment_start.

Referenced by libMesh::TetGenIO::read(), and libMesh::UCDIO::read_implementation().


Member Data Documentation

Map from libmesh element number -> abaqus element number, and the converse.

Definition at line 193 of file abaqus_io.h.

Referenced by assign_sideset_ids(), assign_subdomain_ids(), and read_elements().

Map from abaqus node number -> sequential, 0-based libmesh node numbering. Note that in every Abaqus file I've ever seen the node numbers were 1-based, sequential, and all in order, so that this map is probably overkill. Nevertheless, it is the most general solution in case we come across a weird Abaqus file some day.

Definition at line 202 of file abaqus_io.h.

Referenced by assign_boundary_node_ids(), read_elements(), and read_nodes().

This flag gets set to true after the first "*PART" section we see. If it is still true when we see a second PART section, we will print an error message... we don't currently handle input files with multiple parts.

Definition at line 210 of file abaqus_io.h.

Referenced by read().

A set of the different geometric element types detected when reading the mesh.

Definition at line 186 of file abaqus_io.h.

Referenced by assign_subdomain_ids(), and read_elements().

std::ifstream libMesh::AbaqusIO::_in [private]

Stream object used to interact with the file

Definition at line 180 of file abaqus_io.h.

Referenced by process_and_discard_comments(), read(), read_elements(), read_ids(), read_nodes(), and read_sideset().

Abaqus writes nodesets and elemsets with labels. As we read them in, we'll use these maps to provide a natural ordering for them.

Definition at line 173 of file abaqus_io.h.

Referenced by assign_boundary_node_ids(), read(), and read_nodes().

Definition at line 175 of file abaqus_io.h.

Referenced by assign_sideset_ids(), and read().

Default false. Abaqus files have only nodesets in them by default. Set this flag to true if you want libmesh to automatically generate sidesets from Abaqus' nodesets.

Definition at line 62 of file abaqus_io.h.

Referenced by read().


The documentation for this class was generated from the following files: