diff --git a/applications/utilities/parallelProcessing/redistributePar/loadOrCreateMesh.C b/applications/utilities/parallelProcessing/redistributePar/loadOrCreateMesh.C new file mode 100644 index 0000000000000000000000000000000000000000..9e68e1f726e9883f5b0a2ae9fbb6f2cbde127d34 --- /dev/null +++ b/applications/utilities/parallelProcessing/redistributePar/loadOrCreateMesh.C @@ -0,0 +1,323 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 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 "Time.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). +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; + } + + // Check who has a mesh + const bool haveMesh = isDir(io.time().path()/io.instance()/meshSubDir); + +Pout<< "meshpath:" << io.time().path()/io.instance()/meshSubDir << endl; +Pout<< "haveMesh:" << haveMesh << endl; + + if (!haveMesh) + { + // Create dummy mesh. Only used on procs that don't have mesh. + IOobject noReadIO(io); + noReadIO.readOpt() = IOobject::NO_READ; + fvMesh dummyMesh + ( + noReadIO, + xferCopy(pointField()), + xferCopy(faceList()), + xferCopy(labelList()), + xferCopy(labelList()), + false + ); + // 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), + 0, + dummyMesh.pointZones() + ) + ); + List<faceZone*> fz + ( + 1, + new faceZone + ( + "dummyFaceZone", + labelList(0), + boolList(0), + 0, + dummyMesh.faceZones() + ) + ); + List<cellZone*> cz + ( + 1, + new cellZone + ( + "dummyCellZone", + labelList(0), + 0, + dummyMesh.cellZones() + ) + ); + dummyMesh.addZones(pz, fz, cz); + //Pout<< "Writing dummy mesh to " << dummyMesh.polyMesh::objectPath() + // << endl; + dummyMesh.write(); + } + + //Pout<< "Reading mesh from " << io.objectPath() << endl; + autoPtr<fvMesh> meshPtr(new fvMesh(io)); + fvMesh& mesh = meshPtr(); + + + // Sync patches + // ~~~~~~~~~~~~ + + if (Pstream::master()) + { + // Send patches + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + slave++ + ) + { + OPstream toSlave(Pstream::scheduled, slave); + toSlave << mesh.boundaryMesh(); + } + } + else + { + // Receive patches + IPstream fromMaster(Pstream::scheduled, Pstream::masterNo()); + PtrList<entry> patchEntries(fromMaster); + + if (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()) + { + FatalErrorIn + ( + "createMesh(const Time&, const fileName&, const bool)" + ) << "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() + ) + { + FatalErrorIn + ( + "createMesh(const Time&, const fileName&, const bool)" + ) << "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); + } + } + } + else + { + // Add patch + 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) + { + break; + } + + //Pout<< "Adding patch:" << nPatches + // << " name:" << name << " type:" << type << endl; + + dictionary patchDict(e.dict()); + patchDict.remove("nFaces"); + patchDict.add("nFaces", 0); + patchDict.remove("startFace"); + patchDict.add("startFace", 0); + + patches[patchI] = polyPatch::New + ( + name, + patchDict, + nPatches++, + mesh.boundaryMesh() + ).ptr(); + } + patches.setSize(nPatches); + mesh.addFvPatches(patches, false); // no parallel comms + + //// Write empty mesh now we have correct patches + //meshPtr().write(); + } + } + + + // 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), + i, + mesh.pointZones() + ); + } + List<faceZone*> fz(faceZoneNames.size()); + forAll(faceZoneNames, i) + { + fz[i] = new faceZone + ( + faceZoneNames[i], + labelList(0), + boolList(0), + i, + mesh.faceZones() + ); + } + List<cellZone*> cz(cellZoneNames.size()); + forAll(cellZoneNames, i) + { + cz[i] = new cellZone + ( + cellZoneNames[i], + labelList(0), + i, + mesh.cellZones() + ); + } + mesh.addZones(pz, fz, cz); + } + + + if (!haveMesh) + { + // We created a dummy mesh file above. Delete it. + //Pout<< "Removing dummy mesh " << io.objectPath() << endl; + rmDir(io.objectPath()); + } + + // 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; +} + + +// ************************************************************************* // diff --git a/applications/utilities/parallelProcessing/redistributePar/loadOrCreateMesh.H b/applications/utilities/parallelProcessing/redistributePar/loadOrCreateMesh.H new file mode 100644 index 0000000000000000000000000000000000000000..73d6dfd1c77da43399e69cdc561ca5331c4304d0 --- /dev/null +++ b/applications/utilities/parallelProcessing/redistributePar/loadOrCreateMesh.H @@ -0,0 +1,58 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 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/>. + +InNamespace + Foam + +Description + Load or create (0 size) a mesh. Used in distributing meshes to a + larger number of processors + +SourceFiles + loadOrCreateMesh.C + +\*---------------------------------------------------------------------------*/ + +#ifndef loadOrCreateMesh_H +#define loadOrCreateMesh_H + +#include "fvMesh.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 IOobject& io); + +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* //