Refactoring of load balance: move function into topoChangerFvMesh

This commit is contained in:
Hrvoje Jasak 2018-05-11 18:32:37 +01:00
parent c1f86cba2d
commit a4617cca01
11 changed files with 690 additions and 1075 deletions

View file

@ -1,4 +1,3 @@
dynamicMeshLoadBalance/dynamicMeshLoadBalance.C
loadBalanceFvMesh/loadBalanceFvMesh.C
LIB = $(FOAM_LIBBIN)/libloadBalanceFvMesh

View file

@ -1,11 +1,13 @@
EXE_INC = \
-I$(LIB_SRC)/decompositionMethods/decomposeReconstruct/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/dynamicMesh/dynamicMesh/lnInclude \
-I$(LIB_SRC)/dynamicMesh/dynamicFvMesh/lnInclude
-I$(LIB_SRC)/dynamicMesh/dynamicFvMesh/lnInclude \
-I$(LIB_SRC)/dynamicMesh/topoChangerFvMesh/lnInclude \
-I$(LIB_SRC)/decompositionMethods/decomposeReconstruct/lnInclude
LIB_LIBS = \
-ldecomposeReconstruct\
-lfiniteVolume \
-ldynamicMesh \
-ldynamicFvMesh
-ldynamicFvMesh \
-ltopoChangerFvMesh \
-ldecomposeReconstruct

View file

