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:
Will Bainbridge
2022-10-11 08:09:25 +01:00
parent 9e9ab2204c
commit 03b0619ee1
70 changed files with 4079 additions and 4013 deletions

View File

@ -1,5 +1,6 @@
mapLagrangian.C
mapMeshes.C
mapFields.C
meshToMesh0.C
EXE = $(FOAM_APPBIN)/mapFields

View File

@ -2,12 +2,10 @@ EXE_INC = \
-I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/lagrangian/basic/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/sampling/lnInclude
-I$(LIB_SRC)/finiteVolume/lnInclude
EXE_LIBS = \
-ldecompositionMethods \
-lsampling \
-lmeshTools \
-llagrangian \
-lfiniteVolume \

View 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_;
}
// ************************************************************************* //

View File

@ -1,5 +1,5 @@
mapMeshes.C
mapLagrangian.C
mapGeometricFields.C
mapClouds.C
mapFieldsPar.C
EXE = $(FOAM_APPBIN)/mapFieldsPar

View File

@ -1,11 +1,9 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/lagrangian/basic/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/sampling/lnInclude
-I$(LIB_SRC)/finiteVolume/lnInclude
EXE_LIBS = \
-lsampling \
-lmeshTools \
-llagrangian \
-lfiniteVolume \

View File

@ -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
// ************************************************************************* //

