lagrangian: Support meshToMesh mapping
Lagrangian is now compatible with the meshToMesh topology changer. If a cloud is being simulated and this topology changer is active, then the cloud data will be automatically mapped between the specified sequence of meshes in the same way as the finite volume data. This works both for serial and parallel simulations. In addition, mapFieldsPar now also supports mapping of Lagrangian data when run in parallel.
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
mapLagrangian.C
|
mapLagrangian.C
|
||||||
mapMeshes.C
|
mapMeshes.C
|
||||||
mapFields.C
|
mapFields.C
|
||||||
|
meshToMesh0.C
|
||||||
|
|
||||||
EXE = $(FOAM_APPBIN)/mapFields
|
EXE = $(FOAM_APPBIN)/mapFields
|
||||||
|
|||||||
@ -2,12 +2,10 @@ EXE_INC = \
|
|||||||
-I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
|
-I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
|
||||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||||
-I$(LIB_SRC)/lagrangian/basic/lnInclude \
|
-I$(LIB_SRC)/lagrangian/basic/lnInclude \
|
||||||
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
-I$(LIB_SRC)/finiteVolume/lnInclude
|
||||||
-I$(LIB_SRC)/sampling/lnInclude
|
|
||||||
|
|
||||||
EXE_LIBS = \
|
EXE_LIBS = \
|
||||||
-ldecompositionMethods \
|
-ldecompositionMethods \
|
||||||
-lsampling \
|
|
||||||
-lmeshTools \
|
-lmeshTools \
|
||||||
-llagrangian \
|
-llagrangian \
|
||||||
-lfiniteVolume \
|
-lfiniteVolume \
|
||||||
|
|||||||
762
applications/utilities/preProcessing/mapFields/meshToMesh0.C
Normal file
762
applications/utilities/preProcessing/mapFields/meshToMesh0.C
Normal file
@ -0,0 +1,762 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "meshToMesh0.H"
|
||||||
|
#include "processorFvPatch.H"
|
||||||
|
#include "demandDrivenData.H"
|
||||||
|
#include "treeDataCell.H"
|
||||||
|
#include "treeDataFace.H"
|
||||||
|
#include "tetOverlapVolume.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(meshToMesh0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Foam::scalar Foam::meshToMesh0::directHitTol = 1e-5;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh0::calcAddressing()
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
InfoInFunction
|
||||||
|
<< "Calculating mesh-to-mesh cell addressing" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set reference to cells
|
||||||
|
const cellList& fromCells = fromMesh_.cells();
|
||||||
|
const pointField& fromPoints = fromMesh_.points();
|
||||||
|
|
||||||
|
// In an attempt to preserve the efficiency of linear search and prevent
|
||||||
|
// failure, a RESCUE mechanism will be set up. Here, we shall mark all
|
||||||
|
// cells next to the solid boundaries. If such a cell is found as the
|
||||||
|
// closest, the relationship between the origin and cell will be examined.
|
||||||
|
// If the origin is outside the cell, a global n-squared search is
|
||||||
|
// triggered.
|
||||||
|
|
||||||
|
// SETTING UP RESCUE
|
||||||
|
|
||||||
|
// Visit all boundaries and mark the cell next to the boundary.
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
InfoInFunction << "Setting up rescue" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<bool> boundaryCell(fromCells.size(), false);
|
||||||
|
|
||||||
|
// Set reference to boundary
|
||||||
|
const polyPatchList& patchesFrom = fromMesh_.boundaryMesh();
|
||||||
|
|
||||||
|
forAll(patchesFrom, patchi)
|
||||||
|
{
|
||||||
|
// Get reference to cells next to the boundary
|
||||||
|
const labelUList& bCells = patchesFrom[patchi].faceCells();
|
||||||
|
|
||||||
|
forAll(bCells, facei)
|
||||||
|
{
|
||||||
|
boundaryCell[bCells[facei]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
treeBoundBox meshBb(fromPoints);
|
||||||
|
|
||||||
|
scalar typDim = meshBb.avgDim()/(2.0*cbrt(scalar(fromCells.size())));
|
||||||
|
|
||||||
|
treeBoundBox shiftedBb
|
||||||
|
(
|
||||||
|
meshBb.min(),
|
||||||
|
meshBb.max() + vector(typDim, typDim, typDim)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
Info<< "\nMesh\n"
|
||||||
|
<< " bounding box : " << meshBb << nl
|
||||||
|
<< " bounding box (shifted) : " << shiftedBb << nl
|
||||||
|
<< " typical dimension :" << shiftedBb.typDim() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexedOctree<treeDataCell> oc
|
||||||
|
(
|
||||||
|
treeDataCell(false, fromMesh_, polyMesh::CELL_TETS),
|
||||||
|
shiftedBb, // overall bounding box
|
||||||
|
8, // maxLevel
|
||||||
|
10, // leafsize
|
||||||
|
6.0 // duplicity
|
||||||
|
);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
oc.print(Pout, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
cellAddresses
|
||||||
|
(
|
||||||
|
cellAddressing_,
|
||||||
|
toMesh_.cellCentres(),
|
||||||
|
fromMesh_,
|
||||||
|
boundaryCell,
|
||||||
|
oc
|
||||||
|
);
|
||||||
|
|
||||||
|
forAll(toMesh_.boundaryMesh(), patchi)
|
||||||
|
{
|
||||||
|
const polyPatch& toPatch = toMesh_.boundaryMesh()[patchi];
|
||||||
|
|
||||||
|
if (cuttingPatches_.found(toPatch.name()))
|
||||||
|
{
|
||||||
|
boundaryAddressing_[patchi].setSize(toPatch.size());
|
||||||
|
|
||||||
|
cellAddresses
|
||||||
|
(
|
||||||
|
boundaryAddressing_[patchi],
|
||||||
|
toPatch.faceCentres(),
|
||||||
|
fromMesh_,
|
||||||
|
boundaryCell,
|
||||||
|
oc
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if
|
||||||
|
(
|
||||||
|
patchMap_.found(toPatch.name())
|
||||||
|
&& fromMeshPatches_.found(patchMap_.find(toPatch.name())())
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const polyPatch& fromPatch = fromMesh_.boundaryMesh()
|
||||||
|
[
|
||||||
|
fromMeshPatches_.find(patchMap_.find(toPatch.name())())()
|
||||||
|
];
|
||||||
|
|
||||||
|
if (fromPatch.empty())
|
||||||
|
{
|
||||||
|
WarningInFunction
|
||||||
|
<< "Source patch " << fromPatch.name()
|
||||||
|
<< " has no faces. Not performing mapping for it."
|
||||||
|
<< endl;
|
||||||
|
boundaryAddressing_[patchi].setSize(toPatch.size());
|
||||||
|
boundaryAddressing_[patchi] = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
treeBoundBox wallBb(fromPatch.localPoints());
|
||||||
|
scalar typDim =
|
||||||
|
wallBb.avgDim()/(2.0*sqrt(scalar(fromPatch.size())));
|
||||||
|
|
||||||
|
treeBoundBox shiftedBb
|
||||||
|
(
|
||||||
|
wallBb.min(),
|
||||||
|
wallBb.max() + vector(typDim, typDim, typDim)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Note: allow more levels than in meshSearch. Assume patch
|
||||||
|
// is not as big as all boundary faces
|
||||||
|
indexedOctree<treeDataFace> oc
|
||||||
|
(
|
||||||
|
treeDataFace(false, fromPatch),
|
||||||
|
shiftedBb, // overall search domain
|
||||||
|
12, // maxLevel
|
||||||
|
10, // leafsize
|
||||||
|
6.0 // duplicity
|
||||||
|
);
|
||||||
|
|
||||||
|
const vectorField::subField centresToBoundary =
|
||||||
|
toPatch.faceCentres();
|
||||||
|
|
||||||
|
boundaryAddressing_[patchi].setSize(toPatch.size());
|
||||||
|
|
||||||
|
const scalar distSqr = sqr(wallBb.mag());
|
||||||
|
|
||||||
|
forAll(toPatch, toi)
|
||||||
|
{
|
||||||
|
boundaryAddressing_[patchi][toi] = oc.findNearest
|
||||||
|
(
|
||||||
|
centresToBoundary[toi],
|
||||||
|
distSqr
|
||||||
|
).index();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
InfoInFunction
|
||||||
|
<< "Finished calculating mesh-to-mesh cell addressing" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh0::cellAddresses
|
||||||
|
(
|
||||||
|
labelList& cellAddressing_,
|
||||||
|
const pointField& points,
|
||||||
|
const fvMesh& fromMesh,
|
||||||
|
const List<bool>& boundaryCell,
|
||||||
|
const indexedOctree<treeDataCell>& oc
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// The implemented search method is a simple neighbour array search.
|
||||||
|
// It starts from a cell zero, searches its neighbours and finds one
|
||||||
|
// which is nearer to the target point than the current position.
|
||||||
|
// The location of the "current position" is reset to that cell and
|
||||||
|
// search through the neighbours continues. The search is finished
|
||||||
|
// when all the neighbours of the cell are farther from the target
|
||||||
|
// point than the current cell
|
||||||
|
|
||||||
|
// Set curCell label to zero (start)
|
||||||
|
label curCell = 0;
|
||||||
|
|
||||||
|
// Set reference to cell to cell addressing
|
||||||
|
const vectorField& centresFrom = fromMesh.cellCentres();
|
||||||
|
const labelListList& cc = fromMesh.cellCells();
|
||||||
|
|
||||||
|
forAll(points, toi)
|
||||||
|
{
|
||||||
|
// Pick up target position
|
||||||
|
const vector& p = points[toi];
|
||||||
|
|
||||||
|
// Set the sqr-distance
|
||||||
|
scalar distSqr = magSqr(p - centresFrom[curCell]);
|
||||||
|
|
||||||
|
bool closer;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
closer = false;
|
||||||
|
|
||||||
|
// Set the current list of neighbouring cells
|
||||||
|
const labelList& neighbours = cc[curCell];
|
||||||
|
|
||||||
|
forAll(neighbours, ni)
|
||||||
|
{
|
||||||
|
const scalar curDistSqr =
|
||||||
|
magSqr(p - centresFrom[neighbours[ni]]);
|
||||||
|
|
||||||
|
// Search through all the neighbours.
|
||||||
|
// If the cell is closer, reset current cell and distance
|
||||||
|
if (curDistSqr < (1 - small)*distSqr)
|
||||||
|
{
|
||||||
|
curCell = neighbours[ni];
|
||||||
|
distSqr = curDistSqr;
|
||||||
|
closer = true; // A closer neighbour has been found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (closer);
|
||||||
|
|
||||||
|
cellAddressing_[toi] = -1;
|
||||||
|
|
||||||
|
// Check point is actually in the nearest cell
|
||||||
|
if (fromMesh.pointInCell(p, curCell))
|
||||||
|
{
|
||||||
|
cellAddressing_[toi] = curCell;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If curCell is a boundary cell then the point maybe either outside
|
||||||
|
// the domain or in an other region of the doamin, either way use
|
||||||
|
// the octree search to find it.
|
||||||
|
if (boundaryCell[curCell])
|
||||||
|
{
|
||||||
|
cellAddressing_[toi] = oc.findInside(p);
|
||||||
|
if (cellAddressing_[toi] != -1)
|
||||||
|
{
|
||||||
|
curCell = cellAddressing_[toi];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If not on the boundary search the neighbours
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
// Set the current list of neighbouring cells
|
||||||
|
const labelList& neighbours = cc[curCell];
|
||||||
|
|
||||||
|
forAll(neighbours, ni)
|
||||||
|
{
|
||||||
|
// Search through all the neighbours.
|
||||||
|
// If point is in neighbour reset current cell
|
||||||
|
if (fromMesh.pointInCell(p, neighbours[ni]))
|
||||||
|
{
|
||||||
|
cellAddressing_[toi] = neighbours[ni];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
// If still not found search the neighbour-neighbours
|
||||||
|
|
||||||
|
// Set the current list of neighbouring cells
|
||||||
|
const labelList& neighbours = cc[curCell];
|
||||||
|
|
||||||
|
forAll(neighbours, ni)
|
||||||
|
{
|
||||||
|
// Set the current list of neighbour-neighbouring cells
|
||||||
|
const labelList& nn = cc[neighbours[ni]];
|
||||||
|
|
||||||
|
forAll(nn, ni)
|
||||||
|
{
|
||||||
|
// Search through all the neighbours.
|
||||||
|
// If point is in neighbour reset current cell
|
||||||
|
if (fromMesh.pointInCell(p, nn[ni]))
|
||||||
|
{
|
||||||
|
cellAddressing_[toi] = nn[ni];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
// Still not found so use the octree
|
||||||
|
cellAddressing_[toi] = oc.findInside(p);
|
||||||
|
|
||||||
|
if (cellAddressing_[toi] != -1)
|
||||||
|
{
|
||||||
|
curCell = cellAddressing_[toi];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh0::calculateInverseDistanceWeights() const
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
InfoInFunction
|
||||||
|
<< "Calculating inverse distance weighting factors" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inverseDistanceWeightsPtr_)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "weighting factors already calculated"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Initialise overlap volume to zero
|
||||||
|
V_ = 0.0;
|
||||||
|
|
||||||
|
inverseDistanceWeightsPtr_ = new scalarListList(toMesh_.nCells());
|
||||||
|
scalarListList& invDistCoeffs = *inverseDistanceWeightsPtr_;
|
||||||
|
|
||||||
|
// get reference to source mesh data
|
||||||
|
const labelListList& cc = fromMesh_.cellCells();
|
||||||
|
const vectorField& centreFrom = fromMesh_.C();
|
||||||
|
const vectorField& centreTo = toMesh_.C();
|
||||||
|
|
||||||
|
forAll(cellAddressing_, celli)
|
||||||
|
{
|
||||||
|
if (cellAddressing_[celli] != -1)
|
||||||
|
{
|
||||||
|
const vector& target = centreTo[celli];
|
||||||
|
scalar m = mag(target - centreFrom[cellAddressing_[celli]]);
|
||||||
|
|
||||||
|
const labelList& neighbours = cc[cellAddressing_[celli]];
|
||||||
|
|
||||||
|
// if the nearest cell is a boundary cell or there is a direct hit,
|
||||||
|
// pick up the value
|
||||||
|
label directCelli = -1;
|
||||||
|
if (m < directHitTol || neighbours.empty())
|
||||||
|
{
|
||||||
|
directCelli = celli;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
forAll(neighbours, ni)
|
||||||
|
{
|
||||||
|
scalar nm = mag(target - centreFrom[neighbours[ni]]);
|
||||||
|
if (nm < directHitTol)
|
||||||
|
{
|
||||||
|
directCelli = neighbours[ni];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (directCelli != -1)
|
||||||
|
{
|
||||||
|
// Direct hit
|
||||||
|
invDistCoeffs[directCelli].setSize(1);
|
||||||
|
invDistCoeffs[directCelli][0] = 1.0;
|
||||||
|
V_ += fromMesh_.V()[cellAddressing_[directCelli]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
invDistCoeffs[celli].setSize(neighbours.size() + 1);
|
||||||
|
|
||||||
|
// The first coefficient corresponds to the centre cell.
|
||||||
|
// The rest is ordered in the same way as the cellCells list.
|
||||||
|
scalar invDist = 1.0/m;
|
||||||
|
invDistCoeffs[celli][0] = invDist;
|
||||||
|
scalar sumInvDist = invDist;
|
||||||
|
|
||||||
|
// now add the neighbours
|
||||||
|
forAll(neighbours, ni)
|
||||||
|
{
|
||||||
|
invDist = 1.0/mag(target - centreFrom[neighbours[ni]]);
|
||||||
|
invDistCoeffs[celli][ni + 1] = invDist;
|
||||||
|
sumInvDist += invDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
// divide by the total inverse-distance
|
||||||
|
forAll(invDistCoeffs[celli], i)
|
||||||
|
{
|
||||||
|
invDistCoeffs[celli][i] /= sumInvDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
V_ +=
|
||||||
|
invDistCoeffs[celli][0]
|
||||||
|
*fromMesh_.V()[cellAddressing_[celli]];
|
||||||
|
for (label i = 1; i < invDistCoeffs[celli].size(); i++)
|
||||||
|
{
|
||||||
|
V_ +=
|
||||||
|
invDistCoeffs[celli][i]*fromMesh_.V()[neighbours[i-1]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh0::calculateInverseVolumeWeights() const
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
InfoInFunction
|
||||||
|
<< "Calculating inverse volume weighting factors" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inverseVolumeWeightsPtr_)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "weighting factors already calculated"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Initialise overlap volume to zero
|
||||||
|
V_ = 0.0;
|
||||||
|
|
||||||
|
inverseVolumeWeightsPtr_ = new scalarListList(toMesh_.nCells());
|
||||||
|
scalarListList& invVolCoeffs = *inverseVolumeWeightsPtr_;
|
||||||
|
|
||||||
|
const labelListList& cellToCell = cellToCellAddressing();
|
||||||
|
|
||||||
|
tetOverlapVolume overlapEngine;
|
||||||
|
|
||||||
|
forAll(cellToCell, celli)
|
||||||
|
{
|
||||||
|
const labelList& overlapCells = cellToCell[celli];
|
||||||
|
|
||||||
|
if (overlapCells.size() > 0)
|
||||||
|
{
|
||||||
|
invVolCoeffs[celli].setSize(overlapCells.size());
|
||||||
|
|
||||||
|
forAll(overlapCells, j)
|
||||||
|
{
|
||||||
|
label cellFrom = overlapCells[j];
|
||||||
|
treeBoundBox bbFromMesh
|
||||||
|
(
|
||||||
|
pointField
|
||||||
|
(
|
||||||
|
fromMesh_.points(),
|
||||||
|
fromMesh_.cellPoints()[cellFrom]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
scalar v = overlapEngine.cellCellOverlapVolumeMinDecomp
|
||||||
|
(
|
||||||
|
toMesh_,
|
||||||
|
celli,
|
||||||
|
|
||||||
|
fromMesh_,
|
||||||
|
cellFrom,
|
||||||
|
bbFromMesh
|
||||||
|
);
|
||||||
|
invVolCoeffs[celli][j] = v/toMesh_.V()[celli];
|
||||||
|
|
||||||
|
V_ += v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh0::calculateCellToCellAddressing() const
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
InfoInFunction
|
||||||
|
<< "Calculating cell to cell addressing" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cellToCellAddressingPtr_)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "addressing already calculated"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Initialise overlap volume to zero
|
||||||
|
V_ = 0.0;
|
||||||
|
|
||||||
|
tetOverlapVolume overlapEngine;
|
||||||
|
|
||||||
|
cellToCellAddressingPtr_ = new labelListList(toMesh_.nCells());
|
||||||
|
labelListList& cellToCell = *cellToCellAddressingPtr_;
|
||||||
|
|
||||||
|
|
||||||
|
forAll(cellToCell, iTo)
|
||||||
|
{
|
||||||
|
const labelList overLapCells =
|
||||||
|
overlapEngine.overlappingCells(fromMesh_, toMesh_, iTo);
|
||||||
|
if (overLapCells.size() > 0)
|
||||||
|
{
|
||||||
|
cellToCell[iTo].setSize(overLapCells.size());
|
||||||
|
forAll(overLapCells, j)
|
||||||
|
{
|
||||||
|
cellToCell[iTo][j] = overLapCells[j];
|
||||||
|
V_ += fromMesh_.V()[overLapCells[j]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::meshToMesh0::meshToMesh0
|
||||||
|
(
|
||||||
|
const fvMesh& meshFrom,
|
||||||
|
const fvMesh& meshTo,
|
||||||
|
const HashTable<word>& patchMap,
|
||||||
|
const wordList& cuttingPatchNames
|
||||||
|
)
|
||||||
|
:
|
||||||
|
fromMesh_(meshFrom),
|
||||||
|
toMesh_(meshTo),
|
||||||
|
patchMap_(patchMap),
|
||||||
|
cellAddressing_(toMesh_.nCells()),
|
||||||
|
boundaryAddressing_(toMesh_.boundaryMesh().size()),
|
||||||
|
inverseDistanceWeightsPtr_(nullptr),
|
||||||
|
inverseVolumeWeightsPtr_(nullptr),
|
||||||
|
cellToCellAddressingPtr_(nullptr),
|
||||||
|
V_(0.0)
|
||||||
|
{
|
||||||
|
forAll(fromMesh_.boundaryMesh(), patchi)
|
||||||
|
{
|
||||||
|
fromMeshPatches_.insert
|
||||||
|
(
|
||||||
|
fromMesh_.boundaryMesh()[patchi].name(),
|
||||||
|
patchi
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(toMesh_.boundaryMesh(), patchi)
|
||||||
|
{
|
||||||
|
toMeshPatches_.insert
|
||||||
|
(
|
||||||
|
toMesh_.boundaryMesh()[patchi].name(),
|
||||||
|
patchi
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(cuttingPatchNames, i)
|
||||||
|
{
|
||||||
|
if (toMeshPatches_.found(cuttingPatchNames[i]))
|
||||||
|
{
|
||||||
|
cuttingPatches_.insert
|
||||||
|
(
|
||||||
|
cuttingPatchNames[i],
|
||||||
|
toMeshPatches_.find(cuttingPatchNames[i])()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WarningInFunction
|
||||||
|
<< "Cannot find cutting-patch " << cuttingPatchNames[i]
|
||||||
|
<< " in destination mesh" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(toMesh_.boundaryMesh(), patchi)
|
||||||
|
{
|
||||||
|
// Add the processor patches in the toMesh to the cuttingPatches list
|
||||||
|
if (isA<processorPolyPatch>(toMesh_.boundaryMesh()[patchi]))
|
||||||
|
{
|
||||||
|
cuttingPatches_.insert
|
||||||
|
(
|
||||||
|
toMesh_.boundaryMesh()[patchi].name(),
|
||||||
|
patchi
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calcAddressing();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::meshToMesh0::meshToMesh0
|
||||||
|
(
|
||||||
|
const fvMesh& meshFrom,
|
||||||
|
const fvMesh& meshTo
|
||||||
|
)
|
||||||
|
:
|
||||||
|
fromMesh_(meshFrom),
|
||||||
|
toMesh_(meshTo),
|
||||||
|
cellAddressing_(toMesh_.nCells()),
|
||||||
|
boundaryAddressing_(toMesh_.boundaryMesh().size()),
|
||||||
|
inverseDistanceWeightsPtr_(nullptr),
|
||||||
|
inverseVolumeWeightsPtr_(nullptr),
|
||||||
|
cellToCellAddressingPtr_(nullptr),
|
||||||
|
V_(0.0)
|
||||||
|
{
|
||||||
|
// check whether both meshes have got the same number
|
||||||
|
// of boundary patches
|
||||||
|
if (fromMesh_.boundary().size() != toMesh_.boundary().size())
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Incompatible meshes: different number of patches, "
|
||||||
|
<< "fromMesh = " << fromMesh_.boundary().size()
|
||||||
|
<< ", toMesh = " << toMesh_.boundary().size()
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(fromMesh_.boundaryMesh(), patchi)
|
||||||
|
{
|
||||||
|
if
|
||||||
|
(
|
||||||
|
fromMesh_.boundaryMesh()[patchi].name()
|
||||||
|
!= toMesh_.boundaryMesh()[patchi].name()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Incompatible meshes: different patch names for patch "
|
||||||
|
<< patchi
|
||||||
|
<< ", fromMesh = " << fromMesh_.boundary()[patchi].name()
|
||||||
|
<< ", toMesh = " << toMesh_.boundary()[patchi].name()
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if
|
||||||
|
(
|
||||||
|
fromMesh_.boundaryMesh()[patchi].type()
|
||||||
|
!= toMesh_.boundaryMesh()[patchi].type()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Incompatible meshes: different patch types for patch "
|
||||||
|
<< patchi
|
||||||
|
<< ", fromMesh = " << fromMesh_.boundary()[patchi].type()
|
||||||
|
<< ", toMesh = " << toMesh_.boundary()[patchi].type()
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
fromMeshPatches_.insert
|
||||||
|
(
|
||||||
|
fromMesh_.boundaryMesh()[patchi].name(),
|
||||||
|
patchi
|
||||||
|
);
|
||||||
|
|
||||||
|
toMeshPatches_.insert
|
||||||
|
(
|
||||||
|
toMesh_.boundaryMesh()[patchi].name(),
|
||||||
|
patchi
|
||||||
|
);
|
||||||
|
|
||||||
|
patchMap_.insert
|
||||||
|
(
|
||||||
|
toMesh_.boundaryMesh()[patchi].name(),
|
||||||
|
fromMesh_.boundaryMesh()[patchi].name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
calcAddressing();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::meshToMesh0::~meshToMesh0()
|
||||||
|
{
|
||||||
|
deleteDemandDrivenData(inverseDistanceWeightsPtr_);
|
||||||
|
deleteDemandDrivenData(inverseVolumeWeightsPtr_);
|
||||||
|
deleteDemandDrivenData(cellToCellAddressingPtr_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
const Foam::scalarListList& Foam::meshToMesh0::inverseDistanceWeights() const
|
||||||
|
{
|
||||||
|
if (!inverseDistanceWeightsPtr_)
|
||||||
|
{
|
||||||
|
calculateInverseDistanceWeights();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *inverseDistanceWeightsPtr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Foam::scalarListList& Foam::meshToMesh0::inverseVolumeWeights() const
|
||||||
|
{
|
||||||
|
if (!inverseVolumeWeightsPtr_)
|
||||||
|
{
|
||||||
|
calculateInverseVolumeWeights();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *inverseVolumeWeightsPtr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Foam::labelListList& Foam::meshToMesh0::cellToCellAddressing() const
|
||||||
|
{
|
||||||
|
if (!cellToCellAddressingPtr_)
|
||||||
|
{
|
||||||
|
calculateCellToCellAddressing();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *cellToCellAddressingPtr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -1,5 +1,5 @@
|
|||||||
mapMeshes.C
|
mapGeometricFields.C
|
||||||
mapLagrangian.C
|
mapClouds.C
|
||||||
mapFieldsPar.C
|
mapFieldsPar.C
|
||||||
|
|
||||||
EXE = $(FOAM_APPBIN)/mapFieldsPar
|
EXE = $(FOAM_APPBIN)/mapFieldsPar
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
EXE_INC = \
|
EXE_INC = \
|
||||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||||
-I$(LIB_SRC)/lagrangian/basic/lnInclude \
|
-I$(LIB_SRC)/lagrangian/basic/lnInclude \
|
||||||
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
-I$(LIB_SRC)/finiteVolume/lnInclude
|
||||||
-I$(LIB_SRC)/sampling/lnInclude
|
|
||||||
|
|
||||||
EXE_LIBS = \
|
EXE_LIBS = \
|
||||||
-lsampling \
|
|
||||||
-lmeshTools \
|
-lmeshTools \
|
||||||
-llagrangian \
|
-llagrangian \
|
||||||
-lfiniteVolume \
|
-lfiniteVolume \
|
||||||
|
|||||||
@ -1,184 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
InNamespace
|
|
||||||
Foam
|
|
||||||
|
|
||||||
Description
|
|
||||||
Gets the indices of (source)particles that have been appended to the
|
|
||||||
target cloud and maps the lagrangian fields accordingly.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef MapLagrangianFields_H
|
|
||||||
#define MapLagrangianFields_H
|
|
||||||
|
|
||||||
#include "cloud.H"
|
|
||||||
#include "GeometricField.H"
|
|
||||||
#include "meshToMesh.H"
|
|
||||||
#include "IOobjectList.H"
|
|
||||||
#include "CompactIOField.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
namespace Foam
|
|
||||||
{
|
|
||||||
|
|
||||||
//- Gets the indices of (source)particles that have been appended to the
|
|
||||||
// target cloud and maps the lagrangian fields accordingly.
|
|
||||||
template<class Type>
|
|
||||||
void MapLagrangianFields
|
|
||||||
(
|
|
||||||
const string& cloudName,
|
|
||||||
const IOobjectList& objects,
|
|
||||||
const polyMesh& meshTarget,
|
|
||||||
const labelList& addParticles
|
|
||||||
)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
IOobjectList fields = objects.lookupClass(IOField<Type>::typeName);
|
|
||||||
|
|
||||||
forAllIter(IOobjectList, fields, fieldIter)
|
|
||||||
{
|
|
||||||
const word& fieldName = fieldIter()->name();
|
|
||||||
|
|
||||||
Info<< " mapping lagrangian field " << fieldName << endl;
|
|
||||||
|
|
||||||
// Read field (does not need mesh)
|
|
||||||
IOField<Type> fieldSource(*fieldIter());
|
|
||||||
|
|
||||||
// Map
|
|
||||||
IOField<Type> fieldTarget
|
|
||||||
(
|
|
||||||
IOobject
|
|
||||||
(
|
|
||||||
fieldName,
|
|
||||||
meshTarget.time().timeName(),
|
|
||||||
cloud::prefix/cloudName,
|
|
||||||
meshTarget,
|
|
||||||
IOobject::NO_READ,
|
|
||||||
IOobject::NO_WRITE,
|
|
||||||
false
|
|
||||||
),
|
|
||||||
addParticles.size()
|
|
||||||
);
|
|
||||||
|
|
||||||
forAll(addParticles, i)
|
|
||||||
{
|
|
||||||
fieldTarget[i] = fieldSource[addParticles[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write field
|
|
||||||
fieldTarget.write();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
IOobjectList fieldFields =
|
|
||||||
objects.lookupClass(IOField<Field<Type>>::typeName);
|
|
||||||
|
|
||||||
forAllIter(IOobjectList, fieldFields, fieldIter)
|
|
||||||
{
|
|
||||||
const word& fieldName = fieldIter()->name();
|
|
||||||
|
|
||||||
Info<< " mapping lagrangian fieldField " << fieldName << endl;
|
|
||||||
|
|
||||||
// Read field (does not need mesh)
|
|
||||||
IOField<Field<Type>> fieldSource(*fieldIter());
|
|
||||||
|
|
||||||
// Map - use CompactIOField to automatically write in
|
|
||||||
// compact form for binary format.
|
|
||||||
CompactIOField<Field<Type>> fieldTarget
|
|
||||||
(
|
|
||||||
IOobject
|
|
||||||
(
|
|
||||||
fieldName,
|
|
||||||
meshTarget.time().timeName(),
|
|
||||||
cloud::prefix/cloudName,
|
|
||||||
meshTarget,
|
|
||||||
IOobject::NO_READ,
|
|
||||||
IOobject::NO_WRITE,
|
|
||||||
false
|
|
||||||
),
|
|
||||||
addParticles.size()
|
|
||||||
);
|
|
||||||
|
|
||||||
forAll(addParticles, i)
|
|
||||||
{
|
|
||||||
fieldTarget[i] = fieldSource[addParticles[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write field
|
|
||||||
fieldTarget.write();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
IOobjectList fieldFields =
|
|
||||||
objects.lookupClass(CompactIOField<Field<Type>>::typeName);
|
|
||||||
|
|
||||||
forAllIter(IOobjectList, fieldFields, fieldIter)
|
|
||||||
{
|
|
||||||
Info<< " mapping lagrangian fieldField "
|
|
||||||
<< fieldIter()->name() << endl;
|
|
||||||
|
|
||||||
// Read field (does not need mesh)
|
|
||||||
CompactIOField<Field<Type>> fieldSource(*fieldIter());
|
|
||||||
|
|
||||||
// Map
|
|
||||||
CompactIOField<Field<Type>> fieldTarget
|
|
||||||
(
|
|
||||||
IOobject
|
|
||||||
(
|
|
||||||
fieldIter()->name(),
|
|
||||||
meshTarget.time().timeName(),
|
|
||||||
cloud::prefix/cloudName,
|
|
||||||
meshTarget,
|
|
||||||
IOobject::NO_READ,
|
|
||||||
IOobject::NO_WRITE,
|
|
||||||
false
|
|
||||||
),
|
|
||||||
addParticles.size()
|
|
||||||
);
|
|
||||||
|
|
||||||
forAll(addParticles, i)
|
|
||||||
{
|
|
||||||
fieldTarget[i] = fieldSource[addParticles[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write field
|
|
||||||
fieldTarget.write();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
} // End namespace Foam
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
287
applications/utilities/preProcessing/mapFieldsPar/mapClouds.C
Normal file
287
applications/utilities/preProcessing/mapFieldsPar/mapClouds.C
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "mapClouds.H"
|
||||||
|
#include "fvMeshToFvMesh.H"
|
||||||
|
#include "IOobjectList.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
#include "passiveParticleCloud.H"
|
||||||
|
#include "patchToPatchTools.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
List<Type> gatherAndFlatten(const List<Type>& l)
|
||||||
|
{
|
||||||
|
List<List<Type>> procLs(Pstream::nProcs());
|
||||||
|
procLs[Pstream::myProcNo()] = l;
|
||||||
|
|
||||||
|
Pstream::gatherList(procLs);
|
||||||
|
Pstream::scatterList(procLs);
|
||||||
|
|
||||||
|
return
|
||||||
|
HashSet<Type>
|
||||||
|
(
|
||||||
|
ListListOps::combine<List<Type>>
|
||||||
|
(
|
||||||
|
procLs,
|
||||||
|
accessOp<List<Type>>()
|
||||||
|
)
|
||||||
|
).sortedToc();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class ReadIOField, class WriteIOField>
|
||||||
|
void mapCloudTypeFields
|
||||||
|
(
|
||||||
|
const fileName& cloudDir,
|
||||||
|
const IOobjectList& objects,
|
||||||
|
const polyMesh& srcMesh,
|
||||||
|
const polyMesh& tgtMesh,
|
||||||
|
const distributionMap& map
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const wordList fieldNames =
|
||||||
|
gatherAndFlatten(objects.lookupClass(ReadIOField::typeName).names());
|
||||||
|
|
||||||
|
forAll(fieldNames, fieldi)
|
||||||
|
{
|
||||||
|
const word& fieldName = fieldNames[fieldi];
|
||||||
|
|
||||||
|
Info<< " mapping lagrangian field " << fieldName << endl;
|
||||||
|
|
||||||
|
const IOobject* fieldIOPtr = objects.lookup(fieldName);
|
||||||
|
|
||||||
|
// Read the field
|
||||||
|
ReadIOField field
|
||||||
|
(
|
||||||
|
fieldIOPtr != nullptr
|
||||||
|
? *fieldIOPtr
|
||||||
|
: IOobject
|
||||||
|
(
|
||||||
|
fieldName,
|
||||||
|
srcMesh.time().timeName(),
|
||||||
|
cloud::prefix/cloudDir,
|
||||||
|
srcMesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Distribute the field
|
||||||
|
map.distribute(field);
|
||||||
|
|
||||||
|
// Write it out into the target case
|
||||||
|
if (field.size())
|
||||||
|
{
|
||||||
|
WriteIOField
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
fieldName,
|
||||||
|
tgtMesh.time().timeName(),
|
||||||
|
cloud::prefix/cloudDir,
|
||||||
|
tgtMesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE,
|
||||||
|
false
|
||||||
|
),
|
||||||
|
move(field)
|
||||||
|
).write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
void mapCloudTypeFieldsAndFieldFields
|
||||||
|
(
|
||||||
|
const fileName& cloudDir,
|
||||||
|
const IOobjectList& objects,
|
||||||
|
const polyMesh& srcMesh,
|
||||||
|
const polyMesh& tgtMesh,
|
||||||
|
const distributionMap& map
|
||||||
|
)
|
||||||
|
{
|
||||||
|
mapCloudTypeFields
|
||||||
|
<
|
||||||
|
IOField<Type>,
|
||||||
|
IOField<Type>
|
||||||
|
>
|
||||||
|
(
|
||||||
|
cloudDir,
|
||||||
|
objects,
|
||||||
|
srcMesh,
|
||||||
|
tgtMesh,
|
||||||
|
map
|
||||||
|
);
|
||||||
|
|
||||||
|
mapCloudTypeFields
|
||||||
|
<
|
||||||
|
IOField<Field<Type>>,
|
||||||
|
CompactIOField<Field<Type>>
|
||||||
|
>
|
||||||
|
(
|
||||||
|
cloudDir,
|
||||||
|
objects,
|
||||||
|
srcMesh,
|
||||||
|
tgtMesh,
|
||||||
|
map
|
||||||
|
);
|
||||||
|
|
||||||
|
mapCloudTypeFields
|
||||||
|
<
|
||||||
|
CompactIOField<Field<Type>>,
|
||||||
|
CompactIOField<Field<Type>>
|
||||||
|
>
|
||||||
|
(
|
||||||
|
cloudDir,
|
||||||
|
objects,
|
||||||
|
srcMesh,
|
||||||
|
tgtMesh,
|
||||||
|
map
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
void Foam::mapClouds(const fvMeshToFvMesh& interp)
|
||||||
|
{
|
||||||
|
const polyMesh& srcMesh = interp.srcMesh();
|
||||||
|
const polyMesh& tgtMesh = interp.tgtMesh();
|
||||||
|
|
||||||
|
// Determine the clouds present in this mesh
|
||||||
|
const fileNameList cloudDirs =
|
||||||
|
gatherAndFlatten
|
||||||
|
(
|
||||||
|
readDir
|
||||||
|
(
|
||||||
|
srcMesh.time().timePath()/cloud::prefix,
|
||||||
|
fileType::directory
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
forAll(cloudDirs, cloudi)
|
||||||
|
{
|
||||||
|
Info<< nl << "Mapping cloud " << cloudDirs[cloudi] << endl;
|
||||||
|
|
||||||
|
// Read the source cloud positions
|
||||||
|
passiveParticleCloud srcCloud(srcMesh, cloudDirs[cloudi], false);
|
||||||
|
|
||||||
|
Info<< " read "
|
||||||
|
<< returnReduce(srcCloud.size(), sumOp<label>())
|
||||||
|
<< " parcels from source mesh." << endl;
|
||||||
|
|
||||||
|
// Unpack into position and cell lists and construct a send map
|
||||||
|
pointField positions(srcCloud.size());
|
||||||
|
labelList tgtCells(srcCloud.size(), -1);
|
||||||
|
List<DynamicList<label>> sendsDyn(Pstream::nProcs());
|
||||||
|
{
|
||||||
|
label srcParticlei = 0;
|
||||||
|
forAllConstIter(Cloud<passiveParticle>, srcCloud, iter)
|
||||||
|
{
|
||||||
|
const point pos = iter().position(srcMesh);
|
||||||
|
|
||||||
|
const remote tgtProcCell =
|
||||||
|
interp.srcToTgtPoint(iter().cell(), pos);
|
||||||
|
|
||||||
|
positions[srcParticlei] = pos;
|
||||||
|
tgtCells[srcParticlei] = tgtProcCell.elementi;
|
||||||
|
|
||||||
|
sendsDyn[tgtProcCell.proci].append(srcParticlei ++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
labelListList sends;
|
||||||
|
patchToPatchTools::transferListList(sends, sendsDyn);
|
||||||
|
|
||||||
|
// Build a distribution map from the send map
|
||||||
|
autoPtr<distributionMap> mapPtr =
|
||||||
|
patchToPatchTools::constructDistributionMap(sends);
|
||||||
|
const distributionMap& map = mapPtr();
|
||||||
|
|
||||||
|
// Distribute the positions and target cell indices
|
||||||
|
map.distribute(positions);
|
||||||
|
map.distribute(tgtCells);
|
||||||
|
|
||||||
|
// Construct the target cloud positions
|
||||||
|
passiveParticleCloud tgtCloud
|
||||||
|
(
|
||||||
|
tgtMesh,
|
||||||
|
cloudDirs[cloudi],
|
||||||
|
IDLList<passiveParticle>()
|
||||||
|
);
|
||||||
|
forAll(positions, tgtParticlei)
|
||||||
|
{
|
||||||
|
tgtCloud.addParticle
|
||||||
|
(
|
||||||
|
new passiveParticle
|
||||||
|
(
|
||||||
|
tgtMesh,
|
||||||
|
positions[tgtParticlei],
|
||||||
|
tgtCells[tgtParticlei]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< " mapped "
|
||||||
|
<< returnReduce(tgtCloud.size(), sumOp<label>())
|
||||||
|
<< " parcels to the target mesh." << endl;
|
||||||
|
|
||||||
|
// Write the positions
|
||||||
|
IOPosition<passiveParticleCloud>(tgtCloud).write();
|
||||||
|
|
||||||
|
// Search for Lagrangian objects for this time
|
||||||
|
IOobjectList objects
|
||||||
|
(
|
||||||
|
srcMesh,
|
||||||
|
srcMesh.time().timeName(),
|
||||||
|
cloud::prefix/cloudDirs[cloudi]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map and write the fields
|
||||||
|
#define MapCloudTypeFields(Type, nullArg) \
|
||||||
|
mapCloudTypeFieldsAndFieldFields<Type> \
|
||||||
|
( \
|
||||||
|
cloudDirs[cloudi], \
|
||||||
|
objects, \
|
||||||
|
srcMesh, \
|
||||||
|
tgtMesh, \
|
||||||
|
map \
|
||||||
|
);
|
||||||
|
MapCloudTypeFields(label, );
|
||||||
|
FOR_ALL_FIELD_TYPES(MapCloudTypeFields);
|
||||||
|
#undef MapCloudTypeFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -2,7 +2,7 @@
|
|||||||
========= |
|
========= |
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration | Website: https://openfoam.org
|
\\ / O peration | Website: https://openfoam.org
|
||||||
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
@ -21,35 +21,31 @@ License
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
InNamespace
|
||||||
|
Foam
|
||||||
|
|
||||||
|
Description
|
||||||
|
Maps Lagrangian clouds
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
mapClouds.C
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef UnMapped_H
|
#ifndef mapClouds_H
|
||||||
#define UnMapped_H
|
#define mapClouds_H
|
||||||
|
|
||||||
#include "IOobjectList.H"
|
|
||||||
#include "OSspecific.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class Type>
|
class fvMeshToFvMesh;
|
||||||
void UnMapped(const IOobjectList& objects)
|
|
||||||
{
|
void mapClouds(const fvMeshToFvMesh& interp);
|
||||||
IOobjectList fields = objects.lookupClass(Type::typeName);
|
|
||||||
|
|
||||||
forAllConstIter(IOobjectList, fields, fieldIter)
|
|
||||||
{
|
|
||||||
mvBak(fieldIter()->objectPath(false), "unmapped");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
} // End namespace Foam
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -31,11 +31,84 @@ Description
|
|||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "argList.H"
|
#include "argList.H"
|
||||||
#include "mapMeshes.H"
|
#include "fvMeshToFvMesh.H"
|
||||||
|
#include "mapGeometricFields.H"
|
||||||
|
#include "mapClouds.H"
|
||||||
#include "cellVolumeWeightMethod.H"
|
#include "cellVolumeWeightMethod.H"
|
||||||
|
|
||||||
using namespace Foam;
|
using namespace Foam;
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
void mapConsistentMesh
|
||||||
|
(
|
||||||
|
const fvMesh& srcMesh,
|
||||||
|
const fvMesh& tgtMesh,
|
||||||
|
const word& mapMethod,
|
||||||
|
const HashSet<word>& selectedFields,
|
||||||
|
const bool noLagrangian
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< nl << "Consistently creating and mapping fields for time "
|
||||||
|
<< srcMesh.time().timeName() << nl << endl;
|
||||||
|
|
||||||
|
fvMeshToFvMesh interp(srcMesh, tgtMesh, mapMethod);
|
||||||
|
|
||||||
|
Info<< nl << "Mapping geometric fields" << endl;
|
||||||
|
|
||||||
|
mapGeometricFields
|
||||||
|
(
|
||||||
|
interp,
|
||||||
|
selectedFields,
|
||||||
|
noLagrangian
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!noLagrangian)
|
||||||
|
{
|
||||||
|
mapClouds(interp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mapSubMesh
|
||||||
|
(
|
||||||
|
const fvMesh& srcMesh,
|
||||||
|
const fvMesh& tgtMesh,
|
||||||
|
const HashTable<word>& patchMap,
|
||||||
|
const wordList& cuttingPatches,
|
||||||
|
const word& mapMethod,
|
||||||
|
const HashSet<word>& selectedFields,
|
||||||
|
const bool noLagrangian
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< nl << "Creating and mapping fields for time "
|
||||||
|
<< srcMesh.time().timeName() << nl << endl;
|
||||||
|
|
||||||
|
fvMeshToFvMesh interp
|
||||||
|
(
|
||||||
|
srcMesh,
|
||||||
|
tgtMesh,
|
||||||
|
mapMethod,
|
||||||
|
patchMap,
|
||||||
|
cuttingPatches
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< nl << "Mapping geometric fields" << endl;
|
||||||
|
|
||||||
|
mapGeometricFields
|
||||||
|
(
|
||||||
|
interp,
|
||||||
|
selectedFields,
|
||||||
|
noLagrangian
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!noLagrangian)
|
||||||
|
{
|
||||||
|
mapClouds(interp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -162,7 +235,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
Info<< "\nCreate meshes\n" << endl;
|
Info<< "\nCreate meshes\n" << endl;
|
||||||
|
|
||||||
fvMesh meshSource
|
fvMesh srcMesh
|
||||||
(
|
(
|
||||||
IOobject
|
IOobject
|
||||||
(
|
(
|
||||||
@ -173,7 +246,7 @@ int main(int argc, char *argv[])
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
fvMesh meshTarget
|
fvMesh tgtMesh
|
||||||
(
|
(
|
||||||
IOobject
|
IOobject
|
||||||
(
|
(
|
||||||
@ -184,15 +257,18 @@ int main(int argc, char *argv[])
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
Info<< "Source mesh size: " << meshSource.nCells() << tab
|
Info<< "Source mesh size: "
|
||||||
<< "Target mesh size: " << meshTarget.nCells() << nl << endl;
|
<< returnReduce(srcMesh.nCells(), sumOp<label>())
|
||||||
|
<< ", Target mesh size: "
|
||||||
|
<< returnReduce(tgtMesh.nCells(), sumOp<label>())
|
||||||
|
<< endl;
|
||||||
|
|
||||||
if (consistent)
|
if (consistent)
|
||||||
{
|
{
|
||||||
mapConsistentMesh
|
mapConsistentMesh
|
||||||
(
|
(
|
||||||
meshSource,
|
srcMesh,
|
||||||
meshTarget,
|
tgtMesh,
|
||||||
mapMethod,
|
mapMethod,
|
||||||
selectedFields,
|
selectedFields,
|
||||||
noLagrangian
|
noLagrangian
|
||||||
@ -202,8 +278,8 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
mapSubMesh
|
mapSubMesh
|
||||||
(
|
(
|
||||||
meshSource,
|
srcMesh,
|
||||||
meshTarget,
|
tgtMesh,
|
||||||
patchMap,
|
patchMap,
|
||||||
cuttingPatches,
|
cuttingPatches,
|
||||||
mapMethod,
|
mapMethod,
|
||||||
|
|||||||
@ -23,12 +23,12 @@ License
|
|||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef MapVolFields_H
|
#include "mapGeometricFields.H"
|
||||||
#define MapVolFields_H
|
#include "fvMeshToFvMesh.H"
|
||||||
|
#include "surfaceMesh.H"
|
||||||
#include "GeometricField.H"
|
#include "pointMesh.H"
|
||||||
#include "meshToMesh.H"
|
|
||||||
#include "IOobjectList.H"
|
#include "IOobjectList.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -118,19 +118,17 @@ void evaluateConstraintTypes(GeometricField<Type, fvPatchField, volMesh>& fld)
|
|||||||
|
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
void MapVolFields
|
void mapVolTypeFields
|
||||||
(
|
(
|
||||||
const IOobjectList& objects,
|
const IOobjectList& objects,
|
||||||
const HashSet<word>& selectedFields,
|
const HashSet<word>& selectedFields,
|
||||||
const meshToMesh& interp
|
const fvMeshToFvMesh& interp
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
|
const fvMesh& srcMesh = static_cast<const fvMesh&>(interp.srcMesh());
|
||||||
|
const fvMesh& tgtMesh = static_cast<const fvMesh&>(interp.tgtMesh());
|
||||||
|
|
||||||
const fvMesh& meshSource = static_cast<const fvMesh&>(interp.srcRegion());
|
IOobjectList fields = objects.lookupClass(VolField<Type>::typeName);
|
||||||
const fvMesh& meshTarget = static_cast<const fvMesh&>(interp.tgtRegion());
|
|
||||||
|
|
||||||
IOobjectList fields = objects.lookupClass(fieldType::typeName);
|
|
||||||
|
|
||||||
forAllIter(IOobjectList, fields, fieldIter)
|
forAllIter(IOobjectList, fields, fieldIter)
|
||||||
{
|
{
|
||||||
@ -138,13 +136,13 @@ void MapVolFields
|
|||||||
|
|
||||||
if (selectedFields.empty() || selectedFields.found(fieldName))
|
if (selectedFields.empty() || selectedFields.found(fieldName))
|
||||||
{
|
{
|
||||||
const fieldType fieldSource(*fieldIter(), meshSource);
|
const VolField<Type> fieldSource(*fieldIter(), srcMesh);
|
||||||
|
|
||||||
typeIOobject<fieldType> targetIO
|
typeIOobject<VolField<Type>> targetIO
|
||||||
(
|
(
|
||||||
fieldName,
|
fieldName,
|
||||||
meshTarget.time().timeName(),
|
tgtMesh.time().timeName(),
|
||||||
meshTarget,
|
tgtMesh,
|
||||||
IOobject::MUST_READ
|
IOobject::MUST_READ
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -152,7 +150,7 @@ void MapVolFields
|
|||||||
{
|
{
|
||||||
Info<< " interpolating onto existing field "
|
Info<< " interpolating onto existing field "
|
||||||
<< fieldName << endl;
|
<< fieldName << endl;
|
||||||
fieldType fieldTarget(targetIO, meshTarget);
|
VolField<Type> fieldTarget(targetIO, tgtMesh);
|
||||||
|
|
||||||
interp.mapSrcToTgt(fieldSource, fieldTarget);
|
interp.mapSrcToTgt(fieldSource, fieldTarget);
|
||||||
|
|
||||||
@ -167,9 +165,12 @@ void MapVolFields
|
|||||||
|
|
||||||
targetIO.readOpt() = IOobject::NO_READ;
|
targetIO.readOpt() = IOobject::NO_READ;
|
||||||
|
|
||||||
tmp<fieldType> tfieldTarget(interp.mapSrcToTgt(fieldSource));
|
tmp<VolField<Type>> tfieldTarget
|
||||||
|
(
|
||||||
|
interp.mapSrcToTgt(fieldSource)
|
||||||
|
);
|
||||||
|
|
||||||
fieldType fieldTarget(targetIO, tfieldTarget);
|
VolField<Type> fieldTarget(targetIO, tfieldTarget);
|
||||||
|
|
||||||
evaluateConstraintTypes(fieldTarget);
|
evaluateConstraintTypes(fieldTarget);
|
||||||
|
|
||||||
@ -180,12 +181,60 @@ void MapVolFields
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
template<class Type, template<class> class GeoField>
|
||||||
|
void unMappedTypeFields(const IOobjectList& objects)
|
||||||
|
{
|
||||||
|
IOobjectList fields = objects.lookupClass(GeoField<Type>::typeName);
|
||||||
|
|
||||||
|
forAllConstIter(IOobjectList, fields, fieldIter)
|
||||||
|
{
|
||||||
|
mvBak(fieldIter()->objectPath(false), "unmapped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // End namespace Foam
|
} // End namespace Foam
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
#endif
|
void Foam::mapGeometricFields
|
||||||
|
(
|
||||||
|
const fvMeshToFvMesh& interp,
|
||||||
|
const HashSet<word>& selectedFields,
|
||||||
|
const bool noLagrangian
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const polyMesh& srcMesh = interp.srcMesh();
|
||||||
|
const polyMesh& tgtMesh = interp.tgtMesh();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Search for list of source objects for this time
|
||||||
|
IOobjectList objects(srcMesh, srcMesh.time().timeName());
|
||||||
|
|
||||||
|
// Map the fields
|
||||||
|
#define MapVolTypeFields(Type, nullArg) \
|
||||||
|
mapVolTypeFields<Type> \
|
||||||
|
( \
|
||||||
|
objects, \
|
||||||
|
selectedFields, \
|
||||||
|
interp \
|
||||||
|
);
|
||||||
|
FOR_ALL_FIELD_TYPES(MapVolTypeFields);
|
||||||
|
#undef MapVolTypeFields
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Search for list of target objects for this time
|
||||||
|
IOobjectList objects(tgtMesh, tgtMesh.time().timeName());
|
||||||
|
|
||||||
|
// Mark surface and point fields as unmapped
|
||||||
|
#define UnMappedTypeFields(Type, GeoField) \
|
||||||
|
unMappedTypeFields<Type, GeoField>(objects);
|
||||||
|
FOR_ALL_FIELD_TYPES(UnMappedTypeFields, SurfaceField);
|
||||||
|
FOR_ALL_FIELD_TYPES(UnMappedTypeFields, PointField);
|
||||||
|
#undef UnMappedTypeFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
@ -2,7 +2,7 @@
|
|||||||
========= |
|
========= |
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration | Website: https://openfoam.org
|
\\ / O peration | Website: https://openfoam.org
|
||||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
@ -25,27 +25,31 @@ InNamespace
|
|||||||
Foam
|
Foam
|
||||||
|
|
||||||
Description
|
Description
|
||||||
Maps lagrangian positions and fields
|
Maps geometric fields
|
||||||
|
|
||||||
SourceFiles
|
SourceFiles
|
||||||
mapLagrangian.C
|
mapGeometricFields.C
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef mapLagrangian_H
|
#ifndef mapGeometricFields_H
|
||||||
#define mapLagrangian_H
|
#define mapGeometricFields_H
|
||||||
|
|
||||||
#include "meshToMesh.H"
|
#include "fvMesh.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
|
||||||
//- Maps lagrangian positions and fields
|
class fvMeshToFvMesh;
|
||||||
void mapLagrangian(const meshToMesh& interp);
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
void mapGeometricFields
|
||||||
|
(
|
||||||
|
const fvMeshToFvMesh& interp,
|
||||||
|
const HashSet<word>& selectedFields,
|
||||||
|
const bool noLagrangian
|
||||||
|
);
|
||||||
|
|
||||||
} // End namespace Foam
|
} // End namespace Foam
|
||||||
|
|
||||||
@ -1,319 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "MapLagrangianFields.H"
|
|
||||||
#include "passiveParticleCloud.H"
|
|
||||||
#include "meshSearch.H"
|
|
||||||
#include "OSspecific.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
namespace Foam
|
|
||||||
{
|
|
||||||
|
|
||||||
static const scalar perturbFactor = 1e-6;
|
|
||||||
|
|
||||||
|
|
||||||
// Special version of findCell that generates a cell guaranteed to be
|
|
||||||
// compatible with tracking.
|
|
||||||
static label findCell(const Cloud<passiveParticle>& cloud, const point& pt)
|
|
||||||
{
|
|
||||||
label celli = -1;
|
|
||||||
label tetFacei = -1;
|
|
||||||
label tetPtI = -1;
|
|
||||||
|
|
||||||
const polyMesh& mesh = cloud.pMesh();
|
|
||||||
|
|
||||||
mesh.findCellFacePt(pt, celli, tetFacei, tetPtI);
|
|
||||||
|
|
||||||
if (celli >= 0)
|
|
||||||
{
|
|
||||||
return celli;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// See if particle on face by finding nearest face and shifting
|
|
||||||
// particle.
|
|
||||||
|
|
||||||
meshSearch meshSearcher
|
|
||||||
(
|
|
||||||
mesh,
|
|
||||||
polyMesh::FACE_PLANES // no decomposition needed
|
|
||||||
);
|
|
||||||
|
|
||||||
label facei = meshSearcher.findNearestBoundaryFace(pt);
|
|
||||||
|
|
||||||
if (facei >= 0)
|
|
||||||
{
|
|
||||||
const point& cc = mesh.cellCentres()[mesh.faceOwner()[facei]];
|
|
||||||
|
|
||||||
const point perturbPt = (1-perturbFactor)*pt+perturbFactor*cc;
|
|
||||||
|
|
||||||
mesh.findCellFacePt(perturbPt, celli, tetFacei, tetPtI);
|
|
||||||
|
|
||||||
return celli;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void mapLagrangian(const meshToMesh& interp)
|
|
||||||
{
|
|
||||||
// Determine which particles are in meshTarget
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
const polyMesh& meshSource = interp.srcRegion();
|
|
||||||
const polyMesh& meshTarget = interp.tgtRegion();
|
|
||||||
const labelListList& sourceToTarget = interp.srcToTgtCellAddr();
|
|
||||||
|
|
||||||
fileNameList cloudDirs
|
|
||||||
(
|
|
||||||
readDir
|
|
||||||
(
|
|
||||||
meshSource.time().timePath()/cloud::prefix,
|
|
||||||
fileType::directory
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
forAll(cloudDirs, cloudI)
|
|
||||||
{
|
|
||||||
// Search for list of lagrangian objects for this time
|
|
||||||
IOobjectList objects
|
|
||||||
(
|
|
||||||
meshSource,
|
|
||||||
meshSource.time().timeName(),
|
|
||||||
cloud::prefix/cloudDirs[cloudI]
|
|
||||||
);
|
|
||||||
|
|
||||||
IOobject* positionsPtr = objects.lookup(word("positions"));
|
|
||||||
|
|
||||||
if (positionsPtr)
|
|
||||||
{
|
|
||||||
Info<< nl << " processing cloud " << cloudDirs[cloudI] << endl;
|
|
||||||
|
|
||||||
// Read positions & cell
|
|
||||||
passiveParticleCloud sourceParcels
|
|
||||||
(
|
|
||||||
meshSource,
|
|
||||||
cloudDirs[cloudI],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
Info<< " read " << sourceParcels.size()
|
|
||||||
<< " parcels from source mesh." << endl;
|
|
||||||
|
|
||||||
// Construct empty target cloud
|
|
||||||
passiveParticleCloud targetParcels
|
|
||||||
(
|
|
||||||
meshTarget,
|
|
||||||
cloudDirs[cloudI],
|
|
||||||
IDLList<passiveParticle>()
|
|
||||||
);
|
|
||||||
|
|
||||||
passiveParticle::trackingData td(targetParcels);
|
|
||||||
|
|
||||||
label sourceParticleI = 0;
|
|
||||||
|
|
||||||
// Indices of source particles that get added to targetParcels
|
|
||||||
DynamicList<label> addParticles(sourceParcels.size());
|
|
||||||
|
|
||||||
// Unmapped particles
|
|
||||||
labelHashSet unmappedSource(sourceParcels.size());
|
|
||||||
|
|
||||||
|
|
||||||
// Initial: track from fine-mesh cell centre to particle position
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// This requires there to be no boundary in the way.
|
|
||||||
|
|
||||||
|
|
||||||
forAllConstIter(Cloud<passiveParticle>, sourceParcels, iter)
|
|
||||||
{
|
|
||||||
bool foundCell = false;
|
|
||||||
|
|
||||||
// Assume that cell from read parcel is the correct one...
|
|
||||||
if (iter().cell() >= 0)
|
|
||||||
{
|
|
||||||
const labelList& targetCells =
|
|
||||||
sourceToTarget[iter().cell()];
|
|
||||||
|
|
||||||
// Particle probably in one of the targetcells. Try
|
|
||||||
// all by tracking from their cell centre to the parcel
|
|
||||||
// position.
|
|
||||||
|
|
||||||
forAll(targetCells, i)
|
|
||||||
{
|
|
||||||
// Track from its cellcentre to position to make sure.
|
|
||||||
autoPtr<passiveParticle> newPtr
|
|
||||||
(
|
|
||||||
new passiveParticle
|
|
||||||
(
|
|
||||||
meshTarget,
|
|
||||||
barycentric(1, 0, 0, 0),
|
|
||||||
targetCells[i],
|
|
||||||
meshTarget.cells()[targetCells[i]][0],
|
|
||||||
1
|
|
||||||
)
|
|
||||||
);
|
|
||||||
passiveParticle& newP = newPtr();
|
|
||||||
|
|
||||||
newP.track
|
|
||||||
(
|
|
||||||
meshTarget,
|
|
||||||
iter().position(meshSource)
|
|
||||||
- newP.position(meshTarget),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!newP.onFace())
|
|
||||||
{
|
|
||||||
// Hit position.
|
|
||||||
foundCell = true;
|
|
||||||
addParticles.append(sourceParticleI);
|
|
||||||
targetParcels.addParticle(newPtr.ptr());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundCell)
|
|
||||||
{
|
|
||||||
// Store for closer analysis
|
|
||||||
unmappedSource.insert(sourceParticleI);
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceParticleI++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Info<< " after meshToMesh addressing found "
|
|
||||||
<< targetParcels.size()
|
|
||||||
<< " parcels in target mesh." << endl;
|
|
||||||
|
|
||||||
|
|
||||||
// Do closer inspection for unmapped particles
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
if (unmappedSource.size())
|
|
||||||
{
|
|
||||||
sourceParticleI = 0;
|
|
||||||
|
|
||||||
forAllIter(Cloud<passiveParticle>, sourceParcels, iter)
|
|
||||||
{
|
|
||||||
if (unmappedSource.found(sourceParticleI))
|
|
||||||
{
|
|
||||||
label targetCell =
|
|
||||||
findCell
|
|
||||||
(
|
|
||||||
targetParcels,
|
|
||||||
iter().position(meshSource)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (targetCell >= 0)
|
|
||||||
{
|
|
||||||
unmappedSource.erase(sourceParticleI);
|
|
||||||
addParticles.append(sourceParticleI);
|
|
||||||
targetParcels.addParticle
|
|
||||||
(
|
|
||||||
new passiveParticle
|
|
||||||
(
|
|
||||||
meshTarget,
|
|
||||||
iter().position(meshSource),
|
|
||||||
targetCell
|
|
||||||
)
|
|
||||||
);
|
|
||||||
sourceParcels.remove(&iter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sourceParticleI++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addParticles.shrink();
|
|
||||||
|
|
||||||
Info<< " after additional mesh searching found "
|
|
||||||
<< targetParcels.size() << " parcels in target mesh." << endl;
|
|
||||||
|
|
||||||
if (addParticles.size())
|
|
||||||
{
|
|
||||||
IOPosition<passiveParticleCloud>(targetParcels).write();
|
|
||||||
|
|
||||||
// addParticles now contains the indices of the sourceMesh
|
|
||||||
// particles that were appended to the target mesh.
|
|
||||||
|
|
||||||
// Map lagrangian fields
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
MapLagrangianFields<label>
|
|
||||||
(
|
|
||||||
cloudDirs[cloudI],
|
|
||||||
objects,
|
|
||||||
meshTarget,
|
|
||||||
addParticles
|
|
||||||
);
|
|
||||||
MapLagrangianFields<scalar>
|
|
||||||
(
|
|
||||||
cloudDirs[cloudI],
|
|
||||||
objects,
|
|
||||||
meshTarget,
|
|
||||||
addParticles
|
|
||||||
);
|
|
||||||
MapLagrangianFields<vector>
|
|
||||||
(
|
|
||||||
cloudDirs[cloudI],
|
|
||||||
objects,
|
|
||||||
meshTarget,
|
|
||||||
addParticles
|
|
||||||
);
|
|
||||||
MapLagrangianFields<sphericalTensor>
|
|
||||||
(
|
|
||||||
cloudDirs[cloudI],
|
|
||||||
objects,
|
|
||||||
meshTarget,
|
|
||||||
addParticles
|
|
||||||
);
|
|
||||||
MapLagrangianFields<symmTensor>
|
|
||||||
(
|
|
||||||
cloudDirs[cloudI],
|
|
||||||
objects,
|
|
||||||
meshTarget,
|
|
||||||
addParticles
|
|
||||||
);
|
|
||||||
MapLagrangianFields<tensor>
|
|
||||||
(
|
|
||||||
cloudDirs[cloudI],
|
|
||||||
objects,
|
|
||||||
meshTarget,
|
|
||||||
addParticles
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
} // End namespace Foam
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -1,169 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "mapMeshes.H"
|
|
||||||
#include "surfaceMesh.H"
|
|
||||||
#include "processorFvPatch.H"
|
|
||||||
#include "pointMesh.H"
|
|
||||||
#include "mapLagrangian.H"
|
|
||||||
#include "MapVolFields.H"
|
|
||||||
#include "UnMapped.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
void Foam::mapMesh
|
|
||||||
(
|
|
||||||
const meshToMesh& interp,
|
|
||||||
const HashSet<word>& selectedFields,
|
|
||||||
const bool noLagrangian
|
|
||||||
)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
const polyMesh& meshSource = interp.srcRegion();
|
|
||||||
|
|
||||||
// Search for list of objects for this time
|
|
||||||
IOobjectList objects(meshSource, meshSource.time().timeName());
|
|
||||||
|
|
||||||
// Map volFields
|
|
||||||
// ~~~~~~~~~~~~~
|
|
||||||
MapVolFields<scalar>
|
|
||||||
(
|
|
||||||
objects,
|
|
||||||
selectedFields,
|
|
||||||
interp
|
|
||||||
);
|
|
||||||
|
|
||||||
MapVolFields<vector>
|
|
||||||
(
|
|
||||||
objects,
|
|
||||||
selectedFields,
|
|
||||||
interp
|
|
||||||
);
|
|
||||||
MapVolFields<sphericalTensor>
|
|
||||||
(
|
|
||||||
objects,
|
|
||||||
selectedFields,
|
|
||||||
interp
|
|
||||||
);
|
|
||||||
MapVolFields<symmTensor>
|
|
||||||
(
|
|
||||||
objects,
|
|
||||||
selectedFields,
|
|
||||||
interp
|
|
||||||
);
|
|
||||||
MapVolFields<tensor>
|
|
||||||
(
|
|
||||||
objects,
|
|
||||||
selectedFields,
|
|
||||||
interp
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const polyMesh& meshTarget = interp.tgtRegion();
|
|
||||||
|
|
||||||
// Search for list of target objects for this time
|
|
||||||
IOobjectList objects(meshTarget, meshTarget.time().timeName());
|
|
||||||
|
|
||||||
// Mark surfaceFields as unmapped
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
UnMapped<surfaceScalarField>(objects);
|
|
||||||
UnMapped<surfaceVectorField>(objects);
|
|
||||||
UnMapped<surfaceSphericalTensorField>(objects);
|
|
||||||
UnMapped<surfaceSymmTensorField>(objects);
|
|
||||||
UnMapped<surfaceTensorField>(objects);
|
|
||||||
|
|
||||||
// Mark pointFields as unmapped
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
UnMapped<pointScalarField>(objects);
|
|
||||||
UnMapped<pointVectorField>(objects);
|
|
||||||
UnMapped<pointSphericalTensorField>(objects);
|
|
||||||
UnMapped<pointSymmTensorField>(objects);
|
|
||||||
UnMapped<pointTensorField>(objects);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!noLagrangian)
|
|
||||||
{
|
|
||||||
mapLagrangian(interp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::mapConsistentMesh
|
|
||||||
(
|
|
||||||
const fvMesh& meshSource,
|
|
||||||
const fvMesh& meshTarget,
|
|
||||||
const word& mapMethod,
|
|
||||||
const HashSet<word>& selectedFields,
|
|
||||||
const bool noLagrangian
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Info<< nl << "Consistently creating and mapping fields for time "
|
|
||||||
<< meshSource.time().timeName() << nl << endl;
|
|
||||||
|
|
||||||
meshToMesh interp(meshSource, meshTarget, mapMethod);
|
|
||||||
|
|
||||||
mapMesh
|
|
||||||
(
|
|
||||||
interp,
|
|
||||||
selectedFields,
|
|
||||||
noLagrangian
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::mapSubMesh
|
|
||||||
(
|
|
||||||
const fvMesh& meshSource,
|
|
||||||
const fvMesh& meshTarget,
|
|
||||||
const HashTable<word>& patchMap,
|
|
||||||
const wordList& cuttingPatches,
|
|
||||||
const word& mapMethod,
|
|
||||||
const HashSet<word>& selectedFields,
|
|
||||||
const bool noLagrangian
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Info<< nl << "Creating and mapping fields for time "
|
|
||||||
<< meshSource.time().timeName() << nl << endl;
|
|
||||||
|
|
||||||
meshToMesh interp
|
|
||||||
(
|
|
||||||
meshSource,
|
|
||||||
meshTarget,
|
|
||||||
mapMethod,
|
|
||||||
patchMap,
|
|
||||||
cuttingPatches
|
|
||||||
);
|
|
||||||
|
|
||||||
mapMesh
|
|
||||||
(
|
|
||||||
interp,
|
|
||||||
selectedFields,
|
|
||||||
noLagrangian
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -27,9 +27,14 @@ License
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
Foam::polyMeshMap::polyMeshMap(const polyMesh& mesh)
|
Foam::polyMeshMap::polyMeshMap
|
||||||
|
(
|
||||||
|
const polyMesh& mesh,
|
||||||
|
const meshToMesh& mapper
|
||||||
|
)
|
||||||
:
|
:
|
||||||
mesh_(mesh)
|
mesh_(mesh),
|
||||||
|
mapper_(mapper)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ SourceFiles
|
|||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
|
||||||
class polyMesh;
|
class meshToMesh;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*\
|
/*---------------------------------------------------------------------------*\
|
||||||
Class polyMeshMap Declaration
|
Class polyMeshMap Declaration
|
||||||
@ -55,13 +55,16 @@ class polyMeshMap
|
|||||||
//- Reference to polyMesh
|
//- Reference to polyMesh
|
||||||
const polyMesh& mesh_;
|
const polyMesh& mesh_;
|
||||||
|
|
||||||
|
//- Reference to the meshToMesh mapper
|
||||||
|
const meshToMesh& mapper_;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
//- Construct for mesh
|
//- Construct for mesh
|
||||||
polyMeshMap(const polyMesh& mesh);
|
polyMeshMap(const polyMesh& mesh, const meshToMesh& mapper);
|
||||||
|
|
||||||
//- Disallow default bitwise copy construction
|
//- Disallow default bitwise copy construction
|
||||||
polyMeshMap(const polyMeshMap&) = delete;
|
polyMeshMap(const polyMeshMap&) = delete;
|
||||||
@ -74,6 +77,12 @@ public:
|
|||||||
{
|
{
|
||||||
return mesh_;
|
return mesh_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//- Return meshToMesh mapper
|
||||||
|
const meshToMesh& mapper() const
|
||||||
|
{
|
||||||
|
return mapper_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -512,4 +512,7 @@ $(faceSources)/patchFluxToFace/patchFluxToFace.C
|
|||||||
solver/solver.C
|
solver/solver.C
|
||||||
solver/solverNew.C
|
solver/solverNew.C
|
||||||
|
|
||||||
|
fvMeshToFvMesh/fvMeshToFvMesh.C
|
||||||
|
fvMeshToFvMesh/patchToPatchFvPatchFieldMapper.C
|
||||||
|
|
||||||
LIB = $(FOAM_LIBBIN)/libfiniteVolume
|
LIB = $(FOAM_LIBBIN)/libfiniteVolume
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
========= |
|
========= |
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration | Website: https://openfoam.org
|
\\ / O peration | Website: https://openfoam.org
|
||||||
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
@ -23,54 +23,20 @@ License
|
|||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef mapMeshes_H
|
#include "fvMeshToFvMesh.H"
|
||||||
#define mapMeshes_H
|
|
||||||
|
|
||||||
#include "meshToMesh.H"
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
defineTypeNameAndDebug(fvMeshToFvMesh, 0);
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
}
|
||||||
|
|
||||||
void mapMesh
|
|
||||||
(
|
|
||||||
const meshToMesh& interp,
|
|
||||||
const HashSet<word>& selectedFields,
|
|
||||||
const bool noLagrangian
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
void mapConsistentMesh
|
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||||
(
|
|
||||||
const fvMesh& meshSource,
|
|
||||||
const fvMesh& meshTarget,
|
|
||||||
const word& mapMethod,
|
|
||||||
const HashSet<word>& selectedFields,
|
|
||||||
const bool noLagrangian
|
|
||||||
);
|
|
||||||
|
|
||||||
|
Foam::fvMeshToFvMesh::~fvMeshToFvMesh()
|
||||||
|
{}
|
||||||
|
|
||||||
void mapSubMesh
|
|
||||||
(
|
|
||||||
const fvMesh& meshSource,
|
|
||||||
const fvMesh& meshTarget,
|
|
||||||
const HashTable<word>& patchMap,
|
|
||||||
const wordList& cuttingPatches,
|
|
||||||
const word& mapMethod,
|
|
||||||
const HashSet<word>& selectedFields,
|
|
||||||
const bool noLagrangian
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
} // End namespace Foam
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
109
src/finiteVolume/fvMeshToFvMesh/fvMeshToFvMesh.H
Normal file
109
src/finiteVolume/fvMeshToFvMesh/fvMeshToFvMesh.H
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::fvMeshToFvMesh
|
||||||
|
|
||||||
|
Description
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
fvMeshToFvMeshTemplates.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef fvMeshToFvMesh_H
|
||||||
|
#define fvMeshToFvMesh_H
|
||||||
|
|
||||||
|
#include "meshToMesh.H"
|
||||||
|
#include "volFields.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class fvMeshToFvMesh Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class fvMeshToFvMesh
|
||||||
|
:
|
||||||
|
public meshToMesh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Run-time type information
|
||||||
|
TypeName("fvMeshToFvMesh");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Inherit base class' constructors
|
||||||
|
using meshToMesh::meshToMesh;
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~fvMeshToFvMesh();
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
// Evaluation
|
||||||
|
|
||||||
|
// Source-to-target volume field mapping
|
||||||
|
|
||||||
|
//- Interpolate a field with a defined operation. Values
|
||||||
|
// passed in via 'result' are used to initialise the return
|
||||||
|
// value.
|
||||||
|
template<class Type>
|
||||||
|
void mapSrcToTgt
|
||||||
|
(
|
||||||
|
const GeometricField<Type, fvPatchField, volMesh>& field,
|
||||||
|
GeometricField<Type, fvPatchField, volMesh>& result
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Interpolate a field with a defined operation. The initial
|
||||||
|
// values of the result are set to zero.
|
||||||
|
template<class Type>
|
||||||
|
tmp<GeometricField<Type, fvPatchField, volMesh>> mapSrcToTgt
|
||||||
|
(
|
||||||
|
const GeometricField<Type, fvPatchField, volMesh>& field
|
||||||
|
) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#ifdef NoRepository
|
||||||
|
#include "fvMeshToFvMeshTemplates.C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
171
src/finiteVolume/fvMeshToFvMesh/fvMeshToFvMeshTemplates.C
Normal file
171
src/finiteVolume/fvMeshToFvMesh/fvMeshToFvMeshTemplates.C
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "fvMeshToFvMesh.H"
|
||||||
|
#include "directFvPatchFieldMapper.H"
|
||||||
|
#include "patchToPatchFvPatchFieldMapper.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
void Foam::fvMeshToFvMesh::mapSrcToTgt
|
||||||
|
(
|
||||||
|
const GeometricField<Type, fvPatchField, volMesh>& field,
|
||||||
|
GeometricField<Type, fvPatchField, volMesh>& result
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
meshToMesh::mapSrcToTgt(field, result.primitiveFieldRef());
|
||||||
|
|
||||||
|
typename GeometricField<Type, fvPatchField, volMesh>::
|
||||||
|
Boundary& resultBf = result.boundaryFieldRef();
|
||||||
|
|
||||||
|
forAll(srcToTgtPatchIDs(), i)
|
||||||
|
{
|
||||||
|
const label srcPatchi = srcToTgtPatchIDs()[i].first();
|
||||||
|
const label tgtPatchi = srcToTgtPatchIDs()[i].second();
|
||||||
|
|
||||||
|
const fvPatchField<Type>& srcField = field.boundaryField()[srcPatchi];
|
||||||
|
fvPatchField<Type>& tgtField = resultBf[tgtPatchi];
|
||||||
|
|
||||||
|
// Clone and map (since rmap does not do general mapping)
|
||||||
|
tmp<fvPatchField<Type>> tnewTgt
|
||||||
|
(
|
||||||
|
fvPatchField<Type>::New
|
||||||
|
(
|
||||||
|
srcField,
|
||||||
|
tgtField.patch(),
|
||||||
|
result(),
|
||||||
|
patchToPatchFvPatchFieldMapper
|
||||||
|
(
|
||||||
|
srcToTgtPatchToPatches()[i],
|
||||||
|
true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Transfer all mapped quantities (value and e.g. gradient) onto
|
||||||
|
// tgtField. Value will get overwritten below.
|
||||||
|
tgtField.rmap(tnewTgt(), identity(tgtField.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(tgtCuttingPatchIDs(), i)
|
||||||
|
{
|
||||||
|
const label patchi = tgtCuttingPatchIDs()[i];
|
||||||
|
fvPatchField<Type>& pf = resultBf[patchi];
|
||||||
|
pf == pf.patchInternalField();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>>
|
||||||
|
Foam::fvMeshToFvMesh::mapSrcToTgt
|
||||||
|
(
|
||||||
|
const GeometricField<Type, fvPatchField, volMesh>& field
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
|
||||||
|
|
||||||
|
const fvMesh& tgtMesh = static_cast<const fvMesh&>(meshToMesh::tgtMesh());
|
||||||
|
|
||||||
|
const fvBoundaryMesh& tgtBm = tgtMesh.boundary();
|
||||||
|
const typename fieldType::Boundary& srcBfld =
|
||||||
|
field.boundaryField();
|
||||||
|
|
||||||
|
PtrList<fvPatchField<Type>> tgtPatchFields(tgtBm.size());
|
||||||
|
|
||||||
|
// construct tgt boundary patch types as copy of 'field' boundary types
|
||||||
|
// note: this will provide place holders for fields with additional
|
||||||
|
// entries, but these values will need to be reset
|
||||||
|
forAll(srcToTgtPatchIDs(), i)
|
||||||
|
{
|
||||||
|
const label srcPatchi = srcToTgtPatchIDs()[i].first();
|
||||||
|
const label tgtPatchi = srcToTgtPatchIDs()[i].second();
|
||||||
|
|
||||||
|
if (!tgtPatchFields.set(tgtPatchi))
|
||||||
|
{
|
||||||
|
tgtPatchFields.set
|
||||||
|
(
|
||||||
|
tgtPatchi,
|
||||||
|
fvPatchField<Type>::New
|
||||||
|
(
|
||||||
|
srcBfld[srcPatchi],
|
||||||
|
tgtMesh.boundary()[tgtPatchi],
|
||||||
|
DimensionedField<Type, volMesh>::null(),
|
||||||
|
directFvPatchFieldMapper
|
||||||
|
(
|
||||||
|
labelList(tgtMesh.boundary()[tgtPatchi].size(), -1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any unset tgtPatchFields become calculated
|
||||||
|
forAll(tgtPatchFields, tgtPatchi)
|
||||||
|
{
|
||||||
|
if (!tgtPatchFields.set(tgtPatchi))
|
||||||
|
{
|
||||||
|
// Note: use factory New method instead of direct generation of
|
||||||
|
// calculated so we keep constraints
|
||||||
|
tgtPatchFields.set
|
||||||
|
(
|
||||||
|
tgtPatchi,
|
||||||
|
fvPatchField<Type>::New
|
||||||
|
(
|
||||||
|
calculatedFvPatchField<Type>::typeName,
|
||||||
|
tgtMesh.boundary()[tgtPatchi],
|
||||||
|
DimensionedField<Type, volMesh>::null()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp<fieldType> tresult
|
||||||
|
(
|
||||||
|
new fieldType
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
typedName("interpolate(" + field.name() + ")"),
|
||||||
|
tgtMesh.time().timeName(),
|
||||||
|
tgtMesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
tgtMesh,
|
||||||
|
field.dimensions(),
|
||||||
|
Field<Type>(tgtMesh.nCells(), Zero),
|
||||||
|
tgtPatchFields
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
mapSrcToTgt(field, tresult.ref());
|
||||||
|
|
||||||
|
return tresult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -1,13 +1,11 @@
|
|||||||
EXE_INC = \
|
EXE_INC = \
|
||||||
-I$(LIB_SRC)/triSurface/lnInclude \
|
-I$(LIB_SRC)/triSurface/lnInclude \
|
||||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||||
-I$(LIB_SRC)/sampling/lnInclude \
|
|
||||||
-I$(LIB_SRC)/dynamicMesh/lnInclude \
|
-I$(LIB_SRC)/dynamicMesh/lnInclude \
|
||||||
-I$(LIB_SRC)/finiteVolume/lnInclude
|
-I$(LIB_SRC)/finiteVolume/lnInclude
|
||||||
|
|
||||||
LIB_LIBS = \
|
LIB_LIBS = \
|
||||||
-ltriSurface \
|
-ltriSurface \
|
||||||
-lmeshTools \
|
-lmeshTools \
|
||||||
-lsampling \
|
|
||||||
-ldynamicMesh \
|
-ldynamicMesh \
|
||||||
-lfiniteVolume
|
-lfiniteVolume
|
||||||
|
|||||||
@ -35,7 +35,7 @@ Description
|
|||||||
#define MeshToMeshMapGeometricFields_H
|
#define MeshToMeshMapGeometricFields_H
|
||||||
|
|
||||||
#include "polyMesh.H"
|
#include "polyMesh.H"
|
||||||
#include "meshToMesh.H"
|
#include "fvMeshToFvMesh.H"
|
||||||
#include "fvPatchFieldMapper.H"
|
#include "fvPatchFieldMapper.H"
|
||||||
#include "pointPatchFieldMapper.H"
|
#include "pointPatchFieldMapper.H"
|
||||||
#include "setSizeFieldMapper.H"
|
#include "setSizeFieldMapper.H"
|
||||||
@ -131,12 +131,13 @@ void evaluateConstraintTypes(GeometricField<Type, fvPatchField, volMesh>& fld)
|
|||||||
template<class Type>
|
template<class Type>
|
||||||
void MeshToMeshMapVolFields
|
void MeshToMeshMapVolFields
|
||||||
(
|
(
|
||||||
const meshToMesh& mapper
|
const fvMesh& mesh,
|
||||||
|
const fvMeshToFvMesh& mapper
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HashTable<const GeometricField<Type, fvPatchField, volMesh>*> fields
|
HashTable<const GeometricField<Type, fvPatchField, volMesh>*> fields
|
||||||
(
|
(
|
||||||
mapper.srcRegion().objectRegistry::template
|
mesh.objectRegistry::template
|
||||||
lookupClass<GeometricField<Type, fvPatchField, volMesh>>()
|
lookupClass<GeometricField<Type, fvPatchField, volMesh>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -158,7 +159,7 @@ void MeshToMeshMapVolFields
|
|||||||
|
|
||||||
fields =
|
fields =
|
||||||
(
|
(
|
||||||
mapper.srcRegion().objectRegistry::template
|
mesh.objectRegistry::template
|
||||||
lookupClass<GeometricField<Type, fvPatchField, volMesh>>()
|
lookupClass<GeometricField<Type, fvPatchField, volMesh>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ void MeshToMeshMapVolFields
|
|||||||
const_cast<GeometricField<Type, fvPatchField, volMesh>&>
|
const_cast<GeometricField<Type, fvPatchField, volMesh>&>
|
||||||
(*fieldIter());
|
(*fieldIter());
|
||||||
|
|
||||||
if (meshToMesh::debug)
|
if (fvMeshToFvMesh::debug)
|
||||||
{
|
{
|
||||||
Info<< "Mapping " << field.typeName << ' ' << field.name()
|
Info<< "Mapping " << field.typeName << ' ' << field.name()
|
||||||
<< endl;
|
<< endl;
|
||||||
@ -196,7 +197,8 @@ template
|
|||||||
>
|
>
|
||||||
void NaNGeometricFields
|
void NaNGeometricFields
|
||||||
(
|
(
|
||||||
const meshToMesh& mapper
|
const fvMesh& mesh,
|
||||||
|
const fvMeshToFvMesh& mapper
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
typedef GeometricField<Type, PatchField, GeoMesh> Gfield;
|
typedef GeometricField<Type, PatchField, GeoMesh> Gfield;
|
||||||
@ -220,7 +222,7 @@ void NaNGeometricFields
|
|||||||
|
|
||||||
HashTable<const Gfield*> fields
|
HashTable<const Gfield*> fields
|
||||||
(
|
(
|
||||||
mapper.srcRegion().objectRegistry::template lookupClass<Gfield>()
|
mesh.objectRegistry::template lookupClass<Gfield>()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Deleted old time fields
|
// Deleted old time fields
|
||||||
@ -236,8 +238,7 @@ void NaNGeometricFields
|
|||||||
field.clearOldTimes();
|
field.clearOldTimes();
|
||||||
}
|
}
|
||||||
|
|
||||||
fields =
|
fields = mesh.objectRegistry::template lookupClass<Gfield>();
|
||||||
mapper.srcRegion().objectRegistry::template lookupClass<Gfield>();
|
|
||||||
|
|
||||||
Type NaN;
|
Type NaN;
|
||||||
|
|
||||||
@ -255,7 +256,7 @@ void NaNGeometricFields
|
|||||||
{
|
{
|
||||||
Gfield& field = const_cast<Gfield&>(*fieldIter());
|
Gfield& field = const_cast<Gfield&>(*fieldIter());
|
||||||
|
|
||||||
if (meshToMesh::debug)
|
if (fvMeshToFvMesh::debug)
|
||||||
{
|
{
|
||||||
Info<< "Setting to NaN " << field.typeName << ' ' << field.name()
|
Info<< "Setting to NaN " << field.typeName << ' ' << field.name()
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|||||||
@ -29,7 +29,7 @@ License
|
|||||||
#include "surfaceInterpolate.H"
|
#include "surfaceInterpolate.H"
|
||||||
#include "pointFields.H"
|
#include "pointFields.H"
|
||||||
#include "meshToMeshAdjustTimeStepFunctionObject.H"
|
#include "meshToMeshAdjustTimeStepFunctionObject.H"
|
||||||
#include "meshToMesh.H"
|
#include "fvMeshToFvMesh.H"
|
||||||
#include "cellVolumeWeightMethod.H"
|
#include "cellVolumeWeightMethod.H"
|
||||||
#include "surfaceToVolVelocity.H"
|
#include "surfaceToVolVelocity.H"
|
||||||
#include "MeshToMeshMapGeometricFields.H"
|
#include "MeshToMeshMapGeometricFields.H"
|
||||||
@ -154,7 +154,7 @@ bool Foam::fvMeshTopoChangers::meshToMesh::update()
|
|||||||
fvMesh::stitchType::none
|
fvMesh::stitchType::none
|
||||||
);
|
);
|
||||||
|
|
||||||
autoPtr<Foam::meshToMesh> mapper;
|
autoPtr<Foam::fvMeshToFvMesh> mapper;
|
||||||
|
|
||||||
// Create mesh-to-mesh mapper with support for cuttingPatches
|
// Create mesh-to-mesh mapper with support for cuttingPatches
|
||||||
// if specified
|
// if specified
|
||||||
@ -182,7 +182,7 @@ bool Foam::fvMeshTopoChangers::meshToMesh::update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper = new Foam::meshToMesh
|
mapper = new Foam::fvMeshToFvMesh
|
||||||
(
|
(
|
||||||
mesh(),
|
mesh(),
|
||||||
newMesh,
|
newMesh,
|
||||||
@ -193,7 +193,7 @@ bool Foam::fvMeshTopoChangers::meshToMesh::update()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mapper = new Foam::meshToMesh
|
mapper = new Foam::fvMeshToFvMesh
|
||||||
(
|
(
|
||||||
mesh(),
|
mesh(),
|
||||||
newMesh,
|
newMesh,
|
||||||
@ -207,25 +207,27 @@ bool Foam::fvMeshTopoChangers::meshToMesh::update()
|
|||||||
|
|
||||||
// Map all the volFields in the objectRegistry
|
// Map all the volFields in the objectRegistry
|
||||||
#define mapVolFieldType(Type, nullArg) \
|
#define mapVolFieldType(Type, nullArg) \
|
||||||
MeshToMeshMapVolFields<Type>(mapper);
|
MeshToMeshMapVolFields<Type>(mesh(), mapper);
|
||||||
FOR_ALL_FIELD_TYPES(mapVolFieldType);
|
FOR_ALL_FIELD_TYPES(mapVolFieldType);
|
||||||
|
|
||||||
// Set all the surfaceFields in the objectRegistry to NaN
|
// Set all the surfaceFields in the objectRegistry to NaN
|
||||||
#define NaNSurfaceFieldType(Type, nullArg) \
|
#define NaNSurfaceFieldType(Type, nullArg) \
|
||||||
NaNGeometricFields \
|
NaNGeometricFields \
|
||||||
<Type, fvsPatchField, surfaceMesh, fvPatchFieldMapper>(mapper);
|
<Type, fvsPatchField, surfaceMesh, fvPatchFieldMapper> \
|
||||||
|
(mesh(), mapper);
|
||||||
FOR_ALL_FIELD_TYPES(NaNSurfaceFieldType);
|
FOR_ALL_FIELD_TYPES(NaNSurfaceFieldType);
|
||||||
|
|
||||||
// Set all the pointFields in the objectRegistry to NaN
|
// Set all the pointFields in the objectRegistry to NaN
|
||||||
#define NaNPointFieldType(Type, nullArg) \
|
#define NaNPointFieldType(Type, nullArg) \
|
||||||
NaNGeometricFields \
|
NaNGeometricFields \
|
||||||
<Type, pointPatchField, pointMesh, pointPatchFieldMapper>(mapper);
|
<Type, pointPatchField, pointMesh, pointPatchFieldMapper> \
|
||||||
|
(mesh(), mapper);
|
||||||
FOR_ALL_FIELD_TYPES(NaNPointFieldType);
|
FOR_ALL_FIELD_TYPES(NaNPointFieldType);
|
||||||
|
|
||||||
// Interpolate U's to Uf's
|
// Interpolate U's to Uf's
|
||||||
interpolateUfs();
|
interpolateUfs();
|
||||||
|
|
||||||
polyMeshMap map(mesh());
|
polyMeshMap map(mesh(), mapper());
|
||||||
mesh().mapMesh(map);
|
mesh().mapMesh(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@ License
|
|||||||
#include "Cloud.H"
|
#include "Cloud.H"
|
||||||
#include "processorPolyPatch.H"
|
#include "processorPolyPatch.H"
|
||||||
#include "globalMeshData.H"
|
#include "globalMeshData.H"
|
||||||
|
#include "meshToMesh.H"
|
||||||
#include "PstreamCombineReduceOps.H"
|
#include "PstreamCombineReduceOps.H"
|
||||||
#include "polyTopoChangeMap.H"
|
#include "polyTopoChangeMap.H"
|
||||||
#include "polyMeshMap.H"
|
#include "polyMeshMap.H"
|
||||||
@ -433,7 +434,109 @@ void Foam::Cloud<ParticleType>::topoChange(const polyTopoChangeMap& map)
|
|||||||
template<class ParticleType>
|
template<class ParticleType>
|
||||||
void Foam::Cloud<ParticleType>::mapMesh(const polyMeshMap& map)
|
void Foam::Cloud<ParticleType>::mapMesh(const polyMeshMap& map)
|
||||||
{
|
{
|
||||||
NotImplemented;
|
// Ask for the tetBasePtIs to trigger all processors to build
|
||||||
|
// them, otherwise, if some processors have no particles then
|
||||||
|
// there is a comms mismatch.
|
||||||
|
pMesh_.tetBasePtIs();
|
||||||
|
pMesh_.oldCellCentres();
|
||||||
|
|
||||||
|
// Update cached mesh indexing
|
||||||
|
patchNbrProc_ = patchNbrProc(pMesh_);
|
||||||
|
patchNbrProcPatch_ = patchNbrProcPatch(pMesh_);
|
||||||
|
patchNonConformalCyclicPatches_ = patchNonConformalCyclicPatches(pMesh_);
|
||||||
|
|
||||||
|
if (!globalPositionsPtr_.valid())
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Global positions are not available. "
|
||||||
|
<< "Cloud::storeGlobalPositions has not been called."
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
const vectorField& positions = globalPositionsPtr_();
|
||||||
|
|
||||||
|
// Loop the particles. Map those that remain on this processor, and
|
||||||
|
// transfer others into send arrays.
|
||||||
|
List<DynamicList<label>> sendCellIndices(Pstream::nProcs());
|
||||||
|
List<DynamicList<point>> sendPositions(Pstream::nProcs());
|
||||||
|
List<IDLList<ParticleType>> sendParticles(Pstream::nProcs());
|
||||||
|
{
|
||||||
|
label particlei = 0;
|
||||||
|
forAllIter(typename Cloud<ParticleType>, *this, iter)
|
||||||
|
{
|
||||||
|
const point& pos = positions[particlei ++];
|
||||||
|
|
||||||
|
const remote tgtProcCell =
|
||||||
|
map.mapper().srcToTgtPoint(iter().cell(), pos);
|
||||||
|
|
||||||
|
if (tgtProcCell == remote())
|
||||||
|
{
|
||||||
|
WarningInFunction
|
||||||
|
<< "Particle at " << pos << " mapped to a location outside "
|
||||||
|
<< "of the new mesh. This particle will be removed." << nl;
|
||||||
|
}
|
||||||
|
else if (tgtProcCell.proci == Pstream::myProcNo())
|
||||||
|
{
|
||||||
|
iter().map(pMesh_, pos, tgtProcCell.elementi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendCellIndices[tgtProcCell.proci].append(tgtProcCell.elementi);
|
||||||
|
sendPositions[tgtProcCell.proci].append(pos);
|
||||||
|
sendParticles[tgtProcCell.proci].append(this->remove(iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If serial then there is nothing more to do
|
||||||
|
if (!Pstream::parRun())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create transfer buffers
|
||||||
|
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
|
||||||
|
|
||||||
|
// Stream into send buffers
|
||||||
|
forAll(sendParticles, proci)
|
||||||
|
{
|
||||||
|
if (sendParticles[proci].size())
|
||||||
|
{
|
||||||
|
UOPstream particleStream(proci, pBufs);
|
||||||
|
|
||||||
|
particleStream
|
||||||
|
<< sendCellIndices[proci]
|
||||||
|
<< sendPositions[proci]
|
||||||
|
<< sendParticles[proci];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish sending
|
||||||
|
labelList receiveSizes(Pstream::nProcs());
|
||||||
|
pBufs.finishedSends(receiveSizes);
|
||||||
|
|
||||||
|
// Retrieve from receive buffers and map into the new mesh
|
||||||
|
forAll(sendParticles, proci)
|
||||||
|
{
|
||||||
|
if (receiveSizes[proci])
|
||||||
|
{
|
||||||
|
UIPstream particleStream(proci, pBufs);
|
||||||
|
|
||||||
|
const labelList receiveCellIndices(particleStream);
|
||||||
|
const List<point> receivePositions(particleStream);
|
||||||
|
IDLList<ParticleType> receiveParticles(particleStream);
|
||||||
|
|
||||||
|
label particlei = 0;
|
||||||
|
forAllIter(typename Cloud<ParticleType>, receiveParticles, iter)
|
||||||
|
{
|
||||||
|
const label celli = receiveCellIndices[particlei];
|
||||||
|
const vector& pos = receivePositions[particlei ++];
|
||||||
|
|
||||||
|
iter().map(pMesh_, pos, celli);
|
||||||
|
this->append(receiveParticles.remove(iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -215,6 +215,8 @@ triSurface/triSurfaceTools/pointToPointPlanarInterpolation.C
|
|||||||
|
|
||||||
twoDPointCorrector/twoDPointCorrector.C
|
twoDPointCorrector/twoDPointCorrector.C
|
||||||
|
|
||||||
|
patchToPatchTools/patchToPatchTools.C
|
||||||
|
|
||||||
patchToPatch/patchToPatch/patchToPatch.C
|
patchToPatch/patchToPatch/patchToPatch.C
|
||||||
patchToPatch/patchToPatch/patchToPatchParallelOps.C
|
patchToPatch/patchToPatch/patchToPatchParallelOps.C
|
||||||
patchToPatch/matching/matchingPatchToPatch.C
|
patchToPatch/matching/matchingPatchToPatch.C
|
||||||
@ -223,6 +225,14 @@ patchToPatch/inverseDistance/inverseDistancePatchToPatch.C
|
|||||||
patchToPatch/intersection/intersectionPatchToPatch.C
|
patchToPatch/intersection/intersectionPatchToPatch.C
|
||||||
patchToPatch/rays/raysPatchToPatch.C
|
patchToPatch/rays/raysPatchToPatch.C
|
||||||
|
|
||||||
|
meshToMesh/meshToMesh.C
|
||||||
|
meshToMesh/meshToMeshParallelOps.C
|
||||||
|
meshToMesh/calcMethod/meshToMeshMethod/meshToMeshMethod.C
|
||||||
|
meshToMesh/calcMethod/meshToMeshMethod/meshToMeshMethodNew.C
|
||||||
|
meshToMesh/calcMethod/cellVolumeWeight/cellVolumeWeightMethod.C
|
||||||
|
meshToMesh/calcMethod/direct/directMethod.C
|
||||||
|
meshToMesh/calcMethod/mapNearest/mapNearestMethod.C
|
||||||
|
|
||||||
mappedPatches/mappedPatchBase/mappedPatchBase.C
|
mappedPatches/mappedPatchBase/mappedPatchBase.C
|
||||||
mappedPatches/mappedPolyPatch/mappedPolyPatch.C
|
mappedPatches/mappedPolyPatch/mappedPolyPatch.C
|
||||||
mappedPatches/mappedPolyPatch/mappedWallPolyPatch.C
|
mappedPatches/mappedPolyPatch/mappedWallPolyPatch.C
|
||||||
|
|||||||
414
src/meshTools/meshToMesh/meshToMesh.C
Normal file
414
src/meshTools/meshToMesh/meshToMesh.C
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2012-2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "meshToMesh.H"
|
||||||
|
#include "globalIndex.H"
|
||||||
|
#include "meshToMeshMethod.H"
|
||||||
|
#include "PatchTools.H"
|
||||||
|
#include "patchToPatchTools.H"
|
||||||
|
#include "processorPolyPatch.H"
|
||||||
|
#include "Time.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(meshToMesh, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::scalar Foam::meshToMesh::calculateCellToCells(const word& methodName)
|
||||||
|
{
|
||||||
|
Info<< "Creating mesh-to-mesh addressing for " << srcMesh_.name()
|
||||||
|
<< " and " << tgtMesh_.name() << " regions using "
|
||||||
|
<< methodName << endl;
|
||||||
|
|
||||||
|
singleProcess_ =
|
||||||
|
patchToPatchTools::singleProcess
|
||||||
|
(
|
||||||
|
srcMesh_.nCells(),
|
||||||
|
tgtMesh_.nCells()
|
||||||
|
);
|
||||||
|
|
||||||
|
autoPtr<meshToMeshMethod> methodPtr;
|
||||||
|
|
||||||
|
scalar V = 0;
|
||||||
|
|
||||||
|
if (isSingleProcess())
|
||||||
|
{
|
||||||
|
// Do the intersection
|
||||||
|
methodPtr = meshToMeshMethod::New(methodName, srcMesh_, tgtMesh_);
|
||||||
|
V = methodPtr->calculate
|
||||||
|
(
|
||||||
|
srcLocalTgtCells_,
|
||||||
|
srcWeights_,
|
||||||
|
tgtLocalSrcCells_,
|
||||||
|
tgtWeights_
|
||||||
|
);
|
||||||
|
|
||||||
|
// Normalise the weights
|
||||||
|
methodPtr->normalise(srcMesh_, srcLocalTgtCells_, srcWeights_);
|
||||||
|
methodPtr->normalise(tgtMesh_, tgtLocalSrcCells_, tgtWeights_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create the target map of overlapping cells. This map gets remote
|
||||||
|
// parts of the target mesh so that everything needed to compute an
|
||||||
|
// intersection is available locally to the source. Use it to create a
|
||||||
|
// source-local target mesh.
|
||||||
|
tgtMapPtr_ =
|
||||||
|
patchToPatchTools::constructDistributionMap
|
||||||
|
(
|
||||||
|
tgtMeshSendCells(srcMesh_, tgtMesh_)
|
||||||
|
);
|
||||||
|
localTgtProcCellsPtr_.reset
|
||||||
|
(
|
||||||
|
new List<remote>
|
||||||
|
(
|
||||||
|
distributeMesh
|
||||||
|
(
|
||||||
|
tgtMapPtr_(),
|
||||||
|
tgtMesh_,
|
||||||
|
localTgtMeshPtr_
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const polyMesh& localTgtMesh = localTgtMeshPtr_();
|
||||||
|
|
||||||
|
if (debug > 1)
|
||||||
|
{
|
||||||
|
Pout<< "Writing local target mesh: "
|
||||||
|
<< localTgtMesh.name() << endl;
|
||||||
|
localTgtMesh.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the intersection
|
||||||
|
methodPtr = meshToMeshMethod::New(methodName, srcMesh_, localTgtMesh);
|
||||||
|
V = methodPtr->calculate
|
||||||
|
(
|
||||||
|
srcLocalTgtCells_,
|
||||||
|
srcWeights_,
|
||||||
|
tgtLocalSrcCells_,
|
||||||
|
tgtWeights_
|
||||||
|
);
|
||||||
|
|
||||||
|
// Trim the local target mesh
|
||||||
|
trimLocalTgt();
|
||||||
|
|
||||||
|
if (debug > 1)
|
||||||
|
{
|
||||||
|
Pout<< "Writing trimmed local target mesh: "
|
||||||
|
<< localTgtMesh.name() << endl;
|
||||||
|
localTgtMesh.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the source map
|
||||||
|
srcMapPtr_ =
|
||||||
|
patchToPatchTools::constructDistributionMap
|
||||||
|
(
|
||||||
|
patchToPatchTools::procSendIndices
|
||||||
|
(
|
||||||
|
tgtLocalSrcCells_,
|
||||||
|
localTgtProcCellsPtr_()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
localSrcProcCellsPtr_.reset
|
||||||
|
(
|
||||||
|
new List<remote>
|
||||||
|
(
|
||||||
|
patchToPatchTools::distributeAddressing(srcMapPtr_())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Collect the addressing on the target
|
||||||
|
patchToPatchTools::rDistributeTgtAddressing
|
||||||
|
(
|
||||||
|
tgtMesh_.nCells(),
|
||||||
|
tgtMapPtr_(),
|
||||||
|
localSrcProcCellsPtr_(),
|
||||||
|
tgtLocalSrcCells_
|
||||||
|
);
|
||||||
|
|
||||||
|
// Collect the weights on the target
|
||||||
|
patchToPatchTools::rDistributeListList
|
||||||
|
(
|
||||||
|
tgtMesh_.nCells(),
|
||||||
|
tgtMapPtr_(),
|
||||||
|
tgtWeights_
|
||||||
|
);
|
||||||
|
|
||||||
|
// Normalise the weights
|
||||||
|
methodPtr->normalise(srcMesh_, srcLocalTgtCells_, srcWeights_);
|
||||||
|
methodPtr->normalise(tgtMesh_, tgtLocalSrcCells_, tgtWeights_);
|
||||||
|
|
||||||
|
// collect volume intersection contributions
|
||||||
|
reduce(V, sumOp<scalar>());
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< " Overlap volume: " << V << endl;
|
||||||
|
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh::calculatePatchToPatches(const word& methodName)
|
||||||
|
{
|
||||||
|
if (!srcToTgtPatchToPatches_.empty())
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "srcToTgtPatchToPatches already calculated"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
const word& patchToPatchType =
|
||||||
|
meshToMeshMethod::New
|
||||||
|
(
|
||||||
|
methodName,
|
||||||
|
NullObjectRef<polyMesh>(),
|
||||||
|
NullObjectRef<polyMesh>()
|
||||||
|
)->patchToPatchMethod();
|
||||||
|
|
||||||
|
srcToTgtPatchToPatches_.setSize(srcToTgtPatchIDs_.size());
|
||||||
|
|
||||||
|
forAll(srcToTgtPatchIDs_, i)
|
||||||
|
{
|
||||||
|
const label srcPatchi = srcToTgtPatchIDs_[i].first();
|
||||||
|
const label tgtPatchi = srcToTgtPatchIDs_[i].second();
|
||||||
|
|
||||||
|
const polyPatch& srcPP = srcMesh_.boundaryMesh()[srcPatchi];
|
||||||
|
const polyPatch& tgtPP = tgtMesh_.boundaryMesh()[tgtPatchi];
|
||||||
|
|
||||||
|
Info<< "Creating patchToPatch between source patch "
|
||||||
|
<< srcPP.name() << " and target patch " << tgtPP.name()
|
||||||
|
<< " using " << patchToPatchType << endl;
|
||||||
|
|
||||||
|
Info<< incrIndent;
|
||||||
|
|
||||||
|
srcToTgtPatchToPatches_.set
|
||||||
|
(
|
||||||
|
i,
|
||||||
|
patchToPatch::New(patchToPatchType, true)
|
||||||
|
);
|
||||||
|
|
||||||
|
srcToTgtPatchToPatches_[i].update
|
||||||
|
(
|
||||||
|
srcPP,
|
||||||
|
PatchTools::pointNormals(srcMesh_, srcPP),
|
||||||
|
tgtPP
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< decrIndent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh::constructNoCuttingPatches
|
||||||
|
(
|
||||||
|
const word& methodName,
|
||||||
|
const bool interpAllPatches
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (interpAllPatches)
|
||||||
|
{
|
||||||
|
DynamicList<labelPair> srcToTgtPatchIDs;
|
||||||
|
|
||||||
|
forAll(srcMesh_.boundaryMesh(), srcPatchi)
|
||||||
|
{
|
||||||
|
const polyPatch& srcPp = srcMesh_.boundaryMesh()[srcPatchi];
|
||||||
|
|
||||||
|
// We want to map all the global patches, including constraint
|
||||||
|
// patches (since they might have mappable properties, e.g.
|
||||||
|
// jumpCyclic). We'll fix the value afterwards.
|
||||||
|
if (!isA<processorPolyPatch>(srcPp))
|
||||||
|
{
|
||||||
|
const label tgtPatchi =
|
||||||
|
tgtMesh_.boundaryMesh().findPatchID(srcPp.name());
|
||||||
|
|
||||||
|
if (tgtPatchi == -1)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Source patch " << srcPp.name()
|
||||||
|
<< " not found in target mesh. "
|
||||||
|
<< "Available target patches are "
|
||||||
|
<< tgtMesh_.boundaryMesh().names()
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
srcToTgtPatchIDs.append(labelPair(srcPatchi, tgtPatchi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srcToTgtPatchIDs_.transfer(srcToTgtPatchIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate cell addressing and weights
|
||||||
|
calculateCellToCells(methodName);
|
||||||
|
|
||||||
|
// calculate patch addressing and weights
|
||||||
|
calculatePatchToPatches(methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh::constructFromCuttingPatches
|
||||||
|
(
|
||||||
|
const word& methodName,
|
||||||
|
const HashTable<word>& patchMap,
|
||||||
|
const wordList& tgtCuttingPatches
|
||||||
|
)
|
||||||
|
{
|
||||||
|
srcToTgtPatchIDs_.setSize(patchMap.size());
|
||||||
|
label i = 0;
|
||||||
|
forAllConstIter(HashTable<word>, patchMap, iter)
|
||||||
|
{
|
||||||
|
const word& tgtPatchName = iter.key();
|
||||||
|
const word& srcPatchName = iter();
|
||||||
|
|
||||||
|
srcToTgtPatchIDs_[i++] =
|
||||||
|
labelPair
|
||||||
|
(
|
||||||
|
srcMesh_.boundaryMesh().findPatchID(srcPatchName),
|
||||||
|
tgtMesh_.boundaryMesh().findPatchID(tgtPatchName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate cell addressing and weights
|
||||||
|
calculateCellToCells(methodName);
|
||||||
|
|
||||||
|
// calculate patch addressing and weights
|
||||||
|
calculatePatchToPatches(methodName);
|
||||||
|
|
||||||
|
// set IDs of cutting patches on target mesh
|
||||||
|
tgtCuttingPatchIDs_.setSize(tgtCuttingPatches.size());
|
||||||
|
forAll(tgtCuttingPatchIDs_, i)
|
||||||
|
{
|
||||||
|
const word& patchName = tgtCuttingPatches[i];
|
||||||
|
tgtCuttingPatchIDs_[i] = tgtMesh_.boundaryMesh().findPatchID(patchName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::meshToMesh::meshToMesh
|
||||||
|
(
|
||||||
|
const polyMesh& src,
|
||||||
|
const polyMesh& tgt,
|
||||||
|
const word& methodName,
|
||||||
|
bool interpAllPatches
|
||||||
|
)
|
||||||
|
:
|
||||||
|
srcMesh_(src),
|
||||||
|
tgtMesh_(tgt),
|
||||||
|
srcToTgtPatchIDs_(),
|
||||||
|
srcToTgtPatchToPatches_(),
|
||||||
|
tgtCuttingPatchIDs_(),
|
||||||
|
srcLocalTgtCells_(),
|
||||||
|
tgtLocalSrcCells_(),
|
||||||
|
srcWeights_(),
|
||||||
|
tgtWeights_(),
|
||||||
|
singleProcess_(-1),
|
||||||
|
srcMapPtr_(nullptr),
|
||||||
|
tgtMapPtr_(nullptr),
|
||||||
|
localSrcProcCellsPtr_(nullptr),
|
||||||
|
localTgtProcCellsPtr_(nullptr),
|
||||||
|
localTgtMeshPtr_(nullptr)
|
||||||
|
{
|
||||||
|
constructNoCuttingPatches
|
||||||
|
(
|
||||||
|
methodName,
|
||||||
|
interpAllPatches
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::meshToMesh::meshToMesh
|
||||||
|
(
|
||||||
|
const polyMesh& src,
|
||||||
|
const polyMesh& tgt,
|
||||||
|
const word& methodName,
|
||||||
|
const HashTable<word>& patchMap,
|
||||||
|
const wordList& tgtCuttingPatches
|
||||||
|
)
|
||||||
|
:
|
||||||
|
srcMesh_(src),
|
||||||
|
tgtMesh_(tgt),
|
||||||
|
srcToTgtPatchIDs_(),
|
||||||
|
srcToTgtPatchToPatches_(),
|
||||||
|
tgtCuttingPatchIDs_(),
|
||||||
|
srcLocalTgtCells_(),
|
||||||
|
tgtLocalSrcCells_(),
|
||||||
|
srcWeights_(),
|
||||||
|
tgtWeights_(),
|
||||||
|
singleProcess_(-1),
|
||||||
|
srcMapPtr_(nullptr),
|
||||||
|
tgtMapPtr_(nullptr),
|
||||||
|
localTgtMeshPtr_(nullptr)
|
||||||
|
{
|
||||||
|
constructFromCuttingPatches
|
||||||
|
(
|
||||||
|
methodName,
|
||||||
|
patchMap,
|
||||||
|
tgtCuttingPatches
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::meshToMesh::~meshToMesh()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::remote Foam::meshToMesh::srcToTgtPoint
|
||||||
|
(
|
||||||
|
const label srcCelli,
|
||||||
|
const point& p
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
forAll(srcLocalTgtCells_[srcCelli], i)
|
||||||
|
{
|
||||||
|
const label tgtCelli = srcLocalTgtCells_[srcCelli][i];
|
||||||
|
|
||||||
|
const polyMesh& tgtMesh =
|
||||||
|
singleProcess_ == -1 ? localTgtMeshPtr_() : tgtMesh_;
|
||||||
|
|
||||||
|
if (tgtMesh.pointInCell(p, tgtCelli))
|
||||||
|
{
|
||||||
|
return
|
||||||
|
singleProcess_ == -1
|
||||||
|
? localTgtProcCellsPtr_()[tgtCelli]
|
||||||
|
: remote(Pstream::myProcNo(), tgtCelli);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return remote();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -45,7 +45,6 @@ SourceFiles
|
|||||||
#include "polyMesh.H"
|
#include "polyMesh.H"
|
||||||
#include "boundBox.H"
|
#include "boundBox.H"
|
||||||
#include "distributionMap.H"
|
#include "distributionMap.H"
|
||||||
#include "volFieldsFwd.H"
|
|
||||||
#include "NamedEnum.H"
|
#include "NamedEnum.H"
|
||||||
#include "patchToPatch.H"
|
#include "patchToPatch.H"
|
||||||
|
|
||||||
@ -63,57 +62,65 @@ class meshToMesh
|
|||||||
// Private Data
|
// Private Data
|
||||||
|
|
||||||
//- Reference to the source mesh
|
//- Reference to the source mesh
|
||||||
const polyMesh& srcRegion_;
|
const polyMesh& srcMesh_;
|
||||||
|
|
||||||
//- Reference to the target mesh
|
//- Reference to the target mesh
|
||||||
const polyMesh& tgtRegion_;
|
const polyMesh& tgtMesh_;
|
||||||
|
|
||||||
//- List of target patch IDs per source patch (local index)
|
//- List of corresponding source and target patches that are to be
|
||||||
List<label> srcPatchID_;
|
// mapped to each other
|
||||||
|
List<labelPair> srcToTgtPatchIDs_;
|
||||||
//- List of source patch IDs per target patch (local index)
|
|
||||||
List<label> tgtPatchID_;
|
|
||||||
|
|
||||||
//- List of patchToPatch interpolation engines between source and
|
//- List of patchToPatch interpolation engines between source and
|
||||||
// target patches
|
// target patches
|
||||||
PtrList<patchToPatch> patchToPatches_;
|
PtrList<patchToPatch> srcToTgtPatchToPatches_;
|
||||||
|
|
||||||
//- Cutting patches whose values are set using a zero-gradient condition
|
//- Cutting patches whose values are set using a zero-gradient condition
|
||||||
List<label> cuttingPatches_;
|
labelList tgtCuttingPatchIDs_;
|
||||||
|
|
||||||
//- Source to target cell addressing
|
//- For each source cell, the coupled local target cells
|
||||||
labelListList srcToTgtCellAddr_;
|
labelListList srcLocalTgtCells_;
|
||||||
|
|
||||||
//- Target to source cell addressing
|
//- For each target cell, the coupled local source cells
|
||||||
labelListList tgtToSrcCellAddr_;
|
labelListList tgtLocalSrcCells_;
|
||||||
|
|
||||||
//- Source to target cell interpolation weights
|
//- For each source cell, the coupled target weights
|
||||||
scalarListList srcToTgtCellWght_;
|
scalarListList srcWeights_;
|
||||||
|
|
||||||
//- Target to source cell interpolation weights
|
//- For each target cell, the coupled source weights
|
||||||
scalarListList tgtToSrcCellWght_;
|
scalarListList tgtWeights_;
|
||||||
|
|
||||||
//- Index of processor that holds all of both sides. -1 in all other
|
//- Index of processor that holds all of both sides, or -1
|
||||||
// cases
|
label singleProcess_;
|
||||||
label singleMeshProc_;
|
|
||||||
|
|
||||||
//- Source map pointer - parallel running only
|
//- Map from source patch cells to target-local source patch cells
|
||||||
autoPtr<distributionMap> srcMapPtr_;
|
autoPtr<distributionMap> srcMapPtr_;
|
||||||
|
|
||||||
//- Target map pointer - parallel running only
|
//- Map from target patch cells to source-local target patch cells
|
||||||
autoPtr<distributionMap> tgtMapPtr_;
|
autoPtr<distributionMap> tgtMapPtr_;
|
||||||
|
|
||||||
|
//- When running in parallel, a map from local source cell index to
|
||||||
|
// source processor and cell index
|
||||||
|
autoPtr<List<remote>> localSrcProcCellsPtr_;
|
||||||
|
|
||||||
|
//- When running in parallel, a map from local target cell index to
|
||||||
|
// target processor and cell index
|
||||||
|
autoPtr<List<remote>> localTgtProcCellsPtr_;
|
||||||
|
|
||||||
|
//- The target mesh, distributed locally to the source
|
||||||
|
autoPtr<polyMesh> localTgtMeshPtr_;
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
//- Helper function to add a constant offset to a list
|
//- Helper function to add a constant offset to a list
|
||||||
template<class Type>
|
template<class Type>
|
||||||
void add(UList<Type>& fld, const label offset) const;
|
static void add(UList<Type>& fld, const label offset);
|
||||||
|
|
||||||
//- Calculate the internal mesh overlap. Returns the overlap volume.
|
//- Calculate the cell intersections. Returns the overlap volume.
|
||||||
scalar calculate(const word& methodName);
|
scalar calculateCellToCells(const word& methodName);
|
||||||
|
|
||||||
//- Calculate patch overlap
|
//- Calculate patch intersections
|
||||||
void calculatePatchToPatches(const word& patchToPatchType);
|
void calculatePatchToPatches(const word& patchToPatchType);
|
||||||
|
|
||||||
//- Constructor helper
|
//- Constructor helper
|
||||||
@ -128,66 +135,49 @@ class meshToMesh
|
|||||||
(
|
(
|
||||||
const word& methodName,
|
const word& methodName,
|
||||||
const HashTable<word>& patchMap,
|
const HashTable<word>& patchMap,
|
||||||
const wordList& cuttingPatches
|
const wordList& tgtCuttingPatches
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Return the list of patchToPatch interpolation engines between
|
|
||||||
// source and target patches
|
|
||||||
inline const PtrList<patchToPatch>& patchToPatches() const;
|
|
||||||
|
|
||||||
|
|
||||||
// Parallel operations
|
// Parallel operations
|
||||||
|
|
||||||
//- Determine whether the meshes are split across multiple pocessors
|
//- Determine which target cells need to be sent to the source.
|
||||||
label calcDistribution
|
// This is done before intersection. Bound boxes are used to
|
||||||
|
// estimate what cells will intersect.
|
||||||
|
labelListList tgtMeshSendCells
|
||||||
(
|
(
|
||||||
const polyMesh& src,
|
const polyMesh& srcMesh,
|
||||||
const polyMesh& tgt
|
const polyMesh& tgtMesh
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
//- Determine which processor bounding-boxes overlap
|
//- Distribute a mesh given its distribution map
|
||||||
label calcOverlappingProcs
|
static List<remote> distributeMesh
|
||||||
(
|
|
||||||
const List<boundBox>& procBb,
|
|
||||||
const boundBox& bb,
|
|
||||||
boolList& overlaps
|
|
||||||
) const;
|
|
||||||
|
|
||||||
//- Calculate the mapping between processors
|
|
||||||
autoPtr<distributionMap> calcProcMap
|
|
||||||
(
|
|
||||||
const polyMesh& src,
|
|
||||||
const polyMesh& tgt
|
|
||||||
) const;
|
|
||||||
|
|
||||||
//- Distribute mesh info from 'my' processor to others
|
|
||||||
void distributeCells
|
|
||||||
(
|
(
|
||||||
const distributionMap& map,
|
const distributionMap& map,
|
||||||
const polyMesh& tgtMesh,
|
const polyMesh& mesh,
|
||||||
const globalIndex& globalTgtCells,
|
autoPtr<polyMesh>& localMeshPtr
|
||||||
List<pointField>& points,
|
);
|
||||||
List<label>& nInternalFaces,
|
|
||||||
List<faceList>& faces,
|
|
||||||
List<labelList>& faceOwner,
|
|
||||||
List<labelList>& faceNeighbour,
|
|
||||||
List<labelList>& globalCellIDs,
|
|
||||||
List<labelList>& nbrProcIDs,
|
|
||||||
List<labelList>& procLocalFaceIDs
|
|
||||||
) const;
|
|
||||||
|
|
||||||
//- Collect pieces of tgt mesh from other processors and restructure
|
//- Trim the local target addressing and mesh so that communication
|
||||||
void distributeAndMergeCells
|
// from the target to the source is optimised
|
||||||
(
|
void trimLocalTgt();
|
||||||
const distributionMap& map,
|
|
||||||
const polyMesh& tgtMesh,
|
|
||||||
const globalIndex& globalTgtCells,
|
protected:
|
||||||
pointField& tgtPoints,
|
|
||||||
faceList& tgtFaces,
|
// Protected Member Functions
|
||||||
labelList& tgtFaceOwners,
|
|
||||||
labelList& tgtFaceNeighbours,
|
// Access
|
||||||
labelList& tgtCellIDs
|
|
||||||
) const;
|
//- Return the source patch indices
|
||||||
|
inline const List<labelPair>& srcToTgtPatchIDs() const;
|
||||||
|
|
||||||
|
//- Return the list of patchToPatch interpolation engines between
|
||||||
|
// source and target patches
|
||||||
|
inline const PtrList<patchToPatch>& srcToTgtPatchToPatches() const;
|
||||||
|
|
||||||
|
//- Return the cutting patch indices
|
||||||
|
inline const labelList& tgtCuttingPatchIDs() const;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -195,6 +185,7 @@ public:
|
|||||||
//- Run-time type information
|
//- Run-time type information
|
||||||
TypeName("meshToMesh");
|
TypeName("meshToMesh");
|
||||||
|
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
//- Construct from source and target meshes, generic mapping methods
|
//- Construct from source and target meshes, generic mapping methods
|
||||||
@ -229,22 +220,17 @@ public:
|
|||||||
// Access
|
// Access
|
||||||
|
|
||||||
//- Return const access to the source mesh
|
//- Return const access to the source mesh
|
||||||
inline const polyMesh& srcRegion() const;
|
inline const polyMesh& srcMesh() const;
|
||||||
|
|
||||||
//- Return const access to the target mesh
|
//- Return const access to the target mesh
|
||||||
inline const polyMesh& tgtRegion() const;
|
inline const polyMesh& tgtMesh() const;
|
||||||
|
|
||||||
//- Return const access to the source to target cell addressing
|
//- Index of the processor holding all cells of the meshToMesh,
|
||||||
inline const labelListList& srcToTgtCellAddr() const;
|
// or -1 if spread across multiple processors
|
||||||
|
inline label singleProcess() const;
|
||||||
|
|
||||||
//- Return const access to the target to source cell addressing
|
//- Is this intersection on a single process?
|
||||||
inline const labelListList& tgtToSrcCellAddr() const;
|
inline bool isSingleProcess() const;
|
||||||
|
|
||||||
//- Return const access to the source to target cell weights
|
|
||||||
inline const scalarListList& srcToTgtCellWght() const;
|
|
||||||
|
|
||||||
//- Return const access to the target to source cell weights
|
|
||||||
inline const scalarListList& tgtToSrcCellWght() const;
|
|
||||||
|
|
||||||
|
|
||||||
// Evaluation
|
// Evaluation
|
||||||
@ -283,24 +269,18 @@ public:
|
|||||||
tmp<Field<Type>> mapTgtToSrc(const Field<Type>& tgtFld) const;
|
tmp<Field<Type>> mapTgtToSrc(const Field<Type>& tgtFld) const;
|
||||||
|
|
||||||
|
|
||||||
// Source-to-target volume field mapping
|
// Source-to-target point finding
|
||||||
|
|
||||||
//- Interpolate a field with a defined operation. Values
|
//- Find the target processor and cell associated with a point
|
||||||
// passed in via 'result' are used to initialise the return
|
// in a source cell. Note that this will only work with
|
||||||
// value
|
// methods that fill a cell's stencil with everything that
|
||||||
template<class Type>
|
// overlaps that cell. At present this is just
|
||||||
void mapSrcToTgt
|
// cellVolumeWeightMethod, but we might add a cheaper
|
||||||
|
// bound-box based method like patchToPatches::rays in future.
|
||||||
|
remote srcToTgtPoint
|
||||||
(
|
(
|
||||||
const GeometricField<Type, fvPatchField, volMesh>& field,
|
const label srcCelli,
|
||||||
GeometricField<Type, fvPatchField, volMesh>& result
|
const point& p
|
||||||
) const;
|
|
||||||
|
|
||||||
//- Interpolate a field with a defined operation. The initial
|
|
||||||
// values of the result are set to zero
|
|
||||||
template<class Type>
|
|
||||||
tmp<GeometricField<Type, fvPatchField, volMesh>> mapSrcToTgt
|
|
||||||
(
|
|
||||||
const GeometricField<Type, fvPatchField, volMesh>& field
|
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
|
|
||||||
@ -25,52 +25,51 @@ License
|
|||||||
|
|
||||||
#include "meshToMesh.H"
|
#include "meshToMesh.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
inline const Foam::polyMesh& Foam::meshToMesh::srcRegion() const
|
inline const Foam::List<Foam::labelPair>&
|
||||||
|
Foam::meshToMesh::srcToTgtPatchIDs() const
|
||||||
{
|
{
|
||||||
return srcRegion_;
|
return srcToTgtPatchIDs_;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const Foam::polyMesh& Foam::meshToMesh::tgtRegion() const
|
|
||||||
{
|
|
||||||
return tgtRegion_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const Foam::labelListList&
|
|
||||||
Foam::meshToMesh::srcToTgtCellAddr() const
|
|
||||||
{
|
|
||||||
return srcToTgtCellAddr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const Foam::labelListList&
|
|
||||||
Foam::meshToMesh::tgtToSrcCellAddr() const
|
|
||||||
{
|
|
||||||
return tgtToSrcCellAddr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const Foam::scalarListList&
|
|
||||||
Foam::meshToMesh::srcToTgtCellWght() const
|
|
||||||
{
|
|
||||||
return srcToTgtCellWght_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const Foam::scalarListList&
|
|
||||||
Foam::meshToMesh::tgtToSrcCellWght() const
|
|
||||||
{
|
|
||||||
return tgtToSrcCellWght_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline const Foam::PtrList<Foam::patchToPatch>&
|
inline const Foam::PtrList<Foam::patchToPatch>&
|
||||||
Foam::meshToMesh::patchToPatches() const
|
Foam::meshToMesh::srcToTgtPatchToPatches() const
|
||||||
{
|
{
|
||||||
return patchToPatches_;
|
return srcToTgtPatchToPatches_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const Foam::labelList& Foam::meshToMesh::tgtCuttingPatchIDs() const
|
||||||
|
{
|
||||||
|
return tgtCuttingPatchIDs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
inline const Foam::polyMesh& Foam::meshToMesh::srcMesh() const
|
||||||
|
{
|
||||||
|
return srcMesh_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const Foam::polyMesh& Foam::meshToMesh::tgtMesh() const
|
||||||
|
{
|
||||||
|
return tgtMesh_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Foam::label Foam::meshToMesh::singleProcess() const
|
||||||
|
{
|
||||||
|
return singleProcess_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Foam::meshToMesh::isSingleProcess() const
|
||||||
|
{
|
||||||
|
return singleProcess_ != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
875
src/meshTools/meshToMesh/meshToMeshParallelOps.C
Normal file
875
src/meshTools/meshToMesh/meshToMeshParallelOps.C
Normal file
@ -0,0 +1,875 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2012-2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "meshToMesh.H"
|
||||||
|
#include "OFstream.H"
|
||||||
|
#include "Time.H"
|
||||||
|
#include "globalIndex.H"
|
||||||
|
#include "processorPolyPatch.H"
|
||||||
|
#include "SubField.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::labelListList Foam::meshToMesh::tgtMeshSendCells
|
||||||
|
(
|
||||||
|
const polyMesh& srcMesh,
|
||||||
|
const polyMesh& tgtMesh
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// Calculate and communicate the bound boxes for the source meshes
|
||||||
|
List<boundBox> procBb(Pstream::nProcs(), boundBox());
|
||||||
|
if (srcMesh.nCells() > 0)
|
||||||
|
{
|
||||||
|
// Bounding box for this mesh. Do not reduce.
|
||||||
|
procBb[Pstream::myProcNo()] = boundBox(srcMesh.points(), false);
|
||||||
|
|
||||||
|
// Slightly increase size to allow for cases where boxes are aligned
|
||||||
|
procBb[Pstream::myProcNo()].inflate(0.01);
|
||||||
|
}
|
||||||
|
Pstream::gatherList(procBb);
|
||||||
|
Pstream::scatterList(procBb);
|
||||||
|
|
||||||
|
// per processor indices into all segments to send
|
||||||
|
List<DynamicList<label>> resultDyn
|
||||||
|
(
|
||||||
|
Pstream::nProcs(),
|
||||||
|
DynamicList<label>(tgtMesh.nCells()/Pstream::nProcs())
|
||||||
|
);
|
||||||
|
|
||||||
|
// Send a target cell to a process if it overlaps the source bound box
|
||||||
|
// for that process
|
||||||
|
forAll(tgtMesh.cells(), tgtCelli)
|
||||||
|
{
|
||||||
|
const boundBox cellBb =
|
||||||
|
tgtMesh.cells()[tgtCelli].bb(tgtMesh.points(), tgtMesh.faces());
|
||||||
|
|
||||||
|
forAll(procBb, proci)
|
||||||
|
{
|
||||||
|
if (procBb[proci].overlaps(cellBb))
|
||||||
|
{
|
||||||
|
resultDyn[proci].append(tgtCelli);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer to permanent storage and return
|
||||||
|
labelListList result(Pstream::nProcs());
|
||||||
|
forAll(result, proci)
|
||||||
|
{
|
||||||
|
result[proci].transfer(resultDyn[proci]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::List<Foam::remote> Foam::meshToMesh::distributeMesh
|
||||||
|
(
|
||||||
|
const distributionMap& map,
|
||||||
|
const polyMesh& mesh,
|
||||||
|
autoPtr<polyMesh>& localMeshPtr
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
|
||||||
|
|
||||||
|
// Exchange raw mesh topology/geometry
|
||||||
|
List<pointField> allPoints(Pstream::nProcs());
|
||||||
|
labelList allNInternalFaces(Pstream::nProcs(), 0);
|
||||||
|
List<faceList> allFaces(Pstream::nProcs());
|
||||||
|
List<labelList> allFaceOwners(Pstream::nProcs());
|
||||||
|
List<labelList> allFaceNeighbours(Pstream::nProcs());
|
||||||
|
List<List<remote>> allProcCells(Pstream::nProcs());
|
||||||
|
List<List<remote>> allProcProcessorPatchFaces(Pstream::nProcs());
|
||||||
|
for (label domain = 0; domain < Pstream::nProcs(); domain++)
|
||||||
|
{
|
||||||
|
const labelList& sendElems = map.subMap()[domain];
|
||||||
|
|
||||||
|
if (sendElems.size())
|
||||||
|
{
|
||||||
|
// reverse cell map
|
||||||
|
labelList reverseCellMap(mesh.nCells(), -1);
|
||||||
|
forAll(sendElems, subCelli)
|
||||||
|
{
|
||||||
|
reverseCellMap[sendElems[subCelli]] = subCelli;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicList<face> subFaces(mesh.nFaces());
|
||||||
|
DynamicList<label> subFaceOwner(mesh.nFaces());
|
||||||
|
DynamicList<label> subFaceNeighbour(mesh.nFaces());
|
||||||
|
DynamicList<remote> subProcProcessorPatchFaces(mesh.nFaces());
|
||||||
|
|
||||||
|
label nInternal = 0;
|
||||||
|
|
||||||
|
// internal faces
|
||||||
|
forAll(mesh.faceNeighbour(), facei)
|
||||||
|
{
|
||||||
|
const label own = mesh.faceOwner()[facei];
|
||||||
|
const label nbr = mesh.faceNeighbour()[facei];
|
||||||
|
const label subOwn = reverseCellMap[own];
|
||||||
|
const label subNbr = reverseCellMap[nbr];
|
||||||
|
|
||||||
|
if (subOwn != -1 && subNbr != -1)
|
||||||
|
{
|
||||||
|
nInternal++;
|
||||||
|
|
||||||
|
if (subOwn < subNbr)
|
||||||
|
{
|
||||||
|
subFaces.append(mesh.faces()[facei]);
|
||||||
|
subFaceOwner.append(subOwn);
|
||||||
|
subFaceNeighbour.append(subNbr);
|
||||||
|
subProcProcessorPatchFaces.append(remote());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subFaces.append(mesh.faces()[facei].reverseFace());
|
||||||
|
subFaceOwner.append(subNbr);
|
||||||
|
subFaceNeighbour.append(subOwn);
|
||||||
|
subProcProcessorPatchFaces.append(remote());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// boundary faces for new region
|
||||||
|
forAll(mesh.faceNeighbour(), facei)
|
||||||
|
{
|
||||||
|
const label own = mesh.faceOwner()[facei];
|
||||||
|
const label nbr = mesh.faceNeighbour()[facei];
|
||||||
|
const label subOwn = reverseCellMap[own];
|
||||||
|
const label subNbr = reverseCellMap[nbr];
|
||||||
|
|
||||||
|
if (subOwn != -1 && subNbr == -1)
|
||||||
|
{
|
||||||
|
subFaces.append(mesh.faces()[facei]);
|
||||||
|
subFaceOwner.append(subOwn);
|
||||||
|
subFaceNeighbour.append(subNbr);
|
||||||
|
subProcProcessorPatchFaces.append(remote());
|
||||||
|
}
|
||||||
|
else if (subOwn == -1 && subNbr != -1)
|
||||||
|
{
|
||||||
|
subFaces.append(mesh.faces()[facei].reverseFace());
|
||||||
|
subFaceOwner.append(subNbr);
|
||||||
|
subFaceNeighbour.append(subOwn);
|
||||||
|
subProcProcessorPatchFaces.append(remote());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// boundary faces of existing region
|
||||||
|
forAll(mesh.boundaryMesh(), patchi)
|
||||||
|
{
|
||||||
|
const polyPatch& pp = mesh.boundaryMesh()[patchi];
|
||||||
|
|
||||||
|
const label nbrProci =
|
||||||
|
isA<processorPolyPatch>(pp)
|
||||||
|
? refCast<const processorPolyPatch>(pp).neighbProcNo()
|
||||||
|
: -1;
|
||||||
|
|
||||||
|
forAll(pp, i)
|
||||||
|
{
|
||||||
|
const label facei = pp.start() + i;
|
||||||
|
const label own = mesh.faceOwner()[facei];
|
||||||
|
|
||||||
|
if (reverseCellMap[own] != -1)
|
||||||
|
{
|
||||||
|
subFaces.append(mesh.faces()[facei]);
|
||||||
|
subFaceOwner.append(reverseCellMap[own]);
|
||||||
|
subFaceNeighbour.append(-1);
|
||||||
|
subProcProcessorPatchFaces.append
|
||||||
|
(
|
||||||
|
nbrProci != -1 ? remote(nbrProci, i) : remote()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse point map
|
||||||
|
labelList reversePointMap(mesh.nPoints(), -1);
|
||||||
|
DynamicList<point> subPoints(mesh.nPoints());
|
||||||
|
forAll(subFaces, subFacei)
|
||||||
|
{
|
||||||
|
face& f = subFaces[subFacei];
|
||||||
|
forAll(f, fp)
|
||||||
|
{
|
||||||
|
label pointi = f[fp];
|
||||||
|
if (reversePointMap[pointi] == -1)
|
||||||
|
{
|
||||||
|
reversePointMap[pointi] = subPoints.size();
|
||||||
|
subPoints.append(mesh.points()[pointi]);
|
||||||
|
}
|
||||||
|
|
||||||
|
f[fp] = reversePointMap[pointi];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cell indices
|
||||||
|
List<remote> subProcCells(sendElems.size());
|
||||||
|
forAll(sendElems, i)
|
||||||
|
{
|
||||||
|
subProcCells[i] = remote(Pstream::myProcNo(), sendElems[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass data
|
||||||
|
if (domain == Pstream::myProcNo())
|
||||||
|
{
|
||||||
|
// allocate my own data
|
||||||
|
allPoints[Pstream::myProcNo()] = subPoints;
|
||||||
|
allNInternalFaces[Pstream::myProcNo()] = nInternal;
|
||||||
|
allFaces[Pstream::myProcNo()] = subFaces;
|
||||||
|
allFaceOwners[Pstream::myProcNo()] = subFaceOwner;
|
||||||
|
allFaceNeighbours[Pstream::myProcNo()] = subFaceNeighbour;
|
||||||
|
allProcCells[Pstream::myProcNo()] = subProcCells;
|
||||||
|
allProcProcessorPatchFaces[Pstream::myProcNo()] =
|
||||||
|
subProcProcessorPatchFaces;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// send data to other processor domains
|
||||||
|
UOPstream toDomain(domain, pBufs);
|
||||||
|
|
||||||
|
toDomain
|
||||||
|
<< subPoints
|
||||||
|
<< nInternal
|
||||||
|
<< subFaces
|
||||||
|
<< subFaceOwner
|
||||||
|
<< subFaceNeighbour
|
||||||
|
<< subProcCells
|
||||||
|
<< subProcProcessorPatchFaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start receiving
|
||||||
|
pBufs.finishedSends();
|
||||||
|
|
||||||
|
// Consume
|
||||||
|
for (label domain = 0; domain < Pstream::nProcs(); domain++)
|
||||||
|
{
|
||||||
|
const labelList& recvElems = map.constructMap()[domain];
|
||||||
|
|
||||||
|
if (domain != Pstream::myProcNo() && recvElems.size())
|
||||||
|
{
|
||||||
|
UIPstream str(domain, pBufs);
|
||||||
|
|
||||||
|
str >> allPoints[domain]
|
||||||
|
>> allNInternalFaces[domain]
|
||||||
|
>> allFaces[domain]
|
||||||
|
>> allFaceOwners[domain]
|
||||||
|
>> allFaceNeighbours[domain]
|
||||||
|
>> allProcCells[domain]
|
||||||
|
>> allProcProcessorPatchFaces[domain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert lists into format that can be used to generate a valid polyMesh
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
//
|
||||||
|
// Points and cells are collected into single flat lists:
|
||||||
|
// - i.e. proc0, proc1 ... procN
|
||||||
|
//
|
||||||
|
// Faces need to be sorted after collection to that internal faces are
|
||||||
|
// contiguous, followed by all boundary faces
|
||||||
|
//
|
||||||
|
// Processor patch faces between included cells on neighbouring processors
|
||||||
|
// are converted into internal faces
|
||||||
|
//
|
||||||
|
// Face list structure:
|
||||||
|
// - Per processor:
|
||||||
|
// - internal faces
|
||||||
|
// - processor faces that have been converted into internal faces
|
||||||
|
// - Followed by all boundary faces
|
||||||
|
// - from 'normal' boundary faces
|
||||||
|
// - from singularly-sided processor patch faces
|
||||||
|
|
||||||
|
// Number of internal+coupled faces
|
||||||
|
labelList allNIntCoupledFaces(allNInternalFaces);
|
||||||
|
|
||||||
|
// Starting offset for points
|
||||||
|
label nPoints = 0;
|
||||||
|
labelList pointOffset(Pstream::nProcs(), 0);
|
||||||
|
forAll(allPoints, proci)
|
||||||
|
{
|
||||||
|
pointOffset[proci] = nPoints;
|
||||||
|
nPoints += allPoints[proci].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count any coupled faces
|
||||||
|
typedef FixedList<label, 3> label3;
|
||||||
|
typedef HashTable<label, label3, label3::Hash<>> procCoupleInfo;
|
||||||
|
procCoupleInfo procFaceToGlobalCell;
|
||||||
|
forAll(allProcProcessorPatchFaces, proci)
|
||||||
|
{
|
||||||
|
const List<remote>& procProcessorPatchFaces =
|
||||||
|
allProcProcessorPatchFaces[proci];
|
||||||
|
|
||||||
|
forAll(procProcessorPatchFaces, i)
|
||||||
|
{
|
||||||
|
if (procProcessorPatchFaces[i] != remote())
|
||||||
|
{
|
||||||
|
const label3 key
|
||||||
|
({
|
||||||
|
min(proci, procProcessorPatchFaces[i].proci),
|
||||||
|
max(proci, procProcessorPatchFaces[i].proci),
|
||||||
|
procProcessorPatchFaces[i].elementi
|
||||||
|
});
|
||||||
|
|
||||||
|
procCoupleInfo::const_iterator fnd =
|
||||||
|
procFaceToGlobalCell.find(key);
|
||||||
|
|
||||||
|
if (fnd == procFaceToGlobalCell.end())
|
||||||
|
{
|
||||||
|
procFaceToGlobalCell.insert(key, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
Pout<< "Additional internal face between procs:"
|
||||||
|
<< key[0] << " and " << key[1]
|
||||||
|
<< " across local face " << key[2] << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
allNIntCoupledFaces[proci]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starting offset for internal faces
|
||||||
|
label nIntFaces = 0;
|
||||||
|
label nFacesTotal = 0;
|
||||||
|
labelList internalFaceOffset(Pstream::nProcs(), 0);
|
||||||
|
forAll(allNIntCoupledFaces, proci)
|
||||||
|
{
|
||||||
|
label nCoupledFaces =
|
||||||
|
allNIntCoupledFaces[proci] - allNInternalFaces[proci];
|
||||||
|
|
||||||
|
internalFaceOffset[proci] = nIntFaces;
|
||||||
|
nIntFaces += allNIntCoupledFaces[proci];
|
||||||
|
nFacesTotal += allFaceOwners[proci].size() - nCoupledFaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starting offset for cells
|
||||||
|
label nCells = 0;
|
||||||
|
labelList cellOffset(Pstream::nProcs(), 0);
|
||||||
|
forAll(allProcCells, proci)
|
||||||
|
{
|
||||||
|
cellOffset[proci] = nCells;
|
||||||
|
nCells += allProcCells[proci].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate
|
||||||
|
List<remote> localProcCells(nCells);
|
||||||
|
pointField localPoints(nPoints);
|
||||||
|
faceList localFaces(nFacesTotal);
|
||||||
|
labelList localFaceOwners(nFacesTotal);
|
||||||
|
labelList localFaceNeighbours(nFacesTotal);
|
||||||
|
|
||||||
|
// Insert proc-cells
|
||||||
|
forAll(allProcCells, proci)
|
||||||
|
{
|
||||||
|
const List<remote>& procCells = allProcCells[proci];
|
||||||
|
SubList<remote>(localProcCells, procCells.size(), cellOffset[proci]) =
|
||||||
|
procCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert points
|
||||||
|
forAll(allPoints, proci)
|
||||||
|
{
|
||||||
|
const pointField& pts = allPoints[proci];
|
||||||
|
SubList<point>(localPoints, pts.size(), pointOffset[proci]) = pts;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert internal faces (from internal faces)
|
||||||
|
forAll(allFaces, proci)
|
||||||
|
{
|
||||||
|
const faceList& fcs = allFaces[proci];
|
||||||
|
const labelList& faceOs = allFaceOwners[proci];
|
||||||
|
const labelList& faceNs = allFaceNeighbours[proci];
|
||||||
|
|
||||||
|
SubList<face> slice
|
||||||
|
(
|
||||||
|
localFaces,
|
||||||
|
allNInternalFaces[proci],
|
||||||
|
internalFaceOffset[proci]
|
||||||
|
);
|
||||||
|
slice = SubList<face>(fcs, allNInternalFaces[proci]);
|
||||||
|
forAll(slice, i)
|
||||||
|
{
|
||||||
|
add(slice[i], pointOffset[proci]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubField<label> ownSlice
|
||||||
|
(
|
||||||
|
localFaceOwners,
|
||||||
|
allNInternalFaces[proci],
|
||||||
|
internalFaceOffset[proci]
|
||||||
|
);
|
||||||
|
ownSlice = SubField<label>(faceOs, allNInternalFaces[proci]);
|
||||||
|
add(ownSlice, cellOffset[proci]);
|
||||||
|
|
||||||
|
SubField<label> nbrSlice
|
||||||
|
(
|
||||||
|
localFaceNeighbours,
|
||||||
|
allNInternalFaces[proci],
|
||||||
|
internalFaceOffset[proci]
|
||||||
|
);
|
||||||
|
nbrSlice = SubField<label>(faceNs, allNInternalFaces[proci]);
|
||||||
|
add(nbrSlice, cellOffset[proci]);
|
||||||
|
|
||||||
|
internalFaceOffset[proci] += allNInternalFaces[proci];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert internal faces (from coupled face-pairs)
|
||||||
|
forAll(allProcProcessorPatchFaces, proci)
|
||||||
|
{
|
||||||
|
const List<remote>& procProcessorPatchFaces =
|
||||||
|
allProcProcessorPatchFaces[proci];
|
||||||
|
const labelList& faceOs = allFaceOwners[proci];
|
||||||
|
const faceList& fcs = allFaces[proci];
|
||||||
|
|
||||||
|
forAll(procProcessorPatchFaces, i)
|
||||||
|
{
|
||||||
|
if (procProcessorPatchFaces[i] != remote())
|
||||||
|
{
|
||||||
|
const label3 key
|
||||||
|
({
|
||||||
|
min(proci, procProcessorPatchFaces[i].proci),
|
||||||
|
max(proci, procProcessorPatchFaces[i].proci),
|
||||||
|
procProcessorPatchFaces[i].elementi
|
||||||
|
});
|
||||||
|
|
||||||
|
procCoupleInfo::iterator fnd = procFaceToGlobalCell.find(key);
|
||||||
|
|
||||||
|
if (fnd != procFaceToGlobalCell.end())
|
||||||
|
{
|
||||||
|
if (fnd() == -1)
|
||||||
|
{
|
||||||
|
// on first visit store the new cell on this side
|
||||||
|
fnd() = cellOffset[proci] + faceOs[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get owner and neighbour in new cell numbering
|
||||||
|
const label newOwn = cellOffset[proci] + faceOs[i];
|
||||||
|
const label newNbr = fnd();
|
||||||
|
const label localFacei = internalFaceOffset[proci]++;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
Pout<< " proc " << proci
|
||||||
|
<< "\tinserting face:" << localFacei
|
||||||
|
<< " connection between owner " << newOwn
|
||||||
|
<< " and neighbour " << newNbr
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newOwn < newNbr)
|
||||||
|
{
|
||||||
|
// we have correct orientation
|
||||||
|
localFaces[localFacei] = fcs[i];
|
||||||
|
localFaceOwners[localFacei] = newOwn;
|
||||||
|
localFaceNeighbours[localFacei] = newNbr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// reverse orientation
|
||||||
|
localFaces[localFacei] = fcs[i].reverseFace();
|
||||||
|
localFaceOwners[localFacei] = newNbr;
|
||||||
|
localFaceNeighbours[localFacei] = newOwn;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(localFaces[localFacei], pointOffset[proci]);
|
||||||
|
|
||||||
|
// mark with unique value
|
||||||
|
fnd() = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
forAll(allProcProcessorPatchFaces, proci)
|
||||||
|
{
|
||||||
|
const List<remote>& procProcessorPatchFaces =
|
||||||
|
allProcProcessorPatchFaces[proci];
|
||||||
|
const labelList& faceOs = allFaceOwners[proci];
|
||||||
|
const labelList& faceNs = allFaceNeighbours[proci];
|
||||||
|
const faceList& fcs = allFaces[proci];
|
||||||
|
|
||||||
|
forAll(procProcessorPatchFaces, i)
|
||||||
|
{
|
||||||
|
// coupled boundary face
|
||||||
|
if (procProcessorPatchFaces[i] != remote())
|
||||||
|
{
|
||||||
|
const label3 key
|
||||||
|
({
|
||||||
|
min(proci, procProcessorPatchFaces[i].proci),
|
||||||
|
max(proci, procProcessorPatchFaces[i].proci),
|
||||||
|
procProcessorPatchFaces[i].elementi
|
||||||
|
});
|
||||||
|
|
||||||
|
if (procFaceToGlobalCell[key] == -1)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Unvisited " << key
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
else if (procFaceToGlobalCell[key] != -2)
|
||||||
|
{
|
||||||
|
const label newOwn = cellOffset[proci] + faceOs[i];
|
||||||
|
const label localFacei = nIntFaces++;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
Pout<< " proc " << proci
|
||||||
|
<< "\tinserting boundary face:" << localFacei
|
||||||
|
<< " from coupled face " << key
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
localFaces[localFacei] = fcs[i];
|
||||||
|
add(localFaces[localFacei], pointOffset[proci]);
|
||||||
|
|
||||||
|
localFaceOwners[localFacei] = newOwn;
|
||||||
|
localFaceNeighbours[localFacei] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal boundary face
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const label own = faceOs[i];
|
||||||
|
const label nbr = faceNs[i];
|
||||||
|
|
||||||
|
if ((own != -1) && (nbr == -1))
|
||||||
|
{
|
||||||
|
const label newOwn = cellOffset[proci] + faceOs[i];
|
||||||
|
const label localFacei = nIntFaces++;
|
||||||
|
|
||||||
|
localFaces[localFacei] = fcs[i];
|
||||||
|
add(localFaces[localFacei], pointOffset[proci]);
|
||||||
|
|
||||||
|
localFaceOwners[localFacei] = newOwn;
|
||||||
|
localFaceNeighbours[localFacei] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the local mesh
|
||||||
|
localMeshPtr.reset
|
||||||
|
(
|
||||||
|
new polyMesh
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"local" + mesh.name().capitalise(),
|
||||||
|
mesh.time().timeName(),
|
||||||
|
mesh.time(),
|
||||||
|
IOobject::NO_READ
|
||||||
|
),
|
||||||
|
move(localPoints),
|
||||||
|
move(localFaces),
|
||||||
|
move(localFaceOwners),
|
||||||
|
move(localFaceNeighbours),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add a dummy patch to the target mesh
|
||||||
|
List<polyPatch*> patches(1);
|
||||||
|
patches[0] = new polyPatch
|
||||||
|
(
|
||||||
|
"defaultFaces",
|
||||||
|
localMeshPtr().nFaces() - localMeshPtr().nInternalFaces(),
|
||||||
|
localMeshPtr().nInternalFaces(),
|
||||||
|
0,
|
||||||
|
localMeshPtr().boundaryMesh(),
|
||||||
|
word::null
|
||||||
|
);
|
||||||
|
localMeshPtr().addPatches(patches);
|
||||||
|
|
||||||
|
// Force calculation of tet-base points used for point-in-cell
|
||||||
|
(void) localMeshPtr().tetBasePtIs();
|
||||||
|
|
||||||
|
return localProcCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::meshToMesh::trimLocalTgt()
|
||||||
|
{
|
||||||
|
// Determine which local target cells are actually used
|
||||||
|
boolList oldLocalTgtCellIsUsed(localTgtProcCellsPtr_().size(), false);
|
||||||
|
forAll(srcLocalTgtCells_, srcCelli)
|
||||||
|
{
|
||||||
|
forAll(srcLocalTgtCells_[srcCelli], i)
|
||||||
|
{
|
||||||
|
oldLocalTgtCellIsUsed[srcLocalTgtCells_[srcCelli][i]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim the target map
|
||||||
|
labelList oldToNewLocalTgtCell, newToOldLocalTgtCell;
|
||||||
|
patchToPatchTools::trimDistributionMap
|
||||||
|
(
|
||||||
|
oldLocalTgtCellIsUsed,
|
||||||
|
tgtMapPtr_(),
|
||||||
|
oldToNewLocalTgtCell,
|
||||||
|
newToOldLocalTgtCell
|
||||||
|
);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
Pout<< "Trim from " << oldToNewLocalTgtCell.size() << " to "
|
||||||
|
<< newToOldLocalTgtCell.size() << " cells" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renumber the source addressing
|
||||||
|
forAll(srcLocalTgtCells_, srcCelli)
|
||||||
|
{
|
||||||
|
forAll(srcLocalTgtCells_[srcCelli], i)
|
||||||
|
{
|
||||||
|
srcLocalTgtCells_[srcCelli][i] =
|
||||||
|
oldToNewLocalTgtCell[srcLocalTgtCells_[srcCelli][i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim the target addressing
|
||||||
|
tgtLocalSrcCells_ =
|
||||||
|
labelListList(tgtLocalSrcCells_, newToOldLocalTgtCell);
|
||||||
|
localTgtProcCellsPtr_() =
|
||||||
|
List<remote>(localTgtProcCellsPtr_(), newToOldLocalTgtCell);
|
||||||
|
|
||||||
|
// Trim the target weights
|
||||||
|
tgtWeights_ = scalarListList(tgtWeights_, newToOldLocalTgtCell);
|
||||||
|
|
||||||
|
// Trim the stored local target mesh
|
||||||
|
const polyMesh& oldLocalTgtMesh = localTgtMeshPtr_();
|
||||||
|
const labelList& oldLocalTgtFaceOwner =
|
||||||
|
oldLocalTgtMesh.faceOwner();
|
||||||
|
labelList oldLocalTgtFaceNeighbour(oldLocalTgtFaceOwner.size(), -1);
|
||||||
|
SubList<label>(oldLocalTgtFaceNeighbour, oldLocalTgtMesh.nInternalFaces()) =
|
||||||
|
oldLocalTgtMesh.faceNeighbour();
|
||||||
|
|
||||||
|
// ...
|
||||||
|
labelList newToOldLocalTgtFace(identity(oldLocalTgtMesh.nFaces()));
|
||||||
|
labelList oldToNewLocalTgtFace;
|
||||||
|
{
|
||||||
|
label i0 = 0;
|
||||||
|
label i1 = newToOldLocalTgtFace.size();
|
||||||
|
label iEnd = newToOldLocalTgtFace.size();
|
||||||
|
|
||||||
|
while (i0 < i1)
|
||||||
|
{
|
||||||
|
label& oldLocalTgtFacei0 = newToOldLocalTgtFace[i0];
|
||||||
|
label& oldLocalTgtFacei1 = newToOldLocalTgtFace[i1 - 1];
|
||||||
|
label& oldLocalTgtFaceiEnd = newToOldLocalTgtFace[iEnd - 1];
|
||||||
|
|
||||||
|
const label newLocalTgtOwni0 =
|
||||||
|
oldLocalTgtFaceOwner[oldLocalTgtFacei0] != -1
|
||||||
|
? oldToNewLocalTgtCell
|
||||||
|
[oldLocalTgtFaceOwner[oldLocalTgtFacei0]]
|
||||||
|
: -1;
|
||||||
|
const label newLocalTgtOwni1 =
|
||||||
|
oldLocalTgtFaceOwner[oldLocalTgtFacei1] != -1
|
||||||
|
? oldToNewLocalTgtCell
|
||||||
|
[oldLocalTgtFaceOwner[oldLocalTgtFacei1]]
|
||||||
|
: -1;
|
||||||
|
|
||||||
|
const label newLocalTgtNbri0 =
|
||||||
|
oldLocalTgtFaceNeighbour[oldLocalTgtFacei0] != -1
|
||||||
|
? oldToNewLocalTgtCell
|
||||||
|
[oldLocalTgtFaceNeighbour[oldLocalTgtFacei0]]
|
||||||
|
: -1;
|
||||||
|
const label newLocalTgtNbri1 =
|
||||||
|
oldLocalTgtFaceNeighbour[oldLocalTgtFacei1] != -1
|
||||||
|
? oldToNewLocalTgtCell
|
||||||
|
[oldLocalTgtFaceNeighbour[oldLocalTgtFacei1]]
|
||||||
|
: -1;
|
||||||
|
|
||||||
|
const bool used0 =
|
||||||
|
newLocalTgtOwni0 != -1 || newLocalTgtNbri0 != -1;
|
||||||
|
const bool used1 =
|
||||||
|
newLocalTgtOwni1 != -1 || newLocalTgtNbri1 != -1;
|
||||||
|
|
||||||
|
const bool internal0 =
|
||||||
|
newLocalTgtOwni0 != -1 && newLocalTgtNbri0 != -1;
|
||||||
|
const bool internal1 =
|
||||||
|
newLocalTgtOwni1 != -1 && newLocalTgtNbri1 != -1;
|
||||||
|
|
||||||
|
// If face 0 is not used, move it to the end to remove it
|
||||||
|
if (!used0)
|
||||||
|
{
|
||||||
|
Swap(oldLocalTgtFacei0, oldLocalTgtFaceiEnd);
|
||||||
|
if (i1 == iEnd) i1 --;
|
||||||
|
iEnd --;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If face 1 is not used, move it to the end to remove it
|
||||||
|
else if (!used1)
|
||||||
|
{
|
||||||
|
Swap(oldLocalTgtFacei1, oldLocalTgtFaceiEnd);
|
||||||
|
if (i1 == iEnd) i1 --;
|
||||||
|
iEnd --;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both are internal faces. Face 0 is fine, but face 1 might be out
|
||||||
|
// of order. So move to the next face 0.
|
||||||
|
else if (internal0 && internal1)
|
||||||
|
{
|
||||||
|
i0 ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both are boundary faces. Face 0 might be out of order, but face
|
||||||
|
// 1 is fine. So move to the next face 1.
|
||||||
|
else if (!internal0 && !internal1)
|
||||||
|
{
|
||||||
|
i1 --;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Face 0 is an internal face and face 1 is a boundary face. Both
|
||||||
|
// are fine. So move to the next two faces.
|
||||||
|
else if (internal0 && !internal1)
|
||||||
|
{
|
||||||
|
i0 ++;
|
||||||
|
i1 --;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Face 0 is a boundary face and face 1 is an internal face. Both
|
||||||
|
// are out of order. So swap and then move to the next two faces.
|
||||||
|
else if (!internal0 && internal1)
|
||||||
|
{
|
||||||
|
Swap(oldLocalTgtFacei0, oldLocalTgtFacei1);
|
||||||
|
i0 ++;
|
||||||
|
i1 --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newToOldLocalTgtFace.resize(iEnd);
|
||||||
|
|
||||||
|
oldToNewLocalTgtFace =
|
||||||
|
invert(oldLocalTgtMesh.nFaces(), newToOldLocalTgtFace);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
Pout<< "Trim from " << oldToNewLocalTgtFace.size() << " to "
|
||||||
|
<< newToOldLocalTgtFace.size() << " faces" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create trimmed mesh primitives
|
||||||
|
pointField newLocalTgtPoints(oldLocalTgtMesh.points());
|
||||||
|
faceList newLocalTgtFaces(oldLocalTgtMesh.faces(), newToOldLocalTgtFace);
|
||||||
|
labelList newLocalTgtFaceOwner
|
||||||
|
(
|
||||||
|
oldLocalTgtFaceOwner,
|
||||||
|
static_cast<const labelUList&>(newToOldLocalTgtFace)
|
||||||
|
);
|
||||||
|
inplaceRenumber(oldToNewLocalTgtCell, newLocalTgtFaceOwner);
|
||||||
|
labelList newLocalTgtFaceNeighbour
|
||||||
|
(
|
||||||
|
oldLocalTgtFaceNeighbour,
|
||||||
|
static_cast<const labelUList&>(newToOldLocalTgtFace)
|
||||||
|
);
|
||||||
|
inplaceRenumber(oldToNewLocalTgtCell, newLocalTgtFaceNeighbour);
|
||||||
|
|
||||||
|
// Check the trimmed mesh structure and flip any faces that have a
|
||||||
|
// neighbour but not an owner
|
||||||
|
{
|
||||||
|
label newLocalTgtNInternalFaces = 0;
|
||||||
|
bool internal0 = true;
|
||||||
|
|
||||||
|
forAll(newLocalTgtFaces, newLocalTgtFacei)
|
||||||
|
{
|
||||||
|
face& newLocalTgtF = newLocalTgtFaces[newLocalTgtFacei];
|
||||||
|
label& newLocalTgtOwni = newLocalTgtFaceOwner[newLocalTgtFacei];
|
||||||
|
label& newLocalTgtNbri = newLocalTgtFaceNeighbour[newLocalTgtFacei];
|
||||||
|
|
||||||
|
// Check that internal and boundary faces are in order
|
||||||
|
const bool internal =
|
||||||
|
newLocalTgtOwni != -1 && newLocalTgtNbri != -1;
|
||||||
|
if (internal0 && !internal)
|
||||||
|
{
|
||||||
|
newLocalTgtNInternalFaces = newLocalTgtFacei;
|
||||||
|
internal0 = false;
|
||||||
|
}
|
||||||
|
if (!internal0 && internal)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Trimmed mesh has boundary faces before internal faces"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flip any face that has a neighbour but not an owner
|
||||||
|
const bool flip =
|
||||||
|
newLocalTgtOwni == -1 && newLocalTgtNbri != -1;
|
||||||
|
if (flip)
|
||||||
|
{
|
||||||
|
newLocalTgtF = newLocalTgtF.reverseFace();
|
||||||
|
Swap(newLocalTgtOwni, newLocalTgtNbri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newLocalTgtFaceNeighbour.resize(newLocalTgtNInternalFaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the local mesh
|
||||||
|
localTgtMeshPtr_.reset
|
||||||
|
(
|
||||||
|
new polyMesh
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"trimmed" + oldLocalTgtMesh.name().capitalise(),
|
||||||
|
oldLocalTgtMesh.time().timeName(),
|
||||||
|
oldLocalTgtMesh.time(),
|
||||||
|
IOobject::NO_READ
|
||||||
|
),
|
||||||
|
move(newLocalTgtPoints),
|
||||||
|
move(newLocalTgtFaces),
|
||||||
|
move(newLocalTgtFaceOwner),
|
||||||
|
move(newLocalTgtFaceNeighbour),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add a dummy patch to the target mesh
|
||||||
|
List<polyPatch*> patches(1);
|
||||||
|
patches[0] = new polyPatch
|
||||||
|
(
|
||||||
|
"defaultFaces",
|
||||||
|
localTgtMeshPtr_().nFaces() - localTgtMeshPtr_().nInternalFaces(),
|
||||||
|
localTgtMeshPtr_().nInternalFaces(),
|
||||||
|
0,
|
||||||
|
localTgtMeshPtr_().boundaryMesh(),
|
||||||
|
word::null
|
||||||
|
);
|
||||||
|
localTgtMeshPtr_().addPatches(patches);
|
||||||
|
|
||||||
|
// Force calculation of tet-base points used for point-in-cell
|
||||||
|
(void) localTgtMeshPtr_().tetBasePtIs();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
200
src/meshTools/meshToMesh/meshToMeshTemplates.C
Normal file
200
src/meshTools/meshToMesh/meshToMeshTemplates.C
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2012-2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "meshToMesh.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
void Foam::meshToMesh::add
|
||||||
|
(
|
||||||
|
UList<Type>& fld,
|
||||||
|
const label offset
|
||||||
|
)
|
||||||
|
{
|
||||||
|
forAll(fld, i)
|
||||||
|
{
|
||||||
|
fld[i] += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
void Foam::meshToMesh::mapSrcToTgt
|
||||||
|
(
|
||||||
|
const UList<Type>& srcField,
|
||||||
|
List<Type>& result
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
if (result.size() != tgtLocalSrcCells_.size())
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Supplied field size is not equal to target mesh size" << nl
|
||||||
|
<< " source mesh = " << srcLocalTgtCells_.size() << nl
|
||||||
|
<< " target mesh = " << tgtLocalSrcCells_.size() << nl
|
||||||
|
<< " supplied field = " << result.size()
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSingleProcess())
|
||||||
|
{
|
||||||
|
const distributionMap& map = srcMapPtr_();
|
||||||
|
|
||||||
|
List<Type> work(srcField);
|
||||||
|
map.distribute(work);
|
||||||
|
|
||||||
|
forAll(result, tgtCelli)
|
||||||
|
{
|
||||||
|
if (tgtLocalSrcCells_[tgtCelli].size())
|
||||||
|
{
|
||||||
|
result[tgtCelli] *= (1.0 - sum(tgtWeights_[tgtCelli]));
|
||||||
|
forAll(tgtLocalSrcCells_[tgtCelli], i)
|
||||||
|
{
|
||||||
|
result[tgtCelli] +=
|
||||||
|
tgtWeights_[tgtCelli][i]
|
||||||
|
*work[tgtLocalSrcCells_[tgtCelli][i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
forAll(result, tgtCelli)
|
||||||
|
{
|
||||||
|
if (tgtLocalSrcCells_[tgtCelli].size())
|
||||||
|
{
|
||||||
|
result[tgtCelli] *= (1.0 - sum(tgtWeights_[tgtCelli]));
|
||||||
|
forAll(tgtLocalSrcCells_[tgtCelli], i)
|
||||||
|
{
|
||||||
|
result[tgtCelli] +=
|
||||||
|
tgtWeights_[tgtCelli][i]
|
||||||
|
*srcField[tgtLocalSrcCells_[tgtCelli][i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::tmp<Foam::Field<Type>> Foam::meshToMesh::mapSrcToTgt
|
||||||
|
(
|
||||||
|
const Field<Type>& srcField
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
tmp<Field<Type>> tresult
|
||||||
|
(
|
||||||
|
new Field<Type>
|
||||||
|
(
|
||||||
|
tgtLocalSrcCells_.size(),
|
||||||
|
Zero
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
mapSrcToTgt(srcField, tresult.ref());
|
||||||
|
|
||||||
|
return tresult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
void Foam::meshToMesh::mapTgtToSrc
|
||||||
|
(
|
||||||
|
const UList<Type>& tgtField,
|
||||||
|
List<Type>& result
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
if (result.size() != srcLocalTgtCells_.size())
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Supplied field size is not equal to source mesh size" << nl
|
||||||
|
<< " source mesh = " << srcLocalTgtCells_.size() << nl
|
||||||
|
<< " target mesh = " << tgtLocalSrcCells_.size() << nl
|
||||||
|
<< " supplied field = " << result.size()
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSingleProcess())
|
||||||
|
{
|
||||||
|
const distributionMap& map = tgtMapPtr_();
|
||||||
|
|
||||||
|
List<Type> work(tgtField);
|
||||||
|
map.distribute(work);
|
||||||
|
|
||||||
|
forAll(result, srcCelli)
|
||||||
|
{
|
||||||
|
if (srcLocalTgtCells_[srcCelli].size())
|
||||||
|
{
|
||||||
|
result[srcCelli] *= (1.0 - sum(srcWeights_[srcCelli]));
|
||||||
|
forAll(srcLocalTgtCells_[srcCelli], i)
|
||||||
|
{
|
||||||
|
result[srcCelli] +=
|
||||||
|
srcWeights_[srcCelli][i]
|
||||||
|
*work[srcLocalTgtCells_[srcCelli][i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
forAll(result, srcCelli)
|
||||||
|
{
|
||||||
|
if (srcLocalTgtCells_[srcCelli].size())
|
||||||
|
{
|
||||||
|
result[srcCelli] *= (1.0 - sum(srcWeights_[srcCelli]));
|
||||||
|
forAll(srcLocalTgtCells_[srcCelli], i)
|
||||||
|
{
|
||||||
|
result[srcCelli] +=
|
||||||
|
srcWeights_[srcCelli][i]
|
||||||
|
*tgtField[srcLocalTgtCells_[srcCelli][i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::tmp<Foam::Field<Type>> Foam::meshToMesh::mapTgtToSrc
|
||||||
|
(
|
||||||
|
const Field<Type>& tgtField
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
tmp<Field<Type>> tresult
|
||||||
|
(
|
||||||
|
new Field<Type>
|
||||||
|
(
|
||||||
|
srcLocalTgtCells_.size(),
|
||||||
|
Zero
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
mapTgtToSrc(tgtField, tresult.ref());
|
||||||
|
|
||||||
|
return tresult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -542,13 +542,13 @@ void Foam::patchToPatches::intersection::initialise
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Foam::labelList Foam::patchToPatches::intersection::subsetLocalTgt
|
Foam::labelList Foam::patchToPatches::intersection::trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const labelList newToOldLocalTgtFace =
|
const labelList newToOldLocalTgtFace =
|
||||||
patchToPatch::subsetLocalTgt(localTgtPatch);
|
patchToPatch::trimLocalTgt(localTgtPatch);
|
||||||
|
|
||||||
tgtCouples_ = List<DynamicList<couple>>(tgtCouples_, newToOldLocalTgtFace);
|
tgtCouples_ = List<DynamicList<couple>>(tgtCouples_, newToOldLocalTgtFace);
|
||||||
|
|
||||||
@ -563,7 +563,12 @@ void Foam::patchToPatches::intersection::rDistributeTgt
|
|||||||
{
|
{
|
||||||
patchToPatch::rDistributeTgt(tgtPatch);
|
patchToPatch::rDistributeTgt(tgtPatch);
|
||||||
|
|
||||||
rDistributeListList(tgtPatch.size(), tgtMapPtr_(), tgtCouples_);
|
patchToPatchTools::rDistributeListList
|
||||||
|
(
|
||||||
|
tgtPatch.size(),
|
||||||
|
tgtMapPtr_(),
|
||||||
|
tgtCouples_
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -328,9 +328,9 @@ private:
|
|||||||
const primitiveOldTimePatch& tgtPatch
|
const primitiveOldTimePatch& tgtPatch
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Subset the local target patch so that only parts that actually
|
//- Trim the local target patch so that only parts that actually
|
||||||
// intersect the source remain
|
// intersect the source remain
|
||||||
virtual labelList subsetLocalTgt
|
virtual labelList trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
);
|
);
|
||||||
|
|||||||
@ -191,13 +191,13 @@ void Foam::patchToPatches::inverseDistance::initialise
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Foam::labelList Foam::patchToPatches::inverseDistance::subsetLocalTgt
|
Foam::labelList Foam::patchToPatches::inverseDistance::trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const labelList newToOldLocalTgtFace =
|
const labelList newToOldLocalTgtFace =
|
||||||
patchToPatch::subsetLocalTgt(localTgtPatch);
|
patchToPatch::trimLocalTgt(localTgtPatch);
|
||||||
|
|
||||||
tgtWeights_ = List<DynamicList<scalar>>(tgtWeights_, newToOldLocalTgtFace);
|
tgtWeights_ = List<DynamicList<scalar>>(tgtWeights_, newToOldLocalTgtFace);
|
||||||
|
|
||||||
@ -212,7 +212,12 @@ void Foam::patchToPatches::inverseDistance::rDistributeTgt
|
|||||||
{
|
{
|
||||||
patchToPatch::rDistributeTgt(tgtPatch);
|
patchToPatch::rDistributeTgt(tgtPatch);
|
||||||
|
|
||||||
rDistributeListList(tgtPatch.size(), tgtMapPtr_(), tgtWeights_);
|
patchToPatchTools::rDistributeListList
|
||||||
|
(
|
||||||
|
tgtPatch.size(),
|
||||||
|
tgtMapPtr_(),
|
||||||
|
tgtWeights_
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -114,9 +114,9 @@ class inverseDistance
|
|||||||
const primitiveOldTimePatch& tgtPatch
|
const primitiveOldTimePatch& tgtPatch
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Subset the local target patch so that only parts that actually
|
//- Trim the local target patch so that only parts that actually
|
||||||
// intersect the source remain
|
// intersect the source remain
|
||||||
virtual labelList subsetLocalTgt
|
virtual labelList trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
);
|
);
|
||||||
|
|||||||
@ -200,13 +200,13 @@ void Foam::patchToPatches::nearest::initialise
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Foam::labelList Foam::patchToPatches::nearest::subsetLocalTgt
|
Foam::labelList Foam::patchToPatches::nearest::trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const labelList newToOldLocalTgtFace =
|
const labelList newToOldLocalTgtFace =
|
||||||
patchToPatch::subsetLocalTgt(localTgtPatch);
|
patchToPatch::trimLocalTgt(localTgtPatch);
|
||||||
|
|
||||||
tgtDistances_ = List<scalar>(tgtDistances_, newToOldLocalTgtFace);
|
tgtDistances_ = List<scalar>(tgtDistances_, newToOldLocalTgtFace);
|
||||||
|
|
||||||
@ -233,7 +233,12 @@ void Foam::patchToPatches::nearest::rDistributeTgt
|
|||||||
patchToPatch::rDistributeTgt(tgtPatch);
|
patchToPatch::rDistributeTgt(tgtPatch);
|
||||||
|
|
||||||
// Reverse distribute the distances
|
// Reverse distribute the distances
|
||||||
rDistributeListList(tgtPatch.size(), tgtMapPtr_(), tgtDistances);
|
patchToPatchTools::rDistributeListList
|
||||||
|
(
|
||||||
|
tgtPatch.size(),
|
||||||
|
tgtMapPtr_(),
|
||||||
|
tgtDistances
|
||||||
|
);
|
||||||
|
|
||||||
// If there is more than one address, remove all but the closest
|
// If there is more than one address, remove all but the closest
|
||||||
tgtDistances_.resize(tgtLocalSrcFaces_.size());
|
tgtDistances_.resize(tgtLocalSrcFaces_.size());
|
||||||
|
|||||||
@ -105,9 +105,9 @@ protected:
|
|||||||
const primitiveOldTimePatch& tgtPatch
|
const primitiveOldTimePatch& tgtPatch
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Subset the local target patch so that only parts that actually
|
//- Trim the local target patch so that only parts that actually
|
||||||
// intersect the source remain
|
// intersect the source remain
|
||||||
virtual labelList subsetLocalTgt
|
virtual labelList trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
);
|
);
|
||||||
|
|||||||
@ -24,6 +24,7 @@ License
|
|||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "patchToPatch.H"
|
#include "patchToPatch.H"
|
||||||
|
#include "patchToPatchTools.H"
|
||||||
#include "cpuTime.H"
|
#include "cpuTime.H"
|
||||||
#include "distributionMap.H"
|
#include "distributionMap.H"
|
||||||
#include "globalIndex.H"
|
#include "globalIndex.H"
|
||||||
@ -78,75 +79,6 @@ namespace Foam
|
|||||||
{
|
{
|
||||||
return treeBoundBox(min(a.min(), b.min()), max(a.max(), b.max()));
|
return treeBoundBox(min(a.min(), b.min()), max(a.max(), b.max()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void subsetDistributionMap
|
|
||||||
(
|
|
||||||
const boolList& oldIsUsed,
|
|
||||||
distributionMap& map,
|
|
||||||
labelList& oldToNew,
|
|
||||||
labelList& newToOld
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// Create re-indexing
|
|
||||||
oldToNew.resize(map.constructSize());
|
|
||||||
newToOld.resize(count(oldIsUsed, true));
|
|
||||||
oldToNew = -1;
|
|
||||||
newToOld = -1;
|
|
||||||
{
|
|
||||||
label newi = 0;
|
|
||||||
forAll(oldIsUsed, oldi)
|
|
||||||
{
|
|
||||||
if (oldIsUsed[oldi])
|
|
||||||
{
|
|
||||||
oldToNew[oldi] = newi;
|
|
||||||
newToOld[newi] = oldi;
|
|
||||||
++ newi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Per-processor used list for construction
|
|
||||||
List<boolList> allOldIsUsed(Pstream::nProcs());
|
|
||||||
forAll(map.constructMap(), proci)
|
|
||||||
{
|
|
||||||
allOldIsUsed[proci] =
|
|
||||||
UIndirectList<bool>(oldIsUsed, map.constructMap()[proci]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Communicate to form a per-processor used list for subsetting
|
|
||||||
List<boolList> allSubOldIsUsed(Pstream::nProcs());
|
|
||||||
Pstream::exchange<boolList, bool>(allOldIsUsed, allSubOldIsUsed);
|
|
||||||
|
|
||||||
// Subset the sub map
|
|
||||||
forAll(map.subMap(), proci)
|
|
||||||
{
|
|
||||||
label newi = 0;
|
|
||||||
forAll(map.subMap()[proci], oldi)
|
|
||||||
{
|
|
||||||
if (allSubOldIsUsed[proci][oldi])
|
|
||||||
{
|
|
||||||
map.subMap()[proci][newi ++] =
|
|
||||||
map.subMap()[proci][oldi];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
map.subMap()[proci].resize(newi);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subset and renumber the construct map
|
|
||||||
forAll(map.constructMap(), proci)
|
|
||||||
{
|
|
||||||
label newi = 0;
|
|
||||||
forAll(map.constructMap()[proci], oldi)
|
|
||||||
{
|
|
||||||
if (allOldIsUsed[proci][oldi])
|
|
||||||
{
|
|
||||||
map.constructMap()[proci][newi ++] =
|
|
||||||
oldToNew[map.constructMap()[proci][oldi]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
map.constructMap()[proci].resize(newi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -161,58 +93,6 @@ namespace Foam
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
Foam::List<Foam::List<Foam::remote>>
|
|
||||||
Foam::patchToPatch::localFacesToProcFaces
|
|
||||||
(
|
|
||||||
const List<DynamicList<label>>& localFaces,
|
|
||||||
const List<remote>& map
|
|
||||||
)
|
|
||||||
{
|
|
||||||
List<List<remote>> result(localFaces.size());
|
|
||||||
|
|
||||||
forAll(localFaces, thisFacei)
|
|
||||||
{
|
|
||||||
result[thisFacei].resize(localFaces[thisFacei].size());
|
|
||||||
|
|
||||||
forAll(localFaces[thisFacei], i)
|
|
||||||
{
|
|
||||||
result[thisFacei][i] =
|
|
||||||
isNull(map)
|
|
||||||
? remote({Pstream::myProcNo(), localFaces[thisFacei][i]})
|
|
||||||
: map[localFaces[thisFacei][i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::List<Foam::DynamicList<Foam::label>>
|
|
||||||
Foam::patchToPatch::procFacesToLocalFaces
|
|
||||||
(
|
|
||||||
const List<List<remote>>& procFaces,
|
|
||||||
const HashTable<label, remote, Hash<remote>>& map
|
|
||||||
)
|
|
||||||
{
|
|
||||||
List<DynamicList<label>> result(procFaces.size());
|
|
||||||
|
|
||||||
forAll(procFaces, tgtFacei)
|
|
||||||
{
|
|
||||||
result[tgtFacei].resize(procFaces[tgtFacei].size());
|
|
||||||
|
|
||||||
forAll(procFaces[tgtFacei], i)
|
|
||||||
{
|
|
||||||
result[tgtFacei][i] =
|
|
||||||
isNull(map)
|
|
||||||
? procFaces[tgtFacei][i].elementi
|
|
||||||
: map[procFaces[tgtFacei][i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::treeBoundBox Foam::patchToPatch::srcBox
|
Foam::treeBoundBox Foam::patchToPatch::srcBox
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& srcPatch,
|
const primitiveOldTimePatch& srcPatch,
|
||||||
@ -777,7 +657,7 @@ void Foam::patchToPatch::initialise
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Foam::labelList Foam::patchToPatch::subsetLocalTgt
|
Foam::labelList Foam::patchToPatch::trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
)
|
)
|
||||||
@ -792,9 +672,9 @@ Foam::labelList Foam::patchToPatch::subsetLocalTgt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subset the target map
|
// Trim the target map
|
||||||
labelList oldToNewLocalTgtFace, newToOldLocalTgtFace;
|
labelList oldToNewLocalTgtFace, newToOldLocalTgtFace;
|
||||||
subsetDistributionMap
|
patchToPatchTools::trimDistributionMap
|
||||||
(
|
(
|
||||||
oldLocalTgtFaceIsUsed,
|
oldLocalTgtFaceIsUsed,
|
||||||
tgtMapPtr_(),
|
tgtMapPtr_(),
|
||||||
@ -812,7 +692,7 @@ Foam::labelList Foam::patchToPatch::subsetLocalTgt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subset the local target faces
|
// Trim the local target faces
|
||||||
tgtLocalSrcFaces_ =
|
tgtLocalSrcFaces_ =
|
||||||
List<DynamicList<label>>(tgtLocalSrcFaces_, newToOldLocalTgtFace);
|
List<DynamicList<label>>(tgtLocalSrcFaces_, newToOldLocalTgtFace);
|
||||||
localTgtProcFacesPtr_() =
|
localTgtProcFacesPtr_() =
|
||||||
@ -827,32 +707,25 @@ void Foam::patchToPatch::distributeSrc
|
|||||||
const primitiveOldTimePatch& srcPatch
|
const primitiveOldTimePatch& srcPatch
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
distributePatch(srcMapPtr_(), localSrcProcFacesPtr_());
|
localSrcProcFacesPtr_.reset
|
||||||
|
(
|
||||||
|
new List<remote>
|
||||||
|
(
|
||||||
|
patchToPatchTools::distributeAddressing(srcMapPtr_())
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::patchToPatch::rDistributeTgt(const primitiveOldTimePatch& tgtPatch)
|
void Foam::patchToPatch::rDistributeTgt(const primitiveOldTimePatch& tgtPatch)
|
||||||
{
|
{
|
||||||
// Create a map from source procFace to local source face
|
patchToPatchTools::rDistributeTgtAddressing
|
||||||
HashTable<label, remote, Hash<remote>> srcProcFaceToLocal;
|
|
||||||
forAll(localSrcProcFacesPtr_(), localSrcFacei)
|
|
||||||
{
|
|
||||||
srcProcFaceToLocal.insert
|
|
||||||
(
|
(
|
||||||
localSrcProcFacesPtr_()[localSrcFacei],
|
tgtPatch.size(),
|
||||||
localSrcFacei
|
tgtMapPtr_(),
|
||||||
|
localSrcProcFacesPtr_(),
|
||||||
|
tgtLocalSrcFaces_
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// Collect the source procFaces on the target and convert to local
|
|
||||||
// source face addressing
|
|
||||||
List<List<remote>> tgtSrcProcFaces =
|
|
||||||
localFacesToProcFaces(tgtLocalSrcFaces_);
|
|
||||||
|
|
||||||
rDistributeListList(tgtPatch.size(), tgtMapPtr_(), tgtSrcProcFaces);
|
|
||||||
|
|
||||||
tgtLocalSrcFaces_ =
|
|
||||||
procFacesToLocalFaces(tgtSrcProcFaces, srcProcFaceToLocal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -892,8 +765,8 @@ Foam::patchToPatch::patchToPatch(const bool reverse)
|
|||||||
tgtLocalSrcFaces_(),
|
tgtLocalSrcFaces_(),
|
||||||
srcMapPtr_(nullptr),
|
srcMapPtr_(nullptr),
|
||||||
tgtMapPtr_(nullptr),
|
tgtMapPtr_(nullptr),
|
||||||
localSrcProcFacesPtr_(new List<remote>()),
|
localSrcProcFacesPtr_(nullptr),
|
||||||
localTgtProcFacesPtr_(new List<remote>())
|
localTgtProcFacesPtr_(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
@ -997,7 +870,12 @@ void Foam::patchToPatch::update
|
|||||||
<< " target faces" << incrIndent << endl;
|
<< " target faces" << incrIndent << endl;
|
||||||
|
|
||||||
// Determine if patches are present on multiple processors
|
// Determine if patches are present on multiple processors
|
||||||
calcSingleProcess(srcPatch, tTgtPatch);
|
singleProcess_ =
|
||||||
|
patchToPatchTools::singleProcess
|
||||||
|
(
|
||||||
|
srcPatch.size(),
|
||||||
|
tTgtPatch.size()
|
||||||
|
);
|
||||||
|
|
||||||
// Do intersection in serial or parallel as appropriate
|
// Do intersection in serial or parallel as appropriate
|
||||||
if (isSingleProcess())
|
if (isSingleProcess())
|
||||||
@ -1027,7 +905,7 @@ void Foam::patchToPatch::update
|
|||||||
// faces will get distributed that ultimately are not used. These will
|
// faces will get distributed that ultimately are not used. These will
|
||||||
// be filtered out after the intersection has been completed.
|
// be filtered out after the intersection has been completed.
|
||||||
tgtMapPtr_ =
|
tgtMapPtr_ =
|
||||||
patchDistributionMap
|
patchToPatchTools::constructDistributionMap
|
||||||
(
|
(
|
||||||
tgtPatchSendFaces
|
tgtPatchSendFaces
|
||||||
(
|
(
|
||||||
@ -1037,16 +915,16 @@ void Foam::patchToPatch::update
|
|||||||
tTgtPatch
|
tTgtPatch
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>> localTTgtPatchPtr =
|
autoPtr<PrimitiveOldTimePatch<faceList, pointField>> localTTgtPatchPtr;
|
||||||
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>>
|
localTgtProcFacesPtr_.reset
|
||||||
(
|
(
|
||||||
new PrimitiveOldTimePatch<faceList, pointField>
|
new List<remote>
|
||||||
(
|
(
|
||||||
distributePatch
|
distributePatch
|
||||||
(
|
(
|
||||||
tgtMapPtr_(),
|
tgtMapPtr_(),
|
||||||
tTgtPatch,
|
tTgtPatch,
|
||||||
localTgtProcFacesPtr_()
|
localTTgtPatchPtr
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -1082,11 +960,19 @@ void Foam::patchToPatch::update
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subset the local target patch
|
// Trim the local target patch
|
||||||
subsetLocalTgt(localTTgtPatch);
|
trimLocalTgt(localTTgtPatch);
|
||||||
|
|
||||||
// Distribute the source patch
|
// Distribute the source patch
|
||||||
srcMapPtr_ = patchDistributionMap(srcPatchSendFaces());
|
srcMapPtr_ =
|
||||||
|
patchToPatchTools::constructDistributionMap
|
||||||
|
(
|
||||||
|
patchToPatchTools::procSendIndices
|
||||||
|
(
|
||||||
|
tgtLocalSrcFaces_,
|
||||||
|
localTgtProcFacesPtr_()
|
||||||
|
)
|
||||||
|
);
|
||||||
distributeSrc(srcPatch);
|
distributeSrc(srcPatch);
|
||||||
|
|
||||||
// Reverse distribute coupling data back to the target
|
// Reverse distribute coupling data back to the target
|
||||||
|
|||||||
@ -89,49 +89,6 @@ protected:
|
|||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
// Indexing
|
|
||||||
|
|
||||||
//- Transfer list-list b into list-list a
|
|
||||||
template<class SubListA, class SubListB>
|
|
||||||
static inline void transferListList
|
|
||||||
(
|
|
||||||
List<SubListA>& a,
|
|
||||||
List<SubListB>& b
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Reverse distribute a list-list given the map
|
|
||||||
template<class Type>
|
|
||||||
static inline void rDistributeListList
|
|
||||||
(
|
|
||||||
const label size,
|
|
||||||
const distributionMap& map,
|
|
||||||
List<List<Type>>& data
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Reverse distribute a dynamic list-list given the map
|
|
||||||
template<class Type>
|
|
||||||
static inline void rDistributeListList
|
|
||||||
(
|
|
||||||
const label size,
|
|
||||||
const distributionMap& map,
|
|
||||||
List<DynamicList<Type>>& data
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Map local faces to proc faces
|
|
||||||
static List<List<remote>> localFacesToProcFaces
|
|
||||||
(
|
|
||||||
const List<DynamicList<label>>& localFaces,
|
|
||||||
const List<remote>& map = NullObjectRef<List<remote>>()
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Map proc faces to local faces
|
|
||||||
static List<DynamicList<label>> procFacesToLocalFaces
|
|
||||||
(
|
|
||||||
const List<List<remote>>& procFaces,
|
|
||||||
const HashTable<label, remote, Hash<remote>>& map
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// Searching
|
// Searching
|
||||||
|
|
||||||
//- Get the bound box for a source face
|
//- Get the bound box for a source face
|
||||||
@ -226,15 +183,6 @@ protected:
|
|||||||
|
|
||||||
// Parallel functionality
|
// Parallel functionality
|
||||||
|
|
||||||
//- Determine whether or not the intersection of the given patches
|
|
||||||
// is on a single process. Set singleProcess_ to that process if
|
|
||||||
// so, and to -1 if not.
|
|
||||||
void calcSingleProcess
|
|
||||||
(
|
|
||||||
const primitiveOldTimePatch& srcPatch,
|
|
||||||
const primitiveOldTimePatch& tgtPatch
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Determine which target faces need to be sent to the source.
|
//- Determine which target faces need to be sent to the source.
|
||||||
// This is done before intersection. Bound boxes are used to
|
// This is done before intersection. Bound boxes are used to
|
||||||
// estimate what faces will intersect.
|
// estimate what faces will intersect.
|
||||||
@ -246,33 +194,14 @@ protected:
|
|||||||
const primitiveOldTimePatch& tgtPatch
|
const primitiveOldTimePatch& tgtPatch
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
//- Determine which source faces need to be sent to the target.
|
|
||||||
// This is done after intersection, using the addressing generated
|
|
||||||
// by the intersection.
|
|
||||||
labelListList srcPatchSendFaces() const;
|
|
||||||
|
|
||||||
//- Create a distribution map from a list-list of faces to be sent
|
|
||||||
// (i.e., the result of calling one of the above methods).
|
|
||||||
autoPtr<distributionMap> patchDistributionMap
|
|
||||||
(
|
|
||||||
labelListList&& sendFaces
|
|
||||||
) const;
|
|
||||||
|
|
||||||
//- Distribute a patch given its distribution map
|
//- Distribute a patch given its distribution map
|
||||||
PrimitiveOldTimePatch<faceList, pointField> distributePatch
|
static List<remote> distributePatch
|
||||||
(
|
(
|
||||||
const distributionMap& map,
|
const distributionMap& map,
|
||||||
const primitiveOldTimePatch& patch,
|
const primitiveOldTimePatch& patch,
|
||||||
List<remote>& localProcFaces
|
autoPtr<PrimitiveOldTimePatch<faceList, pointField>>&
|
||||||
) const;
|
localPatchPtr
|
||||||
|
);
|
||||||
//- As above, but when you want the proc-faces without the
|
|
||||||
// associated patch geometry
|
|
||||||
void distributePatch
|
|
||||||
(
|
|
||||||
const distributionMap& map,
|
|
||||||
List<remote>& localProcFaces
|
|
||||||
) const;
|
|
||||||
|
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
@ -286,9 +215,9 @@ protected:
|
|||||||
const primitiveOldTimePatch& tgtPatch
|
const primitiveOldTimePatch& tgtPatch
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Subset the local target patch so that only parts that actually
|
//- Trim the local target patch so that only parts that actually
|
||||||
// intersect the source remain
|
// intersect the source remain
|
||||||
virtual labelList subsetLocalTgt
|
virtual labelList trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
);
|
);
|
||||||
|
|||||||
@ -24,63 +24,7 @@ License
|
|||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "patchToPatch.H"
|
#include "patchToPatch.H"
|
||||||
|
#include "patchToPatchTools.H"
|
||||||
// * * * * * * * * * * * Private Static Member Functions * * * * * * * * * * //
|
|
||||||
|
|
||||||
template<class SubListA, class SubListB>
|
|
||||||
inline void Foam::patchToPatch::transferListList
|
|
||||||
(
|
|
||||||
List<SubListA>& a,
|
|
||||||
List<SubListB>& b
|
|
||||||
)
|
|
||||||
{
|
|
||||||
a.resize(b.size());
|
|
||||||
forAll(a, i)
|
|
||||||
{
|
|
||||||
a[i].transfer(b[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
inline void Foam::patchToPatch::rDistributeListList
|
|
||||||
(
|
|
||||||
const label size,
|
|
||||||
const distributionMap& map,
|
|
||||||
List<List<Type>>& data
|
|
||||||
)
|
|
||||||
{
|
|
||||||
distributionMapBase::distribute
|
|
||||||
(
|
|
||||||
Pstream::commsTypes::nonBlocking,
|
|
||||||
List<labelPair>(),
|
|
||||||
size,
|
|
||||||
map.constructMap(),
|
|
||||||
false,
|
|
||||||
map.subMap(),
|
|
||||||
false,
|
|
||||||
data,
|
|
||||||
ListAppendEqOp<Type>(),
|
|
||||||
flipOp(),
|
|
||||||
List<Type>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
inline void Foam::patchToPatch::rDistributeListList
|
|
||||||
(
|
|
||||||
const label size,
|
|
||||||
const distributionMap& map,
|
|
||||||
List<DynamicList<Type>>& data
|
|
||||||
)
|
|
||||||
{
|
|
||||||
List<List<Type>> tData;
|
|
||||||
transferListList(tData, data);
|
|
||||||
rDistributeListList(size, map, tData);
|
|
||||||
transferListList(data, tData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -107,8 +51,12 @@ Foam::patchToPatch::srcTgtProcFaces() const
|
|||||||
{
|
{
|
||||||
return
|
return
|
||||||
isSingleProcess()
|
isSingleProcess()
|
||||||
? localFacesToProcFaces(srcLocalTgtFaces_)
|
? patchToPatchTools::localToRemote(srcLocalTgtFaces_)
|
||||||
: localFacesToProcFaces(srcLocalTgtFaces_, localTgtProcFacesPtr_());
|
: patchToPatchTools::localToRemote
|
||||||
|
(
|
||||||
|
srcLocalTgtFaces_,
|
||||||
|
localTgtProcFacesPtr_()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -117,8 +65,12 @@ Foam::patchToPatch::tgtSrcProcFaces() const
|
|||||||
{
|
{
|
||||||
return
|
return
|
||||||
isSingleProcess()
|
isSingleProcess()
|
||||||
? localFacesToProcFaces(tgtLocalSrcFaces_)
|
? patchToPatchTools::localToRemote(tgtLocalSrcFaces_)
|
||||||
: localFacesToProcFaces(tgtLocalSrcFaces_, localSrcProcFacesPtr_());
|
: patchToPatchTools::localToRemote
|
||||||
|
(
|
||||||
|
tgtLocalSrcFaces_,
|
||||||
|
localSrcProcFacesPtr_()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -31,44 +31,6 @@ License
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
void Foam::patchToPatch::calcSingleProcess
|
|
||||||
(
|
|
||||||
const primitiveOldTimePatch& srcPatch,
|
|
||||||
const primitiveOldTimePatch& tgtPatch
|
|
||||||
)
|
|
||||||
{
|
|
||||||
singleProcess_ = 0;
|
|
||||||
|
|
||||||
if (Pstream::parRun())
|
|
||||||
{
|
|
||||||
boolList procHasFaces(Pstream::nProcs(), false);
|
|
||||||
|
|
||||||
if ((srcPatch.size() > 0) || (tgtPatch.size() > 0))
|
|
||||||
{
|
|
||||||
procHasFaces[Pstream::myProcNo()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pstream::gatherList(procHasFaces);
|
|
||||||
Pstream::scatterList(procHasFaces);
|
|
||||||
|
|
||||||
const label nProcsHaveFaces = count(procHasFaces, true);
|
|
||||||
|
|
||||||
if (nProcsHaveFaces == 0)
|
|
||||||
{
|
|
||||||
singleProcess_ = 0;
|
|
||||||
}
|
|
||||||
if (nProcsHaveFaces == 1)
|
|
||||||
{
|
|
||||||
singleProcess_ = findIndex(procHasFaces, true);
|
|
||||||
}
|
|
||||||
if (nProcsHaveFaces > 1)
|
|
||||||
{
|
|
||||||
singleProcess_ = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::labelListList Foam::patchToPatch::tgtPatchSendFaces
|
Foam::labelListList Foam::patchToPatch::tgtPatchSendFaces
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& srcPatch,
|
const primitiveOldTimePatch& srcPatch,
|
||||||
@ -127,103 +89,12 @@ Foam::labelListList Foam::patchToPatch::tgtPatchSendFaces
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Foam::labelListList Foam::patchToPatch::srcPatchSendFaces() const
|
Foam::List<Foam::remote> Foam::patchToPatch::distributePatch
|
||||||
{
|
|
||||||
// Send a source face to a proc if target face on that proc intersects it
|
|
||||||
List<labelHashSet> resultDyn(Pstream::nProcs());
|
|
||||||
forAll(tgtLocalSrcFaces_, tgtFacei)
|
|
||||||
{
|
|
||||||
const label tgtProci = localTgtProcFacesPtr_()[tgtFacei].proci;
|
|
||||||
|
|
||||||
forAll(tgtLocalSrcFaces_[tgtFacei], i)
|
|
||||||
{
|
|
||||||
const label srcFacei = tgtLocalSrcFaces_[tgtFacei][i];
|
|
||||||
|
|
||||||
resultDyn[tgtProci].insert(srcFacei);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfer to non-dynamic storage
|
|
||||||
labelListList result(Pstream::nProcs());
|
|
||||||
forAll(result, proci)
|
|
||||||
{
|
|
||||||
result[proci] = resultDyn[proci].toc();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::autoPtr<Foam::distributionMap> Foam::patchToPatch::patchDistributionMap
|
|
||||||
(
|
|
||||||
labelListList&& sendFaces
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
// Figure out how many target faces are to be received
|
|
||||||
labelList nReceiveFaces(Pstream::nProcs());
|
|
||||||
{
|
|
||||||
labelListList nSendFaces(Pstream::nProcs());
|
|
||||||
|
|
||||||
nSendFaces[Pstream::myProcNo()].setSize(Pstream::nProcs());
|
|
||||||
forAll(sendFaces, proci)
|
|
||||||
{
|
|
||||||
nSendFaces[Pstream::myProcNo()][proci] =
|
|
||||||
sendFaces[proci].size();
|
|
||||||
}
|
|
||||||
|
|
||||||
Pstream::gatherList(nSendFaces);
|
|
||||||
Pstream::scatterList(nSendFaces);
|
|
||||||
|
|
||||||
forAll(sendFaces, proci)
|
|
||||||
{
|
|
||||||
nReceiveFaces[proci] =
|
|
||||||
nSendFaces[proci][Pstream::myProcNo()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine order of receiving
|
|
||||||
labelListList receiveFaces(Pstream::nProcs());
|
|
||||||
|
|
||||||
// Local faces first
|
|
||||||
receiveFaces[Pstream::myProcNo()] =
|
|
||||||
identity(sendFaces[Pstream::myProcNo()].size());
|
|
||||||
|
|
||||||
// Remote faces next
|
|
||||||
label localFacei = receiveFaces[Pstream::myProcNo()].size();
|
|
||||||
forAll(receiveFaces, proci)
|
|
||||||
{
|
|
||||||
if (proci != Pstream::myProcNo())
|
|
||||||
{
|
|
||||||
const label n = nReceiveFaces[proci];
|
|
||||||
receiveFaces[proci].setSize(n);
|
|
||||||
for (label i = 0; i < n; i ++)
|
|
||||||
{
|
|
||||||
receiveFaces[proci][i] = localFacei ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct and return the map
|
|
||||||
return
|
|
||||||
autoPtr<distributionMap>
|
|
||||||
(
|
|
||||||
new distributionMap
|
|
||||||
(
|
|
||||||
localFacei,
|
|
||||||
move(sendFaces),
|
|
||||||
move(receiveFaces)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::PrimitiveOldTimePatch<Foam::faceList, Foam::pointField>
|
|
||||||
Foam::patchToPatch::distributePatch
|
|
||||||
(
|
(
|
||||||
const distributionMap& map,
|
const distributionMap& map,
|
||||||
const primitiveOldTimePatch& patch,
|
const primitiveOldTimePatch& patch,
|
||||||
List<remote>& localProcFaces
|
autoPtr<PrimitiveOldTimePatch<faceList, pointField>>& localPatchPtr
|
||||||
) const
|
)
|
||||||
{
|
{
|
||||||
static const label thisProci = Pstream::myProcNo();
|
static const label thisProci = Pstream::myProcNo();
|
||||||
|
|
||||||
@ -294,6 +165,7 @@ Foam::patchToPatch::distributePatch
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate
|
// Allocate
|
||||||
|
List<remote> localProcFaces;
|
||||||
faceList localFaces;
|
faceList localFaces;
|
||||||
pointField localPoints;
|
pointField localPoints;
|
||||||
pointField localPoints0;
|
pointField localPoints0;
|
||||||
@ -313,37 +185,9 @@ Foam::patchToPatch::distributePatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renumber and flatten
|
// Construct the result
|
||||||
label localFacei = 0, localPointi = 0;
|
label localFacei = 0, localPointi = 0;
|
||||||
|
|
||||||
// Local data first
|
|
||||||
{
|
|
||||||
const labelList& fis = procLocalFaceis[thisProci];
|
|
||||||
const faceList& fs = procLocalFaces[thisProci];
|
|
||||||
forAll(fis, i)
|
|
||||||
{
|
|
||||||
localProcFaces[localFacei] = {thisProci, fis[i]};
|
|
||||||
localFaces[localFacei] = face(fs[i] + localPointi);
|
|
||||||
localFacei ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pointField& ps = procLocalPoints[thisProci];
|
|
||||||
const pointField& ps0 = procLocalPoints0[thisProci];
|
|
||||||
forAll(ps, i)
|
|
||||||
{
|
|
||||||
localPoints[localPointi] = ps[i];
|
|
||||||
if (patch.has0())
|
|
||||||
{
|
|
||||||
localPoints0[localPointi] = ps0[i];
|
|
||||||
}
|
|
||||||
localPointi ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remote data after
|
|
||||||
forAll(procLocalFaces, proci)
|
forAll(procLocalFaces, proci)
|
||||||
{
|
|
||||||
if (proci != thisProci)
|
|
||||||
{
|
{
|
||||||
const labelList& fis = procLocalFaceis[proci];
|
const labelList& fis = procLocalFaceis[proci];
|
||||||
const faceList& fs = procLocalFaces[proci];
|
const faceList& fs = procLocalFaces[proci];
|
||||||
@ -366,103 +210,25 @@ Foam::patchToPatch::distributePatch
|
|||||||
localPointi ++;
|
localPointi ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return
|
// Construct the local patch
|
||||||
|
localPatchPtr.reset
|
||||||
|
(
|
||||||
patch.has0()
|
patch.has0()
|
||||||
? PrimitiveOldTimePatch<faceList, pointField>
|
? new PrimitiveOldTimePatch<faceList, pointField>
|
||||||
(
|
(
|
||||||
localFaces,
|
localFaces,
|
||||||
localPoints,
|
localPoints,
|
||||||
localPoints0
|
localPoints0
|
||||||
)
|
)
|
||||||
: PrimitiveOldTimePatch<faceList, pointField>
|
: new PrimitiveOldTimePatch<faceList, pointField>
|
||||||
(
|
(
|
||||||
localFaces,
|
localFaces,
|
||||||
localPoints
|
localPoints
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
|
return localProcFaces;
|
||||||
void Foam::patchToPatch::distributePatch
|
|
||||||
(
|
|
||||||
const distributionMap& map,
|
|
||||||
List<remote>& localProcFaces
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
static const label thisProci = Pstream::myProcNo();
|
|
||||||
|
|
||||||
// Exchange per-processor data
|
|
||||||
List<labelList> procLocalFaceis(Pstream::nProcs());
|
|
||||||
{
|
|
||||||
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
|
|
||||||
|
|
||||||
// Send
|
|
||||||
for (label proci = 0; proci < Pstream::nProcs(); proci++)
|
|
||||||
{
|
|
||||||
const labelList& sendFaceis = map.subMap()[proci];
|
|
||||||
|
|
||||||
if (proci != thisProci && sendFaceis.size())
|
|
||||||
{
|
|
||||||
UOPstream(proci, pBufs)() << sendFaceis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pBufs.finishedSends();
|
|
||||||
|
|
||||||
// Map local data
|
|
||||||
{
|
|
||||||
const labelList& sendFaceis = map.subMap()[thisProci];
|
|
||||||
|
|
||||||
procLocalFaceis[thisProci] = sendFaceis;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive remote data
|
|
||||||
for (label proci = 0; proci < Pstream::nProcs(); proci++)
|
|
||||||
{
|
|
||||||
if (proci != thisProci && map.constructMap()[proci].size())
|
|
||||||
{
|
|
||||||
UIPstream(proci, pBufs)() >> procLocalFaceis[proci];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate
|
|
||||||
{
|
|
||||||
label nLocalFaces = 0;
|
|
||||||
forAll(procLocalFaceis, proci)
|
|
||||||
{
|
|
||||||
nLocalFaces += procLocalFaceis[proci].size();
|
|
||||||
}
|
|
||||||
localProcFaces.setSize(nLocalFaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renumber and flatten
|
|
||||||
label localFacei = 0;
|
|
||||||
|
|
||||||
// Local data first
|
|
||||||
{
|
|
||||||
const labelList& fis = procLocalFaceis[thisProci];
|
|
||||||
forAll(fis, i)
|
|
||||||
{
|
|
||||||
localProcFaces[localFacei] = {thisProci, fis[i]};
|
|
||||||
localFacei ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remote data after
|
|
||||||
forAll(procLocalFaceis, proci)
|
|
||||||
{
|
|
||||||
if (proci != thisProci)
|
|
||||||
{
|
|
||||||
const labelList& fis = procLocalFaceis[proci];
|
|
||||||
forAll(fis, i)
|
|
||||||
{
|
|
||||||
localProcFaces[localFacei] = {proci, fis[i]};
|
|
||||||
localFacei ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -86,13 +86,13 @@ bool Foam::patchToPatches::rays::intersectFaces
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Foam::labelList Foam::patchToPatches::rays::subsetLocalTgt
|
Foam::labelList Foam::patchToPatches::rays::trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const labelList newToOldLocalTgtFace =
|
const labelList newToOldLocalTgtFace =
|
||||||
patchToPatch::subsetLocalTgt(localTgtPatch);
|
patchToPatch::trimLocalTgt(localTgtPatch);
|
||||||
|
|
||||||
localTgtPatchPtr_.reset
|
localTgtPatchPtr_.reset
|
||||||
(
|
(
|
||||||
@ -113,11 +113,11 @@ void Foam::patchToPatches::rays::distributeSrc
|
|||||||
const primitiveOldTimePatch& srcPatch
|
const primitiveOldTimePatch& srcPatch
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
localSrcPatchPtr_.reset
|
localSrcProcFacesPtr_.reset
|
||||||
(
|
(
|
||||||
new PrimitiveOldTimePatch<faceList, pointField>
|
new List<remote>
|
||||||
(
|
(
|
||||||
distributePatch(srcMapPtr_(), srcPatch, localSrcProcFacesPtr_())
|
distributePatch(srcMapPtr_(), srcPatch, localSrcPatchPtr_)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,7 +94,7 @@ class rays
|
|||||||
|
|
||||||
//- Subset the local target patch so that only parts that actually
|
//- Subset the local target patch so that only parts that actually
|
||||||
// intersect the source remain
|
// intersect the source remain
|
||||||
virtual labelList subsetLocalTgt
|
virtual labelList trimLocalTgt
|
||||||
(
|
(
|
||||||
const primitiveOldTimePatch& localTgtPatch
|
const primitiveOldTimePatch& localTgtPatch
|
||||||
);
|
);
|
||||||
|
|||||||
402
src/meshTools/patchToPatchTools/patchToPatchTools.C
Normal file
402
src/meshTools/patchToPatchTools/patchToPatchTools.C
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "patchToPatchTools.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::label Foam::patchToPatchTools::singleProcess
|
||||||
|
(
|
||||||
|
const label srcSize,
|
||||||
|
const label tgtSize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
label result = 0;
|
||||||
|
|
||||||
|
if (Pstream::parRun())
|
||||||
|
{
|
||||||
|
boolList procHasElements(Pstream::nProcs(), false);
|
||||||
|
|
||||||
|
if (srcSize > 0 || tgtSize > 0)
|
||||||
|
{
|
||||||
|
procHasElements[Pstream::myProcNo()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pstream::gatherList(procHasElements);
|
||||||
|
Pstream::scatterList(procHasElements);
|
||||||
|
|
||||||
|
const label nProcsHaveElements = count(procHasElements, true);
|
||||||
|
|
||||||
|
if (nProcsHaveElements == 0)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nProcsHaveElements == 1)
|
||||||
|
{
|
||||||
|
result = findIndex(procHasElements, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nProcsHaveElements > 1)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::autoPtr<Foam::distributionMap>
|
||||||
|
Foam::patchToPatchTools::constructDistributionMap
|
||||||
|
(
|
||||||
|
const labelListList& procSendIndices
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Communicate the size of all the transfers
|
||||||
|
labelListList transferSizes(Pstream::nProcs());
|
||||||
|
transferSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
|
||||||
|
forAll(procSendIndices, proci)
|
||||||
|
{
|
||||||
|
transferSizes[Pstream::myProcNo()][proci] =
|
||||||
|
procSendIndices[proci].size();
|
||||||
|
}
|
||||||
|
Pstream::gatherList(transferSizes);
|
||||||
|
Pstream::scatterList(transferSizes);
|
||||||
|
|
||||||
|
// Determine order of receiving
|
||||||
|
labelListList constructMap(Pstream::nProcs());
|
||||||
|
label index = constructMap[Pstream::myProcNo()].size();
|
||||||
|
forAll(constructMap, proci)
|
||||||
|
{
|
||||||
|
const label n = transferSizes[proci][Pstream::myProcNo()];
|
||||||
|
constructMap[proci].setSize(n);
|
||||||
|
|
||||||
|
for (label i = 0; i < n; i ++)
|
||||||
|
{
|
||||||
|
constructMap[proci][i] = index ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct and return the map
|
||||||
|
return
|
||||||
|
autoPtr<distributionMap>
|
||||||
|
(
|
||||||
|
new distributionMap
|
||||||
|
(
|
||||||
|
index,
|
||||||
|
labelListList(procSendIndices),
|
||||||
|
move(constructMap)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::List<Foam::remote> Foam::patchToPatchTools::distributeAddressing
|
||||||
|
(
|
||||||
|
const distributionMap& map
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static const label thisProci = Pstream::myProcNo();
|
||||||
|
|
||||||
|
// Exchange per-processor data
|
||||||
|
List<labelList> procLocalFaceis(Pstream::nProcs());
|
||||||
|
{
|
||||||
|
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
|
||||||
|
|
||||||
|
// Send
|
||||||
|
for (label proci = 0; proci < Pstream::nProcs(); proci++)
|
||||||
|
{
|
||||||
|
const labelList& sendFaceis = map.subMap()[proci];
|
||||||
|
|
||||||
|
if (proci != thisProci && sendFaceis.size())
|
||||||
|
{
|
||||||
|
UOPstream(proci, pBufs)() << sendFaceis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pBufs.finishedSends();
|
||||||
|
|
||||||
|
// Map local data
|
||||||
|
{
|
||||||
|
const labelList& sendFaceis = map.subMap()[thisProci];
|
||||||
|
|
||||||
|
procLocalFaceis[thisProci] = sendFaceis;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive remote data
|
||||||
|
for (label proci = 0; proci < Pstream::nProcs(); proci++)
|
||||||
|
{
|
||||||
|
if (proci != thisProci && map.constructMap()[proci].size())
|
||||||
|
{
|
||||||
|
UIPstream(proci, pBufs)() >> procLocalFaceis[proci];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate
|
||||||
|
List<remote> localProcFaces;
|
||||||
|
{
|
||||||
|
label nLocalFaces = 0;
|
||||||
|
forAll(procLocalFaceis, proci)
|
||||||
|
{
|
||||||
|
nLocalFaces += procLocalFaceis[proci].size();
|
||||||
|
}
|
||||||
|
localProcFaces.setSize(nLocalFaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the result
|
||||||
|
label localFacei = 0;
|
||||||
|
forAll(procLocalFaceis, proci)
|
||||||
|
{
|
||||||
|
const labelList& fis = procLocalFaceis[proci];
|
||||||
|
forAll(fis, i)
|
||||||
|
{
|
||||||
|
localProcFaces[localFacei] = {proci, fis[i]};
|
||||||
|
localFacei ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return localProcFaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::labelListList Foam::patchToPatchTools::procSendIndices
|
||||||
|
(
|
||||||
|
const labelListList& tgtLocalSrcFaces,
|
||||||
|
const List<remote>& localTgtProcFaces
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Send a source face to a proc if target face on that proc intersects it
|
||||||
|
List<labelHashSet> resultDyn(Pstream::nProcs());
|
||||||
|
forAll(tgtLocalSrcFaces, tgtFacei)
|
||||||
|
{
|
||||||
|
const label tgtProci = localTgtProcFaces[tgtFacei].proci;
|
||||||
|
|
||||||
|
forAll(tgtLocalSrcFaces[tgtFacei], i)
|
||||||
|
{
|
||||||
|
const label srcFacei = tgtLocalSrcFaces[tgtFacei][i];
|
||||||
|
|
||||||
|
resultDyn[tgtProci].insert(srcFacei);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer to non-dynamic storage
|
||||||
|
labelListList result(Pstream::nProcs());
|
||||||
|
forAll(result, proci)
|
||||||
|
{
|
||||||
|
result[proci] = resultDyn[proci].toc();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::labelListList Foam::patchToPatchTools::procSendIndices
|
||||||
|
(
|
||||||
|
const List<DynamicList<label>>& tgtLocalSrcFaces,
|
||||||
|
const List<remote>& localTgtProcFaces
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
procSendIndices
|
||||||
|
(
|
||||||
|
labelListList(tgtLocalSrcFaces),
|
||||||
|
localTgtProcFaces
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::patchToPatchTools::trimDistributionMap
|
||||||
|
(
|
||||||
|
const boolList& oldIsUsed,
|
||||||
|
distributionMap& map,
|
||||||
|
labelList& oldToNew,
|
||||||
|
labelList& newToOld
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Create re-indexing
|
||||||
|
oldToNew.resize(oldIsUsed.size());
|
||||||
|
newToOld.resize(count(oldIsUsed, true));
|
||||||
|
|
||||||
|
oldToNew = -1;
|
||||||
|
newToOld = -1;
|
||||||
|
|
||||||
|
label newi = 0;
|
||||||
|
forAll(oldIsUsed, oldi)
|
||||||
|
{
|
||||||
|
if (oldIsUsed[oldi])
|
||||||
|
{
|
||||||
|
oldToNew[oldi] = newi;
|
||||||
|
newToOld[newi] = oldi;
|
||||||
|
++ newi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per-processor used list for construction
|
||||||
|
List<boolList> allOldIsUsed(Pstream::nProcs());
|
||||||
|
forAll(map.constructMap(), proci)
|
||||||
|
{
|
||||||
|
allOldIsUsed[proci] =
|
||||||
|
UIndirectList<bool>(oldIsUsed, map.constructMap()[proci]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Communicate to form a per-processor used list for subsetting
|
||||||
|
List<boolList> allSubOldIsUsed(Pstream::nProcs());
|
||||||
|
Pstream::exchange<boolList, bool>(allOldIsUsed, allSubOldIsUsed);
|
||||||
|
|
||||||
|
// Subset the sub map
|
||||||
|
forAll(map.subMap(), proci)
|
||||||
|
{
|
||||||
|
label newi = 0;
|
||||||
|
forAll(map.subMap()[proci], oldi)
|
||||||
|
{
|
||||||
|
if (allSubOldIsUsed[proci][oldi])
|
||||||
|
{
|
||||||
|
map.subMap()[proci][newi ++] =
|
||||||
|
map.subMap()[proci][oldi];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.subMap()[proci].resize(newi);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subset and renumber the construct map
|
||||||
|
forAll(map.constructMap(), proci)
|
||||||
|
{
|
||||||
|
label newi = 0;
|
||||||
|
forAll(map.constructMap()[proci], oldi)
|
||||||
|
{
|
||||||
|
if (allOldIsUsed[proci][oldi])
|
||||||
|
{
|
||||||
|
map.constructMap()[proci][newi ++] =
|
||||||
|
oldToNew[map.constructMap()[proci][oldi]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.constructMap()[proci].resize(newi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::List<Foam::List<Foam::remote>> Foam::patchToPatchTools::localToRemote
|
||||||
|
(
|
||||||
|
const labelListList& indices,
|
||||||
|
const List<remote>& indexToProcIndex
|
||||||
|
)
|
||||||
|
{
|
||||||
|
List<List<remote>> result(indices.size());
|
||||||
|
|
||||||
|
forAll(indices, thisFacei)
|
||||||
|
{
|
||||||
|
result[thisFacei].resize(indices[thisFacei].size());
|
||||||
|
|
||||||
|
forAll(indices[thisFacei], i)
|
||||||
|
{
|
||||||
|
result[thisFacei][i] =
|
||||||
|
isNull(indexToProcIndex)
|
||||||
|
? remote(Pstream::myProcNo(), indices[thisFacei][i])
|
||||||
|
: indexToProcIndex[indices[thisFacei][i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::List<Foam::List<Foam::remote>> Foam::patchToPatchTools::localToRemote
|
||||||
|
(
|
||||||
|
const List<DynamicList<label>>& indices,
|
||||||
|
const List<remote>& indexToProcIndex
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
localToRemote
|
||||||
|
(
|
||||||
|
labelListList(indices),
|
||||||
|
indexToProcIndex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::patchToPatchTools::rDistributeTgtAddressing
|
||||||
|
(
|
||||||
|
const label tgtSize,
|
||||||
|
const distributionMap& tgtMap,
|
||||||
|
const List<remote>& localSrcProcFaces,
|
||||||
|
labelListList& tgtLocalSrcFaces
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Create a map from source procFace to local source face
|
||||||
|
HashTable<label, remote, Hash<remote>> srcProcFaceToLocal;
|
||||||
|
forAll(localSrcProcFaces, localSrcFacei)
|
||||||
|
{
|
||||||
|
srcProcFaceToLocal.insert
|
||||||
|
(
|
||||||
|
localSrcProcFaces[localSrcFacei],
|
||||||
|
localSrcFacei
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect the source procFaces on the target and convert to local
|
||||||
|
// source face addressing
|
||||||
|
List<List<remote>> tgtSrcProcFaces = localToRemote(tgtLocalSrcFaces);
|
||||||
|
|
||||||
|
rDistributeListList(tgtSize, tgtMap, tgtSrcProcFaces);
|
||||||
|
|
||||||
|
tgtLocalSrcFaces.resize(tgtSize);
|
||||||
|
forAll(tgtSrcProcFaces, tgtFacei)
|
||||||
|
{
|
||||||
|
tgtLocalSrcFaces[tgtFacei].resize(tgtSrcProcFaces[tgtFacei].size());
|
||||||
|
|
||||||
|
forAll(tgtSrcProcFaces[tgtFacei], i)
|
||||||
|
{
|
||||||
|
tgtLocalSrcFaces[tgtFacei][i] =
|
||||||
|
srcProcFaceToLocal[tgtSrcProcFaces[tgtFacei][i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::patchToPatchTools::rDistributeTgtAddressing
|
||||||
|
(
|
||||||
|
const label tgtSize,
|
||||||
|
const distributionMap& tgtMap,
|
||||||
|
const List<remote>& localSrcProcFaces,
|
||||||
|
List<DynamicList<label>>& tgtLocalSrcFaces
|
||||||
|
)
|
||||||
|
{
|
||||||
|
labelListList tTgtLocalSrcFaces;
|
||||||
|
transferListList(tTgtLocalSrcFaces, tgtLocalSrcFaces);
|
||||||
|
rDistributeTgtAddressing
|
||||||
|
(
|
||||||
|
tgtSize,
|
||||||
|
tgtMap,
|
||||||
|
localSrcProcFaces,
|
||||||
|
tTgtLocalSrcFaces
|
||||||
|
);
|
||||||
|
transferListList(tgtLocalSrcFaces, tTgtLocalSrcFaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
153
src/meshTools/patchToPatchTools/patchToPatchTools.H
Normal file
153
src/meshTools/patchToPatchTools/patchToPatchTools.H
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Namespace
|
||||||
|
Foam::patchToPatchTools
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef patchToPatchTools_H
|
||||||
|
#define patchToPatchTools_H
|
||||||
|
|
||||||
|
#include "distributionMap.H"
|
||||||
|
#include "remote.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace patchToPatchTools
|
||||||
|
{
|
||||||
|
|
||||||
|
//- Determine whether this intersection is confined to a single processor or
|
||||||
|
// not, purely from the numbers of elements in the geometry
|
||||||
|
label singleProcess(const label srcSize, const label tgtSize);
|
||||||
|
|
||||||
|
//- Turn a list of send-to-processor indices into a distribution map
|
||||||
|
autoPtr<distributionMap> constructDistributionMap
|
||||||
|
(
|
||||||
|
const labelListList& procSendIndices
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Construct local addressing from the given distribution map. The result is a
|
||||||
|
// list of remote element indices that correspond to the elements that were
|
||||||
|
// sent by the distribution map.
|
||||||
|
List<remote> distributeAddressing(const distributionMap& map);
|
||||||
|
|
||||||
|
//- Given a local intersection addressing, determine what elements need sending
|
||||||
|
// to each processor
|
||||||
|
labelListList procSendIndices
|
||||||
|
(
|
||||||
|
const labelListList& tgtLocalSrcFaces,
|
||||||
|
const List<remote>& localTgtProcFaces
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Dynamic list overload of the above
|
||||||
|
labelListList procSendIndices
|
||||||
|
(
|
||||||
|
const List<DynamicList<label>>& tgtLocalSrcFaces,
|
||||||
|
const List<remote>& localTgtProcFaces
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Trim unused elements from a distribution map. Return the map and maps
|
||||||
|
// between the old and new construct list.
|
||||||
|
void trimDistributionMap
|
||||||
|
(
|
||||||
|
const boolList& oldIsUsed,
|
||||||
|
distributionMap& map,
|
||||||
|
labelList& oldToNew,
|
||||||
|
labelList& newToOld
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Transfer list-list b into list-list a
|
||||||
|
template<class SubListA, class SubListB>
|
||||||
|
static inline void transferListList
|
||||||
|
(
|
||||||
|
List<SubListA>& a,
|
||||||
|
List<SubListB>& b
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Reverse distribute a list-list given the map
|
||||||
|
template<class Type>
|
||||||
|
static inline void rDistributeListList
|
||||||
|
(
|
||||||
|
const label size,
|
||||||
|
const distributionMap& map,
|
||||||
|
List<List<Type>>& data
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Dynamic list overload of the above
|
||||||
|
template<class Type>
|
||||||
|
static inline void rDistributeListList
|
||||||
|
(
|
||||||
|
const label size,
|
||||||
|
const distributionMap& map,
|
||||||
|
List<DynamicList<Type>>& data
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Map local to remote indices
|
||||||
|
List<List<remote>> localToRemote
|
||||||
|
(
|
||||||
|
const labelListList& indices,
|
||||||
|
const List<remote>& indexToProcIndex = NullObjectRef<List<remote>>()
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Dynamic list overload of the above
|
||||||
|
List<List<remote>> localToRemote
|
||||||
|
(
|
||||||
|
const List<DynamicList<label>>& indices,
|
||||||
|
const List<remote>& indexToProcIndex = NullObjectRef<List<remote>>()
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Reverse distribute a set of target addressing
|
||||||
|
void rDistributeTgtAddressing
|
||||||
|
(
|
||||||
|
const label tgtSize,
|
||||||
|
const distributionMap& tgtMap,
|
||||||
|
const List<remote>& localSrcProcFaces,
|
||||||
|
labelListList& tgtLocalSrcFaces
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Dynamic list overload of the above
|
||||||
|
void rDistributeTgtAddressing
|
||||||
|
(
|
||||||
|
const label tgtSize,
|
||||||
|
const distributionMap& tgtMap,
|
||||||
|
const List<remote>& localSrcProcFaces,
|
||||||
|
List<DynamicList<label>>& tgtLocalSrcFaces
|
||||||
|
);
|
||||||
|
|
||||||
|
} // End namespace patchToPatchTools
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#ifdef NoRepository
|
||||||
|
#include "patchToPatchToolsTemplates.C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
85
src/meshTools/patchToPatchTools/patchToPatchToolsTemplates.C
Normal file
85
src/meshTools/patchToPatchTools/patchToPatchToolsTemplates.C
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
|
||||||
|
\\/ 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "patchToPatchTools.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class SubListA, class SubListB>
|
||||||
|
void Foam::patchToPatchTools::transferListList
|
||||||
|
(
|
||||||
|
List<SubListA>& a,
|
||||||
|
List<SubListB>& b
|
||||||
|
)
|
||||||
|
{
|
||||||
|
a.resize(b.size());
|
||||||
|
forAll(a, i)
|
||||||
|
{
|
||||||
|
a[i].transfer(b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
void Foam::patchToPatchTools::rDistributeListList
|
||||||
|
(
|
||||||
|
const label size,
|
||||||
|
const distributionMap& map,
|
||||||
|
List<List<Type>>& data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
distributionMapBase::distribute
|
||||||
|
(
|
||||||
|
Pstream::commsTypes::nonBlocking,
|
||||||
|
List<labelPair>(),
|
||||||
|
size,
|
||||||
|
map.constructMap(),
|
||||||
|
false,
|
||||||
|
map.subMap(),
|
||||||
|
false,
|
||||||
|
data,
|
||||||
|
ListAppendEqOp<Type>(),
|
||||||
|
flipOp(),
|
||||||
|
List<Type>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
void Foam::patchToPatchTools::rDistributeListList
|
||||||
|
(
|
||||||
|
const label size,
|
||||||
|
const distributionMap& map,
|
||||||
|
List<DynamicList<Type>>& data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
List<List<Type>> tData;
|
||||||
|
transferListList(tData, data);
|
||||||
|
rDistributeListList(size, map, tData);
|
||||||
|
transferListList(data, tData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -60,19 +60,5 @@ $(surfWriters)/proxy/proxySurfaceWriter.C
|
|||||||
$(surfWriters)/raw/rawSurfaceWriter.C
|
$(surfWriters)/raw/rawSurfaceWriter.C
|
||||||
$(surfWriters)/vtk/vtkSurfaceWriter.C
|
$(surfWriters)/vtk/vtkSurfaceWriter.C
|
||||||
|
|
||||||
meshToMesh/meshToMesh.C
|
|
||||||
meshToMesh/meshToMeshParallelOps.C
|
|
||||||
meshToMesh/patchToPatchFvPatchFieldMapper.C
|
|
||||||
meshToMeshMethods = meshToMesh/calcMethod
|
|
||||||
$(meshToMeshMethods)/meshToMeshMethod/meshToMeshMethod.C
|
|
||||||
$(meshToMeshMethods)/meshToMeshMethod/meshToMeshMethodNew.C
|
|
||||||
$(meshToMeshMethods)/cellVolumeWeight/cellVolumeWeightMethod.C
|
|
||||||
$(meshToMeshMethods)/direct/directMethod.C
|
|
||||||
$(meshToMeshMethods)/mapNearest/mapNearestMethod.C
|
|
||||||
|
|
||||||
meshToMesh0/meshToMesh0.C
|
|
||||||
meshToMesh0/calculateMeshToMesh0Addressing.C
|
|
||||||
meshToMesh0/calculateMeshToMesh0Weights.C
|
|
||||||
|
|
||||||
|
|
||||||
LIB = $(FOAM_LIBBIN)/libsampling
|
LIB = $(FOAM_LIBBIN)/libsampling
|
||||||
|
|||||||
@ -1,462 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2012-2022 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "meshToMesh.H"
|
|
||||||
#include "globalIndex.H"
|
|
||||||
#include "meshToMeshMethod.H"
|
|
||||||
#include "PatchTools.H"
|
|
||||||
#include "processorPolyPatch.H"
|
|
||||||
#include "Time.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
namespace Foam
|
|
||||||
{
|
|
||||||
defineTypeNameAndDebug(meshToMesh, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
||||||
|
|
||||||
Foam::scalar Foam::meshToMesh::calculate(const word& methodName)
|
|
||||||
{
|
|
||||||
Info<< "Creating mesh-to-mesh addressing for " << srcRegion_.name()
|
|
||||||
<< " and " << tgtRegion_.name() << " regions using "
|
|
||||||
<< methodName << endl;
|
|
||||||
|
|
||||||
singleMeshProc_ = calcDistribution(srcRegion_, tgtRegion_);
|
|
||||||
|
|
||||||
autoPtr<meshToMeshMethod> methodPtr;
|
|
||||||
|
|
||||||
scalar V = 0;
|
|
||||||
|
|
||||||
if (singleMeshProc_ == -1)
|
|
||||||
{
|
|
||||||
// create global indexing for src and tgt meshes
|
|
||||||
globalIndex globalSrcCells(srcRegion_.nCells());
|
|
||||||
globalIndex globalTgtCells(tgtRegion_.nCells());
|
|
||||||
|
|
||||||
// Create processor map of overlapping cells. This map gets
|
|
||||||
// (possibly remote) cells from the tgt mesh such that they (together)
|
|
||||||
// cover all of the src mesh
|
|
||||||
autoPtr<distributionMap> mapPtr = calcProcMap(srcRegion_, tgtRegion_);
|
|
||||||
const distributionMap& map = mapPtr();
|
|
||||||
|
|
||||||
// Distribute the target geometry to create local-target geometry
|
|
||||||
// (i.e., local to the source)
|
|
||||||
pointField localTgtPoints;
|
|
||||||
faceList localTgtFaces;
|
|
||||||
labelList localTgtFaceOwners;
|
|
||||||
labelList localTgtFaceNeighbours;
|
|
||||||
labelList localTgtGlobalCellIDs;
|
|
||||||
distributeAndMergeCells
|
|
||||||
(
|
|
||||||
map,
|
|
||||||
tgtRegion_,
|
|
||||||
globalTgtCells,
|
|
||||||
localTgtPoints,
|
|
||||||
localTgtFaces,
|
|
||||||
localTgtFaceOwners,
|
|
||||||
localTgtFaceNeighbours,
|
|
||||||
localTgtGlobalCellIDs
|
|
||||||
);
|
|
||||||
|
|
||||||
// create a new target mesh
|
|
||||||
polyMesh localTgtMesh
|
|
||||||
(
|
|
||||||
IOobject
|
|
||||||
(
|
|
||||||
"localTgt",
|
|
||||||
tgtRegion_.time().timeName(),
|
|
||||||
tgtRegion_.time(),
|
|
||||||
IOobject::NO_READ
|
|
||||||
),
|
|
||||||
move(localTgtPoints),
|
|
||||||
move(localTgtFaces),
|
|
||||||
move(localTgtFaceOwners),
|
|
||||||
move(localTgtFaceNeighbours),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
// create some dummy patch info and add to the new target mesh
|
|
||||||
List<polyPatch*> patches(1);
|
|
||||||
patches[0] = new polyPatch
|
|
||||||
(
|
|
||||||
"defaultFaces",
|
|
||||||
localTgtMesh.nFaces() - localTgtMesh.nInternalFaces(),
|
|
||||||
localTgtMesh.nInternalFaces(),
|
|
||||||
0,
|
|
||||||
localTgtMesh.boundaryMesh(),
|
|
||||||
word::null
|
|
||||||
);
|
|
||||||
localTgtMesh.addPatches(patches);
|
|
||||||
|
|
||||||
// force calculation of tet-base points used for point-in-cell
|
|
||||||
(void)localTgtMesh.tetBasePtIs();
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Pout<< "Created local target mesh:" << nl
|
|
||||||
<< " cells = " << tgtRegion_.nCells()
|
|
||||||
<< ", local cells = " << localTgtMesh.nCells() << nl
|
|
||||||
<< " faces = " << tgtRegion_.nFaces()
|
|
||||||
<< ", local faces = " << localTgtMesh.nFaces() << endl;
|
|
||||||
|
|
||||||
if (debug > 1)
|
|
||||||
{
|
|
||||||
Pout<< "Writing local target mesh: "
|
|
||||||
<< localTgtMesh.name() << endl;
|
|
||||||
localTgtMesh.write();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the intersection
|
|
||||||
methodPtr = meshToMeshMethod::New(methodName, srcRegion_, localTgtMesh);
|
|
||||||
V = methodPtr->calculate
|
|
||||||
(
|
|
||||||
srcToTgtCellAddr_,
|
|
||||||
srcToTgtCellWght_,
|
|
||||||
tgtToSrcCellAddr_,
|
|
||||||
tgtToSrcCellWght_
|
|
||||||
);
|
|
||||||
|
|
||||||
// per source cell the target cell address in localTgtMesh mesh
|
|
||||||
forAll(srcToTgtCellAddr_, i)
|
|
||||||
{
|
|
||||||
labelList& addressing = srcToTgtCellAddr_[i];
|
|
||||||
forAll(addressing, addrI)
|
|
||||||
{
|
|
||||||
addressing[addrI] = localTgtGlobalCellIDs[addressing[addrI]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert target addresses in localTgtMesh into global cell numbering
|
|
||||||
forAll(tgtToSrcCellAddr_, i)
|
|
||||||
{
|
|
||||||
labelList& addressing = tgtToSrcCellAddr_[i];
|
|
||||||
forAll(addressing, addrI)
|
|
||||||
{
|
|
||||||
addressing[addrI] = globalSrcCells.toGlobal(addressing[addrI]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// send the connectivity back to the target
|
|
||||||
distributionMapBase::distribute
|
|
||||||
(
|
|
||||||
Pstream::commsTypes::nonBlocking,
|
|
||||||
List<labelPair>(),
|
|
||||||
tgtRegion_.nCells(),
|
|
||||||
map.constructMap(),
|
|
||||||
false,
|
|
||||||
map.subMap(),
|
|
||||||
false,
|
|
||||||
tgtToSrcCellAddr_,
|
|
||||||
ListAppendEqOp<label>(),
|
|
||||||
flipOp(),
|
|
||||||
labelList()
|
|
||||||
);
|
|
||||||
distributionMapBase::distribute
|
|
||||||
(
|
|
||||||
Pstream::commsTypes::nonBlocking,
|
|
||||||
List<labelPair>(),
|
|
||||||
tgtRegion_.nCells(),
|
|
||||||
map.constructMap(),
|
|
||||||
false,
|
|
||||||
map.subMap(),
|
|
||||||
false,
|
|
||||||
tgtToSrcCellWght_,
|
|
||||||
ListAppendEqOp<scalar>(),
|
|
||||||
flipOp(),
|
|
||||||
scalarList()
|
|
||||||
);
|
|
||||||
|
|
||||||
// weights normalisation
|
|
||||||
methodPtr->normalise
|
|
||||||
(
|
|
||||||
srcRegion_,
|
|
||||||
srcToTgtCellAddr_,
|
|
||||||
srcToTgtCellWght_
|
|
||||||
);
|
|
||||||
methodPtr->normalise
|
|
||||||
(
|
|
||||||
tgtRegion_,
|
|
||||||
tgtToSrcCellAddr_,
|
|
||||||
tgtToSrcCellWght_
|
|
||||||
);
|
|
||||||
|
|
||||||
// cache maps and reset addresses
|
|
||||||
List<Map<label>> cMap;
|
|
||||||
srcMapPtr_.reset
|
|
||||||
(
|
|
||||||
new distributionMap(globalSrcCells, tgtToSrcCellAddr_, cMap)
|
|
||||||
);
|
|
||||||
tgtMapPtr_.reset
|
|
||||||
(
|
|
||||||
new distributionMap(globalTgtCells, srcToTgtCellAddr_, cMap)
|
|
||||||
);
|
|
||||||
|
|
||||||
// collect volume intersection contributions
|
|
||||||
reduce(V, sumOp<scalar>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Do the intersection
|
|
||||||
methodPtr = meshToMeshMethod::New(methodName, srcRegion_, tgtRegion_);
|
|
||||||
V = methodPtr->calculate
|
|
||||||
(
|
|
||||||
srcToTgtCellAddr_,
|
|
||||||
srcToTgtCellWght_,
|
|
||||||
tgtToSrcCellAddr_,
|
|
||||||
tgtToSrcCellWght_
|
|
||||||
);
|
|
||||||
|
|
||||||
// Normalise the weights
|
|
||||||
methodPtr->normalise
|
|
||||||
(
|
|
||||||
srcRegion_,
|
|
||||||
srcToTgtCellAddr_,
|
|
||||||
srcToTgtCellWght_
|
|
||||||
);
|
|
||||||
methodPtr->normalise
|
|
||||||
(
|
|
||||||
tgtRegion_,
|
|
||||||
tgtToSrcCellAddr_,
|
|
||||||
tgtToSrcCellWght_
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Info<< " Overlap volume: " << V << endl;
|
|
||||||
|
|
||||||
return V;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::meshToMesh::calculatePatchToPatches(const word& methodName)
|
|
||||||
{
|
|
||||||
if (!patchToPatches_.empty())
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "patchToPatches already calculated"
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
const word& patchToPatchType =
|
|
||||||
meshToMeshMethod::New
|
|
||||||
(
|
|
||||||
methodName,
|
|
||||||
NullObjectRef<polyMesh>(),
|
|
||||||
NullObjectRef<polyMesh>()
|
|
||||||
)->patchToPatchMethod();
|
|
||||||
|
|
||||||
patchToPatches_.setSize(srcPatchID_.size());
|
|
||||||
|
|
||||||
forAll(srcPatchID_, i)
|
|
||||||
{
|
|
||||||
const label srcPatchi = srcPatchID_[i];
|
|
||||||
const label tgtPatchi = tgtPatchID_[i];
|
|
||||||
|
|
||||||
const polyPatch& srcPP = srcRegion_.boundaryMesh()[srcPatchi];
|
|
||||||
const polyPatch& tgtPP = tgtRegion_.boundaryMesh()[tgtPatchi];
|
|
||||||
|
|
||||||
Info<< "Creating patchToPatch between source patch "
|
|
||||||
<< srcPP.name() << " and target patch " << tgtPP.name()
|
|
||||||
<< " using " << patchToPatchType << endl;
|
|
||||||
|
|
||||||
Info<< incrIndent;
|
|
||||||
|
|
||||||
patchToPatches_.set(i, patchToPatch::New(patchToPatchType, true));
|
|
||||||
|
|
||||||
patchToPatches_[i].update
|
|
||||||
(
|
|
||||||
srcPP,
|
|
||||||
PatchTools::pointNormals(srcRegion_, srcPP),
|
|
||||||
tgtPP
|
|
||||||
);
|
|
||||||
|
|
||||||
Info<< decrIndent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::meshToMesh::constructNoCuttingPatches
|
|
||||||
(
|
|
||||||
const word& methodName,
|
|
||||||
const bool interpAllPatches
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (interpAllPatches)
|
|
||||||
{
|
|
||||||
const polyBoundaryMesh& srcBM = srcRegion_.boundaryMesh();
|
|
||||||
const polyBoundaryMesh& tgtBM = tgtRegion_.boundaryMesh();
|
|
||||||
|
|
||||||
DynamicList<label> srcPatchID(srcBM.size());
|
|
||||||
DynamicList<label> tgtPatchID(tgtBM.size());
|
|
||||||
forAll(srcBM, patchi)
|
|
||||||
{
|
|
||||||
const polyPatch& pp = srcBM[patchi];
|
|
||||||
|
|
||||||
// We want to map all the global patches, including constraint
|
|
||||||
// patches (since they might have mappable properties, e.g.
|
|
||||||
// jumpCyclic). We'll fix the value afterwards.
|
|
||||||
if (!isA<processorPolyPatch>(pp))
|
|
||||||
{
|
|
||||||
srcPatchID.append(pp.index());
|
|
||||||
|
|
||||||
label tgtPatchi = tgtBM.findPatchID(pp.name());
|
|
||||||
|
|
||||||
if (tgtPatchi != -1)
|
|
||||||
{
|
|
||||||
tgtPatchID.append(tgtPatchi);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Source patch " << pp.name()
|
|
||||||
<< " not found in target mesh. "
|
|
||||||
<< "Available target patches are " << tgtBM.names()
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
srcPatchID_.transfer(srcPatchID);
|
|
||||||
tgtPatchID_.transfer(tgtPatchID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate volume addressing and weights
|
|
||||||
calculate(methodName);
|
|
||||||
|
|
||||||
// calculate patch addressing and weights
|
|
||||||
calculatePatchToPatches(methodName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::meshToMesh::constructFromCuttingPatches
|
|
||||||
(
|
|
||||||
const word& methodName,
|
|
||||||
const HashTable<word>& patchMap,
|
|
||||||
const wordList& cuttingPatches
|
|
||||||
)
|
|
||||||
{
|
|
||||||
srcPatchID_.setSize(patchMap.size());
|
|
||||||
tgtPatchID_.setSize(patchMap.size());
|
|
||||||
|
|
||||||
label i = 0;
|
|
||||||
forAllConstIter(HashTable<word>, patchMap, iter)
|
|
||||||
{
|
|
||||||
const word& tgtPatchName = iter.key();
|
|
||||||
const word& srcPatchName = iter();
|
|
||||||
|
|
||||||
const polyPatch& srcPatch = srcRegion_.boundaryMesh()[srcPatchName];
|
|
||||||
const polyPatch& tgtPatch = tgtRegion_.boundaryMesh()[tgtPatchName];
|
|
||||||
|
|
||||||
srcPatchID_[i] = srcPatch.index();
|
|
||||||
tgtPatchID_[i] = tgtPatch.index();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate volume addressing and weights
|
|
||||||
calculate(methodName);
|
|
||||||
|
|
||||||
// calculate patch addressing and weights
|
|
||||||
calculatePatchToPatches(methodName);
|
|
||||||
|
|
||||||
// set IDs of cutting patches on target mesh
|
|
||||||
cuttingPatches_.setSize(cuttingPatches.size());
|
|
||||||
forAll(cuttingPatches_, i)
|
|
||||||
{
|
|
||||||
const word& patchName = cuttingPatches[i];
|
|
||||||
cuttingPatches_[i] = tgtRegion_.boundaryMesh().findPatchID(patchName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
Foam::meshToMesh::meshToMesh
|
|
||||||
(
|
|
||||||
const polyMesh& src,
|
|
||||||
const polyMesh& tgt,
|
|
||||||
const word& methodName,
|
|
||||||
bool interpAllPatches
|
|
||||||
)
|
|
||||||
:
|
|
||||||
srcRegion_(src),
|
|
||||||
tgtRegion_(tgt),
|
|
||||||
srcPatchID_(),
|
|
||||||
tgtPatchID_(),
|
|
||||||
patchToPatches_(),
|
|
||||||
cuttingPatches_(),
|
|
||||||
srcToTgtCellAddr_(),
|
|
||||||
tgtToSrcCellAddr_(),
|
|
||||||
srcToTgtCellWght_(),
|
|
||||||
tgtToSrcCellWght_(),
|
|
||||||
singleMeshProc_(-1),
|
|
||||||
srcMapPtr_(nullptr),
|
|
||||||
tgtMapPtr_(nullptr)
|
|
||||||
{
|
|
||||||
constructNoCuttingPatches(methodName, interpAllPatches);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::meshToMesh::meshToMesh
|
|
||||||
(
|
|
||||||
const polyMesh& src,
|
|
||||||
const polyMesh& tgt,
|
|
||||||
const word& methodName,
|
|
||||||
const HashTable<word>& patchMap,
|
|
||||||
const wordList& cuttingPatches
|
|
||||||
)
|
|
||||||
:
|
|
||||||
srcRegion_(src),
|
|
||||||
tgtRegion_(tgt),
|
|
||||||
srcPatchID_(),
|
|
||||||
tgtPatchID_(),
|
|
||||||
patchToPatches_(),
|
|
||||||
cuttingPatches_(),
|
|
||||||
srcToTgtCellAddr_(),
|
|
||||||
tgtToSrcCellAddr_(),
|
|
||||||
srcToTgtCellWght_(),
|
|
||||||
tgtToSrcCellWght_(),
|
|
||||||
singleMeshProc_(-1),
|
|
||||||
srcMapPtr_(nullptr),
|
|
||||||
tgtMapPtr_(nullptr)
|
|
||||||
{
|
|
||||||
constructFromCuttingPatches
|
|
||||||
(
|
|
||||||
methodName,
|
|
||||||
patchMap,
|
|
||||||
cuttingPatches
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
Foam::meshToMesh::~meshToMesh()
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -1,833 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2012-2022 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "meshToMesh.H"
|
|
||||||
#include "OFstream.H"
|
|
||||||
#include "Time.H"
|
|
||||||
#include "globalIndex.H"
|
|
||||||
#include "processorPolyPatch.H"
|
|
||||||
#include "SubField.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
||||||
|
|
||||||
Foam::label Foam::meshToMesh::calcDistribution
|
|
||||||
(
|
|
||||||
const polyMesh& src,
|
|
||||||
const polyMesh& tgt
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
label proci = 0;
|
|
||||||
|
|
||||||
if (Pstream::parRun())
|
|
||||||
{
|
|
||||||
List<label> cellsPresentOnProc(Pstream::nProcs(), 0);
|
|
||||||
if ((src.nCells() > 0) || (tgt.nCells() > 0))
|
|
||||||
{
|
|
||||||
cellsPresentOnProc[Pstream::myProcNo()] = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cellsPresentOnProc[Pstream::myProcNo()] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pstream::gatherList(cellsPresentOnProc);
|
|
||||||
Pstream::scatterList(cellsPresentOnProc);
|
|
||||||
|
|
||||||
label nHaveCells = sum(cellsPresentOnProc);
|
|
||||||
|
|
||||||
if (nHaveCells > 1)
|
|
||||||
{
|
|
||||||
proci = -1;
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction
|
|
||||||
<< "Meshes split across multiple processors" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (nHaveCells == 1)
|
|
||||||
{
|
|
||||||
proci = findIndex(cellsPresentOnProc, 1);
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction
|
|
||||||
<< "Meshes local to processor" << proci << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return proci;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::label Foam::meshToMesh::calcOverlappingProcs
|
|
||||||
(
|
|
||||||
const List<boundBox>& procBb,
|
|
||||||
const boundBox& bb,
|
|
||||||
boolList& overlaps
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
overlaps = false;
|
|
||||||
|
|
||||||
label nOverlaps = 0;
|
|
||||||
|
|
||||||
forAll(procBb, proci)
|
|
||||||
{
|
|
||||||
const boundBox& bbp = procBb[proci];
|
|
||||||
|
|
||||||
if (bbp.overlaps(bb))
|
|
||||||
{
|
|
||||||
overlaps[proci] = true;
|
|
||||||
nOverlaps++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nOverlaps;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::autoPtr<Foam::distributionMap> Foam::meshToMesh::calcProcMap
|
|
||||||
(
|
|
||||||
const polyMesh& src,
|
|
||||||
const polyMesh& tgt
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
// get decomposition of cells on src mesh
|
|
||||||
List<boundBox> procBb(Pstream::nProcs());
|
|
||||||
|
|
||||||
if (src.nCells() > 0)
|
|
||||||
{
|
|
||||||
// bounding box for my mesh - do not parallel reduce
|
|
||||||
procBb[Pstream::myProcNo()] = boundBox(src.points(), false);
|
|
||||||
|
|
||||||
// slightly increase size of bounding boxes to allow for cases where
|
|
||||||
// bounding boxes are perfectly aligned
|
|
||||||
procBb[Pstream::myProcNo()].inflate(0.01);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
procBb[Pstream::myProcNo()] = boundBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Pstream::gatherList(procBb);
|
|
||||||
Pstream::scatterList(procBb);
|
|
||||||
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction
|
|
||||||
<< "Determining extent of src mesh per processor:" << nl
|
|
||||||
<< "\tproc\tbb" << endl;
|
|
||||||
forAll(procBb, proci)
|
|
||||||
{
|
|
||||||
Info<< '\t' << proci << '\t' << procBb[proci] << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// determine which cells of tgt mesh overlaps src mesh per proc
|
|
||||||
const cellList& cells = tgt.cells();
|
|
||||||
const faceList& faces = tgt.faces();
|
|
||||||
const pointField& points = tgt.points();
|
|
||||||
|
|
||||||
labelListList sendMap;
|
|
||||||
|
|
||||||
{
|
|
||||||
// per processor indices into all segments to send
|
|
||||||
List<DynamicList<label>> dynSendMap(Pstream::nProcs());
|
|
||||||
label iniSize = floor(tgt.nCells()/Pstream::nProcs());
|
|
||||||
|
|
||||||
forAll(dynSendMap, proci)
|
|
||||||
{
|
|
||||||
dynSendMap[proci].setCapacity(iniSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// work array - whether src processor bb overlaps the tgt cell bounds
|
|
||||||
boolList procBbOverlaps(Pstream::nProcs());
|
|
||||||
forAll(cells, celli)
|
|
||||||
{
|
|
||||||
const cell& c = cells[celli];
|
|
||||||
|
|
||||||
// determine bounding box of tgt cell
|
|
||||||
boundBox cellBb(point::max, point::min);
|
|
||||||
forAll(c, facei)
|
|
||||||
{
|
|
||||||
const face& f = faces[c[facei]];
|
|
||||||
forAll(f, fp)
|
|
||||||
{
|
|
||||||
cellBb.min() = min(cellBb.min(), points[f[fp]]);
|
|
||||||
cellBb.max() = max(cellBb.max(), points[f[fp]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the overlapping tgt cells on each src processor
|
|
||||||
(void)calcOverlappingProcs(procBb, cellBb, procBbOverlaps);
|
|
||||||
|
|
||||||
forAll(procBbOverlaps, proci)
|
|
||||||
{
|
|
||||||
if (procBbOverlaps[proci])
|
|
||||||
{
|
|
||||||
dynSendMap[proci].append(celli);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert dynamicList to labelList
|
|
||||||
sendMap.setSize(Pstream::nProcs());
|
|
||||||
forAll(sendMap, proci)
|
|
||||||
{
|
|
||||||
sendMap[proci].transfer(dynSendMap[proci]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Pout<< "Of my " << cells.size() << " target cells I need to send to:"
|
|
||||||
<< nl << "\tproc\tcells" << endl;
|
|
||||||
forAll(sendMap, proci)
|
|
||||||
{
|
|
||||||
Pout<< '\t' << proci << '\t' << sendMap[proci].size() << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// send over how many tgt cells I need to receive from each processor
|
|
||||||
labelListList sendSizes(Pstream::nProcs());
|
|
||||||
sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
|
|
||||||
forAll(sendMap, proci)
|
|
||||||
{
|
|
||||||
sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size();
|
|
||||||
}
|
|
||||||
Pstream::gatherList(sendSizes);
|
|
||||||
Pstream::scatterList(sendSizes);
|
|
||||||
|
|
||||||
|
|
||||||
// determine order of receiving
|
|
||||||
labelListList constructMap(Pstream::nProcs());
|
|
||||||
|
|
||||||
label segmentI = 0;
|
|
||||||
forAll(constructMap, proci)
|
|
||||||
{
|
|
||||||
// what I need to receive is what other processor is sending to me
|
|
||||||
label nRecv = sendSizes[proci][Pstream::myProcNo()];
|
|
||||||
constructMap[proci].setSize(nRecv);
|
|
||||||
|
|
||||||
for (label i = 0; i < nRecv; i++)
|
|
||||||
{
|
|
||||||
constructMap[proci][i] = segmentI++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
autoPtr<distributionMap> mapPtr
|
|
||||||
(
|
|
||||||
new distributionMap
|
|
||||||
(
|
|
||||||
segmentI, // size after construction
|
|
||||||
move(sendMap),
|
|
||||||
move(constructMap)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return mapPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::meshToMesh::distributeCells
|
|
||||||
(
|
|
||||||
const distributionMap& map,
|
|
||||||
const polyMesh& tgtMesh,
|
|
||||||
const globalIndex& globalTgtCells,
|
|
||||||
List<pointField>& points,
|
|
||||||
List<label>& nInternalFaces,
|
|
||||||
List<faceList>& faces,
|
|
||||||
List<labelList>& faceOwner,
|
|
||||||
List<labelList>& faceNeighbour,
|
|
||||||
List<labelList>& globalCellIDs,
|
|
||||||
List<labelList>& nbrProcIDs,
|
|
||||||
List<labelList>& procLocalFaceIDs
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
|
|
||||||
|
|
||||||
points.setSize(Pstream::nProcs());
|
|
||||||
nInternalFaces.setSize(Pstream::nProcs(), 0);
|
|
||||||
faces.setSize(Pstream::nProcs());
|
|
||||||
faceOwner.setSize(Pstream::nProcs());
|
|
||||||
faceNeighbour.setSize(Pstream::nProcs());
|
|
||||||
globalCellIDs.setSize(Pstream::nProcs());
|
|
||||||
|
|
||||||
nbrProcIDs.setSize(Pstream::nProcs());;
|
|
||||||
procLocalFaceIDs.setSize(Pstream::nProcs());;
|
|
||||||
|
|
||||||
|
|
||||||
for (label domain = 0; domain < Pstream::nProcs(); domain++)
|
|
||||||
{
|
|
||||||
const labelList& sendElems = map.subMap()[domain];
|
|
||||||
|
|
||||||
if (sendElems.size())
|
|
||||||
{
|
|
||||||
// reverse cell map
|
|
||||||
labelList reverseCellMap(tgtMesh.nCells(), -1);
|
|
||||||
forAll(sendElems, subCelli)
|
|
||||||
{
|
|
||||||
reverseCellMap[sendElems[subCelli]] = subCelli;
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicList<face> subFaces(tgtMesh.nFaces());
|
|
||||||
DynamicList<label> subFaceOwner(tgtMesh.nFaces());
|
|
||||||
DynamicList<label> subFaceNeighbour(tgtMesh.nFaces());
|
|
||||||
|
|
||||||
DynamicList<label> subNbrProcIDs(tgtMesh.nFaces());
|
|
||||||
DynamicList<label> subProcLocalFaceIDs(tgtMesh.nFaces());
|
|
||||||
|
|
||||||
label nInternal = 0;
|
|
||||||
|
|
||||||
// internal faces
|
|
||||||
forAll(tgtMesh.faceNeighbour(), facei)
|
|
||||||
{
|
|
||||||
label own = tgtMesh.faceOwner()[facei];
|
|
||||||
label nbr = tgtMesh.faceNeighbour()[facei];
|
|
||||||
label subOwn = reverseCellMap[own];
|
|
||||||
label subNbr = reverseCellMap[nbr];
|
|
||||||
|
|
||||||
if (subOwn != -1 && subNbr != -1)
|
|
||||||
{
|
|
||||||
nInternal++;
|
|
||||||
|
|
||||||
if (subOwn < subNbr)
|
|
||||||
{
|
|
||||||
subFaces.append(tgtMesh.faces()[facei]);
|
|
||||||
subFaceOwner.append(subOwn);
|
|
||||||
subFaceNeighbour.append(subNbr);
|
|
||||||
subNbrProcIDs.append(-1);
|
|
||||||
subProcLocalFaceIDs.append(-1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
subFaces.append(tgtMesh.faces()[facei].reverseFace());
|
|
||||||
subFaceOwner.append(subNbr);
|
|
||||||
subFaceNeighbour.append(subOwn);
|
|
||||||
subNbrProcIDs.append(-1);
|
|
||||||
subProcLocalFaceIDs.append(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// boundary faces for new region
|
|
||||||
forAll(tgtMesh.faceNeighbour(), facei)
|
|
||||||
{
|
|
||||||
label own = tgtMesh.faceOwner()[facei];
|
|
||||||
label nbr = tgtMesh.faceNeighbour()[facei];
|
|
||||||
label subOwn = reverseCellMap[own];
|
|
||||||
label subNbr = reverseCellMap[nbr];
|
|
||||||
|
|
||||||
if (subOwn != -1 && subNbr == -1)
|
|
||||||
{
|
|
||||||
subFaces.append(tgtMesh.faces()[facei]);
|
|
||||||
subFaceOwner.append(subOwn);
|
|
||||||
subFaceNeighbour.append(subNbr);
|
|
||||||
subNbrProcIDs.append(-1);
|
|
||||||
subProcLocalFaceIDs.append(-1);
|
|
||||||
}
|
|
||||||
else if (subOwn == -1 && subNbr != -1)
|
|
||||||
{
|
|
||||||
subFaces.append(tgtMesh.faces()[facei].reverseFace());
|
|
||||||
subFaceOwner.append(subNbr);
|
|
||||||
subFaceNeighbour.append(subOwn);
|
|
||||||
subNbrProcIDs.append(-1);
|
|
||||||
subProcLocalFaceIDs.append(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// boundary faces of existing region
|
|
||||||
forAll(tgtMesh.boundaryMesh(), patchi)
|
|
||||||
{
|
|
||||||
const polyPatch& pp = tgtMesh.boundaryMesh()[patchi];
|
|
||||||
|
|
||||||
label nbrProci = -1;
|
|
||||||
|
|
||||||
// store info for faces on processor patches
|
|
||||||
if (isA<processorPolyPatch>(pp))
|
|
||||||
{
|
|
||||||
const processorPolyPatch& ppp =
|
|
||||||
dynamic_cast<const processorPolyPatch&>(pp);
|
|
||||||
|
|
||||||
nbrProci = ppp.neighbProcNo();
|
|
||||||
}
|
|
||||||
|
|
||||||
forAll(pp, i)
|
|
||||||
{
|
|
||||||
label facei = pp.start() + i;
|
|
||||||
label own = tgtMesh.faceOwner()[facei];
|
|
||||||
|
|
||||||
if (reverseCellMap[own] != -1)
|
|
||||||
{
|
|
||||||
subFaces.append(tgtMesh.faces()[facei]);
|
|
||||||
subFaceOwner.append(reverseCellMap[own]);
|
|
||||||
subFaceNeighbour.append(-1);
|
|
||||||
subNbrProcIDs.append(nbrProci);
|
|
||||||
subProcLocalFaceIDs.append(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reverse point map
|
|
||||||
labelList reversePointMap(tgtMesh.nPoints(), -1);
|
|
||||||
DynamicList<point> subPoints(tgtMesh.nPoints());
|
|
||||||
forAll(subFaces, subFacei)
|
|
||||||
{
|
|
||||||
face& f = subFaces[subFacei];
|
|
||||||
forAll(f, fp)
|
|
||||||
{
|
|
||||||
label pointi = f[fp];
|
|
||||||
if (reversePointMap[pointi] == -1)
|
|
||||||
{
|
|
||||||
reversePointMap[pointi] = subPoints.size();
|
|
||||||
subPoints.append(tgtMesh.points()[pointi]);
|
|
||||||
}
|
|
||||||
|
|
||||||
f[fp] = reversePointMap[pointi];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tgt cells into global numbering
|
|
||||||
labelList globalElems(sendElems.size());
|
|
||||||
forAll(sendElems, i)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Pout<< "tgtProc:" << Pstream::myProcNo()
|
|
||||||
<< " sending tgt cell " << sendElems[i]
|
|
||||||
<< "[" << globalTgtCells.toGlobal(sendElems[i]) << "]"
|
|
||||||
<< " to srcProc " << domain << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalElems[i] = globalTgtCells.toGlobal(sendElems[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pass data
|
|
||||||
if (domain == Pstream::myProcNo())
|
|
||||||
{
|
|
||||||
// allocate my own data
|
|
||||||
points[Pstream::myProcNo()] = subPoints;
|
|
||||||
nInternalFaces[Pstream::myProcNo()] = nInternal;
|
|
||||||
faces[Pstream::myProcNo()] = subFaces;
|
|
||||||
faceOwner[Pstream::myProcNo()] = subFaceOwner;
|
|
||||||
faceNeighbour[Pstream::myProcNo()] = subFaceNeighbour;
|
|
||||||
globalCellIDs[Pstream::myProcNo()] = globalElems;
|
|
||||||
nbrProcIDs[Pstream::myProcNo()] = subNbrProcIDs;
|
|
||||||
procLocalFaceIDs[Pstream::myProcNo()] = subProcLocalFaceIDs;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// send data to other processor domains
|
|
||||||
UOPstream toDomain(domain, pBufs);
|
|
||||||
|
|
||||||
toDomain
|
|
||||||
<< subPoints
|
|
||||||
<< nInternal
|
|
||||||
<< subFaces
|
|
||||||
<< subFaceOwner
|
|
||||||
<< subFaceNeighbour
|
|
||||||
<< globalElems
|
|
||||||
<< subNbrProcIDs
|
|
||||||
<< subProcLocalFaceIDs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start receiving
|
|
||||||
pBufs.finishedSends();
|
|
||||||
|
|
||||||
// Consume
|
|
||||||
for (label domain = 0; domain < Pstream::nProcs(); domain++)
|
|
||||||
{
|
|
||||||
const labelList& recvElems = map.constructMap()[domain];
|
|
||||||
|
|
||||||
if (domain != Pstream::myProcNo() && recvElems.size())
|
|
||||||
{
|
|
||||||
UIPstream str(domain, pBufs);
|
|
||||||
|
|
||||||
str >> points[domain]
|
|
||||||
>> nInternalFaces[domain]
|
|
||||||
>> faces[domain]
|
|
||||||
>> faceOwner[domain]
|
|
||||||
>> faceNeighbour[domain]
|
|
||||||
>> globalCellIDs[domain]
|
|
||||||
>> nbrProcIDs[domain]
|
|
||||||
>> procLocalFaceIDs[domain];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Pout<< "Target mesh send sizes[" << domain << "]"
|
|
||||||
<< ": points="<< points[domain].size()
|
|
||||||
<< ", faces=" << faces[domain].size()
|
|
||||||
<< ", nInternalFaces=" << nInternalFaces[domain]
|
|
||||||
<< ", faceOwn=" << faceOwner[domain].size()
|
|
||||||
<< ", faceNbr=" << faceNeighbour[domain].size()
|
|
||||||
<< ", globalCellIDs=" << globalCellIDs[domain].size() << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::meshToMesh::distributeAndMergeCells
|
|
||||||
(
|
|
||||||
const distributionMap& map,
|
|
||||||
const polyMesh& tgt,
|
|
||||||
const globalIndex& globalTgtCells,
|
|
||||||
pointField& tgtPoints,
|
|
||||||
faceList& tgtFaces,
|
|
||||||
labelList& tgtFaceOwners,
|
|
||||||
labelList& tgtFaceNeighbours,
|
|
||||||
labelList& tgtGlobalCellIDs
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
// Exchange per-processor data
|
|
||||||
List<pointField> allPoints;
|
|
||||||
List<label> allNInternalFaces;
|
|
||||||
List<faceList> allFaces;
|
|
||||||
List<labelList> allFaceOwners;
|
|
||||||
List<labelList> allFaceNeighbours;
|
|
||||||
List<labelList> allGlobalCellIDs;
|
|
||||||
|
|
||||||
// Per target mesh face the neighbouring proc and index in
|
|
||||||
// processor patch (all -1 for normal boundary face)
|
|
||||||
List<labelList> allNbrProcIDs;
|
|
||||||
List<labelList> allProcLocalFaceIDs;
|
|
||||||
|
|
||||||
distributeCells
|
|
||||||
(
|
|
||||||
map,
|
|
||||||
tgt,
|
|
||||||
globalTgtCells,
|
|
||||||
allPoints,
|
|
||||||
allNInternalFaces,
|
|
||||||
allFaces,
|
|
||||||
allFaceOwners,
|
|
||||||
allFaceNeighbours,
|
|
||||||
allGlobalCellIDs,
|
|
||||||
allNbrProcIDs,
|
|
||||||
allProcLocalFaceIDs
|
|
||||||
);
|
|
||||||
|
|
||||||
// Convert lists into format that can be used to generate a valid polyMesh
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
//
|
|
||||||
// Points and cells are collected into single flat lists:
|
|
||||||
// - i.e. proc0, proc1 ... procN
|
|
||||||
//
|
|
||||||
// Faces need to be sorted after collection to that internal faces are
|
|
||||||
// contiguous, followed by all boundary faces
|
|
||||||
//
|
|
||||||
// Processor patch faces between included cells on neighbouring processors
|
|
||||||
// are converted into internal faces
|
|
||||||
//
|
|
||||||
// Face list structure:
|
|
||||||
// - Per processor:
|
|
||||||
// - internal faces
|
|
||||||
// - processor faces that have been converted into internal faces
|
|
||||||
// - Followed by all boundary faces
|
|
||||||
// - from 'normal' boundary faces
|
|
||||||
// - from singularly-sided processor patch faces
|
|
||||||
|
|
||||||
|
|
||||||
// Number of internal+coupled faces
|
|
||||||
labelList allNIntCoupledFaces(allNInternalFaces);
|
|
||||||
|
|
||||||
// Starting offset for points
|
|
||||||
label nPoints = 0;
|
|
||||||
labelList pointOffset(Pstream::nProcs(), 0);
|
|
||||||
forAll(allPoints, proci)
|
|
||||||
{
|
|
||||||
pointOffset[proci] = nPoints;
|
|
||||||
nPoints += allPoints[proci].size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starting offset for cells
|
|
||||||
label nCells = 0;
|
|
||||||
labelList cellOffset(Pstream::nProcs(), 0);
|
|
||||||
forAll(allGlobalCellIDs, proci)
|
|
||||||
{
|
|
||||||
cellOffset[proci] = nCells;
|
|
||||||
nCells += allGlobalCellIDs[proci].size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count any coupled faces
|
|
||||||
typedef FixedList<label, 3> label3;
|
|
||||||
typedef HashTable<label, label3, label3::Hash<>> procCoupleInfo;
|
|
||||||
procCoupleInfo procFaceToGlobalCell;
|
|
||||||
|
|
||||||
forAll(allNbrProcIDs, proci)
|
|
||||||
{
|
|
||||||
const labelList& nbrProci = allNbrProcIDs[proci];
|
|
||||||
const labelList& localFacei = allProcLocalFaceIDs[proci];
|
|
||||||
|
|
||||||
forAll(nbrProci, i)
|
|
||||||
{
|
|
||||||
if (nbrProci[i] != -1 && localFacei[i] != -1)
|
|
||||||
{
|
|
||||||
label3 key;
|
|
||||||
key[0] = min(proci, nbrProci[i]);
|
|
||||||
key[1] = max(proci, nbrProci[i]);
|
|
||||||
key[2] = localFacei[i];
|
|
||||||
|
|
||||||
procCoupleInfo::const_iterator fnd =
|
|
||||||
procFaceToGlobalCell.find(key);
|
|
||||||
|
|
||||||
if (fnd == procFaceToGlobalCell.end())
|
|
||||||
{
|
|
||||||
procFaceToGlobalCell.insert(key, -1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Pout<< "Additional internal face between procs:"
|
|
||||||
<< key[0] << " and " << key[1]
|
|
||||||
<< " across local face " << key[2] << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
allNIntCoupledFaces[proci]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Starting offset for internal faces
|
|
||||||
label nIntFaces = 0;
|
|
||||||
label nFacesTotal = 0;
|
|
||||||
labelList internalFaceOffset(Pstream::nProcs(), 0);
|
|
||||||
forAll(allNIntCoupledFaces, proci)
|
|
||||||
{
|
|
||||||
label nCoupledFaces =
|
|
||||||
allNIntCoupledFaces[proci] - allNInternalFaces[proci];
|
|
||||||
|
|
||||||
internalFaceOffset[proci] = nIntFaces;
|
|
||||||
nIntFaces += allNIntCoupledFaces[proci];
|
|
||||||
nFacesTotal += allFaceOwners[proci].size() - nCoupledFaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
tgtPoints.setSize(nPoints);
|
|
||||||
tgtFaces.setSize(nFacesTotal);
|
|
||||||
tgtFaceOwners.setSize(nFacesTotal);
|
|
||||||
tgtFaceNeighbours.setSize(nFacesTotal);
|
|
||||||
tgtGlobalCellIDs.setSize(nCells);
|
|
||||||
|
|
||||||
// Insert points
|
|
||||||
forAll(allPoints, proci)
|
|
||||||
{
|
|
||||||
const pointField& pts = allPoints[proci];
|
|
||||||
SubList<point>(tgtPoints, pts.size(), pointOffset[proci]) = pts;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert cellIDs
|
|
||||||
forAll(allGlobalCellIDs, proci)
|
|
||||||
{
|
|
||||||
const labelList& cellIDs = allGlobalCellIDs[proci];
|
|
||||||
SubList<label>(tgtGlobalCellIDs, cellIDs.size(), cellOffset[proci]) =
|
|
||||||
cellIDs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert internal faces (from internal faces)
|
|
||||||
forAll(allFaces, proci)
|
|
||||||
{
|
|
||||||
const faceList& fcs = allFaces[proci];
|
|
||||||
const labelList& faceOs = allFaceOwners[proci];
|
|
||||||
const labelList& faceNs = allFaceNeighbours[proci];
|
|
||||||
|
|
||||||
SubList<face> slice
|
|
||||||
(
|
|
||||||
tgtFaces,
|
|
||||||
allNInternalFaces[proci],
|
|
||||||
internalFaceOffset[proci]
|
|
||||||
);
|
|
||||||
slice = SubList<face>(fcs, allNInternalFaces[proci]);
|
|
||||||
forAll(slice, i)
|
|
||||||
{
|
|
||||||
add(slice[i], pointOffset[proci]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SubField<label> ownSlice
|
|
||||||
(
|
|
||||||
tgtFaceOwners,
|
|
||||||
allNInternalFaces[proci],
|
|
||||||
internalFaceOffset[proci]
|
|
||||||
);
|
|
||||||
ownSlice = SubField<label>(faceOs, allNInternalFaces[proci]);
|
|
||||||
add(ownSlice, cellOffset[proci]);
|
|
||||||
|
|
||||||
SubField<label> nbrSlice
|
|
||||||
(
|
|
||||||
tgtFaceNeighbours,
|
|
||||||
allNInternalFaces[proci],
|
|
||||||
internalFaceOffset[proci]
|
|
||||||
);
|
|
||||||
nbrSlice = SubField<label>(faceNs, allNInternalFaces[proci]);
|
|
||||||
add(nbrSlice, cellOffset[proci]);
|
|
||||||
|
|
||||||
internalFaceOffset[proci] += allNInternalFaces[proci];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert internal faces (from coupled face-pairs)
|
|
||||||
forAll(allNbrProcIDs, proci)
|
|
||||||
{
|
|
||||||
const labelList& nbrProci = allNbrProcIDs[proci];
|
|
||||||
const labelList& localFacei = allProcLocalFaceIDs[proci];
|
|
||||||
const labelList& faceOs = allFaceOwners[proci];
|
|
||||||
const faceList& fcs = allFaces[proci];
|
|
||||||
|
|
||||||
forAll(nbrProci, i)
|
|
||||||
{
|
|
||||||
if (nbrProci[i] != -1 && localFacei[i] != -1)
|
|
||||||
{
|
|
||||||
label3 key;
|
|
||||||
key[0] = min(proci, nbrProci[i]);
|
|
||||||
key[1] = max(proci, nbrProci[i]);
|
|
||||||
key[2] = localFacei[i];
|
|
||||||
|
|
||||||
procCoupleInfo::iterator fnd = procFaceToGlobalCell.find(key);
|
|
||||||
|
|
||||||
if (fnd != procFaceToGlobalCell.end())
|
|
||||||
{
|
|
||||||
label tgtFacei = fnd();
|
|
||||||
if (tgtFacei == -1)
|
|
||||||
{
|
|
||||||
// on first visit store the new cell on this side
|
|
||||||
fnd() = cellOffset[proci] + faceOs[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// get owner and neighbour in new cell numbering
|
|
||||||
label newOwn = cellOffset[proci] + faceOs[i];
|
|
||||||
label newNbr = fnd();
|
|
||||||
label tgtFacei = internalFaceOffset[proci]++;
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Pout<< " proc " << proci
|
|
||||||
<< "\tinserting face:" << tgtFacei
|
|
||||||
<< " connection between owner " << newOwn
|
|
||||||
<< " and neighbour " << newNbr
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newOwn < newNbr)
|
|
||||||
{
|
|
||||||
// we have correct orientation
|
|
||||||
tgtFaces[tgtFacei] = fcs[i];
|
|
||||||
tgtFaceOwners[tgtFacei] = newOwn;
|
|
||||||
tgtFaceNeighbours[tgtFacei] = newNbr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// reverse orientation
|
|
||||||
tgtFaces[tgtFacei] = fcs[i].reverseFace();
|
|
||||||
tgtFaceOwners[tgtFacei] = newNbr;
|
|
||||||
tgtFaceNeighbours[tgtFacei] = newOwn;
|
|
||||||
}
|
|
||||||
|
|
||||||
add(tgtFaces[tgtFacei], pointOffset[proci]);
|
|
||||||
|
|
||||||
// mark with unique value
|
|
||||||
fnd() = -2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
forAll(allNbrProcIDs, proci)
|
|
||||||
{
|
|
||||||
const labelList& nbrProci = allNbrProcIDs[proci];
|
|
||||||
const labelList& localFacei = allProcLocalFaceIDs[proci];
|
|
||||||
const labelList& faceOs = allFaceOwners[proci];
|
|
||||||
const labelList& faceNs = allFaceNeighbours[proci];
|
|
||||||
const faceList& fcs = allFaces[proci];
|
|
||||||
|
|
||||||
forAll(nbrProci, i)
|
|
||||||
{
|
|
||||||
// coupled boundary face
|
|
||||||
if (nbrProci[i] != -1 && localFacei[i] != -1)
|
|
||||||
{
|
|
||||||
label3 key;
|
|
||||||
key[0] = min(proci, nbrProci[i]);
|
|
||||||
key[1] = max(proci, nbrProci[i]);
|
|
||||||
key[2] = localFacei[i];
|
|
||||||
|
|
||||||
label tgtFacei = procFaceToGlobalCell[key];
|
|
||||||
|
|
||||||
if (tgtFacei == -1)
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Unvisited " << key
|
|
||||||
<< abort(FatalError);
|
|
||||||
}
|
|
||||||
else if (tgtFacei != -2)
|
|
||||||
{
|
|
||||||
label newOwn = cellOffset[proci] + faceOs[i];
|
|
||||||
label tgtFacei = nIntFaces++;
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Pout<< " proc " << proci
|
|
||||||
<< "\tinserting boundary face:" << tgtFacei
|
|
||||||
<< " from coupled face " << key
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
tgtFaces[tgtFacei] = fcs[i];
|
|
||||||
add(tgtFaces[tgtFacei], pointOffset[proci]);
|
|
||||||
|
|
||||||
tgtFaceOwners[tgtFacei] = newOwn;
|
|
||||||
tgtFaceNeighbours[tgtFacei] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// normal boundary face
|
|
||||||
else
|
|
||||||
{
|
|
||||||
label own = faceOs[i];
|
|
||||||
label nbr = faceNs[i];
|
|
||||||
if ((own != -1) && (nbr == -1))
|
|
||||||
{
|
|
||||||
label newOwn = cellOffset[proci] + faceOs[i];
|
|
||||||
label tgtFacei = nIntFaces++;
|
|
||||||
|
|
||||||
tgtFaces[tgtFacei] = fcs[i];
|
|
||||||
add(tgtFaces[tgtFacei], pointOffset[proci]);
|
|
||||||
|
|
||||||
tgtFaceOwners[tgtFacei] = newOwn;
|
|
||||||
tgtFaceNeighbours[tgtFacei] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -1,344 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2012-2022 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "meshToMesh.H"
|
|
||||||
#include "fvMesh.H"
|
|
||||||
#include "volFields.H"
|
|
||||||
#include "directFvPatchFieldMapper.H"
|
|
||||||
#include "calculatedFvPatchField.H"
|
|
||||||
#include "patchToPatchFvPatchFieldMapper.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
void Foam::meshToMesh::add
|
|
||||||
(
|
|
||||||
UList<Type>& fld,
|
|
||||||
const label offset
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
forAll(fld, i)
|
|
||||||
{
|
|
||||||
fld[i] += offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
void Foam::meshToMesh::mapSrcToTgt
|
|
||||||
(
|
|
||||||
const UList<Type>& srcField,
|
|
||||||
List<Type>& result
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
if (result.size() != tgtToSrcCellAddr_.size())
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Supplied field size is not equal to target mesh size" << nl
|
|
||||||
<< " source mesh = " << srcToTgtCellAddr_.size() << nl
|
|
||||||
<< " target mesh = " << tgtToSrcCellAddr_.size() << nl
|
|
||||||
<< " supplied field = " << result.size()
|
|
||||||
<< abort(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (singleMeshProc_ == -1)
|
|
||||||
{
|
|
||||||
const distributionMap& map = srcMapPtr_();
|
|
||||||
|
|
||||||
List<Type> work(srcField);
|
|
||||||
map.distribute(work);
|
|
||||||
|
|
||||||
forAll(result, celli)
|
|
||||||
{
|
|
||||||
const labelList& srcAddress = tgtToSrcCellAddr_[celli];
|
|
||||||
const scalarList& srcWeight = tgtToSrcCellWght_[celli];
|
|
||||||
|
|
||||||
if (srcAddress.size())
|
|
||||||
{
|
|
||||||
result[celli] *= (1.0 - sum(srcWeight));
|
|
||||||
forAll(srcAddress, i)
|
|
||||||
{
|
|
||||||
result[celli] += srcWeight[i]*work[srcAddress[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
forAll(result, celli)
|
|
||||||
{
|
|
||||||
const labelList& srcAddress = tgtToSrcCellAddr_[celli];
|
|
||||||
const scalarList& srcWeight = tgtToSrcCellWght_[celli];
|
|
||||||
|
|
||||||
if (srcAddress.size())
|
|
||||||
{
|
|
||||||
result[celli] *= (1.0 - sum(srcWeight));
|
|
||||||
forAll(srcAddress, i)
|
|
||||||
{
|
|
||||||
result[celli] += srcWeight[i]*srcField[srcAddress[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
Foam::tmp<Foam::Field<Type>> Foam::meshToMesh::mapSrcToTgt
|
|
||||||
(
|
|
||||||
const Field<Type>& srcField
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
tmp<Field<Type>> tresult
|
|
||||||
(
|
|
||||||
new Field<Type>
|
|
||||||
(
|
|
||||||
tgtToSrcCellAddr_.size(),
|
|
||||||
Zero
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
mapSrcToTgt(srcField, tresult.ref());
|
|
||||||
|
|
||||||
return tresult;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
void Foam::meshToMesh::mapTgtToSrc
|
|
||||||
(
|
|
||||||
const UList<Type>& tgtField,
|
|
||||||
List<Type>& result
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
if (result.size() != srcToTgtCellAddr_.size())
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Supplied field size is not equal to source mesh size" << nl
|
|
||||||
<< " source mesh = " << srcToTgtCellAddr_.size() << nl
|
|
||||||
<< " target mesh = " << tgtToSrcCellAddr_.size() << nl
|
|
||||||
<< " supplied field = " << result.size()
|
|
||||||
<< abort(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (singleMeshProc_ == -1)
|
|
||||||
{
|
|
||||||
const distributionMap& map = tgtMapPtr_();
|
|
||||||
|
|
||||||
List<Type> work(tgtField);
|
|
||||||
map.distribute(work);
|
|
||||||
|
|
||||||
forAll(result, celli)
|
|
||||||
{
|
|
||||||
const labelList& tgtAddress = srcToTgtCellAddr_[celli];
|
|
||||||
const scalarList& tgtWeight = srcToTgtCellWght_[celli];
|
|
||||||
|
|
||||||
if (tgtAddress.size())
|
|
||||||
{
|
|
||||||
result[celli] *= (1.0 - sum(tgtWeight));
|
|
||||||
forAll(tgtAddress, i)
|
|
||||||
{
|
|
||||||
result[celli] += tgtWeight[i]*work[tgtAddress[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
forAll(result, celli)
|
|
||||||
{
|
|
||||||
const labelList& tgtAddress = srcToTgtCellAddr_[celli];
|
|
||||||
const scalarList& tgtWeight = srcToTgtCellWght_[celli];
|
|
||||||
|
|
||||||
if (tgtAddress.size())
|
|
||||||
{
|
|
||||||
result[celli] *= (1.0 - sum(tgtWeight));
|
|
||||||
forAll(tgtAddress, i)
|
|
||||||
{
|
|
||||||
result[celli] += tgtWeight[i]*tgtField[tgtAddress[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
Foam::tmp<Foam::Field<Type>> Foam::meshToMesh::mapTgtToSrc
|
|
||||||
(
|
|
||||||
const Field<Type>& tgtField
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
tmp<Field<Type>> tresult
|
|
||||||
(
|
|
||||||
new Field<Type>
|
|
||||||
(
|
|
||||||
srcToTgtCellAddr_.size(),
|
|
||||||
Zero
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
mapTgtToSrc(tgtField, tresult.ref());
|
|
||||||
|
|
||||||
return tresult;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
void Foam::meshToMesh::mapSrcToTgt
|
|
||||||
(
|
|
||||||
const GeometricField<Type, fvPatchField, volMesh>& field,
|
|
||||||
GeometricField<Type, fvPatchField, volMesh>& result
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
mapSrcToTgt(field, result.primitiveFieldRef());
|
|
||||||
|
|
||||||
typename GeometricField<Type, fvPatchField, volMesh>::
|
|
||||||
Boundary& resultBf = result.boundaryFieldRef();
|
|
||||||
|
|
||||||
forAll(patchToPatches(), i)
|
|
||||||
{
|
|
||||||
label srcPatchi = srcPatchID_[i];
|
|
||||||
label tgtPatchi = tgtPatchID_[i];
|
|
||||||
|
|
||||||
const fvPatchField<Type>& srcField = field.boundaryField()[srcPatchi];
|
|
||||||
fvPatchField<Type>& tgtField = resultBf[tgtPatchi];
|
|
||||||
|
|
||||||
// Clone and map (since rmap does not do general mapping)
|
|
||||||
tmp<fvPatchField<Type>> tnewTgt
|
|
||||||
(
|
|
||||||
fvPatchField<Type>::New
|
|
||||||
(
|
|
||||||
srcField,
|
|
||||||
tgtField.patch(),
|
|
||||||
result(),
|
|
||||||
patchToPatchFvPatchFieldMapper(patchToPatches()[i], true)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Transfer all mapped quantities (value and e.g. gradient) onto
|
|
||||||
// tgtField. Value will get overwritten below.
|
|
||||||
tgtField.rmap(tnewTgt(), identity(tgtField.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
forAll(cuttingPatches_, i)
|
|
||||||
{
|
|
||||||
label patchi = cuttingPatches_[i];
|
|
||||||
fvPatchField<Type>& pf = resultBf[patchi];
|
|
||||||
pf == pf.patchInternalField();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>>
|
|
||||||
Foam::meshToMesh::mapSrcToTgt
|
|
||||||
(
|
|
||||||
const GeometricField<Type, fvPatchField, volMesh>& field
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
|
|
||||||
|
|
||||||
const fvMesh& tgtMesh = static_cast<const fvMesh&>(tgtRegion_);
|
|
||||||
|
|
||||||
const fvBoundaryMesh& tgtBm = tgtMesh.boundary();
|
|
||||||
const typename fieldType::Boundary& srcBfld =
|
|
||||||
field.boundaryField();
|
|
||||||
|
|
||||||
PtrList<fvPatchField<Type>> tgtPatchFields(tgtBm.size());
|
|
||||||
|
|
||||||
// construct tgt boundary patch types as copy of 'field' boundary types
|
|
||||||
// note: this will provide place holders for fields with additional
|
|
||||||
// entries, but these values will need to be reset
|
|
||||||
forAll(tgtPatchID_, i)
|
|
||||||
{
|
|
||||||
label srcPatchi = srcPatchID_[i];
|
|
||||||
label tgtPatchi = tgtPatchID_[i];
|
|
||||||
|
|
||||||
if (!tgtPatchFields.set(tgtPatchi))
|
|
||||||
{
|
|
||||||
tgtPatchFields.set
|
|
||||||
(
|
|
||||||
tgtPatchi,
|
|
||||||
fvPatchField<Type>::New
|
|
||||||
(
|
|
||||||
srcBfld[srcPatchi],
|
|
||||||
tgtMesh.boundary()[tgtPatchi],
|
|
||||||
DimensionedField<Type, volMesh>::null(),
|
|
||||||
directFvPatchFieldMapper
|
|
||||||
(
|
|
||||||
labelList(tgtMesh.boundary()[tgtPatchi].size(), -1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any unset tgtPatchFields become calculated
|
|
||||||
forAll(tgtPatchFields, tgtPatchi)
|
|
||||||
{
|
|
||||||
if (!tgtPatchFields.set(tgtPatchi))
|
|
||||||
{
|
|
||||||
// Note: use factory New method instead of direct generation of
|
|
||||||
// calculated so we keep constraints
|
|
||||||
tgtPatchFields.set
|
|
||||||
(
|
|
||||||
tgtPatchi,
|
|
||||||
fvPatchField<Type>::New
|
|
||||||
(
|
|
||||||
calculatedFvPatchField<Type>::typeName,
|
|
||||||
tgtMesh.boundary()[tgtPatchi],
|
|
||||||
DimensionedField<Type, volMesh>::null()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp<fieldType> tresult
|
|
||||||
(
|
|
||||||
new fieldType
|
|
||||||
(
|
|
||||||
IOobject
|
|
||||||
(
|
|
||||||
typedName("interpolate(" + field.name() + ")"),
|
|
||||||
tgtMesh.time().timeName(),
|
|
||||||
tgtMesh,
|
|
||||||
IOobject::NO_READ,
|
|
||||||
IOobject::NO_WRITE
|
|
||||||
),
|
|
||||||
tgtMesh,
|
|
||||||
field.dimensions(),
|
|
||||||
Field<Type>(tgtMesh.nCells(), Zero),
|
|
||||||
tgtPatchFields
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
mapSrcToTgt(field, tresult.ref());
|
|
||||||
|
|
||||||
return tresult;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -1,344 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "meshToMesh0.H"
|
|
||||||
#include "treeDataCell.H"
|
|
||||||
#include "treeDataFace.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
||||||
|
|
||||||
void Foam::meshToMesh0::calcAddressing()
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction
|
|
||||||
<< "Calculating mesh-to-mesh cell addressing" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set reference to cells
|
|
||||||
const cellList& fromCells = fromMesh_.cells();
|
|
||||||
const pointField& fromPoints = fromMesh_.points();
|
|
||||||
|
|
||||||
// In an attempt to preserve the efficiency of linear search and prevent
|
|
||||||
// failure, a RESCUE mechanism will be set up. Here, we shall mark all
|
|
||||||
// cells next to the solid boundaries. If such a cell is found as the
|
|
||||||
// closest, the relationship between the origin and cell will be examined.
|
|
||||||
// If the origin is outside the cell, a global n-squared search is
|
|
||||||
// triggered.
|
|
||||||
|
|
||||||
// SETTING UP RESCUE
|
|
||||||
|
|
||||||
// Visit all boundaries and mark the cell next to the boundary.
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction << "Setting up rescue" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<bool> boundaryCell(fromCells.size(), false);
|
|
||||||
|
|
||||||
// Set reference to boundary
|
|
||||||
const polyPatchList& patchesFrom = fromMesh_.boundaryMesh();
|
|
||||||
|
|
||||||
forAll(patchesFrom, patchi)
|
|
||||||
{
|
|
||||||
// Get reference to cells next to the boundary
|
|
||||||
const labelUList& bCells = patchesFrom[patchi].faceCells();
|
|
||||||
|
|
||||||
forAll(bCells, facei)
|
|
||||||
{
|
|
||||||
boundaryCell[bCells[facei]] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
treeBoundBox meshBb(fromPoints);
|
|
||||||
|
|
||||||
scalar typDim = meshBb.avgDim()/(2.0*cbrt(scalar(fromCells.size())));
|
|
||||||
|
|
||||||
treeBoundBox shiftedBb
|
|
||||||
(
|
|
||||||
meshBb.min(),
|
|
||||||
meshBb.max() + vector(typDim, typDim, typDim)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Info<< "\nMesh\n"
|
|
||||||
<< " bounding box : " << meshBb << nl
|
|
||||||
<< " bounding box (shifted) : " << shiftedBb << nl
|
|
||||||
<< " typical dimension :" << shiftedBb.typDim() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
indexedOctree<treeDataCell> oc
|
|
||||||
(
|
|
||||||
treeDataCell(false, fromMesh_, polyMesh::CELL_TETS),
|
|
||||||
shiftedBb, // overall bounding box
|
|
||||||
8, // maxLevel
|
|
||||||
10, // leafsize
|
|
||||||
6.0 // duplicity
|
|
||||||
);
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
oc.print(Pout, false, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
cellAddresses
|
|
||||||
(
|
|
||||||
cellAddressing_,
|
|
||||||
toMesh_.cellCentres(),
|
|
||||||
fromMesh_,
|
|
||||||
boundaryCell,
|
|
||||||
oc
|
|
||||||
);
|
|
||||||
|
|
||||||
forAll(toMesh_.boundaryMesh(), patchi)
|
|
||||||
{
|
|
||||||
const polyPatch& toPatch = toMesh_.boundaryMesh()[patchi];
|
|
||||||
|
|
||||||
if (cuttingPatches_.found(toPatch.name()))
|
|
||||||
{
|
|
||||||
boundaryAddressing_[patchi].setSize(toPatch.size());
|
|
||||||
|
|
||||||
cellAddresses
|
|
||||||
(
|
|
||||||
boundaryAddressing_[patchi],
|
|
||||||
toPatch.faceCentres(),
|
|
||||||
fromMesh_,
|
|
||||||
boundaryCell,
|
|
||||||
oc
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if
|
|
||||||
(
|
|
||||||
patchMap_.found(toPatch.name())
|
|
||||||
&& fromMeshPatches_.found(patchMap_.find(toPatch.name())())
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const polyPatch& fromPatch = fromMesh_.boundaryMesh()
|
|
||||||
[
|
|
||||||
fromMeshPatches_.find(patchMap_.find(toPatch.name())())()
|
|
||||||
];
|
|
||||||
|
|
||||||
if (fromPatch.empty())
|
|
||||||
{
|
|
||||||
WarningInFunction
|
|
||||||
<< "Source patch " << fromPatch.name()
|
|
||||||
<< " has no faces. Not performing mapping for it."
|
|
||||||
<< endl;
|
|
||||||
boundaryAddressing_[patchi].setSize(toPatch.size());
|
|
||||||
boundaryAddressing_[patchi] = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
treeBoundBox wallBb(fromPatch.localPoints());
|
|
||||||
scalar typDim =
|
|
||||||
wallBb.avgDim()/(2.0*sqrt(scalar(fromPatch.size())));
|
|
||||||
|
|
||||||
treeBoundBox shiftedBb
|
|
||||||
(
|
|
||||||
wallBb.min(),
|
|
||||||
wallBb.max() + vector(typDim, typDim, typDim)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Note: allow more levels than in meshSearch. Assume patch
|
|
||||||
// is not as big as all boundary faces
|
|
||||||
indexedOctree<treeDataFace> oc
|
|
||||||
(
|
|
||||||
treeDataFace(false, fromPatch),
|
|
||||||
shiftedBb, // overall search domain
|
|
||||||
12, // maxLevel
|
|
||||||
10, // leafsize
|
|
||||||
6.0 // duplicity
|
|
||||||
);
|
|
||||||
|
|
||||||
const vectorField::subField centresToBoundary =
|
|
||||||
toPatch.faceCentres();
|
|
||||||
|
|
||||||
boundaryAddressing_[patchi].setSize(toPatch.size());
|
|
||||||
|
|
||||||
const scalar distSqr = sqr(wallBb.mag());
|
|
||||||
|
|
||||||
forAll(toPatch, toi)
|
|
||||||
{
|
|
||||||
boundaryAddressing_[patchi][toi] = oc.findNearest
|
|
||||||
(
|
|
||||||
centresToBoundary[toi],
|
|
||||||
distSqr
|
|
||||||
).index();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction
|
|
||||||
<< "Finished calculating mesh-to-mesh cell addressing" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::meshToMesh0::cellAddresses
|
|
||||||
(
|
|
||||||
labelList& cellAddressing_,
|
|
||||||
const pointField& points,
|
|
||||||
const fvMesh& fromMesh,
|
|
||||||
const List<bool>& boundaryCell,
|
|
||||||
const indexedOctree<treeDataCell>& oc
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
// The implemented search method is a simple neighbour array search.
|
|
||||||
// It starts from a cell zero, searches its neighbours and finds one
|
|
||||||
// which is nearer to the target point than the current position.
|
|
||||||
// The location of the "current position" is reset to that cell and
|
|
||||||
// search through the neighbours continues. The search is finished
|
|
||||||
// when all the neighbours of the cell are farther from the target
|
|
||||||
// point than the current cell
|
|
||||||
|
|
||||||
// Set curCell label to zero (start)
|
|
||||||
label curCell = 0;
|
|
||||||
|
|
||||||
// Set reference to cell to cell addressing
|
|
||||||
const vectorField& centresFrom = fromMesh.cellCentres();
|
|
||||||
const labelListList& cc = fromMesh.cellCells();
|
|
||||||
|
|
||||||
forAll(points, toi)
|
|
||||||
{
|
|
||||||
// Pick up target position
|
|
||||||
const vector& p = points[toi];
|
|
||||||
|
|
||||||
// Set the sqr-distance
|
|
||||||
scalar distSqr = magSqr(p - centresFrom[curCell]);
|
|
||||||
|
|
||||||
bool closer;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
closer = false;
|
|
||||||
|
|
||||||
// Set the current list of neighbouring cells
|
|
||||||
const labelList& neighbours = cc[curCell];
|
|
||||||
|
|
||||||
forAll(neighbours, ni)
|
|
||||||
{
|
|
||||||
const scalar curDistSqr =
|
|
||||||
magSqr(p - centresFrom[neighbours[ni]]);
|
|
||||||
|
|
||||||
// Search through all the neighbours.
|
|
||||||
// If the cell is closer, reset current cell and distance
|
|
||||||
if (curDistSqr < (1 - small)*distSqr)
|
|
||||||
{
|
|
||||||
curCell = neighbours[ni];
|
|
||||||
distSqr = curDistSqr;
|
|
||||||
closer = true; // A closer neighbour has been found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (closer);
|
|
||||||
|
|
||||||
cellAddressing_[toi] = -1;
|
|
||||||
|
|
||||||
// Check point is actually in the nearest cell
|
|
||||||
if (fromMesh.pointInCell(p, curCell))
|
|
||||||
{
|
|
||||||
cellAddressing_[toi] = curCell;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If curCell is a boundary cell then the point maybe either outside
|
|
||||||
// the domain or in an other region of the doamin, either way use
|
|
||||||
// the octree search to find it.
|
|
||||||
if (boundaryCell[curCell])
|
|
||||||
{
|
|
||||||
cellAddressing_[toi] = oc.findInside(p);
|
|
||||||
if (cellAddressing_[toi] != -1)
|
|
||||||
{
|
|
||||||
curCell = cellAddressing_[toi];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If not on the boundary search the neighbours
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
// Set the current list of neighbouring cells
|
|
||||||
const labelList& neighbours = cc[curCell];
|
|
||||||
|
|
||||||
forAll(neighbours, ni)
|
|
||||||
{
|
|
||||||
// Search through all the neighbours.
|
|
||||||
// If point is in neighbour reset current cell
|
|
||||||
if (fromMesh.pointInCell(p, neighbours[ni]))
|
|
||||||
{
|
|
||||||
cellAddressing_[toi] = neighbours[ni];
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
// If still not found search the neighbour-neighbours
|
|
||||||
|
|
||||||
// Set the current list of neighbouring cells
|
|
||||||
const labelList& neighbours = cc[curCell];
|
|
||||||
|
|
||||||
forAll(neighbours, ni)
|
|
||||||
{
|
|
||||||
// Set the current list of neighbour-neighbouring cells
|
|
||||||
const labelList& nn = cc[neighbours[ni]];
|
|
||||||
|
|
||||||
forAll(nn, ni)
|
|
||||||
{
|
|
||||||
// Search through all the neighbours.
|
|
||||||
// If point is in neighbour reset current cell
|
|
||||||
if (fromMesh.pointInCell(p, nn[ni]))
|
|
||||||
{
|
|
||||||
cellAddressing_[toi] = nn[ni];
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
// Still not found so use the octree
|
|
||||||
cellAddressing_[toi] = oc.findInside(p);
|
|
||||||
|
|
||||||
if (cellAddressing_[toi] != -1)
|
|
||||||
{
|
|
||||||
curCell = cellAddressing_[toi];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -1,271 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "meshToMesh0.H"
|
|
||||||
#include "tetOverlapVolume.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
||||||
|
|
||||||
void Foam::meshToMesh0::calculateInverseDistanceWeights() const
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction
|
|
||||||
<< "Calculating inverse distance weighting factors" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inverseDistanceWeightsPtr_)
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "weighting factors already calculated"
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Initialise overlap volume to zero
|
|
||||||
V_ = 0.0;
|
|
||||||
|
|
||||||
inverseDistanceWeightsPtr_ = new scalarListList(toMesh_.nCells());
|
|
||||||
scalarListList& invDistCoeffs = *inverseDistanceWeightsPtr_;
|
|
||||||
|
|
||||||
// get reference to source mesh data
|
|
||||||
const labelListList& cc = fromMesh_.cellCells();
|
|
||||||
const vectorField& centreFrom = fromMesh_.C();
|
|
||||||
const vectorField& centreTo = toMesh_.C();
|
|
||||||
|
|
||||||
forAll(cellAddressing_, celli)
|
|
||||||
{
|
|
||||||
if (cellAddressing_[celli] != -1)
|
|
||||||
{
|
|
||||||
const vector& target = centreTo[celli];
|
|
||||||
scalar m = mag(target - centreFrom[cellAddressing_[celli]]);
|
|
||||||
|
|
||||||
const labelList& neighbours = cc[cellAddressing_[celli]];
|
|
||||||
|
|
||||||
// if the nearest cell is a boundary cell or there is a direct hit,
|
|
||||||
// pick up the value
|
|
||||||
label directCelli = -1;
|
|
||||||
if (m < directHitTol || neighbours.empty())
|
|
||||||
{
|
|
||||||
directCelli = celli;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
forAll(neighbours, ni)
|
|
||||||
{
|
|
||||||
scalar nm = mag(target - centreFrom[neighbours[ni]]);
|
|
||||||
if (nm < directHitTol)
|
|
||||||
{
|
|
||||||
directCelli = neighbours[ni];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (directCelli != -1)
|
|
||||||
{
|
|
||||||
// Direct hit
|
|
||||||
invDistCoeffs[directCelli].setSize(1);
|
|
||||||
invDistCoeffs[directCelli][0] = 1.0;
|
|
||||||
V_ += fromMesh_.V()[cellAddressing_[directCelli]];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
invDistCoeffs[celli].setSize(neighbours.size() + 1);
|
|
||||||
|
|
||||||
// The first coefficient corresponds to the centre cell.
|
|
||||||
// The rest is ordered in the same way as the cellCells list.
|
|
||||||
scalar invDist = 1.0/m;
|
|
||||||
invDistCoeffs[celli][0] = invDist;
|
|
||||||
scalar sumInvDist = invDist;
|
|
||||||
|
|
||||||
// now add the neighbours
|
|
||||||
forAll(neighbours, ni)
|
|
||||||
{
|
|
||||||
invDist = 1.0/mag(target - centreFrom[neighbours[ni]]);
|
|
||||||
invDistCoeffs[celli][ni + 1] = invDist;
|
|
||||||
sumInvDist += invDist;
|
|
||||||
}
|
|
||||||
|
|
||||||
// divide by the total inverse-distance
|
|
||||||
forAll(invDistCoeffs[celli], i)
|
|
||||||
{
|
|
||||||
invDistCoeffs[celli][i] /= sumInvDist;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
V_ +=
|
|
||||||
invDistCoeffs[celli][0]
|
|
||||||
*fromMesh_.V()[cellAddressing_[celli]];
|
|
||||||
for (label i = 1; i < invDistCoeffs[celli].size(); i++)
|
|
||||||
{
|
|
||||||
V_ +=
|
|
||||||
invDistCoeffs[celli][i]*fromMesh_.V()[neighbours[i-1]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::meshToMesh0::calculateInverseVolumeWeights() const
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction
|
|
||||||
<< "Calculating inverse volume weighting factors" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inverseVolumeWeightsPtr_)
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "weighting factors already calculated"
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Initialise overlap volume to zero
|
|
||||||
V_ = 0.0;
|
|
||||||
|
|
||||||
inverseVolumeWeightsPtr_ = new scalarListList(toMesh_.nCells());
|
|
||||||
scalarListList& invVolCoeffs = *inverseVolumeWeightsPtr_;
|
|
||||||
|
|
||||||
const labelListList& cellToCell = cellToCellAddressing();
|
|
||||||
|
|
||||||
tetOverlapVolume overlapEngine;
|
|
||||||
|
|
||||||
forAll(cellToCell, celli)
|
|
||||||
{
|
|
||||||
const labelList& overlapCells = cellToCell[celli];
|
|
||||||
|
|
||||||
if (overlapCells.size() > 0)
|
|
||||||
{
|
|
||||||
invVolCoeffs[celli].setSize(overlapCells.size());
|
|
||||||
|
|
||||||
forAll(overlapCells, j)
|
|
||||||
{
|
|
||||||
label cellFrom = overlapCells[j];
|
|
||||||
treeBoundBox bbFromMesh
|
|
||||||
(
|
|
||||||
pointField
|
|
||||||
(
|
|
||||||
fromMesh_.points(),
|
|
||||||
fromMesh_.cellPoints()[cellFrom]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
scalar v = overlapEngine.cellCellOverlapVolumeMinDecomp
|
|
||||||
(
|
|
||||||
toMesh_,
|
|
||||||
celli,
|
|
||||||
|
|
||||||
fromMesh_,
|
|
||||||
cellFrom,
|
|
||||||
bbFromMesh
|
|
||||||
);
|
|
||||||
invVolCoeffs[celli][j] = v/toMesh_.V()[celli];
|
|
||||||
|
|
||||||
V_ += v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::meshToMesh0::calculateCellToCellAddressing() const
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
InfoInFunction
|
|
||||||
<< "Calculating cell to cell addressing" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cellToCellAddressingPtr_)
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "addressing already calculated"
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Initialise overlap volume to zero
|
|
||||||
V_ = 0.0;
|
|
||||||
|
|
||||||
tetOverlapVolume overlapEngine;
|
|
||||||
|
|
||||||
cellToCellAddressingPtr_ = new labelListList(toMesh_.nCells());
|
|
||||||
labelListList& cellToCell = *cellToCellAddressingPtr_;
|
|
||||||
|
|
||||||
|
|
||||||
forAll(cellToCell, iTo)
|
|
||||||
{
|
|
||||||
const labelList overLapCells =
|
|
||||||
overlapEngine.overlappingCells(fromMesh_, toMesh_, iTo);
|
|
||||||
if (overLapCells.size() > 0)
|
|
||||||
{
|
|
||||||
cellToCell[iTo].setSize(overLapCells.size());
|
|
||||||
forAll(overLapCells, j)
|
|
||||||
{
|
|
||||||
cellToCell[iTo][j] = overLapCells[j];
|
|
||||||
V_ += fromMesh_.V()[overLapCells[j]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
const Foam::scalarListList& Foam::meshToMesh0::inverseDistanceWeights() const
|
|
||||||
{
|
|
||||||
if (!inverseDistanceWeightsPtr_)
|
|
||||||
{
|
|
||||||
calculateInverseDistanceWeights();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *inverseDistanceWeightsPtr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Foam::scalarListList& Foam::meshToMesh0::inverseVolumeWeights() const
|
|
||||||
{
|
|
||||||
if (!inverseVolumeWeightsPtr_)
|
|
||||||
{
|
|
||||||
calculateInverseVolumeWeights();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *inverseVolumeWeightsPtr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Foam::labelListList& Foam::meshToMesh0::cellToCellAddressing() const
|
|
||||||
{
|
|
||||||
if (!cellToCellAddressingPtr_)
|
|
||||||
{
|
|
||||||
calculateCellToCellAddressing();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *cellToCellAddressingPtr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -1,202 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
|
||||||
\\/ 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "meshToMesh0.H"
|
|
||||||
#include "processorFvPatch.H"
|
|
||||||
#include "demandDrivenData.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
namespace Foam
|
|
||||||
{
|
|
||||||
defineTypeNameAndDebug(meshToMesh0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Foam::scalar Foam::meshToMesh0::directHitTol = 1e-5;
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
Foam::meshToMesh0::meshToMesh0
|
|
||||||
(
|
|
||||||
const fvMesh& meshFrom,
|
|
||||||
const fvMesh& meshTo,
|
|
||||||
const HashTable<word>& patchMap,
|
|
||||||
const wordList& cuttingPatchNames
|
|
||||||
)
|
|
||||||
:
|
|
||||||
fromMesh_(meshFrom),
|
|
||||||
toMesh_(meshTo),
|
|
||||||
patchMap_(patchMap),
|
|
||||||
cellAddressing_(toMesh_.nCells()),
|
|
||||||
boundaryAddressing_(toMesh_.boundaryMesh().size()),
|
|
||||||
inverseDistanceWeightsPtr_(nullptr),
|
|
||||||
inverseVolumeWeightsPtr_(nullptr),
|
|
||||||
cellToCellAddressingPtr_(nullptr),
|
|
||||||
V_(0.0)
|
|
||||||
{
|
|
||||||
forAll(fromMesh_.boundaryMesh(), patchi)
|
|
||||||
{
|
|
||||||
fromMeshPatches_.insert
|
|
||||||
(
|
|
||||||
fromMesh_.boundaryMesh()[patchi].name(),
|
|
||||||
patchi
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
forAll(toMesh_.boundaryMesh(), patchi)
|
|
||||||
{
|
|
||||||
toMeshPatches_.insert
|
|
||||||
(
|
|
||||||
toMesh_.boundaryMesh()[patchi].name(),
|
|
||||||
patchi
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
forAll(cuttingPatchNames, i)
|
|
||||||
{
|
|
||||||
if (toMeshPatches_.found(cuttingPatchNames[i]))
|
|
||||||
{
|
|
||||||
cuttingPatches_.insert
|
|
||||||
(
|
|
||||||
cuttingPatchNames[i],
|
|
||||||
toMeshPatches_.find(cuttingPatchNames[i])()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WarningInFunction
|
|
||||||
<< "Cannot find cutting-patch " << cuttingPatchNames[i]
|
|
||||||
<< " in destination mesh" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
forAll(toMesh_.boundaryMesh(), patchi)
|
|
||||||
{
|
|
||||||
// Add the processor patches in the toMesh to the cuttingPatches list
|
|
||||||
if (isA<processorPolyPatch>(toMesh_.boundaryMesh()[patchi]))
|
|
||||||
{
|
|
||||||
cuttingPatches_.insert
|
|
||||||
(
|
|
||||||
toMesh_.boundaryMesh()[patchi].name(),
|
|
||||||
patchi
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
calcAddressing();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::meshToMesh0::meshToMesh0
|
|
||||||
(
|
|
||||||
const fvMesh& meshFrom,
|
|
||||||
const fvMesh& meshTo
|
|
||||||
)
|
|
||||||
:
|
|
||||||
fromMesh_(meshFrom),
|
|
||||||
toMesh_(meshTo),
|
|
||||||
cellAddressing_(toMesh_.nCells()),
|
|
||||||
boundaryAddressing_(toMesh_.boundaryMesh().size()),
|
|
||||||
inverseDistanceWeightsPtr_(nullptr),
|
|
||||||
inverseVolumeWeightsPtr_(nullptr),
|
|
||||||
cellToCellAddressingPtr_(nullptr),
|
|
||||||
V_(0.0)
|
|
||||||
{
|
|
||||||
// check whether both meshes have got the same number
|
|
||||||
// of boundary patches
|
|
||||||
if (fromMesh_.boundary().size() != toMesh_.boundary().size())
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Incompatible meshes: different number of patches, "
|
|
||||||
<< "fromMesh = " << fromMesh_.boundary().size()
|
|
||||||
<< ", toMesh = " << toMesh_.boundary().size()
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
forAll(fromMesh_.boundaryMesh(), patchi)
|
|
||||||
{
|
|
||||||
if
|
|
||||||
(
|
|
||||||
fromMesh_.boundaryMesh()[patchi].name()
|
|
||||||
!= toMesh_.boundaryMesh()[patchi].name()
|
|
||||||
)
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Incompatible meshes: different patch names for patch "
|
|
||||||
<< patchi
|
|
||||||
<< ", fromMesh = " << fromMesh_.boundary()[patchi].name()
|
|
||||||
<< ", toMesh = " << toMesh_.boundary()[patchi].name()
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if
|
|
||||||
(
|
|
||||||
fromMesh_.boundaryMesh()[patchi].type()
|
|
||||||
!= toMesh_.boundaryMesh()[patchi].type()
|
|
||||||
)
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Incompatible meshes: different patch types for patch "
|
|
||||||
<< patchi
|
|
||||||
<< ", fromMesh = " << fromMesh_.boundary()[patchi].type()
|
|
||||||
<< ", toMesh = " << toMesh_.boundary()[patchi].type()
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
fromMeshPatches_.insert
|
|
||||||
(
|
|
||||||
fromMesh_.boundaryMesh()[patchi].name(),
|
|
||||||
patchi
|
|
||||||
);
|
|
||||||
|
|
||||||
toMeshPatches_.insert
|
|
||||||
(
|
|
||||||
toMesh_.boundaryMesh()[patchi].name(),
|
|
||||||
patchi
|
|
||||||
);
|
|
||||||
|
|
||||||
patchMap_.insert
|
|
||||||
(
|
|
||||||
toMesh_.boundaryMesh()[patchi].name(),
|
|
||||||
fromMesh_.boundaryMesh()[patchi].name()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
calcAddressing();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
Foam::meshToMesh0::~meshToMesh0()
|
|
||||||
{
|
|
||||||
deleteDemandDrivenData(inverseDistanceWeightsPtr_);
|
|
||||||
deleteDemandDrivenData(inverseVolumeWeightsPtr_);
|
|
||||||
deleteDemandDrivenData(cellToCellAddressingPtr_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -4,11 +4,14 @@ cd ${0%/*} || exit 1 # Run from this directory
|
|||||||
# Source tutorial run functions
|
# Source tutorial run functions
|
||||||
. $WM_PROJECT_DIR/bin/tools/CleanFunctions
|
. $WM_PROJECT_DIR/bin/tools/CleanFunctions
|
||||||
|
|
||||||
cd hopperInitialState
|
(
|
||||||
cleanCase
|
cd hopperInitialState || exit 1
|
||||||
|
cleanCase
|
||||||
|
)
|
||||||
|
|
||||||
cd ../hopperEmptying
|
(
|
||||||
cleanCase
|
cd hopperEmptying || exit 1
|
||||||
rm -rf 0
|
cleanCase
|
||||||
|
)
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -4,20 +4,21 @@ cd ${0%/*} || exit 1 # Run from this directory
|
|||||||
# Source tutorial run functions
|
# Source tutorial run functions
|
||||||
. $WM_PROJECT_DIR/bin/tools/RunFunctions
|
. $WM_PROJECT_DIR/bin/tools/RunFunctions
|
||||||
|
|
||||||
cd hopperInitialState
|
(
|
||||||
runApplication blockMesh
|
cd hopperInitialState || exit 1
|
||||||
runApplication decomposePar
|
runApplication blockMesh
|
||||||
runParallel $(getApplication)
|
runApplication decomposePar
|
||||||
runApplication reconstructPar -latestTime
|
runParallel $(getApplication)
|
||||||
cd ..
|
runApplication reconstructPar
|
||||||
|
)
|
||||||
|
|
||||||
cd hopperEmptying
|
(
|
||||||
rm -rf 0
|
cd hopperEmptying || exit 1
|
||||||
cp -R 0.orig 0
|
runApplication blockMesh
|
||||||
runApplication blockMesh
|
runApplication decomposePar
|
||||||
runApplication mapFields ../hopperInitialState -sourceTime latestTime
|
runParallel mapFieldsPar ../hopperInitialState -sourceTime latestTime
|
||||||
runApplication decomposePar
|
runParallel $(getApplication)
|
||||||
runParallel $(getApplication)
|
runApplication reconstructPar
|
||||||
runApplication reconstructPar
|
)
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user