Beispiel #1
0
        public static double rhoDinvA(MsrMatrix A, out MsrMatrix DinvA)
        {
            double rho;

            // extract diagonal matrix
            double[] Diag = A.GetDiagVector();
            int      n    = Diag.Length;

            // % form (D^-1) A
            //Diag = spdiags(1./Diag, 0, n, n);
            //DinvA = Diag*A;
            DinvA = new MsrMatrix(A.RowPartitioning, A.ColPartition);
            int i0 = A.RowPartitioning.i0;

            int Lr;

            int[]    ColumnIdx = null;
            double[] Values    = null;

            for (int i = 0; i < n; i++)
            {
                Lr = A.GetRow(i + i0, ref ColumnIdx, ref Values);
                for (int k = 0; k < Lr; k++)
                {
                    Values[k] *= 1.0 / Diag[i];
                }
                DinvA.SetRow(i + i0, ColumnIdx, Values, Lr);
            }
#if DEBUG
            for (int i = 0; i < n; i++)
            {
                Debug.Assert(Math.Abs(1.0 - DinvA[i + i0, i + i0]) < BLAS.MachineEps * 10);
            }
#endif

            // estimate the largest eigen value from Arnoldi iteration
            int        kk = 20;
            var        rand = new Random(0);
            double[]   v0 = n.ForLoop(i => rand.NextDouble());
            double[][] V; double[,] H; int kact;
            arnoldi(out V, out H, out kact, DinvA, v0, kk, false);
            kk = Math.Min(H.GetLength(0), H.GetLength(1));
            H  = H.GetSubMatrix(0, kk, 0, kk);

            rho = MaxAbsEigen(H);

            return(rho);
        }
        private static void CheckMatrix(MsrMatrix MM, int iRow0, int N, int iRow)
        {
            int[]    Cols = null;
            double[] Vals = null;
            int      LR   = MM.GetRow(iRow, ref Cols, ref Vals);
            int      cMin = int.MaxValue;
            int      cMax = int.MinValue;

            for (int lr = 0; lr < LR; lr++)
            {
                if (Vals[lr] != 0.0)
                {
                    cMin = Math.Min(cMin, Cols[lr]);
                    cMax = Math.Max(cMax, Cols[lr]);
                }
            }
            Debug.Assert(cMin >= iRow0);
            Debug.Assert(cMax < iRow0 + N);
        }