View 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
}
}
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -21,34 +21,30 @@ License
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
Maps Lagrangian clouds
SourceFiles
mapClouds.C
\*---------------------------------------------------------------------------*/
#ifndef UnMapped_H
#define UnMapped_H
#include "IOobjectList.H"
#include "OSspecific.H"
#ifndef mapClouds_H
#define mapClouds_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
template<class Type>
void UnMapped(const IOobjectList& objects)
{
IOobjectList fields = objects.lookupClass(Type::typeName);
class fvMeshToFvMesh;
void mapClouds(const fvMeshToFvMesh& interp);
forAllConstIter(IOobjectList, fields, fieldIter)
{
mvBak(fieldIter()->objectPath(false), "unmapped");
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -31,11 +31,84 @@ Description
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "mapMeshes.H"
#include "fvMeshToFvMesh.H"
#include "mapGeometricFields.H"
#include "mapClouds.H"
#include "cellVolumeWeightMethod.H"
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[])
@ -162,7 +235,7 @@ int main(int argc, char *argv[])
Info<< "\nCreate meshes\n" << endl;
fvMesh meshSource
fvMesh srcMesh
(
IOobject
(
@ -173,7 +246,7 @@ int main(int argc, char *argv[])
false
);
fvMesh meshTarget
fvMesh tgtMesh
(
IOobject
(
@ -184,15 +257,18 @@ int main(int argc, char *argv[])
false
);
Info<< "Source mesh size: " << meshSource.nCells() << tab
<< "Target mesh size: " << meshTarget.nCells() << nl << endl;
Info<< "Source mesh size: "
<< returnReduce(srcMesh.nCells(), sumOp<label>())
<< ", Target mesh size: "
<< returnReduce(tgtMesh.nCells(), sumOp<label>())
<< endl;
if (consistent)
{
mapConsistentMesh
(
meshSource,
meshTarget,
srcMesh,
tgtMesh,
mapMethod,
selectedFields,
noLagrangian
@ -202,8 +278,8 @@ int main(int argc, char *argv[])
{
mapSubMesh
(
meshSource,
meshTarget,
srcMesh,
tgtMesh,
patchMap,
cuttingPatches,
mapMethod,

View File

@ -23,12 +23,12 @@ License
\*---------------------------------------------------------------------------*/
#ifndef MapVolFields_H
#define MapVolFields_H
#include "GeometricField.H"
#include "meshToMesh.H"
#include "mapGeometricFields.H"
#include "fvMeshToFvMesh.H"
#include "surfaceMesh.H"
#include "pointMesh.H"
#include "IOobjectList.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -118,19 +118,17 @@ void evaluateConstraintTypes(GeometricField<Type, fvPatchField, volMesh>& fld)
template<class Type>
void MapVolFields
void mapVolTypeFields
(
const IOobjectList& objects,
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());
const fvMesh& meshTarget = static_cast<const fvMesh&>(interp.tgtRegion());
IOobjectList fields = objects.lookupClass(fieldType::typeName);
IOobjectList fields = objects.lookupClass(VolField<Type>::typeName);
forAllIter(IOobjectList, fields, fieldIter)
{
@ -138,13 +136,13 @@ void MapVolFields
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,
meshTarget.time().timeName(),
meshTarget,
tgtMesh.time().timeName(),
tgtMesh,
IOobject::MUST_READ
);
@ -152,7 +150,7 @@ void MapVolFields
{
Info<< " interpolating onto existing field "
<< fieldName << endl;
fieldType fieldTarget(targetIO, meshTarget);
VolField<Type> fieldTarget(targetIO, tgtMesh);
interp.mapSrcToTgt(fieldSource, fieldTarget);
@ -167,9 +165,12 @@ void MapVolFields
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);
@ -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
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#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
}
}
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -25,27 +25,31 @@ InNamespace
Foam
Description
Maps lagrangian positions and fields
Maps geometric fields
SourceFiles
mapLagrangian.C
mapGeometricFields.C
\*---------------------------------------------------------------------------*/
#ifndef mapLagrangian_H
#define mapLagrangian_H
#ifndef mapGeometricFields_H
#define mapGeometricFields_H
#include "meshToMesh.H"
#include "fvMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
//- Maps lagrangian positions and fields
void mapLagrangian(const meshToMesh& interp);
class fvMeshToFvMesh;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void mapGeometricFields
(
const fvMeshToFvMesh& interp,
const HashSet<word>& selectedFields,
const bool noLagrangian
);
} // End namespace Foam

View File

@ -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
// ************************************************************************* //

View File

@ -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
);
}
// ************************************************************************* //

View File

@ -27,9 +27,14 @@ License
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::polyMeshMap::polyMeshMap(const polyMesh& mesh)
Foam::polyMeshMap::polyMeshMap
(
const polyMesh& mesh,
const meshToMesh& mapper
)
:
mesh_(mesh)
mesh_(mesh),
mapper_(mapper)
{}

View File

@ -42,7 +42,7 @@ SourceFiles
namespace Foam
{
class polyMesh;
class meshToMesh;
/*---------------------------------------------------------------------------*\
Class polyMeshMap Declaration
@ -55,13 +55,16 @@ class polyMeshMap
//- Reference to polyMesh
const polyMesh& mesh_;
//- Reference to the meshToMesh mapper
const meshToMesh& mapper_;
public:
// Constructors
//- Construct for mesh
polyMeshMap(const polyMesh& mesh);
polyMeshMap(const polyMesh& mesh, const meshToMesh& mapper);
//- Disallow default bitwise copy construction
polyMeshMap(const polyMeshMap&) = delete;
@ -74,6 +77,12 @@ public:
{
return mesh_;
}
//- Return meshToMesh mapper
const meshToMesh& mapper() const
{
return mapper_;
}
};

View File

@ -512,4 +512,7 @@ $(faceSources)/patchFluxToFace/patchFluxToFace.C
solver/solver.C
solver/solverNew.C
fvMeshToFvMesh/fvMeshToFvMesh.C
fvMeshToFvMesh/patchToPatchFvPatchFieldMapper.C
LIB = $(FOAM_LIBBIN)/libfiniteVolume

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -23,54 +23,20 @@ License
\*---------------------------------------------------------------------------*/
#ifndef mapMeshes_H
#define mapMeshes_H
#include "fvMeshToFvMesh.H"
#include "meshToMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void mapMesh
(
const meshToMesh& interp,
const HashSet<word>& selectedFields,
const bool noLagrangian
);
defineTypeNameAndDebug(fvMeshToFvMesh, 0);
}
void mapConsistentMesh
(
const fvMesh& meshSource,
const fvMesh& meshTarget,
const word& mapMethod,
const HashSet<word>& selectedFields,
const bool noLagrangian
);
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
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
// ************************************************************************* //

View 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
// ************************************************************************* //

View 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;
}
// ************************************************************************* //

View File

@ -1,13 +1,11 @@
EXE_INC = \
-I$(LIB_SRC)/triSurface/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/sampling/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude
LIB_LIBS = \
-ltriSurface \
-lmeshTools \
-lsampling \
-ldynamicMesh \
-lfiniteVolume

View File

@ -35,7 +35,7 @@ Description
#define MeshToMeshMapGeometricFields_H
#include "polyMesh.H"
#include "meshToMesh.H"
#include "fvMeshToFvMesh.H"
#include "fvPatchFieldMapper.H"
#include "pointPatchFieldMapper.H"
#include "setSizeFieldMapper.H"
@ -131,12 +131,13 @@ void evaluateConstraintTypes(GeometricField<Type, fvPatchField, volMesh>& fld)
template<class Type>
void MeshToMeshMapVolFields
(
const meshToMesh& mapper
const fvMesh& mesh,
const fvMeshToFvMesh& mapper
)
{
HashTable<const GeometricField<Type, fvPatchField, volMesh>*> fields
(
mapper.srcRegion().objectRegistry::template
mesh.objectRegistry::template
lookupClass<GeometricField<Type, fvPatchField, volMesh>>()
);
@ -158,7 +159,7 @@ void MeshToMeshMapVolFields
fields =
(
mapper.srcRegion().objectRegistry::template
mesh.objectRegistry::template
lookupClass<GeometricField<Type, fvPatchField, volMesh>>()
);
@ -174,7 +175,7 @@ void MeshToMeshMapVolFields
const_cast<GeometricField<Type, fvPatchField, volMesh>&>
(*fieldIter());
if (meshToMesh::debug)
if (fvMeshToFvMesh::debug)
{
Info<< "Mapping " << field.typeName << ' ' << field.name()
<< endl;
@ -196,7 +197,8 @@ template
>
void NaNGeometricFields
(
const meshToMesh& mapper
const fvMesh& mesh,
const fvMeshToFvMesh& mapper
)
{
typedef GeometricField<Type, PatchField, GeoMesh> Gfield;
@ -220,7 +222,7 @@ void NaNGeometricFields
HashTable<const Gfield*> fields
(
mapper.srcRegion().objectRegistry::template lookupClass<Gfield>()
mesh.objectRegistry::template lookupClass<Gfield>()
);
// Deleted old time fields
@ -236,8 +238,7 @@ void NaNGeometricFields
field.clearOldTimes();
}
fields =
mapper.srcRegion().objectRegistry::template lookupClass<Gfield>();
fields = mesh.objectRegistry::template lookupClass<Gfield>();
Type NaN;
@ -255,7 +256,7 @@ void NaNGeometricFields
{
Gfield& field = const_cast<Gfield&>(*fieldIter());
if (meshToMesh::debug)
if (fvMeshToFvMesh::debug)
{
Info<< "Setting to NaN " << field.typeName << ' ' << field.name()
<< endl;

View File

@ -29,7 +29,7 @@ License
#include "surfaceInterpolate.H"
#include "pointFields.H"
#include "meshToMeshAdjustTimeStepFunctionObject.H"
#include "meshToMesh.H"
#include "fvMeshToFvMesh.H"
#include "cellVolumeWeightMethod.H"
#include "surfaceToVolVelocity.H"
#include "MeshToMeshMapGeometricFields.H"
@ -154,7 +154,7 @@ bool Foam::fvMeshTopoChangers::meshToMesh::update()
fvMesh::stitchType::none
);
autoPtr<Foam::meshToMesh> mapper;
autoPtr<Foam::fvMeshToFvMesh> mapper;
// Create mesh-to-mesh mapper with support for cuttingPatches
// if specified
@ -182,7 +182,7 @@ bool Foam::fvMeshTopoChangers::meshToMesh::update()
}
}
mapper = new Foam::meshToMesh
mapper = new Foam::fvMeshToFvMesh
(
mesh(),
newMesh,
@ -193,7 +193,7 @@ bool Foam::fvMeshTopoChangers::meshToMesh::update()
}
else
{
mapper = new Foam::meshToMesh
mapper = new Foam::fvMeshToFvMesh
(
mesh(),
newMesh,
@ -207,25 +207,27 @@ bool Foam::fvMeshTopoChangers::meshToMesh::update()
// Map all the volFields in the objectRegistry
#define mapVolFieldType(Type, nullArg) \
MeshToMeshMapVolFields<Type>(mapper);
MeshToMeshMapVolFields<Type>(mesh(), mapper);
FOR_ALL_FIELD_TYPES(mapVolFieldType);
// Set all the surfaceFields in the objectRegistry to NaN
#define NaNSurfaceFieldType(Type, nullArg) \
NaNGeometricFields \
<Type, fvsPatchField, surfaceMesh, fvPatchFieldMapper>(mapper);
<Type, fvsPatchField, surfaceMesh, fvPatchFieldMapper> \
(mesh(), mapper);
FOR_ALL_FIELD_TYPES(NaNSurfaceFieldType);
// Set all the pointFields in the objectRegistry to NaN
#define NaNPointFieldType(Type, nullArg) \
NaNGeometricFields \
<Type, pointPatchField, pointMesh, pointPatchFieldMapper>(mapper);
<Type, pointPatchField, pointMesh, pointPatchFieldMapper> \
(mesh(), mapper);
FOR_ALL_FIELD_TYPES(NaNPointFieldType);
// Interpolate U's to Uf's
interpolateUfs();
polyMeshMap map(mesh());
polyMeshMap map(mesh(), mapper());
mesh().mapMesh(map);
}

View File

@ -26,6 +26,7 @@ License
#include "Cloud.H"
#include "processorPolyPatch.H"
#include "globalMeshData.H"
#include "meshToMesh.H"
#include "PstreamCombineReduceOps.H"
#include "polyTopoChangeMap.H"
#include "polyMeshMap.H"
@ -433,7 +434,109 @@ void Foam::Cloud<ParticleType>::topoChange(const polyTopoChangeMap& map)
template<class ParticleType>
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));
}
}
}
}

View File

@ -215,6 +215,8 @@ triSurface/triSurfaceTools/pointToPointPlanarInterpolation.C
twoDPointCorrector/twoDPointCorrector.C
patchToPatchTools/patchToPatchTools.C
patchToPatch/patchToPatch/patchToPatch.C
patchToPatch/patchToPatch/patchToPatchParallelOps.C
patchToPatch/matching/matchingPatchToPatch.C
@ -223,6 +225,14 @@ patchToPatch/inverseDistance/inverseDistancePatchToPatch.C
patchToPatch/intersection/intersectionPatchToPatch.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/mappedPolyPatch/mappedPolyPatch.C
mappedPatches/mappedPolyPatch/mappedWallPolyPatch.C

View 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();
}
// ************************************************************************* //

View File

@ -45,7 +45,6 @@ SourceFiles
#include "polyMesh.H"
#include "boundBox.H"
#include "distributionMap.H"
#include "volFieldsFwd.H"
#include "NamedEnum.H"
#include "patchToPatch.H"
@ -63,57 +62,65 @@ class meshToMesh
// Private Data
//- Reference to the source mesh
const polyMesh& srcRegion_;
const polyMesh& srcMesh_;
//- Reference to the target mesh
const polyMesh& tgtRegion_;
const polyMesh& tgtMesh_;
//- List of target patch IDs per source patch (local index)
List<label> srcPatchID_;
//- List of source patch IDs per target patch (local index)
List<label> tgtPatchID_;
//- List of corresponding source and target patches that are to be
// mapped to each other
List<labelPair> srcToTgtPatchIDs_;
//- List of patchToPatch interpolation engines between source and
// target patches
PtrList<patchToPatch> patchToPatches_;
PtrList<patchToPatch> srcToTgtPatchToPatches_;
//- Cutting patches whose values are set using a zero-gradient condition
List<label> cuttingPatches_;
labelList tgtCuttingPatchIDs_;
//- Source to target cell addressing
labelListList srcToTgtCellAddr_;
//- For each source cell, the coupled local target cells
labelListList srcLocalTgtCells_;
//- Target to source cell addressing
labelListList tgtToSrcCellAddr_;
//- For each target cell, the coupled local source cells
labelListList tgtLocalSrcCells_;
//- Source to target cell interpolation weights
scalarListList srcToTgtCellWght_;
//- For each source cell, the coupled target weights
scalarListList srcWeights_;
//- Target to source cell interpolation weights
scalarListList tgtToSrcCellWght_;
//- For each target cell, the coupled source weights
scalarListList tgtWeights_;
//- Index of processor that holds all of both sides. -1 in all other
// cases
label singleMeshProc_;
//- Index of processor that holds all of both sides, or -1
label singleProcess_;
//- Source map pointer - parallel running only
//- Map from source patch cells to target-local source patch cells
autoPtr<distributionMap> srcMapPtr_;
//- Target map pointer - parallel running only
//- Map from target patch cells to source-local target patch cells
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
//- Helper function to add a constant offset to a list
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.
scalar calculate(const word& methodName);
//- Calculate the cell intersections. Returns the overlap volume.
scalar calculateCellToCells(const word& methodName);
//- Calculate patch overlap
//- Calculate patch intersections
void calculatePatchToPatches(const word& patchToPatchType);
//- Constructor helper
@ -128,66 +135,49 @@ class meshToMesh
(
const word& methodName,
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
//- Determine whether the meshes are split across multiple pocessors
label calcDistribution
//- Determine which target cells need to be sent to the source.
// This is done before intersection. Bound boxes are used to
// estimate what cells will intersect.
labelListList tgtMeshSendCells
(
const polyMesh& src,
const polyMesh& tgt
const polyMesh& srcMesh,
const polyMesh& tgtMesh
) const;
//- Determine which processor bounding-boxes overlap
label calcOverlappingProcs
(
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
//- Distribute a mesh given its distribution map
static List<remote> distributeMesh
(
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;
const polyMesh& mesh,
autoPtr<polyMesh>& localMeshPtr
);
//- Collect pieces of tgt mesh from other processors and restructure
void distributeAndMergeCells
(
const distributionMap& map,
const polyMesh& tgtMesh,
const globalIndex& globalTgtCells,
pointField& tgtPoints,
faceList& tgtFaces,
labelList& tgtFaceOwners,
labelList& tgtFaceNeighbours,
labelList& tgtCellIDs
) const;
//- Trim the local target addressing and mesh so that communication
// from the target to the source is optimised
void trimLocalTgt();
protected:
// Protected Member Functions
// Access
//- 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:
@ -195,6 +185,7 @@ public:
//- Run-time type information
TypeName("meshToMesh");
// Constructors
//- Construct from source and target meshes, generic mapping methods
@ -229,22 +220,17 @@ public:
// Access
//- Return const access to the source mesh
inline const polyMesh& srcRegion() const;
inline const polyMesh& srcMesh() const;
//- 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
inline const labelListList& srcToTgtCellAddr() const;
//- Index of the processor holding all cells of the meshToMesh,
// or -1 if spread across multiple processors
inline label singleProcess() const;
//- Return const access to the target to source cell addressing
inline const labelListList& tgtToSrcCellAddr() 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;
//- Is this intersection on a single process?
inline bool isSingleProcess() const;
// Evaluation
@ -283,24 +269,18 @@ public:
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
// passed in via 'result' are used to initialise the return
// value
template<class Type>
void mapSrcToTgt
//- Find the target processor and cell associated with a point
// in a source cell. Note that this will only work with
// methods that fill a cell's stencil with everything that
// overlaps that cell. At present this is just
// cellVolumeWeightMethod, but we might add a cheaper
// bound-box based method like patchToPatches::rays in future.
remote srcToTgtPoint
(
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 label srcCelli,
const point& p
) const;

View File

@ -25,52 +25,51 @@ License
#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_;
}
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_;
return srcToTgtPatchIDs_;
}
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;
}

View 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();
}
// ************************************************************************* //

View 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;
}
// ************************************************************************* //

View File

@ -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 labelList newToOldLocalTgtFace =
patchToPatch::subsetLocalTgt(localTgtPatch);
patchToPatch::trimLocalTgt(localTgtPatch);
tgtCouples_ = List<DynamicList<couple>>(tgtCouples_, newToOldLocalTgtFace);
@ -563,7 +563,12 @@ void Foam::patchToPatches::intersection::rDistributeTgt
{
patchToPatch::rDistributeTgt(tgtPatch);
rDistributeListList(tgtPatch.size(), tgtMapPtr_(), tgtCouples_);
patchToPatchTools::rDistributeListList
(
tgtPatch.size(),
tgtMapPtr_(),
tgtCouples_
);
}

View File

@ -328,9 +328,9 @@ private:
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
virtual labelList subsetLocalTgt
virtual labelList trimLocalTgt
(
const primitiveOldTimePatch& localTgtPatch
);

View File

@ -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 labelList newToOldLocalTgtFace =
patchToPatch::subsetLocalTgt(localTgtPatch);
patchToPatch::trimLocalTgt(localTgtPatch);
tgtWeights_ = List<DynamicList<scalar>>(tgtWeights_, newToOldLocalTgtFace);
@ -212,7 +212,12 @@ void Foam::patchToPatches::inverseDistance::rDistributeTgt
{
patchToPatch::rDistributeTgt(tgtPatch);
rDistributeListList(tgtPatch.size(), tgtMapPtr_(), tgtWeights_);
patchToPatchTools::rDistributeListList
(
tgtPatch.size(),
tgtMapPtr_(),
tgtWeights_
);
}

