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;
            }
        }
Exemplo n.º 3
0
        /// <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());
            }
        }