reconstructPar: Reconstruct the mesh
The reconstructPar utility now reconstructs the mesh if and when it is necessary to do so. The reconstructParMesh utility is therefore no longer necessary and has been removed. It was necessary/advantagous to consolidate these utilities into one because in the case of mesh changes it becomes increasingly less clear which of the separate utilities is responsible for reconstructing data that is neither clearly physical field nor mesh topology; e.g., moving points, sets, refinement data, and so on.
This commit is contained in:
@ -164,36 +164,12 @@ void decomposeUniform
|
||||
|
||||
void writeDecomposition(const domainDecomposition& meshes)
|
||||
{
|
||||
const labelList& procIds = meshes.cellToProc();
|
||||
|
||||
// Write the decomposition as labelList for use with 'manual'
|
||||
// decomposition method.
|
||||
labelIOList cellDecomposition
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"cellDecomposition",
|
||||
meshes.completeMesh().facesInstance(),
|
||||
meshes.completeMesh(),
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
procIds
|
||||
);
|
||||
|
||||
cellDecomposition.write();
|
||||
|
||||
Info<< nl << "Wrote decomposition to "
|
||||
<< cellDecomposition.relativeObjectPath()
|
||||
<< " for use in manual decomposition." << endl;
|
||||
|
||||
// Write as volScalarField for postprocessing.
|
||||
volScalarField::Internal cellDist
|
||||
volScalarField::Internal cellProc
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"cellDist",
|
||||
"cellProc",
|
||||
meshes.completeMesh().time().timeName(),
|
||||
meshes.completeMesh(),
|
||||
IOobject::NO_READ,
|
||||
@ -201,14 +177,14 @@ void writeDecomposition(const domainDecomposition& meshes)
|
||||
),
|
||||
meshes.completeMesh(),
|
||||
dimless,
|
||||
scalarField(scalarList(procIds))
|
||||
scalarField(scalarList(meshes.cellProc()))
|
||||
);
|
||||
|
||||
cellDist.write();
|
||||
cellProc.write();
|
||||
|
||||
Info<< nl << "Wrote decomposition as volScalarField to "
|
||||
<< cellDist.name() << " for use in postprocessing."
|
||||
<< endl;
|
||||
Info<< "Wrote decomposition as volScalarField to "
|
||||
<< cellProc.name() << " for use in postprocessing."
|
||||
<< nl << endl;
|
||||
}
|
||||
|
||||
|
||||
@ -281,8 +257,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (decomposeGeomOnly)
|
||||
{
|
||||
Info<< "Skipping decomposing fields"
|
||||
<< nl << endl;
|
||||
Info<< "Skipping decomposing fields" << nl << endl;
|
||||
|
||||
if (decomposeFieldsOnly || copyZero)
|
||||
{
|
||||
@ -304,65 +279,71 @@ int main(int argc, char *argv[])
|
||||
const wordList regionNames =
|
||||
selectRegionNames(args, runTimes.completeTime());
|
||||
|
||||
// Handle existing decomposition directories
|
||||
// Remove existing processor directories if requested
|
||||
if (forceOverwrite)
|
||||
{
|
||||
// Determine the processor count from the directories
|
||||
label nProcs = fileHandler().nProcs(runTimes.completeTime().path());
|
||||
|
||||
if (forceOverwrite)
|
||||
if (region)
|
||||
{
|
||||
if (region)
|
||||
FatalErrorInFunction
|
||||
<< "Cannot force the decomposition of a single region"
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
const label nProcs0 =
|
||||
fileHandler().nProcs(runTimes.completeTime().path());
|
||||
|
||||
Info<< "Removing " << nProcs0
|
||||
<< " existing processor directories" << endl;
|
||||
|
||||
// Remove existing processor directories
|
||||
const fileNameList dirs
|
||||
(
|
||||
fileHandler().readDir
|
||||
(
|
||||
runTimes.completeTime().path(),
|
||||
fileType::directory
|
||||
)
|
||||
);
|
||||
forAllReverse(dirs, diri)
|
||||
{
|
||||
const fileName& d = dirs[diri];
|
||||
|
||||
// Starts with 'processors'
|
||||
if (d.find("processors") == 0)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Cannot force the decomposition of a single region"
|
||||
<< exit(FatalError);
|
||||
if (fileHandler().exists(d))
|
||||
{
|
||||
fileHandler().rmDir(d);
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "Removing " << nProcs
|
||||
<< " existing processor directories" << endl;
|
||||
|
||||
// Remove existing processors directory
|
||||
fileNameList dirs
|
||||
(
|
||||
fileHandler().readDir
|
||||
(
|
||||
runTimes.completeTime().path(),
|
||||
fileType::directory
|
||||
)
|
||||
);
|
||||
forAllReverse(dirs, diri)
|
||||
// Starts with 'processor'
|
||||
if (d.find("processor") == 0)
|
||||
{
|
||||
const fileName& d = dirs[diri];
|
||||
|
||||
// Starts with 'processors'
|
||||
if (d.find("processors") == 0)
|
||||
// Check that integer after processor
|
||||
fileName num(d.substr(9));
|
||||
label proci = -1;
|
||||
if (Foam::read(num.c_str(), proci))
|
||||
{
|
||||
if (fileHandler().exists(d))
|
||||
{
|
||||
fileHandler().rmDir(d);
|
||||
}
|
||||
}
|
||||
|
||||
// Starts with 'processor'
|
||||
if (d.find("processor") == 0)
|
||||
{
|
||||
// Check that integer after processor
|
||||
fileName num(d.substr(9));
|
||||
label proci = -1;
|
||||
if (Foam::read(num.c_str(), proci))
|
||||
{
|
||||
if (fileHandler().exists(d))
|
||||
{
|
||||
fileHandler().rmDir(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nProcs && !region && !decomposeFieldsOnly)
|
||||
}
|
||||
|
||||
// Check the specified number of processes is consistent with any existing
|
||||
// processor directories
|
||||
{
|
||||
const label nProcs0 =
|
||||
fileHandler().nProcs(runTimes.completeTime().path());
|
||||
|
||||
if (nProcs0 && nProcs0 != runTimes.nProcs())
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Case is already decomposed with " << nProcs
|
||||
<< "Case is already decomposed with " << nProcs0
|
||||
<< " domains, use the -force option or manually" << nl
|
||||
<< "remove processor directories before decomposing. e.g.,"
|
||||
<< nl
|
||||
@ -413,25 +394,14 @@ int main(int argc, char *argv[])
|
||||
// Create meshes
|
||||
Info<< "Create mesh" << endl;
|
||||
domainDecomposition meshes(runTimes, regionName);
|
||||
meshes.readComplete();
|
||||
|
||||
// Read or generate a decomposition as necessary
|
||||
if (decomposeFieldsOnly)
|
||||
if (!decomposeFieldsOnly || !copyZero)
|
||||
{
|
||||
meshes.readProcs();
|
||||
if (!copyZero)
|
||||
if (meshes.readDecompose(decomposeSets) && writeCellDist)
|
||||
{
|
||||
meshes.readAddressing();
|
||||
meshes.readUpdate();
|
||||
writeDecomposition(meshes);
|
||||
fileHandler().flush();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
meshes.decompose();
|
||||
meshes.writeProcs(decomposeSets);
|
||||
if (writeCellDist) writeDecomposition(meshes);
|
||||
fileHandler().flush();
|
||||
}
|
||||
|
||||
// Field maps. These are preserved if decomposing multiple times.
|
||||
PtrList<fvFieldDecomposer> fieldDecomposerList
|
||||
@ -448,10 +418,10 @@ int main(int argc, char *argv[])
|
||||
);
|
||||
|
||||
// Loop over all times
|
||||
forAll(times, timeI)
|
||||
forAll(times, timei)
|
||||
{
|
||||
// Set the time
|
||||
runTimes.setTime(times[timeI], timeI);
|
||||
runTimes.setTime(times[timei], timei);
|
||||
|
||||
Info<< "Time = " << runTimes.completeTime().userTimeName() << endl;
|
||||
|
||||
@ -459,7 +429,7 @@ int main(int argc, char *argv[])
|
||||
fvMesh::readUpdateState state = fvMesh::UNCHANGED;
|
||||
if (!decomposeFieldsOnly || !copyZero)
|
||||
{
|
||||
state = meshes.readUpdate();
|
||||
state = meshes.readUpdateDecompose();
|
||||
}
|
||||
|
||||
// Write the mesh out, if necessary
|
||||
@ -467,18 +437,20 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
else if (state == fvMesh::POINTS_MOVED)
|
||||
{
|
||||
meshes.writeProcs(false);
|
||||
}
|
||||
else if
|
||||
(
|
||||
state == fvMesh::TOPO_CHANGE
|
||||
|| state == fvMesh::TOPO_PATCH_CHANGE
|
||||
)
|
||||
else if (state != fvMesh::UNCHANGED)
|
||||
{
|
||||
meshes.writeProcs(decomposeSets);
|
||||
if (writeCellDist) writeDecomposition(meshes);
|
||||
}
|
||||
|
||||
// Write the decomposition, if necessary
|
||||
if
|
||||
(
|
||||
writeCellDist
|
||||
&& meshes.completeMesh().facesInstance()
|
||||
== runTimes.completeTime().timeName()
|
||||
)
|
||||
{
|
||||
writeDecomposition(meshes);
|
||||
fileHandler().flush();
|
||||
}
|
||||
|
||||
@ -510,10 +482,9 @@ int main(int argc, char *argv[])
|
||||
runTimes.completeTime().timePath();
|
||||
|
||||
fileName prevProcTimePath;
|
||||
for (label proci = 0; proci < meshes.nProcs(); proci++)
|
||||
for (label proci = 0; proci < runTimes.nProcs(); proci++)
|
||||
{
|
||||
const Time& procRunTime =
|
||||
meshes.procMeshes()[proci].time();
|
||||
const Time& procRunTime = runTimes.procTimes()[proci];
|
||||
|
||||
if (fileHandler().isDir(completeTimePath))
|
||||
{
|
||||
|
||||
@ -48,7 +48,6 @@ SourceFiles
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class fvFieldReconstructor Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -169,6 +169,8 @@ void Foam::pointFieldReconstructor::reconstructFields
|
||||
Info<< " " << fieldIter()->name() << endl;
|
||||
|
||||
reconstructField<Type>(*fieldIter())().write();
|
||||
|
||||
nReconstructed_++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -45,25 +45,56 @@ Description
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
bool haveAllTimes
|
||||
(
|
||||
const HashSet<word>& masterTimeDirSet,
|
||||
const instantList& timeDirs
|
||||
)
|
||||
|
||||
bool haveAllTimes
|
||||
(
|
||||
const HashSet<word>& masterTimeDirSet,
|
||||
const instantList& timeDirs
|
||||
)
|
||||
{
|
||||
// Loop over all times
|
||||
forAll(timeDirs, timei)
|
||||
{
|
||||
// Loop over all times
|
||||
forAll(timeDirs, timei)
|
||||
if (!masterTimeDirSet.found(timeDirs[timei].name()))
|
||||
{
|
||||
if (!masterTimeDirSet.found(timeDirs[timei].name()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void writeDecomposition(const domainDecomposition& meshes)
|
||||
{
|
||||
// Write as volScalarField for postprocessing.
|
||||
volScalarField::Internal cellProc
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"cellProc",
|
||||
meshes.completeMesh().time().timeName(),
|
||||
meshes.completeMesh(),
|
||||
IOobject::NO_READ,
|
||||
IOobject::AUTO_WRITE
|
||||
),
|
||||
meshes.completeMesh(),
|
||||
dimless,
|
||||
scalarField(scalarList(meshes.cellProc()))
|
||||
);
|
||||
|
||||
cellProc.write();
|
||||
|
||||
Info<< "Wrote decomposition as volScalarField to "
|
||||
<< cellProc.name() << " for use in postprocessing."
|
||||
<< nl << endl;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
@ -77,6 +108,12 @@ int main(int argc, char *argv[])
|
||||
argList::noParallel();
|
||||
#include "addRegionOption.H"
|
||||
#include "addAllRegionsOption.H"
|
||||
argList::addBoolOption
|
||||
(
|
||||
"cellDist",
|
||||
"write cell distribution as a labelList - for use with 'manual' "
|
||||
"decomposition method or as a volScalarField for post-processing."
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"fields",
|
||||
@ -115,6 +152,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
const bool writeCellDist = args.optionFound("cellDist");
|
||||
|
||||
HashSet<word> selectedFields;
|
||||
if (args.optionFound("fields"))
|
||||
{
|
||||
@ -225,25 +264,12 @@ int main(int argc, char *argv[])
|
||||
const word& regionDir = Foam::regionDir(regionName);
|
||||
|
||||
// Create meshes
|
||||
Info<< "\n\nReconstructing fields for mesh " << regionName
|
||||
<< nl << endl;
|
||||
Info<< "\n\nReconstructing mesh " << regionName << nl << endl;
|
||||
domainDecomposition meshes(runTimes, regionName);
|
||||
meshes.readComplete();
|
||||
meshes.readProcs();
|
||||
meshes.readAddressing();
|
||||
meshes.readUpdate();
|
||||
|
||||
// Write the complete mesh if at the constant instant. Otherwise
|
||||
// mesh-associated things (sets, hexRef8, ...) will not be written by
|
||||
// domainDecomposition because there is no change of mesh to trigger
|
||||
// them to write.
|
||||
if
|
||||
(
|
||||
runTimes.completeTime().timeName()
|
||||
== runTimes.completeTime().constant()
|
||||
)
|
||||
if (meshes.readReconstruct(!noReconstructSets) && writeCellDist)
|
||||
{
|
||||
meshes.writeComplete(!noReconstructSets);
|
||||
writeDecomposition(meshes);
|
||||
fileHandler().flush();
|
||||
}
|
||||
|
||||
// Loop over all times
|
||||
@ -263,20 +289,27 @@ int main(int argc, char *argv[])
|
||||
<< nl << endl;
|
||||
|
||||
// Update the meshes
|
||||
const fvMesh::readUpdateState state = meshes.readUpdate();
|
||||
if (state == fvMesh::POINTS_MOVED)
|
||||
{
|
||||
meshes.writeComplete(false);
|
||||
}
|
||||
if
|
||||
(
|
||||
state == fvMesh::TOPO_CHANGE
|
||||
|| state == fvMesh::TOPO_PATCH_CHANGE
|
||||
)
|
||||
const fvMesh::readUpdateState state =
|
||||
meshes.readUpdateReconstruct();
|
||||
|
||||
// Write the mesh out, if necessary
|
||||
if (state != fvMesh::UNCHANGED)
|
||||
{
|
||||
meshes.writeComplete(!noReconstructSets);
|
||||
}
|
||||
|
||||
// Write the decomposition, if necessary
|
||||
if
|
||||
(
|
||||
writeCellDist
|
||||
&& meshes.completeMesh().facesInstance()
|
||||
== runTimes.completeTime().timeName()
|
||||
)
|
||||
{
|
||||
writeDecomposition(meshes);
|
||||
fileHandler().flush();
|
||||
}
|
||||
|
||||
// Get list of objects from processor0 database
|
||||
IOobjectList objects
|
||||
(
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
reconstructParMesh.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/reconstructParMesh
|
||||
@ -1,10 +0,0 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude \
|
||||
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/regionModels/regionModel/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ldynamicMesh \
|
||||
-lmeshTools \
|
||||
-lregionModels
|
||||
@ -1,693 +0,0 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Application
|
||||
reconstructParMesh
|
||||
|
||||
Description
|
||||
Reconstructs a mesh.
|
||||
|
||||
Writes point/face/cell procAddressing so afterwards reconstructPar can be
|
||||
used to reconstruct fields.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "argList.H"
|
||||
#include "timeSelector.H"
|
||||
|
||||
#include "IOobjectList.H"
|
||||
#include "labelIOList.H"
|
||||
#include "processorPolyPatch.H"
|
||||
#include "mapAddedPolyMesh.H"
|
||||
#include "polyMeshAdder.H"
|
||||
#include "faceCoupleInfo.H"
|
||||
#include "fvMeshAdder.H"
|
||||
#include "polyTopoChange.H"
|
||||
#include "extrapolatedCalculatedFvPatchFields.H"
|
||||
#include "regionProperties.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
autoPtr<faceCoupleInfo> determineCoupledFaces
|
||||
(
|
||||
const label masterMeshProcStart,
|
||||
const label masterMeshProcEnd,
|
||||
const polyMesh& masterMesh,
|
||||
const label meshToAddProcStart,
|
||||
const label meshToAddProcEnd,
|
||||
const polyMesh& meshToAdd
|
||||
)
|
||||
{
|
||||
const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
|
||||
const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
|
||||
|
||||
DynamicList<label> masterFaces
|
||||
(
|
||||
masterMesh.nFaces() - masterMesh.nInternalFaces()
|
||||
);
|
||||
DynamicList<label> addFaces
|
||||
(
|
||||
meshToAdd.nFaces() - meshToAdd.nInternalFaces()
|
||||
);
|
||||
|
||||
for
|
||||
(
|
||||
label masterProci = masterMeshProcStart;
|
||||
masterProci < masterMeshProcEnd;
|
||||
masterProci++
|
||||
)
|
||||
{
|
||||
for
|
||||
(
|
||||
label addProci = meshToAddProcStart;
|
||||
addProci < meshToAddProcEnd;
|
||||
addProci++
|
||||
)
|
||||
{
|
||||
const word masterToAddName
|
||||
(
|
||||
"procBoundary" + name(masterProci) + "to" + name(addProci)
|
||||
);
|
||||
const word addToMasterName
|
||||
(
|
||||
"procBoundary" + name(addProci) + "to" + name(masterProci)
|
||||
);
|
||||
|
||||
const label masterToAddID =
|
||||
masterPatches.findPatchID(masterToAddName);
|
||||
const label addToMasterID =
|
||||
addPatches.findPatchID(addToMasterName);
|
||||
|
||||
if (masterToAddID != -1 && addToMasterID != -1)
|
||||
{
|
||||
const polyPatch& masterPp = masterPatches[masterToAddID];
|
||||
|
||||
forAll(masterPp, i)
|
||||
{
|
||||
masterFaces.append(masterPp.start() + i);
|
||||
}
|
||||
|
||||
const polyPatch& addPp = addPatches[addToMasterID];
|
||||
|
||||
forAll(addPp, i)
|
||||
{
|
||||
addFaces.append(addPp.start() + i);
|
||||
}
|
||||
}
|
||||
|
||||
if ((masterToAddID != -1) != (addToMasterID != -1))
|
||||
{
|
||||
const label foundProci =
|
||||
masterToAddID != -1 ? masterProci : addProci;
|
||||
const word& foundName =
|
||||
masterToAddID != -1 ? masterToAddName : addToMasterName;
|
||||
|
||||
const label missingProci =
|
||||
masterToAddID != -1 ? addProci : masterProci;
|
||||
const word& missingName =
|
||||
masterToAddID != -1 ? addToMasterName : masterToAddName;
|
||||
|
||||
FatalErrorInFunction
|
||||
<< "Patch " << foundName << " found on processor "
|
||||
<< foundProci << " but corresponding patch "
|
||||
<< missingName << " missing on processor "
|
||||
<< missingProci << exit(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
masterFaces.shrink();
|
||||
addFaces.shrink();
|
||||
|
||||
return autoPtr<faceCoupleInfo>
|
||||
(
|
||||
new faceCoupleInfo
|
||||
(
|
||||
masterMesh,
|
||||
masterFaces,
|
||||
meshToAdd,
|
||||
addFaces
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void writeCellDistribution
|
||||
(
|
||||
Time& runTime,
|
||||
const fvMesh& masterMesh,
|
||||
const labelListList& cellProcAddressing
|
||||
|
||||
)
|
||||
{
|
||||
// Write the decomposition as labelList for use with 'manual'
|
||||
// decomposition method.
|
||||
labelIOList cellDecomposition
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"cellDecomposition",
|
||||
masterMesh.facesInstance(),
|
||||
masterMesh,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
masterMesh.nCells()
|
||||
);
|
||||
|
||||
forAll(cellProcAddressing, proci)
|
||||
{
|
||||
const labelList& pCells = cellProcAddressing[proci];
|
||||
UIndirectList<label>(cellDecomposition, pCells) = proci;
|
||||
}
|
||||
|
||||
cellDecomposition.write();
|
||||
|
||||
Info<< nl << "Wrote decomposition to "
|
||||
<< cellDecomposition.relativeObjectPath()
|
||||
<< " for use in manual decomposition." << endl;
|
||||
|
||||
|
||||
// Write as volScalarField for postprocessing. Change time to 0
|
||||
// if was 'constant'
|
||||
{
|
||||
const scalar oldTime = runTime.value();
|
||||
const label oldIndex = runTime.timeIndex();
|
||||
if (runTime.timeName() == runTime.constant() && oldIndex == 0)
|
||||
{
|
||||
runTime.setTime(0, oldIndex+1);
|
||||
}
|
||||
|
||||
volScalarField cellDist
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"cellDist",
|
||||
runTime.timeName(),
|
||||
masterMesh,
|
||||
IOobject::NO_READ,
|
||||
IOobject::AUTO_WRITE
|
||||
),
|
||||
masterMesh,
|
||||
dimensionedScalar(dimless, 0),
|
||||
extrapolatedCalculatedFvPatchScalarField::typeName
|
||||
);
|
||||
|
||||
forAll(cellDecomposition, celli)
|
||||
{
|
||||
cellDist[celli] = cellDecomposition[celli];
|
||||
}
|
||||
cellDist.correctBoundaryConditions();
|
||||
|
||||
cellDist.write();
|
||||
|
||||
Info<< nl << "Wrote decomposition as volScalarField to "
|
||||
<< cellDist.name() << " for use in postprocessing."
|
||||
<< endl;
|
||||
|
||||
// Restore time
|
||||
runTime.setTime(oldTime, oldIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote("reconstruct a mesh");
|
||||
timeSelector::addOptions(true, true);
|
||||
argList::noParallel();
|
||||
argList::addBoolOption
|
||||
(
|
||||
"cellDist",
|
||||
"write cell distribution as a labelList - for use with 'manual' "
|
||||
"decomposition method or as a volScalarField for post-processing."
|
||||
);
|
||||
|
||||
#include "addRegionOption.H"
|
||||
#include "addAllRegionsOption.H"
|
||||
#include "setRootCase.H"
|
||||
#include "createTime.H"
|
||||
|
||||
const wordList regionNames(selectRegionNames(args, runTime));
|
||||
if (regionNames.size() > 1)
|
||||
{
|
||||
Info<< "Operating on regions " << regionNames[0];
|
||||
for (label regioni = 1; regioni < regionNames.size() - 1; ++ regioni)
|
||||
{
|
||||
Info<< ", " << regionNames[regioni];
|
||||
}
|
||||
Info<< " and " << regionNames.last() << nl << endl;
|
||||
}
|
||||
else if (regionNames[0] != polyMesh::defaultRegion)
|
||||
{
|
||||
Info<< "Operating on region " << regionNames[0] << nl << endl;
|
||||
}
|
||||
|
||||
label nProcs = fileHandler().nProcs(args.path());
|
||||
Info<< "Found " << nProcs << " processor directories" << nl << endl;
|
||||
|
||||
// Read all time databases
|
||||
PtrList<Time> databases(nProcs);
|
||||
forAll(databases, proci)
|
||||
{
|
||||
Info<< "Reading database "
|
||||
<< args.caseName()/fileName(word("processor") + name(proci))
|
||||
<< endl;
|
||||
|
||||
databases.set
|
||||
(
|
||||
proci,
|
||||
new Time
|
||||
(
|
||||
Time::controlDictName,
|
||||
args.rootPath(),
|
||||
args.caseName()/fileName(word("processor") + name(proci))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Use the times list from the master processor
|
||||
// and select a subset based on the command-line options
|
||||
instantList timeDirs = timeSelector::select
|
||||
(
|
||||
databases[0].times(),
|
||||
args
|
||||
);
|
||||
|
||||
// Loop over all times
|
||||
forAll(timeDirs, timeI)
|
||||
{
|
||||
// Set time for global database
|
||||
runTime.setTime(timeDirs[timeI], timeI);
|
||||
|
||||
Info<< "Time = " << runTime.userTimeName() << nl << endl;
|
||||
|
||||
// Set time for all databases
|
||||
forAll(databases, proci)
|
||||
{
|
||||
databases[proci].setTime(timeDirs[timeI], timeI);
|
||||
}
|
||||
|
||||
forAll(regionNames, regioni)
|
||||
{
|
||||
const word& regionName = regionNames[regioni];
|
||||
const word regionDir =
|
||||
regionName == polyMesh::defaultRegion
|
||||
? word::null
|
||||
: regionName;
|
||||
|
||||
IOobject facesIO
|
||||
(
|
||||
"faces",
|
||||
databases[0].timeName(),
|
||||
regionDir/polyMesh::meshSubDir,
|
||||
databases[0],
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE
|
||||
);
|
||||
|
||||
|
||||
// Problem: faceCompactIOList recognises both 'faceList' and
|
||||
// 'faceCompactList' so we cannot check the type
|
||||
if (!facesIO.headerOk())
|
||||
{
|
||||
Info<< "No mesh." << nl << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Addressing from processor to reconstructed case
|
||||
labelListList cellProcAddressing(nProcs);
|
||||
labelListList faceProcAddressing(nProcs);
|
||||
labelListList pointProcAddressing(nProcs);
|
||||
|
||||
// Internal faces on the final reconstructed mesh
|
||||
label masterInternalFaces;
|
||||
|
||||
// Owner addressing on the final reconstructed mesh
|
||||
labelList masterOwner;
|
||||
|
||||
{
|
||||
// Construct empty mesh.
|
||||
PtrList<fvMesh> masterMesh(nProcs);
|
||||
|
||||
// Read all the meshes
|
||||
for (label proci=0; proci<nProcs; proci++)
|
||||
{
|
||||
masterMesh.set
|
||||
(
|
||||
proci,
|
||||
new fvMesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
regionName,
|
||||
runTime.timeName(),
|
||||
runTime,
|
||||
IOobject::NO_READ
|
||||
),
|
||||
pointField(),
|
||||
faceList(),
|
||||
cellList()
|
||||
)
|
||||
);
|
||||
|
||||
fvMesh meshToAdd
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
regionName,
|
||||
databases[proci].timeName(),
|
||||
databases[proci]
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
// Initialise its addressing
|
||||
cellProcAddressing[proci] = identity(meshToAdd.nCells());
|
||||
faceProcAddressing[proci] = identity(meshToAdd.nFaces());
|
||||
pointProcAddressing[proci] = identity(meshToAdd.nPoints());
|
||||
|
||||
// Find shared points/faces
|
||||
autoPtr<faceCoupleInfo> couples = determineCoupledFaces
|
||||
(
|
||||
proci,
|
||||
proci,
|
||||
masterMesh[proci],
|
||||
proci,
|
||||
proci,
|
||||
meshToAdd
|
||||
);
|
||||
|
||||
// Add elements to mesh
|
||||
autoPtr<mapAddedPolyMesh> map = fvMeshAdder::add
|
||||
(
|
||||
masterMesh[proci],
|
||||
meshToAdd,
|
||||
couples
|
||||
);
|
||||
|
||||
// Added processor
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedCellMap(),
|
||||
cellProcAddressing[proci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedFaceMap(),
|
||||
faceProcAddressing[proci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedPointMap(),
|
||||
pointProcAddressing[proci]
|
||||
);
|
||||
}
|
||||
|
||||
// Merge the meshes
|
||||
for (label step=2; step<nProcs*2; step*=2)
|
||||
{
|
||||
for (label proci=0; proci<nProcs; proci+=step)
|
||||
{
|
||||
label next = proci + step/2;
|
||||
if(next >= nProcs)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Info<< "Merging mesh " << proci << " with " << next
|
||||
<< endl;
|
||||
|
||||
// Find shared points/faces
|
||||
autoPtr<faceCoupleInfo> couples = determineCoupledFaces
|
||||
(
|
||||
proci,
|
||||
next,
|
||||
masterMesh[proci],
|
||||
next,
|
||||
proci+step,
|
||||
masterMesh[next]
|
||||
);
|
||||
|
||||
// Add elements to mesh
|
||||
autoPtr<mapAddedPolyMesh> map = fvMeshAdder::add
|
||||
(
|
||||
masterMesh[proci],
|
||||
masterMesh[next],
|
||||
couples
|
||||
);
|
||||
|
||||
// Processors that were already in masterMesh
|
||||
for (label mergedI=proci; mergedI<next; mergedI++)
|
||||
{
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldCellMap(),
|
||||
cellProcAddressing[mergedI]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldFaceMap(),
|
||||
faceProcAddressing[mergedI]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldPointMap(),
|
||||
pointProcAddressing[mergedI]
|
||||
);
|
||||
}
|
||||
|
||||
// Added processor
|
||||
for
|
||||
(
|
||||
label addedI=next;
|
||||
addedI<min(proci+step, nProcs);
|
||||
addedI++
|
||||
)
|
||||
{
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedCellMap(),
|
||||
cellProcAddressing[addedI]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedFaceMap(),
|
||||
faceProcAddressing[addedI]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedPointMap(),
|
||||
pointProcAddressing[addedI]
|
||||
);
|
||||
}
|
||||
|
||||
masterMesh.set(next, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
for (label proci=0; proci<nProcs; proci++)
|
||||
{
|
||||
Info<< "Reading mesh to add from "
|
||||
<< databases[proci].caseName()
|
||||
<< " for time = " << databases[proci].timeName()
|
||||
<< nl << nl << endl;
|
||||
}
|
||||
|
||||
|
||||
// Save some properties on the reconstructed mesh
|
||||
masterInternalFaces = masterMesh[0].nInternalFaces();
|
||||
masterOwner = masterMesh[0].faceOwner();
|
||||
|
||||
|
||||
Info<< "\nWriting merged mesh to "
|
||||
<< runTime.path()/runTime.timeName()
|
||||
<< nl << endl;
|
||||
|
||||
if (!masterMesh[0].write())
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Failed writing polyMesh."
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
if (args.optionFound("cellDist"))
|
||||
{
|
||||
writeCellDistribution
|
||||
(
|
||||
runTime,
|
||||
masterMesh[0],
|
||||
cellProcAddressing
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the addressing
|
||||
|
||||
Info<< "Reconstructing the addressing from the processor meshes"
|
||||
<< " to the newly reconstructed mesh" << nl << endl;
|
||||
|
||||
forAll(databases, proci)
|
||||
{
|
||||
Info<< "Reading processor " << proci << " mesh from "
|
||||
<< databases[proci].caseName() << endl;
|
||||
|
||||
polyMesh procMesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
regionName,
|
||||
databases[proci].timeName(),
|
||||
databases[proci]
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
// From processor point to reconstructed mesh point
|
||||
|
||||
Info<< "Writing pointProcAddressing to "
|
||||
<< databases[proci].caseName()
|
||||
/procMesh.facesInstance()
|
||||
/polyMesh::meshSubDir
|
||||
<< endl;
|
||||
|
||||
labelIOList
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"pointProcAddressing",
|
||||
procMesh.facesInstance(),
|
||||
polyMesh::meshSubDir,
|
||||
procMesh,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false // Do not register
|
||||
),
|
||||
pointProcAddressing[proci]
|
||||
).write();
|
||||
|
||||
|
||||
// From processor face to reconstructed mesh face
|
||||
|
||||
Info<< "Writing faceProcAddressing to "
|
||||
<< databases[proci].caseName()
|
||||
/procMesh.facesInstance()
|
||||
/polyMesh::meshSubDir
|
||||
<< endl;
|
||||
|
||||
labelIOList faceProcAddr
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"faceProcAddressing",
|
||||
procMesh.facesInstance(),
|
||||
polyMesh::meshSubDir,
|
||||
procMesh,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false // Do not register
|
||||
),
|
||||
faceProcAddressing[proci]
|
||||
);
|
||||
|
||||
// Now add turning index to faceProcAddressing.
|
||||
// See reconstructPar for meaning of turning index.
|
||||
forAll(faceProcAddr, procFacei)
|
||||
{
|
||||
const label masterFacei = faceProcAddr[procFacei];
|
||||
|
||||
if
|
||||
(
|
||||
!procMesh.isInternalFace(procFacei)
|
||||
&& masterFacei < masterInternalFaces
|
||||
)
|
||||
{
|
||||
// proc face is now external but used to be internal
|
||||
// face. Check if we have owner or neighbour.
|
||||
|
||||
label procOwn = procMesh.faceOwner()[procFacei];
|
||||
label masterOwn = masterOwner[masterFacei];
|
||||
|
||||
if (cellProcAddressing[proci][procOwn] == masterOwn)
|
||||
{
|
||||
// No turning. Offset by 1.
|
||||
faceProcAddr[procFacei]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Turned face.
|
||||
faceProcAddr[procFacei] =
|
||||
-1 - faceProcAddr[procFacei];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No turning. Offset by 1.
|
||||
faceProcAddr[procFacei]++;
|
||||
}
|
||||
}
|
||||
|
||||
faceProcAddr.write();
|
||||
|
||||
|
||||
// From processor cell to reconstructed mesh cell
|
||||
|
||||
Info<< "Writing cellProcAddressing to "
|
||||
<< databases[proci].caseName()
|
||||
/procMesh.facesInstance()
|
||||
/polyMesh::meshSubDir
|
||||
<< endl;
|
||||
|
||||
labelIOList
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"cellProcAddressing",
|
||||
procMesh.facesInstance(),
|
||||
polyMesh::meshSubDir,
|
||||
procMesh,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false // Do not register
|
||||
),
|
||||
cellProcAddressing[proci]
|
||||
).write();
|
||||
|
||||
Info<< endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Info<< "End.\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
49
bin/reconstructParMesh
Executable file
49
bin/reconstructParMesh
Executable file
@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
#------------------------------------------------------------------------------
|
||||
# ========= |
|
||||
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
# \\ / O peration | Website: https://openfoam.org
|
||||
# \\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
|
||||
# \\/ M anipulation |
|
||||
#------------------------------------------------------------------------------
|
||||
# License
|
||||
# This file is part of OpenFOAM.
|
||||
#
|
||||
# OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Script
|
||||
# reconstructParMesh
|
||||
#
|
||||
# Description
|
||||
# Script to inform the user that reconstructParMesh has been superseded
|
||||
# and replaced by the more general reconstructPar utility.
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
cat <<EOF
|
||||
|
||||
The reconstructParMesh utility has been superseded and replaced by by the
|
||||
more general reconstructPar.
|
||||
|
||||
The reconstructPar utility now reconstructs the mesh if and when it is
|
||||
necessary; i.e., when it has changed in the processor* directories as a result
|
||||
of utility usage or dynamic mesh changes.
|
||||
|
||||
Most parallel workflows previously included a call to reconstructParMesh first
|
||||
to reconstruct the mesh, and then called reconstructPar for the fields. This
|
||||
sort of workflow can be updated by removing the call to reconstructParMesh.
|
||||
|
||||
EOF
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
@ -50,7 +50,7 @@ cleanCase()
|
||||
$d/fvMesh $d/*/fvMesh \
|
||||
$d/cellToRegion $d/*/cellToRegion \
|
||||
$d/cellLevel* $d/pointLevel* \
|
||||
$d/cellDist $d/cellDecomposition
|
||||
$d/cellProc
|
||||
done
|
||||
|
||||
[ -d system ] && [ -d dynamicCode ] && rm -rf dynamicCode
|
||||
|
||||
@ -2851,33 +2851,6 @@ _reconstructPar_ ()
|
||||
}
|
||||
complete -o filenames -o nospace -F _reconstructPar_ reconstructPar
|
||||
|
||||
_reconstructParMesh_ ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
local prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
local line=${COMP_LINE}
|
||||
local used=$(echo "$line" | grep -oE "\-[a-zA-Z]+ ")
|
||||
|
||||
opts="-allRegions -case -cellDist -constant -doc -fileHandler -help -latestTime -libs -noFunctionObjects -noZero -region -srcDoc -time -withZero"
|
||||
for o in $used ; do opts="${opts/$o/}" ; done
|
||||
extra=""
|
||||
|
||||
[ "$COMP_CWORD" = 1 ] || \
|
||||
case "$prev" in
|
||||
-case)
|
||||
opts="" ; extra="-d" ;;
|
||||
-fileHandler)
|
||||
opts="uncollated collated masterUncollated" ; extra="" ;;
|
||||
-time)
|
||||
opts="$(foamListTimes -withZero 2> /dev/null)" ; extra="" ;;
|
||||
-libs|-region)
|
||||
opts="" ; extra="" ;;
|
||||
*) ;;
|
||||
esac
|
||||
COMPREPLY=( $(compgen -W "${opts}" $extra -- ${cur}) )
|
||||
}
|
||||
complete -o filenames -o nospace -F _reconstructParMesh_ reconstructParMesh
|
||||
|
||||
_redistributePar_ ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
|
||||
@ -26,6 +26,7 @@ License
|
||||
#include "polyMesh.H"
|
||||
#include "Time.H"
|
||||
#include "cellIOList.H"
|
||||
#include "OSspecific.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
@ -509,6 +510,33 @@ bool Foam::polyMesh::writeObject
|
||||
const bool write
|
||||
) const
|
||||
{
|
||||
if (faces_.writeOpt() == AUTO_WRITE)
|
||||
{
|
||||
auto rmAddressing = [&](const word& name)
|
||||
{
|
||||
const IOobject faceProcAddressingIO
|
||||
(
|
||||
name,
|
||||
facesInstance(),
|
||||
meshSubDir,
|
||||
*this
|
||||
);
|
||||
|
||||
rm(faceProcAddressingIO.objectPath(false));
|
||||
};
|
||||
|
||||
if (!Pstream::parRun())
|
||||
{
|
||||
rmAddressing("cellProc");
|
||||
}
|
||||
else
|
||||
{
|
||||
rmAddressing("pointProcAddressing");
|
||||
rmAddressing("faceProcAddressing");
|
||||
rmAddressing("cellProcAddressing");
|
||||
}
|
||||
}
|
||||
|
||||
const bool written = objectRegistry::writeObject(fmt, ver, cmp, write);
|
||||
|
||||
const_cast<polyMesh&>(*this).setTopologyWrite(IOobject::NO_WRITE);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -29,7 +29,8 @@ Description
|
||||
|
||||
SourceFiles
|
||||
domainDecomposition.C
|
||||
decomposeMesh.C
|
||||
domainDecompositionDecompose.C
|
||||
domainDecompositionReconstruct.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -67,12 +68,18 @@ class domainDecomposition
|
||||
PtrList<fvMesh> procMeshes_;
|
||||
|
||||
|
||||
// Complete mesh to processor mesh addressing
|
||||
|
||||
//- For each complete cell, the processor index
|
||||
labelList cellProc_;
|
||||
|
||||
|
||||
// Processor mesh to complete mesh addressing
|
||||
|
||||
//- Labels of points for each processor
|
||||
//- For each processor point, the complete point index
|
||||
labelListList procPointAddressing_;
|
||||
|
||||
//- Labels of faces for each processor
|
||||
//- For each processor face, the complete face index
|
||||
// Note: Face turning index is stored as the sign on addressing
|
||||
// Only the processor boundary faces are affected: if the sign of
|
||||
// the index is negative, the processor face is the reverse of the
|
||||
@ -82,7 +89,7 @@ class domainDecomposition
|
||||
// sign.
|
||||
labelListList procFaceAddressing_;
|
||||
|
||||
//- Labels of cells for each processor
|
||||
//- For each processor cell, the complete point index
|
||||
labelListList procCellAddressing_;
|
||||
|
||||
|
||||
@ -128,7 +135,7 @@ class domainDecomposition
|
||||
template<class BinaryOp>
|
||||
inline void processInterCyclics
|
||||
(
|
||||
const labelList& cellToProc,
|
||||
const labelList& cellProc,
|
||||
const polyBoundaryMesh& patches,
|
||||
List<DynamicList<DynamicList<label>>>& interPatchFaces,
|
||||
List<Map<label>>& procNbrToInterPatch,
|
||||
@ -165,6 +172,35 @@ class domainDecomposition
|
||||
//- Validate that the processor meshes have been generated or read
|
||||
void validateProcs() const;
|
||||
|
||||
//- ...
|
||||
void readComplete();
|
||||
|
||||
//- ...
|
||||
void readProcs();
|
||||
|
||||
//- ...
|
||||
void readAddressing();
|
||||
|
||||
//- ...
|
||||
fvMesh::readUpdateState readUpdate();
|
||||
|
||||
//- ...
|
||||
void readUpdateDecompose(const fvMesh::readUpdateState& stat);
|
||||
|
||||
//- ...
|
||||
void readUpdateReconstruct(const fvMesh::readUpdateState& stat);
|
||||
|
||||
//- Decompose the complete mesh to create the processor meshes and
|
||||
// populate the addressing
|
||||
void decompose();
|
||||
|
||||
//- Reconstruct the processor meshes to create the complete mesh and
|
||||
// populate the addressing
|
||||
void reconstruct();
|
||||
|
||||
//- Write the decomposition addressing
|
||||
void writeAddressing() const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
@ -208,28 +244,27 @@ public:
|
||||
return runTimes_.nProcs();
|
||||
}
|
||||
|
||||
//- ...
|
||||
void readComplete();
|
||||
//- Read in the complete mesh. Read the processor meshes if they are
|
||||
// available and up to date relative to the complete mesh, or
|
||||
// decompose if not. Return whether or not decomposition happened.
|
||||
bool readDecompose(const bool doSets);
|
||||
|
||||
//- Read in the processor meshes. Read the complete mesh if it is
|
||||
// available and up to date relative to the processor meshes, or
|
||||
// reconstruct if not. Return whether or not reconstruction happened.
|
||||
bool readReconstruct(const bool doSets);
|
||||
|
||||
//- ...
|
||||
void readProcs();
|
||||
fvMesh::readUpdateState readUpdateDecompose();
|
||||
|
||||
//- ...
|
||||
void readAddressing();
|
||||
|
||||
//- ...
|
||||
fvMesh::readUpdateState readUpdate();
|
||||
|
||||
//- Decompose the complete mesh to create the processor meshes and
|
||||
// populate the addressing
|
||||
void decompose();
|
||||
|
||||
//- Reconstruct the processor meshes to create the complete mesh and
|
||||
// populate the addressing
|
||||
void reconstruct();
|
||||
fvMesh::readUpdateState readUpdateReconstruct();
|
||||
|
||||
//- Return the distribution as an FV field for writing
|
||||
labelList cellToProc() const;
|
||||
const labelList& cellProc() const
|
||||
{
|
||||
return cellProc_;
|
||||
}
|
||||
|
||||
//- Access the labels of points for each processor
|
||||
const labelListList& procPointAddressing() const
|
||||
@ -256,9 +291,6 @@ public:
|
||||
const PtrList<surfaceLabelField::Boundary>&
|
||||
procFaceAddressingBf() const;
|
||||
|
||||
//- Write the decomposition addressing
|
||||
void writeAddressing() const;
|
||||
|
||||
//- Write the decomposed meshes and associated data
|
||||
void writeComplete(const bool doSets) const;
|
||||
|
||||
|
||||
@ -178,7 +178,7 @@ Foam::labelList Foam::domainDecomposition::distributeCells()
|
||||
template<class BinaryOp>
|
||||
inline void Foam::domainDecomposition::processInterCyclics
|
||||
(
|
||||
const labelList& cellToProc,
|
||||
const labelList& cellProc,
|
||||
const polyBoundaryMesh& patches,
|
||||
List<DynamicList<DynamicList<label>>>& interPatchFaces,
|
||||
List<Map<label>>& procNbrToInterPatch,
|
||||
@ -209,12 +209,12 @@ inline void Foam::domainDecomposition::processInterCyclics
|
||||
forAll(origPatchFaceCells, origFacei)
|
||||
{
|
||||
const label ownerProc =
|
||||
cellToProc[origPatchFaceCells[origFacei]];
|
||||
cellProc[origPatchFaceCells[origFacei]];
|
||||
|
||||
forAll(nbrOrigPatchFaceCells, nbrOrigFacei)
|
||||
{
|
||||
const label nbrProc =
|
||||
cellToProc[nbrOrigPatchFaceCells[nbrOrigFacei]];
|
||||
cellProc[nbrOrigPatchFaceCells[nbrOrigFacei]];
|
||||
|
||||
if (bop(ownerProc, nbrProc))
|
||||
{
|
||||
@ -246,8 +246,8 @@ inline void Foam::domainDecomposition::processInterCyclics
|
||||
// Add faces with different owner and neighbour processors
|
||||
forAll(patchFaceCells, facei)
|
||||
{
|
||||
const label ownerProc = cellToProc[patchFaceCells[facei]];
|
||||
const label nbrProc = cellToProc[nbrPatchFaceCells[facei]];
|
||||
const label ownerProc = cellProc[patchFaceCells[facei]];
|
||||
const label nbrProc = cellProc[nbrPatchFaceCells[facei]];
|
||||
|
||||
if (bop(ownerProc, nbrProc))
|
||||
{
|
||||
@ -274,7 +274,7 @@ inline void Foam::domainDecomposition::processInterCyclics
|
||||
void Foam::domainDecomposition::decompose()
|
||||
{
|
||||
// Decide which cell goes to which processor
|
||||
const labelList cellToProc = distributeCells();
|
||||
cellProc_ = distributeCells();
|
||||
|
||||
// Distribute the cells according to the given processor label
|
||||
|
||||
@ -293,7 +293,7 @@ void Foam::domainDecomposition::decompose()
|
||||
Info<< "\nDistributing cells to processors" << endl;
|
||||
|
||||
// Cells per processor
|
||||
procCellAddressing_ = invertOneToMany(nProcs(), cellToProc);
|
||||
procCellAddressing_ = invertOneToMany(nProcs(), cellProc_);
|
||||
|
||||
Info<< "\nDistributing faces to processors" << endl;
|
||||
|
||||
@ -306,10 +306,10 @@ void Foam::domainDecomposition::decompose()
|
||||
// Internal faces
|
||||
forAll(neighbour, facei)
|
||||
{
|
||||
if (cellToProc[owner[facei]] == cellToProc[neighbour[facei]])
|
||||
if (cellProc_[owner[facei]] == cellProc_[neighbour[facei]])
|
||||
{
|
||||
// Face internal to processor. Notice no turning index.
|
||||
dynProcFaceAddressing[cellToProc[owner[facei]]].append(facei+1);
|
||||
dynProcFaceAddressing[cellProc_[owner[facei]]].append(facei+1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,7 +345,7 @@ void Foam::domainDecomposition::decompose()
|
||||
|
||||
forAll(patchFaceCells, facei)
|
||||
{
|
||||
const label curProc = cellToProc[patchFaceCells[facei]];
|
||||
const label curProc = cellProc_[patchFaceCells[facei]];
|
||||
|
||||
// add the face without turning index
|
||||
dynProcFaceAddressing[curProc].append(patchStart+facei+1);
|
||||
@ -367,8 +367,8 @@ void Foam::domainDecomposition::decompose()
|
||||
|
||||
forAll(patchFaceCells, facei)
|
||||
{
|
||||
const label curProc = cellToProc[patchFaceCells[facei]];
|
||||
const label nbrProc = cellToProc[nbrPatchFaceCells[facei]];
|
||||
const label curProc = cellProc_[patchFaceCells[facei]];
|
||||
const label nbrProc = cellProc_[nbrPatchFaceCells[facei]];
|
||||
|
||||
if (curProc == nbrProc)
|
||||
{
|
||||
@ -398,8 +398,8 @@ void Foam::domainDecomposition::decompose()
|
||||
// Processor boundaries from internal faces
|
||||
forAll(neighbour, facei)
|
||||
{
|
||||
label ownerProc = cellToProc[owner[facei]];
|
||||
label nbrProc = cellToProc[neighbour[facei]];
|
||||
const label ownerProc = cellProc_[owner[facei]];
|
||||
const label nbrProc = cellProc_[neighbour[facei]];
|
||||
|
||||
if (ownerProc != nbrProc)
|
||||
{
|
||||
@ -443,7 +443,7 @@ void Foam::domainDecomposition::decompose()
|
||||
|
||||
processInterCyclics
|
||||
(
|
||||
cellToProc,
|
||||
cellProc_,
|
||||
patches,
|
||||
interPatchFaces,
|
||||
procNbrToInterPatch,
|
||||
@ -455,7 +455,7 @@ void Foam::domainDecomposition::decompose()
|
||||
|
||||
processInterCyclics
|
||||
(
|
||||
cellToProc,
|
||||
cellProc_,
|
||||
patches,
|
||||
interPatchFaces,
|
||||
procNbrToInterPatch,
|
||||
@ -467,7 +467,7 @@ void Foam::domainDecomposition::decompose()
|
||||
|
||||
processInterCyclics
|
||||
(
|
||||
cellToProc,
|
||||
cellProc_,
|
||||
patches,
|
||||
interPatchFaces,
|
||||
procNbrToInterPatch,
|
||||
@ -479,7 +479,7 @@ void Foam::domainDecomposition::decompose()
|
||||
|
||||
processInterCyclics
|
||||
(
|
||||
cellToProc,
|
||||
cellProc_,
|
||||
patches,
|
||||
interPatchFaces,
|
||||
procNbrToInterPatch,
|
||||
|
||||
@ -24,21 +24,342 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "domainDecomposition.H"
|
||||
#include "decompositionMethod.H"
|
||||
#include "IOobjectList.H"
|
||||
#include "cyclicFvPatch.H"
|
||||
#include "processorCyclicFvPatch.H"
|
||||
#include "nonConformalCyclicFvPatch.H"
|
||||
#include "nonConformalProcessorCyclicFvPatch.H"
|
||||
#include "fvMeshAdder.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
autoPtr<faceCoupleInfo> determineCoupledFaces
|
||||
(
|
||||
const label masterMeshProcStart,
|
||||
const label masterMeshProcEnd,
|
||||
const polyMesh& masterMesh,
|
||||
const label meshToAddProcStart,
|
||||
const label meshToAddProcEnd,
|
||||
const polyMesh& meshToAdd
|
||||
)
|
||||
{
|
||||
const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
|
||||
const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
|
||||
|
||||
DynamicList<label> masterFaces
|
||||
(
|
||||
masterMesh.nFaces() - masterMesh.nInternalFaces()
|
||||
);
|
||||
DynamicList<label> addFaces
|
||||
(
|
||||
meshToAdd.nFaces() - meshToAdd.nInternalFaces()
|
||||
);
|
||||
|
||||
for
|
||||
(
|
||||
label masterProci = masterMeshProcStart;
|
||||
masterProci < masterMeshProcEnd;
|
||||
masterProci++
|
||||
)
|
||||
{
|
||||
for
|
||||
(
|
||||
label addProci = meshToAddProcStart;
|
||||
addProci < meshToAddProcEnd;
|
||||
addProci++
|
||||
)
|
||||
{
|
||||
const word masterToAddName
|
||||
(
|
||||
"procBoundary" + name(masterProci) + "to" + name(addProci)
|
||||
);
|
||||
const word addToMasterName
|
||||
(
|
||||
"procBoundary" + name(addProci) + "to" + name(masterProci)
|
||||
);
|
||||
|
||||
const label masterToAddID =
|
||||
masterPatches.findPatchID(masterToAddName);
|
||||
const label addToMasterID =
|
||||
addPatches.findPatchID(addToMasterName);
|
||||
|
||||
if (masterToAddID != -1 && addToMasterID != -1)
|
||||
{
|
||||
const polyPatch& masterPp = masterPatches[masterToAddID];
|
||||
|
||||
forAll(masterPp, i)
|
||||
{
|
||||
masterFaces.append(masterPp.start() + i);
|
||||
}
|
||||
|
||||
const polyPatch& addPp = addPatches[addToMasterID];
|
||||
|
||||
forAll(addPp, i)
|
||||
{
|
||||
addFaces.append(addPp.start() + i);
|
||||
}
|
||||
}
|
||||
|
||||
if ((masterToAddID != -1) != (addToMasterID != -1))
|
||||
{
|
||||
const label foundProci =
|
||||
masterToAddID != -1 ? masterProci : addProci;
|
||||
const word& foundName =
|
||||
masterToAddID != -1 ? masterToAddName : addToMasterName;
|
||||
|
||||
const label missingProci =
|
||||
masterToAddID != -1 ? addProci : masterProci;
|
||||
const word& missingName =
|
||||
masterToAddID != -1 ? addToMasterName : masterToAddName;
|
||||
|
||||
FatalErrorInFunction
|
||||
<< "Patch " << foundName << " found on processor "
|
||||
<< foundProci << " but corresponding patch "
|
||||
<< missingName << " missing on processor "
|
||||
<< missingProci << exit(FatalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
masterFaces.shrink();
|
||||
addFaces.shrink();
|
||||
|
||||
return autoPtr<faceCoupleInfo>
|
||||
(
|
||||
new faceCoupleInfo
|
||||
(
|
||||
masterMesh,
|
||||
masterFaces,
|
||||
meshToAdd,
|
||||
addFaces
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::domainDecomposition::reconstruct()
|
||||
{
|
||||
// To-do: The plan is to paste most of reconstructParMesh in here. Then,
|
||||
// reconstructPar could be tinkered with such that it automatically
|
||||
// reconstructs the mesh when necessary.
|
||||
NotImplemented;
|
||||
Info<< "Reconstructing meshes" << incrIndent << nl << endl;
|
||||
|
||||
// ???
|
||||
PtrList<fvMesh> masterMeshes(nProcs());
|
||||
|
||||
// ???
|
||||
for (label proci=0; proci<nProcs(); proci++)
|
||||
{
|
||||
masterMeshes.set
|
||||
(
|
||||
proci,
|
||||
new fvMesh
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
regionName_,
|
||||
procMeshes()[0].facesInstance(),
|
||||
runTimes_.completeTime()
|
||||
),
|
||||
pointField(),
|
||||
faceList(),
|
||||
cellList()
|
||||
)
|
||||
);
|
||||
fvMesh& masterMesh = masterMeshes[proci];
|
||||
masterMesh.setPointsInstance(procMeshes()[0].pointsInstance());
|
||||
|
||||
// Initialise the addressing
|
||||
procPointAddressing_[proci] = identity(procMeshes()[proci].nPoints());
|
||||
procFaceAddressing_[proci] = identity(procMeshes()[proci].nFaces());
|
||||
procCellAddressing_[proci] = identity(procMeshes()[proci].nCells());
|
||||
|
||||
// Find shared points and faces
|
||||
autoPtr<faceCoupleInfo> couples = determineCoupledFaces
|
||||
(
|
||||
proci,
|
||||
proci,
|
||||
masterMesh,
|
||||
proci,
|
||||
proci,
|
||||
procMeshes()[proci]
|
||||
);
|
||||
|
||||
// Add elements to the master mesh
|
||||
autoPtr<mapAddedPolyMesh> map = fvMeshAdder::add
|
||||
(
|
||||
masterMesh,
|
||||
procMeshes()[proci],
|
||||
couples
|
||||
);
|
||||
|
||||
// Renumber addressing following the add
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedPointMap(),
|
||||
procPointAddressing_[proci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedFaceMap(),
|
||||
procFaceAddressing_[proci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedCellMap(),
|
||||
procCellAddressing_[proci]
|
||||
);
|
||||
}
|
||||
|
||||
// Merge the meshes
|
||||
for (label step=2; step<nProcs()*2; step*=2)
|
||||
{
|
||||
for (label proci=0; proci<nProcs(); proci+=step)
|
||||
{
|
||||
label procj = proci + step/2;
|
||||
|
||||
if (procj >= nProcs()) continue;
|
||||
|
||||
Info<< indent << "Merging mesh " << proci
|
||||
<< " with " << procj << endl;
|
||||
|
||||
// Find shared points/faces
|
||||
autoPtr<faceCoupleInfo> couples = determineCoupledFaces
|
||||
(
|
||||
proci,
|
||||
procj,
|
||||
masterMeshes[proci],
|
||||
procj,
|
||||
proci+step,
|
||||
masterMeshes[procj]
|
||||
);
|
||||
|
||||
// Add elements to mesh
|
||||
autoPtr<mapAddedPolyMesh> map = fvMeshAdder::add
|
||||
(
|
||||
masterMeshes[proci],
|
||||
masterMeshes[procj],
|
||||
couples
|
||||
);
|
||||
|
||||
// Renumber processors that were already present
|
||||
for
|
||||
(
|
||||
label mergedProci = proci;
|
||||
mergedProci < procj;
|
||||
mergedProci ++
|
||||
)
|
||||
{
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldPointMap(),
|
||||
procPointAddressing_[mergedProci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldFaceMap(),
|
||||
procFaceAddressing_[mergedProci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().oldCellMap(),
|
||||
procCellAddressing_[mergedProci]
|
||||
);
|
||||
}
|
||||
|
||||
// Renumber processors that were just added
|
||||
for
|
||||
(
|
||||
label addedProci = procj;
|
||||
addedProci < min(proci + step, nProcs());
|
||||
addedProci ++
|
||||
)
|
||||
{
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedPointMap(),
|
||||
procPointAddressing_[addedProci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedFaceMap(),
|
||||
procFaceAddressing_[addedProci]
|
||||
);
|
||||
inplaceRenumber
|
||||
(
|
||||
map().addedCellMap(),
|
||||
procCellAddressing_[addedProci]
|
||||
);
|
||||
}
|
||||
|
||||
masterMeshes.set(procj, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the complete mesh
|
||||
completeMesh_.reset(masterMeshes.set(0, nullptr).ptr());
|
||||
completeMesh_->setInstance(procMeshes()[0].facesInstance());
|
||||
completeMesh_->setPointsInstance(procMeshes()[0].pointsInstance());
|
||||
|
||||
// Add turning index to the face addressing
|
||||
for (label proci=0; proci<nProcs(); proci++)
|
||||
{
|
||||
const fvMesh& procMesh = procMeshes_[proci];
|
||||
|
||||
forAll(procFaceAddressing_[proci], procFacei)
|
||||
{
|
||||
const label completeFacei = procFaceAddressing_[proci][procFacei];
|
||||
|
||||
if
|
||||
(
|
||||
!procMesh.isInternalFace(procFacei)
|
||||
&& completeMesh().isInternalFace(completeFacei)
|
||||
)
|
||||
{
|
||||
// Processor face is external, but the corresponding complete
|
||||
// face is internal. Turn if the owner has changed.
|
||||
|
||||
const label procOwnCelli =
|
||||
procMesh.faceOwner()[procFacei];
|
||||
const label completeOwnCelli =
|
||||
completeMesh().faceOwner()[completeFacei];
|
||||
|
||||
if
|
||||
(
|
||||
procCellAddressing_[proci][procOwnCelli]
|
||||
== completeOwnCelli
|
||||
)
|
||||
{
|
||||
procFaceAddressing_[proci][procFacei] ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
procFaceAddressing_[proci][procFacei] =
|
||||
-1 - procFaceAddressing_[proci][procFacei];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Processor face is the same (internal/external) as the
|
||||
// corresponding complete face
|
||||
|
||||
procFaceAddressing_[proci][procFacei] ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear (and thus trigger re-generation) of finite volume face addressing
|
||||
procFaceAddressingBf_.clear();
|
||||
|
||||
// Construct complete cell to proc map
|
||||
cellProc_.resize(completeMesh().nCells());
|
||||
forAll(procCellAddressing_, proci)
|
||||
{
|
||||
forAll(procCellAddressing_[proci], procCelli)
|
||||
{
|
||||
cellProc_[procCellAddressing_[proci][procCelli]] = proci;
|
||||
}
|
||||
}
|
||||
|
||||
Info<< decrIndent << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -14,7 +14,6 @@ runParallel -s par $(getApplication)
|
||||
runParallel -s par checkMesh
|
||||
runParallel -s par foamToEnsight
|
||||
|
||||
runApplication reconstructParMesh
|
||||
# This will fail for any processors that does not have any local patches
|
||||
# added so exclude that time
|
||||
runApplication reconstructPar -time '0:0.01'
|
||||
|
||||
@ -18,21 +18,11 @@ numberOfSubdomains 4;
|
||||
|
||||
method hierarchical;
|
||||
|
||||
simpleCoeffs
|
||||
{
|
||||
n (1 2 2);
|
||||
}
|
||||
|
||||
hierarchicalCoeffs
|
||||
{
|
||||
n (1 2 2);
|
||||
order xyz;
|
||||
}
|
||||
|
||||
manualCoeffs
|
||||
{
|
||||
dataFile "cellDecomposition";
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -18,21 +18,5 @@ numberOfSubdomains 2;
|
||||
|
||||
method scotch;
|
||||
|
||||
simpleCoeffs
|
||||
{
|
||||
n (4 1 1);
|
||||
}
|
||||
|
||||
hierarchicalCoeffs
|
||||
{
|
||||
n (3 2 1);
|
||||
order xyz;
|
||||
}
|
||||
|
||||
manualCoeffs
|
||||
{
|
||||
dataFile "cellDecomposition";
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -23,15 +23,5 @@ simpleCoeffs
|
||||
n (1 3 1);
|
||||
}
|
||||
|
||||
hierarchicalCoeffs
|
||||
{
|
||||
n (3 2 1);
|
||||
order xyz;
|
||||
}
|
||||
|
||||
manualCoeffs
|
||||
{
|
||||
dataFile "cellDecomposition";
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
Reference in New Issue
Block a user