Files
OpenFOAM-12/applications/utilities/parallelProcessing/redistributePar/loadOrCreateMesh.C
Henry Weller 6d05a6c425 cellZone, faceZone, pointZone: Removed internal index
Zones are now completely dynamic, i.e. the number of zones of each type can
change during the run, e.g. by run-time mesh-to-mesh mapping onto meshes with
different zones used to control mesh motion.  This means that the index of each
zone may change during the run and so it better that the zones do not cache
their own index but it is looked-up from the zone list using findIndex when
required.
2024-01-31 14:58:43 +00:00

357 lines
10 KiB
C++

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2012-2024 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/>.
\*---------------------------------------------------------------------------*/
#include "loadOrCreateMesh.H"
#include "processorPolyPatch.H"
#include "processorCyclicPolyPatch.H"
#include "IOPtrList.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
namespace Foam
{
defineTemplateTypeNameAndDebug(IOPtrList<entry>, 0);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// 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).
Foam::autoPtr<Foam::fvMesh> Foam::loadOrCreateMesh
(
const IOobject& io
)
{
fileName meshSubDir;
if (io.name() == polyMesh::defaultRegion)
{
meshSubDir = polyMesh::meshSubDir;
}
else
{
meshSubDir = io.name()/polyMesh::meshSubDir;
}
// Scatter master patches
PtrList<entry> patchEntries;
if (Pstream::master())
{
// Read PtrList of dictionary as dictionary.
const word oldTypeName = IOPtrList<entry>::typeName;
const_cast<word&>(IOPtrList<entry>::typeName) = word::null;
IOPtrList<entry> dictList
(
IOobject
(
"boundary",
io.time().findInstance
(
meshSubDir,
"boundary",
IOobject::MUST_READ
),
meshSubDir,
io.db(),
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
)
);
const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
// Fake type back to what was in field
const_cast<word&>(dictList.type()) = dictList.headerClassName();
patchEntries.transfer(dictList);
// Send patches
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
slave++
)
{
OPstream toSlave(Pstream::commsTypes::scheduled, slave);
toSlave << patchEntries;
}
}
else
{
// Receive patches
IPstream fromMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
fromMaster >> patchEntries;
}
// Check who has a mesh
const bool haveMesh = fileHandler().isDir
(
fileHandler().filePath(io.time().path()/io.instance()/meshSubDir)
);
if (!haveMesh)
{
bool oldParRun = Pstream::parRun();
Pstream::parRun() = false;
// Create dummy mesh. Only used on procs that don't have mesh.
IOobject noReadIO(io);
noReadIO.readOpt() = IOobject::NO_READ;
fvMesh dummyMesh
(
noReadIO,
pointField(),
faceList(),
labelList(),
labelList(),
false
);
// Add patches
List<polyPatch*> patches(patchEntries.size());
label nPatches = 0;
forAll(patchEntries, patchi)
{
const entry& e = patchEntries[patchi];
const word type(e.dict().lookup("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
(
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",
labelList(0),
dummyMesh.pointZones()
)
);
List<faceZone*> fz
(
1,
new faceZone
(
"dummyFaceZone",
labelList(0),
boolList(0),
dummyMesh.faceZones()
)
);
List<cellZone*> cz
(
1,
new cellZone
(
"dummyCellZone",
labelList(0),
dummyMesh.cellZones()
)
);
dummyMesh.addZones(pz, fz, cz);
dummyMesh.write();
Pstream::parRun() = oldParRun;
}
autoPtr<fvMesh> meshPtr(new fvMesh(io, false));
fvMesh& mesh = meshPtr();
// Sync patches
// ~~~~~~~~~~~~
if (!Pstream::master() && haveMesh)
{
// Check master names against mine
const polyBoundaryMesh& patches = mesh.boundaryMesh();
forAll(patchEntries, patchi)
{
const entry& e = patchEntries[patchi];
const word type(e.dict().lookup("type"));
const word& name = e.keyword();
if (type == processorPolyPatch::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);
}
}
}
// 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],
labelList(0),
mesh.pointZones()
);
}
List<faceZone*> fz(faceZoneNames.size());
forAll(faceZoneNames, i)
{
fz[i] = new faceZone
(
faceZoneNames[i],
labelList(0),
boolList(0),
mesh.faceZones()
);
}
List<cellZone*> cz(cellZoneNames.size());
forAll(cellZoneNames, i)
{
cz[i] = new cellZone
(
cellZoneNames[i],
labelList(0),
mesh.cellZones()
);
}
mesh.addZones(pz, fz, cz);
}
if (!haveMesh)
{
// We created a dummy mesh file above. Delete it.
const fileName meshFiles = io.time().path()/io.instance()/meshSubDir;
// Pout<< "Removing dummy mesh " << meshFiles << endl;
mesh.removeFiles();
rmDir(meshFiles);
}
// Force recreation of globalMeshData.
mesh.clearOut();
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;
}
// ************************************************************************* //