libMesh
Public Member Functions | Public Attributes | Protected Types | Protected Member Functions | Protected Attributes | List of all members
libMesh::AbaqusIO Class Reference

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

#include <abaqus_io.h>

Inheritance diagram for libMesh::AbaqusIO:
[legend]

Public Member Functions

 AbaqusIO (MeshBase &mesh)
 Constructor. More...
 
virtual ~AbaqusIO ()
 Destructor. More...
 
virtual void read (const std::string &name) override
 This method implements reading a mesh from a specified file. More...
 
bool is_parallel_format () const
 Returns true iff this mesh file format and input class are parallelized, so that all processors can read their share of the data at once. More...
 

Public Attributes

bool build_sidesets_from_nodesets
 Default false. More...
 

Protected Types

typedef std::map< std::string, std::vector< dof_id_type > > container_t
 The type of data structure used to store Node and Elemset IDs. More...
 
typedef std::map< std::string, std::vector< std::pair< dof_id_type, unsigned > > > sideset_container_t
 Type of the data structure for storing the (elem ID, side) pairs defining sidesets. More...
 

Protected Member Functions

void read_nodes (std::string nset_name)
 This function parses a block of nodes in the Abaqus file once such a block has been found. More...
 
void read_elements (std::string upper, std::string elset_name)
 This function parses a block of elements in the Abaqus file. More...
 
std::string parse_label (std::string line, std::string label_name) const
 This function parses a label of the form foo=bar from a comma-delimited line of the form ..., foo=bar, ... More...
 
bool detect_generated_set (std::string upper) const
 
void read_ids (std::string set_name, container_t &container)
 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. More...
 
void generate_ids (std::string set_name, container_t &container)
 This function handles "generated" nset and elset sections. More...
 
void assign_subdomain_ids ()
 This function is called after all the elements have been read and assigns element subdomain IDs. More...
 
void read_sideset (const std::string &sideset_name, const std::string &sideset_type, sideset_container_t &container)
 This function reads a sideset from the input file. More...
 
void assign_boundary_node_ids ()
 This function assigns boundary IDs to node sets based on the alphabetical order in which the sets are labeled in the Abaqus file. More...
 
void assign_sideset_ids ()
 Called at the end of the read() function, assigns any sideset IDs found when reading the file to the BoundaryInfo object. More...
 
void process_and_discard_comments ()
 Any of the various sections can start with some number of lines of comments, which start with "**". More...
 
unsigned char max_elem_dimension_seen ()
 
bool string_to_num (const std::string &input, dof_id_type &output) const
 Attempts to convert the input string to a numerical value using strtol. More...
 
void strip_ws (std::string &line) const
 Removes all whitespace characters from "line". More...
 
virtual void extended_parsing (const std::string &)
 Override this callback to implement support for more sections in derived classes. More...
 
MeshBasemesh ()
 
void set_n_partitions (unsigned int n_parts)
 Sets the number of partitions in the mesh. More...
 
void skip_comment_lines (std::istream &in, const char comment_start)
 Reads input from in, skipping all the lines that start with the character comment_start. More...
 

Protected Attributes

container_t _nodeset_ids
 Abaqus writes nodesets and elemsets with labels. More...
 
container_t _elemset_ids
 
sideset_container_t _sideset_ids
 
std::unique_ptr< std::istream > _in
 Stream object used to interact with the file. More...
 
std::set< ElemType_elem_types
 A set of the different geometric element types detected when reading the mesh. More...
 
bool _already_seen_part
 This flag gets set to true after the first "*PART" section we see. More...
 
std::vector< bool > elems_of_dimension
 A vector of bools describing what dimension elements have been encountered when reading a mesh. More...
 

Detailed Description

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

Author
John W. Peterson
Date
2011

Definition at line 41 of file abaqus_io.h.

Member Typedef Documentation

◆ container_t

typedef std::map<std::string, std::vector<dof_id_type> > libMesh::AbaqusIO::container_t
protected

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

Definition at line 73 of file abaqus_io.h.

◆ sideset_container_t

typedef std::map<std::string, std::vector<std::pair<dof_id_type, unsigned> > > libMesh::AbaqusIO::sideset_container_t
protected

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 80 of file abaqus_io.h.

Constructor & Destructor Documentation

◆ AbaqusIO()

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

Constructor.

Takes a writable reference to a mesh object.

Definition at line 214 of file abaqus_io.C.

214  :
215  MeshInput<MeshBase> (mesh_in),
217  _already_seen_part(false)
218 {
219 }
bool _already_seen_part
This flag gets set to true after the first "*PART" section we see.
Definition: abaqus_io.h:221
bool build_sidesets_from_nodesets
Default false.
Definition: abaqus_io.h:67

◆ ~AbaqusIO()

libMesh::AbaqusIO::~AbaqusIO ( )
virtualdefault

Destructor.

Member Function Documentation

◆ assign_boundary_node_ids()

void libMesh::AbaqusIO::assign_boundary_node_ids ( )
protected

This function assigns boundary IDs to node sets based on the alphabetical order in which the sets are labeled in the Abaqus file.

We choose the alphabetical ordering simply because Abaqus does not provide a numerical one within the file.

Definition at line 1050 of file abaqus_io.C.

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

Referenced by read().

1051 {
1052  // Get a reference to the mesh we are reading
1053  MeshBase & the_mesh = MeshInput<MeshBase>::mesh();
1054 
1055  // Iterate over the container of nodesets
1056  container_t::iterator it = _nodeset_ids.begin(), end = _nodeset_ids.end();
1057  for (boundary_id_type current_id=0; it != end; ++it, ++current_id)
1058  {
1059  // Associate current_id with the name we determined earlier
1060  the_mesh.get_boundary_info().nodeset_name(current_id) = it->first;
1061 
1062  // Get a reference to the current vector of nodeset ID values
1063  std::vector<dof_id_type> & nodeset_ids = it->second;
1064 
1065  for (const auto & id : nodeset_ids)
1066  {
1067  // Map the id'th element ID (Abaqus 1-based numbering) to LibMesh numbering
1068  libmesh_error_msg_if(id < 1,
1069  "Invalid Abaqus node ID found");
1070  const dof_id_type libmesh_global_node_id = id-1;
1071 
1072  // Get node pointer from the mesh
1073  Node * node = the_mesh.node_ptr(libmesh_global_node_id);
1074 
1075  libmesh_error_msg_if(node == nullptr,
1076  "Error! Mesh::node_ptr() returned nullptr!");
1077 
1078  // Add this node with the current_id (which is determined by the
1079  // alphabetical ordering of the map) to the BoundaryInfo object
1080  the_mesh.get_boundary_info().add_node(node, current_id);
1081  }
1082  }
1083 }
A Node is like a Point, but with more information.
Definition: node.h:52
std::string & nodeset_name(boundary_id_type id)
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
This is the MeshBase class.
Definition: mesh_base.h:75
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
int8_t boundary_id_type
Definition: id_types.h:51
container_t _nodeset_ids
Abaqus writes nodesets and elemsets with labels.
Definition: abaqus_io.h:200
virtual const Node * node_ptr(const dof_id_type i) const =0
uint8_t dof_id_type
Definition: id_types.h:67

◆ assign_sideset_ids()

void libMesh::AbaqusIO::assign_sideset_ids ( )
protected

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

Definition at line 1088 of file abaqus_io.C.

References _elemset_ids, _sideset_ids, libMesh::BoundaryInfo::add_side(), libMesh::as_range(), libMesh::Elem::dim(), libMesh::MeshBase::elem_ref(), libMesh::Utility::enum_to_string(), libMesh::MeshBase::get_boundary_info(), libMesh::Elem::key(), max_elem_dimension_seen(), libMesh::MeshInput< MT >::mesh(), libMesh::BoundaryInfo::sideset_name(), and libMesh::Elem::type().

Referenced by read().