View File

@ -114,9 +114,9 @@ class inverseDistance
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
virtual labelList subsetLocalTgt
virtual labelList trimLocalTgt
(
const primitiveOldTimePatch& localTgtPatch
);

View File

@ -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 labelList newToOldLocalTgtFace =
patchToPatch::subsetLocalTgt(localTgtPatch);
patchToPatch::trimLocalTgt(localTgtPatch);
tgtDistances_ = List<scalar>(tgtDistances_, newToOldLocalTgtFace);
@ -233,7 +233,12 @@ void Foam::patchToPatches::nearest::rDistributeTgt
patchToPatch::rDistributeTgt(tgtPatch);
// 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
tgtDistances_.resize(tgtLocalSrcFaces_.size());

View File

@ -105,9 +105,9 @@ protected:
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
virtual labelList subsetLocalTgt
virtual labelList trimLocalTgt
(
const primitiveOldTimePatch& localTgtPatch
);

View File

@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "patchToPatch.H"
#include "patchToPatchTools.H"
#include "cpuTime.H"
#include "distributionMap.H"
#include "globalIndex.H"
@ -78,75 +79,6 @@ namespace Foam
{
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 * * * * * * * * * * * //
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
(
const primitiveOldTimePatch& srcPatch,
@ -777,7 +657,7 @@ void Foam::patchToPatch::initialise
}
Foam::labelList Foam::patchToPatch::subsetLocalTgt
Foam::labelList Foam::patchToPatch::trimLocalTgt
(
const primitiveOldTimePatch& localTgtPatch
)
@ -792,9 +672,9 @@ Foam::labelList Foam::patchToPatch::subsetLocalTgt
}
}
// Subset the target map
// Trim the target map
labelList oldToNewLocalTgtFace, newToOldLocalTgtFace;
subsetDistributionMap
patchToPatchTools::trimDistributionMap
(
oldLocalTgtFaceIsUsed,
tgtMapPtr_(),
@ -812,7 +692,7 @@ Foam::labelList Foam::patchToPatch::subsetLocalTgt
}
}
// Subset the local target faces
// Trim the local target faces
tgtLocalSrcFaces_ =
List<DynamicList<label>>(tgtLocalSrcFaces_, newToOldLocalTgtFace);
localTgtProcFacesPtr_() =
@ -827,34 +707,27 @@ void Foam::patchToPatch::distributeSrc
const primitiveOldTimePatch& srcPatch
)
{
distributePatch(srcMapPtr_(), localSrcProcFacesPtr_());
localSrcProcFacesPtr_.reset
(
new List<remote>
(
patchToPatchTools::distributeAddressing(srcMapPtr_())
)
);
}
void Foam::patchToPatch::rDistributeTgt(const primitiveOldTimePatch& tgtPatch)
{
// Create a map from source procFace to local source face
HashTable<label, remote, Hash<remote>> srcProcFaceToLocal;
forAll(localSrcProcFacesPtr_(), localSrcFacei)
{
srcProcFaceToLocal.insert
patchToPatchTools::rDistributeTgtAddressing
(
localSrcProcFacesPtr_()[localSrcFacei],
localSrcFacei
tgtPatch.size(),
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);
}
Foam::label Foam::patchToPatch::finalise
(
@ -892,8 +765,8 @@ Foam::patchToPatch::patchToPatch(const bool reverse)
tgtLocalSrcFaces_(),
srcMapPtr_(nullptr),
tgtMapPtr_(nullptr),
localSrcProcFacesPtr_(new List<remote>()),
localTgtProcFacesPtr_(new List<remote>())
localSrcProcFacesPtr_(nullptr),
localTgtProcFacesPtr_(nullptr)
{}
@ -997,7 +870,12 @@ void Foam::patchToPatch::update
<< " target faces" << incrIndent << endl;
// 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
if (isSingleProcess())
@ -1027,7 +905,7 @@ void Foam::patchToPatch::update
// faces will get distributed that ultimately are not used. These will
// be filtered out after the intersection has been completed.
tgtMapPtr_ =
patchDistributionMap
patchToPatchTools::constructDistributionMap
(
tgtPatchSendFaces
(
@ -1037,16 +915,16 @@ void Foam::patchToPatch::update
tTgtPatch
)
);
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>> localTTgtPatchPtr =
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>>
autoPtr<PrimitiveOldTimePatch<faceList, pointField>> localTTgtPatchPtr;
localTgtProcFacesPtr_.reset
(
new PrimitiveOldTimePatch<faceList, pointField>
new List<remote>
(
distributePatch
(
tgtMapPtr_(),
tTgtPatch,
localTgtProcFacesPtr_()
localTTgtPatchPtr
)
)
);
@ -1082,11 +960,19 @@ void Foam::patchToPatch::update
);
}
// Subset the local target patch
subsetLocalTgt(localTTgtPatch);
// Trim the local target patch
trimLocalTgt(localTTgtPatch);
// Distribute the source patch
srcMapPtr_ = patchDistributionMap(srcPatchSendFaces());
srcMapPtr_ =
patchToPatchTools::constructDistributionMap
(
patchToPatchTools::procSendIndices
(
tgtLocalSrcFaces_,
localTgtProcFacesPtr_()
)
);
distributeSrc(srcPatch);
// Reverse distribute coupling data back to the target

