/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 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 .
\*---------------------------------------------------------------------------*/
#include "domainDecomposition.H"
#include "dictionary.H"
#include "labelIOList.H"
#include "processorPolyPatch.H"
#include "processorCyclicPolyPatch.H"
#include "fvMesh.H"
#include "OSspecific.H"
#include "Map.H"
#include "globalMeshData.H"
#include "DynamicList.H"
#include "fvFieldDecomposer.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::domainDecomposition::mark
(
const labelList& zoneElems,
const label zoneI,
labelList& elementToZone
)
{
forAll(zoneElems, i)
{
label pointi = zoneElems[i];
if (elementToZone[pointi] == -1)
{
// First occurrence
elementToZone[pointi] = zoneI;
}
else if (elementToZone[pointi] >= 0)
{
// Multiple zones
elementToZone[pointi] = -2;
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// from components
Foam::domainDecomposition::domainDecomposition(const IOobject& io)
:
fvMesh(io),
facesInstancePointsPtr_
(
pointsInstance() != facesInstance()
? new pointIOField
(
IOobject
(
"points",
facesInstance(),
polyMesh::meshSubDir,
*this,
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
)
)
: NULL
),
decompositionDict_
(
IOobject
(
"decomposeParDict",
time().system(),
*this,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
),
nProcs_(readInt(decompositionDict_.lookup("numberOfSubdomains"))),
distributed_(false),
cellToProc_(nCells()),
procPointAddressing_(nProcs_),
procFaceAddressing_(nProcs_),
procCellAddressing_(nProcs_),
procPatchSize_(nProcs_),
procPatchStartIndex_(nProcs_),
procNeighbourProcessors_(nProcs_),
procProcessorPatchSize_(nProcs_),
procProcessorPatchStartIndex_(nProcs_),
procProcessorPatchSubPatchIDs_(nProcs_),
procProcessorPatchSubPatchStarts_(nProcs_)
{
decompositionDict_.readIfPresent("distributed", distributed_);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::domainDecomposition::~domainDecomposition()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::domainDecomposition::writeDecomposition()
{
Info<< "\nConstructing processor meshes" << endl;
// Mark point/faces/cells that are in zones.
// -1 : not in zone
// -2 : in multiple zones
// >= 0 : in single given zone
// This will give direct lookup of elements that are in a single zone
// and we'll only have to revert back to searching through all zones
// for the duplicate elements
// Point zones
labelList pointToZone(points().size(), -1);
forAll(pointZones(), zoneI)
{
mark(pointZones()[zoneI], zoneI, pointToZone);
}
// Face zones
labelList faceToZone(faces().size(), -1);
forAll(faceZones(), zoneI)
{
mark(faceZones()[zoneI], zoneI, faceToZone);
}
// Cell zones
labelList cellToZone(nCells(), -1);
forAll(cellZones(), zoneI)
{
mark(cellZones()[zoneI], zoneI, cellToZone);
}
label maxProcCells = 0;
label totProcFaces = 0;
label maxProcPatches = 0;
label totProcPatches = 0;
label maxProcFaces = 0;
// Write out the meshes
for (label procI = 0; procI < nProcs_; procI++)
{
// Create processor points
const labelList& curPointLabels = procPointAddressing_[procI];
const pointField& meshPoints = points();
labelList pointLookup(nPoints(), -1);
pointField procPoints(curPointLabels.size());
forAll(curPointLabels, pointi)
{
procPoints[pointi] = meshPoints[curPointLabels[pointi]];
pointLookup[curPointLabels[pointi]] = pointi;
}
// Create processor faces
const labelList& curFaceLabels = procFaceAddressing_[procI];
const faceList& meshFaces = faces();
labelList faceLookup(nFaces(), -1);
faceList procFaces(curFaceLabels.size());
forAll(curFaceLabels, facei)
{
// Mark the original face as used
// Remember to decrement the index by one (turning index)
//
label curF = mag(curFaceLabels[facei]) - 1;
faceLookup[curF] = facei;
// get the original face
labelList origFaceLabels;
if (curFaceLabels[facei] >= 0)
{
// face not turned
origFaceLabels = meshFaces[curF];
}
else
{
origFaceLabels = meshFaces[curF].reverseFace();
}
// translate face labels into local point list
face& procFaceLabels = procFaces[facei];
procFaceLabels.setSize(origFaceLabels.size());
forAll(origFaceLabels, pointi)
{
procFaceLabels[pointi] = pointLookup[origFaceLabels[pointi]];
}
}
// Create processor cells
const labelList& curCellLabels = procCellAddressing_[procI];
const cellList& meshCells = cells();
cellList procCells(curCellLabels.size());
forAll(curCellLabels, celli)
{
const labelList& origCellLabels = meshCells[curCellLabels[celli]];
cell& curCell = procCells[celli];
curCell.setSize(origCellLabels.size());
forAll(origCellLabels, cellFaceI)
{
curCell[cellFaceI] = faceLookup[origCellLabels[cellFaceI]];
}
}
// Create processor mesh without a boundary
fileName processorCasePath
(
time().caseName()/fileName(word("processor") + Foam::name(procI))
);
// make the processor directory
mkDir(time().rootPath()/processorCasePath);
// create a database
Time processorDb
(
Time::controlDictName,
time().rootPath(),
processorCasePath,
word("system"),
word("constant")
);
processorDb.setTime(time());
// create the mesh. Two situations:
// - points and faces come from the same time ('instance'). The mesh
// will get constructed in the same instance.
// - points come from a different time (moving mesh cases).
// It will read the points belonging to the faces instance and
// construct the procMesh with it which then gets handled as above.
// (so with 'old' geometry).
// Only at writing time will it additionally write the current
// points.
autoPtr procMeshPtr;
if (facesInstancePointsPtr_.valid())
{
// Construct mesh from facesInstance.
pointField facesInstancePoints
(
facesInstancePointsPtr_(),
curPointLabels
);
procMeshPtr.reset
(
new polyMesh
(
IOobject
(
this->polyMesh::name(), // region of undecomposed mesh
facesInstance(),
processorDb
),
xferMove(facesInstancePoints),
xferMove(procFaces),
xferMove(procCells)
)
);
}
else
{
procMeshPtr.reset
(
new polyMesh
(
IOobject
(
this->polyMesh::name(), // region of undecomposed mesh
facesInstance(),
processorDb
),
xferMove(procPoints),
xferMove(procFaces),
xferMove(procCells)
)
);
}
polyMesh& procMesh = procMeshPtr();
// Create processor boundary patches
const labelList& curPatchSizes = procPatchSize_[procI];
const labelList& curPatchStarts = procPatchStartIndex_[procI];
const labelList& curNeighbourProcessors =
procNeighbourProcessors_[procI];
const labelList& curProcessorPatchSizes =
procProcessorPatchSize_[procI];
const labelList& curProcessorPatchStarts =
procProcessorPatchStartIndex_[procI];
const labelListList& curSubPatchIDs =
procProcessorPatchSubPatchIDs_[procI];
const labelListList& curSubStarts =
procProcessorPatchSubPatchStarts_[procI];
const polyPatchList& meshPatches = boundaryMesh();
// Count the number of inter-proc patches
label nInterProcPatches = 0;
forAll(curSubPatchIDs, procPatchI)
{
//Info<< "For processor " << procI
// << " have to destination processor "
// << curNeighbourProcessors[procPatchI] << endl;
//
//forAll(curSubPatchIDs[procPatchI], i)
//{
// Info<< " from patch:" << curSubPatchIDs[procPatchI][i]
// << " starting at:" << curSubStarts[procPatchI][i]
// << endl;
//}
nInterProcPatches += curSubPatchIDs[procPatchI].size();
}
//Info<< "For processor " << procI
// << " have " << nInterProcPatches
// << " patches to neighbouring processors" << endl;
List procPatches
(
curPatchSizes.size()
+ nInterProcPatches, //curProcessorPatchSizes.size(),
reinterpret_cast(0)
);
label nPatches = 0;
forAll(curPatchSizes, patchi)
{
// Get the face labels consistent with the field mapping
// (reuse the patch field mappers)
const polyPatch& meshPatch = meshPatches[patchi];
fvFieldDecomposer::patchFieldDecomposer patchMapper
(
SubList