private static int[] ConvertRowIndices( int jCell, AggregationGridBasis basis, int[] Degrees, ChangeOfBasisConfig conf, int E, int[] _i0s, int[] LocIdx) { int NN = conf.VarIndex.Sum(iVar => basis.GetLength(jCell, Degrees[iVar])); int[] Loc2glob = new int[NN]; int i0Rowloc = 0; for (int eRow = 0; eRow < E; eRow++) // loop over variables in configuration { int i0Row = _i0s[eRow]; int iVarRow = conf.VarIndex[eRow]; int NRow = basis.GetLength(jCell, Degrees[iVarRow]); for (int n_row = 0; n_row < NRow; n_row++) // row loop... //n_row = LocIdx[k]; { int iRowLoc = n_row + i0Rowloc; int iRowGlb = n_row + i0Row; Loc2glob[iRowLoc] = iRowGlb; } i0Rowloc += NRow; } return(LocIdx.Select(i => Loc2glob[i]).ToArray()); }
private static void ExtractBlock(int jCell, AggregationGridBasis basis, int[] Degrees, ChangeOfBasisConfig conf, int E, int[] _i0s, bool Sp2Full, IMutableMatrixEx MtxSp, ref MultidimensionalArray MtxFl) { int NN = conf.VarIndex.Sum(iVar => basis.GetLength(jCell, Degrees[iVar])); if (MtxFl == null || MtxFl.NoOfRows != NN) { MtxFl = MultidimensionalArray.Create(NN, NN); } int i0Rowloc = 0; for (int eRow = 0; eRow < E; eRow++) // loop over variables in configuration { int i0Row = _i0s[eRow]; int iVarRow = conf.VarIndex[eRow]; int NRow = basis.GetLength(jCell, Degrees[iVarRow]); int i0Colloc = 0; for (int eCol = 0; eCol < E; eCol++) // loop over variables in configuration { int i0Col = _i0s[eCol]; int iVarCol = conf.VarIndex[eCol]; int NCol = basis.GetLength(jCell, Degrees[iVarCol]); for (int n_row = 0; n_row < NRow; n_row++) // row loop... { for (int n_col = 0; n_col < NCol; n_col++) // column loop... { if (Sp2Full) { // copy from sparse to full MtxFl[n_row + i0Rowloc, n_col + i0Colloc] = (MtxSp != null) ? (MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0); } else { // the other way around. MtxSp[n_row + i0Row, n_col + i0Col] = MtxFl[n_row + i0Rowloc, n_col + i0Colloc]; } } } i0Colloc += NCol; } i0Rowloc += NRow; } }
/// <summary> /// Prolongation/Injection operator to finer grid level. /// </summary> public BlockMsrMatrix GetProlongationOperator(MultigridMapping finerLevel) { using (new FuncTrace()) { // Argument checking // ================= if (!object.ReferenceEquals(finerLevel.AggGrid, this.AggGrid.ParentGrid)) { throw new ArgumentException("Only prolongation/injection to next level is supported."); } if (finerLevel.AggBasis.Length != this.AggBasis.Length) { throw new ArgumentException(""); } int NoOfVar = this.AggBasis.Length; MultidimensionalArray[][] InjOp = new MultidimensionalArray[NoOfVar][]; AggregationGridBasis[] B = new AggregationGridBasis[NoOfVar]; bool[] useX = new bool[NoOfVar]; int[] DegreeS = new int[NoOfVar]; int[] DegreeSfine = new int[NoOfVar]; for (int iVar = 0; iVar < NoOfVar; iVar++) { InjOp[iVar] = this.AggBasis[iVar].InjectionOperator; B[iVar] = AggBasis[iVar]; DegreeS[iVar] = this.DgDegree[iVar]; DegreeSfine[iVar] = finerLevel.DgDegree[iVar]; if (DegreeSfine[iVar] < DegreeS[iVar]) { throw new ArgumentException("Lower DG degree on finer grid is not supported by this method "); } useX[iVar] = this.AggBasis[iVar] is XdgAggregationBasis; if (useX[iVar] != (finerLevel.AggBasis[iVar] is XdgAggregationBasis)) { throw new ArgumentException("XDG / DG mismatch between this and finer level for " + iVar + "-th variable."); } } XdgAggregationBasis XB = null; XdgAggregationBasis XBf = null; int[][,] spcIdxMap = null; SpeciesId[][] spc = null; //SpeciesId[][] spcf = null; for (int iVar = 0; iVar < NoOfVar; iVar++) { if (useX[iVar]) { XB = (XdgAggregationBasis)(B[iVar]); XBf = (XdgAggregationBasis)(finerLevel.AggBasis[iVar]); spcIdxMap = XB.SpeciesIndexMapping; spc = XB.AggCellsSpecies; //spcf = XBf.AggCellsSpecies; break; } } int[] Np = this.AggBasis[0].GetNp(); int[] Np_fine = finerLevel.AggBasis[0].GetNp(); // create matrix // ============= // init retval var PrlgMtx = new BlockMsrMatrix(finerLevel, this); int[][] C2F = this.AggGrid.jCellCoarse2jCellFine; int JCoarse = this.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; //Debug.Assert((JCoarse == C2F.Length) || ()); for (int jc = 0; jc < JCoarse; jc++) // loop over coarse cells... { int[] AggCell = C2F[jc]; int I = AggCell.Length; for (int iVar = 0; iVar < NoOfVar; iVar++) { int DgDeg = DegreeS[iVar]; int DgDegF = DegreeSfine[iVar]; MultidimensionalArray Inj_iVar_jc = InjOp[iVar][jc]; Debug.Assert(Inj_iVar_jc.GetLength(0) == I); bool useX_iVar = false; if (useX[iVar]) { if (spcIdxMap[jc] != null) { useX_iVar = true; } } if (useX_iVar) { //throw new NotImplementedException("todo"); int NoOfSpc = XB.GetNoOfSpecies(jc); int Np_col = Np[DgDeg]; Debug.Assert(Np_col * NoOfSpc == B[iVar].GetLength(jc, DgDeg)); for (int iSpc = 0; iSpc < NoOfSpc; iSpc++) // loop over species { SpeciesId spc_jc_i = spc[jc][iSpc]; int Col0 = this.GlobalUniqueIndex(iVar, jc, Np_col * iSpc); for (int i = 0; i < I; i++) // loop over finer cells { int jf = AggCell[i]; int iSpc_Row = XBf.GetSpeciesIndex(jf, spc_jc_i); if (iSpc_Row < 0) { // nothing to do continue; } int Np_row = Np_fine[DgDegF]; Debug.Assert(Np_row * XBf.GetNoOfSpecies(jf) == finerLevel.AggBasis[iVar].GetLength(jf, DgDegF)); int Row0 = finerLevel.GlobalUniqueIndex(iVar, jf, Np_row * iSpc_Row); //if(Row0 <= 12 && 12 < Row0 + Np_row) { // if(Col0 <= 3 && 3 < Col0 + Np_col) { // Debugger.Break(); // } //} PrlgMtx.AccBlock(Row0, Col0, 1.0, Inj_iVar_jc.ExtractSubArrayShallow(new[] { i, 0, 0 }, new[] { i - 1, Np_row - 1, Np_col - 1 })); } } } else { // ++++++++++++++++++ // standard DG branch // ++++++++++++++++++ int Np_col = Np[DgDeg]; Debug.Assert(Np_col == B[iVar].GetLength(jc, DgDeg)); int Col0 = this.GlobalUniqueIndex(iVar, jc, 0); for (int i = 0; i < I; i++) // loop over finer cells { int jf = AggCell[i]; int Np_row = Np_fine[DgDegF]; Debug.Assert(Np_row == finerLevel.AggBasis[iVar].GetLength(jf, DgDegF)); int Row0 = finerLevel.GlobalUniqueIndex(iVar, jf, 0); PrlgMtx.AccBlock(Row0, Col0, 1.0, Inj_iVar_jc.ExtractSubArrayShallow(new[] { i, 0, 0 }, new[] { i - 1, Np_row - 1, Np_col - 1 })); //if(Row0 <= 12 && 12 < Row0 + Np_row) { // if(Col0 <= 3 && 3 < Col0 + Np_col) { // Debugger.Break(); // } // } } } } } // return // ====== return(PrlgMtx); } }
private static void ExtractBlock(int jCell, AggregationGridBasis basis, int[] Degrees, ChangeOfBasisConfig conf, int E, int[] _i0s, bool Sp2Full, BlockMsrMatrix MtxSp, ref MultidimensionalArray MtxFl) { int NN = conf.VarIndex.Sum(iVar => basis.GetLength(jCell, Degrees[iVar])); if (MtxFl == null || MtxFl.NoOfRows != NN) { Debug.Assert(Sp2Full == true); MtxFl = MultidimensionalArray.Create(NN, NN); } else { if (Sp2Full) { MtxFl.Clear(); } } if (!Sp2Full) { Debug.Assert(MtxSp != null); } int i0Rowloc = 0; for (int eRow = 0; eRow < E; eRow++) // loop over variables in configuration { int i0Row = _i0s[eRow]; int iVarRow = conf.VarIndex[eRow]; int NRow = basis.GetLength(jCell, Degrees[iVarRow]); int i0Colloc = 0; for (int eCol = 0; eCol < E; eCol++) // loop over variables in configuration { int i0Col = _i0s[eCol]; int iVarCol = conf.VarIndex[eCol]; int NCol = basis.GetLength(jCell, Degrees[iVarCol]); MultidimensionalArray MtxFl_blk; if (i0Rowloc == 0 && NRow == MtxFl.GetLength(0) && i0Colloc == 0 && NCol == MtxFl.GetLength(1)) { MtxFl_blk = MtxFl; } else { MtxFl_blk = MtxFl.ExtractSubArrayShallow(new[] { i0Rowloc, i0Colloc }, new[] { i0Rowloc + NRow - 1, i0Colloc + NCol - 1 }); } /* * for(int n_row = 0; n_row < NRow; n_row++) { // row loop... * for(int n_col = 0; n_col < NCol; n_col++) { // column loop... * if(Sp2Full) { * // copy from sparse to full * MtxFl[n_row + i0Rowloc, n_col + i0Colloc] = (MtxSp != null) ? ( MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0); * } else { * // the other way around. * MtxSp[n_row + i0Row, n_col + i0Col] = MtxFl[n_row + i0Rowloc, n_col + i0Colloc]; * } * } * } */ if (Sp2Full) { if (MtxSp != null) { MtxSp.ReadBlock(i0Row, i0Col, MtxFl_blk); } else { MtxFl_blk.AccEye(1.0); } } else { #if DEBUG Debug.Assert(MtxSp != null); //for (int n_row = 0; n_row < NRow; n_row++) { // row loop... // for (int n_col = 0; n_col < NCol; n_col++) { // column loop... // Debug.Assert(MtxSp[n_row + i0Row, n_col + i0Col] == 0.0); // } //} #endif MtxSp.AccBlock(i0Row, i0Col, 1.0, MtxFl_blk, 0.0); } #if DEBUG for (int n_row = 0; n_row < NRow; n_row++) // row loop... { for (int n_col = 0; n_col < NCol; n_col++) // column loop... { Debug.Assert(MtxFl[n_row + i0Rowloc, n_col + i0Colloc] == ((MtxSp != null) ? (MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0))); } } #endif i0Colloc += NCol; } i0Rowloc += NRow; } }
/// <summary> /// applies the pre-conditioning to the operator matrix /// (passed in the constructor) /// and returns the pre-conditioned matrix /// </summary> /// <param name="PCndOpMatrix"> /// on exit, /// <paramref name="LeftPreCond"/>*M*<paramref name="RightPreCond"/>, /// where M denotes the operator matrix passed in the constructor. /// </param> /// <param name="LeftPreCond"> /// left pre-conditioning matrix /// </param> /// <param name="RightPreCond"> /// right pre-conditioning matrix /// </param> /// <param name="RightPreCondInv"> /// the inverse of <paramref name="RightPreCond"/> -- usually required to transform an initial guess. /// </param> /// <returns> /// List of indefinite row indices. /// </returns> int[] ComputeChangeOfBasis(BlockMsrMatrix OpMatrix, BlockMsrMatrix MassMatrix, out BlockMsrMatrix LeftPreCond, out BlockMsrMatrix RightPreCond, out BlockMsrMatrix LeftPreCondInv, out BlockMsrMatrix RightPreCondInv) { using (var tr = new FuncTrace()) { // test arguments // ============== VerifyConfig(); Debug.Assert(OpMatrix.RowPartitioning.LocalLength == this.Mapping.LocalLength); Debug.Assert(OpMatrix.ColPartition.LocalLength == this.Mapping.LocalLength); Debug.Assert(MassMatrix == null || (MassMatrix.RowPartitioning.LocalLength == this.Mapping.LocalLength)); Debug.Assert(MassMatrix == null || (MassMatrix.ColPartition.LocalLength == this.Mapping.LocalLength)); AggregationGridBasis[] basisS = this.Mapping.AggBasis; int[] Degrees = this.Mapping.DgDegree; List <int> IndefRows = new List <int>(); // compute preconditioner matrices // =============================== using (var bt = new BlockTrace("compute-pc", tr)) { Stopwatch stw_Data = new Stopwatch(); stw_Data.Reset(); Stopwatch stw_Comp = new Stopwatch(); stw_Comp.Reset(); LeftPreCond = new BlockMsrMatrix(OpMatrix._RowPartitioning, OpMatrix._ColPartitioning); RightPreCond = new BlockMsrMatrix(OpMatrix._RowPartitioning, OpMatrix._ColPartitioning); RightPreCondInv = new BlockMsrMatrix(OpMatrix._RowPartitioning, OpMatrix._ColPartitioning); LeftPreCondInv = new BlockMsrMatrix(OpMatrix._RowPartitioning, OpMatrix._ColPartitioning); LeftPreCond.AccEyeSp(1.0); RightPreCond.AccEyeSp(1.0); LeftPreCondInv.AccEyeSp(1.0); RightPreCondInv.AccEyeSp(1.0); int LL = this.m_Config.Length; MultidimensionalArray[] MassBlock = new MultidimensionalArray[LL]; MultidimensionalArray[] OperatorBlock = new MultidimensionalArray[LL]; MultidimensionalArray[] PCleftBlock = new MultidimensionalArray[LL]; MultidimensionalArray[] work = new MultidimensionalArray[LL]; MultidimensionalArray[] PCrightBlock_inv = new MultidimensionalArray[LL]; MultidimensionalArray[] PCleftBlock_inv = new MultidimensionalArray[LL]; MultidimensionalArray[] PCrightBlock = new MultidimensionalArray[LL]; int[][] __i0s = new int[LL][]; for (int i = 0; i < LL; i++) { var conf = m_Config[i]; __i0s[i] = new int[conf.VarIndex.Length]; } int J = this.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; int i0 = this.Mapping.Partitioning.i0; for (int jCell = 0; jCell < J; jCell++) // loop over cells... //ReducedRegionCode rrc; //int NoOfSpc = LsTrk.GetNoOfSpecies(jCell, out rrc); //if (this.Mapping.GetLength(jCell) == 0) // // void cell // continue; { for (int i = 0; i < LL; i++) // for each configuration item... { var conf = m_Config[i]; int E = conf.VarIndex.Length; int[] _i0s = __i0s[i]; AggregationGridBasis basis = null; int DOF = 0; bool AnyZeroLength = false; for (int e1 = 0; e1 < E; e1++) { int dof_var = this.Mapping.GetLengthForVar(jCell, conf.VarIndex[e1]); DOF += dof_var; AnyZeroLength |= (dof_var == 0); } if (AnyZeroLength && DOF > 0) { throw new ApplicationException(); } if (DOF == 0) { // void cell continue; } for (int e = 0; e < E; e++) { _i0s[e] = this.Mapping.LocalUniqueIndex(conf.VarIndex[e], jCell, 0) + i0; if (e == 0) { basis = basisS[conf.VarIndex[e]]; } else { if (!object.ReferenceEquals(basis, basisS[conf.VarIndex[e]])) { throw new NotSupportedException("All variables in a configuration item must share the same basis."); } } } // extract blocks from operator and mass matrix // -------------------------------------------- stw_Data.Start(); ExtractBlock(jCell, basis, Degrees, conf, E, _i0s, true, MassMatrix, ref MassBlock[i]); ExtractBlock(jCell, basis, Degrees, conf, E, _i0s, true, OpMatrix, ref OperatorBlock[i]); stw_Data.Stop(); double MassBlkNrm = MassBlock[i].InfNorm(); double OperatorBlkNrm = OperatorBlock[i].InfNorm(); int NN = MassBlock[i].NoOfRows; if (MassBlkNrm == 0) { //throw new ArithmeticException("absolute zero Mass block in cell " + jCell + "."); //Console.WriteLine("absolute zero Mass block in cell " + jCell + "."); if (conf.mode == Mode.IdMass_DropIndefinite || conf.mode == Mode.SymPart_DiagBlockEquilib_DropIndefinite) { // we can deal with this ... } else { throw new ArithmeticException("absolute zero Mass block in cell " + jCell + "."); } } //if(OperatorBlkNrm == 0) { // throw new ArithmeticException("absolute zero Operator block in cell " + jCell + "."); //} // mem alloc // --------- if (PCleftBlock[i] == null || PCleftBlock[i].NoOfRows != NN) { PCleftBlock[i] = MultidimensionalArray.Create(NN, NN); } if (PCrightBlock[i] == null || PCrightBlock[i].NoOfRows != NN) { PCrightBlock[i] = MultidimensionalArray.Create(NN, NN); } if (work[i] == null || work[i].NoOfRows != NN) { work[i] = MultidimensionalArray.Create(NN, NN); } // compute precond // --------------- stw_Comp.Start(); int Rank; PCleftBlock[i].Clear(); PCrightBlock[i].Clear(); int[] idr = ComputeChangeOfBasisBlock(MassBlock[i], OperatorBlock[i], PCleftBlock[i], PCrightBlock[i], conf.mode, out Rank, work[i]); if (Rank != NN) { IndefRows.AddRange(ConvertRowIndices(jCell, basis, Degrees, conf, E, _i0s, idr)); } else { Debug.Assert(idr == null); } stw_Comp.Stop(); // write block back // ---------------- stw_Data.Start(); ExtractBlock(jCell, basis, Degrees, conf, E, _i0s, false, LeftPreCond, ref PCleftBlock[i]); ExtractBlock(jCell, basis, Degrees, conf, E, _i0s, false, RightPreCond, ref PCrightBlock[i]); // inverse precond-matrix // ---------------------- // right-inverse: (required for transforming solution guess) if (PCrightBlock_inv[i] == null || PCrightBlock_inv[i].NoOfRows != NN) { PCrightBlock_inv[i] = MultidimensionalArray.Create(NN, NN); } if (Rank == NN) { PCrightBlock[i].InvertTo(PCrightBlock_inv[i]); } else { RankDefInvert(PCrightBlock[i], PCrightBlock_inv[i]); } ExtractBlock(jCell, basis, Degrees, conf, E, _i0s, false, RightPreCondInv, ref PCrightBlock_inv[i]); // left-inverse: (required for analysis purposes, to transform residuals back onto original grid) if (PCleftBlock_inv[i] == null || PCleftBlock_inv[i].NoOfRows != NN) { PCleftBlock_inv[i] = MultidimensionalArray.Create(NN, NN); } if (Rank == NN) { PCleftBlock[i].InvertTo(PCleftBlock_inv[i]); } else { RankDefInvert(PCleftBlock[i], PCleftBlock_inv[i]); } ExtractBlock(jCell, basis, Degrees, conf, E, _i0s, false, LeftPreCondInv, ref PCleftBlock_inv[i]); stw_Data.Stop(); } } bt.LogDummyblock(stw_Data.Elapsed.Ticks, "Change_of_Basis_data_copy"); bt.LogDummyblock(stw_Comp.Elapsed.Ticks, "Change_of_Basis_compute"); } return(IndefRows.ToArray()); } }