/*---------------------------------------------------------------------------*\ ========= | \\ / 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-2024 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 "faceAreaPairGAMGAgglomeration.H" #include "fvMesh.H" #include "surfaceFields.H" #include "addToRunTimeSelectionTable.H" #include "cyclicAMIGAMGInterface.H" #include "cyclicACMIGAMGInterface.H" //#include "processorGAMGInterface.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(faceAreaPairGAMGAgglomeration, 0); addToRunTimeSelectionTable ( GAMGAgglomeration, faceAreaPairGAMGAgglomeration, lduMesh ); addToRunTimeSelectionTable ( GAMGAgglomeration, faceAreaPairGAMGAgglomeration, geometry ); } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::faceAreaPairGAMGAgglomeration::faceAreaPairGAMGAgglomeration ( const lduMesh& mesh, const dictionary& controlDict ) : pairGAMGAgglomeration(mesh, controlDict) { const fvMesh& fvmesh = refCast(mesh); if (pairGAMGAgglomeration::requiresUpdate()) { // This is the <=2406 logic. Apply perturbation to avoid jagged // agglomerations on axis-aligned meshes DebugPoutInFunction<< "Agglomerate with perturbation" << endl; //agglomerate(mesh, sqrt(fvmesh.magSf().primitiveField())); agglomerate ( nCellsInCoarsestLevel_, 0, //mesh, mag ( cmptMultiply ( fvmesh.Sf().primitiveField() /sqrt(fvmesh.magSf().primitiveField()), vector(1, 1.01, 1.02) //vector::one ) ), true ); } else { // In partial updating mode. Use Galilean invariant agglomeration // to e.g. have constant agglomeration for solid body rotation. Also // scale with face area to be consistent with (most) discretisation. DebugPoutInFunction<< "Agglomerate with faceArea magnitude" << endl; agglomerate ( nCellsInCoarsestLevel_, 0, //mesh, mag(fvmesh.magSf().primitiveField()), true ); } } Foam::faceAreaPairGAMGAgglomeration::faceAreaPairGAMGAgglomeration ( const lduMesh& mesh, const scalarField& cellVolumes, const vectorField& faceAreas, const dictionary& controlDict ) : pairGAMGAgglomeration(mesh, controlDict) { if (pairGAMGAgglomeration::requiresUpdate()) { // This is the <=2406 logic. Apply perturbation to avoid jagged // agglomerations on axis-aligned meshes DebugPoutInFunction<< "Agglomerate with perturbation" << endl; //agglomerate(mesh, sqrt(mag(faceAreas))); agglomerate ( nCellsInCoarsestLevel_, 0, //mesh, mag ( cmptMultiply ( faceAreas /sqrt(mag(faceAreas)), vector(1, 1.01, 1.02) //vector::one ) ), true ); } else { // In partial updating mode. Use Galilean invariant agglomeration // to e.g. have constant agglomeration for solid body rotation. Also // scale with face area to be consistent with (most) discretisation. DebugPoutInFunction<< "Agglomerate with faceArea magnitude" << endl; agglomerate ( nCellsInCoarsestLevel_, 0, //mesh, mag(faceAreas), true ); } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // bool Foam::faceAreaPairGAMGAgglomeration::movePoints() { const bool ok = pairGAMGAgglomeration::movePoints(); if (!requireUpdate_) { // movePoints lower down did not trigger update. Update in case of // cyclicAMI since contains addressing across patches and patches // have moved. bool hasCyclicAMI = false; if (!processorAgglomerate()) { const auto& fineInterfaces = interfaceLevel(0); forAll(fineInterfaces, inti) { if (fineInterfaces.set(inti)) { const auto& intf = fineInterfaces[inti]; if ( isA(intf) || isA(intf) ) { hasCyclicAMI = true; DebugPoutInFunction << "Detected cyclicA(C)MI at interface " << inti << ".Redoing patch agglomeration" << endl; break; } } } } if (hasCyclicAMI) { // Redo the interface agglomeration for ( label fineLevelIndex = 0; fineLevelIndex < size(); fineLevelIndex++ ) { // Near complete copy of boundary handling in // GAMGAgglomeration::agglomerateLduAddressing const auto& fineMesh = meshLevel(fineLevelIndex); const auto& fineInterfaces = interfaceLevel(fineLevelIndex); const lduAddressing& fineMeshAddr = fineMesh.lduAddr(); // Get restriction map for current level const labelField& restrictMap = restrictAddressing(fineLevelIndex); const label startOfRequests = UPstream::nRequests(); forAll(fineInterfaces, inti) { if (fineInterfaces.set(inti)) { const auto& intf = fineInterfaces[inti]; if ( isA(intf) || isA(intf) ) { if (fineLevelIndex == 0) { intf.initInternalFieldTransfer ( Pstream::commsTypes::nonBlocking, restrictMap, fineMeshAddr.patchAddr(inti) ); } else { intf.initInternalFieldTransfer ( Pstream::commsTypes::nonBlocking, restrictMap ); } } } } // Wait for comms to finised UPstream::waitRequests(startOfRequests); // New coarse-level interfaces //lduInterfacePtrsList coarseInterfaces(fineInterfaces.size()); forAll(fineInterfaces, inti) { if (fineInterfaces.set(inti)) { const auto& intf = fineInterfaces[inti]; if ( isA(intf) || isA(intf) ) { tmp restrictMapInternalField; // The finest mesh uses patchAddr from the // original lduAdressing. // the coarser levels create thei own adressing for // faceCells if (fineLevelIndex == 0) { restrictMapInternalField = intf.interfaceInternalField ( restrictMap, fineMeshAddr.patchAddr(inti) ); } else { restrictMapInternalField = intf.interfaceInternalField ( restrictMap ); } tmp nbrRestrictMapInternalField = intf.internalFieldTransfer ( Pstream::commsTypes::nonBlocking, restrictMap ); lduPrimitiveMesh& coarseMesh = meshLevels_[fineLevelIndex]; autoPtr coarseIntf ( GAMGInterface::New ( inti, coarseMesh.rawInterfaces(), intf, restrictMapInternalField(), nbrRestrictMapInternalField(), fineLevelIndex, fineMesh.comm() ) ); //coarseInterfaces.set(inti, coarseIntf.ptr()); coarseMesh.interfaces().set ( inti, coarseIntf.ptr() ); coarseMesh.primitiveInterfaces().set ( inti, &coarseMesh.interfaces()[inti] ); } } } //meshLevels_[fineLevelIndex].addInterfaces //( // coarseInterfaces, // lduPrimitiveMesh::nonBlockingSchedule // < // processorGAMGInterface // > // ( // coarseInterfaces // ) //); } } if (debug) { printLevels(); } } return ok; } // ************************************************************************* //