openfoam/applications/utilities/mesh/generation/extrude/extrudeMesh/extrudeMesh.C
Mark Olesen e5006a62d7 ENH: use simpler boundBox handling
- use default initialize boundBox instead of invertedBox
- reset() instead of assigning from invertedBox
- extend (three parameter version) and grow method
- inflate(Random) instead of extend + re-assigning
2022-11-24 12:21:01 +00:00

1148 lines
31 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2022 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
extrudeMesh
Group
grpMeshGenerationUtilities
Description
Extrude mesh from existing patch (by default outwards facing normals;
optional flips faces) or from patch read from file.
Note: Merges close points so be careful.
Type of extrusion prescribed by run-time selectable model.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "polyTopoChange.H"
#include "polyTopoChanger.H"
#include "edgeCollapser.H"
#include "perfectInterface.H"
#include "addPatchCellLayer.H"
#include "fvMesh.H"
#include "MeshedSurfaces.H"
#include "globalIndex.H"
#include "cellSet.H"
#include "fvMeshTools.H"
#include "extrudedMesh.H"
#include "extrudeModel.H"
#include "wedge.H"
#include "wedgePolyPatch.H"
#include "planeExtrusion.H"
#include "emptyPolyPatch.H"
#include "processorPolyPatch.H"
#include "processorMeshes.H"
#include "hexRef8Data.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
enum ExtrudeMode
{
MESH,
PATCH,
SURFACE
};
static const Enum<ExtrudeMode> ExtrudeModeNames
{
{ ExtrudeMode::MESH, "mesh" },
{ ExtrudeMode::PATCH, "patch" },
{ ExtrudeMode::SURFACE, "surface" },
};
label findPatchID(const polyBoundaryMesh& patches, const word& name)
{
const label patchID = patches.findPatchID(name);
if (patchID == -1)
{
FatalErrorInFunction
<< "Cannot find patch " << name
<< " in the source mesh.\n"
<< "Valid patch names are " << patches.names()
<< exit(FatalError);
}
return patchID;
}
labelList patchFaces(const polyBoundaryMesh& patches, const wordList& names)
{
label n = 0;
forAll(names, i)
{
const polyPatch& pp = patches[findPatchID(patches, names[i])];
n += pp.size();
}
labelList faceLabels(n);
n = 0;
forAll(names, i)
{
const polyPatch& pp = patches[findPatchID(patches, names[i])];
forAll(pp, j)
{
faceLabels[n++] = pp.start()+j;
}
}
return faceLabels;
}
void zoneFaces
(
const faceZoneMesh& fzs,
const wordList& names,
labelList& faceLabels,
bitSet& faceFlip
)
{
label n = 0;
forAll(names, i)
{
const auto& pp = fzs[fzs.findZoneID(names[i])];
n += pp.size();
}
faceLabels.setSize(n);
faceFlip.setSize(n);
n = 0;
forAll(names, i)
{
const auto& pp = fzs[fzs.findZoneID(names[i])];
const boolList& ppFlip = pp.flipMap();
forAll(pp, i)
{
faceLabels[n] = pp[i];
faceFlip[n] = ppFlip[i];
n++;
}
}
}
void updateFaceLabels(const mapPolyMesh& map, labelList& faceLabels)
{
const labelList& reverseMap = map.reverseFaceMap();
labelList newFaceLabels(faceLabels.size());
label newI = 0;
forAll(faceLabels, i)
{
label oldFacei = faceLabels[i];
if (reverseMap[oldFacei] >= 0)
{
newFaceLabels[newI++] = reverseMap[oldFacei];
}
}
newFaceLabels.setSize(newI);
faceLabels.transfer(newFaceLabels);
}
void updateCellSet(const mapPolyMesh& map, labelHashSet& cellLabels)
{
const labelList& reverseMap = map.reverseCellMap();
labelHashSet newCellLabels(2*cellLabels.size());
forAll(cellLabels, i)
{
label oldCelli = cellLabels[i];
if (reverseMap[oldCelli] >= 0)
{
newCellLabels.insert(reverseMap[oldCelli]);
}
}
cellLabels.transfer(newCellLabels);
}
template<class PatchType>
void changeFrontBackPatches
(
polyMesh& mesh,
const word& frontPatchName,
const word& backPatchName
)
{
const polyBoundaryMesh& patches = mesh.boundaryMesh();
label frontPatchi = findPatchID(patches, frontPatchName);
label backPatchi = findPatchID(patches, backPatchName);
DynamicList<polyPatch*> newPatches(patches.size());
forAll(patches, patchi)
{
const polyPatch& pp(patches[patchi]);
if (patchi == frontPatchi || patchi == backPatchi)
{
newPatches.append
(
new PatchType
(
pp.name(),
pp.size(),
pp.start(),
pp.index(),
mesh.boundaryMesh(),
PatchType::typeName
)
);
}
else
{
newPatches.append(pp.clone(mesh.boundaryMesh()).ptr());
}
}
// Edit patches
mesh.removeBoundary();
mesh.addPatches(newPatches, true);
}
int main(int argc, char *argv[])
{
argList::addNote
(
"Extrude mesh from existing patch."
);
#include "addRegionOption.H"
argList::addOption("dict", "file", "Alternative extrudeMeshDict");
#include "setRootCase.H"
#include "createTimeExtruded.H"
// Get optional regionName
word regionName(polyMesh::defaultRegion);
if (args.readIfPresent("region", regionName))
{
Info<< "Create mesh " << regionName << " for time = "
<< runTimeExtruded.timeName() << nl << endl;
}
else
{
Info<< "Create mesh for time = "
<< runTimeExtruded.timeName() << nl << endl;
}
const IOdictionary dict
(
IOobject::selectIO
(
IOobject
(
"extrudeMeshDict",
runTimeExtruded.system(),
runTimeExtruded,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
),
args.getOrDefault<fileName>("dict", "")
)
);
// Point generator
autoPtr<extrudeModel> model(extrudeModel::New(dict));
// Whether to flip normals
const bool flipNormals(dict.get<bool>("flipNormals"));
// What to extrude
const ExtrudeMode mode = ExtrudeModeNames.get("constructFrom", dict);
// Any merging of small edges
const scalar mergeTol(dict.getOrDefault<scalar>("mergeTol", 1e-4));
Info<< "Extruding from " << ExtrudeModeNames[mode]
<< " using model " << model().type() << endl;
if (flipNormals)
{
Info<< "Flipping normals before extruding" << endl;
}
if (mergeTol > 0)
{
Info<< "Collapsing edges < " << mergeTol << " of bounding box" << endl;
}
else
{
Info<< "Not collapsing any edges after extrusion" << endl;
}
Info<< endl;
// Generated mesh (one of either)
autoPtr<fvMesh> meshFromMesh;
autoPtr<polyMesh> meshFromSurface;
// Faces on front and back for stitching (in case of mergeFaces)
word frontPatchName;
labelList frontPatchFaces;
word backPatchName;
labelList backPatchFaces;
// Optional added cells (get written to cellSet)
labelHashSet addedCellsSet;
// Optional refinement data
autoPtr<hexRef8Data> refDataPtr;
if (mode == PATCH || mode == MESH)
{
if (flipNormals && mode == MESH)
{
FatalErrorInFunction
<< "Flipping normals not supported for extrusions from mesh."
<< exit(FatalError);
}
fileName sourceCasePath(dict.get<fileName>("sourceCase").expand());
fileName sourceRootDir = sourceCasePath.path();
fileName sourceCaseDir = sourceCasePath.name();
if (Pstream::parRun())
{
sourceCaseDir =
sourceCaseDir/("processor" + Foam::name(Pstream::myProcNo()));
}
wordList sourcePatches;
wordList sourceFaceZones;
if
(
dict.readIfPresent
(
"sourcePatches",
sourcePatches,
keyType::LITERAL
)
)
{
if (sourcePatches.size() == 1)
{
frontPatchName = sourcePatches[0];
}
Info<< "Extruding patches " << sourcePatches
<< " on mesh " << sourceCasePath << nl
<< endl;
}
else
{
dict.readEntry("sourceFaceZones", sourceFaceZones);
Info<< "Extruding faceZones " << sourceFaceZones
<< " on mesh " << sourceCasePath << nl
<< endl;
}
Time runTime
(
Time::controlDictName,
sourceRootDir,
sourceCaseDir
);
#include "createNamedMesh.H"
const polyBoundaryMesh& patches = mesh.boundaryMesh();
// Extrusion engine. Either adding to existing mesh or
// creating separate mesh.
addPatchCellLayer layerExtrude(mesh, (mode == MESH));
labelList meshFaces;
bitSet faceFlips;
if (sourceFaceZones.size())
{
zoneFaces(mesh.faceZones(), sourceFaceZones, meshFaces, faceFlips);
}
else
{
meshFaces = patchFaces(patches, sourcePatches);
faceFlips.setSize(meshFaces.size());
}
if (mode == PATCH && flipNormals)
{
// Cheat. Flip patch faces in mesh. This invalidates the
// mesh (open cells) but does produce the correct extrusion.
polyTopoChange meshMod(mesh);
forAll(meshFaces, i)
{
label meshFacei = meshFaces[i];
label patchi = patches.whichPatch(meshFacei);
label own = mesh.faceOwner()[meshFacei];
label nei = -1;
if (patchi == -1)
{
nei = mesh.faceNeighbour()[meshFacei];
}
label zoneI = mesh.faceZones().whichZone(meshFacei);
bool zoneFlip = false;
if (zoneI != -1)
{
label index = mesh.faceZones()[zoneI].whichFace(meshFacei);
zoneFlip = mesh.faceZones()[zoneI].flipMap()[index];
}
meshMod.modifyFace
(
mesh.faces()[meshFacei].reverseFace(), // modified face
meshFacei, // label of face
own, // owner
nei, // neighbour
true, // face flip
patchi, // patch for face
zoneI, // zone for face
zoneFlip // face flip in zone
);
}
// Change the mesh. No inflation.
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
// Update fields
mesh.updateMesh(map());
// Move mesh (since morphing does not do this)
if (map().hasMotionPoints())
{
mesh.movePoints(map().preMotionPoints());
}
}
indirectPrimitivePatch extrudePatch
(
IndirectList<face>
(
mesh.faces(),
meshFaces
),
mesh.points()
);
// Determine extrudePatch normal
pointField extrudePatchPointNormals
(
PatchTools::pointNormals(mesh, extrudePatch, faceFlips)
);
// Precalculate mesh edges for pp.edges.
const labelList meshEdges
(
extrudePatch.meshEdges
(
mesh.edges(),
mesh.pointEdges()
)
);
// Global face indices engine
const globalIndex globalFaces(mesh.nFaces());
// Determine extrudePatch.edgeFaces in global numbering (so across
// coupled patches)
labelListList edgeGlobalFaces
(
addPatchCellLayer::globalEdgeFaces
(
mesh,
globalFaces,
extrudePatch
)
);
// Determine what patches boundary edges need to get extruded into.
// This might actually cause edge-connected processors to become
// face-connected so might need to introduce new processor boundaries.
// Calculates:
// - per pp.edge the patch to extrude into
// - any additional processor boundaries (patchToNbrProc = map from
// new patchID to neighbour processor)
// - number of new patches (nPatches)
labelList edgePatchID;
labelList edgeZoneID;
boolList edgeFlip;
labelList inflateFaceID;
label nPatches;
Map<label> nbrProcToPatch;
Map<label> patchToNbrProc;
addPatchCellLayer::calcExtrudeInfo
(
true, // for internal edges get zone info from any face
mesh,
globalFaces,
edgeGlobalFaces,
extrudePatch,
edgePatchID,
nPatches,
nbrProcToPatch,
patchToNbrProc,
edgeZoneID,
edgeFlip,
inflateFaceID
);
// Add any patches.
const label nAdded = returnReduce
(
nPatches - mesh.boundaryMesh().size(),
sumOp<label>()
);
Info<< "Adding overall " << nAdded << " processor patches." << endl;
if (nAdded > 0)
{
DynamicList<polyPatch*> newPatches(nPatches);
forAll(mesh.boundaryMesh(), patchi)
{
newPatches.append
(
mesh.boundaryMesh()[patchi].clone
(
mesh.boundaryMesh()
).ptr()
);
}
for
(
label patchi = mesh.boundaryMesh().size();
patchi < nPatches;
patchi++
)
{
label nbrProci = patchToNbrProc[patchi];
Pout<< "Adding patch " << patchi
<< " between " << Pstream::myProcNo()
<< " and " << nbrProci
<< endl;
newPatches.append
(
new processorPolyPatch
(
0, // size
mesh.nFaces(), // start
patchi, // index
mesh.boundaryMesh(),// polyBoundaryMesh
Pstream::myProcNo(),// myProcNo
nbrProci // neighbProcNo
)
);
}
// Add patches. Do no parallel updates.
mesh.removeFvBoundary();
mesh.addFvPatches(newPatches, true);
}
// Only used for addPatchCellLayer into new mesh
labelList exposedPatchID;
if (mode == PATCH)
{
dict.readEntry("exposedPatchName", backPatchName);
exposedPatchID.setSize
(
extrudePatch.size(),
findPatchID(patches, backPatchName)
);
}
// Determine points and extrusion
pointField layer0Points(extrudePatch.nPoints());
pointField displacement(extrudePatch.nPoints());
forAll(displacement, pointi)
{
const vector& patchNormal = extrudePatchPointNormals[pointi];
// layer0 point
layer0Points[pointi] = model()
(
extrudePatch.localPoints()[pointi],
patchNormal,
0
);
// layerN point
point extrudePt = model()
(
extrudePatch.localPoints()[pointi],
patchNormal,
model().nLayers()
);
displacement[pointi] = extrudePt - layer0Points[pointi];
}
// Check if wedge (has layer0 different from original patch points)
// If so move the mesh to starting position.
if (gMax(mag(layer0Points-extrudePatch.localPoints())) > SMALL)
{
Info<< "Moving mesh to layer0 points since differ from original"
<< " points - this can happen for wedge extrusions." << nl
<< endl;
pointField newPoints(mesh.points());
forAll(extrudePatch.meshPoints(), i)
{
newPoints[extrudePatch.meshPoints()[i]] = layer0Points[i];
}
mesh.movePoints(newPoints);
}
// Layers per face
labelList nFaceLayers(extrudePatch.size(), model().nLayers());
// Layers per point
labelList nPointLayers(extrudePatch.nPoints(), model().nLayers());
// Displacement for first layer
vectorField firstLayerDisp(displacement*model().sumThickness(1));
// Expansion ratio not used.
scalarField ratio(extrudePatch.nPoints(), 1.0);
// Load any refinement data
if (mode == MESH)
{
// Tricky: register hexRef8 onto the database
// since the mesh does not yet exist. It should not be registered
// onto the input mesh.
refDataPtr.reset
(
new hexRef8Data
(
IOobject
(
"dummy",
mesh.facesInstance(),
polyMesh::meshSubDir,
runTimeExtruded, //mesh,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
false
)
)
);
}
// Topo change container. Either copy an existing mesh or start
// with empty storage (number of patches only needed for checking)
autoPtr<polyTopoChange> meshMod
(
(
mode == MESH
? new polyTopoChange(mesh)
: new polyTopoChange(patches.size())
)
);
layerExtrude.setRefinement
(
globalFaces,
edgeGlobalFaces,
ratio, // expansion ratio
extrudePatch, // patch faces to extrude
faceFlips, // side to extrude (for internal/coupled faces)
edgePatchID, // if boundary edge: patch for extruded face
edgeZoneID, // optional zone for extruded face
edgeFlip,
inflateFaceID, // mesh face that zone/patch info is from
exposedPatchID, // if new mesh: patches for exposed faces
nFaceLayers,
nPointLayers,
firstLayerDisp,
meshMod()
);
// Reset points according to extrusion model
forAll(layerExtrude.addedPoints(), pointi)
{
const labelList& pPoints = layerExtrude.addedPoints()[pointi];
forAll(pPoints, pPointi)
{
label meshPointi = pPoints[pPointi];
point modelPt
(
model()
(
extrudePatch.localPoints()[pointi],
extrudePatchPointNormals[pointi],
pPointi+1 // layer
)
);
const_cast<DynamicList<point>&>
(
meshMod().points()
)[meshPointi] = modelPt;
}
}
// Store faces on front and exposed patch (if mode=patch there are
// only added faces so cannot used map to old faces)
const labelListList& layerFaces = layerExtrude.layerFaces();
backPatchFaces.setSize(layerFaces.size());
frontPatchFaces.setSize(layerFaces.size());
forAll(backPatchFaces, patchFacei)
{
backPatchFaces[patchFacei] = layerFaces[patchFacei].first();
frontPatchFaces[patchFacei] = layerFaces[patchFacei].last();
}
// Create dummy fvSchemes, fvSolution
fvMeshTools::createDummyFvMeshFiles
(
mesh,
polyMesh::regionName(regionName),
true
);
// Create actual mesh from polyTopoChange container
autoPtr<mapPolyMesh> map = meshMod().makeMesh
(
meshFromMesh,
IOobject
(
regionName,
runTimeExtruded.constant(),
runTimeExtruded,
IOobject::READ_IF_PRESENT, // Read fv* if present
IOobject::AUTO_WRITE,
false
),
mesh
);
layerExtrude.updateMesh
(
map(),
identity(extrudePatch.size()),
identity(extrudePatch.nPoints())
);
// Calculate face labels for front and back.
frontPatchFaces = renumber
(
map().reverseFaceMap(),
frontPatchFaces
);
backPatchFaces = renumber
(
map().reverseFaceMap(),
backPatchFaces
);
// Update
if (refDataPtr)
{
refDataPtr->updateMesh(map());
}
// Store added cells
if (mode == MESH)
{
const labelListList addedCells
(
layerExtrude.addedCells
(
*meshFromMesh,
layerExtrude.layerFaces()
)
);
forAll(addedCells, facei)
{
const labelList& aCells = addedCells[facei];
addedCellsSet.insert(aCells);
}
}
}
else
{
// Read from surface
fileName surfName(dict.get<fileName>("surface").expand());
Info<< "Extruding surfaceMesh read from file " << surfName << nl
<< endl;
MeshedSurface<face> fMesh(surfName);
if (flipNormals)
{
Info<< "Flipping faces." << nl << endl;
faceList& faces = const_cast<faceList&>(fMesh.surfFaces());
forAll(faces, i)
{
faces[i] = fMesh[i].reverseFace();
}
}
Info<< "Extruding surface with :" << nl
<< " points : " << fMesh.points().size() << nl
<< " faces : " << fMesh.size() << nl
<< " normals[0] : " << fMesh.faceNormals()[0]
<< nl
<< endl;
meshFromSurface.reset
(
new extrudedMesh
(
IOobject
(
extrudedMesh::defaultRegion,
runTimeExtruded.constant(),
runTimeExtruded
),
fMesh,
model()
)
);
// Get the faces on front and back
frontPatchName = "originalPatch";
frontPatchFaces = patchFaces
(
meshFromSurface().boundaryMesh(),
wordList(1, frontPatchName)
);
backPatchName = "otherSide";
backPatchFaces = patchFaces
(
meshFromSurface().boundaryMesh(),
wordList(1, backPatchName)
);
}
polyMesh& mesh =
(
meshFromMesh
? *meshFromMesh
: *meshFromSurface
);
const boundBox& bb = mesh.bounds();
const scalar mergeDim = mergeTol * bb.minDim();
Info<< "Mesh bounding box : " << bb << nl
<< " with span : " << bb.span() << nl
<< "Merge distance : " << mergeDim << nl
<< endl;
// Collapse edges
// ~~~~~~~~~~~~~~
if (mergeDim > 0)
{
Info<< "Collapsing edges < " << mergeDim << " ..." << nl << endl;
// Edge collapsing engine
edgeCollapser collapser(mesh);
const edgeList& edges = mesh.edges();
const pointField& points = mesh.points();
bitSet collapseEdge(mesh.nEdges());
Map<point> collapsePointToLocation(mesh.nPoints());
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
scalar d = e.mag(points);
if (d < mergeDim)
{
Info<< "Merging edge " << e << " since length " << d
<< " << " << mergeDim << nl;
collapseEdge.set(edgeI);
collapsePointToLocation.set(e[1], points[e[0]]);
}
}
List<pointEdgeCollapse> allPointInfo;
const globalIndex globalPoints(mesh.nPoints());
labelList pointPriority(mesh.nPoints(), Zero);
collapser.consistentCollapse
(
globalPoints,
pointPriority,
collapsePointToLocation,
collapseEdge,
allPointInfo
);
// Topo change container
polyTopoChange meshMod(mesh);
// Put all modifications into meshMod
bool anyChange = collapser.setRefinement(allPointInfo, meshMod);
if (returnReduceOr(anyChange))
{
// Construct new mesh from polyTopoChange.
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
// Update fields
mesh.updateMesh(map());
// Update stored data
updateFaceLabels(map(), frontPatchFaces);
updateFaceLabels(map(), backPatchFaces);
updateCellSet(map(), addedCellsSet);
if (refDataPtr)
{
refDataPtr->updateMesh(map());
}
// Move mesh (if inflation used)
if (map().hasMotionPoints())
{
mesh.movePoints(map().preMotionPoints());
}
}
}
// Change the front and back patch types as required
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
word frontBackType(word::null);
if (isType<extrudeModels::wedge>(model()))
{
changeFrontBackPatches<wedgePolyPatch>
(
mesh,
frontPatchName,
backPatchName
);
}
else if (isType<extrudeModels::plane>(model()))
{
changeFrontBackPatches<emptyPolyPatch>
(
mesh,
frontPatchName,
backPatchName
);
}
// Merging front and back patch faces
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (dict.get<bool>("mergeFaces"))
{
if (mode == MESH)
{
FatalErrorInFunction
<< "Cannot stitch front and back of extrusion since"
<< " in 'mesh' mode (extrusion appended to mesh)."
<< exit(FatalError);
}
Info<< "Assuming full 360 degree axisymmetric case;"
<< " stitching faces on patches "
<< frontPatchName << " and "
<< backPatchName << " together ..." << nl << endl;
if (frontPatchFaces.size() != backPatchFaces.size())
{
FatalErrorInFunction
<< "Differing number of faces on front ("
<< frontPatchFaces.size() << ") and back ("
<< backPatchFaces.size() << ")"
<< exit(FatalError);
}
polyTopoChanger stitcher(mesh);
stitcher.setSize(1);
const word cutZoneName("originalCutFaceZone");
List<faceZone*> fz
(
1,
new faceZone
(
cutZoneName,
frontPatchFaces,
false, // none are flipped
0,
mesh.faceZones()
)
);
mesh.addZones(List<pointZone*>(0), fz, List<cellZone*>(0));
// Add the perfect interface mesh modifier
perfectInterface perfectStitcher
(
"couple",
0,
stitcher,
cutZoneName,
word::null, // dummy patch name
word::null // dummy patch name
);
// Topo change container
polyTopoChange meshMod(mesh);
perfectStitcher.setRefinement
(
indirectPrimitivePatch
(
IndirectList<face>
(
mesh.faces(),
frontPatchFaces
),
mesh.points()
),
indirectPrimitivePatch
(
IndirectList<face>
(
mesh.faces(),
backPatchFaces
),
mesh.points()
),
meshMod
);
// Construct new mesh from polyTopoChange.
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
// Update fields
mesh.updateMesh(map());
// Update local data
updateCellSet(map(), addedCellsSet);
if (refDataPtr)
{
refDataPtr->updateMesh(map());
}
// Move mesh (if inflation used)
if (map().hasMotionPoints())
{
mesh.movePoints(map().preMotionPoints());
}
}
mesh.setInstance(runTimeExtruded.constant());
Info<< "Writing mesh to " << mesh.objectPath() << nl << endl;
if (!mesh.write())
{
FatalErrorInFunction
<< exit(FatalError);
}
// Remove any left-over files
processorMeshes::removeFiles(mesh);
// Need writing cellSet
if (returnReduceOr(addedCellsSet.size()))
{
cellSet addedCells(mesh, "addedCells", addedCellsSet);
Info<< "Writing added cells to cellSet " << addedCells.name()
<< nl << endl;
if (!addedCells.write())
{
FatalErrorInFunction
<< addedCells.name()
<< exit(FatalError);
}
}
if (refDataPtr)
{
refDataPtr->write();
}
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //