Files
openfoam/src/dynamicMesh/polyMeshAdder/polyMeshAdder.C
2009-03-12 19:25:21 +00:00

2096 lines
52 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
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 2 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, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\*----------------------------------------------------------------------------*/
#include "polyMeshAdder.H"
#include "mapAddedPolyMesh.H"
#include "IOobject.H"
#include "faceCoupleInfo.H"
#include "processorPolyPatch.H"
#include "SortableList.H"
#include "Time.H"
#include "globalMeshData.H"
#include "mergePoints.H"
#include "polyModifyFace.H"
#include "polyRemovePoint.H"
#include "polyTopoChange.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
//- Append all mapped elements of a list to a DynamicList
void Foam::polyMeshAdder::append
(
const labelList& map,
const labelList& lst,
DynamicList<label>& dynLst
)
{
dynLst.setCapacity(dynLst.size() + lst.size());
forAll(lst, i)
{
label newElem = map[lst[i]];
if (newElem != -1)
{
dynLst.append(newElem);
}
}
}
//- Append all mapped elements of a list to a DynamicList
void Foam::polyMeshAdder::append
(
const labelList& map,
const labelList& lst,
const SortableList<label>& sortedLst,
DynamicList<label>& dynLst
)
{
dynLst.setSize(dynLst.size() + lst.size());
forAll(lst, i)
{
label newElem = map[lst[i]];
if (newElem != -1 && findSortedIndex(sortedLst, newElem) == -1)
{
dynLst.append(newElem);
}
}
}
// Get index of patch in new set of patchnames/types
Foam::label Foam::polyMeshAdder::patchIndex
(
const polyPatch& p,
DynamicList<word>& allPatchNames,
DynamicList<word>& allPatchTypes
)
{
// Find the patch name on the list. If the patch is already there
// and patch types match, return index
const word& pType = p.type();
const word& pName = p.name();
label patchI = findIndex(allPatchNames, pName);
if (patchI == -1)
{
// Patch not found. Append to the list
allPatchNames.append(pName);
allPatchTypes.append(pType);
return allPatchNames.size() - 1;
}
else if (allPatchTypes[patchI] == pType)
{
// Found name and types match
return patchI;
}
else
{
// Found the name, but type is different
// Duplicate name is not allowed. Create a composite name from the
// patch name and case name
const word& caseName = p.boundaryMesh().mesh().time().caseName();
allPatchNames.append(pName + "_" + caseName);
allPatchTypes.append(pType);
Pout<< "label patchIndex(const polyPatch& p) : "
<< "Patch " << p.index() << " named "
<< pName << " in mesh " << caseName
<< " already exists, but patch types"
<< " do not match.\nCreating a composite name as "
<< allPatchNames[allPatchNames.size() - 1] << endl;
return allPatchNames.size() - 1;
}
}
// Get index of zone in new set of zone names
Foam::label Foam::polyMeshAdder::zoneIndex
(
const word& curName,
DynamicList<word>& names
)
{
label zoneI = findIndex(names, curName);
if (zoneI != -1)
{
return zoneI;
}
else
{
// Not found. Add new name to the list
names.append(curName);
return names.size() - 1;
}
}
void Foam::polyMeshAdder::mergePatchNames
(
const polyBoundaryMesh& patches0,
const polyBoundaryMesh& patches1,
DynamicList<word>& allPatchNames,
DynamicList<word>& allPatchTypes,
labelList& from1ToAllPatches,
labelList& fromAllTo1Patches
)
{
// Insert the mesh0 patches and zones
append(patches0.names(), allPatchNames);
append(patches0.types(), allPatchTypes);
// Patches
// ~~~~~~~
// Patches from 0 are taken over as is; those from 1 get either merged
// (if they share name and type) or appended.
// Empty patches are filtered out much much later on.
// Add mesh1 patches and build map both ways.
from1ToAllPatches.setSize(patches1.size());
forAll(patches1, patchI)
{
from1ToAllPatches[patchI] = patchIndex
(
patches1[patchI],
allPatchNames,
allPatchTypes
);
}
allPatchTypes.shrink();
allPatchNames.shrink();
// Invert 1 to all patch map
fromAllTo1Patches.setSize(allPatchNames.size());
fromAllTo1Patches = -1;
forAll(from1ToAllPatches, i)
{
fromAllTo1Patches[from1ToAllPatches[i]] = i;
}
}
Foam::labelList Foam::polyMeshAdder::getPatchStarts
(
const polyBoundaryMesh& patches
)
{
labelList patchStarts(patches.size());
forAll(patches, patchI)
{
patchStarts[patchI] = patches[patchI].start();
}
return patchStarts;
}
Foam::labelList Foam::polyMeshAdder::getPatchSizes
(
const polyBoundaryMesh& patches
)
{
labelList patchSizes(patches.size());
forAll(patches, patchI)
{
patchSizes[patchI] = patches[patchI].size();
}
return patchSizes;
}
Foam::List<Foam::polyPatch*> Foam::polyMeshAdder::combinePatches
(
const polyMesh& mesh0,
const polyMesh& mesh1,
const polyBoundaryMesh& allBoundaryMesh,
const label nAllPatches,
const labelList& fromAllTo1Patches,
const label nInternalFaces,
const labelList& nFaces,
labelList& from0ToAllPatches,
labelList& from1ToAllPatches
)
{
const polyBoundaryMesh& patches0 = mesh0.boundaryMesh();
const polyBoundaryMesh& patches1 = mesh1.boundaryMesh();
// Compacted new patch list.
DynamicList<polyPatch*> allPatches(nAllPatches);
// Map from 0 to all patches (since gets compacted)
from0ToAllPatches.setSize(patches0.size());
from0ToAllPatches = -1;
label startFaceI = nInternalFaces;
// Copy patches0 with new sizes. First patches always come from
// mesh0 and will always be present.
for (label patchI = 0; patchI < patches0.size(); patchI++)
{
// Originates from mesh0. Clone with new size & filter out empty
// patch.
label filteredPatchI;
if (nFaces[patchI] == 0 && isA<processorPolyPatch>(patches0[patchI]))
{
//Pout<< "Removing zero sized mesh0 patch "
// << patches0[patchI].name() << endl;
filteredPatchI = -1;
}
else
{
filteredPatchI = allPatches.size();
allPatches.append
(
patches0[patchI].clone
(
allBoundaryMesh,
filteredPatchI,
nFaces[patchI],
startFaceI
).ptr()
);
startFaceI += nFaces[patchI];
}
// Record new index in allPatches
from0ToAllPatches[patchI] = filteredPatchI;
// Check if patch was also in mesh1 and update its addressing if so.
if (fromAllTo1Patches[patchI] != -1)
{
from1ToAllPatches[fromAllTo1Patches[patchI]] = filteredPatchI;
}
}
// Copy unique patches of mesh1.
forAll(from1ToAllPatches, patchI)
{
label allPatchI = from1ToAllPatches[patchI];
if (allPatchI >= patches0.size())
{
// Patch has not been merged with any mesh0 patch.
label filteredPatchI;
if
(
nFaces[allPatchI] == 0
&& isA<processorPolyPatch>(patches1[patchI])
)
{
//Pout<< "Removing zero sized mesh1 patch "
// << patches1[patchI].name() << endl;
filteredPatchI = -1;
}
else
{
filteredPatchI = allPatches.size();
allPatches.append
(
patches1[patchI].clone
(
allBoundaryMesh,
filteredPatchI,
nFaces[allPatchI],
startFaceI
).ptr()
);
startFaceI += nFaces[allPatchI];
}
from1ToAllPatches[patchI] = filteredPatchI;
}
}
allPatches.shrink();
return allPatches;
}
Foam::labelList Foam::polyMeshAdder::getFaceOrder
(
const cellList& cells,
const label nInternalFaces,
const labelList& owner,
const labelList& neighbour
)
{
labelList oldToNew(owner.size(), -1);
// Leave boundary faces in order
for (label faceI = nInternalFaces; faceI < owner.size(); faceI++)
{
oldToNew[faceI] = faceI;
}
// First unassigned face
label newFaceI = 0;
forAll(cells, cellI)
{
const labelList& cFaces = cells[cellI];
SortableList<label> nbr(cFaces.size());
forAll(cFaces, i)
{
label faceI = cFaces[i];
label nbrCellI = neighbour[faceI];
if (nbrCellI != -1)
{
// Internal face. Get cell on other side.
if (nbrCellI == cellI)
{
nbrCellI = owner[faceI];
}
if (cellI < nbrCellI)
{
// CellI is master
nbr[i] = nbrCellI;
}
else
{
// nbrCell is master. Let it handle this face.
nbr[i] = -1;
}
}
else
{
// External face. Do later.
nbr[i] = -1;
}
}
nbr.sort();
forAll(nbr, i)
{
if (nbr[i] != -1)
{
oldToNew[cFaces[nbr.indices()[i]]] = newFaceI++;
}
}
}
// Check done all faces.
forAll(oldToNew, faceI)
{
if (oldToNew[faceI] == -1)
{
FatalErrorIn
(
"polyMeshAdder::getFaceOrder"
"(const cellList&, const label, const labelList&"
", const labelList&) const"
) << "Did not determine new position"
<< " for face " << faceI
<< abort(FatalError);
}
}
return oldToNew;
}
// Extends face f with split points. cutEdgeToPoints gives for every
// edge the points introduced inbetween the endpoints.
void Foam::polyMeshAdder::insertVertices
(
const edgeLookup& cutEdgeToPoints,
const Map<label>& meshToMaster,
const labelList& masterToCutPoints,
const face& masterF,
DynamicList<label>& workFace,
face& allF
)
{
workFace.clear();
// Check any edge for being cut (check on the cut so takes account
// for any point merging on the cut)
forAll(masterF, fp)
{
label v0 = masterF[fp];
label v1 = masterF.nextLabel(fp);
// Copy existing face point
workFace.append(allF[fp]);
// See if any edge between v0,v1
Map<label>::const_iterator v0Fnd = meshToMaster.find(v0);
if (v0Fnd != meshToMaster.end())
{
Map<label>::const_iterator v1Fnd = meshToMaster.find(v1);
if (v1Fnd != meshToMaster.end())
{
// Get edge in cutPoint numbering
edge cutEdge
(
masterToCutPoints[v0Fnd()],
masterToCutPoints[v1Fnd()]
);
edgeLookup::const_iterator iter = cutEdgeToPoints.find(cutEdge);
if (iter != cutEdgeToPoints.end())
{
const edge& e = iter.key();
const labelList& addedPoints = iter();
// cutPoints first in allPoints so no need for renumbering
if (e[0] == cutEdge[0])
{
forAll(addedPoints, i)
{
workFace.append(addedPoints[i]);
}
}
else
{
forAllReverse(addedPoints, i)
{
workFace.append(addedPoints[i]);
}
}
}
}
}
}
if (workFace.size() != allF.size())
{
allF.transfer(workFace);
}
}
// Adds primitives (cells, faces, points)
// Cells:
// - all of mesh0
// - all of mesh1
// Faces:
// - all uncoupled of mesh0
// - all coupled faces
// - all uncoupled of mesh1
// Points:
// - all coupled
// - all uncoupled of mesh0
// - all uncoupled of mesh1
void Foam::polyMeshAdder::mergePrimitives
(
const polyMesh& mesh0,
const polyMesh& mesh1,
const faceCoupleInfo& coupleInfo,
const label nAllPatches, // number of patches in the new mesh
const labelList& fromAllTo1Patches,
const labelList& from1ToAllPatches,
pointField& allPoints,
labelList& from0ToAllPoints,
labelList& from1ToAllPoints,
faceList& allFaces,
labelList& allOwner,
labelList& allNeighbour,
label& nInternalFaces,
labelList& nFacesPerPatch,
label& nCells,
labelList& from0ToAllFaces,
labelList& from1ToAllFaces,
labelList& from1ToAllCells
)
{
const polyBoundaryMesh& patches0 = mesh0.boundaryMesh();
const polyBoundaryMesh& patches1 = mesh1.boundaryMesh();
const primitiveFacePatch& cutFaces = coupleInfo.cutFaces();
const indirectPrimitivePatch& masterPatch = coupleInfo.masterPatch();
const indirectPrimitivePatch& slavePatch = coupleInfo.slavePatch();
// Points
// ~~~~~~
// Storage for new points
allPoints.setSize(mesh0.nPoints() + mesh1.nPoints());
label allPointI = 0;
from0ToAllPoints.setSize(mesh0.nPoints());
from0ToAllPoints = -1;
from1ToAllPoints.setSize(mesh1.nPoints());
from1ToAllPoints = -1;
// Copy coupled points (on cut)
{
const pointField& cutPoints = coupleInfo.cutPoints();
//const labelListList& cutToMasterPoints =
// coupleInfo.cutToMasterPoints();
labelListList cutToMasterPoints
(
invertOneToMany
(
cutPoints.size(),
coupleInfo.masterToCutPoints()
)
);
//const labelListList& cutToSlavePoints =
// coupleInfo.cutToSlavePoints();
labelListList cutToSlavePoints
(
invertOneToMany
(
cutPoints.size(),
coupleInfo.slaveToCutPoints()
)
);
forAll(cutPoints, i)
{
allPoints[allPointI] = cutPoints[i];
// Mark all master and slave points referring to this point.
const labelList& masterPoints = cutToMasterPoints[i];
forAll(masterPoints, j)
{
label mesh0PointI = masterPatch.meshPoints()[masterPoints[j]];
from0ToAllPoints[mesh0PointI] = allPointI;
}
const labelList& slavePoints = cutToSlavePoints[i];
forAll(slavePoints, j)
{
label mesh1PointI = slavePatch.meshPoints()[slavePoints[j]];
from1ToAllPoints[mesh1PointI] = allPointI;
}
allPointI++;
}
}
// Add uncoupled mesh0 points
forAll(mesh0.points(), pointI)
{
if (from0ToAllPoints[pointI] == -1)
{
allPoints[allPointI] = mesh0.points()[pointI];
from0ToAllPoints[pointI] = allPointI;
allPointI++;
}
}
// Add uncoupled mesh1 points
forAll(mesh1.points(), pointI)
{
if (from1ToAllPoints[pointI] == -1)
{
allPoints[allPointI] = mesh1.points()[pointI];
from1ToAllPoints[pointI] = allPointI;
allPointI++;
}
}
allPoints.setSize(allPointI);
// Faces
// ~~~~~
// Sizes per patch
nFacesPerPatch.setSize(nAllPatches);
nFacesPerPatch = 0;
// Storage for faces and owner/neighbour
allFaces.setSize(mesh0.nFaces() + mesh1.nFaces());
allOwner.setSize(allFaces.size());
allOwner = -1;
allNeighbour.setSize(allFaces.size());
allNeighbour = -1;
label allFaceI = 0;
from0ToAllFaces.setSize(mesh0.nFaces());
from0ToAllFaces = -1;
from1ToAllFaces.setSize(mesh1.nFaces());
from1ToAllFaces = -1;
// Copy mesh0 internal faces (always uncoupled)
for (label faceI = 0; faceI < mesh0.nInternalFaces(); faceI++)
{
allFaces[allFaceI] = renumber(from0ToAllPoints, mesh0.faces()[faceI]);
allOwner[allFaceI] = mesh0.faceOwner()[faceI];
allNeighbour[allFaceI] = mesh0.faceNeighbour()[faceI];
from0ToAllFaces[faceI] = allFaceI++;
}
// Copy coupled faces. Every coupled face has an equivalent master and
// slave. Also uncount as boundary faces all the newly coupled faces.
const labelList& cutToMasterFaces = coupleInfo.cutToMasterFaces();
const labelList& cutToSlaveFaces = coupleInfo.cutToSlaveFaces();
forAll(cutFaces, i)
{
label masterFaceI = cutToMasterFaces[i];
label mesh0FaceI = masterPatch.addressing()[masterFaceI];
if (from0ToAllFaces[mesh0FaceI] == -1)
{
// First occurrence of face
from0ToAllFaces[mesh0FaceI] = allFaceI;
// External face becomes internal so uncount
label patch0 = patches0.whichPatch(mesh0FaceI);
nFacesPerPatch[patch0]--;
}
label slaveFaceI = cutToSlaveFaces[i];
label mesh1FaceI = slavePatch.addressing()[slaveFaceI];
if (from1ToAllFaces[mesh1FaceI] == -1)
{
from1ToAllFaces[mesh1FaceI] = allFaceI;
label patch1 = patches1.whichPatch(mesh1FaceI);
nFacesPerPatch[from1ToAllPatches[patch1]]--;
}
// Copy cut face (since cutPoints are copied first no renumbering
// nessecary)
allFaces[allFaceI] = cutFaces[i];
allOwner[allFaceI] = mesh0.faceOwner()[mesh0FaceI];
allNeighbour[allFaceI] = mesh1.faceOwner()[mesh1FaceI] + mesh0.nCells();
allFaceI++;
}
// Copy mesh1 internal faces (always uncoupled)
for (label faceI = 0; faceI < mesh1.nInternalFaces(); faceI++)
{
allFaces[allFaceI] = renumber(from1ToAllPoints, mesh1.faces()[faceI]);
allOwner[allFaceI] = mesh1.faceOwner()[faceI] + mesh0.nCells();
allNeighbour[allFaceI] = mesh1.faceNeighbour()[faceI] + mesh0.nCells();
from1ToAllFaces[faceI] = allFaceI++;
}
nInternalFaces = allFaceI;
// Copy (unmarked/uncoupled) external faces in new order.
for (label allPatchI = 0; allPatchI < nAllPatches; allPatchI++)
{
if (allPatchI < patches0.size())
{
// Patch is present in mesh0
const polyPatch& pp = patches0[allPatchI];
nFacesPerPatch[allPatchI] += pp.size();
label faceI = pp.start();
forAll(pp, i)
{
if (from0ToAllFaces[faceI] == -1)
{
// Is uncoupled face since has not yet been dealt with
allFaces[allFaceI] = renumber
(
from0ToAllPoints,
mesh0.faces()[faceI]
);
allOwner[allFaceI] = mesh0.faceOwner()[faceI];
allNeighbour[allFaceI] = -1;
from0ToAllFaces[faceI] = allFaceI++;
}
faceI++;
}
}
if (fromAllTo1Patches[allPatchI] != -1)
{
// Patch is present in mesh1
const polyPatch& pp = patches1[fromAllTo1Patches[allPatchI]];
nFacesPerPatch[allPatchI] += pp.size();
label faceI = pp.start();
forAll(pp, i)
{
if (from1ToAllFaces[faceI] == -1)
{
// Is uncoupled face
allFaces[allFaceI] = renumber
(
from1ToAllPoints,
mesh1.faces()[faceI]
);
allOwner[allFaceI] =
mesh1.faceOwner()[faceI]
+ mesh0.nCells();
allNeighbour[allFaceI] = -1;
from1ToAllFaces[faceI] = allFaceI++;
}
faceI++;
}
}
}
allFaces.setSize(allFaceI);
allOwner.setSize(allFaceI);
allNeighbour.setSize(allFaceI);
// So now we have all ok for one-to-one mapping.
// For split slace faces:
// - mesh consistent with slave side
// - mesh not consistent with owner side. It is not zipped up, the
// original faces need edges split.
// Use brute force to prevent having to calculate addressing:
// - get map from master edge to split edges.
// - check all faces to find any edge that is split.
{
// From two cut-points to labels of cut-points inbetween.
// (in order: from e[0] to e[1]
const edgeLookup& cutEdgeToPoints = coupleInfo.cutEdgeToPoints();
// Get map of master face (in mesh labels) that are in cut. These faces
// do not need to be renumbered.
labelHashSet masterCutFaces(cutToMasterFaces.size());
forAll(cutToMasterFaces, i)
{
label meshFaceI = masterPatch.addressing()[cutToMasterFaces[i]];
masterCutFaces.insert(meshFaceI);
}
DynamicList<label> workFace(100);
forAll(from0ToAllFaces, face0)
{
if (!masterCutFaces.found(face0))
{
label allFaceI = from0ToAllFaces[face0];
insertVertices
(
cutEdgeToPoints,
masterPatch.meshPointMap(),
coupleInfo.masterToCutPoints(),
mesh0.faces()[face0],
workFace,
allFaces[allFaceI]
);
}
}
// Same for slave face
labelHashSet slaveCutFaces(cutToSlaveFaces.size());
forAll(cutToSlaveFaces, i)
{
label meshFaceI = slavePatch.addressing()[cutToSlaveFaces[i]];
slaveCutFaces.insert(meshFaceI);
}
forAll(from1ToAllFaces, face1)
{
if (!slaveCutFaces.found(face1))
{
label allFaceI = from1ToAllFaces[face1];
insertVertices
(
cutEdgeToPoints,
slavePatch.meshPointMap(),
coupleInfo.slaveToCutPoints(),
mesh1.faces()[face1],
workFace,
allFaces[allFaceI]
);
}
}
}
// Now we have a full facelist and owner/neighbour addressing.
// Cells
// ~~~~~
from1ToAllCells.setSize(mesh1.nCells());
from1ToAllCells = -1;
forAll(mesh1.cells(), i)
{
from1ToAllCells[i] = i + mesh0.nCells();
}
// Make cells (= cell-face addressing)
nCells = mesh0.nCells() + mesh1.nCells();
cellList allCells(nCells);
primitiveMesh::calcCells(allCells, allOwner, allNeighbour, nCells);
// Reorder faces for upper-triangular order.
labelList oldToNew
(
getFaceOrder
(
allCells,
nInternalFaces,
allOwner,
allNeighbour
)
);
inplaceReorder(oldToNew, allFaces);
inplaceReorder(oldToNew, allOwner);
inplaceReorder(oldToNew, allNeighbour);
inplaceRenumber(oldToNew, from0ToAllFaces);
inplaceRenumber(oldToNew, from1ToAllFaces);
}
void Foam::polyMeshAdder::mergePointZones
(
const pointZoneMesh& pz0,
const pointZoneMesh& pz1,
const labelList& from0ToAllPoints,
const labelList& from1ToAllPoints,
DynamicList<word>& zoneNames,
labelList& from1ToAll,
List<DynamicList<label> >& pzPoints
)
{
zoneNames.setCapacity(pz0.size() + pz1.size());
// Names
append(pz0.names(), zoneNames);
from1ToAll.setSize(pz1.size());
forAll (pz1, zoneI)
{
from1ToAll[zoneI] = zoneIndex(pz1[zoneI].name(), zoneNames);
}
zoneNames.shrink();
// Point labels per merged zone
pzPoints.setSize(zoneNames.size());
forAll(pz0, zoneI)
{
append(from0ToAllPoints, pz0[zoneI], pzPoints[zoneI]);
}
// Get sorted zone contents for duplicate element recognition
PtrList<SortableList<label> > pzPointsSorted(pzPoints.size());
forAll(pzPoints, zoneI)
{
pzPointsSorted.set
(
zoneI,
new SortableList<label>(pzPoints[zoneI])
);
}
// Now we have full addressing for points so do the pointZones of mesh1.
forAll(pz1, zoneI)
{
// Relabel all points of zone and add to correct pzPoints.
label allZoneI = from1ToAll[zoneI];
append
(
from1ToAllPoints,
pz1[zoneI],
pzPointsSorted[allZoneI],
pzPoints[allZoneI]
);
}
forAll(pzPoints, i)
{
pzPoints[i].shrink();
}
}
void Foam::polyMeshAdder::mergeFaceZones
(
const faceZoneMesh& fz0,
const faceZoneMesh& fz1,
const labelList& from0ToAllFaces,
const labelList& from1ToAllFaces,
DynamicList<word>& zoneNames,
labelList& from1ToAll,
List<DynamicList<label> >& fzFaces,
List<DynamicList<bool> >& fzFlips
)
{
zoneNames.setCapacity(fz0.size() + fz1.size());
append(fz0.names(), zoneNames);
from1ToAll.setSize(fz1.size());
forAll (fz1, zoneI)
{
from1ToAll[zoneI] = zoneIndex(fz1[zoneI].name(), zoneNames);
}
zoneNames.shrink();
// Create temporary lists for faceZones.
fzFaces.setSize(zoneNames.size());
fzFlips.setSize(zoneNames.size());
forAll(fz0, zoneI)
{
DynamicList<label>& newZone = fzFaces[zoneI];
DynamicList<bool>& newFlip = fzFlips[zoneI];
newZone.setCapacity(fz0[zoneI].size());
newFlip.setCapacity(newZone.size());
const labelList& addressing = fz0[zoneI];
const boolList& flipMap = fz0[zoneI].flipMap();
forAll(addressing, i)
{
label faceI = addressing[i];
if (from0ToAllFaces[faceI] != -1)
{
newZone.append(from0ToAllFaces[faceI]);
newFlip.append(flipMap[i]);
}
}
}
// Get sorted zone contents for duplicate element recognition
PtrList<SortableList<label> > fzFacesSorted(fzFaces.size());
forAll(fzFaces, zoneI)
{
fzFacesSorted.set
(
zoneI,
new SortableList<label>(fzFaces[zoneI])
);
}
// Now we have full addressing for faces so do the faceZones of mesh1.
forAll(fz1, zoneI)
{
label allZoneI = from1ToAll[zoneI];
DynamicList<label>& newZone = fzFaces[allZoneI];
const SortableList<label>& newZoneSorted = fzFacesSorted[allZoneI];
DynamicList<bool>& newFlip = fzFlips[allZoneI];
newZone.setCapacity(newZone.size() + fz1[zoneI].size());
newFlip.setCapacity(newZone.size());
const labelList& addressing = fz1[zoneI];
const boolList& flipMap = fz1[zoneI].flipMap();
forAll(addressing, i)
{
label faceI = addressing[i];
label allFaceI = from1ToAllFaces[faceI];
if
(
allFaceI != -1
&& findSortedIndex(newZoneSorted, allFaceI) == -1
)
{
newZone.append(allFaceI);
newFlip.append(flipMap[i]);
}
}
}
forAll(fzFaces, i)
{
fzFaces[i].shrink();
fzFlips[i].shrink();
}
}
void Foam::polyMeshAdder::mergeCellZones
(
const cellZoneMesh& cz0,
const cellZoneMesh& cz1,
const labelList& from1ToAllCells,
DynamicList<word>& zoneNames,
labelList& from1ToAll,
List<DynamicList<label> >& czCells
)
{
zoneNames.setCapacity(cz0.size() + cz1.size());
append(cz0.names(), zoneNames);
from1ToAll.setSize(cz1.size());
forAll (cz1, zoneI)
{
from1ToAll[zoneI] = zoneIndex(cz1[zoneI].name(), zoneNames);
}
zoneNames.shrink();
// Create temporary lists for cellZones.
czCells.setSize(zoneNames.size());
forAll(cz0, zoneI)
{
// Insert mesh0 cells
append(cz0[zoneI], czCells[zoneI]);
}
// Cell mapping is trivial.
forAll(cz1, zoneI)
{
label allZoneI = from1ToAll[zoneI];
append(from1ToAllCells, cz1[zoneI], czCells[allZoneI]);
}
forAll(czCells, i)
{
czCells[i].shrink();
}
}
void Foam::polyMeshAdder::mergeZones
(
const polyMesh& mesh0,
const polyMesh& mesh1,
const labelList& from0ToAllPoints,
const labelList& from0ToAllFaces,
const labelList& from1ToAllPoints,
const labelList& from1ToAllFaces,
const labelList& from1ToAllCells,
DynamicList<word>& pointZoneNames,
List<DynamicList<label> >& pzPoints,
DynamicList<word>& faceZoneNames,
List<DynamicList<label> >& fzFaces,
List<DynamicList<bool> >& fzFlips,
DynamicList<word>& cellZoneNames,
List<DynamicList<label> >& czCells
)
{
labelList from1ToAllPZones;
mergePointZones
(
mesh0.pointZones(),
mesh1.pointZones(),
from0ToAllPoints,
from1ToAllPoints,
pointZoneNames,
from1ToAllPZones,
pzPoints
);
labelList from1ToAllFZones;
mergeFaceZones
(
mesh0.faceZones(),
mesh1.faceZones(),
from0ToAllFaces,
from1ToAllFaces,
faceZoneNames,
from1ToAllFZones,
fzFaces,
fzFlips
);
labelList from1ToAllCZones;
mergeCellZones
(
mesh0.cellZones(),
mesh1.cellZones(),
from1ToAllCells,
cellZoneNames,
from1ToAllCZones,
czCells
);
}
void Foam::polyMeshAdder::addZones
(
const DynamicList<word>& pointZoneNames,
const List<DynamicList<label> >& pzPoints,
const DynamicList<word>& faceZoneNames,
const List<DynamicList<label> >& fzFaces,
const List<DynamicList<bool> >& fzFlips,
const DynamicList<word>& cellZoneNames,
const List<DynamicList<label> >& czCells,
polyMesh& mesh
)
{
List<pointZone*> pZones(pzPoints.size());
forAll(pZones, i)
{
pZones[i] = new pointZone
(
pointZoneNames[i],
pzPoints[i],
i,
mesh.pointZones()
);
}
List<faceZone*> fZones(fzFaces.size());
forAll(fZones, i)
{
fZones[i] = new faceZone
(
faceZoneNames[i],
fzFaces[i],
fzFlips[i],
i,
mesh.faceZones()
);
}
List<cellZone*> cZones(czCells.size());
forAll(cZones, i)
{
cZones[i] = new cellZone
(
cellZoneNames[i],
czCells[i],
i,
mesh.cellZones()
);
}
mesh.addZones
(
pZones,
fZones,
cZones
);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// Returns new mesh and sets
// - map from new cell/face/point/patch to either mesh0 or mesh1
//
// mesh0Faces/mesh1Faces: corresponding faces on both meshes.
Foam::autoPtr<Foam::polyMesh> Foam::polyMeshAdder::add
(
const IOobject& io,
const polyMesh& mesh0,
const polyMesh& mesh1,
const faceCoupleInfo& coupleInfo,
autoPtr<mapAddedPolyMesh>& mapPtr
)
{
const polyBoundaryMesh& patches0 = mesh0.boundaryMesh();
const polyBoundaryMesh& patches1 = mesh1.boundaryMesh();
DynamicList<word> allPatchNames(patches0.size() + patches1.size());
DynamicList<word> allPatchTypes(allPatchNames.size());
// Patch maps
labelList from1ToAllPatches(patches1.size());
labelList fromAllTo1Patches(allPatchNames.size(), -1);
mergePatchNames
(
patches0,
patches1,
allPatchNames,
allPatchTypes,
from1ToAllPatches,
fromAllTo1Patches
);
// New points
pointField allPoints;
// Map from mesh0/1 points to allPoints.
labelList from0ToAllPoints(mesh0.nPoints(), -1);
labelList from1ToAllPoints(mesh1.nPoints(), -1);
// New faces
faceList allFaces;
label nInternalFaces;
// New cells
labelList allOwner;
labelList allNeighbour;
label nCells;
// Sizes per patch
labelList nFaces(allPatchNames.size(), 0);
// Maps
labelList from0ToAllFaces(mesh0.nFaces(), -1);
labelList from1ToAllFaces(mesh1.nFaces(), -1);
// Map
labelList from1ToAllCells(mesh1.nCells(), -1);
mergePrimitives
(
mesh0,
mesh1,
coupleInfo,
allPatchNames.size(),
fromAllTo1Patches,
from1ToAllPatches,
allPoints,
from0ToAllPoints,
from1ToAllPoints,
allFaces,
allOwner,
allNeighbour,
nInternalFaces,
nFaces,
nCells,
from0ToAllFaces,
from1ToAllFaces,
from1ToAllCells
);
// Zones
// ~~~~~
DynamicList<word> pointZoneNames;
List<DynamicList<label> > pzPoints;
DynamicList<word> faceZoneNames;
List<DynamicList<label> > fzFaces;
List<DynamicList<bool> > fzFlips;
DynamicList<word> cellZoneNames;
List<DynamicList<label> > czCells;
mergeZones
(
mesh0,
mesh1,
from0ToAllPoints,
from0ToAllFaces,
from1ToAllPoints,
from1ToAllFaces,
from1ToAllCells,
pointZoneNames,
pzPoints,
faceZoneNames,
fzFaces,
fzFlips,
cellZoneNames,
czCells
);
// Patches
// ~~~~~~~
// Map from 0 to all patches (since gets compacted)
labelList from0ToAllPatches(patches0.size(), -1);
List<polyPatch*> allPatches
(
combinePatches
(
mesh0,
mesh1,
patches0, // Should be boundaryMesh() on new mesh.
allPatchNames.size(),
fromAllTo1Patches,
mesh0.nInternalFaces()
+ mesh1.nInternalFaces()
+ coupleInfo.cutFaces().size(),
nFaces,
from0ToAllPatches,
from1ToAllPatches
)
);
// Map information
// ~~~~~~~~~~~~~~~
mapPtr.reset
(
new mapAddedPolyMesh
(
mesh0.nPoints(),
mesh0.nFaces(),
mesh0.nCells(),
mesh1.nPoints(),
mesh1.nFaces(),
mesh1.nCells(),
from0ToAllPoints,
from0ToAllFaces,
identity(mesh0.nCells()),
from1ToAllPoints,
from1ToAllFaces,
from1ToAllCells,
from0ToAllPatches,
from1ToAllPatches,
getPatchSizes(patches0),
getPatchStarts(patches0)
)
);
// Now we have extracted all information from all meshes.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construct mesh
autoPtr<polyMesh> tmesh
(
new polyMesh
(
io,
xferMove(allPoints),
xferMove(allFaces),
xferMove(allOwner),
xferMove(allNeighbour)
)
);
polyMesh& mesh = tmesh();
// Add zones to new mesh.
addZones
(
pointZoneNames,
pzPoints,
faceZoneNames,
fzFaces,
fzFlips,
cellZoneNames,
czCells,
mesh
);
// Add patches to new mesh
mesh.addPatches(allPatches);
return tmesh;
}
// Inplace add mesh1 to mesh0
Foam::autoPtr<Foam::mapAddedPolyMesh> Foam::polyMeshAdder::add
(
polyMesh& mesh0,
const polyMesh& mesh1,
const faceCoupleInfo& coupleInfo,
const bool validBoundary
)
{
const polyBoundaryMesh& patches0 = mesh0.boundaryMesh();
const polyBoundaryMesh& patches1 = mesh1.boundaryMesh();
DynamicList<word> allPatchNames(patches0.size() + patches1.size());
DynamicList<word> allPatchTypes(allPatchNames.size());
// Patch maps
labelList from1ToAllPatches(patches1.size());
labelList fromAllTo1Patches(allPatchNames.size(), -1);
mergePatchNames
(
patches0,
patches1,
allPatchNames,
allPatchTypes,
from1ToAllPatches,
fromAllTo1Patches
);
// New points
pointField allPoints;
// Map from mesh0/1 points to allPoints.
labelList from0ToAllPoints(mesh0.nPoints(), -1);
labelList from1ToAllPoints(mesh1.nPoints(), -1);
// New faces
faceList allFaces;
labelList allOwner;
labelList allNeighbour;
label nInternalFaces;
// Sizes per patch
labelList nFaces(allPatchNames.size(), 0);
label nCells;
// Maps
labelList from0ToAllFaces(mesh0.nFaces(), -1);
labelList from1ToAllFaces(mesh1.nFaces(), -1);
// Map
labelList from1ToAllCells(mesh1.nCells(), -1);
mergePrimitives
(
mesh0,
mesh1,
coupleInfo,
allPatchNames.size(),
fromAllTo1Patches,
from1ToAllPatches,
allPoints,
from0ToAllPoints,
from1ToAllPoints,
allFaces,
allOwner,
allNeighbour,
nInternalFaces,
nFaces,
nCells,
from0ToAllFaces,
from1ToAllFaces,
from1ToAllCells
);
// Zones
// ~~~~~
DynamicList<word> pointZoneNames;
List<DynamicList<label> > pzPoints;
DynamicList<word> faceZoneNames;
List<DynamicList<label> > fzFaces;
List<DynamicList<bool> > fzFlips;
DynamicList<word> cellZoneNames;
List<DynamicList<label> > czCells;
mergeZones
(
mesh0,
mesh1,
from0ToAllPoints,
from0ToAllFaces,
from1ToAllPoints,
from1ToAllFaces,
from1ToAllCells,
pointZoneNames,
pzPoints,
faceZoneNames,
fzFaces,
fzFlips,
cellZoneNames,
czCells
);
// Patches
// ~~~~~~~
// Store mesh0 patch info before modifying patches0.
labelList mesh0PatchSizes(getPatchSizes(patches0));
labelList mesh0PatchStarts(getPatchStarts(patches0));
// Map from 0 to all patches (since gets compacted)
labelList from0ToAllPatches(patches0.size(), -1);
// Inplace extend mesh0 patches (note that patches0.size() now also
// has changed)
polyBoundaryMesh& allPatches =
const_cast<polyBoundaryMesh&>(mesh0.boundaryMesh());
allPatches.setSize(allPatchNames.size());
label startFaceI = nInternalFaces;
// Copy patches0 with new sizes. First patches always come from
// mesh0 and will always be present.
label allPatchI = 0;
forAll(from0ToAllPatches, patch0)
{
// Originates from mesh0. Clone with new size & filter out empty
// patch.
if (nFaces[patch0] == 0 && isA<processorPolyPatch>(allPatches[patch0]))
{
//Pout<< "Removing zero sized mesh0 patch " << allPatchNames[patch0]
// << endl;
from0ToAllPatches[patch0] = -1;
// Check if patch was also in mesh1 and update its addressing if so.
if (fromAllTo1Patches[patch0] != -1)
{
from1ToAllPatches[fromAllTo1Patches[patch0]] = -1;
}
}
else
{
// Clone.
allPatches.set
(
allPatchI,
allPatches[patch0].clone
(
allPatches,
allPatchI,
nFaces[patch0],
startFaceI
)
);
// Record new index in allPatches
from0ToAllPatches[patch0] = allPatchI;
// Check if patch was also in mesh1 and update its addressing if so.
if (fromAllTo1Patches[patch0] != -1)
{
from1ToAllPatches[fromAllTo1Patches[patch0]] = allPatchI;
}
startFaceI += nFaces[patch0];
allPatchI++;
}
}
// Copy unique patches of mesh1.
forAll(from1ToAllPatches, patch1)
{
label uncompactAllPatchI = from1ToAllPatches[patch1];
if (uncompactAllPatchI >= from0ToAllPatches.size())
{
// Patch has not been merged with any mesh0 patch.
if
(
nFaces[uncompactAllPatchI] == 0
&& isA<processorPolyPatch>(patches1[patch1])
)
{
//Pout<< "Removing zero sized mesh1 patch "
// << allPatchNames[uncompactAllPatchI] << endl;
from1ToAllPatches[patch1] = -1;
}
else
{
// Clone.
allPatches.set
(
allPatchI,
patches1[patch1].clone
(
allPatches,
allPatchI,
nFaces[uncompactAllPatchI],
startFaceI
)
);
// Record new index in allPatches
from1ToAllPatches[patch1] = allPatchI;
startFaceI += nFaces[uncompactAllPatchI];
allPatchI++;
}
}
}
allPatches.setSize(allPatchI);
// Construct map information before changing mesh0 primitives
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
autoPtr<mapAddedPolyMesh> mapPtr
(
new mapAddedPolyMesh
(
mesh0.nPoints(),
mesh0.nFaces(),
mesh0.nCells(),
mesh1.nPoints(),
mesh1.nFaces(),
mesh1.nCells(),
from0ToAllPoints,
from0ToAllFaces,
identity(mesh0.nCells()),
from1ToAllPoints,
from1ToAllFaces,
from1ToAllCells,
from0ToAllPatches,
from1ToAllPatches,
mesh0PatchSizes,
mesh0PatchStarts
)
);
// Now we have extracted all information from all meshes.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
labelList patchSizes(getPatchSizes(allPatches));
labelList patchStarts(getPatchStarts(allPatches));
mesh0.resetMotion(); // delete any oldPoints.
mesh0.resetPrimitives
(
xferMove(allPoints),
xferMove(allFaces),
xferMove(allOwner),
xferMove(allNeighbour),
patchSizes, // size
patchStarts, // patchstarts
validBoundary // boundary valid?
);
// Add zones to new mesh.
mesh0.pointZones().clear();
mesh0.faceZones().clear();
mesh0.cellZones().clear();
addZones
(
pointZoneNames,
pzPoints,
faceZoneNames,
fzFaces,
fzFlips,
cellZoneNames,
czCells,
mesh0
);
return mapPtr;
}
Foam::Map<Foam::label> Foam::polyMeshAdder::findSharedPoints
(
const polyMesh& mesh,
const scalar mergeDist
)
{
const labelList& sharedPointLabels = mesh.globalData().sharedPointLabels();
const labelList& sharedPointAddr = mesh.globalData().sharedPointAddr();
// Because of adding the missing pieces e.g. when redistributing a mesh
// it can be that there are multiple points on the same processor that
// refer to the same shared point.
// Invert point-to-shared addressing
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Map<labelList> sharedToMesh(sharedPointLabels.size());
label nMultiple = 0;
forAll(sharedPointLabels, i)
{
label pointI = sharedPointLabels[i];
label sharedI = sharedPointAddr[i];
Map<labelList>::iterator iter = sharedToMesh.find(sharedI);
if (iter != sharedToMesh.end())
{
// sharedI already used by other point. Add this one.
nMultiple++;
labelList& connectedPointLabels = iter();
label sz = connectedPointLabels.size();
// Check just to make sure.
if (findIndex(connectedPointLabels, pointI) != -1)
{
FatalErrorIn("polyMeshAdder::findSharedPoints(..)")
<< "Duplicate point in sharedPoint addressing." << endl
<< "When trying to add point " << pointI << " on shared "
<< sharedI << " with connected points "
<< connectedPointLabels
<< abort(FatalError);
}
connectedPointLabels.setSize(sz+1);
connectedPointLabels[sz] = pointI;
}
else
{
sharedToMesh.insert(sharedI, labelList(1, pointI));
}
}
// Assign single master for every shared with multiple geometric points
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Map<label> pointToMaster(nMultiple);
forAllConstIter(Map<labelList>, sharedToMesh, iter)
{
const labelList& connectedPointLabels = iter();
//Pout<< "For shared:" << iter.key()
// << " found points:" << connectedPointLabels
// << " at coords:"
// << pointField(mesh.points(), connectedPointLabels) << endl;
if (connectedPointLabels.size() > 1)
{
const pointField connectedPoints
(
mesh.points(),
connectedPointLabels
);
labelList toMergedPoints;
pointField mergedPoints;
bool hasMerged = Foam::mergePoints
(
connectedPoints,
mergeDist,
false,
toMergedPoints,
mergedPoints
);
if (hasMerged)
{
// Invert toMergedPoints
const labelListList mergeSets
(
invertOneToMany
(
mergedPoints.size(),
toMergedPoints
)
);
// Find master for valid merges
forAll(mergeSets, setI)
{
const labelList& mergeSet = mergeSets[setI];
if (mergeSet.size() > 1)
{
// Pick lowest numbered point
label masterPointI = labelMax;
forAll(mergeSet, i)
{
label pointI = connectedPointLabels[mergeSet[i]];
masterPointI = min(masterPointI, pointI);
}
forAll(mergeSet, i)
{
label pointI = connectedPointLabels[mergeSet[i]];
//Pout<< "Merging point " << pointI
// << " at " << mesh.points()[pointI]
// << " into master point "
// << masterPointI
// << " at " << mesh.points()[masterPointI]
// << endl;
pointToMaster.insert(pointI, masterPointI);
}
}
}
}
}
}
//- Old: geometric merging. Causes problems for two close shared points.
//labelList sharedToMerged;
//pointField mergedPoints;
//bool hasMerged = Foam::mergePoints
//(
// pointField
// (
// mesh.points(),
// sharedPointLabels
// ),
// mergeDist,
// false,
// sharedToMerged,
// mergedPoints
//);
//
//// Find out which sets of points get merged and create a map from
//// mesh point to unique point.
//
//Map<label> pointToMaster(10*sharedToMerged.size());
//
//if (hasMerged)
//{
// labelListList mergeSets
// (
// invertOneToMany
// (
// sharedToMerged.size(),
// sharedToMerged
// )
// );
//
// label nMergeSets = 0;
//
// forAll(mergeSets, setI)
// {
// const labelList& mergeSet = mergeSets[setI];
//
// if (mergeSet.size() > 1)
// {
// // Take as master the shared point with the lowest mesh
// // point label. (rather arbitrarily - could use max or
// // any other one of the points)
//
// nMergeSets++;
//
// label masterI = labelMax;
//
// forAll(mergeSet, i)
// {
// label sharedI = mergeSet[i];
//
// masterI = min(masterI, sharedPointLabels[sharedI]);
// }
//
// forAll(mergeSet, i)
// {
// label sharedI = mergeSet[i];
//
// pointToMaster.insert(sharedPointLabels[sharedI], masterI);
// }
// }
// }
//
// //if (debug)
// //{
// // Pout<< "polyMeshAdder : merging:"
// // << pointToMaster.size() << " into " << nMergeSets
// // << " sets." << endl;
// //}
//}
return pointToMaster;
}
void Foam::polyMeshAdder::mergePoints
(
const polyMesh& mesh,
const Map<label>& pointToMaster,
polyTopoChange& meshMod
)
{
// Remove all non-master points.
forAll(mesh.points(), pointI)
{
Map<label>::const_iterator iter = pointToMaster.find(pointI);
if (iter != pointToMaster.end())
{
if (iter() != pointI)
{
meshMod.removePoint(pointI, iter());
}
}
}
// Modify faces for points. Note: could use pointFaces here but want to
// avoid addressing calculation.
const faceList& faces = mesh.faces();
forAll(faces, faceI)
{
const face& f = faces[faceI];
bool hasMerged = false;
forAll(f, fp)
{
label pointI = f[fp];
Map<label>::const_iterator iter = pointToMaster.find(pointI);
if (iter != pointToMaster.end())
{
if (iter() != pointI)
{
hasMerged = true;
break;
}
}
}
if (hasMerged)
{
face newF(f);
forAll(f, fp)
{
label pointI = f[fp];
Map<label>::const_iterator iter = pointToMaster.find(pointI);
if (iter != pointToMaster.end())
{
newF[fp] = iter();
}
}
label patchID = mesh.boundaryMesh().whichPatch(faceI);
label nei = (patchID == -1 ? mesh.faceNeighbour()[faceI] : -1);
label zoneID = mesh.faceZones().whichZone(faceI);
bool zoneFlip = false;
if (zoneID >= 0)
{
const faceZone& fZone = mesh.faceZones()[zoneID];
zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
}
meshMod.setAction
(
polyModifyFace
(
newF, // modified face
faceI, // label of face
mesh.faceOwner()[faceI], // owner
nei, // neighbour
false, // face flip
patchID, // patch for face
false, // remove from zone
zoneID, // zone for face
zoneFlip // face flip in zone
)
);
}
}
}
// ************************************************************************* //