1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
5 \\ / A nd | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
28 Agglomerative AMG policy, adjusted for BlockLduMatrix
31 Klas Jareteg, 2012-12-13
33 \*---------------------------------------------------------------------------*/
35 #include "BlockAamgPolicy.H"
36 #include "coeffFields.H"
37 #include "addToRunTimeSelectionTable.H"
38 #include "BlockGAMGInterfaceField.H"
39 #include "processorLduInterfaceField.H"
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 const Foam::scalar Foam::BlockAamgPolicy<Type>::weightFactor_ = 0.65;
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
50 void Foam::BlockAamgPolicy<Type>::calcChild()
53 // 1) Create temporary equation addressing using a double-pass algorithm.
54 // to create the offset table.
55 // 2) Loop through all equations and for each equation find the best fit
56 // neighbour. If all neighbours are grouped, add equation to best group
58 // Create row-based addressing
60 const label nRows = matrix_.lduAddr().size();
62 const unallocLabelList& upperAddr = matrix_.lduAddr().upperAddr();
63 const unallocLabelList& lowerAddr = matrix_.lduAddr().lowerAddr();
65 // For each equation get number of coefficients in a row
66 labelList cols(upperAddr.size() + lowerAddr.size());
67 labelList cIndex(upperAddr.size() + lowerAddr.size());
68 labelList rowOffset(nRows + 1, 0);
70 // Count the number of coefficients
71 forAll (upperAddr, coeffI)
73 rowOffset[upperAddr[coeffI]]++;
76 forAll (lowerAddr, coeffI)
78 rowOffset[lowerAddr[coeffI]]++;
83 forAll (rowOffset, eqnI)
85 nCoeffs += rowOffset[eqnI];
88 rowOffset[nRows] = nCoeffs;
90 for (label eqnI = nRows - 1; eqnI >= 0; --eqnI)
92 rowOffset[eqnI] = rowOffset[eqnI + 1] - rowOffset[eqnI];
97 // Create column and coefficient index array
99 // Use child array to count number of entries per row.
100 // Reset the list for counting
101 labelList& nPerRow = child_;
104 forAll (upperAddr, coeffI)
106 cols[rowOffset[upperAddr[coeffI]] + nPerRow[upperAddr[coeffI]]] =
109 cIndex[rowOffset[upperAddr[coeffI]] + nPerRow[upperAddr[coeffI]]] =
112 nPerRow[upperAddr[coeffI]]++;
115 forAll (lowerAddr, coeffI)
117 cols[rowOffset[lowerAddr[coeffI]] + nPerRow[lowerAddr[coeffI]]] =
120 cIndex[rowOffset[lowerAddr[coeffI]] + nPerRow[lowerAddr[coeffI]]] =
123 nPerRow[lowerAddr[coeffI]]++;
131 // Calculate agglomeration
133 // Get matrix coefficients
134 const CoeffField<Type>& diag = matrix_.diag();
135 const CoeffField<Type>& upper = matrix_.upper();
137 labelList sizeOfGroups(nRows, 0);
141 label indexU, indexG, colI, curEqn, nextEqn, groupPassI;
143 scalar magRowDiag, magColDiag, weight, weightU, weightG;
145 // Magnitudes pre-calculated
146 Field<scalar> magDiag(diag.size());
147 Field<scalar> magUpper(upper.size());
149 normPtr_->coeffMag(diag,magDiag);
150 normPtr_->coeffMag(upper,magUpper);
152 for (label eqnI = 0; eqnI < nRows; eqnI++)
154 if (child_[eqnI] == -1)
161 child_[curEqn] = nCoarseEqns_;
163 magRowDiag = magDiag[curEqn];
165 for (groupPassI = 1; groupPassI < groupSize_; groupPassI++)
175 label rowCoeffI = rowOffset[curEqn];
176 rowCoeffI < rowOffset[curEqn + 1];
180 colI = cols[rowCoeffI];
182 magColDiag = magDiag[colI];
184 weight = (magUpper[cIndex[rowCoeffI]]
185 / max(magRowDiag, magColDiag));
187 if (child_[colI] == -1)
189 if (indexU == -1 || weight > weightU)
195 else if (child_[curEqn] != child_[colI])
197 if (indexG == -1 || weight > weightG)
208 && (indexG == -1 || weightU >= weightFactor_*weightG)
211 // Found new element of group. Add it and use as
212 // start of next search
214 nextEqn = cols[indexU];
216 child_[nextEqn] = child_[curEqn];
217 sizeOfGroups[child_[curEqn]];
223 // Group full or cannot be extended
232 || sizeOfGroups[child_[cols[indexG]]] > (groupSize_ + 2)
235 sizeOfGroups[child_[eqnI]]++;
240 child_[eqnI] = child_[cols[indexG]];
241 sizeOfGroups[child_[cols[indexG]]]++;
246 // The decision on parallel agglomeration needs to be made for the
247 // whole gang of processes; otherwise I may end up with a different
248 // number of agglomeration levels on different processors.
252 nCoarseEqns_ > BlockAmgPolicy<Type>::minCoarseEqns()
253 && 3*nCoarseEqns_ <= 2*nRows
259 reduce(coarsen_, andOp<bool>());
264 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
267 Foam::BlockAamgPolicy<Type>::BlockAamgPolicy
269 const BlockLduMatrix<Type>& matrix,
270 const dictionary& dict,
271 const label groupSize,
272 const label minCoarseEqns
275 BlockAmgPolicy<Type>(matrix, dict, groupSize, minCoarseEqns),
279 BlockCoeffNorm<Type>::New
284 child_(matrix_.lduAddr().size()),
285 groupSize_(groupSize),
292 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
295 Foam::BlockAamgPolicy<Type>::~BlockAamgPolicy()
299 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
302 Foam::autoPtr<Foam::BlockLduMatrix<Type> >
303 Foam::BlockAamgPolicy<Type>::restrictMatrix() const
309 "autoPtr<amgMatrix> BlockAamgPolicy<Type>::restrictMatrix() const"
310 ) << "Requesting coarse matrix when it cannot be created"
311 << abort(FatalError);
314 // Construct the coarse matrix and ldu addressing for the next level
316 // 1) Loop through all fine coeffs. If the child labels on two sides are
317 // different, this creates a coarse coeff. Define owner and neighbour
318 // for this coeff based on cluster IDs.
319 // 2) Check if the coeff has been seen before. If yes, add the coefficient
320 // to the appropriate field (stored with the equation). If no, create
321 // a new coeff with neighbour ID and add the coefficient
322 // 3) Once all the coeffs have been created, loop through all clusters and
323 // insert the coeffs in the upper order. At the same time, collect the
324 // owner and neighbour addressing.
325 // 4) Agglomerate the diagonal by summing up the fine diagonal
328 const unallocLabelList& upperAddr = matrix_.lduAddr().upperAddr();
329 const unallocLabelList& lowerAddr = matrix_.lduAddr().lowerAddr();
331 const label nFineCoeffs = upperAddr.size();
334 if (child_.size() != matrix_.lduAddr().size())
338 "autoPtr<BlockLduMatrix<Type> > BlockAamgPolicy<Type>::"
339 "restrictMatrix() const"
340 ) << "Child array does not correspond to fine level. " << endl
341 << " Child size: " << child_.size()
342 << " number of equations: " << matrix_.lduAddr().size()
343 << abort(FatalError);
348 // Storage for block neighbours and coefficients
350 // Guess initial maximum number of neighbours in block
353 // Number of neighbours per block
354 labelList blockNnbrs(nCoarseEqns_, 0);
356 // Setup initial packed storage for neighbours and coefficients
357 labelList blockNbrsData(maxNnbrs*nCoarseEqns_);
359 // Create face-restriction addressing
360 labelList coeffRestrictAddr(nFineCoeffs);
362 // Initial neighbour array (not in upper-triangle order)
363 labelList initCoarseNeighb(nFineCoeffs);
365 // Counter for coarse coeffs
366 label nCoarseCoeffs = 0;
368 // Loop through all fine coeffs
369 forAll (upperAddr, fineCoeffi)
371 label rmUpperAddr = child_[upperAddr[fineCoeffi]];
372 label rmLowerAddr = child_[lowerAddr[fineCoeffi]];
374 if (rmUpperAddr == rmLowerAddr)
376 // For each fine coeff inside of a coarse cluster keep the address
377 // of the cluster corresponding to the coeff in the
378 // coeffRestrictAddr as a negative index
379 coeffRestrictAddr[fineCoeffi] = -(rmUpperAddr + 1);
383 // This coeff is a part of a coarse coeff
385 label cOwn = rmUpperAddr;
386 label cNei = rmLowerAddr;
388 // Get coarse owner and neighbour
389 if (rmUpperAddr > rmLowerAddr)
395 // Check the neighbour to see if this coeff has already been found
396 bool nbrFound = false;
397 label& ccnCoeffs = blockNnbrs[cOwn];
399 for (int i = 0; i < ccnCoeffs; i++)
401 if (initCoarseNeighb[blockNbrsData[maxNnbrs*cOwn + i]] == cNei)
404 coeffRestrictAddr[fineCoeffi] =
405 blockNbrsData[maxNnbrs*cOwn + i];
412 if (ccnCoeffs >= maxNnbrs)
414 // Double the size of list and copy data
415 label oldMaxNnbrs = maxNnbrs;
418 // Resize and copy list
419 const labelList oldBlockNbrsData = blockNbrsData;
420 blockNbrsData.setSize(maxNnbrs*nCoarseEqns_);
422 forAll (blockNnbrs, i)
424 for (int j = 0; j < blockNnbrs[i]; j++)
426 blockNbrsData[maxNnbrs*i + j] =
427 oldBlockNbrsData[oldMaxNnbrs*i + j];
432 blockNbrsData[maxNnbrs*cOwn + ccnCoeffs] = nCoarseCoeffs;
433 initCoarseNeighb[nCoarseCoeffs] = cNei;
434 coeffRestrictAddr[fineCoeffi] = nCoarseCoeffs;
437 // New coarse coeff created
441 } // End for all fine coeffs
444 // Renumber into upper-triangular order
446 // All coarse owner-neighbour storage
447 labelList coarseOwner(nCoarseCoeffs);
448 labelList coarseNeighbour(nCoarseCoeffs);
449 labelList coarseCoeffMap(nCoarseCoeffs);
451 label coarseCoeffi = 0;
453 forAll (blockNnbrs, cci)
455 label* cCoeffs = &blockNbrsData[maxNnbrs*cci];
456 label ccnCoeffs = blockNnbrs[cci];
458 for (int i = 0; i < ccnCoeffs; i++)
460 coarseOwner[coarseCoeffi] = cci;
461 coarseNeighbour[coarseCoeffi] = initCoarseNeighb[cCoeffs[i]];
462 coarseCoeffMap[cCoeffs[i]] = coarseCoeffi;
467 forAll(coeffRestrictAddr, fineCoeffi)
469 if (coeffRestrictAddr[fineCoeffi] >= 0)
471 coeffRestrictAddr[fineCoeffi] =
472 coarseCoeffMap[coeffRestrictAddr[fineCoeffi]];
476 // Clear the temporary storage for the coarse matrix data
477 blockNnbrs.setSize(0);
478 blockNbrsData.setSize(0);
479 initCoarseNeighb.setSize(0);
480 coarseCoeffMap.setSize(0);
482 // Create coarse-level coupled interfaces
484 // Create coarse interfaces, addressing and coefficients
485 const label interfaceSize =
486 const_cast<BlockLduMatrix<Type>& >(matrix_).interfaces().size();
488 const typename BlockLduInterfaceFieldPtrsList<Type>::Type&
490 const_cast<BlockLduMatrix<Type>&>(matrix_).interfaces();
492 // Set the coarse interfaces and coefficients
493 lduInterfacePtrsList* coarseInterfacesPtr =
494 new lduInterfacePtrsList(interfaceSize);
495 lduInterfacePtrsList& coarseInterfaces = *coarseInterfacesPtr;
497 labelListList coarseInterfaceAddr(interfaceSize);
499 // Add the coarse level
501 // Set the coarse ldu addressing onto the list
502 lduPrimitiveMesh* coarseAddrPtr =
511 // Initialise transfer of restrict addressing on the interface
512 forAll (interfaceFields, intI)
514 if (interfaceFields.set(intI))
516 interfaceFields[intI].interface().initInternalFieldTransfer
524 // Store coefficients to avoid tangled communications
526 FieldField<Field, label> fineInterfaceAddr(interfaceFields.size());
528 forAll (interfaceFields, intI)
530 if (interfaceFields.set(intI))
532 const lduInterface& fineInterface =
533 interfaceFields[intI].interface();
535 fineInterfaceAddr.set
540 fineInterface.internalFieldTransfer
550 // Create GAMG interfaces
551 forAll (interfaceFields, intI)
553 if (interfaceFields.set(intI))
555 const lduInterface& fineInterface =
556 interfaceFields[intI].interface();
565 fineInterface.interfaceInternalField(child_),
566 fineInterfaceAddr[intI]
572 forAll (interfaceFields, intI)
574 if (interfaceFields.set(intI))
576 const GAMGInterface& coarseInterface =
577 refCast<const GAMGInterface>(coarseInterfaces[intI]);
579 coarseInterfaceAddr[intI] = coarseInterface.faceCells();
584 coarseAddrPtr->addInterfaces
586 *coarseInterfacesPtr,
588 matrix_.patchSchedule()
591 // Set the coarse level matrix
592 BlockLduMatrix<Type>* coarseMatrixPtr =
593 new BlockLduMatrix<Type>(*coarseAddrPtr);
594 BlockLduMatrix<Type>& coarseMatrix = *coarseMatrixPtr;
596 typename BlockLduInterfaceFieldPtrsList<Type>::Type&
597 coarseInterfaceFieldsTransfer =
598 coarseMatrix.interfaces();
600 // Aggolmerate the upper and lower coupled coefficients
601 forAll (interfaceFields, intI)
603 if (interfaceFields.set(intI))
605 const GAMGInterface& coarseInterface =
606 refCast<const GAMGInterface>(coarseInterfaces[intI]);
608 coarseInterfaceFieldsTransfer.set
611 BlockGAMGInterfaceField<Type>::New
614 (interfaceFields[intI])
618 coarseMatrix.coupleUpper().set
621 coarseInterface.agglomerateBlockCoeffs
623 matrix_.coupleUpper()[intI]
627 coarseMatrix.coupleLower().set
630 coarseInterface.agglomerateBlockCoeffs
632 matrix_.coupleLower()[intI]
638 // Matrix restriction done!
640 typedef CoeffField<Type> TypeCoeffField;
642 typedef typename TypeCoeffField::squareTypeField squareTypeField;
644 TypeCoeffField& coarseUpper = coarseMatrix.upper();
645 TypeCoeffField& coarseDiag = coarseMatrix.diag();
646 const TypeCoeffField& fineUpper = matrix_.upper();
647 const TypeCoeffField& fineDiag = matrix_.diag();
649 // KRJ: 2013-01-31: Many cases needed as there are different combinations
650 if (matrix_.asymmetric())
652 TypeCoeffField& coarseLower = coarseMatrix.lower();
653 const TypeCoeffField& fineLower = matrix_.lower();
655 if (fineDiag.activeType() == blockCoeffBase::SQUARE)
657 if (fineUpper.activeType() == blockCoeffBase::SQUARE)
659 squareTypeField& activeCoarseUpper = coarseUpper.asSquare();
660 squareTypeField& activeCoarseDiag = coarseDiag.asSquare();
661 const squareTypeField& activeFineUpper = fineUpper.asSquare();
663 squareTypeField& activeCoarseLower = coarseLower.asSquare();
664 const squareTypeField& activeFineLower = fineLower.asSquare();
666 restrictResidual(fineDiag, coarseDiag);
668 forAll(coeffRestrictAddr, fineCoeffI)
670 label cCoeff = coeffRestrictAddr[fineCoeffI];
674 activeCoarseUpper[cCoeff] += activeFineUpper[fineCoeffI];
675 activeCoarseLower[cCoeff] += activeFineLower[fineCoeffI];
679 // Add the fine face coefficients into the diagonal.
680 activeCoarseDiag[-1 - cCoeff] +=
681 activeFineUpper[fineCoeffI] + activeFineLower[fineCoeffI];
685 else if (fineUpper.activeType() == blockCoeffBase::LINEAR)
687 FatalErrorIn("autoPtr<amgMatrix> BlockAamgPolicy<Type>::restrictMatrix() const")
688 << "Matrix diagonal of square type and upper of linear type is not implemented"
689 << abort(FatalError);
693 FatalErrorIn("autoPtr<amgMatrix> BlockAamgPolicy<Type>::restrictMatrix() const")
694 << "Matrix diagonal of square type and upper of scalar type is not implemented"
695 << abort(FatalError);
698 else if (fineDiag.activeType() == blockCoeffBase::LINEAR)
700 FatalErrorIn("autoPtr<amgMatrix> BlockAamgPolicy<Type>::restrictMatrix() const")
701 << "Matrix diagonal of linear type not implemented"
702 << abort(FatalError);
706 FatalErrorIn("autoPtr<amgMatrix> BlockAamgPolicy<Type>::restrictMatrix() const")
707 << "Matrix diagonal of scalar type not implemented"
708 << abort(FatalError);
713 if (fineDiag.activeType() == blockCoeffBase::SQUARE)
715 if (fineUpper.activeType() == blockCoeffBase::SQUARE)
717 squareTypeField& activeCoarseUpper = coarseUpper.asSquare();
718 squareTypeField& activeCoarseDiag = coarseDiag.asSquare();
719 const squareTypeField& activeFineUpper = fineUpper.asSquare();
721 restrictResidual(fineDiag, coarseDiag);
723 forAll(coeffRestrictAddr, fineCoeffI)
725 label cCoeff = coeffRestrictAddr[fineCoeffI];
729 activeCoarseUpper[cCoeff] += activeFineUpper[fineCoeffI];
733 // Add the fine face coefficient into the diagonal.
734 activeCoarseDiag[-1 - cCoeff] += 2*activeFineUpper[fineCoeffI];
738 else if (fineUpper.activeType() == blockCoeffBase::LINEAR)
740 FatalErrorIn("autoPtr<amgMatrix> BlockAamgPolicy<Type>::restrictMatrix() const")
741 << "Matrix diagonal of square type and upper of linear type is not implemented"
742 << abort(FatalError);
746 FatalErrorIn("autoPtr<amgMatrix> BlockAamgPolicy<Type>::restrictMatrix() const")
747 << "Matrix diagonal of square type and upper of scalar type is not implemented"
748 << abort(FatalError);
752 else if (fineDiag.activeType() == blockCoeffBase::LINEAR)
756 "autoPtr<amgMatrix> BlockAamgPolicy<Type>::"
757 "restrictMatrix() const"
758 ) << "Matrix diagonal of linear type not implemented"
759 << abort(FatalError);
765 "autoPtr<amgMatrix> BlockAamgPolicy<Type>::"
766 "restrictMatrix() const"
767 ) << "Matrix diagonal of scalar type not implemented"
768 << abort(FatalError);
772 return autoPtr<BlockLduMatrix<Type> >
774 new BlockLduMatrix<Type>
783 void Foam::BlockAamgPolicy<Type>::restrictResidual
785 const CoeffField<Type>& res,
786 CoeffField<Type>& coarseRes
789 typedef CoeffField<Type> TypeCoeffField;
791 if (res.activeType() == blockCoeffBase::SQUARE &&
792 coarseRes.activeType() == blockCoeffBase::SQUARE)
794 typedef typename TypeCoeffField::squareTypeField squareTypeField;
796 squareTypeField& activeCoarseRes = coarseRes.asSquare();
797 const squareTypeField& activeRes = res.asSquare();
799 // KRJ: 2013-02-05: To be done by correct pTraits?
800 forAll (coarseRes, i)
802 activeCoarseRes[i] *= 0.0;
807 activeCoarseRes[child_[i]] += activeRes[i];
812 FatalErrorIn("void BlockAamgPolicy<Type>::restrictResidual() const")
813 << "Only present for square type coeff type"
814 << abort(FatalError);
820 void Foam::BlockAamgPolicy<Type>::restrictResidual
822 const Field<Type>& res,
823 Field<Type>& coarseRes
826 coarseRes = pTraits<Type>::zero;
830 coarseRes[child_[i]] += res[i];
836 void Foam::BlockAamgPolicy<Type>::prolongateCorrection
839 const Field<Type>& coarseX
844 x[i] += coarseX[child_[i]];
849 // ************************************************************************* //