openfoam/applications/utilities/mesh/conversion/ideasUnvToFoam/ideasUnvToFoam.C
Mark Olesen b98f53ceca ENH: make ITstream positioning methods noexcept
ENH: add rank() method for compound tokens

ENH: add IOstream::minPrecision(unsigned)

- reduced typing, more expressive, no namespace ambiguity with max()

    new: IOstream::minPrecision(10);
    old: IOstream::defaultPrecision(max(10u, IOstream::defaultPrecision()));

STYLE: namespace qualify min/max for some buffer sizing [clang/hipp]
2024-03-06 11:01:57 +01:00

1283 lines
34 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2021-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
ideasUnvToFoam
Group
grpMeshConversionUtilities
Description
I-Deas unv format mesh conversion.
Uses either
- DOF sets (757) or
- face groups (2452(Cubit), 2467)
to do patching.
Works without but then puts all faces in defaultFaces patch.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "polyMesh.H"
#include "Time.H"
#include "IFstream.H"
#include "cellModel.H"
#include "cellSet.H"
#include "faceSet.H"
#include "DynamicList.H"
#include <cassert>
#include "MeshedSurfaces.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
const string SEPARATOR(" -1");
bool isSeparator(const std::string& line)
{
return line.substr(0, 6) == SEPARATOR;
}
// Reads past -1 and reads element type
label readTag(IFstream& is)
{
string tag;
do
{
if (!is.good())
{
return -1;
}
string line;
is.getLine(line);
if (line.size() < 6)
{
return -1;
}
tag = line.substr(0, 6);
} while (tag == SEPARATOR);
return readLabel(tag);
}
// Reads and prints header
void readHeader(IFstream& is)
{
string line;
while (is.good())
{
is.getLine(line);
if (isSeparator(line))
{
break;
}
else
{
Info<< line << endl;
}
}
}
// Skip
void skipSection(IFstream& is)
{
Info<< "Skipping section at line " << is.lineNumber() << '.' << endl;
string line;
while (is.good())
{
is.getLine(line);
if (isSeparator(line))
{
break;
}
}
}
scalar readUnvScalar(const std::string& unvString)
{
string s(unvString);
s.replaceAll("d", "E");
s.replaceAll("D", "E");
return readScalar(s);
}
// Reads unit section
void readUnits
(
IFstream& is,
scalar& lengthScale,
scalar& forceScale,
scalar& tempScale,
scalar& tempOffset
)
{
Info<< "Starting reading units at line " << is.lineNumber() << '.' << endl;
string line;
is.getLine(line);
label l = readLabel(line.substr(0, 10));
Info<< "l:" << l << endl;
string units(line.substr(10, 20));
Info<< "units:" << units << endl;
label unitType = readLabel(line.substr(30, 10));
Info<< "unitType:" << unitType << endl;
// Read lengthscales
is.getLine(line);
lengthScale = readUnvScalar(line.substr(0, 25));
forceScale = readUnvScalar(line.substr(25, 25));
tempScale = readUnvScalar(line.substr(50, 25));
is.getLine(line);
tempOffset = readUnvScalar(line.substr(0, 25));
Info<< "Unit factors:" << nl
<< " Length scale : " << lengthScale << nl
<< " Force scale : " << forceScale << nl
<< " Temperature scale : " << tempScale << nl
<< " Temperature offset : " << tempOffset << nl
<< endl;
}
// Reads points section. Read region as well?
void readPoints
(
IFstream& is,
DynamicList<point>& points, // coordinates
DynamicList<label>& unvPointID // unv index
)
{
Info<< "Starting reading points at line " << is.lineNumber() << '.' << endl;
static bool hasWarned = false;
while (true)
{
string line;
is.getLine(line);
label pointi = readLabel(line.substr(0, 10));
if (pointi == -1)
{
break;
}
else if (pointi != points.size()+1 && !hasWarned)
{
hasWarned = true;
IOWarningInFunction(is)
<< "Points not in order starting at point " << pointi
<< endl;
}
is.getLine(line);
unvPointID.push_back(pointi);
point& p = points.emplace_back();
p.x() = readUnvScalar(line.substr(0, 25));
p.y() = readUnvScalar(line.substr(25, 25));
p.z() = readUnvScalar(line.substr(50, 25));
}
points.shrink();
unvPointID.shrink();
Info<< "Read " << points.size() << " points." << endl;
}
void addAndExtend
(
DynamicList<label>& indizes,
label celli,
label val
)
{
if (indizes.size() < (celli+1))
{
indizes.setSize(celli+1,-1);
}
indizes[celli] = val;
}
// Reads cells section. Read region as well? Not handled yet but should just
// be a matter of reading corresponding to boundaryFaces the correct property
// and sorting it later on.
void readCells
(
IFstream& is,
DynamicList<cellShape>& cellVerts,
DynamicList<label>& cellMaterial,
DynamicList<label>& boundaryFaceIndices,
DynamicList<face>& boundaryFaces,
DynamicList<label>& cellCorrespondence,
DynamicList<label>& unvPointID // unv index
)
{
Info<< "Starting reading cells at line " << is.lineNumber() << '.' << endl;
// Invert point numbering.
label maxUnvPoint = 0;
forAll(unvPointID, pointi)
{
maxUnvPoint = max(maxUnvPoint, unvPointID[pointi]);
}
labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
const cellModel& hex = cellModel::ref(cellModel::HEX);
const cellModel& prism = cellModel::ref(cellModel::PRISM);
const cellModel& tet = cellModel::ref(cellModel::TET);
labelHashSet skippedElements;
labelHashSet foundFeType;
while (true)
{
string line;
is.getLine(line);
if (isSeparator(line))
{
break;
}
label celli, feID, physProp, matProp, colour, nNodes;
IStringStream lineStr(line);
lineStr
>> celli >> feID >> physProp >> matProp >> colour >> nNodes;
if (foundFeType.insert(feID))
{
Info<< "First occurrence of element type " << feID
<< " for cell " << celli << " at line "
<< is.lineNumber() << endl;
}
if (feID == 11)
{
// Rod. Skip.
is.getLine(line);
is.getLine(line);
}
else if (feID == 171)
{
// Rod. Skip.
is.getLine(line);
}
else if (feID == 41 || feID == 91)
{
// Triangle. Save - used for patching later on.
is.getLine(line);
face cVerts(3);
IStringStream lineStr(line);
lineStr
>> cVerts[0] >> cVerts[1] >> cVerts[2];
boundaryFaces.append(cVerts);
boundaryFaceIndices.append(celli);
}
else if (feID == 44 || feID == 94)
{
// Quad. Save - used for patching later on.
is.getLine(line);
face cVerts(4);
IStringStream lineStr(line);
lineStr
>> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
boundaryFaces.append(cVerts);
boundaryFaceIndices.append(celli);
}
else if (feID == 111)
{
// Tet.
is.getLine(line);
labelList cVerts(4);
IStringStream lineStr(line);
lineStr
>> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
cellVerts.append(cellShape(tet, cVerts, true));
cellMaterial.append(physProp);
addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
if (cellVerts.last().size() != cVerts.size())
{
Info<< "Line:" << is.lineNumber()
<< " element:" << celli
<< " type:" << feID
<< " collapsed from " << cVerts << nl
<< " to:" << cellVerts.last()
<< endl;
}
}
else if (feID == 112)
{
// Wedge.
is.getLine(line);
labelList cVerts(6);
IStringStream lineStr(line);
lineStr
>> cVerts[0] >> cVerts[1] >> cVerts[2]
>> cVerts[3] >> cVerts[4] >> cVerts[5];
cellVerts.append(cellShape(prism, cVerts, true));
cellMaterial.append(physProp);
addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
if (cellVerts.last().size() != cVerts.size())
{
Info<< "Line:" << is.lineNumber()
<< " element:" << celli
<< " type:" << feID
<< " collapsed from " << cVerts << nl
<< " to:" << cellVerts.last()
<< endl;
}
}
else if (feID == 115)
{
// Hex.
is.getLine(line);
labelList cVerts(8);
IStringStream lineStr(line);
lineStr
>> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3]
>> cVerts[4] >> cVerts[5] >> cVerts[6] >> cVerts[7];
cellVerts.append(cellShape(hex, cVerts, true));
cellMaterial.append(physProp);
addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
if (cellVerts.last().size() != cVerts.size())
{
Info<< "Line:" << is.lineNumber()
<< " element:" << celli
<< " type:" << feID
<< " collapsed from " << cVerts << nl
<< " to:" << cellVerts.last()
<< endl;
}
}
else if (feID == 118)
{
// Parabolic Tet
is.getLine(line);
labelList cVerts(4);
label dummy;
{
IStringStream lineStr(line);
lineStr
>> cVerts[0] >> dummy >> cVerts[1] >> dummy >> cVerts[2];
}
is.getLine(line);
{
IStringStream lineStr(line);
lineStr >> dummy>> cVerts[3];
}
cellVerts.append(cellShape(tet, cVerts, true));
cellMaterial.append(physProp);
addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
if (cellVerts.last().size() != cVerts.size())
{
Info<< "Line:" << is.lineNumber()
<< " element:" << celli
<< " type:" << feID
<< " collapsed from " << cVerts << nl
<< " to:" << cellVerts.last()
<< endl;
}
}
else
{
if (skippedElements.insert(feID))
{
IOWarningInFunction(is)
<< "Cell type " << feID << " not supported" << endl;
}
is.getLine(line);
}
}
cellVerts.shrink();
cellMaterial.shrink();
boundaryFaces.shrink();
boundaryFaceIndices.shrink();
cellCorrespondence.shrink();
Info<< "Read " << cellVerts.size() << " cells"
<< " and " << boundaryFaces.size() << " boundary faces." << endl;
if (!cellVerts.size())
{
WarningInFunction
<< "There are no cells in the mesh." << endl
<< " Note: 2D meshes are not supported."<< endl;
}
}
void readSets
(
IFstream& is,
DynamicList<word>& patchNames,
DynamicList<labelList>& patchFaceIndices
)
{
Info<< "Starting reading patches at line " << is.lineNumber() << '.'
<< endl;
while (true)
{
string line;
is.getLine(line);
if (isSeparator(line))
{
break;
}
IStringStream lineStr(line);
label group, constraintSet, restraintSet, loadSet, dofSet,
tempSet, contactSet, nFaces;
lineStr
>> group >> constraintSet >> restraintSet >> loadSet
>> dofSet >> tempSet >> contactSet >> nFaces;
is.getLine(line);
const word groupName = word::validate(line);
Info<< "For group " << group
<< " named " << groupName
<< " trying to read " << nFaces << " patch face indices."
<< endl;
labelList groupIndices(nFaces);
label groupType = -1;
nFaces = 0;
while (nFaces < groupIndices.size())
{
is.getLine(line);
IStringStream lineStr(line);
// Read one (for last face) or two entries from line.
label nRead = 2;
if (nFaces == groupIndices.size()-1)
{
nRead = 1;
}
for (label i = 0; i < nRead; i++)
{
label tag, nodeLeaf, component;
lineStr >> groupType >> tag >> nodeLeaf >> component;
groupIndices[nFaces++] = tag;
}
}
// Store
if (groupType == 8)
{
patchNames.append(groupName);
patchFaceIndices.append(groupIndices);
}
else
{
IOWarningInFunction(is)
<< "When reading patches expect entity type code 8"
<< nl << " Skipping group code " << groupType
<< endl;
}
}
patchNames.shrink();
patchFaceIndices.shrink();
}
// Read dof set (757)
void readDOFS
(
IFstream& is,
DynamicList<word>& patchNames,
DynamicList<labelList>& dofVertices
)
{
Info<< "Starting reading constraints at line " << is.lineNumber() << '.'
<< endl;
string line;
is.getLine(line);
label group;
{
IStringStream lineStr(line);
lineStr >> group;
}
is.getLine(line);
{
IStringStream lineStr(line);
word pName(lineStr);
patchNames.append(pName);
}
Info<< "For DOF set " << group
<< " named " << patchNames.last()
<< " trying to read vertex indices."
<< endl;
DynamicList<label> vertices;
while (true)
{
string line;
is.getLine(line);
if (isSeparator(line))
{
break;
}
IStringStream lineStr(line);
label pointi;
lineStr >> pointi;
vertices.append(pointi);
}
Info<< "For DOF set " << group
<< " named " << patchNames.last()
<< " read " << vertices.size() << " vertex indices." << endl;
dofVertices.append(vertices.shrink());
patchNames.shrink();
dofVertices.shrink();
}
// Returns -1 or group that all of the vertices of f are in,
label findPatch(const List<labelHashSet>& dofGroups, const face& f)
{
forAll(dofGroups, patchi)
{
if (dofGroups[patchi].found(f[0]))
{
bool allInGroup = true;
// Check rest of face
for (label fp = 1; fp < f.size(); fp++)
{
if (!dofGroups[patchi].found(f[fp]))
{
allInGroup = false;
break;
}
}
if (allInGroup)
{
return patchi;
}
}
}
return -1;
}
int main(int argc, char *argv[])
{
argList::addNote
(
"Convert I-Deas unv format to OpenFOAM"
);
argList::noParallel();
argList::addArgument(".unv file");
argList::addBoolOption
(
"dump",
"Dump boundary faces as boundaryFaces.obj (for debugging)"
);
#include "setRootCase.H"
#include "createTime.H"
const auto ideasName = args.get<fileName>(1);
IFstream inFile(ideasName);
if (!inFile.good())
{
FatalErrorInFunction
<< "Cannot open file " << ideasName
<< exit(FatalError);
}
// Switch on additional debug info
const bool verbose = false; //true;
// Unit scale factors
scalar lengthScale = 1;
scalar forceScale = 1;
scalar tempScale = 1;
scalar tempOffset = 0;
// Points
DynamicList<point> points;
// Original unv point label
DynamicList<label> unvPointID;
// Cells
DynamicList<cellShape> cellVerts;
DynamicList<label> cellMat;
DynamicList<label> cellCorrespondence;
// Boundary faces
DynamicList<label> boundaryFaceIndices;
DynamicList<face> boundaryFaces;
// Patch names and patchFace indices.
DynamicList<word> patchNames;
DynamicList<labelList> patchFaceIndices;
DynamicList<labelList> dofVertIndices;
while (inFile.good())
{
label tag = readTag(inFile);
if (tag == -1)
{
break;
}
Info<< "Processing tag:" << tag << endl;
switch (tag)
{
case 151:
readHeader(inFile);
break;
case 164:
readUnits
(
inFile,
lengthScale,
forceScale,
tempScale,
tempOffset
);
break;
case 2411:
readPoints(inFile, points, unvPointID);
break;
case 2412:
readCells
(
inFile,
cellVerts,
cellMat,
boundaryFaceIndices,
boundaryFaces,
cellCorrespondence,
unvPointID
);
break;
case 2452:
case 2467:
readSets
(
inFile,
patchNames,
patchFaceIndices
);
break;
case 757:
readDOFS
(
inFile,
patchNames,
dofVertIndices
);
break;
default:
Info<< "Skipping tag " << tag << " on line "
<< inFile.lineNumber() << endl;
skipSection(inFile);
break;
}
Info<< endl;
}
// Invert point numbering.
label maxUnvPoint = 0;
forAll(unvPointID, pointi)
{
maxUnvPoint = max(maxUnvPoint, unvPointID[pointi]);
}
labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
// Renumber vertex numbers on cells
forAll(cellVerts, celli)
{
labelList foamVerts
(
renumber
(
unvToFoam,
static_cast<labelList&>(cellVerts[celli])
)
);
if (foamVerts.found(-1))
{
FatalErrorInFunction
<< "Cell " << celli
<< " unv vertices " << cellVerts[celli]
<< " has some undefined vertices " << foamVerts
<< abort(FatalError);
}
// Bit nasty: replace vertex list.
cellVerts[celli].transfer(foamVerts);
}
// Renumber vertex numbers on boundaryFaces
forAll(boundaryFaces, bFacei)
{
labelList foamVerts(renumber(unvToFoam, boundaryFaces[bFacei]));
if (foamVerts.found(-1))
{
FatalErrorInFunction
<< "Boundary face " << bFacei
<< " unv vertices " << boundaryFaces[bFacei]
<< " has some undefined vertices " << foamVerts
<< abort(FatalError);
}
// Bit nasty: replace vertex list.
boundaryFaces[bFacei].transfer(foamVerts);
}
// Patchify = create patchFaceVerts for use in cellShape construction
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Works in one of two modes. Either has read boundaryFaces which
// just need to be sorted according to patch. Or has read point constraint
// sets (dofVertIndices).
List<faceList> patchFaceVerts;
labelList own(boundaryFaces.size(), -1);
labelList nei(boundaryFaces.size(), -1);
Pair<Map<label>> faceToCell;
{
// Can use face::symmHasher or use sorted indices instead
// - choose the latter in case UNV has anything odd
HashTable<label, face> faceToFaceID(2*boundaryFaces.size());
forAll(boundaryFaces, bfacei)
{
face sortedVerts(boundaryFaces[bfacei]);
Foam::sort(sortedVerts);
faceToFaceID.insert(sortedVerts, bfacei);
}
forAll(cellVerts, celli)
{
const cellShape& shape = cellVerts[celli];
for (const face& f : shape.faces())
{
face sortedVerts(f);
Foam::sort(sortedVerts);
const label bfacei = faceToFaceID.lookup(sortedVerts, -1);
if (bfacei != -1)
{
const int cmp = face::compare(f, boundaryFaces[bfacei]);
if (cmp == 1)
{
// Same orientation. Cell is owner.
own[bfacei] = celli;
}
else if (cmp == -1)
{
// Opposite orientation. Cell is neighbour.
nei[bfacei] = celli;
}
}
}
}
label nReverse = 0;
forAll(own, facei)
{
if (own[facei] == -1 && nei[facei] != -1)
{
// Boundary face with incorrect orientation
boundaryFaces[facei].flip();
std::swap(own[facei], nei[facei]);
nReverse++;
}
}
if (nReverse > 0)
{
Info << "Found " << nReverse << " reversed boundary faces out of "
<< boundaryFaces.size() << endl;
}
label cnt = 0;
forAll(own, facei)
{
if (own[facei] != -1 && nei[facei] != -1)
{
faceToCell[1].insert(facei, own[facei]);
faceToCell[0].insert(facei, nei[facei]);
cnt++;
}
}
if (cnt > 0)
{
Info << "Of " << boundaryFaces.size() << " so-called"
<< " boundary faces " << cnt << " belong to two cells "
<< "and are therefore internal" << endl;
}
}
HashTable<labelList> cellZones;
HashTable<labelList> faceZones;
List<bool> isAPatch(patchNames.size(),true);
if (dofVertIndices.size())
{
// Use the vertex constraints to patch. Is of course bit dodgy since
// face goes on patch if all its vertices are on a constraint.
// Note: very inefficient since goes through all faces (including
// internal ones) twice. Should do a construct without patches
// and then repatchify.
Info<< "Using " << dofVertIndices.size()
<< " DOF sets to detect boundary faces."<< endl;
// Renumber vertex numbers on constraints
forAll(dofVertIndices, patchi)
{
inplaceRenumber(unvToFoam, dofVertIndices[patchi]);
}
// Build labelHashSet of points per dofGroup/patch
List<labelHashSet> dofGroups(dofVertIndices.size());
forAll(dofVertIndices, patchi)
{
const labelList& foamVerts = dofVertIndices[patchi];
dofGroups[patchi].insert(foamVerts);
}
List<DynamicList<face>> dynPatchFaces(dofVertIndices.size());
forAll(cellVerts, celli)
{
const cellShape& shape = cellVerts[celli];
for (const face& f : shape.faces())
{
label patchi = findPatch(dofGroups, f);
if (patchi != -1)
{
dynPatchFaces[patchi].append(f);
}
}
}
// Transfer
patchFaceVerts.setSize(dynPatchFaces.size());
forAll(dynPatchFaces, patchi)
{
patchFaceVerts[patchi].transfer(dynPatchFaces[patchi]);
}
}
else
{
// Use the boundary faces.
// Construct the patch faces by sorting the boundaryFaces according to
// patch.
patchFaceVerts.setSize(patchFaceIndices.size());
Info<< "Sorting boundary faces according to group (patch)" << endl;
// make sure that no face is used twice on the boundary
// (possible for boundary-only faceZones)
labelHashSet alreadyOnBoundary;
// Construct map from boundaryFaceIndices
Map<label> boundaryFaceToIndex(invertToMap(boundaryFaceIndices));
forAll(patchFaceVerts, patchi)
{
Info << patchi << ": " << patchNames[patchi] << " is " << flush;
faceList& patchFaces = patchFaceVerts[patchi];
const labelList& faceIndices = patchFaceIndices[patchi];
patchFaces.setSize(faceIndices.size());
bool duplicateFaces = false;
label cnt = 0;
forAll(patchFaces, i)
{
if (boundaryFaceToIndex.found(faceIndices[i]))
{
label bFacei = boundaryFaceToIndex[faceIndices[i]];
if (own[bFacei] != -1 && nei[bFacei] == -1)
{
patchFaces[cnt] = boundaryFaces[bFacei];
cnt++;
if (alreadyOnBoundary.found(bFacei))
{
duplicateFaces = true;
}
}
}
}
if (cnt != patchFaces.size() || duplicateFaces)
{
isAPatch[patchi] = false;
if (verbose)
{
if (cnt != patchFaces.size())
{
WarningInFunction
<< "For patch " << patchi << " there were "
<< patchFaces.size()-cnt
<< " faces not used because they seem"
<< " to be internal. "
<< "This seems to be a face or a cell-zone"
<< endl;
}
else
{
WarningInFunction
<< "Patch "
<< patchi << " has faces that are already "
<< " in use on other boundary-patches,"
<< " Assuming faceZoneset." << endl;
}
}
patchFaces.clear(); // Assume that this is no patch at all
if (cellCorrespondence[faceIndices[0]] >= 0)
{
Info << "cellZone" << endl;
labelList theCells(faceIndices.size());
forAll(faceIndices, i)
{
if (cellCorrespondence[faceIndices[0]] < 0)
{
FatalErrorInFunction
<< "The face index " << faceIndices[i]
<< " was not found amongst the cells."
<< " This kills the theory that "
<< patchNames[patchi] << " is a cell zone"
<< endl
<< abort(FatalError);
}
theCells[i] = cellCorrespondence[faceIndices[i]];
}
cellZones.insert(patchNames[patchi], theCells);
}
else
{
Info << "faceZone" << endl;
labelList theFaces(faceIndices.size());
forAll(faceIndices, i)
{
theFaces[i] = boundaryFaceToIndex[faceIndices[i]];
}
faceZones.insert(patchNames[patchi],theFaces);
}
}
else
{
Info << "patch" << endl;
forAll(patchFaces, i)
{
label bFacei = boundaryFaceToIndex[faceIndices[i]];
alreadyOnBoundary.insert(bFacei);
}
}
}
}
pointField polyPoints;
polyPoints.transfer(points);
// Length scaling factor
polyPoints /= lengthScale;
// For debugging: dump boundary faces as OBJ surface mesh
if (args.found("dump"))
{
Info<< "Writing boundary faces to OBJ file boundaryFaces.obj"
<< nl << endl;
// Create globally numbered surface
meshedSurface rawSurface(polyPoints, boundaryFaces);
// Write locally numbered surface
meshedSurface
(
rawSurface.localPoints(),
rawSurface.localFaces()
).write(runTime.path()/"boundaryFaces.obj");
}
Info<< "\nConstructing mesh with non-default patches of size:" << nl;
DynamicList<word> usedPatchNames;
DynamicList<faceList> usedPatchFaceVerts;
forAll(patchNames, patchi)
{
if (isAPatch[patchi])
{
Info<< " " << patchNames[patchi] << '\t'
<< patchFaceVerts[patchi].size() << nl;
usedPatchNames.append(patchNames[patchi]);
usedPatchFaceVerts.append(patchFaceVerts[patchi]);
}
}
usedPatchNames.shrink();
usedPatchFaceVerts.shrink();
Info<< endl;
// Construct mesh
polyMesh mesh
(
IOobject
(
polyMesh::defaultRegion,
runTime.constant(),
runTime
),
std::move(polyPoints),
cellVerts,
usedPatchFaceVerts, // boundaryFaces,
usedPatchNames, // boundaryPatchNames,
wordList(patchNames.size(), polyPatch::typeName), // boundaryPatchTypes,
"defaultFaces", // defaultFacesName
polyPatch::typeName, // defaultFacesType,
wordList() // boundaryPatchPhysicalTypes
);
// Remove files now, to ensure all mesh files written are consistent.
mesh.removeFiles();
if (faceZones.size() || cellZones.size())
{
Info << "Adding cell and face zones" << endl;
List<pointZone*> pZones(0);
List<faceZone*> fZones(faceZones.size());
List<cellZone*> cZones(cellZones.size());
if (cellZones.size())
{
forAll(cellZones.toc(), cnt)
{
word name = cellZones.toc()[cnt];
Info<< " Cell Zone " << name << " " << tab
<< cellZones[name].size() << endl;
cZones[cnt] = new cellZone
(
name,
cellZones[name],
cnt,
mesh.cellZones()
);
}
}
if (faceZones.size())
{
const labelList& own = mesh.faceOwner();
const labelList& nei = mesh.faceNeighbour();
const pointField& centers = mesh.faceCentres();
const pointField& points = mesh.points();
forAll(faceZones.toc(), cnt)
{
word name = faceZones.toc()[cnt];
const labelList& oldIndizes = faceZones[name];
labelList indizes(oldIndizes.size());
Info<< " Face Zone " << name << " " << tab
<< oldIndizes.size() << endl;
forAll(indizes, i)
{
const label old = oldIndizes[i];
label noveau = -1;
label c1 = faceToCell[0].lookup(old, -1);
label c2 = faceToCell[1].lookup(old, -1);
if (c1 < c2)
{
std::swap(c1, c2);
}
if (c2 == -1)
{
// Boundary face is part of the faceZone
forAll(own, j)
{
if (own[j] == c1)
{
const face& f = boundaryFaces[old];
if (mag(centers[j]- f.centre(points)) < SMALL)
{
noveau = j;
break;
}
}
}
}
else
{
forAll(nei, j)
{
if
(
(c1 == own[j] && c2 == nei[j])
|| (c2 == own[j] && c1 == nei[j])
)
{
noveau = j;
break;
}
}
}
assert(noveau > -1);
indizes[i] = noveau;
}
fZones[cnt] = new faceZone
(
faceZones.toc()[cnt],
indizes,
false, // none are flipped
cnt,
mesh.faceZones()
);
}
}
mesh.addZones(pZones, fZones, cZones);
Info << endl;
}
// More precision (for points data)
IOstream::minPrecision(10);
mesh.write();
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //