ENH: combine loadOrCreateMesh from redistributePar into fvMeshTools.

- similar functionality as newMesh etc.
  Relocated to finiteVolume since there are no dynamicMesh dependencies.

- use simpler procAddressing (with updated mapDistributeBase).
  separated from redistributePar
This commit is contained in:
Mark Olesen 2022-05-02 17:36:22 +02:00
parent b712e7289e
commit 68b692fdfc
12 changed files with 1754 additions and 1809 deletions

View File

@ -27,377 +27,62 @@ License
\*---------------------------------------------------------------------------*/
#include "loadOrCreateMesh.H"
#include "processorPolyPatch.H"
#include "processorCyclicPolyPatch.H"
#include "Time.H"
#include "polyBoundaryMeshEntries.H"
#include "IOobjectList.H"
#include "pointSet.H"
#include "faceSet.H"
#include "cellSet.H"
#include "basicFvGeometryScheme.H"
#include "Pstream.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
// Read mesh if available. Otherwise create empty mesh with same non-proc
// patches as proc0 mesh. Requires:
// - all processors to have all patches (and in same order).
// - io.instance() set to facesInstance
Foam::autoPtr<Foam::fvMesh> Foam::loadOrCreateMesh
Foam::boolList Foam::haveMeshFile
(
const bool decompose,
const IOobject& io
const Time& runTime,
const fileName& meshPath,
const word& meshFile,
const bool verbose
)
{
// Region name
// ~~~~~~~~~~~
fileName meshSubDir;
if (io.name() == polyMesh::defaultRegion)
{
meshSubDir = polyMesh::meshSubDir;
}
else
{
meshSubDir = io.name()/polyMesh::meshSubDir;
}
// Patch types
// ~~~~~~~~~~~
// Read and scatter master patches (without reading master mesh!)
PtrList<entry> patchEntries;
if (Pstream::master())
{
const bool oldParRun = Pstream::parRun(false);
patchEntries = polyBoundaryMeshEntries
boolList haveFileOnProc
(
UPstream::listGatherValues<bool>
(
IOobject
fileHandler().isFile
(
"boundary",
io.instance(), //facesInstance,
meshSubDir,
io.db(),
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
)
);
Pstream::parRun(oldParRun);
}
// Broadcast: send patches to all
Pstream::scatter(patchEntries); // == worldComm;
// Dummy meshes
// ~~~~~~~~~~~~
// Check who has a mesh
bool haveMesh;
if (decompose)
{
// Mesh needs to be present on the master only
haveMesh = Pstream::master();
}
else
{
const fileName facesFile
(
io.time().path()
/io.instance() //facesInstance
/meshSubDir
/"faces"
);
// Check presence of the searched-for faces file
haveMesh = fileHandler().isFile(fileHandler().filePath(facesFile));
}
if (!haveMesh)
{
const bool oldParRun = Pstream::parRun(false);
// Create dummy mesh. Only used on procs that don't have mesh.
IOobject noReadIO(io);
noReadIO.readOpt(IOobject::NO_READ);
noReadIO.writeOpt(IOobject::AUTO_WRITE);
fvMesh dummyMesh(noReadIO, Zero, false);
// Add patches
List<polyPatch*> patches(patchEntries.size());
label nPatches = 0;
forAll(patchEntries, patchi)
{
const entry& e = patchEntries[patchi];
const word type(e.dict().get<word>("type"));
const word& name = e.keyword();
if
(
type != processorPolyPatch::typeName
&& type != processorCyclicPolyPatch::typeName
)
{
dictionary patchDict(e.dict());
patchDict.set("nFaces", 0);
patchDict.set("startFace", 0);
patches[patchi] = polyPatch::New
fileHandler().filePath
(
name,
patchDict,
nPatches++,
dummyMesh.boundaryMesh()
).ptr();
}
}
patches.setSize(nPatches);
dummyMesh.addFvPatches(patches, false); // no parallel comms
// Add some dummy zones so upon reading it does not read them
// from the undecomposed case. Should be done as extra argument to
// regIOobject::readStream?
List<pointZone*> pz
(
1,
new pointZone
(
"dummyPointZone",
0,
dummyMesh.pointZones()
runTime.path()/meshPath/meshFile
)
)
);
List<faceZone*> fz
(
1,
new faceZone
(
"dummyFaceZone",
0,
dummyMesh.faceZones()
)
);
List<cellZone*> cz
(
1,
new cellZone
(
"dummyCellZone",
0,
dummyMesh.cellZones()
)
);
dummyMesh.addZones(pz, fz, cz);
dummyMesh.pointZones().clear();
dummyMesh.faceZones().clear();
dummyMesh.cellZones().clear();
//Pout<< "Writing dummy mesh to " << dummyMesh.polyMesh::objectPath()
// << endl;
dummyMesh.write();
)
);
Pstream::parRun(oldParRun); // Restore parallel state
}
// Read mesh
// ~~~~~~~~~
// Now all processors have a (possibly zero size) mesh so read in
// parallel
//Pout<< "Reading mesh from " << io.objectPath() << endl;
auto meshPtr = autoPtr<fvMesh>::New(io);
fvMesh& mesh = *meshPtr;
// Make sure to use a non-parallel geometry calculation method
if (verbose)
{
tmp<fvGeometryScheme> basicGeometry
(
fvGeometryScheme::New
(
mesh,
dictionary(),
basicFvGeometryScheme::typeName
)
);
mesh.geometry(basicGeometry);
Info<< "Per processor availability of \""
<< meshFile << "\" file in " << meshPath << nl
<< " " << flatOutput(haveFileOnProc) << nl << endl;
}
Pstream::broadcast(haveFileOnProc);
return haveFileOnProc;
}
// Sync patches
// ~~~~~~~~~~~~
if (!Pstream::master() && haveMesh)
void Foam::removeProcAddressing(const polyMesh& mesh)
{
IOobject ioAddr
(
"procAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh.thisDb()
);
for (const auto prefix : {"boundary", "cell", "face", "point"})
{
// Check master names against mine
ioAddr.rename(prefix + word("ProcAddressing"));
const polyBoundaryMesh& patches = mesh.boundaryMesh();
forAll(patchEntries, patchi)
{
const entry& e = patchEntries[patchi];
const word type(e.dict().get<word>("type"));
const word& name = e.keyword();
if
(
type == processorPolyPatch::typeName
|| type == processorCyclicPolyPatch::typeName
)
{
break;
}
if (patchi >= patches.size())
{
FatalErrorInFunction
<< "Non-processor patches not synchronised."
<< endl
<< "Processor " << Pstream::myProcNo()
<< " has only " << patches.size()
<< " patches, master has "
<< patchi
<< exit(FatalError);
}
if
(
type != patches[patchi].type()
|| name != patches[patchi].name()
)
{
FatalErrorInFunction
<< "Non-processor patches not synchronised."
<< endl
<< "Master patch " << patchi
<< " name:" << type
<< " type:" << type << endl
<< "Processor " << Pstream::myProcNo()
<< " patch " << patchi
<< " has name:" << patches[patchi].name()
<< " type:" << patches[patchi].type()
<< exit(FatalError);
}
}
const fileName procFile(ioAddr.objectPath());
Foam::rm(procFile);
}
// Determine zones
// ~~~~~~~~~~~~~~~
wordList pointZoneNames(mesh.pointZones().names());
Pstream::scatter(pointZoneNames);
wordList faceZoneNames(mesh.faceZones().names());
Pstream::scatter(faceZoneNames);
wordList cellZoneNames(mesh.cellZones().names());
Pstream::scatter(cellZoneNames);
if (!haveMesh)
{
// Add the zones. Make sure to remove the old dummy ones first
mesh.pointZones().clear();
mesh.faceZones().clear();
mesh.cellZones().clear();
List<pointZone*> pz(pointZoneNames.size());
forAll(pointZoneNames, i)
{
pz[i] = new pointZone
(
pointZoneNames[i],
i,
mesh.pointZones()
);
}
List<faceZone*> fz(faceZoneNames.size());
forAll(faceZoneNames, i)
{
fz[i] = new faceZone
(
faceZoneNames[i],
i,
mesh.faceZones()
);
}
List<cellZone*> cz(cellZoneNames.size());
forAll(cellZoneNames, i)
{
cz[i] = new cellZone
(
cellZoneNames[i],
i,
mesh.cellZones()
);
}
mesh.addZones(pz, fz, cz);
}
// Determine sets
// ~~~~~~~~~~~~~~
wordList pointSetNames;
wordList faceSetNames;
wordList cellSetNames;
if (Pstream::master())
{
// Read sets
const bool oldParRun = Pstream::parRun(false);
IOobjectList objects(mesh, mesh.facesInstance(), "polyMesh/sets");
Pstream::parRun(oldParRun);
pointSetNames = objects.sortedNames(pointSet::typeName);
faceSetNames = objects.sortedNames(faceSet::typeName);
cellSetNames = objects.sortedNames(cellSet::typeName);
}
Pstream::scatter(pointSetNames);
Pstream::scatter(faceSetNames);
Pstream::scatter(cellSetNames);
if (!haveMesh)
{
for (const word& setName : pointSetNames)
{
pointSet(mesh, setName, 0).write();
}
for (const word& setName : faceSetNames)
{
faceSet(mesh, setName, 0).write();
}
for (const word& setName : cellSetNames)
{
cellSet(mesh, setName, 0).write();
}
}
// Force recreation of globalMeshData.
mesh.globalData();
// Do some checks.
// Check if the boundary definition is unique
mesh.boundaryMesh().checkDefinition(true);
// Check if the boundary processor patches are correct
mesh.boundaryMesh().checkParallelSync(true);
// Check names of zones are equal
mesh.cellZones().checkDefinition(true);
mesh.cellZones().checkParallelSync(true);
mesh.faceZones().checkDefinition(true);
mesh.faceZones().checkParallelSync(true);
mesh.pointZones().checkDefinition(true);
mesh.pointZones().checkParallelSync(true);
return meshPtr;
}

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,29 +28,35 @@ InNamespace
Foam
Description
Load or create (0 size) a mesh. Used in distributing meshes to a
larger number of processors
Miscellaneous file handling for meshes.
SourceFiles
loadOrCreateMesh.C
\*---------------------------------------------------------------------------*/
#ifndef loadOrCreateMesh_H
#define loadOrCreateMesh_H
#ifndef Foam_loadOrCreateMesh_H
#define Foam_loadOrCreateMesh_H
#include "fvMesh.H"
#include "fvMeshTools.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
//- Load (if it exists) or create zero cell mesh given an IOobject:
// name : regionName
// instance : exact directory where to find mesh (i.e. does not
// do a findInstance
autoPtr<fvMesh> loadOrCreateMesh(const bool decompose, const IOobject& io);
//- Check for availability of specified mesh file (default: "faces")
boolList haveMeshFile
(
const Time& runTime,
const fileName& meshPath,
const word& meshFile = "faces",
const bool verbose = true
);
//- Remove procAddressing
void removeProcAddressing(const polyMesh& mesh);
//- Remove empty directory. Return true if removed.
bool removeEmptyDir(const fileName& path);