1089 {
1090  // Get a reference to the mesh we are reading
1091  MeshBase & the_mesh = MeshInput<MeshBase>::mesh();
1092 
1093  // initialize the eletypes map (eletypes is a file-global variable)
1094  init_eletypes();
1095 
1096  // Iterate over the container of sidesets
1097  {
1098  sideset_container_t::iterator it = _sideset_ids.begin(), end = _sideset_ids.end();
1099  for (boundary_id_type current_id=0; it != end; ++it, ++current_id)
1100  {
1101  // Associate current_id with the name we determined earlier
1102  the_mesh.get_boundary_info().sideset_name(current_id) = it->first;
1103 
1104  // Get a reference to the current vector of nodeset ID values
1105  std::vector<std::pair<dof_id_type,unsigned>> & sideset_ids = it->second;
1106 
1107  for (const auto & [abaqus_elem_id, abaqus_side_number] : sideset_ids)
1108  {
1109  // Map the id'th element ID (Abaqus 1-based numbering) to LibMesh numbering
1110  libmesh_error_msg_if(abaqus_elem_id < 1,
1111  "Invalid Abaqus element ID found");
1112  const dof_id_type libmesh_elem_id = abaqus_elem_id-1;
1113 
1114  // Get a reference to that element
1115  Elem & elem = the_mesh.elem_ref(libmesh_elem_id);
1116 
1117  // Grab a reference to the element definition for this element type
1118  const ElementDefinition & eledef = eletypes[elem.type()];
1119 
1120  // If the element definition was not found, the call above would have
1121  // created one with an uninitialized struct. Check for that here...
1122  libmesh_error_msg_if(eledef.abaqus_zero_based_side_id_to_libmesh_side_id.size() == 0,
1123  "No Abaqus->LibMesh mapping information for ElemType "
1124  << Utility::enum_to_string(elem.type()) << "!");
1125 
1126  // Add this node with the current_id (which is determined by the
1127  // alphabetical ordering of the map). Side numbers in Abaqus are 1-based,
1128  // so we subtract 1 here before passing the abaqus side number to the
1129  // mapping array
1130  the_mesh.get_boundary_info().add_side
1131  (&elem,
1132  eledef.abaqus_zero_based_side_id_to_libmesh_side_id[abaqus_side_number-1],
1133  current_id);
1134  }
1135  }
1136  }
1137 
1138 
1139  // Some elsets (if they contain lower-dimensional elements) also
1140  // define sidesets. So loop over them and build a searchable data
1141  // structure we can use to assign sidesets.
1142  {
1143  unsigned char max_dim = this->max_elem_dimension_seen();
1144 
1145  // multimap from lower-dimensional-element-hash-key to
1146  // pair(lower-dimensional-element, boundary_id). The
1147  // lower-dimensional element is used to verify the results of the
1148  // hash table search. The boundary_id will be used to set a
1149  // boundary ID on a higher-dimensional element. We use a multimap
1150  // because the lower-dimensional elements can belong to more than
1151  // 1 sideset, and multiple lower-dimensional elements can hash to
1152  // the same value, but this is very rare.
1153  std::unordered_multimap<dof_id_type, std::pair<Elem *, boundary_id_type>> provide_bcs;
1154 
1155  // The elemset_id counter assigns a logical numbering to the
1156  // _elemset_ids keys. We are going to use these ids as boundary
1157  // ids, so elemset_id is of type boundary_id_type.
1158  container_t::iterator it = _elemset_ids.begin(), end = _elemset_ids.end();
1159  for (boundary_id_type elemset_id=0; it != end; ++it, ++elemset_id)
1160  {
1161  // Grab a reference to the vector of IDs
1162  std::vector<dof_id_type> & id_vector = it->second;
1163 
1164  // Loop over this vector
1165  for (const auto & id : id_vector)
1166  {
1167  // Map the id'th element ID (Abaqus 1-based numbering) to LibMesh numbering
1168  libmesh_error_msg_if(id < 1,
1169  "Invalid Abaqus element ID found");
1170  const dof_id_type libmesh_elem_id = id-1;
1171 
1172  // Get a reference to that element
1173  Elem & elem = the_mesh.elem_ref(libmesh_elem_id);
1174 
1175  // If the element dimension is equal to the maximum
1176  // dimension seen, we can break out of this for loop --
1177  // this elset does not contain sideset information.
1178  if (elem.dim() == max_dim)
1179  break;
1180 
1181  // If the element dimension is zero, this elset contains
1182  // NodeElems which AFAIK are not used for sidesets, they
1183  // are only used to define point masses.
1184  if (elem.dim() == 0)
1185  break;
1186 
1187  // We can only handle elements that are *exactly*
1188  // one dimension lower than the max element
1189  // dimension. Not sure if "edge" BCs in 3D
1190  // actually make sense/are required...
1191  libmesh_error_msg_if(elem.dim()+1 != max_dim,
1192  "ERROR: Expected boundary element of dimension " << max_dim-1 << " but got " << elem.dim());
1193 
1194  // Insert the current (key, pair(elem,id)) into the multimap.
1195  provide_bcs.emplace(elem.key(), std::make_pair(&elem, elemset_id));
1196 
1197  // Associate the name of this sideset with the ID we've
1198  // chosen. It's not necessary to do this for every
1199  // element in the set, but it's convenient to do it here
1200  // since we have all the necessary information...
1201  the_mesh.get_boundary_info().sideset_name(elemset_id) = it->first;
1202  }
1203  }
1204 
1205  // Loop over elements and try to assign boundary information
1206  for (auto & elem : the_mesh.active_element_ptr_range())
1207  if (elem->dim() == max_dim)
1208  for (auto sn : elem->side_index_range())
1209  {
1210  // This is a max-dimension element that may require BCs.
1211  // For each of its sides, including internal sides, we'll
1212  // see if a lower-dimensional element provides boundary
1213  // information for it. Note that we have not yet called
1214  // find_neighbors(), so we can't use elem->neighbor(sn) in
1215  // this algorithm...
1216  auto bounds = provide_bcs.equal_range (elem->key(sn));
1217 
1218  // Add boundary information for each side in the range.
1219  for (const auto & pr : as_range(bounds))
1220  {
1221  // We'll need to compare the lower dimensional element against the current side.
1222  std::unique_ptr<Elem> side (elem->build_side_ptr(sn));
1223 
1224  // Extract the relevant data. We don't need the key for anything.
1225  Elem * lower_dim_elem = pr.second.first;
1226  boundary_id_type bid = pr.second.second;
1227 
1228  // This was a hash, so it might not be perfect. Let's verify...
1229  if (*lower_dim_elem == *side)
1230  the_mesh.get_boundary_info().add_side(elem, sn, bid);
1231  }
1232  }
1233  }
1234 }
IntRange< unsigned short > side_index_range() const
Definition: elem.h:2710
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i)=0
sideset_container_t _sideset_ids
Definition: abaqus_io.h:202
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
This is the MeshBase class.
Definition: mesh_base.h:75
int8_t boundary_id_type
Definition: id_types.h:51
virtual dof_id_type key(const unsigned int s) const =0
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
Definition: simple_range.h:57
std::string & sideset_name(boundary_id_type id)
std::string enum_to_string(const T e)
virtual unsigned short dim() const =0
unsigned char max_elem_dimension_seen()
Definition: abaqus_io.C:1281
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure...
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:639
container_t _elemset_ids
Definition: abaqus_io.h:201
virtual ElemType type() const =0
uint8_t dof_id_type
Definition: id_types.h:67

◆ assign_subdomain_ids()

void libMesh::AbaqusIO::assign_subdomain_ids ( )
protected

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 979 of file abaqus_io.C.

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

Referenced by read().