View File

@ -89,49 +89,6 @@ protected:
// 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
//- Get the bound box for a source face
@ -226,15 +183,6 @@ protected:
// 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.
// This is done before intersection. Bound boxes are used to
// estimate what faces will intersect.
@ -246,33 +194,14 @@ protected:
const primitiveOldTimePatch& tgtPatch
) 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
PrimitiveOldTimePatch<faceList, pointField> distributePatch
static List<remote> distributePatch
(
const distributionMap& map,
const primitiveOldTimePatch& patch,
List<remote>& localProcFaces
) const;
//- As above, but when you want the proc-faces without the
// associated patch geometry
void distributePatch
(
const distributionMap& map,
List<remote>& localProcFaces
) const;
autoPtr<PrimitiveOldTimePatch<faceList, pointField>>&
localPatchPtr
);
// Hooks
@ -286,9 +215,9 @@ protected:
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
virtual labelList subsetLocalTgt
virtual labelList trimLocalTgt
(
const primitiveOldTimePatch& localTgtPatch
);

View File

@ -24,63 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "patchToPatch.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);
}
#include "patchToPatchTools.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
@ -107,8 +51,12 @@ Foam::patchToPatch::srcTgtProcFaces() const
{
return
isSingleProcess()
? localFacesToProcFaces(srcLocalTgtFaces_)
: localFacesToProcFaces(srcLocalTgtFaces_, localTgtProcFacesPtr_());
? patchToPatchTools::localToRemote(srcLocalTgtFaces_)
: patchToPatchTools::localToRemote
(
srcLocalTgtFaces_,
localTgtProcFacesPtr_()
);
}
@ -117,8 +65,12 @@ Foam::patchToPatch::tgtSrcProcFaces() const
{
return
isSingleProcess()
? localFacesToProcFaces(tgtLocalSrcFaces_)
: localFacesToProcFaces(tgtLocalSrcFaces_, localSrcProcFacesPtr_());
? patchToPatchTools::localToRemote(tgtLocalSrcFaces_)
: patchToPatchTools::localToRemote
(
tgtLocalSrcFaces_,
localSrcProcFacesPtr_()
);
}

