Skip to content
Snippets Groups Projects
Commit 1d398d8c authored by Mark OLESEN's avatar Mark OLESEN
Browse files

ENH: handle abaqus SURFACE input (#1600)

- read surfaces which are defined in terms of solid element sides. Eg,

```
  *ELEMENT, TYPE=C3D4, ELSET=...
  1, ...
  2, ...

  *SURFACE, NAME=Things, TYPE=ELEMENT
  1, S1
  2, S1
```

  The element and side number are encoded as a synthetic face id
  according to

      -(10 * elemId + sideNum)

  but the underlying solid geometry is discarded, since there is no
  reasonable way to pass it through the surface sampling mechanism.
parent 986199f8
1 merge request!394Updated surface handling
......@@ -30,8 +30,9 @@ License
#include "ListOps.H"
#include "stringOps.H"
#include "UIListStream.H"
#undef Foam_readAbaqusSurface
#include "cellModel.H"
#include <algorithm>
#include <cctype>
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
......@@ -319,11 +320,10 @@ Foam::fileFormats::ABAQUSCore::readHelper::readPoints
const label initialCount = points_.size();
char sep; // Comma separator (dummy)
string line;
label id;
point p;
string line;
// Read nodes (points) until next "*Section"
while (is.peek() != '*' && is.peek() != EOF)
{
......@@ -368,10 +368,10 @@ Foam::fileFormats::ABAQUSCore::readHelper::readElements
const label initialCount = elemTypes_.size();
char sep; // Comma separator (dummy)
string line;
label id;
labelList elemNodes(nNodes, Zero);
string line;
labelList elemNodes(nNodes, Zero);
// Read element connectivity until next "*Section"
......@@ -403,6 +403,130 @@ Foam::fileFormats::ABAQUSCore::readHelper::readElements
}
Foam::label
Foam::fileFormats::ABAQUSCore::readHelper::readSurfaceElements
(
ISstream& is,
const label setId
)
{
// Info<< "*Surface" << nl;
// Models for supported solids (need to face mapping)
const cellModel& tet = cellModel::ref(cellModel::TET);
const cellModel& prism = cellModel::ref(cellModel::PRISM);
const cellModel& hex = cellModel::ref(cellModel::HEX);
// Face mapping from Abaqus cellModel to OpenFOAM cellModel
const auto& abqToFoamFaceMap = abaqusToFoamFaceAddr();
const label initialCount = elemTypes_.size();
char sep; // Comma separator (dummy)
string line;
label id;
// Read until next "*Section"
// Parse for elemId, sideId.
// Eg, "1235, S1"
while (is.peek() != '*' && is.peek() != EOF)
{
is >> id >> sep;
is.getLine(line);
const word sideName(word::validate(stringOps::upper(line)));
if
(
sideName.size() != 2
|| sideName[0] != 'S'
|| !std::isdigit(sideName[1])
)
{
Info<< "Abaqus reader: unsupported surface element side "
<< id << ", " << sideName << nl;
continue;
}
const label index = elemIds_.find(id);
if (id <= 0 || index < 0)
{
Info<< "Abaqus reader: unsupported surface element "
<< id << nl;
continue;
}
const auto faceIdIter = abqToFoamFaceMap.cfind(elemTypes_[index]);
if (!faceIdIter.found())
{
Info<< "Abaqus reader: reject non-solid shape: " << nl;
}
// The abaqus element side number (1-based)
const label sideNum = (sideName[1] - '0');
const label foamFaceNum = (*faceIdIter)[sideNum - 1];
const labelList& connect = connectivity_[index];
// Nodes for the derived shell element
labelList elemNodes;
switch (elemTypes_[index])
{
case shapeType::abaqusTet:
{
elemNodes = labelList(connect, tet.modelFaces()[foamFaceNum]);
break;
}
case shapeType::abaqusPrism:
{
elemNodes = labelList(connect, prism.modelFaces()[foamFaceNum]);
break;
}
case shapeType::abaqusHex:
{
elemNodes = labelList(connect, hex.modelFaces()[foamFaceNum]);
break;
}
default:
break;
}
enum shapeType shape = shapeType::abaqusUnknownShape;
if (elemNodes.size() == 3)
{
shape = shapeType::abaqusTria;
}
else if (elemNodes.size() == 4)
{
shape = shapeType::abaqusQuad;
}
else
{
// Cannot happen
FatalErrorInFunction
<< "Could not map face side for "
<< id << ", " << sideName << nl
<< exit(FatalError);
}
// Synthesize face Id from solid element Id and side Id
const label newElemId = ABAQUSCore::encodeSolidId(id, sideNum);
// Further checks?
connectivity_.append(std::move(elemNodes));
elemTypes_.append(shape);
elemIds_.append(newElemId);
elsetIds_.append(setId);
}
return (elemTypes_.size() - initialCount);
}
void Foam::fileFormats::ABAQUSCore::readHelper::read
(
ISstream& is
......@@ -427,9 +551,11 @@ void Foam::fileFormats::ABAQUSCore::readHelper::read
// Some abaqus files use upper-case or mixed-case for section names,
// convert all to upper-case for ease.
string upperLine(stringOps::upper(line));
const string upperLine(stringOps::upper(line));
//
// "*Nodes" section
//
if (upperLine.starts_with("*NODE"))
{
// Ignore "NSET=...", we cannot do anything useful with it
......@@ -446,14 +572,16 @@ void Foam::fileFormats::ABAQUSCore::readHelper::read
continue;
}
//
// "*Element" section
//
if (upperLine.starts_with("*ELEMENT,"))
{
// Must have "TYPE=..."
auto elemTypeName = getIdentifier("TYPE", line);
const string elemTypeName(getIdentifier("TYPE", line));
// May have "ELSET=..." on the same line
string elsetName(getIdentifier("ELSET", line));
const string elsetName(getIdentifier("ELSET", line));
const shapeType shape(getElementType(elemTypeName));
......@@ -485,18 +613,42 @@ void Foam::fileFormats::ABAQUSCore::readHelper::read
continue;
}
//
// "*Surface" section
//
if (upperLine.starts_with("*SURFACE,"))
{
#ifdef Foam_readAbaqusSurface
// Require "NAME=..." on the same line
const string elsetName(getIdentifier("NAME", line));
// May have "TYPE=..." on the same line.
// If missing, default is ELEMENT.
const string surfTypeName(getIdentifier("TYPE", line));
if
(
!surfTypeName.empty()
&& stringOps::upper(surfTypeName) != "ELEMENT"
)
{
Info<< "Reading abaqus surface type "
<< surfTypeName << " is not implemented" << nl;
continue;
}
// Treat like an element set
const label elsetId = addNewElset(elsetName);
skipComments(is);
#else
Info<< "Reading of abaqus surfaces not implemented" << nl;
#endif
nread = readSurfaceElements(is, elsetId);
if (verbose_)
{
InfoErr
<< "Read " << nread << " *SURFACE entries for "
<< elsetName << nl;
}
continue;
}
}
......@@ -623,6 +775,15 @@ void Foam::fileFormats::ABAQUSCore::readHelper::compact_nodes()
}
void Foam::fileFormats::ABAQUSCore::readHelper::renumber_elements_1to0()
{
for (label& elemId : elemIds_)
{
renumber0_elemId(elemId);
}
}
void Foam::fileFormats::ABAQUSCore::writePoints
(
Ostream& os,
......
......@@ -90,7 +90,6 @@ SourceFiles
namespace Foam
{
namespace fileFormats
{
......@@ -148,11 +147,62 @@ public:
return (tag & 0x80);
}
//- Is a combined (synthetic) face Id?
inline static bool isEncodedSolidId(const label combinedId)
{
return (combinedId < 0);
}
//- Combine solid element Id and side Id into synthetic face Id
inline static label encodeSolidId(const label id, const label side)
{
return -(10 * id + side);
}
//- Entangle solid element id from synthetic face Id
inline static label decodeSolidElementId(const label combinedId)
{
return
(
isEncodedSolidId(combinedId)
? (-combinedId / 10)
: combinedId
);
}
//- Entangle solid side id from synthetic face Id
//- Synthesize faceId from solid element Id and sideId
inline static label decodeSolidSideNum(const label combinedId)
{
return
(
isEncodedSolidId(combinedId)
? (-combinedId % 10)
: 0
);
}
protected:
// Protected Member Functions
//- From 1-based to 0-based
inline static void renumber0_elemId(label& elemId)
{
if (isEncodedSolidId(elemId))
{
// Eg,
// 1-based (solid 4, side 2) is -42
// 0-based (solid 3, side 2) is -32
elemId += 10;
}
else
{
--elemId;
}
}
//- Face addressing from ABAQUS faces to OpenFOAM faces.
// For hex, prism, tet primitive shapes.
static const Map<labelList>& abaqusToFoamFaceAddr();
......@@ -249,12 +299,26 @@ protected:
const label setId = 0
);
//- Read elements within an "*Surface" section.
// If the shape is known/supported, appends to
// connectivity, elemType, elemIds lists.
//
// \return the number of elements read
label readSurfaceElements
(
ISstream& is,
const label setId = 0
);
//- Remove non-shell elements and compact the points
void purge_solids();
//- Compact unused points and relabel connectivity
void compact_nodes();
//- Renumber elements from 1-based to 0-based
void renumber_elements_1to0();
};
......
......@@ -154,6 +154,7 @@ bool Foam::fileFormats::ABAQUSsurfaceFormat<Face>::read
// No solids
reader.purge_solids();
reader.compact_nodes();
reader.renumber_elements_1to0(); // Convert 1-based -> 0-based
// Convert connectivity to faces
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment