Ejemplo n.º 1
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
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Spatial operator matrix analysis method
        /// </summary>
        public void SpatialOperatorMatrixAnalysis(bool CheckAssertions, int AnalysisLevel)
        {
            using (var solver = new Rheology()) {
                int D = solver.Grid.SpatialDimension;

                if (AnalysisLevel < 0 || AnalysisLevel > 2)
                {
                    throw new ArgumentException();
                }


                BlockMsrMatrix OpMatrix;
                double[]       OpAffine;

                solver.AssembleMatrix(out OpMatrix, out OpAffine, solver.CurrentSolution.Mapping.ToArray(), true);


                // =============================
                // AnalysisLevel 0
                // =============================
                {
                    var OpMatrixT = OpMatrix.Transpose();

                    CoordinateVector TestVec = new CoordinateVector(solver.CurrentSolution.Mapping.Fields.Select(f => f.CloneAs()).ToArray());

                    double testsumPos = 0.0;
                    double testsumNeg = 0.0;
                    for (int rnd_seed = 0; rnd_seed < 20; rnd_seed++)
                    {
                        // fill the pressure components of the test vector
                        TestVec.Clear();
                        Random  rnd      = new Random(rnd_seed);
                        DGField Pressack = TestVec.Mapping.Fields[D] as DGField;
                        int     J        = solver.GridData.iLogicalCells.NoOfLocalUpdatedCells;
                        for (int j = 0; j < J; j++)
                        {
                            int N = Pressack.Basis.GetLength(j);

                            for (int n = 0; n < N; n++)
                            {
                                Pressack.Coordinates[j, n] = rnd.NextDouble();
                            }
                        }

                        // Gradient times P:
                        double[] R1 = new double[TestVec.Count];
                        OpMatrix.SpMV(1.0, TestVec, 0.0, R1);       // R1 = Grad * P
                        //Console.WriteLine("L2 of 'Grad * P': " + R1.L2Norm());

                        // transpose of Divergence times P:
                        double[] R2 = new double[TestVec.Count];
                        OpMatrix.SpMV(1.0, TestVec, 0.0, R2);      // R2 = divT * P
                        //Console.WriteLine("L2 of 'divT * P': " + R2.L2Norm());

                        TestVec.Clear();
                        TestVec.Acc(1.0, R1);
                        TestVec.Acc(1.0, R2);


                        // analyze!
                        testsumNeg += GenericBlas.L2Dist(R1, R2);

                        R2.ScaleV(-1.0);
                        testsumPos += GenericBlas.L2Dist(R1, R2);
                    }

                    Console.WriteLine("Pressure/Divergence Symmetry error in all tests (+): " + testsumPos);
                    Console.WriteLine("Pressure/Divergence Symmetry error in all tests (-): " + testsumNeg);

                    if (CheckAssertions)
                    {
                        Assert.LessOrEqual(Math.Abs(testsumNeg), testsumPos * 1.0e-13);
                    }
                }


                // =============================
                // AnalysisLevel 1 and 2
                // =============================

                if (AnalysisLevel > 0)
                {
                    AggregationGridBasis[][] MgBasis = AggregationGridBasis.CreateSequence(solver.MultigridSequence, solver.CurrentSolution.Mapping.BasisS);

                    MultigridOperator mgOp = new MultigridOperator(MgBasis, solver.CurrentSolution.Mapping, OpMatrix, null, solver.MultigridOperatorConfig);

                    // extract
                    ////////////

                    MsrMatrix FullMatrix = mgOp.OperatorMatrix.ToMsrMatrix();

                    MsrMatrix DiffMatrix;
                    {
                        int[] VelVarIdx = D.ForLoop(d => d);

                        int[] USubMatrixIdx_Row = mgOp.Mapping.GetSubvectorIndices(VelVarIdx);
                        int[] USubMatrixIdx_Col = mgOp.Mapping.GetSubvectorIndices(VelVarIdx);
                        int   L = USubMatrixIdx_Row.Length;

                        DiffMatrix = new MsrMatrix(L, L, 1, 1);
                        FullMatrix.WriteSubMatrixTo(DiffMatrix, USubMatrixIdx_Row, default(int[]), USubMatrixIdx_Col, default(int[]));

                        double DiffMatrix_sd = DiffMatrix.SymmetryDeviation();
                        Console.WriteLine("Diffusion assymetry:" + DiffMatrix_sd);
                    }

                    MsrMatrix SaddlePointMatrix;
                    {
                        int[] VelPVarIdx = new int[] { 0, 1, 2 };

                        int[] VelPSubMatrixIdx_Row = mgOp.Mapping.GetSubvectorIndices(VelPVarIdx);
                        int[] VelPSubMatrixIdx_Col = mgOp.Mapping.GetSubvectorIndices(VelPVarIdx);
                        int   L = VelPSubMatrixIdx_Row.Length;

                        SaddlePointMatrix = new MsrMatrix(L, L, 1, 1);
                        FullMatrix.WriteSubMatrixTo(SaddlePointMatrix, VelPSubMatrixIdx_Row, default(int[]), VelPSubMatrixIdx_Col, default(int[]));
                    }
                    //SaddlePointMatrix.SaveToTextFileSparse("C:\\Users\\kikker\\Documents\\MATLAB\\spm.txt");

                    MsrMatrix ConstitutiveMatrix;
                    {
                        int[] StressVarIdx = new int[] { 3, 4, 5 };

                        int[] StressSubMatrixIdx_Row = mgOp.Mapping.GetSubvectorIndices(StressVarIdx);
                        int[] StressSubMatrixIdx_Col = mgOp.Mapping.GetSubvectorIndices(StressVarIdx);
                        int   L = StressSubMatrixIdx_Row.Length;

                        ConstitutiveMatrix = new MsrMatrix(L, L, 1, 1);
                        FullMatrix.WriteSubMatrixTo(ConstitutiveMatrix, StressSubMatrixIdx_Row, default(int[]), StressSubMatrixIdx_Col, default(int[]));
                    }

                    // operator analysis
                    //////////////////////

                    bool posDef;
                    if (AnalysisLevel > 1)
                    {
                        // +++++++++++++++++++++++++++++++
                        // check condition number, etc
                        // +++++++++++++++++++++++++++++++

                        MultidimensionalArray ret = MultidimensionalArray.Create(1, 5);
                        Console.WriteLine("Calling MATLAB/Octave...");
                        using (BatchmodeConnector bmc = new BatchmodeConnector()) {
                            bmc.PutSparseMatrix(FullMatrix, "FullMatrix");
                            bmc.PutSparseMatrix(SaddlePointMatrix, "SaddlePointMatrix");
                            bmc.PutSparseMatrix(ConstitutiveMatrix, "ConstitutiveMatrix");
                            bmc.PutSparseMatrix(DiffMatrix, "DiffMatrix");
                            bmc.Cmd("DiffMatrix = 0.5*(DiffMatrix + DiffMatrix');");

                            bmc.Cmd("condNoFullMatrix = condest(FullMatrix);");
                            bmc.Cmd("condNoSaddlePointMatrix = condest(SaddlePointMatrix);");
                            bmc.Cmd("condNoConstitutiveMatrix = condest(ConstitutiveMatrix);");
                            bmc.Cmd("condNoDiffMatrix = condest(DiffMatrix);");

                            //bmc.Cmd("eigiMaxiSaddle = 1.0; % eigs(SaddlePointMatrix,1,'lm')");
                            //bmc.Cmd("eigiMiniSaddle = 1.0; % eigs(SaddlePointMatrix,1,'sm')");
                            //bmc.Cmd("eigiMaxiConst = 1.0; % eigs(ConstitutiveMatrix,1,'lm')");
                            //bmc.Cmd("eigiMiniConst = 1.0; % eigs(ConstitutiveMatrix,1,'sm')");
                            //bmc.Cmd("eigiMaxiDiff = 1.0; % eigs(DiffMatrix,1,'lm')");
                            //bmc.Cmd("eigiMiniDiff = 1.0; % eigs(DiffMatrix,1,'sm')");

                            bmc.Cmd("lasterr");
                            bmc.Cmd("[V,r]=chol(SaddlePointMatrix);");
                            bmc.Cmd("[V,r]=chol(ConstitutiveMatrix);");
                            bmc.Cmd("ret = [condNoFullMatrix, condNoSaddlePointMatrix, condNoConstitutiveMatrix, condNoDiffMatrix, r]"); //eigiMaxiSaddle, eigiMiniSaddle, eigiMaxiConst, eigiMiniConst, eigiMaxiDiff, eigiMiniDiff,
                            bmc.GetMatrix(ret, "ret");

                            bmc.Execute(false);
                        }

                        double condNoFullMatrix         = ret[0, 0];
                        double condNoSaddlePMatrix      = ret[0, 1];
                        double condNoConstitutiveMatrix = ret[0, 2];
                        double condNoDiffMatrix         = ret[0, 3];
                        //double eigiMaxiSaddle = ret[0, 4];
                        //double eigiMiniSaddle = ret[0, 5];
                        //double eigiMaxiConst = ret[0, 6];
                        //double eigiMiniConst = ret[0, 7];
                        //double eigiMaxiDiff = ret[0, 8];
                        //double eigiMiniDiff = ret[0, 9];
                        posDef = ret[0, 4] == 0;

                        //Console.WriteLine("Eigenvalue range of saddle point matrix: {0} to {1}", eigiMiniSaddle, eigiMaxiSaddle);
                        //Console.WriteLine("Eigenvalue range of constitutive matrix: {0} to {1}", eigiMiniConst, eigiMaxiConst);
                        //Console.WriteLine("Eigenvalue range of diffusion matrix: {0} to {1}", eigiMiniDiff, eigiMaxiDiff);

                        Console.WriteLine("Condition number full operator: {0:0.####E-00}", condNoFullMatrix);
                        Console.WriteLine("Condition number saddle point operator: {0:0.####E-00}", condNoSaddlePMatrix);
                        Console.WriteLine("Condition number constitutive operator: {0:0.####E-00}", condNoConstitutiveMatrix);
                        Console.WriteLine("Condition number diffusion operator: {0:0.####E-00}", condNoDiffMatrix);

                        //base.QueryHandler.ValueQuery("ConditionNumber", condNoFullMatrix);
                    }
                    else
                    {
                        // +++++++++++++++++++++++++++++++++++++++
                        // test only for positive definiteness
                        // +++++++++++++++++++++++++++++++++++++++

                        var SaddlePMatrixFull = SaddlePointMatrix.ToFullMatrixOnProc0();
                        var ConstMatrixFull   = ConstitutiveMatrix.ToFullMatrixOnProc0();


                        posDef = true;
                        try {
                            SaddlePMatrixFull.Cholesky();
                        } catch (ArithmeticException) {
                            posDef = false;
                        }

                        posDef = true;
                        try {
                            ConstMatrixFull.Cholesky();
                        } catch (ArithmeticException) {
                            posDef = false;
                        }
                    }


                    double SaddlePSymm = SaddlePointMatrix.SymmetryDeviation();
                    Console.WriteLine("Symmetry deviation of saddle point matrix: " + SaddlePSymm);

                    if (posDef)
                    {
                        Console.WriteLine("Good news: Saddle point operator matrix seems to be positive definite.");
                    }
                    else
                    {
                        Console.WriteLine("WARNING: Saddle point operator matrix is not positive definite.");
                    }


                    double ConstSymm = ConstitutiveMatrix.SymmetryDeviation();
                    Console.WriteLine("Symmetry deviation of constitutive matrix: " + ConstSymm);

                    if (posDef)
                    {
                        Console.WriteLine("Good news: constitutive operator matrix seems to be positive definite.");
                    }
                    else
                    {
                        Console.WriteLine("WARNING: constitutive operator matrix is not positive definite.");
                    }

                    //if (CheckAssertions) {
                    //    if (Control.AdvancedDiscretizationOptions.ViscosityMode == ViscosityMode.FullySymmetric && Control.PhysicalParameters.IncludeConvection == false) {
                    //        Assert.IsTrue(posDef, "Positive definiteness test failed.");
                    //        double compVal = DiffMatrix.InfNorm() * 1e-13;
                    //        Assert.LessOrEqual(DiffSymm, compVal, "Diffusion matrix seems to be non-symmetric.");
                    //    }
                    //}
                }
            }
        }