View File

@ -31,44 +31,6 @@ License
// * * * * * * * * * * * * * 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
(
const primitiveOldTimePatch& srcPatch,
@ -127,103 +89,12 @@ Foam::labelListList Foam::patchToPatch::tgtPatchSendFaces
}
Foam::labelListList Foam::patchToPatch::srcPatchSendFaces() const
{
// 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
Foam::List<Foam::remote> Foam::patchToPatch::distributePatch
(
const distributionMap& map,
const primitiveOldTimePatch& patch,
List<remote>& localProcFaces
) const
autoPtr<PrimitiveOldTimePatch<faceList, pointField>>& localPatchPtr
)
{
static const label thisProci = Pstream::myProcNo();
@ -294,6 +165,7 @@ Foam::patchToPatch::distributePatch
}
// Allocate
List<remote> localProcFaces;
faceList localFaces;
pointField localPoints;
pointField localPoints0;
@ -313,37 +185,9 @@ Foam::patchToPatch::distributePatch
}
}
// Renumber and flatten
// Construct the result
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)
{
if (proci != thisProci)
{
const labelList& fis = procLocalFaceis[proci];
const faceList& fs = procLocalFaces[proci];
@ -366,103 +210,25 @@ Foam::patchToPatch::distributePatch
localPointi ++;
}
}
}
return
// Construct the local patch
localPatchPtr.reset
(
patch.has0()
? PrimitiveOldTimePatch<faceList, pointField>
? new PrimitiveOldTimePatch<faceList, pointField>
(
localFaces,
localPoints,
localPoints0
)
: PrimitiveOldTimePatch<faceList, pointField>
: new PrimitiveOldTimePatch<faceList, pointField>
(
localFaces,
localPoints
)
);
}
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 ++;
}
}
}
return localProcFaces;
}