980 {
981  // Get a reference to the mesh we are reading
982  MeshBase & the_mesh = MeshInput<MeshBase>::mesh();
983 
984  // The number of elemsets we've found while reading
985  std::size_t n_elemsets = _elemset_ids.size();
986 
987  // Fill in a temporary map with (ElemType, index) pairs based on the _elem_types set. This
988  // will allow us to easily look up this index in the loop below.
989  std::map<ElemType, unsigned> elem_types_map;
990  {
991  unsigned ctr=0;
992  for (const auto & type : _elem_types)
993  elem_types_map[type] = ctr++;
994  }
995 
996  // Loop over each Elemset and assign subdomain IDs to Mesh elements
997  {
998  // The maximum element dimension seen while reading the Mesh
999  unsigned char max_dim = this->max_elem_dimension_seen();
1000 
1001  // The elemset_id counter assigns a logical numbering to the _elemset_ids keys
1002  container_t::iterator it = _elemset_ids.begin(), end = _elemset_ids.end();
1003  for (unsigned elemset_id=0; it != end; ++it, ++elemset_id)
1004  {
1005  // Grab a reference to the vector of IDs
1006  std::vector<dof_id_type> & id_vector = it->second;
1007 
1008  // Loop over this vector
1009  for (const auto & id : id_vector)
1010  {
1011  // Map the id'th element ID (Abaqus 1-based numbering) to LibMesh numbering
1012  libmesh_error_msg_if(id < 1,
1013  "Invalid Abaqus element ID found");
1014  const dof_id_type libmesh_elem_id = id-1;
1015 
1016  // Get reference to that element
1017  Elem & elem = the_mesh.elem_ref(libmesh_elem_id);
1018 
1019  // We won't assign subdomain ids to lower-dimensional
1020  // elements, as they are assumed to represent boundary
1021  // conditions. Since lower-dimensional elements can
1022  // appear in multiple sidesets, it doesn't make sense to
1023  // assign them a single subdomain id... only the last one
1024  // assigned would actually "stick".
1025  if (elem.dim() < max_dim)
1026  break;
1027 
1028  // Compute the proper subdomain ID, based on the formula in the
1029  // documentation for this function.
1030  subdomain_id_type computed_id = cast_int<subdomain_id_type>
1031  (elemset_id + (elem_types_map[elem.type()] * n_elemsets));
1032 
1033  // Assign this ID to the element in question
1034  elem.subdomain_id() = computed_id;
1035 
1036  // We will also assign a unique name to the computed_id,
1037  // which is created by appending the geometric element
1038  // name to the elset name provided by the user in the
1039  // Abaqus file.
1040  std::string computed_name = it->first + "_" + Utility::enum_to_string(elem.type());
1041  the_mesh.subdomain_name(computed_id) = computed_name;
1042  }
1043  }
1044  }
1045 }
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
This is the MeshBase class.
Definition: mesh_base.h:75
std::string & subdomain_name(subdomain_id_type id)
Definition: mesh_base.C:1692
std::string enum_to_string(const T e)
std::set< ElemType > _elem_types
A set of the different geometric element types detected when reading the mesh.
Definition: abaqus_io.h:213
subdomain_id_type subdomain_id() const
Definition: elem.h:2582
virtual unsigned short dim() const =0
unsigned char max_elem_dimension_seen()
Definition: abaqus_io.C:1281
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:639
container_t _elemset_ids
Definition: abaqus_io.h:201
virtual ElemType type() const =0
uint8_t dof_id_type
Definition: id_types.h:67

◆ detect_generated_set()

bool libMesh::AbaqusIO::detect_generated_set ( std::string  upper) const
protected
Returns
true if the input string is a generated elset or nset, false otherwise.

The input string is assumed to already be in all upper case. Generated nsets are assumed to have the following format: *Nset, nset=Set-1, generate

Definition at line 821 of file abaqus_io.C.

References strip_ws().

Referenced by read().

822 {
823  // Avoid issues with weird line endings, spaces before commas, etc.
824  strip_ws(upper);
825 
826  // Check each comma-separated value in "upper" to see if it is the generate flag.
827  std::string cell;
828  std::stringstream line_stream(upper);
829  while (std::getline(line_stream, cell, ','))
830  if (cell == "GENERATE")
831  return true;
832 
833  return false;
834 }
void strip_ws(std::string &line) const
Removes all whitespace characters from "line".
Definition: abaqus_io.C:1303

◆ extended_parsing()

virtual void libMesh::AbaqusIO::extended_parsing ( const std::string &  )
inlineprotectedvirtual

Override this callback to implement support for more sections in derived classes.

Definition at line 241 of file abaqus_io.h.

Referenced by read().

241 {}

◆ generate_ids()

void libMesh::AbaqusIO::generate_ids ( std::string  set_name,
container_t container 
)
protected

This function handles "generated" nset and elset sections.

These are denoted by having the comma-separated "GENERATE" keyword in their definition, e.g. *Nset, nset=Set-1, generate

Definition at line 871 of file abaqus_io.C.

References _in, and strip_ws().

Referenced by read().

872 {
873  // Grab a reference to a vector that will hold all the IDs
874  std::vector<dof_id_type> & id_storage = container[set_name];
875 
876  // Read until the start of another section is detected, or EOF is
877  // encountered. "generate" sections seem to only have one line,
878  // although I suppose it's possible they could have more.
879  while (_in->peek() != '*' && _in->peek() != EOF)
880  {
881  // Read entire comma-separated line into a string
882  std::string csv_line;
883  std::getline(*_in, csv_line);
884 
885  // Remove all whitespaces from csv_line.
886  strip_ws(csv_line);
887 
888  // Create a new stringstream object from the string, and stream
889  // in the comma-separated values.
890  char c;
891  dof_id_type start, end, stride;
892  std::stringstream line_stream(csv_line);
893  line_stream >> start >> c >> end >> c >> stride;
894 
895  // Generate entries in the id_storage. Note: each element can
896  // only belong to a single Elset (since this corresponds to the
897  // subdomain_id) so if an element appears in multiple Elsets,
898  // the "last" one (alphabetically, based on set name) in the
899  // _elemset_ids map will "win".
900  for (dof_id_type current = start; current <= end; current += stride)
901  id_storage.push_back(current);
902  }
903 }
void strip_ws(std::string &line) const
Removes all whitespace characters from "line".
Definition: abaqus_io.C:1303
std::unique_ptr< std::istream > _in
Stream object used to interact with the file.
Definition: abaqus_io.h:207
uint8_t dof_id_type
Definition: id_types.h:67

◆ is_parallel_format()

bool libMesh::MeshInput< MeshBase >::is_parallel_format ( ) const
inlineinherited

Returns true iff this mesh file format and input class are parallelized, so that all processors can read their share of the data at once.

Definition at line 87 of file mesh_input.h.

References libMesh::MeshInput< MT >::_is_parallel_format.

87 { return this->_is_parallel_format; }
const bool _is_parallel_format
Flag specifying whether this format is parallel-capable.
Definition: mesh_input.h:130

◆ max_elem_dimension_seen()

unsigned char libMesh::AbaqusIO::max_elem_dimension_seen ( )
protected
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 1281 of file abaqus_io.C.

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

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

1282 {
1283  unsigned char max_dim = 0;
1284 
1285  unsigned char elem_dimensions_size = cast_int<unsigned char>
1286  (elems_of_dimension.size());
1287  // The elems_of_dimension array is 1-based in the UNV reader
1288  for (unsigned char i=1; i<elem_dimensions_size; ++i)
1289  if (elems_of_dimension[i])
1290  max_dim = i;
1291 
1292  return max_dim;
1293 }
std::vector< bool > elems_of_dimension
A vector of bools describing what dimension elements have been encountered when reading a mesh...
Definition: mesh_input.h:107

◆ mesh()

MeshBase & libMesh::MeshInput< MeshBase >::mesh ( )
inlineprotectedinherited
Returns
The object as a writable reference.

Definition at line 178 of file mesh_input.h.

Referenced by libMesh::GMVIO::_read_one_cell(), libMesh::VTKIO::cells_to_vtk(), libMesh::ExodusII_IO::copy_elemental_solution(), libMesh::Nemesis_IO::copy_elemental_solution(), libMesh::ExodusII_IO::copy_nodal_solution(), libMesh::TetGenIO::element_in(), libMesh::UNVIO::elements_in(), libMesh::UNVIO::elements_out(), libMesh::VTKIO::get_local_node_values(), libMesh::ExodusII_IO::get_sideset_data_indices(), libMesh::UNVIO::groups_in(), libMesh::TetGenIO::node_in(), libMesh::UNVIO::nodes_in(), libMesh::UNVIO::nodes_out(), libMesh::VTKIO::nodes_to_vtk(), libMesh::Nemesis_IO::prepare_to_write_nodal_data(), libMesh::GMVIO::read(), libMesh::STLIO::read(), libMesh::Nemesis_IO::read(), libMesh::XdrIO::read(), libMesh::ExodusII_IO::read(), libMesh::CheckpointIO::read(), libMesh::VTKIO::read(), libMesh::STLIO::read_ascii(), libMesh::CheckpointIO::read_bcs(), libMesh::STLIO::read_binary(), libMesh::CheckpointIO::read_connectivity(), libMesh::ExodusII_IO::read_header(), libMesh::CheckpointIO::read_header(), libMesh::XdrIO::read_header(), libMesh::UCDIO::read_implementation(), libMesh::UNVIO::read_implementation(), libMesh::GmshIO::read_mesh(), libMesh::DynaIO::read_mesh(), libMesh::CheckpointIO::read_nodes(), libMesh::CheckpointIO::read_nodesets(), libMesh::CheckpointIO::read_remote_elem(), libMesh::XdrIO::read_serialized_bcs_helper(), libMesh::XdrIO::read_serialized_connectivity(), libMesh::XdrIO::read_serialized_nodes(), libMesh::XdrIO::read_serialized_nodesets(), libMesh::XdrIO::read_serialized_subdomain_names(), libMesh::ExodusII_IO::read_sideset_data(), libMesh::OFFIO::read_stream(), libMesh::MatlabIO::read_stream(), libMesh::CheckpointIO::read_subdomain_names(), libMesh::STLIO::write(), libMesh::TetGenIO::write(), libMesh::Nemesis_IO::write(), libMesh::XdrIO::write(), libMesh::CheckpointIO::write(), libMesh::ExodusII_IO::write(), libMesh::GMVIO::write_ascii_new_impl(), libMesh::GMVIO::write_ascii_old_impl(), libMesh::GMVIO::write_binary(), libMesh::GMVIO::write_discontinuous_gmv(), libMesh::Nemesis_IO::write_element_data(), libMesh::ExodusII_IO::write_element_data(), libMesh::ExodusII_IO::write_elemsets(), libMesh::UCDIO::write_header(), libMesh::UCDIO::write_implementation(), libMesh::UCDIO::write_interior_elems(), libMesh::GmshIO::write_mesh(), libMesh::UCDIO::write_nodal_data(), libMesh::VTKIO::write_nodal_data(), libMesh::ExodusII_IO::write_nodal_data(), libMesh::ExodusII_IO::write_nodal_data_common(), libMesh::ExodusII_IO::write_nodal_data_discontinuous(), libMesh::UCDIO::write_nodes(), libMesh::CheckpointIO::write_nodesets(), libMesh::XdrIO::write_parallel(), libMesh::GmshIO::write_post(), libMesh::XdrIO::write_serialized_bcs_helper(), libMesh::XdrIO::write_serialized_connectivity(), libMesh::XdrIO::write_serialized_nodes(), libMesh::XdrIO::write_serialized_nodesets(), libMesh::XdrIO::write_serialized_subdomain_names(), libMesh::ExodusII_IO::write_sideset_data(), libMesh::UCDIO::write_soln(), and libMesh::CheckpointIO::write_subdomain_names().

179 {
180  libmesh_error_msg_if(_obj == nullptr, "ERROR: _obj should not be nullptr!");
181  return *_obj;
182 }
MeshBase * _obj
A pointer to a non-const object object.
Definition: mesh_input.h:123

◆ parse_label()

std::string libMesh::AbaqusIO::parse_label ( std::string  line,
std::string  label_name 
) const
protected

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 776 of file abaqus_io.C.

References strip_ws().

Referenced by read().

777 {
778  // Handle files which have weird line endings from e.g. windows.
779  // You can check what kind of line endings you have with 'cat -vet'.
780  // For example, some files may have two kinds of line endings like:
781  //
782  // 4997,^I496,^I532,^I487,^I948^M$
783  //
784  // and we don't want to deal with this when extracting a label, so
785  // just remove all the space characters, which should include all
786  // kinds of remaining newlines. (I don't think Abaqus allows
787  // whitespace in label names.)
788  strip_ws(line);
789 
790  // Do all string comparisons in upper-case
791  std::string
792  upper_line(line),
793  upper_label_name(label_name);
794  std::transform(upper_line.begin(), upper_line.end(), upper_line.begin(), ::toupper);
795  std::transform(upper_label_name.begin(), upper_label_name.end(), upper_label_name.begin(), ::toupper);
796 
797  // Get index of start of "label="
798  size_t label_index = upper_line.find(upper_label_name + "=");
799 
800  if (label_index != std::string::npos)
801  {
802  // Location of the first comma following "label="
803  size_t comma_index = upper_line.find(",", label_index);
804 
805  // Construct iterators from which to build the sub-string.
806  // Note: The +1 while initializing beg is to skip past the "=" which follows the label name
807  std::string::iterator
808  beg = line.begin() + label_name.size() + 1 + label_index,
809  end = (comma_index == std::string::npos) ? line.end() : line.begin() + comma_index;
810 
811  return std::string(beg, end);
812  }
813 
814  // The label index was not found, return the empty string
815  return std::string("");
816 }
void strip_ws(std::string &line) const
Removes all whitespace characters from "line".
Definition: abaqus_io.C:1303

◆ process_and_discard_comments()

void libMesh::AbaqusIO::process_and_discard_comments ( )
protected

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 1238 of file abaqus_io.C.

References _in.

Referenced by read().

1239 {
1240  std::string dummy;
1241  while (true)
1242  {
1243  // We assume we are at the beginning of a line that may be
1244  // comments or may be data. We need to only discard the line if
1245  // it begins with **, but we must avoid calling std::getline()
1246  // since there's no way to put that back.
1247  if (_in->peek() == '*')
1248  {
1249  // The first character was a star, so actually read it from the stream.
1250  _in->get();
1251 
1252  // Peek at the next character...
1253  if (_in->peek() == '*')
1254  {
1255  // OK, second character was star also, by definition this
1256  // line must be a comment! Read the rest of the line and discard!
1257  std::getline(*_in, dummy);
1258  }
1259  else
1260  {
1261  // The second character was _not_ a star, so put back the first star
1262  // we pulled out so that the line can be parsed correctly by somebody
1263  // else!
1264  _in->unget();
1265 
1266  // Finally, break out of the while loop, we are done parsing comments
1267  break;
1268  }
1269  }
1270  else
1271  {
1272  // First character was not *, so this line must be data! Break out of the
1273  // while loop!
1274  break;
1275  }
1276  }
1277 }
std::unique_ptr< std::istream > _in
Stream object used to interact with the file.
Definition: abaqus_io.h:207

◆ read()

void libMesh::AbaqusIO::read ( const std::string &  name)
overridevirtual

This method implements reading a mesh from a specified file.

Implements libMesh::MeshInput< MeshBase >.

Definition at line 227 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(), detect_generated_set(), libMesh::MeshInput< MeshBase >::elems_of_dimension, extended_parsing(), generate_ids(), libMesh::MeshBase::get_boundary_info(), libMesh::libmesh_assert(), max_elem_dimension_seen(), libMesh::MeshInput< MT >::mesh(), libMesh::BoundaryInfo::n_boundary_conds(), parse_label(), process_and_discard_comments(), read_elements(), read_ids(), read_nodes(), read_sideset(), libMesh::MeshBase::set_mesh_dimension(), and libMesh::Utility::unzip_file().

Referenced by libMesh::NameBasedIO::read(), and MeshInputTest::testAbaqusRead().