View File

@ -92,7 +92,6 @@ Usage
#include "zeroGradientFvPatchFields.H"
#include "topoSet.H"
#include "regionProperties.H"
#include "basicFvGeometryScheme.H"
#include "parFvFieldReconstructor.H"
#include "parLagrangianRedistributor.H"
@ -257,49 +256,6 @@ void copyUniform
}
boolList haveFacesFile(const fileName& meshPath)
{
const fileName facesPath(meshPath/"faces");
Info<< "Checking for mesh in " << facesPath << nl << endl;
boolList haveMesh
(
UPstream::listGatherValues<bool>
(
fileHandler().isFile(fileHandler().filePath(facesPath))
)
);
Info<< "Per processor mesh availability:" << nl
<< " " << flatOutput(haveMesh) << nl << endl;
Pstream::broadcast(haveMesh);
return haveMesh;
}
void setBasicGeometry(fvMesh& mesh)
{
// Set the fvGeometryScheme to basic since it does not require
// any parallel communication to construct the geometry. During
// redistributePar one might temporarily end up with processors
// with zero procBoundaries. Normally procBoundaries trigger geometry
// calculation (e.g. send over cellCentres) so on the processors without
// procBoundaries this will not happen. The call to the geometry calculation
// is not synchronised and this might lead to a hang for geometry schemes
// that do require synchronisation
tmp<fvGeometryScheme> basicGeometry
(
fvGeometryScheme::New
(
mesh,
dictionary(),
basicFvGeometryScheme::typeName
)
);
mesh.geometry(basicGeometry);
}
void printMeshData(const polyMesh& mesh)
{
// Collect all data on master
@ -557,213 +513,6 @@ void determineDecomposition
}
// Write addressing if decomposing (1 to many) or reconstructing (many to 1)
void writeProcAddressing
(
autoPtr<fileOperation>&& writeHandler,
const fvMesh& mesh,
const mapDistributePolyMesh& map,
const bool decompose
)
{
Info<< "Writing procAddressing files to " << mesh.facesInstance()
<< endl;
labelIOList cellMap
(
IOobject
(
"cellProcAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh,
IOobject::NO_READ
),
0
);
labelIOList faceMap
(
IOobject
(
"faceProcAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh,
IOobject::NO_READ
),
0
);
labelIOList pointMap
(
IOobject
(
"pointProcAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh,
IOobject::NO_READ
),
0
);
labelIOList patchMap
(
IOobject
(
"boundaryProcAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh,
IOobject::NO_READ
),
0
);
// Decomposing: see how cells moved from undecomposed case
if (decompose)
{
cellMap = identity(map.nOldCells());
map.distributeCellData(cellMap);
faceMap = identity(map.nOldFaces());
{
const mapDistribute& faceDistMap = map.faceMap();
if (faceDistMap.subHasFlip() || faceDistMap.constructHasFlip())
{
// Offset by 1
faceMap = faceMap + 1;
}
// Apply face flips
mapDistributeBase::distribute
(
Pstream::commsTypes::nonBlocking,
List<labelPair>(),
faceDistMap.constructSize(),
faceDistMap.subMap(),
faceDistMap.subHasFlip(),
faceDistMap.constructMap(),
faceDistMap.constructHasFlip(),
faceMap,
flipLabelOp()
);
}
pointMap = identity(map.nOldPoints());
map.distributePointData(pointMap);
patchMap = identity(map.oldPatchSizes().size());
const mapDistribute& patchDistMap = map.patchMap();
// Use explicit distribute since we need to provide a null value
// (for new patches) and this is the only call that allow us to
// provide one ...
mapDistributeBase::distribute
(
Pstream::commsTypes::nonBlocking,
List<labelPair>(),
patchDistMap.constructSize(),
patchDistMap.subMap(),
patchDistMap.subHasFlip(),
patchDistMap.constructMap(),
patchDistMap.constructHasFlip(),
patchMap,
label(-1),
eqOp<label>(),
flipOp(),
UPstream::msgType()
);
}
else // reconstruct
{
cellMap = identity(mesh.nCells());
map.cellMap().reverseDistribute(map.nOldCells(), cellMap);
faceMap = identity(mesh.nFaces());
{
const mapDistribute& faceDistMap = map.faceMap();
if (faceDistMap.subHasFlip() || faceDistMap.constructHasFlip())
{
// Offset by 1
faceMap = faceMap + 1;
}
mapDistributeBase::distribute
(
Pstream::commsTypes::nonBlocking,
List<labelPair>(),
map.nOldFaces(),
faceDistMap.constructMap(),
faceDistMap.constructHasFlip(),
faceDistMap.subMap(),
faceDistMap.subHasFlip(),
faceMap,
flipLabelOp()
);
}
pointMap = identity(mesh.nPoints());
map.pointMap().reverseDistribute(map.nOldPoints(), pointMap);
const mapDistribute& patchDistMap = map.patchMap();
patchMap = identity(mesh.boundaryMesh().size());
patchDistMap.reverseDistribute
(
map.oldPatchSizes().size(),
label(-1),
patchMap
);
}
autoPtr<fileOperation> defaultHandler;
if (writeHandler)
{
defaultHandler = fileHandler(std::move(writeHandler));
}
const bool cellOk = cellMap.write();
const bool faceOk = faceMap.write();
const bool pointOk = pointMap.write();
const bool patchOk = patchMap.write();
if (defaultHandler)
{
writeHandler = fileHandler(std::move(defaultHandler));
}
if (!cellOk || !faceOk || !pointOk || !patchOk)
{
WarningInFunction
<< "Failed to write " << cellMap.objectPath()
<< ", " << faceMap.objectPath()
<< ", " << pointMap.objectPath()
<< ", " << patchMap.objectPath()
<< endl;
}
}
// Remove addressing
void removeProcAddressing(const polyMesh& mesh)
{
for (const auto prefix : {"boundary", "cell", "face", "point"})
{
IOobject io
(
prefix + word("ProcAddressing"),
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh
);
const fileName procFile(io.objectPath());
rm(procFile);
}
}
// Generic mesh-based field reading
template<class GeoField>
void readField
@ -1391,7 +1140,13 @@ autoPtr<mapDistributePolyMesh> redistributeAndWrite
{
// Decompose (1 -> N) or reconstruct (N -> 1)
// so {boundary,cell,face,point}ProcAddressing have meaning
writeProcAddressing(std::move(writeHandler), mesh, map, decompose);
fvMeshTools::writeProcAddressing
(
mesh,
map,
decompose,
std::move(writeHandler)
);
}
else
{
@ -1531,322 +1286,6 @@ autoPtr<mapDistributePolyMesh> redistributeAndWrite
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
autoPtr<mapDistributePolyMesh> createReconstructMap
(
const autoPtr<fvMesh>& baseMeshPtr,
const fvMesh& mesh,
const labelList& cellProcAddressing,
const labelList& faceProcAddressing,
const labelList& pointProcAddressing,
const labelList& boundaryProcAddressing
)
{
// Send addressing to master
labelListList cellAddressing(Pstream::nProcs());
cellAddressing[Pstream::myProcNo()] = cellProcAddressing;
Pstream::gatherList(cellAddressing);
labelListList faceAddressing(Pstream::nProcs());
faceAddressing[Pstream::myProcNo()] = faceProcAddressing;
Pstream::gatherList(faceAddressing);
labelListList pointAddressing(Pstream::nProcs());
pointAddressing[Pstream::myProcNo()] = pointProcAddressing;
Pstream::gatherList(pointAddressing);
labelListList boundaryAddressing(Pstream::nProcs());
{
// Remove -1 entries
DynamicList<label> patchProcAddressing(boundaryProcAddressing.size());
forAll(boundaryProcAddressing, i)
{
if (boundaryProcAddressing[i] != -1)
{
patchProcAddressing.append(boundaryProcAddressing[i]);
}
}
boundaryAddressing[Pstream::myProcNo()] = patchProcAddressing;
Pstream::gatherList(boundaryAddressing);
}
autoPtr<mapDistributePolyMesh> mapPtr;
if (baseMeshPtr && baseMeshPtr->nCells())
{
const fvMesh& baseMesh = *baseMeshPtr;
labelListList cellSubMap(Pstream::nProcs());
cellSubMap[Pstream::masterNo()] = identity(mesh.nCells());
mapDistribute cellMap
(
baseMesh.nCells(),
std::move(cellSubMap),
std::move(cellAddressing)
);
labelListList faceSubMap(Pstream::nProcs());
faceSubMap[Pstream::masterNo()] = identity(mesh.nFaces());
mapDistribute faceMap
(
baseMesh.nFaces(),
std::move(faceSubMap),
std::move(faceAddressing),
false, //subHasFlip
true //constructHasFlip
);
labelListList pointSubMap(Pstream::nProcs());
pointSubMap[Pstream::masterNo()] = identity(mesh.nPoints());
mapDistribute pointMap
(
baseMesh.nPoints(),
std::move(pointSubMap),
std::move(pointAddressing)
);
labelListList patchSubMap(Pstream::nProcs());
// Send (filtered) patches to master
patchSubMap[Pstream::masterNo()] =
boundaryAddressing[Pstream::myProcNo()];
mapDistribute patchMap
(
baseMesh.boundaryMesh().size(),
std::move(patchSubMap),
std::move(boundaryAddressing)
);
const label nOldPoints = mesh.nPoints();
const label nOldFaces = mesh.nFaces();
const label nOldCells = mesh.nCells();
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
labelList oldPatchStarts(pbm.size());
labelList oldPatchNMeshPoints(pbm.size());
forAll(pbm, patchI)
{
oldPatchStarts[patchI] = pbm[patchI].start();
oldPatchNMeshPoints[patchI] = pbm[patchI].nPoints();
}
mapPtr.reset
(
new mapDistributePolyMesh
(
nOldPoints,
nOldFaces,
nOldCells,
std::move(oldPatchStarts),
std::move(oldPatchNMeshPoints),
std::move(pointMap),
std::move(faceMap),
std::move(cellMap),
std::move(patchMap)
)
);
}
else
{
labelListList cellSubMap(Pstream::nProcs());
cellSubMap[Pstream::masterNo()] = identity(mesh.nCells());
labelListList cellConstructMap(Pstream::nProcs());
mapDistribute cellMap
(
0,
std::move(cellSubMap),
std::move(cellConstructMap)
);
labelListList faceSubMap(Pstream::nProcs());
faceSubMap[Pstream::masterNo()] = identity(mesh.nFaces());
labelListList faceConstructMap(Pstream::nProcs());
mapDistribute faceMap
(
0,
std::move(faceSubMap),
std::move(faceConstructMap),
false, //subHasFlip
true //constructHasFlip
);
labelListList pointSubMap(Pstream::nProcs());
pointSubMap[Pstream::masterNo()] = identity(mesh.nPoints());
labelListList pointConstructMap(Pstream::nProcs());
mapDistribute pointMap
(
0,
std::move(pointSubMap),
std::move(pointConstructMap)
);
labelListList patchSubMap(Pstream::nProcs());
// Send (filtered) patches to master
patchSubMap[Pstream::masterNo()] =
boundaryAddressing[Pstream::myProcNo()];
labelListList patchConstructMap(Pstream::nProcs());
mapDistribute patchMap
(
0,
std::move(patchSubMap),
std::move(patchConstructMap)
);
const label nOldPoints = mesh.nPoints();
const label nOldFaces = mesh.nFaces();
const label nOldCells = mesh.nCells();
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
labelList oldPatchStarts(pbm.size());
labelList oldPatchNMeshPoints(pbm.size());
forAll(pbm, patchI)
{
oldPatchStarts[patchI] = pbm[patchI].start();
oldPatchNMeshPoints[patchI] = pbm[patchI].nPoints();
}
mapPtr.reset
(
new mapDistributePolyMesh
(
nOldPoints,
nOldFaces,
nOldCells,
std::move(oldPatchStarts),
std::move(oldPatchNMeshPoints),
std::move(pointMap),
std::move(faceMap),
std::move(cellMap),
std::move(patchMap)
)
);
}
return mapPtr;
}
void readProcAddressing
(
const fvMesh& mesh,
const autoPtr<fvMesh>& baseMeshPtr,
autoPtr<mapDistributePolyMesh>& distMap
)
{
//IOobject io
//(
// "procAddressing",
// mesh.facesInstance(),
// polyMesh::meshSubDir,
// mesh,
// IOobject::MUST_READ
//);
//if (io.typeHeaderOk<labelIOList>(true))
//{
// Pout<< "Reading addressing from " << io.name() << " at "
// << mesh.facesInstance() << nl << endl;
// distMap.reset(new IOmapDistributePolyMesh(io));
//}
//else
{
Info<< "Reading addressing from procXXXAddressing at "
<< mesh.facesInstance() << nl << endl;
labelIOList cellProcAddressing
(
IOobject
(
"cellProcAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh,
IOobject::READ_IF_PRESENT
),
labelList()
);
labelIOList faceProcAddressing
(
IOobject
(
"faceProcAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh,
IOobject::READ_IF_PRESENT
),
labelList()
);
labelIOList pointProcAddressing
(
IOobject
(
"pointProcAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh,
IOobject::READ_IF_PRESENT
),
labelList()
);
labelIOList boundaryProcAddressing
(
IOobject
(
"boundaryProcAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh,
IOobject::READ_IF_PRESENT
),
labelList()
);
if
(
mesh.nCells() != cellProcAddressing.size()
|| mesh.nPoints() != pointProcAddressing.size()
|| mesh.nFaces() != faceProcAddressing.size()
|| mesh.boundaryMesh().size() != boundaryProcAddressing.size()
)
{
FatalErrorInFunction
<< "Read addressing inconsistent with mesh sizes" << nl
<< "cells:" << mesh.nCells()
<< " addressing:" << cellProcAddressing.objectPath()
<< " size:" << cellProcAddressing.size() << nl
<< "faces:" << mesh.nFaces()
<< " addressing:" << faceProcAddressing.objectPath()
<< " size:" << faceProcAddressing.size() << nl
<< "points:" << mesh.nPoints()
<< " addressing:" << pointProcAddressing.objectPath()
<< " size:" << pointProcAddressing.size()
<< "patches:" << mesh.boundaryMesh().size()
<< " addressing:" << boundaryProcAddressing.objectPath()
<< " size:" << boundaryProcAddressing.size()
<< exit(FatalError);
}
distMap.clear();
distMap = createReconstructMap
(
baseMeshPtr,
mesh,
cellProcAddressing,
faceProcAddressing,
pointProcAddressing,
boundaryProcAddressing
);
}
}
void reconstructMeshFields
(
const parFvFieldReconstructor& fvReconstructor,
@ -2745,9 +2184,11 @@ int main(int argc, char *argv[])
// Check who has a mesh (by checking for 'faces' file)
const boolList haveMesh
(
haveFacesFile
haveMeshFile
(
runTime.path()/facesInstance/meshSubDir
runTime,
facesInstance/meshSubDir,
"faces"
)
);
@ -2840,22 +2281,22 @@ int main(int argc, char *argv[])
)
{
Info<< "loading mesh from " << facesInstance << endl;
autoPtr<fvMesh> meshPtr = loadOrCreateMesh
autoPtr<fvMesh> meshPtr = fvMeshTools::loadOrCreateMesh
(
decompose,
IOobject
(
regionName,
facesInstance,
runTime,
Foam::IOobject::MUST_READ
)
),
decompose
);
fvMesh& mesh = meshPtr();
// Use basic geometry calculation to avoid synchronisation
// problems. See comment in routine
setBasicGeometry(mesh);
fvMeshTools::setBasicGeometry(mesh);
// Determine decomposition
@ -2919,20 +2360,20 @@ int main(int argc, char *argv[])
true // read on master only
);
setBasicGeometry(baseMeshPtr());
fvMeshTools::setBasicGeometry(baseMeshPtr());
Info<< "Reading local, decomposed mesh" << endl;
autoPtr<fvMesh> meshPtr = loadOrCreateMesh
autoPtr<fvMesh> meshPtr = fvMeshTools::loadOrCreateMesh
(
decompose,
IOobject
(
regionName,
baseMeshPtr().facesInstance(),
runTime,
Foam::IOobject::MUST_READ
)
),
decompose
);
fvMesh& mesh = meshPtr();
@ -2949,7 +2390,7 @@ int main(int argc, char *argv[])
// Read addressing back to base mesh
autoPtr<mapDistributePolyMesh> distMap;
readProcAddressing(mesh, baseMeshPtr, distMap);
distMap = fvMeshTools::readProcAddressing(mesh, baseMeshPtr);
// Construct field mapper
autoPtr<parFvFieldReconstructor> fvReconstructorPtr
@ -3032,8 +2473,9 @@ int main(int argc, char *argv[])
);
}
// Re-read procXXXaddressing
readProcAddressing(mesh, baseMeshPtr, distMap);
// Re-read procaddressing
distMap =
fvMeshTools::readProcAddressing(mesh, baseMeshPtr);
// Reset field mapper
fvReconstructorPtr.reset
@ -3188,9 +2630,16 @@ int main(int argc, char *argv[])
}
Pstream::scatter(masterInstDir);
// Check who has a mesh
const fileName meshPath(runTime.path()/masterInstDir/meshSubDir);
const boolList haveMesh(haveFacesFile(meshPath));
// Check who has a polyMesh
const boolList haveMesh
(
haveMeshFile
(
runTime,
masterInstDir/meshSubDir,
"faces"
)
);
// Collect objectPath of polyMesh for the current file handler. This
// is where the mesh would be written if it didn't exist already.
@ -3222,17 +2671,16 @@ int main(int argc, char *argv[])
runTime.processorCase(false);
}
autoPtr<fvMesh> meshPtr = loadOrCreateMesh
autoPtr<fvMesh> meshPtr = fvMeshTools::loadOrCreateMesh
(
decompose,
//haveMesh[Pstream::myProcNo()],
IOobject
(
regionName,
masterInstDir,
runTime,
Foam::IOobject::MUST_READ
)
),
decompose
);
fvMesh& mesh = meshPtr();

