diff --git a/src/foam/Make/files b/src/foam/Make/files
index 2b7605d3d..8e795fdb2 100644
--- a/src/foam/Make/files
+++ b/src/foam/Make/files
@@ -718,7 +718,7 @@ BlockMatrixCoarsening = $(BlockAMG)/BlockMatrixCoarsening
$(BlockMatrixCoarsening)/BlockMatrixCoarsening/blockMatrixCoarsenings.C
$(BlockMatrixCoarsening)/BlockMatrixAgglomeration/blockMatrixAgglomerations.C
$(BlockMatrixCoarsening)/BlockMatrixClustering/blockMatrixClusterings.C
-$(BlockMatrixCoarsening)/BlockSelectiveAMG/blockSelectiveAMGs.C
+$(BlockMatrixCoarsening)/BlockMatrixReorderedClustering/blockMatrixReorderedClusterings.C
$(BlockMatrixCoarsening)/BlockMatrixSelection/blockMatrixSelections.C
BlockLduPrecons = matrices/blockLduMatrix/BlockLduPrecons
diff --git a/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/BlockMatrixReorderedClustering.C b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/BlockMatrixReorderedClustering.C
new file mode 100644
index 000000000..5126e480a
--- /dev/null
+++ b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/BlockMatrixReorderedClustering.C
@@ -0,0 +1,1505 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | foam-extend: Open Source CFD
+ \\ / O peration | Version: 4.0
+ \\ / A nd | Web: http://www.foam-extend.org
+ \\/ M anipulation | For copyright notice see file Copyright
+-------------------------------------------------------------------------------
+License
+ This file is part of foam-extend.
+
+ foam-extend 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.
+
+ foam-extend 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 foam-extend. If not, see .
+
+Class
+ BlockMatrixReorderedClustering
+
+Description
+ Block matrix AMG coarsening by Jasak clustering algorithm
+
+Author
+ Hrvoje Jasak, Wikki Ltd. All rights reserved
+
+\*---------------------------------------------------------------------------*/
+
+#include "BlockMatrixReorderedClustering.H"
+#include "boolList.H"
+#include "tolerancesSwitch.H"
+#include "coeffFields.H"
+#include "BlockAMGInterfaceField.H"
+#include "coarseBlockAMGLevel.H"
+#include "PriorityList.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+template
+const Foam::debug::tolerancesSwitch
+Foam::BlockMatrixReorderedClustering::weightFactor_
+(
+ "aamgWeightFactor",
+ 0.65
+);
+
+
+template
+const Foam::debug::tolerancesSwitch
+Foam::BlockMatrixReorderedClustering::diagFactor_
+(
+ "aamgDiagFactor",
+ 1e-8
+);
+
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+template
+void Foam::BlockMatrixReorderedClustering::calcClustering()
+{
+ if (matrix_.diagonal())
+ {
+ // Diag only matrix. Reset and return
+ agglomIndex_ = 0;
+ nCoarseEqns_ = 1;
+
+ return;
+ }
+
+ // Algorithm:
+ // 1) Calculate appropriate connection strength for symmetric and asymmetric
+ // matrix
+ // 2) Collect solo (disconnected) cells and remove them from agglomeration
+ // by placing them into cluster zero (solo group)
+ // 3) Loop through all equations and for each equation find the best fit
+ // neighbour. If all neighbours are grouped, add equation
+ // to best group
+
+ // Initialise child array
+ agglomIndex_ = -1;
+
+ const label nRows = matrix_.lduAddr().size();
+
+ // Get matrix addressing
+ const unallocLabelList& lowerAddr = matrix_.lduAddr().lowerAddr();
+ const unallocLabelList& upperAddr = matrix_.lduAddr().upperAddr();
+ const unallocLabelList& losortAddr = matrix_.lduAddr().losortAddr();
+
+ const unallocLabelList& ownerStartAddr =
+ matrix_.lduAddr().ownerStartAddr();
+ const unallocLabelList& losortStartAddr =
+ matrix_.lduAddr().losortStartAddr();
+
+
+ // Calculate clustering
+
+ // Get matrix coefficients and norms Note: the norm
+ // may be signed, ie. it will take the sign of the coefficient
+
+ const CoeffField& diag = matrix_.diag();
+ scalarField normDiag(diag.size());
+ normPtr_->normalize(normDiag, diag);
+
+ scalarField normUpper(upperAddr.size(), 0);
+ scalarField normLower(upperAddr.size(), 0);
+
+ // Note:
+ // Matrix properties are no longer assumed, eg. the diag and off-diag
+ // sign is checked
+ // HJ, 29/Mar/2017
+
+ // Note: negative connections are eliminated in max(...) below
+ // HJ, 30/Mar/2017
+
+ if (matrix_.thereIsUpper())
+ {
+ normPtr_->normalize(normUpper, matrix_.upper());
+
+ // Owner: upper triangle
+ forAll (lowerAddr, coeffI)
+ {
+ // Sign of strong positive upper is opposite of the sign of
+ // its diagonal coefficient
+ normUpper[coeffI] = Foam::max
+ (
+ -1*sign(normDiag[lowerAddr[coeffI]])*normUpper[coeffI],
+ 0
+ );
+ }
+ }
+
+ if (matrix_.thereIsLower())
+ {
+ normPtr_->normalize(normLower, matrix_.lower());
+
+ // Neighbour: lower triangle
+ forAll (lowerAddr, coeffI)
+ {
+ // Sign of strong positive upper is opposite of the sign of
+ // its diagonal coefficient
+ normLower[coeffI] = Foam::max
+ (
+ -1*sign(normDiag[upperAddr[coeffI]])*normLower[coeffI],
+ 0
+ );
+ }
+ }
+ else
+ {
+ normLower = normUpper;
+ }
+
+ // Take magnitude of the diagonal norm after the normalisation
+ // of upper and lower is complete
+ // Note: upper and lower are already normalised
+ normDiag = mag(normDiag);
+
+ labelList sizeOfGroups(nRows, 0);
+
+ nCoarseEqns_ = 0;
+
+ // Gather disconnected and weakly connected equations into cluster zero
+ // Weak connection is assumed to be the one where the off-diagonal
+ // coefficient is smaller than diagFactor_()*diag
+ {
+ // Algorithm
+ // Mark all cells to belong to zero cluster
+ // Go through all upper and lower coefficients and for the ones
+ // larger than threshold mark the equations out of cluster zero
+
+ scalarField scaledNormDiag = diagFactor_()*normDiag;
+
+ boolList zeroCluster(normDiag.size(), true);
+
+ if (matrix_.symmetric())
+ {
+ // Owner: upper triangle
+ forAll (lowerAddr, coeffI)
+ {
+ if (normUpper[coeffI] > scaledNormDiag[lowerAddr[coeffI]])
+ {
+ zeroCluster[lowerAddr[coeffI]] = false;
+ }
+ }
+
+ // Neighbour: lower triangle with symm coefficients
+ forAll (upperAddr, coeffI)
+ {
+ if (normUpper[coeffI] > scaledNormDiag[upperAddr[coeffI]])
+ {
+ zeroCluster[upperAddr[coeffI]] = false;
+ }
+ }
+ }
+ else if (matrix_.asymmetric())
+ {
+ // Owner: upper triangle
+ forAll (lowerAddr, coeffI)
+ {
+ if (normUpper[coeffI] > scaledNormDiag[lowerAddr[coeffI]])
+ {
+ zeroCluster[lowerAddr[coeffI]] = false;
+ }
+ }
+
+ // Neighbour: lower triangle with lower coeffs
+ forAll (upperAddr, coeffI)
+ {
+ if (normLower[coeffI] > scaledNormDiag[upperAddr[coeffI]])
+ {
+ zeroCluster[upperAddr[coeffI]] = false;
+ }
+ }
+ }
+
+ // Collect solo equations
+ forAll (zeroCluster, eqnI)
+ {
+ if (zeroCluster[eqnI])
+ {
+ // Found solo equation
+ nSolo_++;
+
+ agglomIndex_[eqnI] = nCoarseEqns_;
+ }
+ }
+
+ if (nSolo_ > 0)
+ {
+ // Found solo equations
+ sizeOfGroups[nCoarseEqns_] = nSolo_;
+
+ nCoarseEqns_++;
+ }
+ }
+
+
+ // Loop through cells
+ // - if the cell is not already grouped, open a new group (seed)
+ // - find stroungest grouped and ungrouped connection:
+ // - grouped connection is towards an already grouped cell
+ // - ungrouped connection is towards an ungrouped cell
+ // - decide if a grouped or ungrouped connection is better
+
+ label curEqn, indexUngrouped, indexGrouped, colI, groupPassI,
+ nextUngrouped, nextGrouped;
+
+ scalar curWeight, weightUngrouped, weightGrouped;
+
+ for (label rowI = 0; rowI < nRows; rowI++)
+ {
+ if (agglomIndex_[rowI] == -1)
+ {
+ // Found new ungrouped equation
+ curEqn = rowI;
+
+ // Reset grouped and upgrouped index
+ indexUngrouped = -1;
+ indexGrouped = -1;
+
+ // Make next group (coarse equation) and search for neighbours
+ agglomIndex_[curEqn] = nCoarseEqns_;
+
+ // Work on the group until the min group size is satisfied
+ // As each new element of the group is found, group search starts
+ // from this element until group cluster size is satisfied
+ for
+ (
+ groupPassI = 1;
+ groupPassI < minGroupSize_;
+ groupPassI++
+ )
+ {
+ weightUngrouped = 0;
+ weightGrouped = 0;
+
+ indexUngrouped = -1;
+ indexGrouped = -1;
+
+ nextUngrouped = -1;
+ nextGrouped = -1;
+
+ // Visit all neighbour equations
+
+ // Visit upper triangle coefficients from the equation
+ for
+ (
+ label rowCoeffI = ownerStartAddr[curEqn];
+ rowCoeffI < ownerStartAddr[curEqn + 1];
+ rowCoeffI++
+ )
+ {
+ // Get column index, upper triangle
+ colI = upperAddr[rowCoeffI];
+
+ // curWeight = normUpper[rowCoeffI]/
+ // // normDiag[curEqn];
+ // max(normDiag[curEqn], normDiag[colI]);
+
+ curWeight = Foam::min
+ (
+ normUpper[rowCoeffI]/normDiag[curEqn],
+ normLower[rowCoeffI]/normDiag[colI]
+ );
+
+ if (agglomIndex_[colI] == -1)
+ {
+ // Found ungrouped neighbour
+ if
+ (
+ indexUngrouped == -1
+ || curWeight > weightUngrouped
+ )
+ {
+ // Found or updated ungrouped neighbour
+ indexUngrouped = rowCoeffI;
+ weightUngrouped = curWeight;
+
+ // Record possible next equation for search
+ nextUngrouped = colI;
+ }
+ }
+ else if (agglomIndex_[curEqn] != agglomIndex_[colI])
+ {
+ // Check for neighbour in solo group
+ if (nSolo_ == 0 || agglomIndex_[colI] != 0)
+ {
+ // Found neighbour belonging to other group
+ if (indexGrouped == -1 || curWeight > weightGrouped)
+ {
+ // Found or updated grouped neighbour
+ indexGrouped = rowCoeffI;
+ weightGrouped = curWeight;
+
+ // Record possible next equation for search
+ nextGrouped = colI;
+ }
+ }
+ }
+ }
+
+ // Visit lower triangle coefficients from the equation
+ for
+ (
+ label rowCoeffI = losortStartAddr[curEqn];
+ rowCoeffI < losortStartAddr[curEqn + 1];
+ rowCoeffI++
+ )
+ {
+ // Get column index, lower triangle
+ colI = lowerAddr[losortAddr[rowCoeffI]];
+
+ // curWeight = normLower[losortAddr[rowCoeffI]]/
+ // // normDiag[curEqn];
+ // max(normDiag[curEqn], normDiag[colI]);
+
+ curWeight = Foam::min
+ (
+ normLower[losortAddr[rowCoeffI]]/normDiag[curEqn],
+ normUpper[losortAddr[rowCoeffI]]/normDiag[colI]
+ );
+
+ if (agglomIndex_[colI] == -1)
+ {
+ // Found first or better ungrouped neighbour
+ if
+ (
+ indexUngrouped == -1
+ || curWeight > weightUngrouped
+ )
+ {
+ // Found or updated ungrouped neighbour
+ indexUngrouped = rowCoeffI;
+ weightUngrouped = curWeight;
+
+ // Record possible next equation for search
+ nextUngrouped = colI;
+ }
+ }
+ else if (agglomIndex_[curEqn] != agglomIndex_[colI])
+ {
+ // Check for neighbour in solo group
+ if (nSolo_ == 0 || agglomIndex_[colI] != 0)
+ {
+ // Found first of better neighbour belonging to
+ // other group
+ if
+ (
+ indexGrouped == -1
+ || curWeight > weightGrouped
+ )
+ {
+ // Found or updated grouped neighbour
+ indexGrouped = rowCoeffI;
+ weightGrouped = curWeight;
+
+ // Record possible next equation for search
+ nextGrouped = colI;
+ }
+ }
+ }
+ }
+
+ // Decide what to do with current equation
+
+ // If ungrouped candidate exists and it is stronger
+ // than best weighted grouped candidate, use it
+ if
+ (
+ indexUngrouped != -1
+ && (
+ indexGrouped == -1
+ || weightUngrouped >= weightFactor_()*weightGrouped
+ )
+ )
+ {
+ // Found new element of group. Add it and use as
+ // start of next search
+
+ agglomIndex_[nextUngrouped] = agglomIndex_[curEqn];
+ sizeOfGroups[agglomIndex_[curEqn]]++;
+
+ // Search from nextEqn
+ curEqn = nextUngrouped;
+ }
+ else
+ {
+ // Group full or cannot be extended with new
+ // ungrouped candidates
+ break;
+ }
+ }
+
+
+ // Finished group passes
+ if
+ (
+ groupPassI > 1
+ || indexGrouped == -1
+ || sizeOfGroups[agglomIndex_[nextGrouped]] >= maxGroupSize_
+ )
+ {
+ // If this is a solo cell and a group is available
+ // force it into the group irrespective of size
+ if
+ (
+ sizeOfGroups[agglomIndex_[rowI]] == 0
+ && indexGrouped != -1
+
+ )
+ {
+ // Group exists, but it's too big. Add it anyway
+ agglomIndex_[rowI] = agglomIndex_[nextGrouped];
+ sizeOfGroups[agglomIndex_[nextGrouped]]++;
+ }
+ else
+ {
+ // No group and no solo group. Make its own group
+ sizeOfGroups[agglomIndex_[rowI]]++;
+ nCoarseEqns_++;
+ }
+ }
+ else
+ {
+ // Dump current cell into the best group available
+ agglomIndex_[rowI] = agglomIndex_[nextGrouped];
+ sizeOfGroups[agglomIndex_[nextGrouped]]++;
+ }
+ }
+ }
+
+ // Resize group size count
+ sizeOfGroups.setSize(nCoarseEqns_);
+
+ // Go through faces belonging to a single cluster and sum up their
+ // off-Diagonals - this will go into Priority list for reordering
+
+ // Weight array
+ scalarField clusterWeight(nCoarseEqns_, 0);
+
+ for (label eqn = 0; eqn < nRows; eqn++)
+ {
+ // Find neighbours of cells which are shared with a cell in another
+ // cluster - this is a new face on the coarse level
+ for (label i = ownerStartAddr[eqn]; i < ownerStartAddr[eqn + 1]; i++)
+ {
+ // column of upper coefficient (i.e. neighbour)
+ label j = upperAddr[i];
+
+ // Check whether the neighbour is in my cluster
+ if (agglomIndex_[eqn] != agglomIndex_[j])
+ {
+ // Neighbouring cluster found - new face on coarse level
+
+ // Upper triangle - give weight to me
+ clusterWeight[agglomIndex_[eqn]] += normUpper[i];
+
+ // Lower triangle - give weight to neighbour
+ clusterWeight[agglomIndex_[j]] += normLower[i];
+ }
+ }
+ }
+
+ // Calculate the sum of off-diags for coarse eqns and put them into priority
+ // array
+ // Be careful to match the index of the equation to the coarse level]
+
+ // Create the PriorityList, where the weights are sumMagOffDiagCoeffs
+ PriorityList cardinality(nCoarseEqns_);
+
+ for (label eqnI = 0; eqnI < nCoarseEqns_; ++eqnI)
+ {
+ cardinality.set(eqnI, clusterWeight[eqnI]);
+ }
+
+ // Reorder my coarse equations according to priority array and save into
+ // renumberedCluster
+ labelList renumberedCluster(nCoarseEqns_, -1);
+
+ label count = 0;
+ while (!cardinality.empty())
+ {
+ renumberedCluster[count] = cardinality.removeHead();
+ count++;
+ }
+
+ // Write the new ordering of clusters into agglomIndex_ array
+ forAll (agglomIndex_, i)
+ {
+ agglomIndex_[i] = renumberedCluster[agglomIndex_[i]];
+ }
+
+ // The decision on parallel agglomeration needs to be made for the
+ // whole gang of processes; otherwise I may end up with a different
+ // number of agglomeration levels on different processors.
+
+ // If the number of coarse equations is less than minimum and
+ // if the matrix has reduced in size by at least 1/3, coarsen
+ if
+ (
+ nCoarseEqns_ > BlockMatrixCoarsening::minCoarseEqns()
+ && 3*nCoarseEqns_ <= 2*nRows
+ )
+ {
+ coarsen_ = true;
+ }
+
+ reduce(coarsen_, andOp());
+
+ if (blockLduMatrix::debug >= 3)
+ {
+ // Count singleton clusters
+ label nSingleClusters = 0;
+
+ // Adjust start based on solo cells cluster status
+ label start = 0;
+
+ if (nSolo_ > 0)
+ {
+ start = 1;
+ }
+
+ for (label i = start; i < sizeOfGroups.size(); i++)
+ {
+ if (sizeOfGroups[i] == 1)
+ {
+ nSingleClusters++;
+ }
+ }
+
+ Pout<< "Coarse level size: " << nCoarseEqns_
+ << " nSolo = " << nSolo_
+ << " cluster (" << min(sizeOfGroups) << " "
+ << max(sizeOfGroups)
+ << "). N singleton clusters = " << nSingleClusters;
+
+ if (coarsen_)
+ {
+ Pout << ". Accepted" << endl;
+ }
+ else
+ {
+ Pout << ". Rejected" << endl;
+ }
+ }
+}
+
+
+template
+void Foam::BlockMatrixReorderedClustering::restrictDiag
+(
+ const CoeffField& Coeff,
+ CoeffField& coarseCoeff
+) const
+{
+ typedef CoeffField TypeCoeffField;
+
+ if
+ (
+ Coeff.activeType() == blockCoeffBase::SQUARE
+ && coarseCoeff.activeType() == blockCoeffBase::SQUARE
+ )
+ {
+ typedef typename TypeCoeffField::squareType squareType;
+ typedef typename TypeCoeffField::squareTypeField squareTypeField;
+
+ squareTypeField& activeCoarseCoeff = coarseCoeff.asSquare();
+ const squareTypeField& activeCoeff = Coeff.asSquare();
+
+ forAll (coarseCoeff, i)
+ {
+ activeCoarseCoeff[i] = pTraits::zero;
+ }
+
+ forAll (Coeff, i)
+ {
+ activeCoarseCoeff[agglomIndex_[i]] += activeCoeff[i];
+ }
+ }
+ else if
+ (
+ Coeff.activeType() == blockCoeffBase::LINEAR
+ && coarseCoeff.activeType() == blockCoeffBase::LINEAR
+ )
+ {
+ typedef typename TypeCoeffField::linearType linearType;
+ typedef typename TypeCoeffField::linearTypeField linearTypeField;
+
+ linearTypeField& activeCoarseCoeff = coarseCoeff.asLinear();
+ const linearTypeField& activeCoeff = Coeff.asLinear();
+
+ forAll (coarseCoeff, i)
+ {
+ activeCoarseCoeff[i] = pTraits::zero;
+ }
+
+ forAll (Coeff, i)
+ {
+ activeCoarseCoeff[agglomIndex_[i]] += activeCoeff[i];
+ }
+ }
+ else if
+ (
+ Coeff.activeType() == blockCoeffBase::SCALAR
+ && coarseCoeff.activeType() == blockCoeffBase::SCALAR
+ )
+ {
+ typedef typename TypeCoeffField::scalarType scalarType;
+ typedef typename TypeCoeffField::scalarTypeField scalarTypeField;
+
+ scalarTypeField& activeCoarseCoeff = coarseCoeff.asScalar();
+ const scalarTypeField& activeCoeff = Coeff.asScalar();
+
+ forAll (coarseCoeff, i)
+ {
+ activeCoarseCoeff[i] = pTraits::zero;
+ }
+
+ forAll (Coeff, i)
+ {
+ activeCoarseCoeff[agglomIndex_[i]] += activeCoeff[i];
+ }
+ }
+ else
+ {
+ FatalErrorIn
+ (
+ "void BlockMatrixReorderedClustering::restrictDiag() const"
+ ) << "Problem in coeff type morphing"
+ << abort(FatalError);
+ }
+}
+
+
+template
+template
+void Foam::BlockMatrixReorderedClustering::agglomerateCoeffs
+(
+ const labelList& coeffRestrictAddr,
+ Field& activeCoarseDiag,
+ Field& activeCoarseUpper,
+ const Field& activeFineUpper,
+ const Field& activeFineUpperTranspose
+) const
+{
+ // Does the matrix have solo equations
+ bool soloEqns = nSolo_ > 0;
+
+ // Get addressing
+ const unallocLabelList& upperAddr = matrix_.lduAddr().upperAddr();
+ const unallocLabelList& lowerAddr = matrix_.lduAddr().lowerAddr();
+
+ forAll(coeffRestrictAddr, fineCoeffI)
+ {
+ label rmUpperAddr = agglomIndex_[upperAddr[fineCoeffI]];
+ label rmLowerAddr = agglomIndex_[lowerAddr[fineCoeffI]];
+
+ // If the coefficient touches block zero and
+ // solo equations are present, skip it
+ if (soloEqns && (rmUpperAddr == 0 || rmLowerAddr == 0))
+ {
+ continue;
+ }
+
+ label cCoeff = coeffRestrictAddr[fineCoeffI];
+
+ if (cCoeff >= 0)
+ {
+ activeCoarseUpper[cCoeff] += activeFineUpper[fineCoeffI];
+ }
+ else
+ {
+ // Add the fine face coefficient into the diagonal
+ // Note: upper and lower coeffs are transpose of
+ // each other. HJ, 28/May/2014
+ activeCoarseDiag[-1 - cCoeff] +=
+ activeFineUpper[fineCoeffI]
+ + activeFineUpperTranspose[fineCoeffI];
+ }
+ }
+}
+
+
+template
+template
+void Foam::BlockMatrixReorderedClustering::agglomerateCoeffs
+(
+ const labelList& coeffRestrictAddr,
+ Field& activeCoarseDiag,
+ Field& activeCoarseUpper,
+ const Field& activeFineUpper,
+ Field& activeCoarseLower,
+ const Field& activeFineLower
+) const
+{
+ // Does the matrix have solo equations
+ bool soloEqns = nSolo_ > 0;
+
+ // Get addressing
+ const unallocLabelList& upperAddr = matrix_.lduAddr().upperAddr();
+ const unallocLabelList& lowerAddr = matrix_.lduAddr().lowerAddr();
+
+ forAll(coeffRestrictAddr, fineCoeffI)
+ {
+ label rmUpperAddr = agglomIndex_[upperAddr[fineCoeffI]];
+ label rmLowerAddr = agglomIndex_[lowerAddr[fineCoeffI]];
+
+ // If the coefficient touches block zero and
+ // solo equations are present, skip it
+ if (soloEqns && (rmUpperAddr == 0 || rmLowerAddr == 0))
+ {
+ continue;
+ }
+
+ label cCoeff = coeffRestrictAddr[fineCoeffI];
+
+ if (cCoeff >= 0)
+ {
+ activeCoarseUpper[cCoeff] += activeFineUpper[fineCoeffI];
+ activeCoarseLower[cCoeff] += activeFineLower[fineCoeffI];
+ }
+ else
+ {
+ // Add the fine face coefficients into the diagonal.
+ activeCoarseDiag[-1 - cCoeff] +=
+ activeFineUpper[fineCoeffI]
+ + activeFineLower[fineCoeffI];
+ }
+ }
+}
+
+
+template
+void Foam::BlockMatrixReorderedClustering::restrictDiagDecoupled
+(
+ const CoeffField& Coeff,
+ CoeffField& coarseCoeff
+) const
+{
+ typedef CoeffField TypeCoeffField;
+
+ if
+ (
+ Coeff.activeType() == blockCoeffBase::LINEAR
+ && coarseCoeff.activeType() == blockCoeffBase::LINEAR
+ )
+ {
+ typedef typename TypeCoeffField::linearType linearType;
+ typedef typename TypeCoeffField::linearTypeField linearTypeField;
+
+ linearTypeField& activeCoarseCoeff = coarseCoeff.asLinear();
+ const linearTypeField& activeCoeff = Coeff.asLinear();
+
+ forAll (coarseCoeff, i)
+ {
+ activeCoarseCoeff[i] = pTraits::zero;
+ }
+
+ forAll (Coeff, i)
+ {
+ activeCoarseCoeff[agglomIndex_[i]] += activeCoeff[i];
+ }
+ }
+ else if
+ (
+ Coeff.activeType() == blockCoeffBase::SCALAR
+ && coarseCoeff.activeType() == blockCoeffBase::SCALAR
+ )
+ {
+ typedef typename TypeCoeffField::scalarType scalarType;
+ typedef typename TypeCoeffField::scalarTypeField scalarTypeField;
+
+ scalarTypeField& activeCoarseCoeff = coarseCoeff.asScalar();
+ const scalarTypeField& activeCoeff = Coeff.asScalar();
+
+ forAll (coarseCoeff, i)
+ {
+ activeCoarseCoeff[i] = pTraits::zero;
+ }
+
+ forAll (Coeff, i)
+ {
+ activeCoarseCoeff[agglomIndex_[i]] += activeCoeff[i];
+ }
+ }
+ else
+ {
+ FatalErrorIn
+ (
+ "void BlockMatrixReorderedClustering::restrictDiagDecoupled()"
+ " const"
+ ) << "Problem in coeff type morphing"
+ << abort(FatalError);
+ }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+template
+Foam::BlockMatrixReorderedClustering::BlockMatrixReorderedClustering
+(
+ const BlockLduMatrix& matrix,
+ const dictionary& dict,
+ const label groupSize,
+ const label minCoarseEqns
+)
+:
+ BlockMatrixCoarsening(matrix, dict, groupSize, minCoarseEqns),
+ matrix_(matrix),
+ minGroupSize_(readLabel(dict.lookup("minGroupSize"))),
+ maxGroupSize_(readLabel(dict.lookup("maxGroupSize"))),
+ normPtr_(BlockCoeffNorm::New(dict)),
+ agglomIndex_(matrix_.lduAddr().size()),
+ groupSize_(groupSize),
+ nSolo_(0),
+ nCoarseEqns_(0),
+ coarsen_(false),
+ lTime_()
+{
+ calcClustering();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
+
+template
+Foam::BlockMatrixReorderedClustering::~BlockMatrixReorderedClustering()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+template
+Foam::autoPtr >
+Foam::BlockMatrixReorderedClustering::restrictMatrix() const
+{
+ if (!coarsen_)
+ {
+ FatalErrorIn
+ (
+ "autoPtr > "
+ "BlockMatrixReorderedClustering::restrictMatrix() const"
+ ) << "Requesting coarse matrix when it cannot be created"
+ << abort(FatalError);
+ }
+
+ // Construct the coarse matrix and ldu addressing for the next level
+ // Algorithm:
+ // 1) Loop through all fine coeffs. If the agglom labels on two sides are
+ // different, this creates a coarse coeff. Define owner and neighbour
+ // for this coeff based on cluster IDs.
+ // 2) Check if the coeff has been seen before. If yes, add the coefficient
+ // to the appropriate field (stored with the equation). If no, create
+ // a new coeff with neighbour ID and add the coefficient
+ // 3) Once all the coeffs have been created, loop through all clusters and
+ // insert the coeffs in the upper order. At the same time, collect the
+ // owner and neighbour addressing.
+ // 4) Agglomerate the diagonal by summing up the fine diagonal
+
+ // Get addressing
+ const unallocLabelList& upperAddr = matrix_.lduAddr().upperAddr();
+ const unallocLabelList& lowerAddr = matrix_.lduAddr().lowerAddr();
+
+ const label nFineCoeffs = upperAddr.size();
+
+# ifdef FULLDEBUG
+ if (agglomIndex_.size() != matrix_.lduAddr().size())
+ {
+ FatalErrorIn
+ (
+ "autoPtr >"
+ "BlockMatrixReorderedClustering::restrictMatrix() const"
+ ) << "agglomIndex array does not correspond to fine level. " << endl
+ << " Size: " << agglomIndex_.size()
+ << " number of equations: " << matrix_.lduAddr().size()
+ << abort(FatalError);
+ }
+# endif
+
+ // Does the matrix have solo equations
+ bool soloEqns = nSolo_ > 0;
+
+ // Storage for block neighbours and coefficients
+
+ // Guess initial maximum number of neighbours in block
+ label maxNnbrs = 10;
+
+ // Number of neighbours per block
+ labelList blockNnbrs(nCoarseEqns_, 0);
+
+ // Setup initial packed storage for neighbours and coefficients
+ labelList blockNbrsData(maxNnbrs*nCoarseEqns_);
+
+ // Create face-restriction addressing
+ labelList coeffRestrictAddr(nFineCoeffs);
+
+ // Initial neighbour array (not in upper-triangle order)
+ labelList initCoarseNeighb(nFineCoeffs);
+
+ // Counter for coarse coeffs
+ label nCoarseCoeffs = 0;
+
+ // Loop through all fine coeffs
+ forAll (upperAddr, fineCoeffi)
+ {
+ label rmUpperAddr = agglomIndex_[upperAddr[fineCoeffi]];
+ label rmLowerAddr = agglomIndex_[lowerAddr[fineCoeffi]];
+
+ // If the coefficient touches block zero and solo equations are
+ // present, skip it
+ if (soloEqns && (rmUpperAddr == 0 || rmLowerAddr == 0))
+ {
+ continue;
+ }
+
+ if (rmUpperAddr == rmLowerAddr)
+ {
+ // For each fine coeff inside of a coarse cluster keep the address
+ // of the cluster corresponding to the coeff in the
+ // coeffRestrictAddr as a negative index
+ coeffRestrictAddr[fineCoeffi] = -(rmUpperAddr + 1);
+ }
+ else
+ {
+ // This coeff is a part of a coarse coeff
+
+ label cOwn = rmUpperAddr;
+ label cNei = rmLowerAddr;
+
+ // Get coarse owner and neighbour
+ if (rmUpperAddr > rmLowerAddr)
+ {
+ cOwn = rmLowerAddr;
+ cNei = rmUpperAddr;
+ }
+
+ // Check the neighbour to see if this coeff has already been found
+ bool nbrFound = false;
+ label& ccnCoeffs = blockNnbrs[cOwn];
+
+ for (int i = 0; i < ccnCoeffs; i++)
+ {
+ if (initCoarseNeighb[blockNbrsData[maxNnbrs*cOwn + i]] == cNei)
+ {
+ nbrFound = true;
+ coeffRestrictAddr[fineCoeffi] =
+ blockNbrsData[maxNnbrs*cOwn + i];
+ break;
+ }
+ }
+
+ if (!nbrFound)
+ {
+ if (ccnCoeffs >= maxNnbrs)
+ {
+ // Double the size of list and copy data
+ label oldMaxNnbrs = maxNnbrs;
+ maxNnbrs *= 2;
+
+ // Resize and copy list
+ const labelList oldBlockNbrsData = blockNbrsData;
+ blockNbrsData.setSize(maxNnbrs*nCoarseEqns_);
+
+ forAll (blockNnbrs, i)
+ {
+ for (int j = 0; j < blockNnbrs[i]; j++)
+ {
+ blockNbrsData[maxNnbrs*i + j] =
+ oldBlockNbrsData[oldMaxNnbrs*i + j];
+ }
+ }
+ }
+
+ blockNbrsData[maxNnbrs*cOwn + ccnCoeffs] = nCoarseCoeffs;
+ initCoarseNeighb[nCoarseCoeffs] = cNei;
+ coeffRestrictAddr[fineCoeffi] = nCoarseCoeffs;
+ ccnCoeffs++;
+
+ // New coarse coeff created
+ nCoarseCoeffs++;
+ }
+ }
+ } // End for all fine coeffs
+
+
+ // Renumber into upper-triangular order
+
+ // All coarse owner-neighbour storage
+ labelList coarseOwner(nCoarseCoeffs);
+ labelList coarseNeighbour(nCoarseCoeffs);
+ labelList coarseCoeffMap(nCoarseCoeffs);
+
+ label coarseCoeffi = 0;
+
+ forAll (blockNnbrs, cci)
+ {
+ label* cCoeffs = &blockNbrsData[maxNnbrs*cci];
+ label ccnCoeffs = blockNnbrs[cci];
+
+ for (int i = 0; i < ccnCoeffs; i++)
+ {
+ coarseOwner[coarseCoeffi] = cci;
+ coarseNeighbour[coarseCoeffi] = initCoarseNeighb[cCoeffs[i]];
+ coarseCoeffMap[cCoeffs[i]] = coarseCoeffi;
+ coarseCoeffi++;
+ }
+ }
+
+ forAll(coeffRestrictAddr, fineCoeffi)
+ {
+ label rmUpperAddr = agglomIndex_[upperAddr[fineCoeffi]];
+ label rmLowerAddr = agglomIndex_[lowerAddr[fineCoeffi]];
+
+ // If the coefficient touches block zero and solo equations are
+ // present, skip it
+ if (soloEqns && (rmUpperAddr == 0 || rmLowerAddr == 0))
+ {
+ continue;
+ }
+
+ if (coeffRestrictAddr[fineCoeffi] >= 0)
+ {
+ coeffRestrictAddr[fineCoeffi] =
+ coarseCoeffMap[coeffRestrictAddr[fineCoeffi]];
+ }
+ }
+
+ // Clear the temporary storage for the coarse matrix data
+ blockNnbrs.setSize(0);
+ blockNbrsData.setSize(0);
+ initCoarseNeighb.setSize(0);
+ coarseCoeffMap.setSize(0);
+
+
+ // Create coarse-level coupled interfaces
+
+ // Create coarse interfaces, addressing and coefficients
+ const label interfaceSize =
+ const_cast& >(matrix_).interfaces().size();
+
+ const typename BlockLduInterfaceFieldPtrsList::Type&
+ interfaceFields =
+ const_cast&>(matrix_).interfaces();
+
+ // Set the coarse interfaces and coefficients
+ lduInterfacePtrsList coarseInterfaces(interfaceSize);
+
+ labelListList coarseInterfaceAddr(interfaceSize);
+
+ // Add the coarse level
+
+ // Set the coarse ldu addressing onto the list
+ autoPtr coarseAddrPtr
+ (
+ new lduPrimitiveMesh
+ (
+ nCoarseEqns_,
+ coarseOwner,
+ coarseNeighbour,
+ Pstream::worldComm, //HJ, AMG Comm fineMesh.comm(),
+ true
+ )
+ );
+
+ // Initialise transfer of restrict addressing on the interface
+ // HJ, must use blocking comms. HJ, 9/Jun/2016
+ forAll (interfaceFields, intI)
+ {
+ if (interfaceFields.set(intI))
+ {
+ interfaceFields[intI].coupledInterface().initInternalFieldTransfer
+ (
+ Pstream::blocking,
+ agglomIndex_
+ );
+ }
+ }
+
+ // Store coefficients to avoid tangled communications
+ // HJ, 1/Apr/2009
+ FieldField fineInterfaceAddr(interfaceFields.size());
+
+ forAll (interfaceFields, intI)
+ {
+ if (interfaceFields.set(intI))
+ {
+ const lduInterface& fineInterface =
+ interfaceFields[intI].coupledInterface();
+
+ fineInterfaceAddr.set
+ (
+ intI,
+ new labelField
+ (
+ fineInterface.internalFieldTransfer
+ (
+ Pstream::blocking,
+ agglomIndex_
+ )
+ )
+ );
+ }
+ }
+
+ // Create AMG interfaces
+ forAll (interfaceFields, intI)
+ {
+ if (interfaceFields.set(intI))
+ {
+ const lduInterface& fineInterface =
+ interfaceFields[intI].coupledInterface();
+
+ coarseInterfaces.set
+ (
+ intI,
+ AMGInterface::New
+ (
+ coarseAddrPtr(),
+ coarseInterfaces,
+ fineInterface,
+ fineInterface.interfaceInternalField(agglomIndex_),
+ fineInterfaceAddr[intI]
+ ).ptr()
+ );
+ }
+ }
+
+ forAll (interfaceFields, intI)
+ {
+ if (interfaceFields.set(intI))
+ {
+ const AMGInterface& coarseInterface =
+ refCast(coarseInterfaces[intI]);
+
+ coarseInterfaceAddr[intI] = coarseInterface.faceCells();
+ }
+ }
+
+ // Add interfaces
+ coarseAddrPtr->addInterfaces
+ (
+ coarseInterfaces,
+ coarseInterfaceAddr,
+ matrix_.patchSchedule()
+ );
+
+ // Set the coarse level matrix
+ autoPtr > coarseMatrixPtr
+ (
+ new BlockLduMatrix(coarseAddrPtr())
+ );
+ BlockLduMatrix& coarseMatrix = coarseMatrixPtr();
+
+ // Get interfaces from coarse matrix
+ typename BlockLduInterfaceFieldPtrsList::Type&
+ coarseInterfaceFieldsTransfer = coarseMatrix.interfaces();
+
+ // Aggolmerate the upper and lower coupled coefficients
+ forAll (interfaceFields, intI)
+ {
+ if (interfaceFields.set(intI))
+ {
+ const AMGInterface& coarseInterface =
+ refCast(coarseInterfaces[intI]);
+
+ coarseInterfaceFieldsTransfer.set
+ (
+ intI,
+ BlockAMGInterfaceField::New
+ (
+ coarseInterface,
+ interfaceFields[intI]
+ ).ptr()
+ );
+
+ // Since the type of clustering is now templated, clustering
+ // of block coefficients must be done by a FIELD (not interface)
+ // via a new set of virtual functions
+ // HJ, 16/Mar/2016
+
+ // Note: in the scalar AMG, clustering is done by the interface
+ // (always scalar) but in the block matrix it is done by a
+ // templated block interface field
+ // HJ, 16/Mar/2016
+
+ // Cast the interface into AMG type
+ const BlockAMGInterfaceField& coarseField =
+ refCast >
+ (
+ coarseInterfaceFieldsTransfer[intI]
+ );
+
+ coarseMatrix.coupleUpper().set
+ (
+ intI,
+ coarseField.agglomerateBlockCoeffs
+ (
+ matrix_.coupleUpper()[intI]
+ )
+ );
+
+ coarseMatrix.coupleLower().set
+ (
+ intI,
+ coarseField.agglomerateBlockCoeffs
+ (
+ matrix_.coupleLower()[intI]
+ )
+ );
+ }
+ }
+
+ // Matrix restriction done!
+
+ typedef CoeffField TypeCoeffField;
+
+ typedef typename TypeCoeffField::squareTypeField squareTypeField;
+ typedef typename TypeCoeffField::linearTypeField linearTypeField;
+ typedef typename TypeCoeffField::scalarTypeField scalarTypeField;
+
+ TypeCoeffField& coarseUpper = coarseMatrix.upper();
+ TypeCoeffField& coarseDiag = coarseMatrix.diag();
+ const TypeCoeffField& fineUpper = matrix_.upper();
+ const TypeCoeffField& fineDiag = matrix_.diag();
+
+ // KRJ: 2013-01-31: Many cases needed as there are different combinations
+
+ // Note:
+ // In coarsening, the off-diagonal coefficient type should be preserved
+ // and the case of taking out of off-diag from diag may need to be handled
+ // separately (expand the off-diag coeff to diag type before removing it
+ // from the diag coefficient). Since this has not been encountered yet
+ // only matching diag/off-diag types are handled.
+ // HJ, 15/Feb/2016
+ if (matrix_.symmetric())
+ {
+ if
+ (
+ fineDiag.activeType() == blockCoeffBase::SQUARE
+ || fineUpper.activeType() == blockCoeffBase::SQUARE
+ )
+ {
+ squareTypeField& activeCoarseDiag = coarseDiag.asSquare();
+
+ squareTypeField& activeCoarseUpper = coarseUpper.asSquare();
+ const squareTypeField& activeFineUpper = fineUpper.asSquare();
+
+ // Use lower as transpose of upper
+ squareTypeField activeFineUpperTranspose =
+ activeFineUpper.T();
+
+ restrictDiag(fineDiag, coarseDiag);
+
+ agglomerateCoeffs
+ (
+ coeffRestrictAddr,
+ activeCoarseDiag,
+ activeCoarseUpper,
+ activeFineUpper,
+ activeFineUpperTranspose
+ );
+ }
+ else if
+ (
+ fineDiag.activeType() == blockCoeffBase::LINEAR
+ || fineUpper.activeType() == blockCoeffBase::LINEAR
+ )
+ {
+ linearTypeField& activeCoarseDiag = coarseDiag.asLinear();
+
+ linearTypeField& activeCoarseUpper = coarseUpper.asLinear();
+ const linearTypeField& activeFineUpper = fineUpper.asLinear();
+
+ restrictDiag(fineDiag, coarseDiag);
+
+ agglomerateCoeffs
+ (
+ coeffRestrictAddr,
+ activeCoarseDiag,
+ activeCoarseUpper,
+ activeFineUpper,
+ activeFineUpper
+ );
+ }
+ else if
+ (
+ fineDiag.activeType() == blockCoeffBase::SCALAR
+ || fineUpper.activeType() == blockCoeffBase::SCALAR
+ )
+ {
+ scalarTypeField& activeCoarseDiag = coarseDiag.asScalar();
+
+ scalarTypeField& activeCoarseUpper = coarseUpper.asScalar();
+ const scalarTypeField& activeFineUpper = fineUpper.asScalar();
+
+ restrictDiag(fineDiag, coarseDiag);
+
+ agglomerateCoeffs
+ (
+ coeffRestrictAddr,
+ activeCoarseDiag,
+ activeCoarseUpper,
+ activeFineUpper,
+ activeFineUpper
+ );
+ }
+ else
+ {
+ FatalErrorIn
+ (
+ "autoPtr >"
+ "BlockMatrixReorderedClustering::restrictMatrix() const"
+ ) << "Matrix coeff type morphing error, symmetric matrix"
+ << abort(FatalError);
+ }
+ }
+ else // asymmetric matrix
+ {
+ TypeCoeffField& coarseLower = coarseMatrix.lower();
+ const TypeCoeffField& fineLower = matrix_.lower();
+
+ if
+ (
+ fineDiag.activeType() == blockCoeffBase::SQUARE
+ || fineUpper.activeType() == blockCoeffBase::SQUARE
+ )
+ {
+ squareTypeField& activeCoarseDiag = coarseDiag.asSquare();
+
+ squareTypeField& activeCoarseUpper = coarseUpper.asSquare();
+ const squareTypeField& activeFineUpper = fineUpper.asSquare();
+
+ squareTypeField& activeCoarseLower = coarseLower.asSquare();
+ const squareTypeField& activeFineLower = fineLower.asSquare();
+
+ restrictDiag(fineDiag, coarseDiag);
+
+ agglomerateCoeffs
+ (
+ coeffRestrictAddr,
+ activeCoarseDiag,
+ activeCoarseUpper,
+ activeFineUpper,
+ activeCoarseLower,
+ activeFineLower
+ );
+ }
+ else if
+ (
+ fineDiag.activeType() == blockCoeffBase::LINEAR
+ || fineUpper.activeType() == blockCoeffBase::LINEAR
+ )
+ {
+ linearTypeField& activeCoarseDiag = coarseDiag.asLinear();
+
+ linearTypeField& activeCoarseUpper = coarseUpper.asLinear();
+ const linearTypeField& activeFineUpper = fineUpper.asLinear();
+
+ linearTypeField& activeCoarseLower = coarseLower.asLinear();
+ const linearTypeField& activeFineLower = fineLower.asLinear();
+
+ restrictDiag(fineDiag, coarseDiag);
+
+ agglomerateCoeffs
+ (
+ coeffRestrictAddr,
+ activeCoarseDiag,
+ activeCoarseUpper,
+ activeFineUpper,
+ activeCoarseLower,
+ activeFineLower
+ );
+ }
+ else if
+ (
+ fineDiag.activeType() == blockCoeffBase::SCALAR
+ || fineUpper.activeType() == blockCoeffBase::SCALAR
+ )
+ {
+ scalarTypeField& activeCoarseDiag = coarseDiag.asScalar();
+
+ scalarTypeField& activeCoarseUpper = coarseUpper.asScalar();
+ const scalarTypeField& activeFineUpper = fineUpper.asScalar();
+
+ scalarTypeField& activeCoarseLower = coarseLower.asScalar();
+ const scalarTypeField& activeFineLower = fineLower.asScalar();
+
+ restrictDiag(fineDiag, coarseDiag);
+
+ agglomerateCoeffs
+ (
+ coeffRestrictAddr,
+ activeCoarseDiag,
+ activeCoarseUpper,
+ activeFineUpper,
+ activeCoarseLower,
+ activeFineLower
+ );
+ }
+ else
+ {
+ FatalErrorIn
+ (
+ "autoPtr >"
+ "BlockMatrixReorderedClustering::restrictMatrix() const"
+ ) << "Matrix coeff type morphing error, asymmetric matrix"
+ << abort(FatalError);
+ }
+ }
+
+ // Create and return BlockAMGLevel
+ return autoPtr >
+ (
+ new coarseBlockAMGLevel
+ (
+ coarseAddrPtr,
+ coarseMatrixPtr,
+ this->dict(),
+ this->type(),
+ this->groupSize(),
+ this->minCoarseEqns()
+ )
+ );
+}
+
+
+template
+void Foam::BlockMatrixReorderedClustering::restrictResidual
+(
+ const Field& res,
+ Field& coarseRes
+) const
+{
+ coarseRes = pTraits::zero;
+
+ forAll (res, i)
+ {
+ coarseRes[agglomIndex_[i]] += res[i];
+ }
+}
+
+
+template
+void Foam::BlockMatrixReorderedClustering::prolongateCorrection
+(
+ Field& x,
+ const Field& coarseX
+) const
+{
+ forAll (x, i)
+ {
+ x[i] += coarseX[agglomIndex_[i]];
+ }
+}
+
+
+// ************************************************************************* //
diff --git a/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/BlockMatrixReorderedClustering.H b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/BlockMatrixReorderedClustering.H
new file mode 100644
index 000000000..4b3058a39
--- /dev/null
+++ b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/BlockMatrixReorderedClustering.H
@@ -0,0 +1,217 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | foam-extend: Open Source CFD
+ \\ / O peration | Version: 4.0
+ \\ / A nd | Web: http://www.foam-extend.org
+ \\/ M anipulation | For copyright notice see file Copyright
+-------------------------------------------------------------------------------
+License
+ This file is part of foam-extend.
+
+ foam-extend 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.
+
+ foam-extend 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 foam-extend. If not, see .
+
+Class
+ BlockMatrixReorderedClustering
+
+Description
+ Block matrix AMG coarsening by Jasak clustering algorithm
+
+Author
+ Hrvoje Jasak, Wikki Ltd. All rights reserved.
+
+SourceFiles
+ BlockMatrixReorderedClustering.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef BlockMatrixReorderedClustering_H
+#define BlockMatrixReorderedClustering_H
+
+#include "BlockMatrixCoarsening.H"
+#include "BlockLduMatrix.H"
+#include "BlockCoeffNorm.H"
+#include "BlockCoeff.H"
+#include "tolerancesSwitch.H"
+#include "cpuTime.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+/*---------------------------------------------------------------------------*\
+ Class BlockMatrixReorderedClustering Declaration
+\*---------------------------------------------------------------------------*/
+
+template
+class BlockMatrixReorderedClustering
+:
+ public BlockMatrixCoarsening
+{
+ // Private Data
+
+ //- Reference to matrix
+ const BlockLduMatrix& matrix_;
+
+ //- Min group size
+ const label minGroupSize_;
+
+ //- Max group size
+ const label maxGroupSize_;
+
+ //- Reference to a templated norm calculator
+ autoPtr > normPtr_;
+
+ //- Child array: for each fine equation give a clustering index
+ labelField agglomIndex_;
+
+ //- Group size
+ label groupSize_;
+
+ //- Number of solo cells
+ label nSolo_;
+
+ //- Number of coarse equations
+ label nCoarseEqns_;
+
+ //- Can a coarse level be constructed?
+ bool coarsen_;
+
+ cpuTime lTime_;
+
+
+ // Private Member Functions
+
+ //- Disallow default bitwise copy construct
+ BlockMatrixReorderedClustering(const BlockMatrixReorderedClustering&);
+
+ // Disallow default bitwise assignment
+ void operator=(const BlockMatrixReorderedClustering&);
+
+
+ //- Calculate clustering index (child)
+ void calcClustering();
+
+ //- Restrict CoeffField. Used for diag coefficient
+ void restrictDiag
+ (
+ const CoeffField& Coeff,
+ CoeffField& coarseCoeff
+ ) const;
+
+ //- Agglomerate coeffs, symmetric matrix
+ template
+ void agglomerateCoeffs
+ (
+ const labelList& coeffRestrictAddr,
+ Field& activeCoarseDiag,
+ Field& activeCoarseUpper,
+ const Field& activeFineUpper,
+ const Field& activeFineUpperTranspose
+ ) const;
+
+ //- Agglomerate coeffs, assymmetric matrix
+ template
+ void agglomerateCoeffs
+ (
+ const labelList& coeffRestrictAddr,
+ Field& activeCoarseDiag,
+ Field& activeCoarseUpper,
+ const Field& activeFineUpper,
+ Field& activeCoarseLower,
+ const Field& activeFineLower
+ ) const;
+
+ //- Restrict CoeffField, decoupled version. Used for diag coefficient
+ void restrictDiagDecoupled
+ (
+ const CoeffField& Coeff,
+ CoeffField& coarseCoeff
+ ) const;
+
+ // Private Static Data
+
+ //- Weighting factor
+ static const debug::tolerancesSwitch weightFactor_;
+
+ //- Diagonal scaling factor
+ static const debug::tolerancesSwitch diagFactor_;
+
+
+public:
+
+ //- Runtime type information
+ TypeName("reorderedCluster");
+
+
+ // Constructors
+
+ //- Construct from matrix and group size
+ BlockMatrixReorderedClustering
+ (
+ const BlockLduMatrix& matrix,
+ const dictionary& dict,
+ const label groupSize,
+ const label minCoarseEqns
+ );
+
+
+ //- Destructor
+ virtual ~BlockMatrixReorderedClustering();
+
+
+ // Member Functions
+
+ //- Can a coarse level be constructed?
+ virtual bool coarsen() const
+ {
+ return coarsen_;
+ }
+
+ //- Restrict matrix
+ virtual autoPtr > restrictMatrix() const;
+
+ //- Restrict residual
+ virtual void restrictResidual
+ (
+ const Field& res,
+ Field& coarseRes
+ ) const;
+
+ //- Prolongate correction
+ virtual void prolongateCorrection
+ (
+ Field& x,
+ const Field& coarseX
+ ) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+# include "BlockMatrixReorderedClustering.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/blockMatrixReorderedClusterings.C b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/blockMatrixReorderedClusterings.C
new file mode 100644
index 000000000..55f7ab0f6
--- /dev/null
+++ b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/blockMatrixReorderedClusterings.C
@@ -0,0 +1,43 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | foam-extend: Open Source CFD
+ \\ / O peration | Version: 4.0
+ \\ / A nd | Web: http://www.foam-extend.org
+ \\/ M anipulation | For copyright notice see file Copyright
+-------------------------------------------------------------------------------
+License
+ This file is part of foam-extend.
+
+ foam-extend 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.
+
+ foam-extend 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 foam-extend. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+#include "blockMatrixReorderedClusterings.H"
+#include "blockMatrixCoarsenings.H"
+#include "coarseBlockAMGLevel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+makeBlockMatrixCoarsenings(blockMatrixReorderedClustering);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/blockMatrixReorderedClusterings.H b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/blockMatrixReorderedClusterings.H
new file mode 100644
index 000000000..3bdf7054a
--- /dev/null
+++ b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/blockMatrixReorderedClusterings.H
@@ -0,0 +1,65 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | foam-extend: Open Source CFD
+ \\ / O peration | Version: 4.0
+ \\ / A nd | Web: http://www.foam-extend.org
+ \\/ M anipulation | For copyright notice see file Copyright
+-------------------------------------------------------------------------------
+License
+ This file is part of foam-extend.
+
+ foam-extend 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.
+
+ foam-extend 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 foam-extend. If not, see .
+
+Class
+ BlockMatrixReorderedClustering
+
+Description
+ Typedefs for block matrix AMG coarsening by Jasak clustering algorithm.
+
+Author
+ Hrvoje Jasak, Wikki Ltd. All rights reserved.
+
+SourceFiles
+ blockMatrixReorderedClustering.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef blockMatrixReorderedClusterings_H
+#define blockMatrixReorderedClusterings_H
+
+#include "scalarBlockMatrixReorderedClustering.H"
+#include "tensorBlockMatrixReorderedClustering.H"
+#include "BlockMatrixReorderedClustering.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+typedef BlockMatrixReorderedClustering blockMatrixReorderedClusteringScalar;
+typedef BlockMatrixReorderedClustering blockMatrixReorderedClusteringVector;
+typedef BlockMatrixReorderedClustering blockMatrixReorderedClusteringTensor;
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/scalarBlockMatrixReorderedClustering.H b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/scalarBlockMatrixReorderedClustering.H
new file mode 100644
index 000000000..84b313a5f
--- /dev/null
+++ b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/scalarBlockMatrixReorderedClustering.H
@@ -0,0 +1,86 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | foam-extend: Open Source CFD
+ \\ / O peration | Version: 4.0
+ \\ / A nd | Web: http://www.foam-extend.org
+ \\/ M anipulation | For copyright notice see file Copyright
+-------------------------------------------------------------------------------
+License
+ This file is part of foam-extend.
+
+ foam-extend 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.
+
+ foam-extend 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 foam-extend. If not, see .
+
+Class
+ BlockMatrixReorderedClustering
+
+Description
+ Specialisation of the BlockMatrixReorderedClustering for scalars.
+
+Author
+ Klas Jareteg, 2013-01-31
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef scalarBlockMatrixReorderedClustering_H
+#define scalarBlockMatrixReorderedClustering_H
+
+#include "blockMatrixCoarsenings.H"
+#include "blockMatrixReorderedClusterings.H"
+#include "BlockMatrixReorderedClustering.H"
+#include "BlockMatrixCoarsening.H"
+#include "runTimeSelectionTables.H"
+#include "scalarBlockLduMatrix.H"
+#include "scalarBlockConstraint.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * Forward declaration of template friend fuctions * * * * * * * //
+
+
+/*---------------------------------------------------------------------------*\
+ Class BlockMatrixReorderedClustering Declaration
+\*---------------------------------------------------------------------------*/
+
+// Disable restrict matrix: no square type
+template<>
+inline autoPtr >
+BlockMatrixReorderedClustering::restrictMatrix() const
+{
+ FatalErrorIn
+ (
+ "autoPtr > "
+ "BlockMatrixReorderedClustering::restrictMatrix() const"
+ ) << "Function not implemented for Type=scalar. " << endl
+ << abort(FatalError);
+
+ // Dummy return to keep compiler happy
+ return autoPtr >(NULL);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/tensorBlockMatrixReorderedClustering.H b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/tensorBlockMatrixReorderedClustering.H
new file mode 100644
index 000000000..53894cb22
--- /dev/null
+++ b/src/foam/matrices/blockLduMatrix/BlockAMG/BlockMatrixCoarsening/BlockMatrixReorderedClustering/tensorBlockMatrixReorderedClustering.H
@@ -0,0 +1,83 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | foam-extend: Open Source CFD
+ \\ / O peration | Version: 4.0
+ \\ / A nd | Web: http://www.foam-extend.org
+ \\/ M anipulation | For copyright notice see file Copyright
+-------------------------------------------------------------------------------
+License
+ This file is part of foam-extend.
+
+ foam-extend 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.
+
+ foam-extend 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 foam-extend. If not, see .
+
+Class
+ BlockMatrixReorderedClustering
+
+Description
+ Specialisation of the BlockMatrixReorderedClustering for tensors.
+
+Author
+ Klas Jareteg, 2013-01-31
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef tensorBlockMatrixReorderedClustering_H
+#define tensorBlockMatrixReorderedClustering_H
+
+#include "blockMatrixCoarsenings.H"
+#include "blockMatrixReorderedClusterings.H"
+#include "BlockMatrixReorderedClustering.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+ Class BlockMatrixReorderedClustering Declaration
+\*---------------------------------------------------------------------------*/
+
+// Disable restrict matrix: no square type
+template<>
+inline autoPtr >
+BlockMatrixReorderedClustering::restrictMatrix
+() const
+{
+ FatalErrorIn
+ (
+ "autoPtr > "
+ "BlockMatrixReorderedClustering::"
+ "restrictMatrix() const"
+ ) << "Function not implemented for Type=tensor. " << endl
+ << abort(FatalError);
+
+ // Dummy return to keep compiler happy
+ return autoPtr >(NULL);
+}
+
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //