/// <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); } }
/// <summary> /// The core of the masking /// Generates index lists and the Ni0-struct-list corresponding to mask /// and is called by the child classes: local and external mask /// Note: the smallest unit are DG sub blocks! /// </summary> protected void GenerateAllMasks() { int NoOfCells = m_NoOfCells; int NoOfVariables = m_NoOfVariables; int[][] NoOfSpecies = m_NoOfSpecies; int[] DGdegreeP1 = m_DGdegree.CloneAs(); for (int iDG = 0; iDG < DGdegreeP1.Length; iDG++) { DGdegreeP1[iDG] += 1; } List <extNi0> ListNi0 = new List <extNi0>(); List <int> Globalint = new List <int>(); List <int> Localint = new List <int>(); List <int> SubBlockIdx = new List <int>(); int SubOffset = m_SubBlockOffset; // 0 for local mask and BMLoc.LocalDof for external mask int Ni0Length = 0; int MaskLen = 0; int prevLocie = m_map.LocalNoOfBlocks; var tmpCell = new List <extNi0[][][]>(); // local caching of filter functions // ensures that functions are not re-allocated during the loops var CellInstruction = m_sbs.CellFilter; var VarInstruction = m_sbs.VariableFilter; var SpecInstruction = m_sbs.SpeciesFilter; var ModeInstruction = m_sbs.ModeFilter; bool emptysel = true; // loop over cells... for (int iLoc = 0; iLoc < NoOfCells; iLoc++) { int jLoc = m_CellOffset + iLoc; //to address correctly, external cells offset has to be concidered, you know ... emptysel &= !CellInstruction(jLoc); //for testing if the entire selection is empty, which hopefully only can happen at the level of cells if (!CellInstruction(jLoc)) { continue; } var tmpVar = new List <extNi0[][]>(); // loop over variables... for (int iVar = 0; iVar < NoOfVariables; iVar++) { if (!VarInstruction(jLoc, iVar)) { continue; } var tmpSpc = new List <extNi0[]>(); // loop over species... for (int iSpc = 0; iSpc < NoOfSpecies[iLoc][iVar]; iSpc++) { if (!SpecInstruction(jLoc, iVar, iSpc)) { continue; } int GlobalOffset = m_map.GlobalUniqueIndex(iVar, jLoc, iSpc, 0); int LocalOffset = m_map.LocalUniqueIndex(iVar, jLoc, iSpc, 0); var tmpMod = new List <extNi0>(); // loop over polynomial degrees... for (int degree = 0; degree < DGdegreeP1[iVar]; degree++) { if (ModeInstruction(jLoc, iVar, iSpc, degree)) { int GlobalModeOffset = m_Ni0[degree].i0 + GlobalOffset; int LocalModeOffset = m_Ni0[degree].i0 + LocalOffset; int ModeLength = m_Ni0[degree].N; var newNi0 = new extNi0(LocalModeOffset, GlobalModeOffset, SubOffset, ModeLength); SubOffset += ModeLength; // Fill int lists for (int i = 0; i < newNi0.N; i++) { Globalint.Add(newNi0.Gi0 + i); Localint.Add(newNi0.Li0 + i); SubBlockIdx.Add(newNi0.Si0 + i); MaskLen++; } // Fill Ni0 Lists tmpMod.Add(newNi0); Ni0Length++; ListNi0.Add(newNi0); Debug.Assert(m_map.LocalUniqueIndex(iVar, jLoc, iSpc, GetNp(degree) - 1) == LocalModeOffset + ModeLength - 1); } } if (tmpMod.Count > 0) { tmpSpc.Add(tmpMod.ToArray()); } } if (tmpSpc.Count > 0) { tmpVar.Add(tmpSpc.ToArray()); } } if (tmpVar.Count > 0) { tmpCell.Add(tmpVar.ToArray()); } } var tmpStructNi0 = tmpCell.ToArray(); int NumOfNi0 = 0; #if DEBUG for (int iCell = 0; iCell < tmpStructNi0.Length; iCell++) { for (int iVar = 0; iVar < tmpStructNi0[iCell].Length; iVar++) { for (int iSpc = 0; iSpc < tmpStructNi0[iCell][iVar].Length; iSpc++) { NumOfNi0 += tmpStructNi0[iCell][iVar][iSpc].Length; } } } #endif // an empty selection is allowed, // e.g. consider a combination of empty external and non empty local mask if (!emptysel) { Debug.Assert(ListNi0.GroupBy(x => x.Li0).Any(g => g.Count() == 1)); Debug.Assert(ListNi0.GroupBy(x => x.Gi0).Any(g => g.Count() == 1)); Debug.Assert(ListNi0.Count() == NumOfNi0); Debug.Assert(MaskLen <= m_LocalLength); Debug.Assert(Localint.GroupBy(x => x).Any(g => g.Count() == 1)); Debug.Assert(Globalint.GroupBy(x => x).Any(g => g.Count() == 1)); Debug.Assert(Localint.Count() == MaskLen); Debug.Assert(SubBlockIdx.Count() == MaskLen); Debug.Assert(SubBlockIdx.GroupBy(x => x).Any(g => g.Count() == 1)); } m_GlobalMask = Globalint; m_LocalMask = Localint; m_StructuredNi0 = tmpStructNi0; m_MaskLen = MaskLen; m_Ni0Len = Ni0Length; m_SubBlockMask = SubBlockIdx; }