Beispiel #3
0
        private static MsrMatrix ColumnPermute(MsrMatrix M, int[] ColPerm)
        {
            MsrMatrix M2;

            M2 = new MsrMatrix(M.RowPartitioning, M.ColPartition);

            int[]    ColIdx  = null;
            double[] MtxVals = null;
            int      LR;

            for (int i = M2.RowPartitioning.i0; i < M2.RowPartitioning.iE; i++)
            {
                //var row = M.GetRow(i);
                LR = M.GetRow(i, ref ColIdx, ref MtxVals);

                for (int lr = 0; lr < LR; lr++)
                {
                    int iCol      = ColIdx[lr];
                    int icol_Targ = ColPerm[iCol];
                    M2[i, icol_Targ] = MtxVals[lr];
                }
            }
            return(M2);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="jCell"></param>
        /// <param name="AcceptedMask"></param>
        /// <param name="Phi"></param>
        /// <param name="gradPhi"></param>
        /// <param name="__DiffusionCoeff">Output: if artificial diffusion is turned</param>
        /// <param name="MaxAllowedPhi">Input: upper threshold for the values of <paramref name="Phi"/> in cell <see cref="jCell"/>.</param>
        /// <param name="MinAllowedPhi">Input: lower threshold for the values of <paramref name="Phi"/> in cell <see cref="jCell"/>.</param>
        /// <returns></returns>
        public bool LocalSolve_Iterative(int jCell, BitArray AcceptedMask, SinglePhaseField Phi, VectorField <SinglePhaseField> gradPhi, SinglePhaseField __DiffusionCoeff, double MaxAllowedPhi, double MinAllowedPhi)
        {
            //this.LocalSolve_Geometric(jCell, AcceptedMask, Phi, +1, out MinAllowedPhi, out MaxAllowedPhi);) {
            int N   = this.LevelSetBasis.GetLength(jCell);
            int i0G = this.LevelSetMapping.GlobalUniqueCoordinateIndex(0, jCell, 0);
            int i0L = this.LevelSetMapping.LocalUniqueCoordinateIndex(0, jCell, 0);

            SinglePhaseField __AcceptedMask = new SinglePhaseField(new Basis(this.GridDat, 0), "accepted");

            for (int j = 0; j < AcceptedMask.Length; j++)
            {
                __AcceptedMask.SetMeanValue(j, AcceptedMask[j] ? 1.0 : 0.0);
            }


            // subgrid on which we are working, consisting only of one cell
            SubGrid jCellGrid = new SubGrid(new CellMask(this.GridDat, Chunk.GetSingleElementChunk(jCell)));

            // create spatial operator
            IEvaluatorNonLin evo;
            {
                SpatialOperator op = new SpatialOperator(1, 2, 1, QuadOrderFunc.NonLinear(2), "Phi", "dPhi_dx0", "dPhi_dx1", "cod1");
                op.EquationComponents["cod1"].Add(new ReinitOperator());
                op.EdgeQuadraturSchemeProvider   = g => (new EdgeQuadratureScheme(domain: EdgeMask.GetEmptyMask(g)));
                op.VolumeQuadraturSchemeProvider = g => (new CellQuadratureScheme(domain: jCellGrid.VolumeMask));
                op.Commit();

                evo = op.GetEvaluatorEx(Phi.Mapping.Fields, gradPhi.Mapping.Fields, Phi.Mapping);
                evo.ActivateSubgridBoundary(jCellGrid.VolumeMask, subGridBoundaryTreatment: SubGridBoundaryModes.InnerEdge);
            }

            // create artificial diffusion operator
            MultidimensionalArray DiffMtx;

            double[]        DiffRhs;
            SpatialOperator dop;
            {
                double penaltyBase = this.LevelSetBasis.Degree + 2;
                penaltyBase = penaltyBase.Pow2();

                dop = (new ArtificialViscosity(AcceptedMask, penaltyBase, GridDat.Cells.h_min, jCell, -1.0)).Operator(1);

                MsrMatrix _DiffMtx = new MsrMatrix(this.LevelSetMapping, this.LevelSetMapping);
                double[]  _DiffRhs = new double[this.LevelSetMapping.LocalLength];

                dop.ComputeMatrixEx(this.LevelSetMapping, new DGField[] { Phi, null, null }, this.LevelSetMapping,
                                    _DiffMtx, _DiffRhs, OnlyAffine: false,
                                    edgeQuadScheme: (new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask)),
                                    volQuadScheme: (new CellQuadratureScheme(domain: jCellGrid.VolumeMask)));

                // extract matrix for 'jCell'
                DiffMtx = MultidimensionalArray.Create(N, N);
                DiffRhs = new double[N];
                for (int n = 0; n < N; n++)
                {
#if DEBUG
                    int      Lr;
                    int[]    row_cols = null;
                    double[] row_vals = null;
                    Lr = _DiffMtx.GetRow(i0G + n, ref row_cols, ref row_vals);
                    for (int lr = 0; lr < Lr; lr++)
                    {
                        int    ColIndex = row_cols[lr];
                        double Value    = row_vals[lr];
                        Debug.Assert((ColIndex >= i0G && ColIndex < i0G + N) || (Value == 0.0), "Matrix is expected to be block-diagonal.");
                    }
#endif
                    for (int m = 0; m < N; m++)
                    {
                        DiffMtx[n, m] = _DiffMtx[i0G + n, i0G + m];
                    }
                    DiffRhs[n] = _DiffRhs[i0L + n];
                }

#if DEBUG
                var Test = DiffMtx.Transpose();
                Test.Acc(-1.0, DiffMtx);
                Debug.Assert(Test.InfNorm() <= 1.0e-8);
#endif
            }

            // find 'good' initial value by geometric solve AND
            // thresholds for the maximum an minimal value of Phi
            double Range = MaxAllowedPhi - MinAllowedPhi;
            MinAllowedPhi -= 0.1 * Range;
            MaxAllowedPhi += 0.1 * Range;


            // timestep for pseudo-timestepping
            double dt = 0.5 * this.GridDat.Cells.h_min[jCell] / (((double)(this.LevelSetBasis.Degree)).Pow2());


            DGField[] PlotFields = new DGField[] { Phi, gradPhi[0], gradPhi[1], __DiffusionCoeff, __AcceptedMask };
            //Tecplot.Tecplot.PlotFields(Params, "itt_0", "EllipicReinit", 0, 3);

            double[] PrevVal = new double[N];
            double[] NextVal = new double[N];
            Phi.Coordinates.GetRow(jCell, PrevVal);

            // pseudo-timestepping
            //if(jCell == 80)
            //    Tecplot.Tecplot.PlotFields(PlotFields, "itt_0", "EllipicReinit", 0, 3);
            //Console.Write("  Local solve cell " + jCell + " ... ");

            bool   converged      = false;
            double DiffusionCoeff = 0;
            int    IterGrowCount  = 0; // number of iterations in which the residual grew
            double LastResi       = double.NaN;
            for (int iIter = 0; iIter < 1000; iIter++)
            {
                //Console.Write("  Local solve iteration " + iIter + " ... ");
                PerformRKstep(dt, jCell, AcceptedMask, Phi, gradPhi, evo);

                __DiffusionCoeff.SetMeanValue(jCell, DiffusionCoeff);

                if (jCell == 80)
                {
                    DiffusionCoeff = 0.1;
                }
                if (DiffusionCoeff > 0)
                {
                    //Console.WriteLine(" Diffusion on.");


                    double[] _DiffRhs = new double[this.LevelSetMapping.LocalLength];


                    dop.ComputeMatrixEx(this.LevelSetMapping, new DGField[] { Phi, gradPhi[0], gradPhi[1] }, this.LevelSetMapping,
                                        default(MsrMatrix), _DiffRhs, OnlyAffine: true,
                                        edgeQuadScheme: (new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask)),
                                        volQuadScheme: (new CellQuadratureScheme(domain: CellMask.GetEmptyMask(this.GridDat))));

                    // extract matrix for 'jCell'
                    for (int n = 0; n < N; n++)
                    {
                        DiffRhs[n] = _DiffRhs[i0L + n];
                    }

                    PerformArtificialDiffusion(dt * DiffusionCoeff, jCell, Phi, DiffMtx, DiffRhs);
                }
                Phi.Coordinates.GetRow(jCell, NextVal);
                double   resi = Math.Sqrt(GenericBlas.L2DistPow2(NextVal, PrevVal) / GenericBlas.L2NormPow2(PrevVal));
                double[] A    = NextVal;
                NextVal = PrevVal;
                PrevVal = A;
                if (iIter > 0 && resi > LastResi)
                {
                    IterGrowCount++;
                }
                else
                {
                    IterGrowCount = 0;
                }
                LastResi = resi;


                if (resi < 1.0e-10)
                {
                    converged = true;
                    break;
                }

                double maxPhi, minPhi;
                Phi.GetExtremalValuesInCell(out minPhi, out maxPhi, jCell);

                bool MinAlarm  = minPhi < MinAllowedPhi;
                bool Maxalarm  = maxPhi > MaxAllowedPhi;
                bool GrowAlarm = IterGrowCount > 4;
                bool IterAlarm = iIter >= 50;

                if (MinAlarm || Maxalarm || GrowAlarm)
                {
                    // Diffusion coefficient should be increased
                    if (DiffusionCoeff == 0)
                    {
                        DiffusionCoeff = 1.0e-2;
                    }
                    else
                    {
                        if (DiffusionCoeff < 1.0e3)
                        {
                            DiffusionCoeff *= 2;
                        }
                    }
                    //Console.WriteLine("   increasing Diffusion: {0}, Alarms : {1}{2}{3}{4}", DiffusionCoeff, MinAlarm ? 1 : 0, Maxalarm ? 1 : 0, GrowAlarm ? 1 : 0, IterAlarm ? 1 : 0);
                }


                //if(jCell == 80 && iIter < 100)
                //    Tecplot.Tecplot.PlotFields(PlotFields, "itt_" + (iIter + 1), "EllipicReinit", iIter + 1, 3);
            }


            return(converged);
        }