@ -1,288 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 4.0
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend 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.
foam-extend 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 foam-extend. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "dynamicMeshLoadBalance.H"
#include "volFields.H"
#include "domainDecomposition.H"
#include "fvFieldDecomposer.H"
#include "processorMeshesReconstructor.H"
#include "fvFieldReconstructor.H"
#include "mapPolyMesh.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
// namespace Foam
// {
// defineTypeNameAndDebug(dynamicMeshLoadBalance, 0);
// addToRunTimeSelectionTable
// (
// topoChangerFvMesh,
// dynamicFvMesh,
// IOobject
// );
// }
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::dynamicMeshLoadBalance::dynamicMeshLoadBalance(dynamicFvMesh& mesh)
:
mesh_(mesh),
dict_
(
IOdictionary
(
IOobject
(
"decomposeParDict",
mesh_.time().system(),
mesh_,
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
)
)
),
imbalanceTrigger_(readScalar(dict_.lookup("imbalanceTrigger")))
{
// Check imbalance trigger
if (imbalanceTrigger_ < SMALL || imbalanceTrigger_ > 1)
{
WarningIn
(
"dynamicMeshLoadBalance::"
"dynamicMeshLoadBalance(dynamicFvMesh& mesh)"
) << "Invalid imbalance trigger " << imbalanceTrigger_
<< " Should be between 0 and 1. Resetting to 0.8"
<< endl;
imbalanceTrigger_ = 0.8;
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::dynamicMeshLoadBalance::~dynamicMeshLoadBalance()
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::mapPolyMesh>
Foam::dynamicMeshLoadBalance::updateMesh() const
{
Info<< "Hello from dynamicMeshLoadBalance::updateMesh()" << endl;
// Create a parallel decomposition
domainDecomposition meshDecomp
(
mesh_,
dict_
);
// Decompose the mesh based on processor data
meshDecomp.decomposeMesh(false);
// Analyse mesh decomposition to see how many cells are passed to which processor
labelListList migratedCells(meshDecomp.nProcs());
// Fill local list with number of local cells to be sent to each processor
// First index = my processor. Second index = processor to send to
labelList& curMigratedCells = migratedCells[Pstream::myProcNo()];
curMigratedCells.setSize(Pstream::myProcNo(), 0);
const labelList& cellToProc = meshDecomp.cellToProc();
forAll (cellToProc, cellI)
{
curMigratedCells[cellToProc[cellI]]++;
}
// Now that each processor has filled in its own part, combine the data
Pstream::gatherList(migratedCells);
Pstream::scatterList(migratedCells);
// Reading through second index now tells how many cells will arrive
// from which processor
// Split the mesh and fields over processors and send
for (label procI = 0; procI < meshDecomp.nProcs(); procI++)
{
if (procI != Pstream::myProcNo())
{
Info<< "Processor " << procI << ": send mesh and fields"
<< endl;
// Check if there is a mesh to send
if (curMigratedCells[procI] > 0)
{
// Send mesh and field to processor procI
// Get mesh from decomposition
autoPtr<fvMesh> procMeshPtr = meshDecomp.processorMesh
(
procI,
mesh_.time(),
"processorPart" + name(procI)
);
fvMesh& procMesh = procMeshPtr();
// Create a field decomposer
fvFieldDecomposer fieldDecomposer
(
mesh_,
procMesh,
meshDecomp.procFaceAddressing()[procI],
meshDecomp.procCellAddressing()[procI],
meshDecomp.procBoundaryAddressing()[procI]
);
/*
// Simple test only: rebalance volScalarFields
HashTable<const volScalarField*> volScalarFields =
mesh_.thisDb().lookupClass<volScalarField>();
for
(
HashTable<const volScalarField*>::const_iterator iter =
volScalarFields.begin();
iter != volScalarFields.end();
++iter
)
{
fieldDecomposer.decomposeField(*(iter()));
}
*/
// Note: communication can be optimised. HJ, 27/Feb/2018
OPstream toProc
(
Pstream::nonBlocking,
procI
);
// Send the mesh and fields to target processor
toProc << procMesh;
}
}
}
// Collect pieces of mesh and fields from other processors
// Create a list of processor meshes
// Create the reconstructor
processorMeshesReconstructor meshRecon("reconstructed");
PtrList<fvMesh>& procMeshes = meshRecon.meshes();
procMeshes.setSize(meshDecomp.nProcs());
List<PtrList<volScalarField*> > receiveVolScalarFields
(
meshDecomp.nProcs()
);
for (label procI = 0; procI < meshDecomp.nProcs(); procI++)
{
if (procI != Pstream::myProcNo())
{
// Check if there is a mesh to send
if (migratedCells[procI][Pstream::myProcNo()] > 0)
{
Info<< "Processor " << procI << ": receive mesh and fields"
<< endl;
// Note: communication can be optimised. HJ, 27/Feb/2018
IPstream fromProc
(
Pstream::nonBlocking,
procI
);
// Receive the mesh
procMeshes.set
(
procI,
new fvMesh
(
IOobject
(
"processorPart" + name(procI),
mesh_.time().timeName(),
mesh_.time(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
fromProc,
false // Do not sync
)
);
// Receive the fields
}
}
else
{
// Insert own mesh
}
}
// Create the reconstructed mesh
autoPtr<fvMesh> reconstructedMeshPtr =
meshRecon.reconstructMesh(mesh_.time());
const fvMesh& reconstructedMesh = reconstructedMeshPtr();
// Create field reconstructor
fvFieldReconstructor fieldReconstructor
(
mesh_,
procMeshes,
meshRecon.faceProcAddressing(),
meshRecon.cellProcAddressing(),
meshRecon.boundaryProcAddressing()
);
// Create mapPolyMesh
// DUMMY!!!
autoPtr<mapPolyMesh> tmpm(new mapPolyMesh(mesh_));
return tmpm;
}
// ************************************************************************* //

View file

@ -1,145 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 4.0
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend 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.
foam-extend 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 foam-extend. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::dynamicMeshLoadBalance
Description
Dynamic mesh load balance class.
The modifier will examine the weighted imbalance in the mesh to determine
when the load distribution is no longer satisfactory.
Imbalance is measured as a weighted field over all cells and is checked over
a parallel decomposition
When load balance is detected:
- parallel-aware decompositionMethod to receive the cell-to-processor
assignment on each processor
- polyMesh is split into parts and point, face, cell, boundary addressing
objects are created
- tools equivalent to decomposePar are used to split up the original mesh
into processor parts
- for each processor piece:
- the new mesh is built, ready to be transferred to a processor
- fields are subset onto each processor mesh
- mesh and fields are passed onto the target processor
- ALL DECOMPOSITION PIECES ARE CLEARED AFTER SEND, AND RE-USED ONTO RECEIVE
- processor pieces are received from all components
- new mesh is built by inserting processor pieces in order of processors
- for each processor piece:
- if different from myProcNo, point, face, cell, boundary addressing
objects are created
- if equal to myProcNo, a mapPolyMesh object is assembled
- once the complete mesh is built, updateMesh is called on the local
processor. This will re-map local data and re-size the fields
- when completed, tools equivalent to reconstructPar are used to rebuild
the parts of fields from other processors
SourceFiles
dynamicMeshLoadBalance.C
dynamicMeshLoadBalanceIO.C
\*---------------------------------------------------------------------------*/
#ifndef dynamicMeshLoadBalance_H
#define dynamicMeshLoadBalance_H
#include "dynamicFvMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
/*---------------------------------------------------------------------------*\
Class dynamicMeshLoadBalance Declaration
\*---------------------------------------------------------------------------*/
class dynamicMeshLoadBalance
{
// Private data
//- Dynamic mesh reference
dynamicFvMesh& mesh_;
//- Decomposition dictionary
IOdictionary dict_;
//- Imbalance trigger 0 < imbalance < 1
scalar imbalanceTrigger_;
// Private Member Functions
//- Disallow default bitwise copy construct
dynamicMeshLoadBalance(const dynamicMeshLoadBalance&);
//- Disallow default bitwise assignment
void operator=(const dynamicMeshLoadBalance&);
//- Send mesh to other processor
static void sendMesh
(
const fvMesh& mesh,
Ostream& os
);
public:
// //- Runtime type information
// TypeName("testLoadBalanceFvMesh");
// Constructors
//- Construct from dynamic mesh
dynamicMeshLoadBalance(dynamicFvMesh&);
//- Destructor
~dynamicMeshLoadBalance();
// Member Functions
//- Check balance. Return true if re-balancing is required
bool checkLoadBalance(const scalarField& weights) const;
//- Update mesh
autoPtr<mapPolyMesh> updateMesh() const;
//- Update fields
void updateFields() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -31,7 +31,7 @@ License
#include "mapPolyMesh.H"
#include "addToRunTimeSelectionTable.H"
#include "GeoMesh.H"
#include "passiveProcessorPolyPatch.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -82,8 +82,8 @@ bool Foam::loadBalanceFvMesh::checkLoadBalance
Foam::loadBalanceFvMesh::loadBalanceFvMesh(const IOobject& io)
:
dynamicFvMesh(io),
dynamicMeshCoeffs_
topoChangerFvMesh(io),
dict_
(
IOdictionary
(
@ -99,7 +99,7 @@ Foam::loadBalanceFvMesh::loadBalanceFvMesh(const IOobject& io)
),
imbalanceTrigger_
(
readScalar(dynamicMeshCoeffs_.lookup("imbalanceTrigger"))
readScalar(dict_.lookup("imbalanceTrigger"))
)
{
// Check imbalance trigger
@ -128,579 +128,17 @@ Foam::loadBalanceFvMesh::~loadBalanceFvMesh()
bool Foam::loadBalanceFvMesh::update()
{
if (!Pstream::parRun())
if (Pstream::parRun())
{
InfoIn("bool loadBalanceFvMesh::update()")
<< "Load balancing a serial run. Skipping."
<< endl;
// Decide when to balance here
return false;
}
// Check imbalance. Note: add run-time selection for the imbalance
// weights criterion
// Create a parallel decomposition
domainDecomposition meshDecomp
(
*this,
dynamicMeshCoeffs_
);
// Decompose the mesh based on processor data
meshDecomp.decomposeMesh(false);
// Analyse mesh decomposition to see how many cells are passed
// to which processor
labelListList migratedCells(meshDecomp.nProcs());
// Fill local list with number of local cells to be sent to each processor
// First index = my processor. Second index = processor to send to
labelList& curMigratedCells = migratedCells[Pstream::myProcNo()];
curMigratedCells.setSize(Pstream::nProcs(), 0);
const labelList& cellToProc = meshDecomp.cellToProc();
// Write as volScalarField for post-processing
volScalarField cellDist
(
IOobject
(
"cellDist",
time().timeName(),
*this,
IOobject::NO_READ,
IOobject::NO_WRITE
),
*this,
dimensionedScalar("cellDist", dimless, 0),
zeroGradientFvPatchScalarField::typeName
);
forAll(cellToProc, celli)
{
cellDist[celli] = cellToProc[celli];
}
cellDist.write();
forAll (cellToProc, cellI)
{
curMigratedCells[cellToProc[cellI]]++;
}
// Now that each processor has filled in its own part, combine the data
Pstream::gatherList(migratedCells);
Pstream::scatterList(migratedCells);
// Reading through second index now tells how many cells will arrive
// from which processor
// Find out which processor faces will become local internal faces
// by comparing decomposition index from the other side
// Split the mesh and fields over processors and send
// Prepare receiving side
// Create the reconstructor
processorMeshesReconstructor meshRecon("reconstructed");
PtrList<fvMesh>& procMeshes = meshRecon.meshes();
procMeshes.setSize(meshDecomp.nProcs());
// Collect local fields for decomposition
clearOut();
// Collect fields for load balancing
HashTable<const volScalarField*> volScalarFields =
thisDb().lookupClass<volScalarField>();
Pout<< "volScalarFields: " << volScalarFields.sortedToc() << endl;
HashTable<const volVectorField*>volVectorFields =
thisDb().lookupClass<volVectorField>();
Pout<< "volVectorFields: " << volVectorFields.sortedToc() << endl;
HashTable<const surfaceScalarField*> surfaceScalarFields =
thisDb().lookupClass<surfaceScalarField>();
Pout<< "surfaceScalarFields: " << surfaceScalarFields.sortedToc() << endl;
//HJ, HERE: remove the fields that should not be load balanced
// Prepare fields for reconstruction
// First index: field index from volScalarFields
// Second index: processor entry for the field
List<PtrList<volScalarField> > receivedVolScalarFields
(
volScalarFields.size()
);
List<PtrList<volVectorField> > receivedVolVectorFields
(
volVectorFields.size()
);
List<PtrList<surfaceScalarField> > receivedSurfaceScalarFields
(
surfaceScalarFields.size()
);
forAll (receivedVolScalarFields, fieldI)
{
receivedVolScalarFields[fieldI].setSize(Pstream::nProcs());
}
forAll (receivedVolVectorFields, fieldI)
{
receivedVolVectorFields[fieldI].setSize(Pstream::nProcs());
}
forAll (receivedSurfaceScalarFields, fieldI)
{
receivedSurfaceScalarFields[fieldI].setSize(Pstream::nProcs());
}
for (label procI = 0; procI < meshDecomp.nProcs(); procI++)
{
// Check if there is a mesh to send
if (curMigratedCells[procI] > 0)
{
// Send mesh and field to processor procI
// Get mesh from decomposition
autoPtr<fvMesh> procMeshPtr = meshDecomp.processorMesh
(
procI,
time(),
"processorPart" + Foam::name(procI),
true // Create passive processor patches
);
fvMesh& procMesh = procMeshPtr();
// Create a field decomposer
fvFieldDecomposer fieldDecomposer
(
*this,
procMesh,
meshDecomp.procFaceAddressing()[procI],
meshDecomp.procCellAddressing()[procI],
meshDecomp.procBoundaryAddressing()[procI]
);
if (procI != Pstream::myProcNo())
{
Pout<< "Send mesh and fields to processor " << procI << endl;
OPstream toProc
(
Pstream::blocking,
procI
);
// Send the mesh and fields to target processor
toProc << procMesh << nl;
// Send fields
sendFields(volScalarFields, fieldDecomposer, toProc);
sendFields(volVectorFields, fieldDecomposer, toProc);
sendFields(surfaceScalarFields, fieldDecomposer, toProc);
return loadBalance(dict_);
}
else
{
// My processor. Grab mesh and fields
// Note: procI == Pstream::myProcNo()
// HJ, 26/Apr/2018
// Set local mesh piece
procMeshes.set
(
procI,
procMeshPtr
);
// Set local fields
// Note: first index is field index and second index is procI
insertFields
(
volScalarFields,
fieldDecomposer,
receivedVolScalarFields
);
insertFields
(
volVectorFields,
fieldDecomposer,
receivedVolVectorFields
);
insertFields
(
surfaceScalarFields,
fieldDecomposer,
receivedSurfaceScalarFields
);
// Serial run: no balancing
return false;
}
}
}
// Collect pieces of mesh and fields from other processors
for (label procI = 0; procI < meshDecomp.nProcs(); procI++)
{
if (procI != Pstream::myProcNo())
{
// Check if there is a mesh to send
if (migratedCells[procI][Pstream::myProcNo()] > 0)
{
Pout<< "Receive mesh and fields from " << procI
<< endl;
// Note: communication can be optimised. HJ, 27/Feb/2018
IPstream fromProc
(
Pstream::blocking,
procI
);
// Receive the mesh
procMeshes.set
(
procI,
new fvMesh
(
IOobject
(
"processorPart" + Foam::name(procI),
time().timeName(),
time(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
fromProc,
false // Do not sync
)
);
// Receive fields
// Note: first index is field index and second index is procI
receiveFields
(
procI,
receivedVolScalarFields,
procMeshes[procI],
fromProc
);
receiveFields
(
procI,
receivedVolVectorFields,
procMeshes[procI],
fromProc
);
receiveFields
(
procI,
receivedSurfaceScalarFields,
procMeshes[procI],
fromProc
);
}
}
}
// Create the reconstructed mesh
autoPtr<fvMesh> reconstructedMeshPtr =
meshRecon.reconstructMesh(time());
fvMesh& reconMesh = reconstructedMeshPtr();
Pout<< "Reconstructed mesh stats: "
<< " nCells: " << reconMesh.nCells()
<< " polyPatches: "
<< reconMesh.boundaryMesh().size()
<< " patches: "
<< reconMesh.boundary().size()
<< endl;
// Apply changes to the local mesh:
// - refactor the boundary to match new patches. Note: processor
// patch types may be added or removed
// - reset all primitives
// Use non-const access to boundaryMesh
polyBoundaryMesh& bMesh = const_cast<polyBoundaryMesh&>(boundaryMesh());
const polyBoundaryMesh& reconBMesh = reconMesh.boundaryMesh();
// Resize the existing boundary to match in the number of patches
if (bMesh.size() > reconBMesh.size())
{
// Decreasing in size: check patches that are due to disappear
// Check before resizing: only processor patches may be deleted
bool okToDelete = true;
for (label patchI = reconBMesh.size(); patchI < bMesh.size(); patchI++)
{
if (!isA<processorPolyPatch>(bMesh[patchI]))
{
okToDelete = false;
break;
}
}
if (!okToDelete)
{
FatalErrorIn("bool loadBalanceFvMesh::update()")
<< "Boundary resizing error: deleting non-processor patches "
<< bMesh.size() << " to " << reconBMesh.size() << nl
<< "old patch types: " << bMesh.types() << nl
<< "new patch types: " << reconBMesh.types() << nl
<< "This is not allowed."
<< abort(FatalError);
}
// Resize the boundary. Patches hanging off the end of the list
// will be deleted by PtrList
bMesh.setSize(reconBMesh.size());
}
else if (bMesh.size() < reconBMesh.size())
{
// Increasing in size: check patches that are due to disappear
bMesh.setSize(reconBMesh.size());
}
// Delete processor patches from old boundary
boolList patchFlag(bMesh.size(), false);
forAll (bMesh, patchI)
{
// If the patch is not set, the slot is available for re-use
if (!bMesh.set(patchI))
{
patchFlag[patchI] = true;
}
else if (isA<processorPolyPatch>(bMesh[patchI]))
{
// If the patch is set and contains an "old" processor patch
// the old patch will be deleted and replaced with a new one
patchFlag[patchI] = true;
}
}
// Store the resetFvPatchFlag to indicate patches that will be rebuilt
// patchFlag will be used in further signalling
boolList resetFvPatchFlag = patchFlag;
// Check alignment and types of old and new boundary
// Insert new patches processor patches
// Collect patch sizes and starts
labelList reconPatchSizes(reconBMesh.size(), 0);
forAll (bMesh, patchI)
{
// If the patch is preserved, types need to match
if (!patchFlag[patchI])
{
const polyPatch& bPatch = bMesh[patchI];
const polyPatch& reconBPatch = reconBMesh[patchI];
// Check if the patch is matching
if
(
bPatch.type() != reconBPatch.type()
|| bPatch.name() != reconBPatch.name()
)
{
FatalErrorIn("bool loadBalanceFvMesh::update()")
<< "Patch names or types not matching for index "
<< patchI << nl
<< "bMesh name: " << bPatch.name()
<< " type: " << bPatch.type() << nl
<< "reconBMesh name: " << reconBPatch.name()
<< " type: " << reconBPatch.type() << nl
<< abort(FatalError);
}
// Record patch size
reconPatchSizes[patchI] = reconBMesh[patchI].size();
}
}
// Insert new processor patches
// Note:
// The code is set up so that any intermediate empty boundary patch
// slots are re-used. It is expected that the new patches will be
// added at the end, so this is safety.
// As a result, patch sizes and starts need to be re-assembled
// rather than used directly from reconBMesh
// HJ, 16/Apr/2018
forAll (reconBMesh, reconPatchI)
{
if (isA<processorPolyPatch>(reconBMesh[reconPatchI]))
{
// Find a slot to insert into
label nextPatchSlot = 0;
for
(
nextPatchSlot = 0;
nextPatchSlot < patchFlag.size();
nextPatchSlot++
)
{
if (patchFlag[nextPatchSlot])
{
// Found a patch slot
break;
}
}
if (nextPatchSlot >= patchFlag.size())
{
FatalErrorIn("bool loadBalanceFvMesh::update()")
<< "Cannot find available patch slot: " << nextPatchSlot
<< abort(FatalError);
}
// Insert a patch
const processorPolyPatch& ppPatch =
refCast<const processorPolyPatch>
(
reconBMesh[reconPatchI]
);
// Note:
// The new mesh has not been reset. Therefore, sizes and starts
// cannot be set properly until the mesh is reset
// This is done in the resetPrimitives function
// HJ, 16/Apr/2018
bMesh.set
(
nextPatchSlot,
new processorPolyPatch
(
// ppPatch.name(),
"procBoundary" + Foam::name(ppPatch.myProcNo()) + "to"
+ Foam::name(ppPatch.neighbProcNo()),
0, // dummy size
nInternalFaces(), // dummy start
// ppPatch.size(),
// ppPatch.start(),
nextPatchSlot,
bMesh,
ppPatch.myProcNo(),
ppPatch.neighbProcNo()
)
);
// Mark patch slot as used
patchFlag[nextPatchSlot] = false;
// Collect size
reconPatchSizes[nextPatchSlot] = reconBMesh[reconPatchI].size();
}
}
// Patch sizes are assembled. Collect patch starts for the new mesh
labelList reconPatchStarts(reconBMesh.size(), 0);
if (!reconPatchStarts.empty())
{
reconPatchStarts[0] = reconMesh.nInternalFaces();
for (label i = 1; i < reconPatchStarts.size(); i++)
{
reconPatchStarts[i] =
reconPatchStarts[i - 1]
+ reconPatchSizes[i - 1];
}
}
// Reset fvMesh and patches
resetFvPrimitives
(
xferCopy(reconMesh.allPoints()),
xferCopy(reconMesh.allFaces()),
xferCopy(reconMesh.faceOwner()),
xferCopy(reconMesh.faceNeighbour()),
reconPatchSizes,
reconPatchStarts,
resetFvPatchFlag,
true // Valid boundary
);
Pout<< "New mesh: points " << nPoints()
<< " faces: " << nFaces()
<< " internal: " << nInternalFaces()
<< " cells: " << nCells()
<< " patches: " << reconPatchSizes.size() << endl;
forAll (procMeshes, procI)
{
Pout<< "procMesh " << procI
<< " points " << procMeshes[procI].nPoints()
<< " faces: " << procMeshes[procI].nFaces()
<< " internal: " << procMeshes[procI].nInternalFaces()
<< " cells: " << procMeshes[procI].nCells()
<< " patches: " << procMeshes[procI].boundary().size()
<< endl;
}
// Pout<< "RECON face: " << meshRecon.faceProcAddressing() << nl
// << " cell: " << meshRecon.cellProcAddressing() << nl
// << " boundary: " << meshRecon.boundaryProcAddressing() << nl
// << endl;
// To Do: build a reconstructor from addressing data
Pout<< nl << nl
<< "FINISHED CYCLE" << nl << nl << nl
<< endl;
// Create a dummy mapping object to re-size all fields
// Create field reconstructor
fvFieldReconstructor fieldReconstructor
(
*this,
procMeshes,
meshRecon.faceProcAddressing(),
meshRecon.cellProcAddressing(),
meshRecon.boundaryProcAddressing()
);
// Rebuild fields
rebuildFields
(
volScalarFields,
fieldReconstructor,
receivedVolScalarFields,
resetFvPatchFlag
);
rebuildFields
(
volVectorFields,
fieldReconstructor,
receivedVolVectorFields,
resetFvPatchFlag
);
rebuildFields
(
surfaceScalarFields,
fieldReconstructor,
receivedSurfaceScalarFields,
resetFvPatchFlag
);
return true;
}

View file

@ -35,7 +35,7 @@ SourceFiles
#ifndef loadBalanceFvMesh_H
#define loadBalanceFvMesh_H
#include "dynamicFvMesh.H"
#include "topoChangerFvMesh.H"
#include "dictionary.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -49,12 +49,12 @@ namespace Foam
class loadBalanceFvMesh
:
public dynamicFvMesh
public topoChangerFvMesh
{
// Private data
//- Dictionary of motion control parameters
dictionary dynamicMeshCoeffs_;
dictionary dict_;
//- Imbalance trigger 0 < imbalance < 1
scalar imbalanceTrigger_;
@ -71,44 +71,6 @@ class loadBalanceFvMesh
//- Check balance. Return true if re-balancing is required
bool checkLoadBalance(const scalarField& weights) const;
//- Send fields to other processor
template<class GeoField, class Decomposer>
void sendFields
(
const HashTable<const GeoField*>& geoFields,
const Decomposer& decomposer,
Ostream& toProc
) const;
//- Insert local fields
template<class GeoField, class Decomposer>
void insertFields
(
const HashTable<const GeoField*>& geoFields,
const Decomposer& decomposer,
List<PtrList<GeoField> >& localFields
) const;
//- Receive fields from other processor
template<class GeoMesh, class GeoField>
void receiveFields
(
const label procIndex,
List<PtrList<GeoField> >& receivedFields,
const GeoMesh& procMesh,
Istream& fromProc
) const;
//- Resize and rebuild fields
template<class GeoField, class Reconstructor>
void rebuildFields
(
const HashTable<const GeoField*>& geoFields,
const Reconstructor& reconstructor,
const List<PtrList<GeoField> >& receivedFields,
const boolList& patchesToReplace
) const;
public:
@ -133,12 +95,6 @@ public:
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
# include "loadBalanceFvMeshTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam

View file

@ -1,4 +1,5 @@
topoChangerFvMesh/topoChangerFvMesh.C
topoChangerFvMesh/topoChangerFvMeshLoadBalance.C
attachDetachFvMesh/attachDetachFvMesh.C
linearValveFvMesh/linearValveFvMesh.C

View file

@ -3,6 +3,7 @@ EXE_INC = \
-I$(LIB_SRC)/dynamicMesh/dynamicFvMesh/lnInclude \
-I$(LIB_SRC)/dynamicMesh/dynamicMesh/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/decompositionMethods/decomposeReconstruct/lnInclude \
-I$(LIB_SRC)/dynamicMesh/meshMotion/solidBodyMotion/lnInclude \
-I$(LIB_SRC)/tetFiniteElement/lnInclude \
-I$(LIB_SRC)/dynamicMesh/meshMotion/tetMotionSolver/lnInclude
@ -12,6 +13,7 @@ LIB_LIBS = \
-ldynamicFvMesh \
-ldynamicMesh \
-lmeshTools \
-ldecomposeReconstruct \
-lsolidBodyMotion \
-ltetFiniteElement \
-ltetMotionSolver

View file

@ -30,6 +30,8 @@ Description
SourceFiles
topoChangerFvMesh.C
newTopoFvMesh.C
topoChangerFvMeshLoadBalance.C
topoChangerFvMeshLoadBalanceTemplates.C
\*---------------------------------------------------------------------------*/
@ -61,10 +63,52 @@ class topoChangerFvMesh
void operator=(const topoChangerFvMesh&);
// Load balancing functions
//- Send fields to other processor
template<class GeoField, class Decomposer>
void sendFields
(
const HashTable<const GeoField*>& geoFields,
const Decomposer& decomposer,
Ostream& toProc
) const;
//- Insert local fields
template<class GeoField, class Decomposer>
void insertFields
(
const HashTable<const GeoField*>& geoFields,
const Decomposer& decomposer,
List<PtrList<GeoField> >& localFields
) const;
//- Receive fields from other processor
template<class GeoMesh, class GeoField>
void receiveFields
(
const label procIndex,
List<PtrList<GeoField> >& receivedFields,
const GeoMesh& procMesh,
Istream& fromProc
) const;
//- Resize and rebuild fields
template<class GeoField, class Reconstructor>
void rebuildFields
(
const HashTable<const GeoField*>& geoFields,
const Reconstructor& reconstructor,
const List<PtrList<GeoField> >& receivedFields,
const boolList& patchesToReplace
) const;
protected:
// Protected Data
//- Topo changer
polyTopoChanger topoChanger_;
@ -106,18 +150,26 @@ public:
);
// Destructor
//- Destructor
virtual ~topoChangerFvMesh();
// Member Functions
//- Load balance the mesh in parallel execution
bool loadBalance(const dictionary& dict);
//- Update the mesh for both mesh motion and topology change
virtual bool update() = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
# include "topoChangerFvMeshLoadBalanceTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam

View file

@ -0,0 +1,602 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 4.0
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend 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.
foam-extend 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 foam-extend. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "topoChangerFvMesh.H"
#include "domainDecomposition.H"
#include "fvFieldDecomposer.H"
#include "processorMeshesReconstructor.H"
#include "fvFieldReconstructor.H"
#include "mapPolyMesh.H"
#include "addToRunTimeSelectionTable.H"
#include "passiveProcessorPolyPatch.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::topoChangerFvMesh::loadBalance(const dictionary& decompDict)
{
if (!Pstream::parRun())
{
InfoIn("bool topoChangerFvMesh::loadBalance()")
<< "Load balancing a serial run. Skipping."
<< endl;
return false;
}
// Check imbalance. Note: add run-time selection for the imbalance
// weights criterion
// Create a parallel decomposition
domainDecomposition meshDecomp
(
*this,
decompDict
);
// Decompose the mesh based on processor data
meshDecomp.decomposeMesh(false);
// Analyse mesh decomposition to see how many cells are passed
// to which processor
labelListList migratedCells(meshDecomp.nProcs());
// Fill local list with number of local cells to be sent to each processor
// First index = my processor. Second index = processor to send to
labelList& curMigratedCells = migratedCells[Pstream::myProcNo()];
curMigratedCells.setSize(Pstream::nProcs(), 0);
const labelList& cellToProc = meshDecomp.cellToProc();
// // Write as volScalarField for post-processing
// volScalarField cellDist
// (
// IOobject
// (
// "cellDist",
// time().timeName(),
// *this,
// IOobject::NO_READ,
// IOobject::NO_WRITE
// ),
// *this,
// dimensionedScalar("cellDist", dimless, 0),
// zeroGradientFvPatchScalarField::typeName
// );
// forAll(cellToProc, celli)
// {
// cellDist[celli] = cellToProc[celli];
// }
// cellDist.write();
// Count migrated cells
forAll (cellToProc, cellI)
{
curMigratedCells[cellToProc[cellI]]++;
}
// Now that each processor has filled in its own part, combine the data
Pstream::gatherList(migratedCells);
Pstream::scatterList(migratedCells);
Info<< "Migrated cells per processor: " << migratedCells << endl;
// Reading through second index now tells how many cells will arrive
// from which processor
// Find out which processor faces will become local internal faces
// by comparing decomposition index from the other side
// Split the mesh and fields over processors and send
// Prepare receiving side
// Create the reconstructor
processorMeshesReconstructor meshRecon("reconstructed");
PtrList<fvMesh>& procMeshes = meshRecon.meshes();
procMeshes.setSize(meshDecomp.nProcs());
// Collect local fields for decomposition
clearOut();
// Collect fields for load balancing
HashTable<const volScalarField*> volScalarFields =
thisDb().lookupClass<volScalarField>();
HashTable<const volVectorField*>volVectorFields =
thisDb().lookupClass<volVectorField>();
HashTable<const surfaceScalarField*> surfaceScalarFields =
thisDb().lookupClass<surfaceScalarField>();
//HJ, HERE: remove the fields that should not be load balanced
// Prepare fields for reconstruction
// First index: field index from volScalarFields
// Second index: processor entry for the field
List<PtrList<volScalarField> > receivedVolScalarFields
(
volScalarFields.size()
);
List<PtrList<volVectorField> > receivedVolVectorFields
(
volVectorFields.size()
);
List<PtrList<surfaceScalarField> > receivedSurfaceScalarFields
(
surfaceScalarFields.size()
);
forAll (receivedVolScalarFields, fieldI)
{
receivedVolScalarFields[fieldI].setSize(Pstream::nProcs());
}
forAll (receivedVolVectorFields, fieldI)
{
receivedVolVectorFields[fieldI].setSize(Pstream::nProcs());
}
forAll (receivedSurfaceScalarFields, fieldI)
{
receivedSurfaceScalarFields[fieldI].setSize(Pstream::nProcs());
}
for (label procI = 0; procI < meshDecomp.nProcs(); procI++)
{
// Check if there is a mesh to send
if (curMigratedCells[procI] > 0)
{
// Send mesh and field to processor procI
// Get mesh from decomposition
autoPtr<fvMesh> procMeshPtr = meshDecomp.processorMesh
(
procI,
time(),
"processorPart" + Foam::name(procI),
true // Create passive processor patches
);
fvMesh& procMesh = procMeshPtr();
// Create a field decomposer
fvFieldDecomposer fieldDecomposer
(
*this,
procMesh,
meshDecomp.procFaceAddressing()[procI],
meshDecomp.procCellAddressing()[procI],
meshDecomp.procBoundaryAddressing()[procI]
);
if (procI != Pstream::myProcNo())
{
// Pout<< "Send mesh and fields to processor " << procI << endl;
OPstream toProc
(
Pstream::blocking,
procI
);
// Send the mesh and fields to target processor
toProc << procMesh << nl;
// Send fields
sendFields(volScalarFields, fieldDecomposer, toProc);
sendFields(volVectorFields, fieldDecomposer, toProc);
sendFields(surfaceScalarFields, fieldDecomposer, toProc);
}
else
{
// My processor. Grab mesh and fields
// Note: procI == Pstream::myProcNo()
// HJ, 26/Apr/2018
// Pout<< "Set local mesh and fields" << endl;
// Set local mesh piece
procMeshes.set
(
procI,
procMeshPtr
);
// Set local fields
// Note: first index is field index and second index is procI
insertFields
(
volScalarFields,
fieldDecomposer,
receivedVolScalarFields
);
insertFields
(
volVectorFields,
fieldDecomposer,
receivedVolVectorFields
);
insertFields
(
surfaceScalarFields,
fieldDecomposer,
receivedSurfaceScalarFields
);
}
}
}
// Collect pieces of mesh and fields from other processors
for (label procI = 0; procI < meshDecomp.nProcs(); procI++)
{
if (procI != Pstream::myProcNo())
{
// Check if there is a mesh to send
if (migratedCells[procI][Pstream::myProcNo()] > 0)
{
// Pout<< "Receive mesh and fields from " << procI
// << endl;
// Note: communication can be optimised. HJ, 27/Feb/2018
IPstream fromProc
(
Pstream::blocking,
procI
);
// Receive the mesh
procMeshes.set
(
procI,
new fvMesh
(
IOobject
(
"processorPart" + Foam::name(procI),
time().timeName(),
time(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
fromProc,
false // Do not sync
)
);
// Receive fields
// Note: first index is field index and second index is procI
receiveFields
(
procI,
receivedVolScalarFields,
procMeshes[procI],
fromProc
);
receiveFields
(
procI,
receivedVolVectorFields,
procMeshes[procI],
fromProc
);
receiveFields
(
procI,
receivedSurfaceScalarFields,
procMeshes[procI],
fromProc
);
}
}
}
forAll (procMeshes, procI)
{
if (procMeshes.set(procI))
{
Pout<< "procMesh " << procI
<< " points " << procMeshes[procI].nPoints()
<< " faces: " << procMeshes[procI].nFaces()
<< " internal: " << procMeshes[procI].nInternalFaces()
<< " cells: " << procMeshes[procI].nCells()
<< " patches: " << procMeshes[procI].boundary().size()
<< endl;
}
}
// Create the reconstructed mesh
autoPtr<fvMesh> reconstructedMeshPtr =
meshRecon.reconstructMesh(time());
fvMesh& reconMesh = reconstructedMeshPtr();
Pout<< "Reconstructed mesh stats: "
<< " nCells: " << reconMesh.nCells()
<< " polyPatches: "
<< reconMesh.boundaryMesh().size()
<< " patches: "
<< reconMesh.boundary().size()
<< endl;
// Apply changes to the local mesh:
// - refactor the boundary to match new patches. Note: processor
// patch types may be added or removed
// - reset all primitives
// Use non-const access to boundaryMesh
polyBoundaryMesh& bMesh = const_cast<polyBoundaryMesh&>(boundaryMesh());
const polyBoundaryMesh& reconBMesh = reconMesh.boundaryMesh();
// Resize the existing boundary to match in the number of patches
if (bMesh.size() > reconBMesh.size())
{
// Decreasing in size: check patches that are due to disappear
// Check before resizing: only processor patches may be deleted
bool okToDelete = true;
for (label patchI = reconBMesh.size(); patchI < bMesh.size(); patchI++)
{
if (!isA<processorPolyPatch>(bMesh[patchI]))
{
okToDelete = false;
break;
}
}
if (!okToDelete)
{
FatalErrorIn("bool topoChangerFvMesh::loadBalance()")
<< "Boundary resizing error: deleting non-processor patches "
<< bMesh.size() << " to " << reconBMesh.size() << nl
<< "old patch types: " << bMesh.types() << nl
<< "new patch types: " << reconBMesh.types() << nl
<< "This is not allowed."
<< abort(FatalError);
}
// Resize the boundary. Patches hanging off the end of the list
// will be deleted by PtrList
bMesh.setSize(reconBMesh.size());
}
else if (bMesh.size() < reconBMesh.size())
{
// Increasing in size: check patches that are due to disappear
bMesh.setSize(reconBMesh.size());
}
// Delete processor patches from old boundary
boolList patchFlag(bMesh.size(), false);
forAll (bMesh, patchI)
{
// If the patch is not set, the slot is available for re-use
if (!bMesh.set(patchI))
{
patchFlag[patchI] = true;
}
else if (isA<processorPolyPatch>(bMesh[patchI]))
{
// If the patch is set and contains an "old" processor patch
// the old patch will be deleted and replaced with a new one
patchFlag[patchI] = true;
}
}
// Store the resetFvPatchFlag to indicate patches that will be rebuilt
// patchFlag will be used in further signalling
boolList resetFvPatchFlag = patchFlag;
// Check alignment and types of old and new boundary
// Insert new patches processor patches
// Collect patch sizes and starts
labelList reconPatchSizes(reconBMesh.size(), 0);
forAll (bMesh, patchI)
{
// If the patch is preserved, types need to match
if (!patchFlag[patchI])
{
const polyPatch& bPatch = bMesh[patchI];
const polyPatch& reconBPatch = reconBMesh[patchI];
// Check if the patch is matching
if
(
bPatch.type() != reconBPatch.type()
|| bPatch.name() != reconBPatch.name()
)
{
FatalErrorIn("bool topoChangerFvMesh::loadBalance()")
<< "Patch names or types not matching for index "
<< patchI << nl
<< "bMesh name: " << bPatch.name()
<< " type: " << bPatch.type() << nl
<< "reconBMesh name: " << reconBPatch.name()
<< " type: " << reconBPatch.type() << nl
<< abort(FatalError);
}
// Record patch size
reconPatchSizes[patchI] = reconBMesh[patchI].size();
}
}
// Insert new processor patches
// Note:
// The code is set up so that any intermediate empty boundary patch
// slots are re-used. It is expected that the new patches will be
// added at the end, so this is safety.
// As a result, patch sizes and starts need to be re-assembled
// rather than used directly from reconBMesh
// HJ, 16/Apr/2018
forAll (reconBMesh, reconPatchI)
{
if (isA<processorPolyPatch>(reconBMesh[reconPatchI]))
{
// Find a slot to insert into
label nextPatchSlot = 0;
for
(
nextPatchSlot = 0;
nextPatchSlot < patchFlag.size();
nextPatchSlot++
)
{
if (patchFlag[nextPatchSlot])
{
// Found a patch slot
break;
}
}
if (nextPatchSlot >= patchFlag.size())
{
FatalErrorIn("bool topoChangerFvMesh::loadBalance()")
<< "Cannot find available patch slot: " << nextPatchSlot
<< abort(FatalError);
}
// Insert a patch
const processorPolyPatch& ppPatch =
refCast<const processorPolyPatch>
(
reconBMesh[reconPatchI]
);
// Note:
// The new mesh has not been reset. Therefore, sizes and starts
// cannot be set properly until the mesh is reset
// This is done in the resetPrimitives function
// HJ, 16/Apr/2018
bMesh.set
(
nextPatchSlot,
new processorPolyPatch
(
// ppPatch.name(),
"procBoundary" + Foam::name(ppPatch.myProcNo()) + "to"
+ Foam::name(ppPatch.neighbProcNo()),
0, // dummy size
nInternalFaces(), // dummy start
// ppPatch.size(),
// ppPatch.start(),
nextPatchSlot,
bMesh,
ppPatch.myProcNo(),
ppPatch.neighbProcNo()
)
);
// Mark patch slot as used
patchFlag[nextPatchSlot] = false;
// Collect size
reconPatchSizes[nextPatchSlot] = reconBMesh[reconPatchI].size();
}
}
// Patch sizes are assembled. Collect patch starts for the new mesh
labelList reconPatchStarts(reconBMesh.size(), 0);
if (!reconPatchStarts.empty())
{
reconPatchStarts[0] = reconMesh.nInternalFaces();
for (label i = 1; i < reconPatchStarts.size(); i++)
{
reconPatchStarts[i] =
reconPatchStarts[i - 1]
+ reconPatchSizes[i - 1];
}
}
// Reset fvMesh and patches
resetFvPrimitives
(
xferCopy(reconMesh.allPoints()),
xferCopy(reconMesh.allFaces()),
xferCopy(reconMesh.faceOwner()),
xferCopy(reconMesh.faceNeighbour()),
reconPatchSizes,
reconPatchStarts,
resetFvPatchFlag,
true // Valid boundary
);
// Create field reconstructor
fvFieldReconstructor fieldReconstructor
(
*this,
procMeshes,
meshRecon.faceProcAddressing(),
meshRecon.cellProcAddressing(),
meshRecon.boundaryProcAddressing()
);
// Rebuild fields
rebuildFields
(
volScalarFields,
fieldReconstructor,
receivedVolScalarFields,
resetFvPatchFlag
);
rebuildFields
(
volVectorFields,
fieldReconstructor,
receivedVolVectorFields,
resetFvPatchFlag
);
rebuildFields
(
surfaceScalarFields,
fieldReconstructor,
receivedSurfaceScalarFields,
resetFvPatchFlag
);
// Debug
checkMesh(true);
return true;
}
// ************************************************************************* //

View file

@ -23,12 +23,12 @@ License
\*---------------------------------------------------------------------------*/
#include "loadBalanceFvMesh.H"
#include "topoChangerFvMesh.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class GeoField, class Decomposer>
void Foam::loadBalanceFvMesh::sendFields
void Foam::topoChangerFvMesh::sendFields
(
const HashTable<const GeoField*>& geoFields,
const Decomposer& decomposer,
@ -47,7 +47,6 @@ void Foam::loadBalanceFvMesh::sendFields
iter
)
{
Pout<< "Sending field " << iter()->name() << " in slot " << fI << endl;
// Encapsulate a field within a dictionary in order
// to read it correctly on the receiving side
toProc << iter()->name() << nl
@ -62,7 +61,7 @@ void Foam::loadBalanceFvMesh::sendFields
template<class GeoField, class Decomposer>
void Foam::loadBalanceFvMesh::insertFields
void Foam::topoChangerFvMesh::insertFields
(
const HashTable<const GeoField*>& geoFields,
const Decomposer& decomposer,
@ -96,15 +95,13 @@ void Foam::loadBalanceFvMesh::insertFields
decomposer.decomposeField(*(iter()))
);
Pout<< "Setting field " << localFields[fI][Pstream::myProcNo()].name()
<< " in slot " << fI << endl;
fI++;
}
}
template<class GeoMesh, class GeoField>
void Foam::loadBalanceFvMesh::receiveFields
void Foam::topoChangerFvMesh::receiveFields
(
const label procIndex,
List<PtrList<GeoField> >& receivedFields,
@ -130,7 +127,6 @@ void Foam::loadBalanceFvMesh::receiveFields
forAll (receivedFields, fI)
{
word fieldName(fromProc);
Pout<< "Receiving field " << fieldName << " in slot " << fI << endl;
dictionary dict(fromProc);
@ -156,7 +152,7 @@ void Foam::loadBalanceFvMesh::receiveFields
template<class GeoField, class Reconstructor>
void Foam::loadBalanceFvMesh::rebuildFields
void Foam::topoChangerFvMesh::rebuildFields
(
const HashTable<const GeoField*>& geoFields,
const Reconstructor& reconstructor,
@ -220,7 +216,7 @@ void Foam::loadBalanceFvMesh::rebuildFields
{
FatalErrorIn
(
"loadBalanceFvMesh::rebuildFields\n"
"topoChangerFvMesh::rebuildFields\n"
"(\n"
" const HashTable<const GeoField*>& geoFields,\n"
" const Reconstructor& reconstructor,\n"
@ -234,7 +230,7 @@ void Foam::loadBalanceFvMesh::rebuildFields
{
FatalErrorIn
(
"loadBalanceFvMesh::rebuildFields\n"
"topoChangerFvMesh::rebuildFields\n"
"(\n"
" const HashTable<const GeoField*>& geoFields,\n"
" const Reconstructor& reconstructor,\n"
@ -323,7 +319,7 @@ void Foam::loadBalanceFvMesh::rebuildFields
<< masterField.mesh().boundary()[patchI].size()
<< endl;
patchFields[patchI].setSize
patchFields[patchI].resetSize
(
masterField.mesh().boundary()[patchI].size()
);