Refactoring of load balance: move function into topoChangerFvMesh
This commit is contained in:
parent
c1f86cba2d
commit
a4617cca01
11 changed files with 690 additions and 1075 deletions
|
@ -1,4 +1,3 @@
|
|||
dynamicMeshLoadBalance/dynamicMeshLoadBalance.C
|
||||
loadBalanceFvMesh/loadBalanceFvMesh.C
|
||||
|
||||
LIB = $(FOAM_LIBBIN)/libloadBalanceFvMesh
|
||||
|
|
|
@ -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\
|
||||
LIB_LIBS = \
|
||||
-lfiniteVolume \
|
||||
-ldynamicMesh \
|
||||
-ldynamicFvMesh
|
||||
-ldynamicFvMesh \
|
||||
-ltopoChangerFvMesh \
|
||||
-ldecomposeReconstruct
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
|
@ -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
|
||||
|
||||
// ************************************************************************* //
|
|
@ -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 loadBalance(dict_);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Serial run: no balancing
|
||||
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);
|
||||
}
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
topoChangerFvMesh/topoChangerFvMesh.C
|
||||
topoChangerFvMesh/topoChangerFvMeshLoadBalance.C
|
||||
|
||||
attachDetachFvMesh/attachDetachFvMesh.C
|
||||
linearValveFvMesh/linearValveFvMesh.C
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
virtual ~topoChangerFvMesh();
|
||||
//- 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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
|
@ -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()
|
||||
);
|
Reference in a new issue