diff --git a/src/fileFormats/abaqus/ABAQUSCore.C b/src/fileFormats/abaqus/ABAQUSCore.C index 356bffa3c1d99211cbca07db08f5ba4e25198f47..c99f217b030596c233109de8784bc6140c982fa2 100644 --- a/src/fileFormats/abaqus/ABAQUSCore.C +++ b/src/fileFormats/abaqus/ABAQUSCore.C @@ -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, diff --git a/src/fileFormats/abaqus/ABAQUSCore.H b/src/fileFormats/abaqus/ABAQUSCore.H index 3f99516c854f7443fcdbf04138dfacdf0a459c52..4149d5962171dc021f85c98277e718184d6e6cf7 100644 --- a/src/fileFormats/abaqus/ABAQUSCore.H +++ b/src/fileFormats/abaqus/ABAQUSCore.H @@ -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(); }; diff --git a/src/surfMesh/surfaceFormats/abaqus/ABAQUSsurfaceFormat.C b/src/surfMesh/surfaceFormats/abaqus/ABAQUSsurfaceFormat.C index 72ebcfc65e22452b43cec5d370a70f06ff335091..cfcd5357dc76c5e3cc5854e221bfc4b8781707fb 100644 --- a/src/surfMesh/surfaceFormats/abaqus/ABAQUSsurfaceFormat.C +++ b/src/surfMesh/surfaceFormats/abaqus/ABAQUSsurfaceFormat.C @@ -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