228 {
229  // Get a reference to the mesh we are reading
230  MeshBase & the_mesh = MeshInput<MeshBase>::mesh();
231 
232  // Clear any existing mesh data
233  the_mesh.clear();
234 
235  // Open stream for reading
236  const bool gzipped_file = (fname.rfind(".gz") == fname.size() - 3);
237 
238  if (gzipped_file)
239  {
240 #ifdef LIBMESH_HAVE_GZSTREAM
241  auto inf = std::make_unique<igzstream>();
242  libmesh_assert(inf);
243  inf->open(fname.c_str(), std::ios::in);
244  _in = std::move(inf); // class takes ownership as base class pointer
245 #else
246  libmesh_error_msg("ERROR: need gzstream to handle .gz files!!!");
247 #endif
248  }
249  else
250  {
251  auto inf = std::make_unique<std::ifstream>();
252  libmesh_assert(inf);
253 
254  std::string new_name = Utility::unzip_file(fname);
255  inf->open(new_name.c_str(), std::ios::in);
256  libmesh_assert(inf->good());
257  _in = std::move(inf); // class takes ownership as base class pointer
258  }
259 
260  // Initialize the elems_of_dimension array. We will use this in a
261  // "1-based" manner so that elems_of_dimension[d]==true means
262  // elements of dimension d have been seen.
263  elems_of_dimension.resize(4, false);
264 
265  // Read file line-by-line... this is based on a set of different
266  // test input files. I have not looked at the full input file
267  // specs for Abaqus.
268  std::string s;
269  while (true)
270  {
271  // Try to read something. This may set EOF!
272  std::getline(*_in, s);
273 
274  if (*_in)
275  {
276  // Process s...
277  //
278  // There are many sections in Abaqus files, we read some
279  // but others are just ignored... Some sections may occur
280  // more than once. For example for a hybrid grid, you
281  // will have multiple *Element sections...
282 
283  // Some Abaqus files use all upper-case for section names,
284  // so we will just convert s to uppercase
285  std::string upper(s);
286  std::transform(upper.begin(), upper.end(), upper.begin(), ::toupper);
287 
288  // 0.) Look for the "*Part" section
289  if (upper.find("*PART") == static_cast<std::string::size_type>(0))
290  {
291  libmesh_error_msg_if
293  "We currently don't support reading Abaqus files with multiple PART sections");
294 
295  _already_seen_part = true;
296  }
297 
298  // 1.) Look for the "*Nodes" section
299  if (upper.find("*NODE") == static_cast<std::string::size_type>(0))
300  {
301  // Some sections that begin with *NODE are actually
302  // unrelated sections which we want to skip. I
303  // have only seen this with a single space, but it would
304  // probably be more robust to remove whitespace before
305  // making this check.
306  bool skip_this_section = false;
307  std::vector<std::string> keywords_to_ignore = {"OUTPUT", "PRINT", "FILE", "RESPONSE"};
308  for (auto & affix : keywords_to_ignore) {
309  std::stringstream keyword;
310  keyword << "*NODE " << affix;
311  if (upper.find(keyword.str()) == static_cast<std::string::size_type>(0))
312  skip_this_section = true;
313  }
314  if (skip_this_section)
315  continue;
316 
317  // Some *Node sections also specify an Nset name on the same line.
318  // Look for one here.
319  std::string nset_name = this->parse_label(s, "nset");
320 
321  // Process any lines of comments that may be present
323 
324  // Read a block of nodes
325  this->read_nodes(nset_name);
326  }
327 
328 
329 
330  // 2.) Look for the "*Element" section
331  else if (upper.find("*ELEMENT,") == static_cast<std::string::size_type>(0))
332  {
333  // Some sections that begin with *ELEMENT are actually
334  // "*ELEMENT OUTPUT" sections which we want to skip. I
335  // have only seen this with a single space, but it would
336  // probably be more robust to remove whitespace before
337  // making this check.
338  bool skip_this_section = false;
339  std::vector<std::string> keywords_to_ignore = {"OUTPUT", "MATRIX", "PROPERTIES", "RESPONSE"};
340  for (auto & affix : keywords_to_ignore) {
341  std::stringstream keyword;
342  keyword << "*ELEMENT " << affix;
343  if (upper.find(keyword.str()) == static_cast<std::string::size_type>(0))
344  skip_this_section = true;
345  }
346  if (skip_this_section)
347  continue;
348 
349  // Some *Element sections also specify an Elset name on the same line.
350  // Look for one here.
351  std::string elset_name = this->parse_label(s, "elset");
352 
353  // Process any lines of comments that may be present
355 
356  // Read a block of elements
357  this->read_elements(upper, elset_name);
358  }
359 
360 
361 
362  // 3.) Look for a Nodeset section
363  else if (upper.find("*NSET") == static_cast<std::string::size_type>(0))
364  {
365  std::string nset_name = this->parse_label(s, "nset");
366 
367  // I haven't seen an unnamed nset yet, but let's detect it
368  // just in case...
369  libmesh_error_msg_if(nset_name == "", "Unnamed nset encountered!");
370 
371  // Is this a "generated" nset, i.e. one which has three
372  // entries corresponding to (first, last, stride)?
373  bool is_generated = this->detect_generated_set(upper);
374 
375  // Process any lines of comments that may be present
377 
378  // Read the IDs, storing them in _nodeset_ids
379  if (is_generated)
380  this->generate_ids(nset_name, _nodeset_ids);
381  else
382  this->read_ids(nset_name, _nodeset_ids);
383  } // *Nodeset
384 
385 
386 
387  // 4.) Look for an Elset section
388  else if (upper.find("*ELSET") == static_cast<std::string::size_type>(0))
389  {
390  std::string elset_name = this->parse_label(s, "elset");
391 
392  // I haven't seen an unnamed elset yet, but let's detect it
393  // just in case...
394  libmesh_error_msg_if(elset_name == "", "Unnamed elset encountered!");
395 
396  // Is this a "generated" elset, i.e. one which has three
397  // entries corresponding to (first, last, stride)?
398  bool is_generated = this->detect_generated_set(upper);
399 
400  // Process any lines of comments that may be present
402 
403  // Read the IDs, storing them in _elemset_ids
404  if (is_generated)
405  this->generate_ids(elset_name, _elemset_ids);
406  else
407  this->read_ids(elset_name, _elemset_ids);
408  } // *Elset
409 
410 
411 
412  // 5.) Look for a Surface section. Need to be a little
413  // careful, since there are also "surface interaction"
414  // sections we don't want to read here.
415  else if (upper.find("*SURFACE,") == static_cast<std::string::size_type>(0))
416  {
417  // Get the name from the Name=Foo label. This will be the map key.
418  std::string sideset_name = this->parse_label(s, "name");
419 
420  // Some (all?) surfaces also declare a type, which can
421  // help us figure out how they should be parsed, so we
422  // pass this to the read_sideset() function.
423  std::string sideset_type = this->parse_label(s, "type");
424 
425  // Process any lines of comments that may be present
427 
428  // Read the sideset IDs
429  this->read_sideset(sideset_name, sideset_type, _sideset_ids);
430  }
431 
432  // Derived classes could override this to add support for additional sections
433  extended_parsing(upper);
434 
435  continue;
436  } // if (*_in)
437 
438  // If !file, check to see if EOF was set. If so, break out
439  // of while loop.
440  if (_in->eof())
441  break;
442 
443  // If !in and !in.eof(), stream is in a bad state!
444  libmesh_error_msg("Stream is bad! Perhaps the file: " << fname << " does not exist?");
445  } // while
446 
447  // Set the Mesh dimension based on the highest dimension element seen.
449 
450  // Set element IDs based on the element sets.
451  this->assign_subdomain_ids();
452 
453  // Assign nodeset values to the BoundaryInfo object
454  this->assign_boundary_node_ids();
455 
456  // Assign sideset values in the BoundaryInfo object
457  this->assign_sideset_ids();
458 
459  // If the Abaqus file contains only nodesets, we can have libmesh
460  // generate sidesets from them. This BoundaryInfo function currently
461  // *overwrites* existing sidesets in surprising ways, so we don't
462  // call it if there are already sidesets present in the original file.
465 
466  // Delete lower-dimensional elements from the Mesh. We assume these
467  // were only used for setting BCs, and aren't part of the actual
468  // Mesh.
469  {
470  unsigned char max_dim = this->max_elem_dimension_seen();
471 
472  for (auto & elem : the_mesh.element_ptr_range())
473  if (elem->dim() < max_dim)
474  the_mesh.delete_elem(elem);
475  }
476 }
void process_and_discard_comments()
Any of the various sections can start with some number of lines of comments, which start with "**"...
Definition: abaqus_io.C:1238
std::size_t n_boundary_conds() const
bool _already_seen_part
This flag gets set to true after the first "*PART" section we see.
Definition: abaqus_io.h:221
std::vector< bool > elems_of_dimension
A vector of bools describing what dimension elements have been encountered when reading a mesh...
Definition: mesh_input.h:107
sideset_container_t _sideset_ids
Definition: abaqus_io.h:202
void read_ids(std::string set_name, container_t &container)
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: abaqus_io.C:838
bool build_sidesets_from_nodesets
Default false.
Definition: abaqus_io.h:67
void assign_sideset_ids()
Called at the end of the read() function, assigns any sideset IDs found when reading the file to the ...
Definition: abaqus_io.C:1088
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
void read_nodes(std::string nset_name)
This function parses a block of nodes in the Abaqus file once such a block has been found...
Definition: abaqus_io.C:484
virtual void extended_parsing(const std::string &)
Override this callback to implement support for more sections in derived classes. ...
Definition: abaqus_io.h:241
This is the MeshBase class.
Definition: mesh_base.h:75
void read_elements(std::string upper, std::string elset_name)
This function parses a block of elements in the Abaqus file.
Definition: abaqus_io.C:561
void read_sideset(const std::string &sideset_name, const std::string &sideset_type, sideset_container_t &container)
This function reads a sideset from the input file.
Definition: abaqus_io.C:908
std::string parse_label(std::string line, std::string label_name) const
This function parses a label of the form foo=bar from a comma-delimited line of the form ...
Definition: abaqus_io.C:776
bool detect_generated_set(std::string upper) const
Definition: abaqus_io.C:821
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
void build_side_list_from_node_list()
Adds sides to a sideset if every node on that side are in the same sideset.
void generate_ids(std::string set_name, container_t &container)
This function handles "generated" nset and elset sections.
Definition: abaqus_io.C:871
void assign_subdomain_ids()
This function is called after all the elements have been read and assigns element subdomain IDs...
Definition: abaqus_io.C:979
std::string unzip_file(std::string_view name)
Create an unzipped copy of a bz2 or xz file, returning the name of the now-unzipped file that can be ...
Definition: utility.C:164
libmesh_assert(ctx)
void assign_boundary_node_ids()
This function assigns boundary IDs to node sets based on the alphabetical order in which the sets are...
Definition: abaqus_io.C:1050
container_t _nodeset_ids
Abaqus writes nodesets and elemsets with labels.
Definition: abaqus_io.h:200
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition: mesh_base.h:275
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:920
unsigned char max_elem_dimension_seen()
Definition: abaqus_io.C:1281
std::unique_ptr< std::istream > _in
Stream object used to interact with the file.
Definition: abaqus_io.h:207
container_t _elemset_ids
Definition: abaqus_io.h:201

◆ read_elements()

void libMesh::AbaqusIO::read_elements ( std::string  upper,
std::string  elset_name 
)
protected

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 561 of file abaqus_io.C.

References _elem_types, _elemset_ids, _in, libMesh::MeshBase::add_elem(), libMesh::Elem::build(), libMesh::EDGE2, libMesh::EDGE3, libMesh::MeshInput< MeshBase >::elems_of_dimension, libMesh::Utility::enum_to_string(), libMesh::HEX20, libMesh::HEX27, libMesh::HEX8, libMesh::INVALID_ELEM, libMesh::MeshInput< MT >::mesh(), libMesh::MeshBase::node_ptr(), libMesh::NODEELEM, libMesh::PRISM15, libMesh::PRISM6, libMesh::QUAD4, libMesh::QUAD8, libMesh::Elem::set_node(), string_to_num(), libMesh::TET10, libMesh::TET4, libMesh::TRI3, and libMesh::TRI6.

Referenced by read().

562 {
563  // Get a reference to the mesh we are reading
564  MeshBase & the_mesh = MeshInput<MeshBase>::mesh();
565 
566  // initialize the eletypes map (eletypes is a file-global variable)
567  init_eletypes();
568 
569  ElemType elem_type = INVALID_ELEM;
570  unsigned n_nodes_per_elem = 0;
571 
572  // Within s, we should have "type=XXXX"
573  if (upper.find("T3D2") != std::string::npos ||
574  upper.find("B31") != std::string::npos)
575  {
576  elem_type = EDGE2;
577  n_nodes_per_elem = 2;
578  elems_of_dimension[1] = true;
579  }
580  else if (upper.find("B32") != std::string::npos)
581  {
582  elem_type = EDGE3;
583  n_nodes_per_elem = 3;
584  elems_of_dimension[1] = true;
585  }
586  else if (upper.find("S3") != std::string::npos ||
587  upper.find("CPE3") != std::string::npos ||
588  upper.find("2D3") != std::string::npos)
589  {
590  elem_type = TRI3;
591  n_nodes_per_elem = 3;
592  elems_of_dimension[2] = true;
593  }
594  else if (upper.find("CPE4") != std::string::npos ||
595  upper.find("S4") != std::string::npos ||
596  upper.find("CPEG4") != std::string::npos ||
597  upper.find("2D4") != std::string::npos)
598  {
599  elem_type = QUAD4;
600  n_nodes_per_elem = 4;
601  elems_of_dimension[2] = true;
602  }
603  else if (upper.find("CPE6") != std::string::npos ||
604  upper.find("S6") != std::string::npos ||
605  upper.find("CPEG6") != std::string::npos ||
606  upper.find("2D6") != std::string::npos)
607  {
608  elem_type = TRI6;
609  n_nodes_per_elem = 6;
610  elems_of_dimension[2] = true;
611  }
612  else if (upper.find("CPE8") != std::string::npos ||
613  upper.find("S8") != std::string::npos ||
614  upper.find("CPEG8") != std::string::npos ||
615  upper.find("2D8") != std::string::npos)
616  {
617  elem_type = QUAD8;
618  n_nodes_per_elem = 8;
619  elems_of_dimension[2] = true;
620  }
621  else if (upper.find("3D8") != std::string::npos)
622  {
623  elem_type = HEX8;
624  n_nodes_per_elem = 8;
625  elems_of_dimension[3] = true;
626  }
627  else if (upper.find("3D4") != std::string::npos)
628  {
629  elem_type = TET4;
630  n_nodes_per_elem = 4;
631  elems_of_dimension[3] = true;
632  }
633  else if (upper.find("3D20") != std::string::npos)
634  {
635  elem_type = HEX20;
636  n_nodes_per_elem = 20;
637  elems_of_dimension[3] = true;
638  }
639  else if (upper.find("3D27") != std::string::npos)
640  {
641  elem_type = HEX27;
642  n_nodes_per_elem = 27;
643  elems_of_dimension[3] = true;
644  }
645  else if (upper.find("3D6") != std::string::npos)
646  {
647  elem_type = PRISM6;
648  n_nodes_per_elem = 6;
649  elems_of_dimension[3] = true;
650  }
651  else if (upper.find("3D15") != std::string::npos)
652  {
653  elem_type = PRISM15;
654  n_nodes_per_elem = 15;
655  elems_of_dimension[3] = true;
656  }
657  else if (upper.find("3D10") != std::string::npos)
658  {
659  elem_type = TET10;
660  n_nodes_per_elem = 10;
661  elems_of_dimension[3] = true;
662  }
663  else if (upper.find("MASS") != std::string::npos)
664  {
665  // "MASS" elements are used to indicate point masses in Abaqus
666  // models. These are mapped to NODEELEMs in libmesh.
667  elem_type = NODEELEM;
668  n_nodes_per_elem = 1;
669  elems_of_dimension[0] = true;
670  }
671  else
672  libmesh_error_msg("Unrecognized element type: " << upper);
673 
674  // Insert the elem type we detected into the set of all elem types for this mesh
675  _elem_types.insert(elem_type);
676 
677  // Grab a reference to the element definition for this element type
678  const ElementDefinition & eledef = eletypes[elem_type];
679 
680  // If the element definition was not found, the call above would have
681  // created one with an uninitialized struct. Check for that here...
682  libmesh_error_msg_if
683  (eledef.abaqus_zero_based_node_id_to_libmesh_node_id.size() == 0,
684  "No Abaqus->LibMesh mapping information for ElemType "
685  << Utility::enum_to_string(elem_type) << "!");
686 
687  // We will read elements until the next line begins with *, since that will be the
688  // next section.
689  while (_in->peek() != '*' && _in->peek() != EOF)
690  {
691  // Read the element ID, it is the first number on each line. It is
692  // followed by a comma, so read that also. We will need this ID later
693  // when we try to assign subdomain IDs
694  dof_id_type abaqus_elem_id = 0;
695  char c;
696  *_in >> abaqus_elem_id >> c;
697 
698  // Add an element of the appropriate type to the Mesh, with the
699  // abaqus element ID.
700  std::unique_ptr<Elem> new_elem = Elem::build(elem_type);
701  new_elem->set_id() = abaqus_elem_id-1;
702 
703  Elem * elem = the_mesh.add_elem(std::move(new_elem));
704 
705  // The count of the total number of IDs read for the current element.
706  unsigned id_count=0;
707 
708  // Continue reading line-by-line until we have read enough nodes for this element
709  while (id_count < n_nodes_per_elem)
710  {
711  // Read entire line (up to carriage return) of comma-separated values
712  std::string csv_line;
713  std::getline(*_in, csv_line);
714 
715  // Create a stream object out of the current line
716  std::stringstream line_stream(csv_line);
717 
718  // Process the comma-separated values
719  std::string cell;
720  while (std::getline(line_stream, cell, ','))
721  {
722  dof_id_type abaqus_global_node_id;
723  bool success = string_to_num(cell, abaqus_global_node_id);
724 
725  if (success)
726  {
727  // Map the id'th element ID (Abaqus 1-based numbering) to LibMesh numbering
728  libmesh_error_msg_if(abaqus_global_node_id < 1,
729  "Invalid Abaqus node ID found");
730  const dof_id_type libmesh_global_node_id = abaqus_global_node_id-1;
731 
732  // Grab the node pointer from the mesh for this ID
733  Node * node = the_mesh.node_ptr(libmesh_global_node_id);
734 
735  // If node_ptr() returns nullptr, it may mean we have not yet read the
736  // *Nodes section, though I assumed that always came before the *Elements section...
737  libmesh_error_msg_if
738  (node == nullptr,
739  "Error! Mesh::node_ptr() returned nullptr. Either no node exists with ID "
740  << libmesh_global_node_id
741  << " or perhaps this input file has *Elements defined before *Nodes?");
742 
743  // Note: id_count is the zero-based abaqus (elem local) node index. We therefore map
744  // it to a libmesh elem local node index using the element definition map
745  unsigned libmesh_elem_local_node_id =
746  eledef.abaqus_zero_based_node_id_to_libmesh_node_id[id_count];
747 
748  // Set this node pointer within the element.
749  elem->set_node(libmesh_elem_local_node_id, node);
750 
751  // Increment the count of IDs read for this element
752  id_count++;
753  } // end if (success)
754  } // end while getline(',')
755  } // end while (id_count)
756 
757  // Ensure that we read *exactly* as many nodes as we were expecting to, no more.
758  libmesh_error_msg_if
759  (id_count != n_nodes_per_elem,
760  "Error: Needed to read "
761  << n_nodes_per_elem
762  << " nodes, but read "
763  << id_count
764  << " instead!");
765 
766  // If we are recording Elset IDs, add this element to the correct set for later processing.
767  // Make sure to add it with the Abaqus ID, not the libmesh one!
768  if (elset_name != "")
769  _elemset_ids[elset_name].push_back(abaqus_elem_id);
770  } // end while (peek)
771 }
ElemType
Defines an enum for geometric element types.
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2558
A Node is like a Point, but with more information.
Definition: node.h:52
std::vector< bool > elems_of_dimension
A vector of bools describing what dimension elements have been encountered when reading a mesh...
Definition: mesh_input.h:107
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
This is the MeshBase class.
Definition: mesh_base.h:75
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:444
bool string_to_num(const std::string &input, dof_id_type &output) const
Attempts to convert the input string to a numerical value using strtol.
Definition: abaqus_io.C:1295
std::string enum_to_string(const T e)
std::set< ElemType > _elem_types
A set of the different geometric element types detected when reading the mesh.
Definition: abaqus_io.h:213
std::unique_ptr< std::istream > _in
Stream object used to interact with the file.
Definition: abaqus_io.h:207
virtual const Node * node_ptr(const dof_id_type i) const =0
container_t _elemset_ids
Definition: abaqus_io.h:201
uint8_t dof_id_type
Definition: id_types.h:67

◆ read_ids()

void libMesh::AbaqusIO::read_ids ( std::string  set_name,
container_t container 
)
protected

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 838 of file abaqus_io.C.

References _in, and string_to_num().

Referenced by read().

839 {
840  // Grab a reference to a vector that will hold all the IDs
841  std::vector<dof_id_type> & id_storage = container[set_name];
842 
843  // Read until the start of another section is detected, or EOF is encountered
844  while (_in->peek() != '*' && _in->peek() != EOF)
845  {
846  // Read entire comma-separated line into a string
847  std::string csv_line;
848  std::getline(*_in, csv_line);
849 
850  // On that line, use std::getline again to parse each
851  // comma-separated entry.
852  std::string cell;
853  std::stringstream line_stream(csv_line);
854  while (std::getline(line_stream, cell, ','))
855  {
856  dof_id_type id;
857  bool success = string_to_num(cell, id);
858 
859  // Note that lists of comma-separated values in abaqus also
860  // *end* with a comma, so the last call to getline on a given
861  // line will get an empty string, which we must detect.
862  if (success)
863  id_storage.push_back(id);
864  }
865  }
866 }
bool string_to_num(const std::string &input, dof_id_type &output) const
Attempts to convert the input string to a numerical value using strtol.
Definition: abaqus_io.C:1295
std::unique_ptr< std::istream > _in
Stream object used to interact with the file.
Definition: abaqus_io.h:207
uint8_t dof_id_type
Definition: id_types.h:67

◆ read_nodes()

void libMesh::AbaqusIO::read_nodes ( std::string  nset_name)
protected

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 484 of file abaqus_io.C.

References _in, _nodeset_ids, libMesh::MeshBase::add_point(), libMesh::MeshInput< MT >::mesh(), libMesh::MeshBase::query_node_ptr(), libMesh::Real, and strip_ws().

Referenced by read().

485 {
486  // Get a reference to the mesh we are reading
487  MeshBase & the_mesh = MeshInput<MeshBase>::mesh();
488 
489  // In the input files I have, Abaqus neither tells what
490  // the mesh dimension is nor how many nodes it has...
491  //
492  // The node line format is:
493  // id, x, y, z
494  // and you do have to parse out the commas.
495  // The z-coordinate will only be present for 3D meshes
496 
497  // Temporary variables for parsing lines of text
498  char c;
499  std::string line;
500 
501  // We need to duplicate some of the read_ids code if this *NODE
502  // section also defines an NSET. We'll set up the id_storage
503  // pointer and push back IDs into this vector in the loop below...
504  std::vector<dof_id_type> * id_storage = nullptr;
505  if (nset_name != "")
506  id_storage = &(_nodeset_ids[nset_name]);
507 
508  // We will read nodes until the next line begins with *, since that will be the
509  // next section.
510  // TODO: Is Abaqus guaranteed to start the line with '*' or can there be leading white space?
511  while (_in->peek() != '*' && _in->peek() != EOF)
512  {
513  // Read an entire line which corresponds to a single point's id
514  // and (x,y,z) values.
515  std::getline(*_in, line);
516 
517  // Remove all whitespace characters from the line. This way we
518  // can do the remaining parsing without worrying about tabs,
519  // different numbers of spaces, etc.
520  strip_ws(line);
521 
522  // Make a stream out of the modified line so we can stream values
523  // from it in the usual way.
524  std::stringstream ss(line);
525 
526  // Values to be read in from file
527  dof_id_type abaqus_node_id=0;
528  Real x=0, y=0, z=0;
529 
530  // Note: we assume *at least* 2D points here, should we worry about
531  // trying to read 1D Abaqus meshes?
532  ss >> abaqus_node_id >> c >> x >> c >> y;
533 
534  // Peek at the next character. If it is a comma, then there is another
535  // value to read!
536  if (ss.peek() == ',')
537  ss >> c >> z;
538 
539  // If this *NODE section defines an NSET, also store the abaqus ID in id_storage
540  if (id_storage)
541  id_storage->push_back(abaqus_node_id);
542 
543  // Convert from Abaqus 1-based to libMesh 0-based numbering
544  libmesh_error_msg_if(abaqus_node_id < 1,
545  "Invalid Abaqus node ID found");
546  const dof_id_type libmesh_node_id = abaqus_node_id-1;
547 
548  libmesh_error_msg_if(the_mesh.query_node_ptr(libmesh_node_id),
549  "Duplicate Abaqus node ID found");
550 
551  // Add the point to the mesh using libmesh's numbering,
552  // and post-increment the libmesh node counter.
553  the_mesh.add_point(Point(x,y,z), libmesh_node_id);
554  } // while
555 }
void strip_ws(std::string &line) const
Removes all whitespace characters from "line".
Definition: abaqus_io.C:1303
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
This is the MeshBase class.
Definition: mesh_base.h:75
virtual const Node * query_node_ptr(const dof_id_type i) const =0
container_t _nodeset_ids
Abaqus writes nodesets and elemsets with labels.
Definition: abaqus_io.h:200
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::unique_ptr< std::istream > _in
Stream object used to interact with the file.
Definition: abaqus_io.h:207
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
uint8_t dof_id_type
Definition: id_types.h:67

