/*---------------------------------------------------------------------------*\
========= |
\\ / 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) 2019-2023 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 .
\*---------------------------------------------------------------------------*/
#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"
#include "globalIndex.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Get index of patch in new set of patchnames/types
Foam::label Foam::polyMeshAdder::patchIndex
(
const polyPatch& p,
DynamicList& allPatchNames,
DynamicList& 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 = allPatchNames.find(pName);
if (patchi < 0)
{
// Not found - add to the lists
patchi = allPatchNames.size();
allPatchNames.push_back(pName);
allPatchTypes.push_back(pType);
}
else if (allPatchTypes[patchi] != pType)
{
// Found the name, but type is different
patchi = allPatchNames.size();
// 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.push_back(pName + "_" + caseName);
allPatchTypes.push_back(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.back() << endl;
}
return patchi;
}
// Get index of zone in new set of zone names
Foam::label Foam::polyMeshAdder::zoneIndex
(
const word& curName,
DynamicList& names
)
{
label zonei = names.find(curName);
if (zonei < 0)
{
// Not found - add to the list
zonei = names.size();
names.push_back(curName);
}
return zonei;
}
void Foam::polyMeshAdder::mergePatchNames
(
const polyBoundaryMesh& patches0,
const polyBoundaryMesh& patches1,
DynamicList& allPatchNames,
DynamicList& allPatchTypes,
labelList& from1ToAllPatches,
labelList& fromAllTo1Patches
)
{
// Insert the mesh0 patches and zones
allPatchNames.push_back(patches0.names());
allPatchTypes.push_back(patches0.types());
// 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::List 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 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.
forAll(patches0, patchi)
{
// Originates from mesh0. Clone with new size & filter out empty
// patch.
label filteredPatchi;
if (nFaces[patchi] == 0 && isA(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(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 nbr(cFaces.size());
forAll(cFaces, i)
{
const 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)
{
FatalErrorInFunction
<< "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 EdgeMap& cutEdgeToPoints,
const Map& meshToMaster,
const labelList& masterToCutPoints,
const face& masterF,
DynamicList& 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
const auto v0Fnd = meshToMaster.cfind(v0);
if (v0Fnd.good())
{
const auto v1Fnd = meshToMaster.cfind(v1);
if (v1Fnd.good())
{
// Get edge in cutPoint numbering
edge cutEdge
(
masterToCutPoints[v0Fnd()],
masterToCutPoints[v1Fnd()]
);
const auto iter = cutEdgeToPoints.cfind(cutEdge);
if (iter.good())
{
const edge& e = iter.key();
const labelList& addedPoints = iter.val();
// 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
// necessary)
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 EdgeMap& 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 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 label nAllPoints,
const pointZoneMesh& pz0,
const pointZoneMesh& pz1,
const labelList& from0ToAllPoints,
const labelList& from1ToAllPoints,
DynamicList& zoneNames,
labelList& from1ToAll,
List>& pzPoints
)
{
zoneNames.setCapacity(pz0.size() + pz1.size());
zoneNames.append(pz0.names());
from1ToAll.setSize(pz1.size());
forAll(pz1, zoneI)
{
from1ToAll[zoneI] = zoneIndex(pz1[zoneI].name(), zoneNames);
}
zoneNames.shrink();
// Zone(s) per point. Two levels: if only one zone
// stored in pointToZone. Any extra stored in additionalPointToZones.
// This is so we only allocate labelLists per point if absolutely
// necessary.
labelList pointToZone(nAllPoints, -1);
labelListList addPointToZones(nAllPoints);
// mesh0 zones kept
forAll(pz0, zoneI)
{
const pointZone& pz = pz0[zoneI];
forAll(pz, i)
{
label point0 = pz[i];
label allPointi = from0ToAllPoints[point0];
if (pointToZone[allPointi] == -1)
{
pointToZone[allPointi] = zoneI;
}
else if (pointToZone[allPointi] != zoneI)
{
addPointToZones[allPointi].push_uniq(zoneI);
}
}
}
// mesh1 zones renumbered
forAll(pz1, zoneI)
{
const pointZone& pz = pz1[zoneI];
const label allZoneI = from1ToAll[zoneI];
forAll(pz, i)
{
label point1 = pz[i];
label allPointi = from1ToAllPoints[point1];
if (pointToZone[allPointi] == -1)
{
pointToZone[allPointi] = allZoneI;
}
else if (pointToZone[allPointi] != allZoneI)
{
addPointToZones[allPointi].push_uniq(allZoneI);
}
}
}
// Extract back into zones
// 1. Count
labelList nPoints(zoneNames.size(), Zero);
forAll(pointToZone, allPointi)
{
label zoneI = pointToZone[allPointi];
if (zoneI != -1)
{
nPoints[zoneI]++;
}
}
forAll(addPointToZones, allPointi)
{
const labelList& pZones = addPointToZones[allPointi];
forAll(pZones, i)
{
nPoints[pZones[i]]++;
}
}
// 2. Fill
pzPoints.setSize(zoneNames.size());
forAll(pzPoints, zoneI)
{
pzPoints[zoneI].setCapacity(nPoints[zoneI]);
}
forAll(pointToZone, allPointi)
{
label zoneI = pointToZone[allPointi];
if (zoneI != -1)
{
pzPoints[zoneI].append(allPointi);
}
}
forAll(addPointToZones, allPointi)
{
const labelList& pZones = addPointToZones[allPointi];
forAll(pZones, i)
{
pzPoints[pZones[i]].append(allPointi);
}
}
forAll(pzPoints, i)
{
pzPoints[i].shrink();
stableSort(pzPoints[i]);
}
}
void Foam::polyMeshAdder::mergeFaceZones
(
const labelList& allOwner,
const polyMesh& mesh0,
const polyMesh& mesh1,
const labelList& from0ToAllFaces,
const labelList& from1ToAllFaces,
const labelList& from1ToAllCells,
DynamicList& zoneNames,
labelList& from1ToAll,
List>& fzFaces,
List>& fzFlips
)
{
const faceZoneMesh& fz0 = mesh0.faceZones();
const labelList& owner0 = mesh0.faceOwner();
const faceZoneMesh& fz1 = mesh1.faceZones();
const labelList& owner1 = mesh1.faceOwner();
zoneNames.setCapacity(fz0.size() + fz1.size());
zoneNames.append(fz0.names());
from1ToAll.setSize(fz1.size());
forAll(fz1, zoneI)
{
from1ToAll[zoneI] = zoneIndex(fz1[zoneI].name(), zoneNames);
}
zoneNames.shrink();
// Zone(s) per face
labelList faceToZone(allOwner.size(), -1);
labelListList addFaceToZones(allOwner.size());
boolList faceToFlip(allOwner.size(), false);
boolListList addFaceToFlips(allOwner.size());
// mesh0 zones kept
forAll(fz0, zoneI)
{
const labelList& addressing = fz0[zoneI];
const boolList& flipMap = fz0[zoneI].flipMap();
forAll(addressing, i)
{
label face0 = addressing[i];
bool flip0 = flipMap[i];
label allFacei = from0ToAllFaces[face0];
if (allFacei != -1)
{
// Check if orientation same
label allCell0 = owner0[face0];
if (allOwner[allFacei] != allCell0)
{
flip0 = !flip0;
}
if (faceToZone[allFacei] == -1)
{
faceToZone[allFacei] = zoneI;
faceToFlip[allFacei] = flip0;
}
else if (faceToZone[allFacei] != zoneI)
{
if (addFaceToZones[allFacei].push_uniq(zoneI))
{
addFaceToFlips[allFacei].push_back(flip0);
}
}
}
}
}
// mesh1 zones renumbered
forAll(fz1, zoneI)
{
const labelList& addressing = fz1[zoneI];
const boolList& flipMap = fz1[zoneI].flipMap();
const label allZoneI = from1ToAll[zoneI];
forAll(addressing, i)
{
label face1 = addressing[i];
bool flip1 = flipMap[i];
label allFacei = from1ToAllFaces[face1];
if (allFacei != -1)
{
// Check if orientation same
label allCell1 = from1ToAllCells[owner1[face1]];
if (allOwner[allFacei] != allCell1)
{
flip1 = !flip1;
}
if (faceToZone[allFacei] == -1)
{
faceToZone[allFacei] = allZoneI;
faceToFlip[allFacei] = flip1;
}
else if (faceToZone[allFacei] != allZoneI)
{
if (addFaceToZones[allFacei].push_uniq(allZoneI))
{
addFaceToFlips[allFacei].push_back(flip1);
}
}
}
}
}
// Extract back into zones
// 1. Count
labelList nFaces(zoneNames.size(), Zero);
forAll(faceToZone, allFacei)
{
label zoneI = faceToZone[allFacei];
if (zoneI != -1)
{
nFaces[zoneI]++;
}
}
forAll(addFaceToZones, allFacei)
{
const labelList& fZones = addFaceToZones[allFacei];
forAll(fZones, i)
{
nFaces[fZones[i]]++;
}
}
// 2. Fill
fzFaces.setSize(zoneNames.size());
fzFlips.setSize(zoneNames.size());
forAll(fzFaces, zoneI)
{
fzFaces[zoneI].setCapacity(nFaces[zoneI]);
fzFlips[zoneI].setCapacity(nFaces[zoneI]);
}
forAll(faceToZone, allFacei)
{
label zoneI = faceToZone[allFacei];
bool flip = faceToFlip[allFacei];
if (zoneI != -1)
{
fzFaces[zoneI].append(allFacei);
fzFlips[zoneI].append(flip);
}
}
forAll(addFaceToZones, allFacei)
{
const labelList& fZones = addFaceToZones[allFacei];
const boolList& flipZones = addFaceToFlips[allFacei];
forAll(fZones, i)
{
label zoneI = fZones[i];
fzFaces[zoneI].append(allFacei);
fzFlips[zoneI].append(flipZones[i]);
}
}
forAll(fzFaces, i)
{
fzFaces[i].shrink();
fzFlips[i].shrink();
labelList order(sortedOrder(fzFaces[i]));
fzFaces[i] = labelUIndList(fzFaces[i], order)();
fzFlips[i] = boolUIndList(fzFlips[i], order)();
}
}
void Foam::polyMeshAdder::mergeCellZones
(
const label nAllCells,
const cellZoneMesh& cz0,
const cellZoneMesh& cz1,
const labelList& from1ToAllCells,
DynamicList& zoneNames,
labelList& from1ToAll,
List>& czCells
)
{
zoneNames.setCapacity(cz0.size() + cz1.size());
zoneNames.append(cz0.names());
from1ToAll.setSize(cz1.size());
forAll(cz1, zoneI)
{
from1ToAll[zoneI] = zoneIndex(cz1[zoneI].name(), zoneNames);
}
zoneNames.shrink();
// Zone(s) per cell. Two levels: if only one zone
// stored in cellToZone. Any extra stored in additionalCellToZones.
// This is so we only allocate labelLists per cell if absolutely
// necessary.
labelList cellToZone(nAllCells, -1);
labelListList addCellToZones(nAllCells);
// mesh0 zones kept
forAll(cz0, zoneI)
{
const cellZone& cz = cz0[zoneI];
forAll(cz, i)
{
label cell0 = cz[i];
if (cellToZone[cell0] == -1)
{
cellToZone[cell0] = zoneI;
}
else if (cellToZone[cell0] != zoneI)
{
addCellToZones[cell0].push_uniq(zoneI);
}
}
}
// mesh1 zones renumbered
forAll(cz1, zoneI)
{
const cellZone& cz = cz1[zoneI];
const label allZoneI = from1ToAll[zoneI];
forAll(cz, i)
{
label cell1 = cz[i];
label allCelli = from1ToAllCells[cell1];
if (cellToZone[allCelli] == -1)
{
cellToZone[allCelli] = allZoneI;
}
else if (cellToZone[allCelli] != allZoneI)
{
addCellToZones[allCelli].push_uniq(allZoneI);
}
}
}
// Extract back into zones
// 1. Count
labelList nCells(zoneNames.size(), Zero);
forAll(cellToZone, allCelli)
{
label zoneI = cellToZone[allCelli];
if (zoneI != -1)
{
nCells[zoneI]++;
}
}
forAll(addCellToZones, allCelli)
{
const labelList& cZones = addCellToZones[allCelli];
forAll(cZones, i)
{
nCells[cZones[i]]++;
}
}
// 2. Fill
czCells.setSize(zoneNames.size());
forAll(czCells, zoneI)
{
czCells[zoneI].setCapacity(nCells[zoneI]);
}
forAll(cellToZone, allCelli)
{
label zoneI = cellToZone[allCelli];
if (zoneI != -1)
{
czCells[zoneI].append(allCelli);
}
}
forAll(addCellToZones, allCelli)
{
const labelList& cZones = addCellToZones[allCelli];
forAll(cZones, i)
{
czCells[cZones[i]].append(allCelli);
}
}
forAll(czCells, i)
{
czCells[i].shrink();
stableSort(czCells[i]);
}
}
void Foam::polyMeshAdder::mergeZones
(
const label nAllPoints,
const labelList& allOwner,
const label nAllCells,
const polyMesh& mesh0,
const polyMesh& mesh1,
const labelList& from0ToAllPoints,
const labelList& from0ToAllFaces,
const labelList& from1ToAllPoints,
const labelList& from1ToAllFaces,
const labelList& from1ToAllCells,
DynamicList& pointZoneNames,
List>& pzPoints,
DynamicList& faceZoneNames,
List>& fzFaces,
List>& fzFlips,
DynamicList& cellZoneNames,
List>& czCells
)
{
labelList from1ToAllPZones;
mergePointZones
(
nAllPoints,
mesh0.pointZones(),
mesh1.pointZones(),
from0ToAllPoints,
from1ToAllPoints,
pointZoneNames,
from1ToAllPZones,
pzPoints
);
labelList from1ToAllFZones;
mergeFaceZones
(
allOwner,
mesh0,
mesh1,
from0ToAllFaces,
from1ToAllFaces,
from1ToAllCells,
faceZoneNames,
from1ToAllFZones,
fzFaces,
fzFlips
);
labelList from1ToAllCZones;
mergeCellZones
(
nAllCells,
mesh0.cellZones(),
mesh1.cellZones(),
from1ToAllCells,
cellZoneNames,
from1ToAllCZones,
czCells
);
}
void Foam::polyMeshAdder::addZones
(
const UList& pointZoneNames,
const List>& pzPoints,
const UList& faceZoneNames,
const List>& fzFaces,
const List>& fzFlips,
const UList& cellZoneNames,
const List>& czCells,
polyMesh& mesh
)
{
List pZones(pzPoints.size());
forAll(pZones, i)
{
pZones[i] = new pointZone
(
pointZoneNames[i],
pzPoints[i],
i,
mesh.pointZones()
);
}
List fZones(fzFaces.size());
forAll(fZones, i)
{
fZones[i] = new faceZone
(
faceZoneNames[i],
fzFaces[i],
fzFlips[i],
i,
mesh.faceZones()
);
}
List 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::polyMeshAdder::add
(
const IOobject& io,
const polyMesh& mesh0,
const polyMesh& mesh1,
const faceCoupleInfo& coupleInfo,
autoPtr& mapPtr
)
{
const polyBoundaryMesh& patches0 = mesh0.boundaryMesh();
const polyBoundaryMesh& patches1 = mesh1.boundaryMesh();
DynamicList allPatchNames(patches0.size() + patches1.size());
DynamicList 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(), Zero);
// 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 pointZoneNames;
List> pzPoints;
DynamicList faceZoneNames;
List> fzFaces;
List> fzFlips;
DynamicList cellZoneNames;
List> czCells;
mergeZones
(
allPoints.size(),
allOwner,
nCells,
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 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,
patches0.patchSizes(),
patches0.patchStarts()
)
);
// Now we have extracted all information from all meshes.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construct mesh
auto meshPtr = autoPtr::New
(
io,
std::move(allPoints),
std::move(allFaces),
std::move(allOwner),
std::move(allNeighbour)
);
polyMesh& mesh = *meshPtr;
// Add zones to new mesh.
addZones
(
pointZoneNames,
pzPoints,
faceZoneNames,
fzFaces,
fzFlips,
cellZoneNames,
czCells,
mesh
);
// Add patches to new mesh
mesh.addPatches(allPatches);
return meshPtr;
}
// Inplace add mesh1 to mesh0
Foam::autoPtr 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 allPatchNames(patches0.size() + patches1.size());
DynamicList 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(), Zero);
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 pointZoneNames;
List> pzPoints;
DynamicList faceZoneNames;
List> fzFaces;
List> fzFlips;
DynamicList cellZoneNames;
List> czCells;
mergeZones
(
allPoints.size(),
allOwner,
nCells,
mesh0,
mesh1,
from0ToAllPoints,
from0ToAllFaces,
from1ToAllPoints,
from1ToAllFaces,
from1ToAllCells,
pointZoneNames,
pzPoints,
faceZoneNames,
fzFaces,
fzFlips,
cellZoneNames,
czCells
);
// Patches
// ~~~~~~~
// Store mesh0 patch info before modifying patches0.
labelList mesh0PatchSizes(patches0.patchSizes());
labelList mesh0PatchStarts(patches0.patchStarts());
// 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(mesh0.boundaryMesh());
allPatches.setSize(allPatchNames.size());
labelList patchSizes(allPatches.size());
labelList patchStarts(allPatches.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(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. Note dummy size and start. Gets overwritten later in
// resetPrimitives. This avoids getting temporarily illegal
// SubList construction in polyPatch.
allPatches.set
(
allPatchi,
allPatches[patch0].clone
(
allPatches,
allPatchi,
0, // dummy size
0 // dummy start
)
);
patchSizes[allPatchi] = nFaces[patch0];
patchStarts[allPatchi] = 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(patches1[patch1])
)
{
//Pout<< "Removing zero sized mesh1 patch "
// << allPatchNames[uncompactAllPatchi] << endl;
from1ToAllPatches[patch1] = -1;
}
else
{
// Clone.
allPatches.set
(
allPatchi,
patches1[patch1].clone
(
allPatches,
allPatchi,
0, // dummy size
0 // dummy start
)
);
patchSizes[allPatchi] = nFaces[uncompactAllPatchi];
patchStarts[allPatchi] = startFacei;
// Record new index in allPatches
from1ToAllPatches[patch1] = allPatchi;
startFacei += nFaces[uncompactAllPatchi];
allPatchi++;
}
}
}
allPatches.setSize(allPatchi);
patchSizes.setSize(allPatchi);
patchStarts.setSize(allPatchi);
// Construct map information before changing mesh0 primitives
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
autoPtr 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.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mesh0.resetMotion(); // delete any oldPoints.
mesh0.resetPrimitives
(
autoPtr::New(std::move(allPoints)),
autoPtr::New(std::move(allFaces)),
autoPtr::New(std::move(allOwner)),
autoPtr::New(std::move(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::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 sharedToMesh(sharedPointLabels.size());
label nMultiple = 0;
forAll(sharedPointLabels, i)
{
label pointi = sharedPointLabels[i];
label sharedI = sharedPointAddr[i];
auto iter = sharedToMesh.find(sharedI);
if (iter.good())
{
// sharedI already used by other point. Add this one.
nMultiple++;
labelList& connectedPointLabels = iter.val();
label sz = connectedPointLabels.size();
// Check just to make sure.
if (connectedPointLabels.found(pointi))
{
FatalErrorInFunction
<< "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 pointToMaster(nMultiple);
forAllConstIters(sharedToMesh, iter)
{
const labelList& connectedPointLabels = iter.val();
//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;
label nUnique = Foam::mergePoints
(
connectedPoints,
mergeDist,
false,
toMergedPoints
);
if (nUnique < connectedPoints.size())
{
// Invert toMergedPoints
const labelListList mergeSets
(
invertOneToMany
(
nUnique,
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;
//label nUnique = Foam::mergePoints
//(
// UIndirectList(mesh.points(), sharedPointLabels),
// mergeDist,
// false,
// sharedToMerged
//);
//
//// Find out which sets of points get merged and create a map from
//// mesh point to unique point.
//
//Map pointToMaster(10*sharedToMerged.size());
//
//if (nUnique < sharedPointLabels.size())
//{
// 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& pointToMaster,
polyTopoChange& meshMod
)
{
// Remove all non-master points.
forAll(mesh.points(), pointi)
{
const auto iter = pointToMaster.cfind(pointi);
if (iter.good())
{
if (iter.val() != pointi)
{
meshMod.removePoint(pointi, iter.val());
}
}
}
// 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];
const auto iter = pointToMaster.cfind(pointi);
if (iter.good())
{
if (iter.val() != pointi)
{
hasMerged = true;
break;
}
}
}
if (hasMerged)
{
face newF(f);
forAll(f, fp)
{
label pointi = f[fp];
const auto iter = pointToMaster.cfind(pointi);
if (iter.good())
{
newF[fp] = iter.val();
}
}
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
)
);
}
}
}
Foam::label Foam::polyMeshAdder::procPatchIndex
(
const polyBoundaryMesh& pbm,
const label nbrProci,
const label n
)
{
// Find n'th processor patch going to nbrProci. Usually n=0 but in some
// cases (e.g. processorCyclic, implicit cht) there can be more than one
// processor patch between two processors.
label index = n;
for (label patchi = pbm.nNonProcessor(); patchi < pbm.size(); patchi++)
{
const processorPolyPatch& pp =
refCast(pbm[patchi]);
if (pp.neighbProcNo() == nbrProci)
{
if (index == 0)
{
return patchi;
}
else
{
--index;
}
}
}
FatalErrorInFunction << "no patch found to processor " << nbrProci
<< ". Current patches:" << pbm.names() << exit(FatalError);
return -1;
}
Foam::label Foam::polyMeshAdder::procPatchPairs
(
const UPtrList& meshes,
List>& localPatch,
List>& remoteProc,
List>& remotePatch
//List& remotePatchFace,
//List& remotePatchFaceStart
)
{
// Determine pairs of processor patches:
// - remote processor
// - patch on remote processor
// - face on remote patch
// - starting index on remote face
localPatch.setSize(meshes.size());
remoteProc.setSize(meshes.size());
remotePatch.setSize(meshes.size());
//remotePatchFace.setSize(meshes.size());
//remotePatchFaceStart.setSize(meshes.size());
// Check that all processors have the same globalPatches
{
const polyBoundaryMesh& pbm = meshes[0].boundaryMesh();
const wordList names0(SubList(pbm.names(), pbm.nNonProcessor()));
for (label proci = 1; proci < meshes.size(); proci++)
{
const polyBoundaryMesh& pbm = meshes[proci].boundaryMesh();
const wordList names(pbm.names());
if (SubList(names, pbm.nNonProcessor()) != names0)
{
FatalErrorInFunction
<< "Patch names should be identical on all processors."
<< " Processor 0 has " << names0
<< ". Processor " << proci
<< " has " << names
<< exit(FatalError);
}
}
}
// Work array
labelList nNeighbourProcs(meshes.size());
forAll(meshes, proci)
{
const polyBoundaryMesh& pbm = meshes[proci].boundaryMesh();
// Running count of number of patches communicating with same nbr
// (usually 0)
nNeighbourProcs = 0;
for (label patchi = pbm.nNonProcessor(); patchi < pbm.size(); patchi++)
{
const processorPolyPatch& pp =
refCast(pbm[patchi]);
if (pp.owner())
{
const label nbrProci = pp.neighbProcNo();
const label nbrPatchi = procPatchIndex
(
meshes[nbrProci].boundaryMesh(),
proci,
nNeighbourProcs[nbrProci]
);
const auto& nbrPbm = meshes[nbrProci].boundaryMesh();
const auto& nbrPp = nbrPbm[nbrPatchi];
if (pp.size() != nbrPp.size())
{
FatalErrorInFunction
<< "at proc:" << proci
<< " processor patch "
<< pp.name() << " is not same size " << pp.size()
<< " as coupled patch " << nbrPp.name()
<< " on proc:" << nbrProci
<< " size:" << nbrPp.size()
<< exit(FatalError);
}
localPatch[proci].append(patchi);
remoteProc[proci].append(nbrProci);
remotePatch[proci].append(nbrPatchi);
localPatch[nbrProci].append(nbrPatchi);
remoteProc[nbrProci].append(proci);
remotePatch[nbrProci].append(patchi);
nNeighbourProcs[nbrProci]++;
}
}
}
//// Fill in the patch face ordering. Assume correct ordering.
//forAll(meshes, proci)
//{
// const polyBoundaryMesh& pbm = meshes[proci].boundaryMesh();
//
// const DynamicList& localPatches = localPatch[proci];
//
// labelListList& rpf = remotePatchFace[proci];
// rpf.setSize(localPatches.size());
//
// labelListList& rps = remotePatchFaceStart[proci];
// rps.setSize(localPatches.size());
//
// forAll(localPatches, i)
// {
// const auto& pp = pbm[localPatches[i]];
// rpf[i] = identity(pp.size());
// rps[i].setSize(pp.size(), 0);
// }
//}
return meshes[0].boundaryMesh().nNonProcessor();
}
void Foam::polyMeshAdder::patchFacePairs
(
const UPtrList& meshes,
const List>& localPatch,
const List>& remoteMesh,
const List>& remotePatch,
labelListList& localBoundaryFace,
labelListList& remoteFaceMesh,
labelListList& remoteBoundaryFace
)
{
// Calculates pairs of matching (boundary) faces. Returns
// localBoundaryFace[meshi] : index of local face (in boundary face
// indexing!)
// remoteMesh[meshi] : index of remote mesh
// remoteBoundaryFace[meshi] : index of remote face (in boundary face
// indexing!)
localBoundaryFace.setSize(meshes.size());
remoteFaceMesh.setSize(meshes.size());
remoteBoundaryFace.setSize(meshes.size());
forAll(meshes, meshi)
{
const auto& mesh = meshes[meshi];
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
const labelUList& procPatches = localPatch[meshi];
const labelUList& procNbrs = remoteMesh[meshi];
const labelUList& procNbrPatches = remotePatch[meshi];
// Count number of processor faces
label nFaces = 0;
for (const label patchi : procPatches)
{
nFaces += pbm[patchi].size();
}
labelList& procFaces = localBoundaryFace[meshi];
labelList& remoteMeshes = remoteFaceMesh[meshi];
labelList& remoteFaces = remoteBoundaryFace[meshi];
procFaces.setSize(nFaces);
remoteMeshes.setSize(nFaces);
remoteFaces.setSize(nFaces);
nFaces = 0;
forAll(procPatches, i)
{
const label patchi = procPatches[i];
const label nbrMeshi = procNbrs[i];
const label nbrPatchi = procNbrPatches[i];
const auto& pp = pbm[patchi];
const label offset = pp.start()-mesh.nInternalFaces();
const auto& nbrMesh = meshes[nbrMeshi];
const auto& nbrPp = nbrMesh.boundaryMesh()[nbrPatchi];
const label nbrOffset = nbrPp.start()-nbrMesh.nInternalFaces();
forAll(pp, patchFacei)
{
procFaces[nFaces] = offset+patchFacei;
remoteMeshes[nFaces] = nbrMeshi;
remoteFaces[nFaces] = nbrOffset+patchFacei;
nFaces++;
}
}
}
}
void Foam::polyMeshAdder::compactPoints
(
const UPtrList& meshes,
const labelListList& localBoundaryFace,
const labelListList& remoteFaceMesh,
const labelListList& remoteBoundaryFace,
const labelListList& remoteFaceStart,
const globalIndex& globalPoints,
labelListList& pointProcAddressing,
labelListList& localPoints
)
{
// Determines 'master' points for shared points. Returns
// pointProcAddressing[meshi] : global point for every mesh point
// localPoints[meshi] : indices of local points that are unique
// Choose minimum point for shared ones. Iterate minimising global points
// until nothing changes
while (true)
{
label nChanged = 0;
forAll(meshes, meshi)
{
if (meshes.set(meshi))
{
const polyMesh& mesh = meshes[meshi];
const faceList& faces = mesh.faces();
labelList& pAddressing = pointProcAddressing[meshi];
const labelList& localBFaces = localBoundaryFace[meshi];
const labelList& procNbrs = remoteFaceMesh[meshi];
const labelList& procNbrBFaces = remoteBoundaryFace[meshi];
const labelList& procNbrIndex = remoteFaceStart[meshi];
forAll(localBFaces, i)
{
const label bFacei = localBFaces[i];
const label nbrMeshi = procNbrs[i];
const label nbrBFacei = procNbrBFaces[i];
// Local mesh face
const label facei = mesh.nInternalFaces()+bFacei;
const face& f = faces[facei];
// Matched (remote) face
const auto& nbrMesh = meshes[nbrMeshi];
const label nbrFacei = nbrMesh.nInternalFaces()+nbrBFacei;
const face& nbrF = nbrMesh.faces()[nbrFacei];
labelList& nbrAddressing = pointProcAddressing[nbrMeshi];
// Starting index is indexed wrt matched, not original
// face. Check!
label nbrFp = procNbrIndex[i];
forAll(f, fp)
{
label& ppPointi = pAddressing[f[fp]];
label& nbrPointi = nbrAddressing[nbrF[nbrFp]];
//const point& pt = mesh.points()[f[fp]];
//const point& nbrPt = nbrMesh.points()[nbrF[nbrFp]];
//if (mag(pt-nbrPt) > SMALL)
//{
// FatalErrorInFunction
// << "Merging differing points :"
// << " pt:" << pt
// << " nbrPt:" << nbrPt
// << exit(FatalError);
//}
if (ppPointi < nbrPointi)
{
//Pout<< "on proc:" << nbrMeshi
// << " point:" << nbrF[nbrFp]
// << " changing from:" << nbrPointi
// << " to:" << ppPointi << endl;
nbrPointi = ppPointi;
nChanged++;
}
else if (nbrPointi < ppPointi)
{
//Pout<< "on proc:" << meshi
// << " point:" << f[fp]
// << " changing from:" << ppPointi
// << " to:" << nbrPointi << endl;
ppPointi = nbrPointi;
nChanged++;
}
nbrFp = nbrF.rcIndex(nbrFp);
}
}
}
}
if (nChanged == 0)
{
break;
}
}
// Compact out unused points
localPoints.setSize(meshes.size());
labelList globalToCompact(globalPoints.totalSize(), -1);
label nGlobal = 0;
forAll(meshes, meshi)
{
if (meshes.set(meshi))
{
const polyMesh& mesh = meshes[meshi];
labelList& compactPoints = localPoints[meshi];
compactPoints.setSize(mesh.nPoints());
label nCompact = 0;
const labelList& pAddressing = pointProcAddressing[meshi];
forAll(pAddressing, pointi)
{
//Pout<< "proc:" << meshi
// << " localpoint:" << pointi
// << " globalpoint:"
// << globalPoints.toGlobal(meshi, pointi)
// << " merged:" << pAddressing[pointi]
// << endl;
const label globali = globalPoints.toGlobal(meshi, pointi);
if (pAddressing[pointi] == globali)
{
// Unchanged address
globalToCompact[globali] = nGlobal++;
compactPoints[nCompact++] = pointi;
}
}
compactPoints.setSize(nCompact);
}
}
forAll(meshes, meshi)
{
labelList& pAddressing = pointProcAddressing[meshi];
pAddressing = UIndirectList(globalToCompact, pAddressing);
}
}
void Foam::polyMeshAdder::add
(
const UPtrList& meshes,
const UList& patchMap,
const labelListList& localBoundaryFace,
const labelListList& remoteFaceMesh,
const labelListList& remoteBoundaryFace,
const labelListList& remoteFaceStart,
const UList& pointZoneMap,
const UList& faceZoneMap,
const UList& cellZoneMap,
polyTopoChange& meshMod,
labelListList& cellProcAddressing,
labelListList& faceProcAddressing,
labelListList& pointProcAddressing
//labelListList& boundaryProcAddressing
)
{
cellProcAddressing.setSize(meshes.size());
faceProcAddressing.setSize(meshes.size());
pointProcAddressing.setSize(meshes.size());
//boundaryProcAddressing.setSize(meshes.size());
forAll(cellProcAddressing, meshi)
{
cellProcAddressing[meshi].clear();
faceProcAddressing[meshi].clear();
pointProcAddressing[meshi].clear();
}
// Start off with points allocated in processor order.
labelList offsets(meshes.size()+1);
offsets[0] = 0;
forAll(meshes, meshi)
{
label nPoints = 0;
if (meshes.set(meshi))
{
const polyMesh& mesh = meshes[meshi];
nPoints = mesh.nPoints();
}
pointProcAddressing[meshi] = identity(nPoints, offsets[meshi]);
offsets[meshi+1] = offsets[meshi]+nPoints;
}
const globalIndex globalPoints(std::move(offsets));
labelListList uniquePoints(meshes.size());
compactPoints
(
meshes,
localBoundaryFace,
remoteFaceMesh,
remoteBoundaryFace,
remoteFaceStart,
globalPoints,
pointProcAddressing, // per proc, per point the compact,global point
uniquePoints // per proc indices of local preserved points
);
// Add cells
// ~~~~~~~~~
// These are used by face adding later on
forAll(meshes, meshi)
{
if (meshes.set(meshi))
{
const polyMesh& mesh = meshes[meshi];
const cellZoneMesh& cellZones = mesh.cellZones();
// Add cells in mesh order
cellProcAddressing[meshi].setSize(mesh.nCells());
DynamicList zones;
for (label celli = 0; celli < mesh.nCells(); celli++)
{
// Get current zones and renumber
cellZones.whichZones(celli, zones);
inplaceRenumber(cellZoneMap[meshi], zones);
// Add cell from cell
cellProcAddressing[meshi][celli] = meshMod.addCell
(
-1,
-1,
-1,
celli,
zones
);
}
}
}
// Add points
// ~~~~~~~~~~
// These are used by face adding later on
forAll(meshes, meshi)
{
if (meshes.set(meshi))
{
const polyMesh& mesh = meshes[meshi];
const pointField& points = mesh.points();
const pointZoneMesh& pointZones = mesh.pointZones();
// Add points in mesh order
const labelList& myUniquePoints = uniquePoints[meshi];
DynamicList zones;
for (const label pointi : myUniquePoints)
{
// Get current zones and renumber
pointZones.whichZones(pointi, zones);
inplaceRenumber(pointZoneMap[meshi], zones);
// Rewrite the addressing (should already be compact) just in
// case the polyTopoChange does some special ordering
pointProcAddressing[meshi][pointi] = meshMod.addPoint
(
points[pointi],
pointi,
zones,
true
);
}
}
}
// Add faces
// ~~~~~~~~~
forAll(meshes, meshi)
{
if (meshes.set(meshi))
{
const polyMesh& mesh = meshes[meshi];
faceProcAddressing[meshi].setSize(mesh.nFaces());
faceProcAddressing[meshi] = -1;
//boundaryProcAddressing[meshi].setSize(mesh.boundaryMesh().size());
//boundaryProcAddressing[meshi] = -1;
}
}
forAll(meshes, meshi)
{
if (meshes.set(meshi))
{
const polyMesh& mesh = meshes[meshi];
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
const faceList& faces = mesh.faces();
const labelList& faceOwner = mesh.faceOwner();
const labelList& faceNeighbour = mesh.faceNeighbour();
const faceZoneMesh& faceZones = mesh.faceZones();
DynamicList zones;
DynamicList flips;
// Add faces in mesh order
// 1. Internal faces
face newFace;
for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
{
const face& f = faces[facei];
label newOwn = cellProcAddressing[meshi][faceOwner[facei]];
label newNei = cellProcAddressing[meshi][faceNeighbour[facei]];
newFace.setSize(f.size());
forAll(f, fp)
{
newFace[fp] = pointProcAddressing[meshi][f[fp]];
}
// Get current zones and renumber
faceZones.whichZones(facei, zones);
flips.clear();
forAll(zones, i)
{
const label zonei = zones[i];
const label index = faceZones[zonei].localID(facei);
flips.append(faceZones[zonei].flipMap()[index]);
}
inplaceRenumber(faceZoneMap[meshi], zones);
bool flipFaceFlux = false;
if (newNei < newOwn)
{
std::swap(newOwn, newNei);
newFace.flip();
flipFaceFlux = !flipFaceFlux;
for (bool& flip : flips)
{
flip = !flip;
}
}
const label newFacei = meshMod.addFace
(
newFace,
newOwn,
newNei,
-1, // masterPointID
-1, // masterEdgeID
facei, // masterFaceID
flipFaceFlux, // flipFaceFlux
-1, // patchID
zones, // zoneIDs
flips // zoneFlips
);
faceProcAddressing[meshi][facei] = newFacei;
}
// 1b. Owner side of coupled faces (since owner side cells are
// smallest)
const labelList& localBFaces = localBoundaryFace[meshi];
const labelList& procNbrs = remoteFaceMesh[meshi];
const labelList& procNbrBFaces = remoteBoundaryFace[meshi];
forAll(localBFaces, i)
{
const label bFacei = localBFaces[i];
const label nbrMeshi = procNbrs[i];
const label nbrBFacei = procNbrBFaces[i];
// Local mesh face
const label facei = mesh.nInternalFaces()+bFacei;
const face& f = mesh.faces()[facei];
const label newOwn =
cellProcAddressing[meshi][faceOwner[facei]];
faceZones.whichZones(facei, zones);
flips.clear();
forAll(zones, i)
{
const label zonei = zones[i];
const label index = faceZones[zonei].localID(facei);
flips.append(faceZones[zonei].flipMap()[index]);
}
inplaceRenumber(faceZoneMap[meshi], zones);
// Neighbour mesh face
const auto& nbrMesh = meshes[nbrMeshi];
const label nbrFacei = nbrMesh.nInternalFaces()+nbrBFacei;
const label nbrOwn = nbrMesh.faceOwner()[nbrFacei];
const label newNei = cellProcAddressing[nbrMeshi][nbrOwn];
//Pout<< "** connection between face:" << facei
// << " at:" << mesh.faceCentres()[facei]
// << " and nbrMesh:" << nbrMeshi
// << " nbrFacei:" << nbrMesh.faceCentres()[nbrFacei]
// << endl;
if (newOwn < newNei)
{
newFace.setSize(f.size());
forAll(f, fp)
{
newFace[fp] = pointProcAddressing[meshi][f[fp]];
}
const bool flipFaceFlux = false;
const label newFacei = meshMod.addFace
(
newFace,
newOwn,
newNei, // neighbour
-1, // masterPointID
-1, // masterEdgeID
facei, // masterFaceID
flipFaceFlux, // flipFaceFlux
-1, // patchID
zones, // zoneIDs
flips // zoneFlips
);
faceProcAddressing[meshi][facei] = newFacei;
faceProcAddressing[nbrMeshi][nbrFacei] = newFacei;
}
}
// 2. Remaining patch faces
forAll(pbm, patchi)
{
const auto& pp = pbm[patchi];
if (patchi < patchMap[meshi].size())
{
const label newPatchi = patchMap[meshi][patchi];
//boundaryProcAddressing[meshi][patchi] = newPatchi;
forAll(pp, patchFacei)
{
const label facei = pp.start() + patchFacei;
if (faceProcAddressing[meshi][facei] == -1)
{
const face& f = faces[facei];
const label newOwn =
cellProcAddressing[meshi][faceOwner[facei]];
newFace.setSize(f.size());
forAll(f, fp)
{
newFace[fp] = pointProcAddressing[meshi][f[fp]];
}
faceZones.whichZones(facei, zones);
flips.clear();
forAll(zones, i)
{
const label zonei = zones[i];
const label index =
faceZones[zonei].localID(facei);
flips.append(faceZones[zonei].flipMap()[index]);
}
inplaceRenumber(faceZoneMap[meshi], zones);
const label newFacei = meshMod.addFace
(
newFace,
newOwn,
-1, // neighbour
-1, // masterPointID
-1, // masterEdgeID
facei, // masterFaceID
false, // flipFaceFlux
newPatchi, // patchID
zones, // zoneID
flips // zoneFlip
);
faceProcAddressing[meshi][facei] = newFacei;
}
}
}
}
}
}
}
// ************************************************************************* //