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/>.
25 BlockMatrixAgglomeration
28 Agglomerative block matrix AMG corsening, adjusted for BlockLduMatrix
31 Klas Jareteg, 2012-12-13
33 \*---------------------------------------------------------------------------*/
35 #include "BlockMatrixAgglomeration.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::BlockMatrixAgglomeration<Type>::weightFactor_ = 0.65;
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
50 void Foam::BlockMatrixAgglomeration<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_ > BlockMatrixCoarsening<Type>::minCoarseEqns()
253 && 3*nCoarseEqns_ <= 2*nRows
259 reduce(coarsen_, andOp<bool>());
264 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
267 Foam::BlockMatrixAgglomeration<Type>::BlockMatrixAgglomeration
269 const BlockLduMatrix<Type>& matrix,
270 const dictionary& dict,
271 const label groupSize,
272 const label minCoarseEqns
275 BlockMatrixCoarsening<Type>(matrix, dict, groupSize, minCoarseEqns),
279 BlockCoeffNorm<Type>::New
284 child_(matrix_.lduAddr().size()),
285 groupSize_(groupSize),
292 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
295 Foam::BlockMatrixAgglomeration<Type>::~BlockMatrixAgglomeration()
299 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
302 Foam::autoPtr<Foam::BlockLduMatrix<Type> >
303 Foam::BlockMatrixAgglomeration<Type>::restrictMatrix() const
309 "autoPtr<amgMatrix> "
310 "BlockMatrixAgglomeration<Type>::restrictMatrix() const"
311 ) << "Requesting coarse matrix when it cannot be created"
312 << abort(FatalError);
315 // Construct the coarse matrix and ldu addressing for the next level
317 // 1) Loop through all fine coeffs. If the child labels on two sides are
318 // different, this creates a coarse coeff. Define owner and neighbour
319 // for this coeff based on cluster IDs.
320 // 2) Check if the coeff has been seen before. If yes, add the coefficient
321 // to the appropriate field (stored with the equation). If no, create
322 // a new coeff with neighbour ID and add the coefficient
323 // 3) Once all the coeffs have been created, loop through all clusters and
324 // insert the coeffs in the upper order. At the same time, collect the
325 // owner and neighbour addressing.
326 // 4) Agglomerate the diagonal by summing up the fine diagonal
329 const unallocLabelList& upperAddr = matrix_.lduAddr().upperAddr();
330 const unallocLabelList& lowerAddr = matrix_.lduAddr().lowerAddr();
332 const label nFineCoeffs = upperAddr.size();
335 if (child_.size() != matrix_.lduAddr().size())
339 "autoPtr<BlockLduMatrix<Type> > BlockMatrixAgglomeration<Type>::"
340 "restrictMatrix() const"
341 ) << "Child array does not correspond to fine level. " << endl
342 << " Child size: " << child_.size()
343 << " number of equations: " << matrix_.lduAddr().size()
344 << abort(FatalError);
349 // Storage for block neighbours and coefficients
351 // Guess initial maximum number of neighbours in block
354 // Number of neighbours per block
355 labelList blockNnbrs(nCoarseEqns_, 0);
357 // Setup initial packed storage for neighbours and coefficients
358 labelList blockNbrsData(maxNnbrs*nCoarseEqns_);
360 // Create face-restriction addressing
361 labelList coeffRestrictAddr(nFineCoeffs);
363 // Initial neighbour array (not in upper-triangle order)
364 labelList initCoarseNeighb(nFineCoeffs);
366 // Counter for coarse coeffs
367 label nCoarseCoeffs = 0;
369 // Loop through all fine coeffs
370 forAll (upperAddr, fineCoeffi)
372 label rmUpperAddr = child_[upperAddr[fineCoeffi]];
373 label rmLowerAddr = child_[lowerAddr[fineCoeffi]];
375 if (rmUpperAddr == rmLowerAddr)
377 // For each fine coeff inside of a coarse cluster keep the address
378 // of the cluster corresponding to the coeff in the
379 // coeffRestrictAddr as a negative index
380 coeffRestrictAddr[fineCoeffi] = -(rmUpperAddr + 1);
384 // This coeff is a part of a coarse coeff
386 label cOwn = rmUpperAddr;
387 label cNei = rmLowerAddr;
389 // Get coarse owner and neighbour
390 if (rmUpperAddr > rmLowerAddr)
396 // Check the neighbour to see if this coeff has already been found
397 bool nbrFound = false;
398 label& ccnCoeffs = blockNnbrs[cOwn];
400 for (int i = 0; i < ccnCoeffs; i++)
402 if (initCoarseNeighb[blockNbrsData[maxNnbrs*cOwn + i]] == cNei)
405 coeffRestrictAddr[fineCoeffi] =
406 blockNbrsData[maxNnbrs*cOwn + i];
413 if (ccnCoeffs >= maxNnbrs)
415 // Double the size of list and copy data
416 label oldMaxNnbrs = maxNnbrs;
419 // Resize and copy list
420 const labelList oldBlockNbrsData = blockNbrsData;
421 blockNbrsData.setSize(maxNnbrs*nCoarseEqns_);
423 forAll (blockNnbrs, i)
425 for (int j = 0; j < blockNnbrs[i]; j++)
427 blockNbrsData[maxNnbrs*i + j] =
428 oldBlockNbrsData[oldMaxNnbrs*i + j];
433 blockNbrsData[maxNnbrs*cOwn + ccnCoeffs] = nCoarseCoeffs;
434 initCoarseNeighb[nCoarseCoeffs] = cNei;
435 coeffRestrictAddr[fineCoeffi] = nCoarseCoeffs;
438 // New coarse coeff created
442 } // End for all fine coeffs
445 // Renumber into upper-triangular order
447 // All coarse owner-neighbour storage
448 labelList coarseOwner(nCoarseCoeffs);
449 labelList coarseNeighbour(nCoarseCoeffs);
450 labelList coarseCoeffMap(nCoarseCoeffs);
452 label coarseCoeffi = 0;
454 forAll (blockNnbrs, cci)
456 label* cCoeffs = &blockNbrsData[maxNnbrs*cci];
457 label ccnCoeffs = blockNnbrs[cci];
459 for (int i = 0; i < ccnCoeffs; i++)
461 coarseOwner[coarseCoeffi] = cci;
462 coarseNeighbour[coarseCoeffi] = initCoarseNeighb[cCoeffs[i]];
463 coarseCoeffMap[cCoeffs[i]] = coarseCoeffi;
468 forAll(coeffRestrictAddr, fineCoeffi)
470 if (coeffRestrictAddr[fineCoeffi] >= 0)
472 coeffRestrictAddr[fineCoeffi] =
473 coarseCoeffMap[coeffRestrictAddr[fineCoeffi]];
477 // Clear the temporary storage for the coarse matrix data
478 blockNnbrs.setSize(0);
479 blockNbrsData.setSize(0);
480 initCoarseNeighb.setSize(0);
481 coarseCoeffMap.setSize(0);
483 // Create coarse-level coupled interfaces
485 // Create coarse interfaces, addressing and coefficients
486 const label interfaceSize =
487 const_cast<BlockLduMatrix<Type>& >(matrix_).interfaces().size();
489 const typename BlockLduInterfaceFieldPtrsList<Type>::Type&
491 const_cast<BlockLduMatrix<Type>&>(matrix_).interfaces();
493 // Set the coarse interfaces and coefficients
494 lduInterfacePtrsList* coarseInterfacesPtr =
495 new lduInterfacePtrsList(interfaceSize);
496 lduInterfacePtrsList& coarseInterfaces = *coarseInterfacesPtr;
498 labelListList coarseInterfaceAddr(interfaceSize);
500 // Add the coarse level
502 // Set the coarse ldu addressing onto the list
503 lduPrimitiveMesh* coarseAddrPtr =
512 // Initialise transfer of restrict addressing on the interface
513 forAll (interfaceFields, intI)
515 if (interfaceFields.set(intI))
517 interfaceFields[intI].interface().initInternalFieldTransfer
525 // Store coefficients to avoid tangled communications
527 FieldField<Field, label> fineInterfaceAddr(interfaceFields.size());
529 forAll (interfaceFields, intI)
531 if (interfaceFields.set(intI))
533 const lduInterface& fineInterface =
534 interfaceFields[intI].interface();
536 fineInterfaceAddr.set
541 fineInterface.internalFieldTransfer
551 // Create GAMG interfaces
552 forAll (interfaceFields, intI)
554 if (interfaceFields.set(intI))
556 const lduInterface& fineInterface =
557 interfaceFields[intI].interface();
566 fineInterface.interfaceInternalField(child_),
567 fineInterfaceAddr[intI]
573 forAll (interfaceFields, intI)
575 if (interfaceFields.set(intI))
577 const GAMGInterface& coarseInterface =
578 refCast<const GAMGInterface>(coarseInterfaces[intI]);
580 coarseInterfaceAddr[intI] = coarseInterface.faceCells();
585 coarseAddrPtr->addInterfaces
587 *coarseInterfacesPtr,
589 matrix_.patchSchedule()
592 // Set the coarse level matrix
593 BlockLduMatrix<Type>* coarseMatrixPtr =
594 new BlockLduMatrix<Type>(*coarseAddrPtr);
595 BlockLduMatrix<Type>& coarseMatrix = *coarseMatrixPtr;
597 typename BlockLduInterfaceFieldPtrsList<Type>::Type&
598 coarseInterfaceFieldsTransfer =
599 coarseMatrix.interfaces();
601 // Aggolmerate the upper and lower coupled coefficients
602 forAll (interfaceFields, intI)
604 if (interfaceFields.set(intI))
606 const GAMGInterface& coarseInterface =
607 refCast<const GAMGInterface>(coarseInterfaces[intI]);
609 coarseInterfaceFieldsTransfer.set
612 BlockGAMGInterfaceField<Type>::New
615 (interfaceFields[intI])
619 coarseMatrix.coupleUpper().set
622 coarseInterface.agglomerateBlockCoeffs
624 matrix_.coupleUpper()[intI]
628 coarseMatrix.coupleLower().set
631 coarseInterface.agglomerateBlockCoeffs
633 matrix_.coupleLower()[intI]
639 // Matrix restriction done!
641 typedef CoeffField<Type> TypeCoeffField;
643 typedef typename TypeCoeffField::squareTypeField squareTypeField;
645 TypeCoeffField& coarseUpper = coarseMatrix.upper();
646 TypeCoeffField& coarseDiag = coarseMatrix.diag();
647 const TypeCoeffField& fineUpper = matrix_.upper();
648 const TypeCoeffField& fineDiag = matrix_.diag();
650 // KRJ: 2013-01-31: Many cases needed as there are different combinations
651 if (matrix_.asymmetric())
653 TypeCoeffField& coarseLower = coarseMatrix.lower();
654 const TypeCoeffField& fineLower = matrix_.lower();
656 if (fineDiag.activeType() == blockCoeffBase::SQUARE)
658 if (fineUpper.activeType() == blockCoeffBase::SQUARE)
660 squareTypeField& activeCoarseUpper = coarseUpper.asSquare();
661 squareTypeField& activeCoarseDiag = coarseDiag.asSquare();
662 const squareTypeField& activeFineUpper = fineUpper.asSquare();
664 squareTypeField& activeCoarseLower = coarseLower.asSquare();
665 const squareTypeField& activeFineLower = fineLower.asSquare();
667 restrictResidual(fineDiag, coarseDiag);
669 forAll(coeffRestrictAddr, fineCoeffI)
671 label cCoeff = coeffRestrictAddr[fineCoeffI];
675 activeCoarseUpper[cCoeff]
676 += activeFineUpper[fineCoeffI];
677 activeCoarseLower[cCoeff]
678 += activeFineLower[fineCoeffI];
682 // Add the fine face coefficients into the diagonal.
683 activeCoarseDiag[-1 - cCoeff] +=
684 activeFineUpper[fineCoeffI]
685 + activeFineLower[fineCoeffI];
689 else if (fineUpper.activeType() == blockCoeffBase::LINEAR)
691 FatalErrorIn("autoPtr<amgMatrix> BlockMatrixAgglomeration<Type>::restrictMatrix() const")
692 << "Matrix diagonal of square type and upper of linear type is not implemented"
693 << abort(FatalError);
697 FatalErrorIn("autoPtr<amgMatrix> BlockMatrixAgglomeration<Type>::restrictMatrix() const")
698 << "Matrix diagonal of square type and upper of scalar type is not implemented"
699 << abort(FatalError);
702 else if (fineDiag.activeType() == blockCoeffBase::LINEAR)
704 FatalErrorIn("autoPtr<amgMatrix> BlockMatrixAgglomeration<Type>::restrictMatrix() const")
705 << "Matrix diagonal of linear type not implemented"
706 << abort(FatalError);
710 FatalErrorIn("autoPtr<amgMatrix> BlockMatrixAgglomeration<Type>::restrictMatrix() const")
711 << "Matrix diagonal of scalar type not implemented"
712 << abort(FatalError);
717 if (fineDiag.activeType() == blockCoeffBase::SQUARE)
719 if (fineUpper.activeType() == blockCoeffBase::SQUARE)
721 squareTypeField& activeCoarseUpper = coarseUpper.asSquare();
722 squareTypeField& activeCoarseDiag = coarseDiag.asSquare();
723 const squareTypeField& activeFineUpper = fineUpper.asSquare();
725 restrictResidual(fineDiag, coarseDiag);
727 forAll(coeffRestrictAddr, fineCoeffI)
729 label cCoeff = coeffRestrictAddr[fineCoeffI];
733 activeCoarseUpper[cCoeff]
734 += activeFineUpper[fineCoeffI];
738 // Add the fine face coefficient into the diagonal.
739 activeCoarseDiag[-1 - cCoeff]
740 += 2*activeFineUpper[fineCoeffI];
744 else if (fineUpper.activeType() == blockCoeffBase::LINEAR)
746 FatalErrorIn("autoPtr<amgMatrix> BlockMatrixAgglomeration<Type>::restrictMatrix() const")
747 << "Matrix diagonal of square type and upper of linear type is not implemented"
748 << abort(FatalError);
752 FatalErrorIn("autoPtr<amgMatrix> BlockMatrixAgglomeration<Type>::restrictMatrix() const")
753 << "Matrix diagonal of square type and upper of scalar type is not implemented"
754 << abort(FatalError);
758 else if (fineDiag.activeType() == blockCoeffBase::LINEAR)
762 "autoPtr<amgMatrix> BlockMatrixAgglomeration<Type>::"
763 "restrictMatrix() const"
764 ) << "Matrix diagonal of linear type not implemented"
765 << abort(FatalError);
771 "autoPtr<amgMatrix> BlockMatrixAgglomeration<Type>::"
772 "restrictMatrix() const"
773 ) << "Matrix diagonal of scalar type not implemented"
774 << abort(FatalError);
778 return autoPtr<BlockLduMatrix<Type> >
780 new BlockLduMatrix<Type>
789 void Foam::BlockMatrixAgglomeration<Type>::restrictResidual
791 const CoeffField<Type>& res,
792 CoeffField<Type>& coarseRes
795 typedef CoeffField<Type> TypeCoeffField;
797 if (res.activeType() == blockCoeffBase::SQUARE &&
798 coarseRes.activeType() == blockCoeffBase::SQUARE)
800 typedef typename TypeCoeffField::squareTypeField squareTypeField;
802 squareTypeField& activeCoarseRes = coarseRes.asSquare();
803 const squareTypeField& activeRes = res.asSquare();
805 // KRJ: 2013-02-05: To be done by correct pTraits?
806 forAll (coarseRes, i)
808 activeCoarseRes[i] *= 0.0;
813 activeCoarseRes[child_[i]] += activeRes[i];
818 FatalErrorIn("void BlockMatrixAgglomeration<Type>::restrictResidual() const")
819 << "Only present for square type coeff type"
820 << abort(FatalError);
826 void Foam::BlockMatrixAgglomeration<Type>::restrictResidual
828 const Field<Type>& res,
829 Field<Type>& coarseRes
832 coarseRes = pTraits<Type>::zero;
836 coarseRes[child_[i]] += res[i];
842 void Foam::BlockMatrixAgglomeration<Type>::prolongateCorrection
845 const Field<Type>& coarseX
850 x[i] += coarseX[child_[i]];
855 // ************************************************************************* //