◆ read_sideset()

void libMesh::AbaqusIO::read_sideset ( const std::string &  sideset_name,
const std::string &  sideset_type,
sideset_container_t container 
)
protected

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 908 of file abaqus_io.C.

References _elemset_ids, _in, _nodeset_ids, libMesh::out, side_id, string_to_num(), and strip_ws().

Referenced by read().

911 {
912  // Grab a reference to a vector that will hold all the IDs
913  std::vector<std::pair<dof_id_type, unsigned>> & id_storage = container[sideset_name];
914 
915  // Variables for storing values read in from file
916  unsigned side_id=0;
917  char c;
918  std::string elem_id_or_set, dummy;
919 
920  // Read until the start of another section is detected, or EOF is encountered
921  while (_in->peek() != '*' && _in->peek() != EOF)
922  {
923  // Read first string up to and including the comma, which is discarded.
924  std::getline(*_in, elem_id_or_set, ',');
925 
926  // Strip any leading or trailing trailing whitespace from this
927  // string, since some Abaqus files may have this.
928  strip_ws(elem_id_or_set);
929 
930  // Handle sidesets of type "NODE"
931  if (sideset_type == "NODE")
932  {
933  // Create a sideset from a nodeset. This is not currently
934  // supported, so print a warning and keep going.
935  if (_nodeset_ids.count(elem_id_or_set))
936  libMesh::out << "Warning: skipped creating a sideset from a "
937  << "nodeset, this is not yet supported."
938  << std::endl;
939  }
940 
941  // Otherwise, we assume it's a sideset of the form: "391, S2" or "Elset_1, S3".
942  // If it's not one of these forms, we'll throw an error instead
943  // of letting the stream get into a bad state.
944  else // sideset_type != "NODE"
945  {
946  // Read the character "S", followed by the side id. Note: the >> operator
947  // eats whitespace until it reaches a valid character, so this should work
948  // whether or not there is a space after the previous comma.
949  *_in >> c >> side_id;
950 
951  // Try to convert first string to an integer.
952  dof_id_type elem_id;
953  bool success = string_to_num(elem_id_or_set, elem_id);
954 
955  if (success)
956  {
957  // if the side set is of the form of "391, S2"
958  id_storage.emplace_back(elem_id, side_id);
959  }
960 
961  if (!success)
962  {
963  // if the side set is of the form of "Elset_1, S3"
964  const auto & vec = libmesh_map_find(_elemset_ids, elem_id_or_set);
965  for (const auto & elem_id_in_elset : vec)
966  id_storage.emplace_back(elem_id_in_elset, side_id);
967  }
968  }
969 
970  // Successful or not, we extract the remaining characters on the
971  // line, including the newline, to (hopefully) go to the next section.
972  std::getline(*_in, dummy);
973  } // while
974 }
const boundary_id_type side_id
void strip_ws(std::string &line) const
Removes all whitespace characters from "line".
Definition: abaqus_io.C:1303
container_t _nodeset_ids
Abaqus writes nodesets and elemsets with labels.
Definition: abaqus_io.h:200
bool string_to_num(const std::string &input, dof_id_type &output) const
Attempts to convert the input string to a numerical value using strtol.
Definition: abaqus_io.C:1295
OStreamProxy out
std::unique_ptr< std::istream > _in
Stream object used to interact with the file.
Definition: abaqus_io.h:207
container_t _elemset_ids
Definition: abaqus_io.h:201
uint8_t dof_id_type
Definition: id_types.h:67

◆ set_n_partitions()

void libMesh::MeshInput< MeshBase >::set_n_partitions ( unsigned int  n_parts)
inlineprotectedinherited

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 101 of file mesh_input.h.

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

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

101 { this->mesh().set_n_partitions() = n_parts; }
unsigned int & set_n_partitions()
Definition: mesh_base.h:1865

◆ skip_comment_lines()

void libMesh::MeshInput< MeshBase >::skip_comment_lines ( std::istream &  in,
const char  comment_start 
)
protectedinherited

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

Definition at line 187 of file mesh_input.h.

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

189 {
190  char c, line[256];
191 
192  while (in.get(c), c==comment_start)
193  in.getline (line, 255);
194 
195  // put back first character of
196  // first non-comment line
197  in.putback (c);
198 }

◆ string_to_num()

bool libMesh::AbaqusIO::string_to_num ( const std::string &  input,
dof_id_type output 
) const
protected

Attempts to convert the input string to a numerical value using strtol.

If the conversion fails, 0 will be stored in the output, so you must check the return value, which will be true if the conversion succeeded, and false if it failed for any reason.

Definition at line 1295 of file abaqus_io.C.

Referenced by read_elements(), read_ids(), and read_sideset().

1296 {
1297  char *endptr;
1298  output = cast_int<dof_id_type>(std::strtol(input.c_str(), &endptr, /*base=*/10));
1299 
1300  return (output != 0 || endptr != input.c_str());
1301 }

◆ strip_ws()

void libMesh::AbaqusIO::strip_ws ( std::string &  line) const
protected

Removes all whitespace characters from "line".

Simpler than trying to remember the erase-remove-if idiom.

Definition at line 1303 of file abaqus_io.C.

Referenced by detect_generated_set(), generate_ids(), parse_label(), read_nodes(), and read_sideset().

1304 {
1305  line.erase(std::remove_if(line.begin(), line.end(),
1306  [](unsigned char const c)
1307  { return std::isspace(c); }),
1308  line.end());
1309 }

Member Data Documentation

◆ _already_seen_part

bool libMesh::AbaqusIO::_already_seen_part
protected

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 221 of file abaqus_io.h.

Referenced by read().

◆ _elem_types

std::set<ElemType> libMesh::AbaqusIO::_elem_types
protected

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

Definition at line 213 of file abaqus_io.h.

Referenced by assign_subdomain_ids(), and read_elements().

◆ _elemset_ids

container_t libMesh::AbaqusIO::_elemset_ids
protected

◆ _in

std::unique_ptr<std::istream> libMesh::AbaqusIO::_in
protected

Stream object used to interact with the file.

Definition at line 207 of file abaqus_io.h.

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

◆ _nodeset_ids

container_t libMesh::AbaqusIO::_nodeset_ids
protected

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 200 of file abaqus_io.h.

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

◆ _sideset_ids

sideset_container_t libMesh::AbaqusIO::_sideset_ids
protected

Definition at line 202 of file abaqus_io.h.

Referenced by assign_sideset_ids(), and read().

◆ build_sidesets_from_nodesets

bool libMesh::AbaqusIO::build_sidesets_from_nodesets

Default false.

Set this flag to true if you want libmesh to automatically generate sidesets from Abaqus' nodesets. If the Abaqus file already contains some sidesets, we ignore this flag and don't generate sidesets, because the algorithm to do so currently does not take into account existing sidesets.

Definition at line 67 of file abaqus_io.h.

Referenced by read().

◆ elems_of_dimension

std::vector<bool> libMesh::MeshInput< MeshBase >::elems_of_dimension
protectedinherited

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