/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2015 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 "simpleGeomDecomp.H" #include "addToRunTimeSelectionTable.H" #include "SortableList.H" #include "globalIndex.H" #include "SubField.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(simpleGeomDecomp, 0); addToRunTimeSelectionTable ( decompositionMethod, simpleGeomDecomp, dictionary ); } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // assignToProcessorGroup : given nCells cells and nProcGroup processor // groups to share them, how do we share them out? Answer : each group // gets nCells/nProcGroup cells, and the first few get one // extra to make up the numbers. This should produce almost // perfect load balancing void Foam::simpleGeomDecomp::assignToProcessorGroup ( labelList& processorGroup, const label nProcGroup ) const { label jump = processorGroup.size()/nProcGroup; label jumpb = jump + 1; label fstProcessorGroup = processorGroup.size() - jump*nProcGroup; label ind = 0; label j = 0; // assign cells to the first few processor groups (those with // one extra cell each for (j=0; j::less(rotatedPoints.component(vector::X)) ); assignToProcessorGroup(processorGroups, n_.x()); forAll(points, i) { finalDecomp[pointIndices[i]] = processorGroups[i]; } // now do the same thing in the Y direction. These processor group // numbers add multiples of nX to the proc. number (columns) sort ( pointIndices, UList::less(rotatedPoints.component(vector::Y)) ); assignToProcessorGroup(processorGroups, n_.y()); forAll(points, i) { finalDecomp[pointIndices[i]] += n_.x()*processorGroups[i]; } // finally in the Z direction. Now we add multiples of nX*nY to give // layers sort ( pointIndices, UList::less(rotatedPoints.component(vector::Z)) ); assignToProcessorGroup(processorGroups, n_.z()); forAll(points, i) { finalDecomp[pointIndices[i]] += n_.x()*n_.y()*processorGroups[i]; } return finalDecomp; } Foam::labelList Foam::simpleGeomDecomp::decomposeOneProc ( const pointField& points, const scalarField& weights ) const { // construct a list for the final result labelList finalDecomp(points.size()); labelList processorGroups(points.size()); labelList pointIndices(points.size()); forAll(pointIndices, i) { pointIndices[i] = i; } const pointField rotatedPoints(rotDelta_ & points); // and one to take the processor group id's. For each direction. // we assign the processors to groups of processors labelled // 0..nX to give a banded structure on the mesh. Then we // construct the actual processor number by treating this as // the units part of the processor number. sort ( pointIndices, UList::less(rotatedPoints.component(vector::X)) ); const scalar summedWeights = sum(weights); assignToProcessorGroup ( processorGroups, n_.x(), pointIndices, weights, summedWeights ); forAll(points, i) { finalDecomp[pointIndices[i]] = processorGroups[i]; } // now do the same thing in the Y direction. These processor group // numbers add multiples of nX to the proc. number (columns) sort ( pointIndices, UList::less(rotatedPoints.component(vector::Y)) ); assignToProcessorGroup ( processorGroups, n_.y(), pointIndices, weights, summedWeights ); forAll(points, i) { finalDecomp[pointIndices[i]] += n_.x()*processorGroups[i]; } // finally in the Z direction. Now we add multiples of nX*nY to give // layers sort ( pointIndices, UList::less(rotatedPoints.component(vector::Z)) ); assignToProcessorGroup ( processorGroups, n_.z(), pointIndices, weights, summedWeights ); forAll(points, i) { finalDecomp[pointIndices[i]] += n_.x()*n_.y()*processorGroups[i]; } return finalDecomp; } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::simpleGeomDecomp::simpleGeomDecomp(const dictionary& decompositionDict) : geomDecomp(decompositionDict, typeName) {} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // Foam::labelList Foam::simpleGeomDecomp::decompose ( const pointField& points ) { if (!Pstream::parRun()) { return decomposeOneProc(points); } else { globalIndex globalNumbers(points.size()); // Collect all points on master if (Pstream::master()) { pointField allPoints(globalNumbers.size()); label nTotalPoints = 0; // Master first SubField(allPoints, points.size()).assign(points); nTotalPoints += points.size(); // Add slaves for (int slave=1; slave ( allPoints, nbrPoints.size(), nTotalPoints ).assign(nbrPoints); nTotalPoints += nbrPoints.size(); } // Decompose labelList finalDecomp(decomposeOneProc(allPoints)); // Send back for (int slave=1; slave ( finalDecomp, globalNumbers.localSize(slave), globalNumbers.offset(slave) ); } // Get my own part finalDecomp.setSize(points.size()); return finalDecomp; } else { // Send my points { OPstream toMaster(Pstream::scheduled, Pstream::masterNo()); toMaster<< points; } // Receive back decomposition IPstream fromMaster(Pstream::scheduled, Pstream::masterNo()); labelList finalDecomp(fromMaster); return finalDecomp; } } } Foam::labelList Foam::simpleGeomDecomp::decompose ( const pointField& points, const scalarField& weights ) { if (!Pstream::parRun()) { return decomposeOneProc(points, weights); } else { globalIndex globalNumbers(points.size()); // Collect all points on master if (Pstream::master()) { pointField allPoints(globalNumbers.size()); scalarField allWeights(allPoints.size()); label nTotalPoints = 0; // Master first SubField(allPoints, points.size()).assign(points); SubField(allWeights, points.size()).assign(weights); nTotalPoints += points.size(); // Add slaves for (int slave=1; slave ( allPoints, nbrPoints.size(), nTotalPoints ).assign(nbrPoints); SubField ( allWeights, nbrWeights.size(), nTotalPoints ).assign(nbrWeights); nTotalPoints += nbrPoints.size(); } // Decompose labelList finalDecomp(decomposeOneProc(allPoints, allWeights)); // Send back for (int slave=1; slave ( finalDecomp, globalNumbers.localSize(slave), globalNumbers.offset(slave) ); } // Get my own part finalDecomp.setSize(points.size()); return finalDecomp; } else { // Send my points { OPstream toMaster(Pstream::scheduled, Pstream::masterNo()); toMaster<< points << weights; } // Receive back decomposition IPstream fromMaster(Pstream::scheduled, Pstream::masterNo()); labelList finalDecomp(fromMaster); return finalDecomp; } } } // ************************************************************************* //