View File

@ -84,8 +84,6 @@ fvMeshDistribute/fvMeshDistribute.C
polyMeshAdder/faceCoupleInfo.C
polyMeshAdder/polyMeshAdder.C
fvMeshTools/fvMeshTools.C
fvMeshSubset/fvMeshSubsetter.C
motionSmoother/motionSmoother.C

View File

@ -1841,10 +1841,9 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshDistribute::receiveMesh
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fvMeshDistribute::fvMeshDistribute(fvMesh& mesh)//, const scalar mergeTol)
Foam::fvMeshDistribute::fvMeshDistribute(fvMesh& mesh)
:
mesh_(mesh)
//mergeTol_(mergeTol)
{}

View File

@ -49,8 +49,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef fvMeshDistribute_H
#define fvMeshDistribute_H
#ifndef Foam_fvMeshDistribute_H
#define Foam_fvMeshDistribute_H
#include "Field.H"
#include "fvMeshSubset.H"

View File

@ -1,815 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "fvMeshTools.H"
#include "processorCyclicPolyPatch.H"
#include "polyBoundaryMeshEntries.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Adds patch if not yet there. Returns patchID.
Foam::label Foam::fvMeshTools::addPatch
(
fvMesh& mesh,
const polyPatch& patch,
const dictionary& patchFieldDict,
const word& defaultPatchFieldType,
const bool validBoundary
)
{
polyBoundaryMesh& polyPatches =
const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
label patchi = polyPatches.findPatchID(patch.name());
if (patchi != -1)
{
// Already there
return patchi;
}
// Append at end unless there are processor patches
label insertPatchi = polyPatches.size();
label startFacei = mesh.nFaces();
if (!isA<processorPolyPatch>(patch))
{
forAll(polyPatches, patchi)
{
const polyPatch& pp = polyPatches[patchi];
if (isA<processorPolyPatch>(pp))
{
insertPatchi = patchi;
startFacei = pp.start();
break;
}
}
}
// Below is all quite a hack. Feel free to change once there is a better
// mechanism to insert and reorder patches.
// Clear local fields and e.g. polyMesh parallelInfo.
mesh.clearOut();
label sz = polyPatches.size();
fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
// Add polyPatch at the end
polyPatches.setSize(sz+1);
polyPatches.set
(
sz,
patch.clone
(
polyPatches,
insertPatchi, //index
0, //size
startFacei //start
)
);
fvPatches.setSize(sz+1);
fvPatches.set
(
sz,
fvPatch::New
(
polyPatches[sz], // point to newly added polyPatch
mesh.boundary()
)
);
addPatchFields<volScalarField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
addPatchFields<volVectorField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
addPatchFields<volSphericalTensorField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
addPatchFields<volSymmTensorField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
addPatchFields<volTensorField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
// Surface fields
addPatchFields<surfaceScalarField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
addPatchFields<surfaceVectorField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
addPatchFields<surfaceSphericalTensorField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
addPatchFields<surfaceSymmTensorField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
addPatchFields<surfaceTensorField>
(
mesh,
patchFieldDict,
defaultPatchFieldType,
Zero
);
// Create reordering list
// patches before insert position stay as is
labelList oldToNew(sz+1);
for (label i = 0; i < insertPatchi; i++)
{
oldToNew[i] = i;
}
// patches after insert position move one up
for (label i = insertPatchi; i < sz; i++)
{
oldToNew[i] = i+1;
}
// appended patch gets moved to insert position
oldToNew[sz] = insertPatchi;
// Shuffle into place
polyPatches.reorder(oldToNew, validBoundary);
fvPatches.reorder(oldToNew);
reorderPatchFields<volScalarField>(mesh, oldToNew);
reorderPatchFields<volVectorField>(mesh, oldToNew);
reorderPatchFields<volSphericalTensorField>(mesh, oldToNew);
reorderPatchFields<volSymmTensorField>(mesh, oldToNew);
reorderPatchFields<volTensorField>(mesh, oldToNew);
reorderPatchFields<surfaceScalarField>(mesh, oldToNew);
reorderPatchFields<surfaceVectorField>(mesh, oldToNew);
reorderPatchFields<surfaceSphericalTensorField>(mesh, oldToNew);
reorderPatchFields<surfaceSymmTensorField>(mesh, oldToNew);
reorderPatchFields<surfaceTensorField>(mesh, oldToNew);
return insertPatchi;
}
void Foam::fvMeshTools::setPatchFields
(
fvMesh& mesh,
const label patchi,
const dictionary& patchFieldDict
)
{
setPatchFields<volScalarField>(mesh, patchi, patchFieldDict);
setPatchFields<volVectorField>(mesh, patchi, patchFieldDict);
setPatchFields<volSphericalTensorField>(mesh, patchi, patchFieldDict);
setPatchFields<volSymmTensorField>(mesh, patchi, patchFieldDict);
setPatchFields<volTensorField>(mesh, patchi, patchFieldDict);
setPatchFields<surfaceScalarField>(mesh, patchi, patchFieldDict);
setPatchFields<surfaceVectorField>(mesh, patchi, patchFieldDict);
setPatchFields<surfaceSphericalTensorField>
(
mesh,
patchi,
patchFieldDict
);
setPatchFields<surfaceSymmTensorField>(mesh, patchi, patchFieldDict);
setPatchFields<surfaceTensorField>(mesh, patchi, patchFieldDict);
}
void Foam::fvMeshTools::zeroPatchFields(fvMesh& mesh, const label patchi)
{
setPatchFields<volScalarField>(mesh, patchi, Zero);
setPatchFields<volVectorField>(mesh, patchi, Zero);
setPatchFields<volSphericalTensorField>
(
mesh,
patchi,
Zero
);
setPatchFields<volSymmTensorField>
(
mesh,
patchi,
Zero
);
setPatchFields<volTensorField>(mesh, patchi, Zero);
setPatchFields<surfaceScalarField>(mesh, patchi, Zero);
setPatchFields<surfaceVectorField>(mesh, patchi, Zero);
setPatchFields<surfaceSphericalTensorField>
(
mesh,
patchi,
Zero
);
setPatchFields<surfaceSymmTensorField>
(
mesh,
patchi,
Zero
);
setPatchFields<surfaceTensorField>(mesh, patchi, Zero);
}
// Deletes last patch
void Foam::fvMeshTools::trimPatches(fvMesh& mesh, const label nPatches)
{
// Clear local fields and e.g. polyMesh globalMeshData.
mesh.clearOut();
polyBoundaryMesh& polyPatches =
const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
if (polyPatches.empty())
{
FatalErrorInFunction
<< "No patches in mesh"
<< abort(FatalError);
}
label nFaces = 0;
for (label patchi = nPatches; patchi < polyPatches.size(); patchi++)
{
nFaces += polyPatches[patchi].size();
}
reduce(nFaces, sumOp<label>());
if (nFaces)
{
FatalErrorInFunction
<< "There are still " << nFaces
<< " faces in " << polyPatches.size()-nPatches
<< " patches to be deleted" << abort(FatalError);
}
// Remove actual patches
polyPatches.setSize(nPatches);
fvPatches.setSize(nPatches);
trimPatchFields<volScalarField>(mesh, nPatches);
trimPatchFields<volVectorField>(mesh, nPatches);
trimPatchFields<volSphericalTensorField>(mesh, nPatches);
trimPatchFields<volSymmTensorField>(mesh, nPatches);
trimPatchFields<volTensorField>(mesh, nPatches);
trimPatchFields<surfaceScalarField>(mesh, nPatches);
trimPatchFields<surfaceVectorField>(mesh, nPatches);
trimPatchFields<surfaceSphericalTensorField>(mesh, nPatches);
trimPatchFields<surfaceSymmTensorField>(mesh, nPatches);
trimPatchFields<surfaceTensorField>(mesh, nPatches);
}
void Foam::fvMeshTools::reorderPatches
(
fvMesh& mesh,
const labelList& oldToNew,
const label nNewPatches,
const bool validBoundary
)
{
polyBoundaryMesh& polyPatches =
const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
// Shuffle into place
polyPatches.reorder(oldToNew, validBoundary);
fvPatches.reorder(oldToNew);
reorderPatchFields<volScalarField>(mesh, oldToNew);
reorderPatchFields<volVectorField>(mesh, oldToNew);
reorderPatchFields<volSphericalTensorField>(mesh, oldToNew);
reorderPatchFields<volSymmTensorField>(mesh, oldToNew);
reorderPatchFields<volTensorField>(mesh, oldToNew);
reorderPatchFields<surfaceScalarField>(mesh, oldToNew);
reorderPatchFields<surfaceVectorField>(mesh, oldToNew);
reorderPatchFields<surfaceSphericalTensorField>(mesh, oldToNew);
reorderPatchFields<surfaceSymmTensorField>(mesh, oldToNew);
reorderPatchFields<surfaceTensorField>(mesh, oldToNew);
// Remove last.
trimPatches(mesh, nNewPatches);
}
Foam::labelList Foam::fvMeshTools::removeEmptyPatches
(
fvMesh& mesh,
const bool validBoundary
)
{
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
labelList newToOld(pbm.size());
labelList oldToNew(pbm.size(), -1);
label newI = 0;
// Assumes all non-coupled boundaries are on all processors!
forAll(pbm, patchI)
{
const polyPatch& pp = pbm[patchI];
if (!isA<processorPolyPatch>(pp))
{
label nFaces = pp.size();
if (validBoundary)
{
reduce(nFaces, sumOp<label>());
}
if (nFaces > 0)
{
newToOld[newI] = patchI;
oldToNew[patchI] = newI++;
}
}
}
// Same for processor patches (but need no reduction)
forAll(pbm, patchI)
{
const polyPatch& pp = pbm[patchI];
if (isA<processorPolyPatch>(pp) && pp.size())
{
newToOld[newI] = patchI;
oldToNew[patchI] = newI++;
}
}
newToOld.setSize(newI);
// Move all deletable patches to the end
forAll(oldToNew, patchI)
{
if (oldToNew[patchI] == -1)
{
oldToNew[patchI] = newI++;
}
}
reorderPatches(mesh, oldToNew, newToOld.size(), validBoundary);
return newToOld;
}
Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
(
const IOobject& io,
const bool masterOnlyReading
)
{
// Region name
// ~~~~~~~~~~~
fileName meshSubDir;
if (io.name() == polyMesh::defaultRegion)
{
meshSubDir = polyMesh::meshSubDir;
}
else
{
meshSubDir = io.name()/polyMesh::meshSubDir;
}
fileName facesInstance;
fileName pointsInstance;
// Patch types
// ~~~~~~~~~~~
// Read and scatter master patches (without reading master mesh!)
PtrList<entry> patchEntries;
if (Pstream::master())
{
const bool oldParRun = Pstream::parRun(false);
facesInstance = io.time().findInstance
(
meshSubDir,
"faces",
IOobject::MUST_READ
);
pointsInstance = io.time().findInstance
(
meshSubDir,
"points",
IOobject::MUST_READ
);
patchEntries = polyBoundaryMeshEntries
(
IOobject
(
"boundary",
facesInstance,
meshSubDir,
io.db(),
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
)
);
Pstream::parRun(oldParRun);
}
// Broadcast information to all
Pstream::broadcasts
(
UPstream::worldComm,
patchEntries,
facesInstance,
pointsInstance
);
// Dummy meshes
// ~~~~~~~~~~~~
// Check who has a mesh
const fileName meshDir = io.time().path()/facesInstance/meshSubDir;
bool haveMesh = isDir(meshDir);
if (masterOnlyReading && !Pstream::master())
{
haveMesh = false;
}
// Set up to read-if-present. Note: does not search for mesh so set
// instance explicitly
IOobject meshIO(io);
meshIO.instance() = facesInstance;
if (masterOnlyReading && !Pstream::master())
{
meshIO.readOpt(IOobject::NO_READ);
}
else
{
meshIO.readOpt(IOobject::READ_IF_PRESENT);
}
// Read mesh
// ~~~~~~~~~
// Now all processors use supplied points,faces etc
// Note: fvSolution, fvSchemes are also using the supplied IOobject so
// on slave will be NO_READ, on master READ_IF_PRESENT. This will
// conflict with e.g. timeStampMaster reading so switch off.
// Note: v2006 used the READ_IF_PRESENT flag in the meshIO.readOpt(). v2012
// (correctly) does no longer so below code explicitly addFvPatches
// using the separately read boundary file.
const IOobject::fileCheckTypes oldCheckType =
IOobject::fileModificationChecking;
IOobject::fileModificationChecking = IOobject::timeStamp;
//- Points
pointIOField points
(
IOobject
(
"points",
pointsInstance, //meshIO.instance(),
meshSubDir,
meshIO.db(),
(haveMesh ? IOobject::MUST_READ : IOobject::NO_READ),
IOobject::NO_WRITE,
false
)
);
//- Faces
faceCompactIOList faces
(
IOobject
(
"faces",
meshIO.instance(),
meshSubDir,
meshIO.db(),
(haveMesh ? IOobject::MUST_READ : IOobject::NO_READ),
IOobject::NO_WRITE,
false
)
);
//- Face owner
labelIOList owner
(
IOobject
(
"owner",
meshIO.instance(),
meshSubDir,
meshIO.db(),
(haveMesh ? IOobject::MUST_READ : IOobject::NO_READ),
IOobject::NO_WRITE,
false
)
);
//- Face neighbour
labelIOList neighbour
(
IOobject
(
"neighbour",
meshIO.instance(),
meshSubDir,
meshIO.db(),
(haveMesh ? IOobject::MUST_READ : IOobject::NO_READ),
IOobject::NO_WRITE,
false
)
);
auto meshPtr = autoPtr<fvMesh>::New
(
meshIO,
std::move(points),
std::move(faces),
std::move(owner),
std::move(neighbour)
);
fvMesh& mesh = *meshPtr;
IOobject::fileModificationChecking = oldCheckType;
// Add patches
// ~~~~~~~~~~~
bool havePatches = mesh.boundary().size();
reduce(havePatches, andOp<bool>());
if (!havePatches)
{
// There are one or more processors without full complement of
// patches
DynamicList<polyPatch*> newPatches;
if (mesh.boundary().size() == patchEntries.size())
{
// Assumably we have correctly read the boundary and can clone.
// Note: for
// v2012 onwards this is probably never the case and this whole
// section can be removed.
forAll(mesh.boundary(), patchI)
{
newPatches.append
(
mesh.boundaryMesh()[patchI].clone(mesh.boundaryMesh()).ptr()
);
}
}
else
{
// Use patchEntries (read on master & scattered to slaves). This
// is probably always happening since boundary file is not read with
// READ_IF_PRESENT on recent versions.
forAll(patchEntries, patchI)
{
const entry& e = patchEntries[patchI];
const word type(e.dict().get<word>("type"));
if
(
type == processorPolyPatch::typeName
|| type == processorCyclicPolyPatch::typeName
)
{}
else
{
dictionary patchDict(e.dict());
if (mesh.nInternalFaces() == 0)
{
patchDict.set("nFaces", 0);
patchDict.set("startFace", 0);
}
newPatches.append
(
polyPatch::New
(
patchEntries[patchI].keyword(),
patchDict,
newPatches.size(),
mesh.boundaryMesh()
).ptr()
);
}
}
}
mesh.removeFvBoundary();
mesh.addFvPatches(newPatches);
}
//Pout<< "patches:" << endl;
//forAll(mesh.boundary(), patchI)
//{
// Pout<< " type" << mesh.boundary()[patchI].type()
// << " size:" << mesh.boundary()[patchI].size()
// << " start:" << mesh.boundary()[patchI].start() << endl;
//}
//Pout<< endl;
// Determine zones
// ~~~~~~~~~~~~~~~
wordList pointZoneNames(mesh.pointZones().names());
wordList faceZoneNames(mesh.faceZones().names());
wordList cellZoneNames(mesh.cellZones().names());
Pstream::broadcasts
(
UPstream::worldComm,
pointZoneNames,
faceZoneNames,
cellZoneNames
);
if (!haveMesh)
{
// Add the zones. Make sure to remove the old dummy ones first
mesh.pointZones().clear();
mesh.faceZones().clear();
mesh.cellZones().clear();
List<pointZone*> pz(pointZoneNames.size());
forAll(pointZoneNames, i)
{
pz[i] = new pointZone
(
pointZoneNames[i],
i,
mesh.pointZones()
);
}
List<faceZone*> fz(faceZoneNames.size());
forAll(faceZoneNames, i)
{
fz[i] = new faceZone
(
faceZoneNames[i],
i,
mesh.faceZones()
);
}
List<cellZone*> cz(cellZoneNames.size());
forAll(cellZoneNames, i)
{
cz[i] = new cellZone
(
cellZoneNames[i],
i,
mesh.cellZones()
);
}
if (pz.size() || fz.size() || cz.size())
{
mesh.addZones(pz, fz, cz);
}
}
return meshPtr;
}
void Foam::fvMeshTools::createDummyFvMeshFiles
(
const objectRegistry& mesh,
const word& regionName,
const bool verbose
)
{
// Create dummy system/fv*
{
IOobject io
(
"fvSchemes",
mesh.time().system(),
regionName,
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE,
false
);
if (!io.typeHeaderOk<IOdictionary>(false))
{
if (verbose)
{
Info<< "Writing dummy " << regionName/io.name() << endl;
}
dictionary dummyDict;
dictionary divDict;
dummyDict.add("divSchemes", divDict);
dictionary gradDict;
dummyDict.add("gradSchemes", gradDict);
dictionary laplDict;
dummyDict.add("laplacianSchemes", laplDict);
IOdictionary(io, dummyDict).regIOobject::write();
}
}
{
IOobject io
(
"fvSolution",
mesh.time().system(),
regionName,
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE,
false
);
if (!io.typeHeaderOk<IOdictionary>(false))
{
if (verbose)
{
Info<< "Writing dummy " << regionName/io.name() << endl;
}
dictionary dummyDict;
IOdictionary(io, dummyDict).regIOobject::write();
}
}
}
// ************************************************************************* //