View File

@ -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 labelList newToOldLocalTgtFace =
patchToPatch::subsetLocalTgt(localTgtPatch);
patchToPatch::trimLocalTgt(localTgtPatch);
localTgtPatchPtr_.reset
(
@ -113,11 +113,11 @@ void Foam::patchToPatches::rays::distributeSrc
const primitiveOldTimePatch& srcPatch
)
{
localSrcPatchPtr_.reset
localSrcProcFacesPtr_.reset
(
new PrimitiveOldTimePatch<faceList, pointField>
new List<remote>
(
distributePatch(srcMapPtr_(), srcPatch, localSrcProcFacesPtr_())
distributePatch(srcMapPtr_(), srcPatch, localSrcPatchPtr_)
)
);
}

View File

@ -94,7 +94,7 @@ class rays
//- Subset the local target patch so that only parts that actually
// intersect the source remain
virtual labelList subsetLocalTgt
virtual labelList trimLocalTgt
(
const primitiveOldTimePatch& localTgtPatch
);

View 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);
}
// ************************************************************************* //

View 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
// ************************************************************************* //

View 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);
}
// ************************************************************************* //

View File

@ -60,19 +60,5 @@ $(surfWriters)/proxy/proxySurfaceWriter.C
$(surfWriters)/raw/rawSurfaceWriter.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

View File

@ -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()
{}
// ************************************************************************* //

View File

@ -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;
}
}
}
}
}
// ************************************************************************* //

View File

@ -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;
}
// ************************************************************************* //

View File

@ -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];
}
}
}
}
}
}
// ************************************************************************* //

View File

@ -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_;
}
// ************************************************************************* //

View File

@ -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_);
}
// ************************************************************************* //

View File

@ -4,11 +4,14 @@ cd ${0%/*} || exit 1 # Run from this directory
# Source tutorial run functions
. $WM_PROJECT_DIR/bin/tools/CleanFunctions
cd hopperInitialState
(
cd hopperInitialState || exit 1
cleanCase
)
cd ../hopperEmptying
(
cd hopperEmptying || exit 1
cleanCase
rm -rf 0
)
#------------------------------------------------------------------------------

View File

@ -4,20 +4,21 @@ cd ${0%/*} || exit 1 # Run from this directory
# Source tutorial run functions
. $WM_PROJECT_DIR/bin/tools/RunFunctions
cd hopperInitialState
(
cd hopperInitialState || exit 1
runApplication blockMesh
runApplication decomposePar
runParallel $(getApplication)
runApplication reconstructPar -latestTime
cd ..
cd hopperEmptying
rm -rf 0
cp -R 0.orig 0
runApplication blockMesh
runApplication mapFields ../hopperInitialState -sourceTime latestTime
runApplication decomposePar
runParallel $(getApplication)
runApplication reconstructPar
)
(
cd hopperEmptying || exit 1
runApplication blockMesh
runApplication decomposePar
runParallel mapFieldsPar ../hopperInitialState -sourceTime latestTime
runParallel $(getApplication)
runApplication reconstructPar
)
#------------------------------------------------------------------------------