mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-12-28 03:37:59 +00:00
1595 lines
46 KiB
C
1595 lines
46 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | Copyright (C) 1991-2007 OpenCFD Ltd.
|
|
\\/ M anipulation |
|
|
-------------------------------------------------------------------------------
|
|
License
|
|
This file is part of OpenFOAM.
|
|
|
|
OpenFOAM is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenFOAM; if not, write to the Free Software Foundation,
|
|
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
#include "syncTools.H"
|
|
#include "polyMesh.H"
|
|
#include "processorPolyPatch.H"
|
|
#include "cyclicPolyPatch.H"
|
|
#include "globalMeshData.H"
|
|
#include "contiguous.H"
|
|
#include "transform.H"
|
|
|
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
|
|
template <class T>
|
|
void Foam::syncTools::separateList
|
|
(
|
|
const vectorField& separation,
|
|
UList<T>& field
|
|
)
|
|
{}
|
|
|
|
|
|
template <class T>
|
|
void Foam::syncTools::separateList
|
|
(
|
|
const vectorField& separation,
|
|
Map<T>& field
|
|
)
|
|
{}
|
|
|
|
|
|
template <class T>
|
|
void Foam::syncTools::separateList
|
|
(
|
|
const vectorField& separation,
|
|
EdgeMap<T>& field
|
|
)
|
|
{}
|
|
|
|
|
|
// Combine val with existing value at index
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::combine
|
|
(
|
|
Map<T>& pointValues,
|
|
const CombineOp& cop,
|
|
const label index,
|
|
const T& val
|
|
)
|
|
{
|
|
typename Map<T>::iterator iter = pointValues.find(index);
|
|
|
|
if (iter != pointValues.end())
|
|
{
|
|
cop(iter(), val);
|
|
}
|
|
else
|
|
{
|
|
pointValues.insert(index, val);
|
|
}
|
|
}
|
|
|
|
|
|
// Combine val with existing value at (implicit index) e.
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::combine
|
|
(
|
|
EdgeMap<T>& edgeValues,
|
|
const CombineOp& cop,
|
|
const edge& index,
|
|
const T& val
|
|
)
|
|
{
|
|
typename EdgeMap<T>::iterator iter = edgeValues.find(index);
|
|
|
|
if (iter != edgeValues.end())
|
|
{
|
|
cop(iter(), val);
|
|
}
|
|
else
|
|
{
|
|
edgeValues.insert(index, val);
|
|
}
|
|
}
|
|
|
|
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::syncPointMap
|
|
(
|
|
const polyMesh& mesh,
|
|
Map<T>& pointValues, // from mesh point label to value
|
|
const CombineOp& cop,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
const polyBoundaryMesh& patches = mesh.boundaryMesh();
|
|
|
|
if (!hasCouples(patches))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Is there any coupled patch with transformation?
|
|
bool hasTransformation = false;
|
|
|
|
if (Pstream::parRun())
|
|
{
|
|
// Send
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].nPoints() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
|
|
// Get data per patchPoint in neighbouring point numbers.
|
|
|
|
const labelList& meshPts = procPatch.meshPoints();
|
|
const labelList& nbrPts = procPatch.neighbPoints();
|
|
|
|
// Extract local values. Create map from nbrPoint to value.
|
|
// Note: how small initial size?
|
|
Map<T> patchInfo(meshPts.size() / 20);
|
|
|
|
forAll(meshPts, i)
|
|
{
|
|
typename Map<T>::const_iterator iter =
|
|
pointValues.find(meshPts[i]);
|
|
|
|
if (iter != pointValues.end())
|
|
{
|
|
if (nbrPts[i] >= 0)
|
|
{
|
|
patchInfo.insert(nbrPts[i], iter());
|
|
}
|
|
}
|
|
}
|
|
|
|
OPstream toNeighb(Pstream::blocking, procPatch.neighbProcNo());
|
|
toNeighb << patchInfo;
|
|
}
|
|
}
|
|
|
|
|
|
// Receive and combine.
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].nPoints() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
checkTransform(procPatch, applySeparation);
|
|
|
|
IPstream fromNb(Pstream::blocking, procPatch.neighbProcNo());
|
|
Map<T> nbrPatchInfo(fromNb);
|
|
|
|
if (!procPatch.parallel())
|
|
{
|
|
hasTransformation = true;
|
|
transformList(procPatch.forwardT(), nbrPatchInfo);
|
|
}
|
|
else if (applySeparation && procPatch.separated())
|
|
{
|
|
hasTransformation = true;
|
|
separateList(-procPatch.separation(), nbrPatchInfo);
|
|
}
|
|
|
|
const labelList& meshPts = procPatch.meshPoints();
|
|
|
|
// Only update those values which come from neighbour
|
|
|
|
forAllConstIter
|
|
(
|
|
typename Map<T>,
|
|
nbrPatchInfo,
|
|
nbrIter
|
|
)
|
|
{
|
|
combine
|
|
(
|
|
pointValues,
|
|
cop,
|
|
meshPts[nbrIter.key()],
|
|
nbrIter()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do the cyclics.
|
|
forAll(patches, patchI)
|
|
{
|
|
if (isA<cyclicPolyPatch>(patches[patchI]))
|
|
{
|
|
const cyclicPolyPatch& cycPatch =
|
|
refCast<const cyclicPolyPatch>(patches[patchI]);
|
|
checkTransform(cycPatch, applySeparation);
|
|
|
|
const edgeList& coupledPoints = cycPatch.coupledPoints();
|
|
const labelList& meshPts = cycPatch.meshPoints();
|
|
|
|
// Extract local values. Create map from nbrPoint to value.
|
|
Map<T> half0Values(meshPts.size() / 20);
|
|
Map<T> half1Values(meshPts.size() / 20);
|
|
|
|
forAll(coupledPoints, i)
|
|
{
|
|
const edge& e = coupledPoints[i];
|
|
|
|
typename Map<T>::const_iterator point0Fnd =
|
|
pointValues.find(meshPts[e[0]]);
|
|
|
|
if (point0Fnd != pointValues.end())
|
|
{
|
|
half0Values.insert(i, point0Fnd());
|
|
}
|
|
|
|
typename Map<T>::const_iterator point1Fnd =
|
|
pointValues.find(meshPts[e[1]]);
|
|
|
|
if (point1Fnd != pointValues.end())
|
|
{
|
|
half1Values.insert(i, point1Fnd());
|
|
}
|
|
}
|
|
|
|
if (!cycPatch.parallel())
|
|
{
|
|
hasTransformation = true;
|
|
transformList(cycPatch.reverseT(), half0Values);
|
|
transformList(cycPatch.forwardT(), half1Values);
|
|
}
|
|
else if (applySeparation && cycPatch.separated())
|
|
{
|
|
hasTransformation = true;
|
|
|
|
const vectorField& v = cycPatch.coupledPolyPatch::separation();
|
|
separateList(v, half0Values);
|
|
separateList(-v, half1Values);
|
|
}
|
|
|
|
forAll(coupledPoints, i)
|
|
{
|
|
const edge& e = coupledPoints[i];
|
|
|
|
typename Map<T>::const_iterator half1Fnd = half1Values.find(i);
|
|
|
|
if (half1Fnd != half1Values.end())
|
|
{
|
|
combine
|
|
(
|
|
pointValues,
|
|
cop,
|
|
meshPts[e[0]],
|
|
half1Fnd()
|
|
);
|
|
}
|
|
|
|
typename Map<T>::const_iterator half0Fnd = half0Values.find(i);
|
|
|
|
if (half0Fnd != half0Values.end())
|
|
{
|
|
combine
|
|
(
|
|
pointValues,
|
|
cop,
|
|
meshPts[e[1]],
|
|
half0Fnd()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//- Note: hasTransformation is only used for warning messages so
|
|
// reduction not strictly nessecary.
|
|
//reduce(hasTransformation, orOp<bool>());
|
|
|
|
// Synchronize multiple shared points.
|
|
const globalMeshData& pd = mesh.globalData();
|
|
|
|
if (pd.nGlobalPoints() > 0)
|
|
{
|
|
if (hasTransformation)
|
|
{
|
|
WarningIn
|
|
(
|
|
"syncTools<class T, class CombineOp>::syncPointMap"
|
|
"(const polyMesh&, Map<T>&, const CombineOp&"
|
|
", const bool)"
|
|
) << "There are decomposed cyclics in this mesh with"
|
|
<< " transformations." << endl
|
|
<< "This is not supported. The result will be incorrect"
|
|
<< endl;
|
|
}
|
|
// meshPoint per local index
|
|
const labelList& sharedPtLabels = pd.sharedPointLabels();
|
|
// global shared index per local index
|
|
const labelList& sharedPtAddr = pd.sharedPointAddr();
|
|
|
|
// Values on shared points. Keyed on global shared index.
|
|
Map<T> sharedPointValues(sharedPtAddr.size());
|
|
|
|
|
|
// Fill my entries in the shared points
|
|
forAll(sharedPtLabels, i)
|
|
{
|
|
label meshPointI = sharedPtLabels[i];
|
|
|
|
typename Map<T>::const_iterator fnd =
|
|
pointValues.find(meshPointI);
|
|
|
|
if (fnd != pointValues.end())
|
|
{
|
|
combine
|
|
(
|
|
sharedPointValues,
|
|
cop,
|
|
sharedPtAddr[i], // index
|
|
fnd() // value
|
|
);
|
|
}
|
|
}
|
|
|
|
// Reduce on master.
|
|
|
|
if (Pstream::parRun())
|
|
{
|
|
if (Pstream::master())
|
|
{
|
|
// Receive the edges using shared points from the slave.
|
|
for
|
|
(
|
|
int slave=Pstream::firstSlave();
|
|
slave<=Pstream::lastSlave();
|
|
slave++
|
|
)
|
|
{
|
|
IPstream fromSlave(Pstream::blocking, slave);
|
|
Map<T> nbrValues(fromSlave);
|
|
|
|
// Merge neighbouring values with my values
|
|
forAllConstIter(typename Map<T>, nbrValues, iter)
|
|
{
|
|
combine
|
|
(
|
|
sharedPointValues,
|
|
cop,
|
|
iter.key(), // edge
|
|
iter() // value
|
|
);
|
|
}
|
|
}
|
|
|
|
// Send back
|
|
for
|
|
(
|
|
int slave=Pstream::firstSlave();
|
|
slave<=Pstream::lastSlave();
|
|
slave++
|
|
)
|
|
{
|
|
OPstream toSlave(Pstream::blocking, slave);
|
|
toSlave << sharedPointValues;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Send to master
|
|
{
|
|
OPstream toMaster
|
|
(
|
|
Pstream::blocking,
|
|
Pstream::masterNo()
|
|
);
|
|
toMaster << sharedPointValues;
|
|
}
|
|
// Receive merged values
|
|
{
|
|
IPstream fromMaster
|
|
(
|
|
Pstream::blocking,
|
|
Pstream::masterNo()
|
|
);
|
|
fromMaster >> sharedPointValues;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Merge sharedPointValues (keyed on sharedPointAddr) into
|
|
// pointValues (keyed on mesh points).
|
|
|
|
// Map from global shared index to meshpoint
|
|
Map<label> sharedToMeshPoint(2*sharedPtAddr.size());
|
|
forAll(sharedPtAddr, i)
|
|
{
|
|
sharedToMeshPoint.insert(sharedPtAddr[i], sharedPtLabels[i]);
|
|
}
|
|
|
|
forAllConstIter(Map<label>, sharedToMeshPoint, iter)
|
|
{
|
|
// Do I have a value for my shared point
|
|
typename Map<T>::const_iterator sharedFnd =
|
|
sharedPointValues.find(iter.key());
|
|
|
|
if (sharedFnd != sharedPointValues.end())
|
|
{
|
|
combine
|
|
(
|
|
pointValues,
|
|
cop,
|
|
iter(), // index
|
|
sharedFnd() // value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::syncEdgeMap
|
|
(
|
|
const polyMesh& mesh,
|
|
EdgeMap<T>& edgeValues,
|
|
const CombineOp& cop,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
const polyBoundaryMesh& patches = mesh.boundaryMesh();
|
|
|
|
if (!hasCouples(patches))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
// Do synchronisation without constructing globalEdge addressing
|
|
// (since this constructs mesh edge addressing)
|
|
|
|
|
|
// Swap proc patch info
|
|
// ~~~~~~~~~~~~~~~~~~~~
|
|
|
|
if (Pstream::parRun())
|
|
{
|
|
// Send
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].nEdges() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
|
|
// Get data per patch edge in neighbouring edge.
|
|
|
|
const edgeList& edges = procPatch.edges();
|
|
const labelList& meshPts = procPatch.meshPoints();
|
|
const labelList& nbrPts = procPatch.neighbPoints();
|
|
|
|
EdgeMap<T> patchInfo(edges.size() / 20);
|
|
|
|
forAll(edges, i)
|
|
{
|
|
const edge& e = edges[i];
|
|
const edge meshEdge(meshPts[e[0]], meshPts[e[1]]);
|
|
|
|
typename EdgeMap<T>::const_iterator iter =
|
|
edgeValues.find(meshEdge);
|
|
|
|
if (iter != edgeValues.end())
|
|
{
|
|
const edge nbrEdge(nbrPts[e[0]], nbrPts[e[1]]);
|
|
|
|
if (nbrEdge[0] >= 0 && nbrEdge[1] >= 0)
|
|
{
|
|
patchInfo.insert(nbrEdge, iter());
|
|
}
|
|
}
|
|
}
|
|
|
|
OPstream toNeighb(Pstream::blocking, procPatch.neighbProcNo());
|
|
toNeighb << patchInfo;
|
|
}
|
|
}
|
|
|
|
|
|
// Receive and combine.
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].nEdges() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
checkTransform(procPatch, applySeparation);
|
|
|
|
const labelList& meshPts = procPatch.meshPoints();
|
|
|
|
IPstream fromNbr(Pstream::blocking, procPatch.neighbProcNo());
|
|
EdgeMap<T> nbrPatchInfo(fromNbr);
|
|
|
|
if (!procPatch.parallel())
|
|
{
|
|
transformList(procPatch.forwardT(), nbrPatchInfo);
|
|
}
|
|
else if (applySeparation && procPatch.separated())
|
|
{
|
|
separateList(-procPatch.separation(), nbrPatchInfo);
|
|
}
|
|
|
|
// Only update those values which come from neighbour
|
|
|
|
forAllConstIter
|
|
(
|
|
typename EdgeMap<T>,
|
|
nbrPatchInfo,
|
|
nbrIter
|
|
)
|
|
{
|
|
const edge& e = nbrIter.key();
|
|
const edge meshEdge(meshPts[e[0]], meshPts[e[1]]);
|
|
|
|
combine
|
|
(
|
|
edgeValues,
|
|
cop,
|
|
meshEdge, // edge
|
|
nbrIter() // value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Swap cyclic info
|
|
// ~~~~~~~~~~~~~~~~
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if (isA<cyclicPolyPatch>(patches[patchI]))
|
|
{
|
|
const cyclicPolyPatch& cycPatch =
|
|
refCast<const cyclicPolyPatch>(patches[patchI]);
|
|
checkTransform(cycPatch, applySeparation);
|
|
|
|
const edgeList& coupledEdges = cycPatch.coupledEdges();
|
|
const labelList& meshPts = cycPatch.meshPoints();
|
|
const edgeList& edges = cycPatch.edges();
|
|
|
|
// Extract local values. Create map from nbrPoint to value.
|
|
Map<T> half0Values(meshPts.size() / 20);
|
|
Map<T> half1Values(meshPts.size() / 20);
|
|
|
|
forAll(coupledEdges, i)
|
|
{
|
|
const edge& twoEdges = coupledEdges[i];
|
|
|
|
{
|
|
const edge& e0 = edges[twoEdges[0]];
|
|
const edge meshEdge0(meshPts[e0[0]], meshPts[e0[1]]);
|
|
|
|
typename EdgeMap<T>::const_iterator iter =
|
|
edgeValues.find(meshEdge0);
|
|
|
|
if (iter != edgeValues.end())
|
|
{
|
|
half0Values.insert(i, iter());
|
|
}
|
|
}
|
|
{
|
|
const edge& e1 = edges[twoEdges[1]];
|
|
const edge meshEdge1(meshPts[e1[0]], meshPts[e1[1]]);
|
|
|
|
typename EdgeMap<T>::const_iterator iter =
|
|
edgeValues.find(meshEdge1);
|
|
|
|
if (iter != edgeValues.end())
|
|
{
|
|
half1Values.insert(i, iter());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Transform
|
|
|
|
if (!cycPatch.parallel())
|
|
{
|
|
transformList(cycPatch.reverseT(), half0Values);
|
|
transformList(cycPatch.forwardT(), half1Values);
|
|
}
|
|
else if (applySeparation && cycPatch.separated())
|
|
{
|
|
const vectorField& v = cycPatch.coupledPolyPatch::separation();
|
|
separateList(v, half0Values);
|
|
separateList(-v, half1Values);
|
|
}
|
|
|
|
|
|
// Extract and combine information
|
|
|
|
forAll(coupledEdges, i)
|
|
{
|
|
const edge& twoEdges = coupledEdges[i];
|
|
|
|
typename Map<T>::const_iterator half1Fnd =
|
|
half1Values.find(i);
|
|
|
|
if (half1Fnd != half1Values.end())
|
|
{
|
|
const edge& e0 = edges[twoEdges[0]];
|
|
const edge meshEdge0(meshPts[e0[0]], meshPts[e0[1]]);
|
|
|
|
combine
|
|
(
|
|
edgeValues,
|
|
cop,
|
|
meshEdge0, // edge
|
|
half1Fnd() // value
|
|
);
|
|
}
|
|
|
|
typename Map<T>::const_iterator half0Fnd =
|
|
half0Values.find(i);
|
|
if (half0Fnd != half0Values.end())
|
|
{
|
|
const edge& e1 = edges[twoEdges[1]];
|
|
const edge meshEdge1(meshPts[e1[0]], meshPts[e1[1]]);
|
|
|
|
combine
|
|
(
|
|
edgeValues,
|
|
cop,
|
|
meshEdge1, // edge
|
|
half0Fnd() // value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Synchronize multiple shared points.
|
|
// Problem is that we don't want to construct shared edges so basically
|
|
// we do here like globalMeshData but then using sparse edge representation
|
|
// (EdgeMap instead of mesh.edges())
|
|
|
|
const globalMeshData& pd = mesh.globalData();
|
|
const labelList& sharedPtAddr = pd.sharedPointAddr();
|
|
const labelList& sharedPtLabels = pd.sharedPointLabels();
|
|
|
|
// 1. Create map from meshPoint to globalShared index.
|
|
Map<label> meshToShared(2*sharedPtLabels.size());
|
|
forAll(sharedPtLabels, i)
|
|
{
|
|
meshToShared.insert(sharedPtLabels[i], sharedPtAddr[i]);
|
|
}
|
|
|
|
// Values on shared points. From two sharedPtAddr indices to a value.
|
|
EdgeMap<T> sharedEdgeValues(meshToShared.size());
|
|
|
|
// From shared edge to mesh edge. Used for merging later on.
|
|
EdgeMap<edge> potentialSharedEdge(meshToShared.size());
|
|
|
|
// 2. Find any edges using two global shared points. These will always be
|
|
// on the outside of the mesh. (though might not be on coupled patch
|
|
// if is single edge and not on coupled face)
|
|
// Store value (if any) on sharedEdgeValues
|
|
for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
|
|
{
|
|
const face& f = mesh.faces()[faceI];
|
|
|
|
forAll(f, fp)
|
|
{
|
|
label v0 = f[fp];
|
|
label v1 = f[f.fcIndex(fp)];
|
|
|
|
Map<label>::const_iterator v0Fnd = meshToShared.find(v0);
|
|
|
|
if (v0Fnd != meshToShared.end())
|
|
{
|
|
Map<label>::const_iterator v1Fnd = meshToShared.find(v1);
|
|
|
|
if (v1Fnd != meshToShared.end())
|
|
{
|
|
const edge meshEdge(v0, v1);
|
|
|
|
// edge in shared point labels
|
|
const edge sharedEdge(v0Fnd(), v1Fnd());
|
|
|
|
// Store mesh edge as a potential shared edge.
|
|
potentialSharedEdge.insert(sharedEdge, meshEdge);
|
|
|
|
typename EdgeMap<T>::const_iterator edgeFnd =
|
|
edgeValues.find(meshEdge);
|
|
|
|
if (edgeFnd != edgeValues.end())
|
|
{
|
|
// edge exists in edgeValues. See if already in map
|
|
// (since on same processor, e.g. cyclic)
|
|
combine
|
|
(
|
|
sharedEdgeValues,
|
|
cop,
|
|
sharedEdge, // edge
|
|
edgeFnd() // value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Now sharedEdgeValues will contain per potential sharedEdge the value.
|
|
// (potential since an edge having two shared points is not nessecary a
|
|
// shared edge).
|
|
// Reduce this on the master.
|
|
|
|
if (Pstream::parRun())
|
|
{
|
|
if (Pstream::master())
|
|
{
|
|
// Receive the edges using shared points from the slave.
|
|
for
|
|
(
|
|
int slave=Pstream::firstSlave();
|
|
slave<=Pstream::lastSlave();
|
|
slave++
|
|
)
|
|
{
|
|
IPstream fromSlave(Pstream::blocking, slave);
|
|
EdgeMap<T> nbrValues(fromSlave);
|
|
|
|
// Merge neighbouring values with my values
|
|
forAllConstIter(typename EdgeMap<T>, nbrValues, iter)
|
|
{
|
|
combine
|
|
(
|
|
sharedEdgeValues,
|
|
cop,
|
|
iter.key(), // edge
|
|
iter() // value
|
|
);
|
|
}
|
|
}
|
|
|
|
// Send back
|
|
for
|
|
(
|
|
int slave=Pstream::firstSlave();
|
|
slave<=Pstream::lastSlave();
|
|
slave++
|
|
)
|
|
{
|
|
|
|
OPstream toSlave(Pstream::blocking, slave);
|
|
toSlave << sharedEdgeValues;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Send to master
|
|
{
|
|
OPstream toMaster(Pstream::blocking, Pstream::masterNo());
|
|
toMaster << sharedEdgeValues;
|
|
}
|
|
// Receive merged values
|
|
{
|
|
IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
|
|
fromMaster >> sharedEdgeValues;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Merge sharedEdgeValues (keyed on sharedPointAddr) into edgeValues
|
|
// (keyed on mesh points).
|
|
|
|
// Loop over all my shared edges.
|
|
forAllConstIter(typename EdgeMap<edge>, potentialSharedEdge, iter)
|
|
{
|
|
const edge& sharedEdge = iter.key();
|
|
const edge& meshEdge = iter();
|
|
|
|
// Do I have a value for the shared edge?
|
|
typename EdgeMap<T>::const_iterator sharedFnd =
|
|
sharedEdgeValues.find(sharedEdge);
|
|
|
|
if (sharedFnd != sharedEdgeValues.end())
|
|
{
|
|
combine
|
|
(
|
|
edgeValues,
|
|
cop,
|
|
meshEdge, // edge
|
|
sharedFnd() // value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::syncPointList
|
|
(
|
|
const polyMesh& mesh,
|
|
UList<T>& pointValues,
|
|
const CombineOp& cop,
|
|
const T& nullValue,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
if (pointValues.size() != mesh.nPoints())
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"syncTools<class T, class CombineOp>::syncPointList"
|
|
"(const polyMesh&, UList<T>&, const CombineOp&, const T&"
|
|
", const bool)"
|
|
) << "Number of values " << pointValues.size()
|
|
<< " is not equal to the number of points in the mesh "
|
|
<< mesh.nPoints() << abort(FatalError);
|
|
}
|
|
|
|
const polyBoundaryMesh& patches = mesh.boundaryMesh();
|
|
|
|
if (!hasCouples(patches))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Is there any coupled patch with transformation?
|
|
bool hasTransformation = false;
|
|
|
|
if (Pstream::parRun())
|
|
{
|
|
// Send
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].nPoints() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
|
|
// Get data per patchPoint in neighbouring point numbers.
|
|
List<T> patchInfo(procPatch.nPoints(), nullValue);
|
|
|
|
const labelList& meshPts = procPatch.meshPoints();
|
|
const labelList& nbrPts = procPatch.neighbPoints();
|
|
|
|
forAll(nbrPts, pointI)
|
|
{
|
|
label nbrPointI = nbrPts[pointI];
|
|
if (nbrPointI >= 0 && nbrPointI < patchInfo.size())
|
|
{
|
|
patchInfo[nbrPointI] = pointValues[meshPts[pointI]];
|
|
}
|
|
}
|
|
|
|
OPstream toNbr(Pstream::blocking, procPatch.neighbProcNo());
|
|
toNbr << patchInfo;
|
|
}
|
|
}
|
|
|
|
|
|
// Receive and combine.
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].nPoints() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
checkTransform(procPatch, applySeparation);
|
|
|
|
List<T> nbrPatchInfo(procPatch.nPoints());
|
|
{
|
|
// We do not know the number of points on the other side
|
|
// so cannot use Pstream::read.
|
|
IPstream fromNbr
|
|
(
|
|
Pstream::blocking,
|
|
procPatch.neighbProcNo()
|
|
);
|
|
fromNbr >> nbrPatchInfo;
|
|
}
|
|
// Null any value which is not on neighbouring processor
|
|
label nbrSize = nbrPatchInfo.size();
|
|
nbrPatchInfo.setSize(procPatch.nPoints());
|
|
for
|
|
(
|
|
label i = nbrSize;
|
|
i < procPatch.nPoints();
|
|
i++
|
|
)
|
|
{
|
|
nbrPatchInfo[i] = nullValue;
|
|
}
|
|
|
|
if (!procPatch.parallel())
|
|
{
|
|
hasTransformation = true;
|
|
transformList(procPatch.forwardT(), nbrPatchInfo);
|
|
}
|
|
else if (applySeparation && procPatch.separated())
|
|
{
|
|
hasTransformation = true;
|
|
separateList(-procPatch.separation(), nbrPatchInfo);
|
|
}
|
|
|
|
const labelList& meshPts = procPatch.meshPoints();
|
|
|
|
forAll(meshPts, pointI)
|
|
{
|
|
label meshPointI = meshPts[pointI];
|
|
cop(pointValues[meshPointI], nbrPatchInfo[pointI]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do the cyclics.
|
|
forAll(patches, patchI)
|
|
{
|
|
if (isA<cyclicPolyPatch>(patches[patchI]))
|
|
{
|
|
const cyclicPolyPatch& cycPatch =
|
|
refCast<const cyclicPolyPatch>(patches[patchI]);
|
|
|
|
checkTransform(cycPatch, applySeparation);
|
|
|
|
const edgeList& coupledPoints = cycPatch.coupledPoints();
|
|
const labelList& meshPts = cycPatch.meshPoints();
|
|
|
|
List<T> half0Values(coupledPoints.size());
|
|
List<T> half1Values(coupledPoints.size());
|
|
|
|
forAll(coupledPoints, i)
|
|
{
|
|
const edge& e = coupledPoints[i];
|
|
|
|
label point0 = meshPts[e[0]];
|
|
label point1 = meshPts[e[1]];
|
|
|
|
half0Values[i] = pointValues[point0];
|
|
half1Values[i] = pointValues[point1];
|
|
}
|
|
|
|
if (!cycPatch.parallel())
|
|
{
|
|
hasTransformation = true;
|
|
transformList(cycPatch.reverseT(), half0Values);
|
|
transformList(cycPatch.forwardT(), half1Values);
|
|
}
|
|
else if (applySeparation && cycPatch.separated())
|
|
{
|
|
hasTransformation = true;
|
|
const vectorField& v = cycPatch.coupledPolyPatch::separation();
|
|
separateList(v, half0Values);
|
|
separateList(-v, half1Values);
|
|
}
|
|
|
|
forAll(coupledPoints, i)
|
|
{
|
|
const edge& e = coupledPoints[i];
|
|
|
|
label point0 = meshPts[e[0]];
|
|
label point1 = meshPts[e[1]];
|
|
|
|
cop(pointValues[point0], half1Values[i]);
|
|
cop(pointValues[point1], half0Values[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//- Note: hasTransformation is only used for warning messages so
|
|
// reduction not strictly nessecary.
|
|
//reduce(hasTransformation, orOp<bool>());
|
|
|
|
// Synchronize multiple shared points.
|
|
const globalMeshData& pd = mesh.globalData();
|
|
|
|
if (pd.nGlobalPoints() > 0)
|
|
{
|
|
if (hasTransformation)
|
|
{
|
|
WarningIn
|
|
(
|
|
"syncTools<class T, class CombineOp>::syncPointList"
|
|
"(const polyMesh&, UList<T>&, const CombineOp&, const T&"
|
|
", const bool)"
|
|
) << "There are decomposed cyclics in this mesh with"
|
|
<< " transformations." << endl
|
|
<< "This is not supported. The result will be incorrect"
|
|
<< endl;
|
|
}
|
|
|
|
|
|
// Values on shared points.
|
|
List<T> sharedPts(pd.nGlobalPoints(), nullValue);
|
|
|
|
forAll(pd.sharedPointLabels(), i)
|
|
{
|
|
label meshPointI = pd.sharedPointLabels()[i];
|
|
// Fill my entries in the shared points
|
|
sharedPts[pd.sharedPointAddr()[i]] = pointValues[meshPointI];
|
|
}
|
|
|
|
// Combine on master.
|
|
Pstream::listCombineGather(sharedPts, cop);
|
|
Pstream::listCombineScatter(sharedPts);
|
|
|
|
// Now we will all have the same information. Merge it back with
|
|
// my local information.
|
|
forAll(pd.sharedPointLabels(), i)
|
|
{
|
|
label meshPointI = pd.sharedPointLabels()[i];
|
|
pointValues[meshPointI] = sharedPts[pd.sharedPointAddr()[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::syncPointList
|
|
(
|
|
const polyMesh& mesh,
|
|
const labelList& meshPoints,
|
|
UList<T>& pointValues,
|
|
const CombineOp& cop,
|
|
const T& nullValue,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
if (pointValues.size() != meshPoints.size())
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"syncTools<class T, class CombineOp>::syncPointList"
|
|
"(const polyMesh&, const labelList&, UList<T>&, const CombineOp&"
|
|
", const T&, const bool)"
|
|
) << "Number of values " << pointValues.size()
|
|
<< " is not equal to the number of points "
|
|
<< meshPoints.size() << abort(FatalError);
|
|
}
|
|
|
|
if (!hasCouples(mesh.boundaryMesh()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
List<T> meshValues(mesh.nPoints(), nullValue);
|
|
|
|
forAll(meshPoints, i)
|
|
{
|
|
meshValues[meshPoints[i]] = pointValues[i];
|
|
}
|
|
|
|
syncTools::syncPointList
|
|
(
|
|
mesh,
|
|
meshValues,
|
|
cop, // combine op
|
|
nullValue, // null value
|
|
applySeparation // separation
|
|
);
|
|
|
|
forAll(meshPoints, i)
|
|
{
|
|
pointValues[i] = meshValues[meshPoints[i]];
|
|
}
|
|
}
|
|
|
|
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::syncEdgeList
|
|
(
|
|
const polyMesh& mesh,
|
|
UList<T>& edgeValues,
|
|
const CombineOp& cop,
|
|
const T& nullValue,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
if (edgeValues.size() != mesh.nEdges())
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"syncTools<class T, class CombineOp>::syncEdgeList"
|
|
"(const polyMesh&, UList<T>&, const CombineOp&, const T&"
|
|
", const bool)"
|
|
) << "Number of values " << edgeValues.size()
|
|
<< " is not equal to the number of edges in the mesh "
|
|
<< mesh.nEdges() << abort(FatalError);
|
|
}
|
|
|
|
const polyBoundaryMesh& patches = mesh.boundaryMesh();
|
|
|
|
if (!hasCouples(patches))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Is there any coupled patch with transformation?
|
|
bool hasTransformation = false;
|
|
|
|
if (Pstream::parRun())
|
|
{
|
|
// Send
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].nEdges() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
|
|
const labelList& meshEdges = procPatch.meshEdges();
|
|
const labelList& neighbEdges = procPatch.neighbEdges();
|
|
|
|
// Get region per patch edge in neighbouring edge numbers.
|
|
List<T> patchInfo(procPatch.nEdges(), nullValue);
|
|
|
|
forAll(neighbEdges, edgeI)
|
|
{
|
|
label nbrEdgeI = neighbEdges[edgeI];
|
|
|
|
if (nbrEdgeI >= 0 && nbrEdgeI < patchInfo.size())
|
|
{
|
|
patchInfo[nbrEdgeI] = edgeValues[meshEdges[edgeI]];
|
|
}
|
|
}
|
|
|
|
OPstream toNbr(Pstream::blocking, procPatch.neighbProcNo());
|
|
toNbr << patchInfo;
|
|
}
|
|
}
|
|
|
|
// Receive and combine.
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].nEdges() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
|
|
checkTransform(procPatch, applySeparation);
|
|
|
|
const labelList& meshEdges = procPatch.meshEdges();
|
|
|
|
// Receive from neighbour. Is per patch edge the region of the
|
|
// neighbouring patch edge.
|
|
List<T> nbrPatchInfo(procPatch.nEdges());
|
|
|
|
{
|
|
IPstream fromNeighb
|
|
(
|
|
Pstream::blocking,
|
|
procPatch.neighbProcNo()
|
|
);
|
|
fromNeighb >> nbrPatchInfo;
|
|
}
|
|
// Null any value which is not on neighbouring processor
|
|
label nbrSize = nbrPatchInfo.size();
|
|
nbrPatchInfo.setSize(procPatch.nEdges());
|
|
for
|
|
(
|
|
label i = nbrSize;
|
|
i < procPatch.nEdges();
|
|
i++
|
|
)
|
|
{
|
|
nbrPatchInfo[i] = nullValue;
|
|
}
|
|
|
|
|
|
if (!procPatch.parallel())
|
|
{
|
|
hasTransformation = true;
|
|
transformList(procPatch.forwardT(), nbrPatchInfo);
|
|
}
|
|
else if (applySeparation && procPatch.separated())
|
|
{
|
|
hasTransformation = true;
|
|
separateList(-procPatch.separation(), nbrPatchInfo);
|
|
}
|
|
|
|
forAll(meshEdges, edgeI)
|
|
{
|
|
label meshEdgeI = meshEdges[edgeI];
|
|
|
|
cop(edgeValues[meshEdgeI], nbrPatchInfo[edgeI]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do the cyclics.
|
|
forAll(patches, patchI)
|
|
{
|
|
if (isA<cyclicPolyPatch>(patches[patchI]))
|
|
{
|
|
const cyclicPolyPatch& cycPatch =
|
|
refCast<const cyclicPolyPatch>(patches[patchI]);
|
|
|
|
checkTransform(cycPatch, applySeparation);
|
|
|
|
const edgeList& coupledEdges = cycPatch.coupledEdges();
|
|
const labelList& meshEdges = cycPatch.meshEdges();
|
|
|
|
List<T> half0Values(coupledEdges.size());
|
|
List<T> half1Values(coupledEdges.size());
|
|
|
|
forAll(coupledEdges, i)
|
|
{
|
|
const edge& e = coupledEdges[i];
|
|
|
|
label meshEdge0 = meshEdges[e[0]];
|
|
label meshEdge1 = meshEdges[e[1]];
|
|
|
|
half0Values[i] = edgeValues[meshEdge0];
|
|
half1Values[i] = edgeValues[meshEdge1];
|
|
}
|
|
|
|
if (!cycPatch.parallel())
|
|
{
|
|
hasTransformation = true;
|
|
transformList(cycPatch.reverseT(), half0Values);
|
|
transformList(cycPatch.forwardT(), half1Values);
|
|
}
|
|
else if (applySeparation && cycPatch.separated())
|
|
{
|
|
hasTransformation = true;
|
|
|
|
const vectorField& v = cycPatch.coupledPolyPatch::separation();
|
|
separateList(v, half0Values);
|
|
separateList(-v, half1Values);
|
|
}
|
|
|
|
forAll(coupledEdges, i)
|
|
{
|
|
const edge& e = coupledEdges[i];
|
|
|
|
label meshEdge0 = meshEdges[e[0]];
|
|
label meshEdge1 = meshEdges[e[1]];
|
|
|
|
cop(edgeValues[meshEdge0], half1Values[i]);
|
|
cop(edgeValues[meshEdge1], half0Values[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//- Note: hasTransformation is only used for warning messages so
|
|
// reduction not strictly nessecary.
|
|
//reduce(hasTransformation, orOp<bool>());
|
|
|
|
// Do the multiple shared edges
|
|
const globalMeshData& pd = mesh.globalData();
|
|
|
|
if (pd.nGlobalEdges() > 0)
|
|
{
|
|
if (hasTransformation)
|
|
{
|
|
WarningIn
|
|
(
|
|
"syncTools<class T, class CombineOp>::syncEdgeList"
|
|
"(const polyMesh&, UList<T>&, const CombineOp&, const T&"
|
|
", const bool)"
|
|
) << "There are decomposed cyclics in this mesh with"
|
|
<< " transformations." << endl
|
|
<< "This is not supported. The result will be incorrect"
|
|
<< endl;
|
|
}
|
|
|
|
// Values on shared edges.
|
|
List<T> sharedPts(pd.nGlobalEdges(), nullValue);
|
|
|
|
forAll(pd.sharedEdgeLabels(), i)
|
|
{
|
|
label meshEdgeI = pd.sharedEdgeLabels()[i];
|
|
|
|
// Fill my entries in the shared edges
|
|
sharedPts[pd.sharedEdgeAddr()[i]] = edgeValues[meshEdgeI];
|
|
}
|
|
|
|
// Combine on master.
|
|
Pstream::listCombineGather(sharedPts, cop);
|
|
Pstream::listCombineScatter(sharedPts);
|
|
|
|
// Now we will all have the same information. Merge it back with
|
|
// my local information.
|
|
forAll(pd.sharedEdgeLabels(), i)
|
|
{
|
|
label meshEdgeI = pd.sharedEdgeLabels()[i];
|
|
edgeValues[meshEdgeI] = sharedPts[pd.sharedEdgeAddr()[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::syncBoundaryFaceList
|
|
(
|
|
const polyMesh& mesh,
|
|
UList<T>& faceValues,
|
|
const CombineOp& cop,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
const label nBFaces = mesh.nFaces() - mesh.nInternalFaces();
|
|
|
|
if (faceValues.size() != nBFaces)
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"syncTools<class T, class CombineOp>::syncBoundaryFaceList"
|
|
"(const polyMesh&, UList<T>&, const CombineOp&"
|
|
", const bool)"
|
|
) << "Number of values " << faceValues.size()
|
|
<< " is not equal to the number of boundary faces in the mesh "
|
|
<< nBFaces << abort(FatalError);
|
|
}
|
|
|
|
const polyBoundaryMesh& patches = mesh.boundaryMesh();
|
|
|
|
if (!hasCouples(patches))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
if (Pstream::parRun())
|
|
{
|
|
// Send
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].size() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
|
|
label patchStart = procPatch.start()-mesh.nInternalFaces();
|
|
|
|
if (contiguous<T>())
|
|
{
|
|
OPstream::write
|
|
(
|
|
Pstream::blocking,
|
|
procPatch.neighbProcNo(),
|
|
reinterpret_cast<const char*>(&faceValues[patchStart]),
|
|
procPatch.size()*sizeof(T)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
OPstream toNbr(Pstream::blocking, procPatch.neighbProcNo());
|
|
toNbr <<
|
|
SubList<T>(faceValues, procPatch.size(), patchStart);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Receive and combine.
|
|
|
|
forAll(patches, patchI)
|
|
{
|
|
if
|
|
(
|
|
isA<processorPolyPatch>(patches[patchI])
|
|
&& patches[patchI].size() > 0
|
|
)
|
|
{
|
|
const processorPolyPatch& procPatch =
|
|
refCast<const processorPolyPatch>(patches[patchI]);
|
|
|
|
List<T> nbrPatchInfo(procPatch.size());
|
|
|
|
if (contiguous<T>())
|
|
{
|
|
IPstream::read
|
|
(
|
|
Pstream::blocking,
|
|
procPatch.neighbProcNo(),
|
|
reinterpret_cast<char*>(nbrPatchInfo.begin()),
|
|
nbrPatchInfo.byteSize()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
IPstream fromNeighb
|
|
(
|
|
Pstream::blocking,
|
|
procPatch.neighbProcNo()
|
|
);
|
|
fromNeighb >> nbrPatchInfo;
|
|
}
|
|
|
|
if (!procPatch.parallel())
|
|
{
|
|
transformList(procPatch.forwardT(), nbrPatchInfo);
|
|
}
|
|
else if (applySeparation && procPatch.separated())
|
|
{
|
|
separateList(-procPatch.separation(), nbrPatchInfo);
|
|
}
|
|
|
|
|
|
label bFaceI = procPatch.start()-mesh.nInternalFaces();
|
|
|
|
forAll(nbrPatchInfo, i)
|
|
{
|
|
cop(faceValues[bFaceI++], nbrPatchInfo[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do the cyclics.
|
|
forAll(patches, patchI)
|
|
{
|
|
if (isA<cyclicPolyPatch>(patches[patchI]))
|
|
{
|
|
const cyclicPolyPatch& cycPatch =
|
|
refCast<const cyclicPolyPatch>(patches[patchI]);
|
|
|
|
label patchStart = cycPatch.start()-mesh.nInternalFaces();
|
|
|
|
label half = cycPatch.size()/2;
|
|
label half1Start = patchStart+half;
|
|
|
|
List<T> half0Values(SubList<T>(faceValues, half, patchStart));
|
|
List<T> half1Values(SubList<T>(faceValues, half, half1Start));
|
|
|
|
if (!cycPatch.parallel())
|
|
{
|
|
transformList(cycPatch.reverseT(), half0Values);
|
|
transformList(cycPatch.forwardT(), half1Values);
|
|
}
|
|
else if (applySeparation && cycPatch.separated())
|
|
{
|
|
const vectorField& v = cycPatch.coupledPolyPatch::separation();
|
|
separateList(v, half0Values);
|
|
separateList(-v, half1Values);
|
|
}
|
|
|
|
label i0 = patchStart;
|
|
forAll(half1Values, i)
|
|
{
|
|
cop(faceValues[i0++], half1Values[i]);
|
|
}
|
|
|
|
label i1 = half1Start;
|
|
forAll(half0Values, i)
|
|
{
|
|
cop(faceValues[i1++], half0Values[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <class T, class CombineOp>
|
|
void Foam::syncTools::syncFaceList
|
|
(
|
|
const polyMesh& mesh,
|
|
UList<T>& faceValues,
|
|
const CombineOp& cop,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
if (faceValues.size() != mesh.nFaces())
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"syncTools<class T, class CombineOp>::syncFaceList"
|
|
"(const polyMesh&, UList<T>&, const CombineOp&"
|
|
", const bool)"
|
|
) << "Number of values " << faceValues.size()
|
|
<< " is not equal to the number of faces in the mesh "
|
|
<< mesh.nFaces() << abort(FatalError);
|
|
}
|
|
|
|
SubList<T> bndValues
|
|
(
|
|
faceValues,
|
|
mesh.nFaces()-mesh.nInternalFaces(),
|
|
mesh.nInternalFaces()
|
|
);
|
|
|
|
syncBoundaryFaceList
|
|
(
|
|
mesh,
|
|
bndValues,
|
|
cop,
|
|
applySeparation
|
|
);
|
|
}
|
|
|
|
|
|
template <class T>
|
|
void Foam::syncTools::swapBoundaryFaceList
|
|
(
|
|
const polyMesh& mesh,
|
|
UList<T>& faceValues,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
syncBoundaryFaceList(mesh, faceValues, eqOp<T>(), applySeparation);
|
|
}
|
|
|
|
|
|
template <class T>
|
|
void Foam::syncTools::swapFaceList
|
|
(
|
|
const polyMesh& mesh,
|
|
UList<T>& faceValues,
|
|
const bool applySeparation
|
|
)
|
|
{
|
|
syncFaceList(mesh, faceValues, eqOp<T>(), applySeparation);
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|