View File

@ -14,6 +14,8 @@ $(surfaceInterpolation)/surfaceInterpolation/surfaceInterpolation.C
fvMesh/fvMeshSubset/fvMeshSubset.C
fvMesh/fvMeshSubset/fvMeshSubsetProxy.C
fvMesh/fvMeshTools/fvMeshTools.C
fvMesh/fvMeshTools/fvMeshToolsProcAddr.C
fvMesh/singleCellFvMesh/singleCellFvMesh.C

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2015-2019 OpenCFD Ltd.
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -32,11 +32,13 @@ Description
SourceFiles
fvMeshTools.C
fvMeshToolsProcAddr.C
fvMeshToolsTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef fvMeshTools_H
#define fvMeshTools_H
#ifndef Foam_fvMeshTools_H
#define Foam_fvMeshTools_H
#include "fvMesh.H"
@ -45,12 +47,18 @@ SourceFiles
namespace Foam
{
// Forward Declarations
class mapDistributePolyMesh;
class writeHandler;
/*---------------------------------------------------------------------------*\
Class fvMeshTools Declaration
\*---------------------------------------------------------------------------*/
class fvMeshTools
{
// Private Member Functions
template<class GeoField>
static void addPatchFields
(
@ -91,6 +99,8 @@ class fvMeshTools
public:
// Member Functions
//- Add patch. Inserts patch before all processor patches.
// Supply per field the new patchField per field as a
// subdictionary or a default type. If validBoundary call is parallel
@ -115,8 +125,8 @@ public:
//- Change patchField to zero on registered fields
static void zeroPatchFields(fvMesh& mesh, const label patchi);
//- Reorder and remove trailing patches. If validBoundary call is parallel
// synced
//- Reorder and remove trailing patches.
// Is parallel synced when validBoundary is true
static void reorderPatches
(
fvMesh&,
@ -124,30 +134,67 @@ public:
const label nPatches,
const bool validBoundary
);
//- Remove zero sized patches. All but processor patches are
// assumed to be present on all processors (so size will be reduced
// if validBoundary). Return map from new
// to old patches
static labelList removeEmptyPatches(fvMesh&, const bool validBoundary);
//- Read mesh or create dummy mesh (0 cells, >0 patches). Works in two
// modes according to masterOnlyReading:
// true : all slaves create dummy mesh
//- Set the fvGeometryScheme to basic (to avoid parallel communication)
static void setBasicGeometry(fvMesh& mesh);
//- Read mesh or create dummy mesh (0 cells, >0 patches).
//
// Works in two modes according to masterOnlyReading:
// true : create dummy mesh on all procs
// false: checks locally for mesh directories and only creates dummy mesh
// if not present
static autoPtr<fvMesh> newMesh
(
const IOobject& io,
const bool masterOnlyReading
const bool masterOnlyReading,
const bool verbose = false
);
//- Create additional fv* files
//- Read mesh if available, or create empty mesh with non-proc as per
//- proc0 mesh.
// Requires:
// - all processors to have all patches (and in same order).
// - io.instance() set to facesInstance
static autoPtr<fvMesh> loadOrCreateMesh
(
const IOobject& io,
const bool decompose,
const bool verbose = false
);
//- Create additional fvSchemes/fvSolution files
static void createDummyFvMeshFiles
(
const objectRegistry& parent,
const word& regionName,
const bool verbose = false
);
//- Read procAddressing components (reconstructing)
static autoPtr<mapDistributePolyMesh> readProcAddressing
(
const fvMesh& procMesh,
const autoPtr<fvMesh>& baseMeshPtr
);
//- Write addressing if decomposing (1 to many) or reconstructing
//- (many to 1)
static void writeProcAddressing
(
const fvMesh& procMesh,
const mapDistributePolyMesh& map,
const bool decompose,
autoPtr<fileOperation>&& writeHandler
);
};

View File

@ -0,0 +1,452 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "fvMeshTools.H"
#include "fileOperation.H"
#include "IndirectList.H"
#include "labelRange.H"
#include "IOmapDistributePolyMesh.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Create a reconstruct map.
// The baseMeshPtr is non-null (and probably has cells) on the master
// is ignored elsewhere.
//
// The incomming faceProcAddressing is assumed to have flip addressing.
static autoPtr<mapDistributePolyMesh> createReconstructMap
(
const fvMesh& mesh,
const autoPtr<fvMesh>& baseMeshPtr,
const labelList& cellProcAddressing,
const labelList& faceProcAddressing,
const labelList& pointProcAddressing,
const labelList& boundaryProcAddressing
)
{
const label nOldPoints = mesh.nPoints();
const label nOldFaces = mesh.nFaces();
const label nOldCells = mesh.nCells();
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
labelList oldPatchStarts(pbm.size());
labelList oldPatchNumPoints(pbm.size());
forAll(pbm, patchi)
{
oldPatchStarts[patchi] = pbm[patchi].start();
oldPatchNumPoints[patchi] = pbm[patchi].nPoints();
}
// Patches: purge -1 entries
labelList patchProcAddressing
(
IndirectList<label>::subset_if
(
boundaryProcAddressing,
labelRange::ge0()
)
);
labelListList cellSubMap(Pstream::nProcs());
cellSubMap[Pstream::masterNo()] = identity(nOldCells);
labelListList faceSubMap(Pstream::nProcs());
faceSubMap[Pstream::masterNo()] = identity(nOldFaces);
labelListList pointSubMap(Pstream::nProcs());
pointSubMap[Pstream::masterNo()] = identity(nOldPoints);
labelListList patchSubMap(Pstream::nProcs());
patchSubMap[Pstream::masterNo()] = patchProcAddressing;
// Gather addressing on master
labelListList cellAddressing(Pstream::nProcs());
cellAddressing[Pstream::myProcNo()] = cellProcAddressing;
Pstream::gatherList(cellAddressing);
labelListList faceAddressing(Pstream::nProcs());
faceAddressing[Pstream::myProcNo()] = faceProcAddressing;
Pstream::gatherList(faceAddressing);
labelListList pointAddressing(Pstream::nProcs());
pointAddressing[Pstream::myProcNo()] = pointProcAddressing;
Pstream::gatherList(pointAddressing);
labelListList patchAddressing(Pstream::nProcs());
patchAddressing[Pstream::myProcNo()] = patchProcAddressing;
Pstream::gatherList(patchAddressing);
// NB: can only have a reconstruct on master!
if (Pstream::master() && baseMeshPtr && baseMeshPtr->nCells())
{
const fvMesh& baseMesh = *baseMeshPtr;
const label nNewPoints = baseMesh.nPoints();
const label nNewFaces = baseMesh.nFaces();
const label nNewCells = baseMesh.nCells();
const label nNewPatches = baseMesh.boundaryMesh().size();
mapDistribute cellMap
(
nNewCells,
std::move(cellSubMap),
std::move(cellAddressing)
);
mapDistribute faceMap
(
nNewFaces,
std::move(faceSubMap),
std::move(faceAddressing),
false, // subHasFlip
true // constructHasFlip
);
mapDistribute pointMap
(
nNewPoints,
std::move(pointSubMap),
std::move(pointAddressing)
);
mapDistribute patchMap
(
nNewPatches,
std::move(patchSubMap),
std::move(patchAddressing)
);
return autoPtr<mapDistributePolyMesh>::New
(
nOldPoints,
nOldFaces,
nOldCells,
std::move(oldPatchStarts),
std::move(oldPatchNumPoints),
std::move(pointMap),
std::move(faceMap),
std::move(cellMap),
std::move(patchMap)
);
}
else
{
// Zero-sized mesh (eg, processor mesh)
mapDistribute cellMap
(
0, // nNewCells
std::move(cellSubMap),
labelListList(Pstream::nProcs()) // constructMap
);
mapDistribute faceMap
(
0, // nNewFaces
std::move(faceSubMap),
labelListList(Pstream::nProcs()), // constructMap
false, // subHasFlip
true // constructHasFlip
);
mapDistribute pointMap
(
0, // nNewPoints
std::move(pointSubMap),
labelListList(Pstream::nProcs()) // constructMap
);
mapDistribute patchMap
(
0, // nNewPatches
std::move(patchSubMap),
labelListList(Pstream::nProcs()) // constructMap
);
return autoPtr<mapDistributePolyMesh>::New
(
nOldPoints,
nOldFaces,
nOldCells,
std::move(oldPatchStarts),
std::move(oldPatchNumPoints),
std::move(pointMap),
std::move(faceMap),
std::move(cellMap),
std::move(patchMap)
);
}
}
} // End namespace Foam
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::autoPtr<Foam::mapDistributePolyMesh>
Foam::fvMeshTools::readProcAddressing
(
const fvMesh& mesh,
const autoPtr<fvMesh>& baseMeshPtr
)
{
// Processor-local reading
IOobject ioAddr
(
"procAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh.thisDb(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
false // no register
);
//if (ioAddr.typeHeaderOk<labelIOList>(true))
//{
// Pout<< "Reading addressing from " << io.name() << " at "
// << mesh.facesInstance() << nl << endl;
// mapDistributePolyMesh distMap = IOmapDistributePolyMesh(ioAddr);
// return autoPtr<mapDistributePolyMesh>::New(std::move(distMap));
//}
//else
{
Info<< "Reading (cell|face|point|boundary)ProcAddressing from "
<< mesh.facesInstance().c_str() << '/'
<< polyMesh::meshSubDir << nl << endl;
ioAddr.rename("cellProcAddressing");
labelIOList cellProcAddressing(ioAddr, Zero);
ioAddr.rename("faceProcAddressing");
labelIOList faceProcAddressing(ioAddr, Zero);
ioAddr.rename("pointProcAddressing");
labelIOList pointProcAddressing(ioAddr, Zero);
ioAddr.rename("boundaryProcAddressing");
labelIOList boundaryProcAddressing(ioAddr, Zero);
if
(
mesh.nCells() != cellProcAddressing.size()
|| mesh.nPoints() != pointProcAddressing.size()
|| mesh.nFaces() != faceProcAddressing.size()
|| mesh.boundaryMesh().size() != boundaryProcAddressing.size()
)
{
FatalErrorInFunction
<< "Read addressing inconsistent with mesh sizes" << nl
<< "cells:" << mesh.nCells()
<< " addressing:" << cellProcAddressing.objectRelPath()
<< " size:" << cellProcAddressing.size() << nl
<< "faces:" << mesh.nFaces()
<< " addressing:" << faceProcAddressing.objectRelPath()
<< " size:" << faceProcAddressing.size() << nl
<< "points:" << mesh.nPoints()
<< " addressing:" << pointProcAddressing.objectRelPath()
<< " size:" << pointProcAddressing.size()
<< "patches:" << mesh.boundaryMesh().size()
<< " addressing:" << boundaryProcAddressing.objectRelPath()
<< " size:" << boundaryProcAddressing.size()
<< exit(FatalError);
}
return createReconstructMap
(
mesh,
baseMeshPtr,
cellProcAddressing,
faceProcAddressing,
pointProcAddressing,
boundaryProcAddressing
);
}
}
void Foam::fvMeshTools::writeProcAddressing
(
const fvMesh& mesh,
const mapDistributePolyMesh& map,
const bool decompose,
autoPtr<fileOperation>&& writeHandler
)
{
Info<< "Writing ("
<< (decompose ? "decompose" : "reconstruct")
<< ") procAddressing files to "
<< mesh.facesInstance().c_str() << '/'
<< polyMesh::meshSubDir << endl;
// Processor-local outputs for components
// NB: the full "procAddressing" output is presumed to already have
// been done independently (as a registered object)
IOobject ioAddr
(
"procAddressing",
mesh.facesInstance(),
polyMesh::meshSubDir,
mesh.thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false // no register
);
// cellProcAddressing (polyMesh)
ioAddr.rename("cellProcAddressing");
labelIOList cellMap(ioAddr, Zero);
// faceProcAddressing (polyMesh)
ioAddr.rename("faceProcAddressing");
labelIOList faceMap(ioAddr, Zero);
// pointProcAddressing (polyMesh)
ioAddr.rename("pointProcAddressing");
labelIOList pointMap(ioAddr, Zero);
// boundaryProcAddressing (polyMesh)
ioAddr.rename("boundaryProcAddressing");
labelIOList patchMap(ioAddr, Zero);
if (decompose)
{
// Decompose
// - forward map: [undecomposed] -> [decomposed]
cellMap = identity(map.nOldCells());
map.distributeCellData(cellMap);
faceMap = identity(map.nOldFaces());
{
const mapDistribute& faceDistMap = map.faceMap();
if (faceDistMap.subHasFlip() || faceDistMap.constructHasFlip())
{
// Offset by 1
faceMap = faceMap + 1;
}
faceDistMap.mapDistributeBase::distribute
(
Pstream::commsTypes::nonBlocking,
faceMap,
flipLabelOp() // Apply face flips
);
}
pointMap = identity(map.nOldPoints());
map.distributePointData(pointMap);
patchMap = identity(map.oldPatchSizes().size());
map.patchMap().mapDistributeBase::distribute
(
Pstream::commsTypes::nonBlocking,
label(-1), // nullValue for new patches...
patchMap,
flipOp() // negate op
);
}
else
{
// Reconstruct
// - reverse map: [undecomposed] <- [decomposed]
cellMap = identity(mesh.nCells());
map.cellMap().reverseDistribute(map.nOldCells(), cellMap);
faceMap = identity(mesh.nFaces());
{
const mapDistribute& faceDistMap = map.faceMap();
if (faceDistMap.subHasFlip() || faceDistMap.constructHasFlip())
{
// Offset by 1
faceMap = faceMap + 1;
}
faceDistMap.mapDistributeBase::reverseDistribute
(
Pstream::commsTypes::nonBlocking,
map.nOldFaces(),
faceMap,
flipLabelOp() // Apply face flips
);
}
pointMap = identity(mesh.nPoints());
map.pointMap().reverseDistribute(map.nOldPoints(), pointMap);
patchMap = identity(mesh.boundaryMesh().size());
map.patchMap().mapDistributeBase::reverseDistribute
(
Pstream::commsTypes::nonBlocking,
map.oldPatchSizes().size(),
label(-1), // nullValue for unmapped patches...
patchMap
);
}
autoPtr<fileOperation> defaultHandler;
if (writeHandler)
{
defaultHandler = fileHandler(std::move(writeHandler));
}
const bool cellOk = cellMap.write();
const bool faceOk = faceMap.write();
const bool pointOk = pointMap.write();
const bool patchOk = patchMap.write();
if (defaultHandler)
{
writeHandler = fileHandler(std::move(defaultHandler));
}
if (!cellOk || !faceOk || !pointOk || !patchOk)
{
WarningInFunction
<< "Failed to write some of "
<< cellMap.objectRelPath() << ", "
<< faceMap.objectRelPath() << ", "
<< pointMap.objectRelPath() << ", "
<< patchMap.objectRelPath() << endl;
}
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -48,23 +48,24 @@ void Foam::fvMeshTools::addPatchFields
forAllIters(flds, iter)
{
GeoField& fld = *iter();
GeoField& fld = *iter.val();
auto& bfld = fld.boundaryFieldRef();
label sz = bfld.size();
bfld.setSize(sz+1);
const label newPatchi = bfld.size();
bfld.resize(newPatchi+1);
if (patchFieldDict.found(fld.name()))
const dictionary* dict = patchFieldDict.findDict(fld.name());
if (dict)
{
bfld.set
(
sz,
newPatchi,
GeoField::Patch::New
(
mesh.boundary()[sz],
fld(),
patchFieldDict.subDict(fld.name())
mesh.boundary()[newPatchi],
fld.internalField(),
*dict
)
);
}
@ -72,15 +73,15 @@ void Foam::fvMeshTools::addPatchFields
{
bfld.set
(
sz,
newPatchi,
GeoField::Patch::New
(
defaultPatchFieldType,
mesh.boundary()[sz],
fld()
mesh.boundary()[newPatchi],
fld.internalField()
)
);
bfld[sz] == defaultPatchValue;
bfld[newPatchi] == defaultPatchValue;
}
}
}
@ -101,11 +102,12 @@ void Foam::fvMeshTools::setPatchFields
forAllIters(flds, iter)
{
GeoField& fld = *iter();
GeoField& fld = *iter.val();
auto& bfld = fld.boundaryFieldRef();
if (patchFieldDict.found(fld.name()))
const dictionary* dict = patchFieldDict.findDict(fld.name());
if (dict)
{
bfld.set
(
@ -113,8 +115,8 @@ void Foam::fvMeshTools::setPatchFields
GeoField::Patch::New
(
mesh.boundary()[patchi],
fld(),
patchFieldDict.subDict(fld.name())
fld.internalField(),
*dict
)
);
}
@ -122,8 +124,6 @@ void Foam::fvMeshTools::setPatchFields
}
template<class GeoField>
void Foam::fvMeshTools::setPatchFields
(
@ -139,8 +139,7 @@ void Foam::fvMeshTools::setPatchFields
forAllIters(flds, iter)
{
GeoField& fld = *iter();
GeoField& fld = *iter.val();
auto& bfld = fld.boundaryFieldRef();
bfld[patchi] == value;
@ -159,8 +158,8 @@ void Foam::fvMeshTools::trimPatchFields(fvMesh& mesh, const label nPatches)
forAllIters(flds, iter)
{
GeoField& fld = *iter();
fld.boundaryFieldRef().setSize(nPatches);
GeoField& fld = *iter.val();
fld.boundaryFieldRef().resize(nPatches);
}
}
@ -180,8 +179,7 @@ void Foam::fvMeshTools::reorderPatchFields
forAllIters(flds, iter)
{
GeoField& fld = *iter();
GeoField& fld = *iter.val();
auto& bfld = fld.boundaryFieldRef();
bfld.reorder(oldToNew);