/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2023 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 . \*---------------------------------------------------------------------------*/ #include "pairGAMGAgglomeration.H" #include "lduAddressing.H" // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * // void Foam::pairGAMGAgglomeration::agglomerate ( const label nCellsInCoarsestLevel, const label startLevel, const scalarField& startFaceWeights, const bool doProcessorAgglomerate ) { if (nCells_.size() < maxLevels_) { // See compactLevels. Make space if not enough nCells_.resize(maxLevels_); restrictAddressing_.resize(maxLevels_); nFaces_.resize(maxLevels_); faceRestrictAddressing_.resize(maxLevels_); faceFlipMap_.resize(maxLevels_); nPatchFaces_.resize(maxLevels_); patchFaceRestrictAddressing_.resize(maxLevels_); meshLevels_.resize(maxLevels_); // Have procCommunicator_ always, even if not procAgglomerating. // Use value -1 to indicate nothing is proc-agglomerated procCommunicator_.resize(maxLevels_ + 1, -1); if (processorAgglomerate()) { procAgglomMap_.resize(maxLevels_); agglomProcIDs_.resize(maxLevels_); procCommunicator_.resize(maxLevels_); procCellOffsets_.resize(maxLevels_); procFaceMap_.resize(maxLevels_); procBoundaryMap_.resize(maxLevels_); procBoundaryFaceMap_.resize(maxLevels_); } } // Start geometric agglomeration from the given faceWeights scalarField faceWeights = startFaceWeights; // Agglomerate until the required number of cells in the coarsest level // is reached label nPairLevels = 0; label nCreatedLevels = startLevel; while (nCreatedLevels < maxLevels_ - 1) { if (!hasMeshLevel(nCreatedLevels)) { FatalErrorInFunction<< "No mesh at nCreatedLevels:" << nCreatedLevels << exit(FatalError); } const auto& fineMesh = meshLevel(nCreatedLevels); label nCoarseCells = -1; tmp finalAgglomPtr = agglomerate ( nCoarseCells, fineMesh.lduAddr(), faceWeights ); if ( continueAgglomerating ( nCellsInCoarsestLevel, finalAgglomPtr().size(), nCoarseCells, fineMesh.comm() ) ) { nCells_[nCreatedLevels] = nCoarseCells; restrictAddressing_.set(nCreatedLevels, finalAgglomPtr); } else { break; } // Create coarse mesh agglomerateLduAddressing(nCreatedLevels); // Agglomerate the faceWeights field for the next level { scalarField aggFaceWeights ( meshLevels_[nCreatedLevels].upperAddr().size(), 0.0 ); restrictFaceField ( aggFaceWeights, faceWeights, nCreatedLevels ); faceWeights = std::move(aggFaceWeights); } if (nPairLevels % mergeLevels_) { combineLevels(nCreatedLevels); } else { nCreatedLevels++; } nPairLevels++; } // Shrink the storage of the levels to those created compactLevels(nCreatedLevels, doProcessorAgglomerate); } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // Foam::tmp Foam::pairGAMGAgglomeration::agglomerate ( label& nCoarseCells, const lduAddressing& fineMatrixAddressing, const scalarField& faceWeights ) { const label nFineCells = fineMatrixAddressing.size(); const labelUList& upperAddr = fineMatrixAddressing.upperAddr(); const labelUList& lowerAddr = fineMatrixAddressing.lowerAddr(); // For each cell calculate faces labelList cellFaces(upperAddr.size() + lowerAddr.size()); labelList cellFaceOffsets(nFineCells + 1); // memory management { labelList nNbrs(nFineCells, Zero); forAll(upperAddr, facei) { nNbrs[upperAddr[facei]]++; } forAll(lowerAddr, facei) { nNbrs[lowerAddr[facei]]++; } cellFaceOffsets[0] = 0; forAll(nNbrs, celli) { cellFaceOffsets[celli+1] = cellFaceOffsets[celli] + nNbrs[celli]; } // reset the whole list to use as counter nNbrs = 0; forAll(upperAddr, facei) { cellFaces [ cellFaceOffsets[upperAddr[facei]] + nNbrs[upperAddr[facei]] ] = facei; nNbrs[upperAddr[facei]]++; } forAll(lowerAddr, facei) { cellFaces [ cellFaceOffsets[lowerAddr[facei]] + nNbrs[lowerAddr[facei]] ] = facei; nNbrs[lowerAddr[facei]]++; } } // go through the faces and create clusters auto tcoarseCellMap = tmp::New(nFineCells, -1); auto& coarseCellMap = tcoarseCellMap.ref(); nCoarseCells = 0; label celli; for (label cellfi=0; cellfi maxFaceWeight ) { // Match found. Pick up all the necessary data matchFaceNo = facei; maxFaceWeight = faceWeights[facei]; } } if (matchFaceNo >= 0) { // Make a new group coarseCellMap[upperAddr[matchFaceNo]] = nCoarseCells; coarseCellMap[lowerAddr[matchFaceNo]] = nCoarseCells; nCoarseCells++; } else { // No match. Find the best neighbouring cluster and // put the cell there label clusterMatchFaceNo = -1; scalar clusterMaxFaceCoeff = -GREAT; for ( label faceOs=cellFaceOffsets[celli]; faceOs clusterMaxFaceCoeff) { clusterMatchFaceNo = facei; clusterMaxFaceCoeff = faceWeights[facei]; } } if (clusterMatchFaceNo >= 0) { // Add the cell to the best cluster coarseCellMap[celli] = max ( coarseCellMap[upperAddr[clusterMatchFaceNo]], coarseCellMap[lowerAddr[clusterMatchFaceNo]] ); } } } } // Check that all cells are part of clusters, // if not create single-cell "clusters" for each for (label cellfi=0; cellfi