Beispiel #5
0
        private void ApproximationMatrix()
        {
            this.Aapprox        = null;
            this.AapproxInverse = null;

            //MsrMatrix AapproxComp = null;

            /*
             * switch(m_SIMPLEOptions.Option_Approximation_Predictor) {
             *  case ApproxPredictor.MassMatrix:
             *  case ApproxPredictor.LocalizedOperator: { break; }
             *  default: {
             *      Aapprox = ConvDiff.CloneAs();
             *      //switch (m_SIMPLEOptions.Option_Timestepper) {
             *      //    case Timestepper.Steady: break;
             *      //    case Timestepper.ImplicitEuler: {
             *      //            Aapprox.Acc(1.0 / dt, MassMatrix);
             *      //            break;
             *      //        }
             *      //    default: {
             *      //            throw new NotImplementedException("Unknown Timestepper");
             *      //        }
             *      //}
             *      AapproxComp = new MsrMatrix(USubMatrixIdx.Length, USubMatrixIdx.Length, MassMatrix.RowPartitioning.BlockSize / (2 * D), MassMatrix.ColPartition.BlockSize / (2 * D));
             *      Aapprox.WriteSubMatrixTo(AapproxComp, USubMatrixIdx, default(int[]), USubMatrixIdx, default(int[]));
             *      break;
             *  }
             * }
             */
            switch (m_SIMPLEOptions.Option_Approximation_Predictor)
            {
            case ApproxPredictor.MassMatrix: {
                BlockMsrMatrix MM;
                if (!double.IsPositiveInfinity(this.m_SIMPLEOptions.dt))
                {
                    // instationary SIMPLE

                    //MM = this.m_MgOp.MassMatrix.CloneAs();


                    // hier muss ich mir nochmal was überlegen --
                    // für einige Präkond.-Optionen
                    // (genau jene, welche die XDG-Basen für beide Phasen in Cut-Zellen mischen),
                    // wie etwa
                    //   MultigridOperator.Mode.SymPart_DiagBlockEquilib
                    // ist eine Block-Skalierung mit rho_A und rho_B
                    // inkonsistent!
                    //

                    throw new NotImplementedException("todo");
                }
                else
                {
                    MM = this.m_MgOp.MassMatrix;
                }
                Aapprox = new MsrMatrix(this.ConvDiff.RowPartitioning);
                this.m_MgOp.MassMatrix.WriteSubMatrixTo(Aapprox, this.USubMatrixIdx_Row, default(int[]), this.USubMatrixIdx_Row, default(int[]));

                //AapproxInverse = MassMatrixInv._ToMsrMatrix();// Aapprox.Invert();
                //switch(m_SIMPLEOptions.Option_Timestepper) {
                //    case Timestepper.Steady: break;
                //    case Timestepper.ImplicitEuler: {
                //        Aapprox.Scale(1 + 1.0 / dt);
                //        AapproxInverse.Scale(1 / (1 + 1.0 / dt));
                //        /*#if DEBUG
                //                                            var CheckMX = AapproxInverse * Aapprox;
                //                                            foreach (int i in USubMatrixIdx) {
                //                                                if (Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-10) throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix");
                //                                            }

                //        #endif*/
                //        break;
                //    }
                //    default: {
                //        throw new NotImplementedException("Unknown Timestepper");
                //    }
                //}
                break;
            }

            case ApproxPredictor.Exact: {
                if (this.LsTrk.GridDat.CellPartitioning.MpiSize > 1)
                {
                    throw new NotSupportedException("Not implemented for MPI-parallel runs.");
                }

                //RowIdx = VelocityMapping.GetSubvectorIndices(this.LsTrk, D.ForLoop(d => d), _SpcIds: this.LsTrk.SpeciesIdS, drk: this.TransportAgglomerator);
                //ColIdx = RowIdx;

                if (USubMatrixIdx_Row.Length > 4500)
                {
                    Console.WriteLine(string.Format("WARNING: you don't really want to invert a {0}x{0} matrix.", USubMatrixIdx_Row.Length));
                }

                this.Aapprox = this.ConvDiff;

                MultidimensionalArray AapproxFull        = Aapprox.ToFullMatrixOnProc0();
                MultidimensionalArray AapproxInverseFull = AapproxFull.GetInverse();
                this.AapproxInverse = new MsrMatrix(new Partitioning(USubMatrixIdx_Row.Length));
                this.AapproxInverse.AccDenseMatrix(1.0, AapproxInverseFull);
                break;
            }

            case ApproxPredictor.Diagonal: {
                /*
                 * Aapprox = new MsrMatrix(ConvDiff.RowPartitioning, ConvDiff.ColPartition);
                 * AapproxInverse = new MsrMatrix(ConvDiff.RowPartitioning, ConvDiff.ColPartition);
                 * foreach(int i in USubMatrixIdx) {
                 *  int[] j = new int[] { i };
                 *  double Value = ConvDiff.GetValues(i, j)[0];
                 *  //Value += MassMatrix.GetValues(i, j)[0];
                 *  Aapprox.SetDiagonalElement(i, Value);
                 *  if(Value == 0) {
                 *      AapproxInverse.SetDiagonalElement(i, 0);
                 *  } else {
                 *      AapproxInverse.SetDiagonalElement(i, 1 / Value);
                 *  }
                 * }
                 #if DEBUG
                 * Aapprox.VerifyDataStructure();
                 * AapproxInverse.VerifyDataStructure();
                 * var CheckMX = AapproxInverse * Aapprox;
                 * foreach(int i in USubMatrixIdx) {
                 *  if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-13) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix");
                 * }
                 #endif
                 * break;
                 */
                throw new NotImplementedException("todo");
            }

            case ApproxPredictor.BlockDiagonal: {
                /*
                 * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition);
                 * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp);
                 * var AapproxCompInvBD = AapproxCompBD.Invert();
                 * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(Aapprox, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx);
                 * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx);
                 * //#if DEBUG
                 * Aapprox.VerifyDataStructure();
                 * AapproxInverse.VerifyDataStructure();
                 * var CheckMX = AapproxInverse * Aapprox;
                 * foreach(int i in USubMatrixIdx) {
                 *  if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix");
                 * }
                 * //#endif
                 *
                 * break;
                 */
                throw new NotImplementedException("todo");
            }

            case ApproxPredictor.BlockSum: {
                /*
                 * Console.WriteLine("BlockSum is not properly tested yet and did not work in previous tests");
                 * int AccdBlockSize = ConvDiff.RowPartitioning.BlockSize / (2 * D);
                 * var AapproxBD = new BlockDiagonalMatrix(ConvDiff.RowPartitioning);
                 * var Aapprox = new MsrMatrix(ConvDiff.RowPartitioning);
                 * int[] indexer = new int[AccdBlockSize];
                 * for(int i = 0; i < indexer.Length; i++) {
                 *  indexer[i] = i;
                 * }
                 * int[] rowindexer = indexer.CloneAs();
                 *
                 *
                 * for(int i = 0; i < ConvDiff.NoOfRows / AccdBlockSize; i++) {
                 *  int[] colindexer = indexer.CloneAs();
                 *  for(int j = 0; j < ConvDiff.NoOfCols / AccdBlockSize; j++) {
                 *      ConvDiff.AccSubMatrixTo(1.0, Aapprox, rowindexer, rowindexer, colindexer, rowindexer);
                 *      for(int r = 0; r < indexer.Length; r++) {
                 *          colindexer[r] += AccdBlockSize;
                 *      }
                 *  }
                 *  for(int r = 0; r < indexer.Length; r++) {
                 *      rowindexer[r] += AccdBlockSize;
                 *  }
                 * }
                 * //if (m_SIMPLEOptions.Option_Timestepper == Timestepper.ImplicitEuler) {
                 * //    Aapprox.Acc(1 / dt, MassMatrix);
                 * //}
                 * AapproxComp = new MsrMatrix(USubMatrixIdx.Length, USubMatrixIdx.Length, AccdBlockSize, AccdBlockSize);
                 * Aapprox.WriteSubMatrixTo(AapproxComp, USubMatrixIdx, default(int[]), USubMatrixIdx, default(int[]));
                 * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition);
                 * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp);
                 * var AapproxCompInvBD = AapproxCompBD.Invert();
                 * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx);
                 #if DEBUG
                 * Aapprox.VerifyDataStructure();
                 * AapproxInverse.VerifyDataStructure();
                 *
                 * // Check copying back and forth
                 * var CheckAapproxComp = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition);
                 * AapproxComp.WriteSubMatrixTo(CheckAapproxComp, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx);
                 * CheckAapproxComp.Acc(-1.0, Aapprox);
                 * if(CheckAapproxComp.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix");
                 *
                 * //Check Transformation to BlockdiagonalMatrix
                 * var CheckAapproxCompBD = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition);
                 * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(CheckAapproxCompBD, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx);
                 * CheckAapproxCompBD.Acc(-1.0, Aapprox);
                 * if(CheckAapproxCompBD.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix");
                 *
                 * //Check Matrix Inversion
                 * var CheckMX = AapproxInverse * Aapprox;
                 * foreach(int i in USubMatrixIdx) {
                 *  if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix");
                 * }
                 #endif
                 * break;
                 */
                throw new NotImplementedException("todo");
            }

            case ApproxPredictor.Neumann: {
                /*
                 * Console.WriteLine("Neumann did not work in previous Tests, Series does typically not converge");
                 * int serieslength = 10;
                 *
                 * Aapprox = ConvDiff.CloneAs();
                 * //if (m_SIMPLEOptions.Option_Timestepper != Timestepper.Steady) {
                 * //    Aapprox.Acc(1.0 / dt, MassMatrix);
                 * //}
                 * var B = Aapprox.CloneAs();
                 * double ScalingFactor = Aapprox.InfNorm();
                 * B.Scale((-1.0 / ScalingFactor.Pow(0))); //Scaling Power up to 4 tried
                 * B.AccEyeSp(1.0);
                 * AapproxInverse = B;
                 * AapproxInverse.AccEyeSp(1.0);
                 * MsrMatrix OldMoment = B;
                 * for(int i = 0; i <= serieslength; i++) {
                 *  var NewMoment = OldMoment * B;
                 *  AapproxInverse.Acc(1.0, NewMoment);
                 *  //Debug
                 *  Console.WriteLine("MomentNumber #{0}, InfNormOf Inverse #{1}", i, NewMoment.InfNorm());
                 *  OldMoment = NewMoment;
                 * }
                 * AapproxInverse.Scale((1.0 / ScalingFactor.Pow(0))); //Scaling Power up to 4 tried
                 * break;
                 */
                throw new NotImplementedException("todo");
            }

            case ApproxPredictor.LocalizedOperator: {
                /*
                 * Console.WriteLine("Localized Operator did not work in previous Tests");
                 * double[] LocalizedOpAffine;
                 * MultiphaseCellAgglomerator LocalizedAgglomerator;
                 * Aapprox = new MsrMatrix(MassMatrix.RowPartitioning, MassMatrix.ColPartition);
                 * TransportOpLocalized.AssembleMatrix(
                 *  out Aapprox, out LocalizedOpAffine,
                 *  out LocalizedAgglomerator, out TransportMassFact,
                 *  this.Velocity.Current, null,
                 *  this.LevSet, null, Curv,
                 *  VelocityMapping, VelocityMapping);
                 * if(Option_Timestepper == Timestepper.ImplicitEuler) {
                 *  Aapprox.Acc(1 / dt, MassMatrix);
                 * }
                 *
                 * var DiagAverage = Aapprox.GetDiagVector().Average();
                 * foreach(int i in RowIdx) {
                 *  if(Aapprox.GetDiagonalElement(i) == 0.0) {
                 *      //Aapprox.SetDiagonalElement(i, MassMatrix.GetDiagonalElement(i));
                 *      Aapprox.SetDiagonalElement(i, DiagAverage);
                 *  }
                 * }
                 * AapproxComp = new MsrMatrix(RowIdx.Length, RowIdx.Length, MassMatrix.RowPartitioning.BlockSize / (2 * D), MassMatrix.ColPartition.BlockSize / (2 * D));
                 * Aapprox.WriteSubMatrixTo(AapproxComp, RowIdx, default(int[]), ColIdx, default(int[]));
                 * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition);
                 * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp);
                 * var AapproxCompInvBD = AapproxCompBD.Invert();
                 * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), RowIdx, default(int[]), ColIdx);
                 * //AapproxComp._ToMsrMatrix().WriteSubMatrixTo(Aapprox, default(int[]), RowIdx, default(int[]), ColIdx);
                 *
                 *
                 #if DEBUG
                 * Aapprox.VerifyDataStructure();
                 * AapproxInverse.VerifyDataStructure();
                 * var CheckAapproxCompBD = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition);
                 * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(CheckAapproxCompBD, default(int[]), RowIdx, default(int[]), ColIdx);
                 * CheckAapproxCompBD.Acc(-1.0, Aapprox);
                 * if(CheckAapproxCompBD.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix");
                 * var CheckMX = AapproxInverse * Aapprox;
                 * foreach(int i in RowIdx) {
                 *  if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix");
                 * }
                 #endif
                 * break;
                 */
                throw new NotImplementedException("todo");
            }

            default:
                throw new NotImplementedException("todo");
            }


            if (this.AapproxInverse == null)
            {
                // block-inversion is required.
                // ++++++++++++++++++++++++++++

                int D = this.LsTrk.GridDat.SpatialDimension;
                this.AapproxInverse = new MsrMatrix(this.Aapprox.RowPartitioning, this.Aapprox.ColPartition);

                //int N = this.m_MgOp.Mapping.AggBasis.GetMinimalLength(this.m_MgOp.Mapping.DgDegree[0]);
                //Debug.Assert(this.Aapprox.RowPartitioning.LocalLength % N == 0);
                MultidimensionalArray Block    = new MultidimensionalArray(2);
                MultidimensionalArray InvBlock = new MultidimensionalArray(2);


                int   iRow0   = this.Aapprox.RowPartitioning.i0;
                int   JAGG    = this.m_MgOp.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells;
                int[] DegreeS = this.m_MgOp.Mapping.DgDegree;
                for (int jagg = 0; jagg < JAGG; jagg++) // loop over aggregate cells...
                {
                    for (int d = 0; d < D; d++)         // loop over velocity components...
                    {
                        int N = this.m_MgOp.Mapping.AggBasis[d].GetLength(jagg, DegreeS[d]);
                        if (Block.GetLength(0) != N)
                        {
                            Block.Allocate(N, N);
                            InvBlock.Allocate(N, N);
                        }

                        for (int n = 0; n < N; n++)
                        {
#if DEBUG
                            int iRow = iRow0 + n;
                            {
                                int[]    Cols = null;
                                double[] Vals = null;
                                int      LR   = Aapprox.GetRow(iRow, ref Cols, ref Vals);
                                int      cMin = int.MaxValue;
                                int      cMax = int.MinValue;
                                for (int lr = 0; lr < LR; lr++)
                                {
                                    if (Vals[lr] != 0.0)
                                    {
                                        cMin = Math.Min(cMin, Cols[lr]);
                                        cMax = Math.Max(cMax, Cols[lr]);
                                    }
                                }
                                Debug.Assert(cMin >= iRow0);
                                Debug.Assert(cMax < iRow0 + N);
                            }
#endif
                            for (int m = 0; m < N; m++)
                            {
                                Block[n, m] = this.Aapprox[iRow0 + n, iRow0 + m];
                            }
                        }

                        Block.InvertTo(InvBlock);

                        for (int n = 0; n < N; n++)
                        {
                            for (int m = 0; m < N; m++)
                            {
                                this.AapproxInverse[iRow0 + n, iRow0 + m] = InvBlock[n, m];
                            }
                        }

                        iRow0 += N;
                    }
                }

                Debug.Assert(iRow0 == this.Aapprox.RowPartitioning.iE);
            }

#if DEBUG
            var    CheckMX = AapproxInverse * Aapprox;
            double TRESH   = Math.Max(AapproxInverse.InfNorm(), Aapprox.InfNorm()) * 1.0e-10;
            for (int iRow = CheckMX.RowPartitioning.i0; iRow < CheckMX.RowPartitioning.iE; iRow++)
            {
                if (Math.Abs(CheckMX.GetDiagonalElement(iRow) - 1.0) > TRESH)
                {
                    throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix");
                }
            }
#endif
        }
        void ExtractMatrices()
        {
            // dispose old solver, if required
            // ===============================

            if (this.m_PressureSolver != null)
            {
                this.m_PressureSolver.Dispose();
                this.m_PressureSolver = null;
            }


            // sub-matrices for the Potential Solver
            // =====================================
            int VelocityLength = this.USubMatrixIdx_Row.Length;
            int PressureLength = this.PSubMatrixIdx_Row.Length;


            this.PressureGrad = new MsrMatrix(VelocityLength, PressureLength, 1, 1);
            this.VelocityDiv  = new MsrMatrix(PressureLength, VelocityLength, 1, 1);
            this.Stab         = new MsrMatrix(PressureLength, PressureLength, 1, 1);

            var WholeSystemMatrix = this.m_MgOp.OperatorMatrix;

            WholeSystemMatrix.WriteSubMatrixTo(PressureGrad, USubMatrixIdx_Row, default(int[]), PSubMatrixIdx_Row, default(int[]));
            WholeSystemMatrix.WriteSubMatrixTo(VelocityDiv, PSubMatrixIdx_Row, default(int[]), USubMatrixIdx_Row, default(int[]));
            WholeSystemMatrix.WriteSubMatrixTo(Stab, PSubMatrixIdx_Row, default(int[]), PSubMatrixIdx_Row, default(int[]));



            // inverse mass matrix
            // ===================

            if (this.m_SIMPLEOptions.PotentialSolver_UseMassMatrix)
            {
                // extract the mass-matrix block for the velocity part
                // ---------------------------------------------------
                MsrMatrix MM = new MsrMatrix(this.PressureGrad.RowPartitioning, this.VelocityDiv.ColPartition);
                this.m_MgOp.MassMatrix.WriteSubMatrixTo(MM, this.USubMatrixIdx_Row, default(int[]), this.USubMatrixIdx_Row, default(int[]));

                // invert mass matrix
                // ------------------

                int D = this.LsTrk.GridDat.SpatialDimension;
                this.invMM = new MsrMatrix(MM.RowPartitioning, MM.ColPartition);

                MultidimensionalArray Block    = new MultidimensionalArray(2);
                MultidimensionalArray InvBlock = new MultidimensionalArray(2);

                int   iRow0   = MM.RowPartitioning.i0;
                int   JAGG    = this.m_MgOp.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells;
                int[] DegreeS = this.m_MgOp.Mapping.DgDegree;
                for (int jagg = 0; jagg < JAGG; jagg++) // loop over aggregate cells...
                {
                    for (int d = 0; d < D; d++)         // loop over velocity components...
                    {
                        int N = this.m_MgOp.Mapping.AggBasis[d].GetLength(jagg, DegreeS[d]);
                        if (Block.GetLength(0) != N)
                        {
                            Block.Allocate(N, N);
                            InvBlock.Allocate(N, N);
                        }

                        for (int n = 0; n < N; n++)
                        {
#if DEBUG
                            int iRow = iRow0 + n;
                            {
                                int[]    Cols = null;
                                double[] Vals = null;
                                int      LR   = MM.GetRow(iRow, ref Cols, ref Vals);
                                int      cMin = int.MaxValue;
                                int      cMax = int.MinValue;
                                for (int lr = 0; lr < LR; lr++)
                                {
                                    if (Vals[lr] != 0.0)
                                    {
                                        cMin = Math.Min(cMin, Cols[lr]);
                                        cMax = Math.Max(cMax, Cols[lr]);
                                    }
                                }
                                Debug.Assert(cMin >= iRow0);
                                Debug.Assert(cMax < iRow0 + N);
                            }
#endif
                            for (int m = 0; m < N; m++)
                            {
                                Block[n, m] = MM[iRow0 + n, iRow0 + m];
                            }
                        }

                        Block.InvertTo(InvBlock);

                        for (int n = 0; n < N; n++)
                        {
                            for (int m = 0; m < N; m++)
                            {
                                this.invMM[iRow0 + n, iRow0 + m] = InvBlock[n, m];
                            }
                        }

                        iRow0 += N;
                    }
                }

                Debug.Assert(iRow0 == MM.RowPartitioning.iE);

#if DEBUG
                var    CheckMX = MM * invMM;
                double TRESH   = Math.Max(MM.InfNorm(), invMM.InfNorm()) * 1.0e-10;
                for (int iRow = CheckMX.RowPartitioning.i0; iRow < CheckMX.RowPartitioning.iE; iRow++)
                {
                    if (Math.Abs(CheckMX.GetDiagonalElement(iRow) - 1.0) > TRESH)
                    {
                        throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix");
                    }
                }
#endif
            }
        }