Exemple #1
0
        /// <summary>
        /// Rhs corrector, cf. right-hand side of Eq. (17) in
        /// B. Klein, F. Kummer, M. Keil, and M. Oberlack,
        /// An extension of the SIMPLE based discontinuous Galerkin solver to unsteady incompressible flows, J. Comput. Phys., 2013.
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="SpatialComponent"></param>
        /// <returns></returns>
        protected override IList <double> DefineRhs(double dt, int SpatialComponent)
        {
            double[] Rhs = new double[m_DivB4.DOFLocal];

            // calculate mass defect
            m_DivB4.Clear();
            SolverUtils.CalculateMassDefect_Divergence(m_VelocityDivergence, m_Velocity_Intrmed, m_DivB4);
            Rhs.AccV(1.0, m_DivB4.CoordinateVector);

            // pressure stabilization
            if (base.m_solverConf.Control.PressureStabilizationScaling > 0.0)
            {
                double[] PressureStabi = new double[Rhs.Length];
                m_PressureStabilization.OperatorMatrix.SpMVpara(1.0, m_Pressure.CoordinateVector, 0.0, PressureStabi);
                Rhs.AccV(1.0, PressureStabi);
            }

            // reference point pressure
            if (base.m_solverConf.Control.PressureReferencePoint != null)
            {
                BoSSS.Solution.NSECommon.SolverUtils.SetRefPtPressure_Rhs(Rhs, base.m_solverConf.PressureReferencePointIndex, m_MatAsmblyCorrector.i0);
            }

            return(Rhs);
        }
        protected override IList <double> DefineRhs(double dt, int SpatialComponent)
        {
            double[] Rhs = new double[DivB4.DOFLocal];


            // calculate mass defect
            DivB4.Clear();

            SolverUtils.CalculateMassDefect_Divergence(VelocityDivergence, Velocity_Intrmed, DivB4);
            Rhs.AccV(1.0, DivB4.CoordinateVector);

            // time derivative density
            if (base.m_solverConf.Control.Algorithm == SolutionAlgorithms.Unsteady_SIMPLE)
            {
                SinglePhaseField DensitySummand = new SinglePhaseField(DivB4.Basis);
                BDF.ComputeDensitySummand(dt, base.m_solverConf.BDFOrder, Temperature, EoS, DensitySummand);
                Rhs.AccV(1.0, DensitySummand.CoordinateVector);
            }



            // reference point pressure
            if (base.m_solverConf.Control.PressureReferencePoint != null)
            {
                BoSSS.Solution.NSECommon.SolverUtils.SetRefPtPressure_Rhs(Rhs, base.m_solverConf.PressureReferencePointIndex, MatAsmblyCorrector.i0);
            }

            return(Rhs);
        }
Exemple #3
0
        private void recomb(double[] Velocity, double[] Pressure, List <double[]> Z, List <double[]> Q)
        {
            int L = this.USubMatrixIdx_Row.Length + this.PSubMatrixIdx_Row.Length;

            if (this.m_SIMPLEOptions.CorrrectionMode == SimpleCorrectionMode.ResidualMinimization)
            {
                double[] Z1 = new double[L];
                if (Velocity != null)
                {
                    Z1.AccV(1.0, Velocity, this.USubMatrixIdx_Row, default(int[]));
                }
                if (Pressure != null)
                {
                    Z1.AccV(1.0, Pressure, this.PSubMatrixIdx_Row, default(int[]));
                }


                double[] Q1 = new double[L];
                this.m_MgOp.OperatorMatrix.SpMV(1.0, Z1, 0.0, Q1);

                Z.Add(Z1);
                Q.Add(Q1);
            }
            else if (this.m_SIMPLEOptions.CorrrectionMode == SimpleCorrectionMode.ResidualMinimization_perSpecies)
            {
                if (this.PSpcSubMatrix_Row.Length != this.USpcSubMatrix_Row.Length)
                {
                    throw new ApplicationException();
                }

                int NoOfSpc = PSpcSubMatrix_Row.Length;


                for (int iSpc = 0; iSpc < NoOfSpc; iSpc++)
                {
                    double[] Z4 = new double[L];

                    if (Velocity != null)
                    {
                        Z4.AccV(1.0, Velocity, this.USpcSubMatrix_Row[iSpc], default(int[]));
                    }
                    if (Pressure != null)
                    {
                        Z4.AccV(1.0, Pressure, this.PSpcSubMatrix_Row[iSpc], default(int[]));
                    }

                    double[] Q4 = new double[L];
                    this.m_MgOp.OperatorMatrix.SpMV(1.0, Z4, 0.0, Q4);

                    Z.Add(Z4);
                    Q.Add(Q4);
                }
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Exemple #4
0
        private void AssembleMatrix(double dt, out BlockMsrMatrix SystemMatrix, out double[] SystemAffine)
        {
            // Init Matrix and Affine Part
            SystemMatrix = new BlockMsrMatrix(Mapping);
            SystemAffine = new double[Mapping.LocalLength];

            // choose TimeStepping-Scheme, based on what has been pushed to the stack,yet
            int Smax = TSCchain[0].S;

            Debug.Assert(Smax == TSCchain.Length);
            Tsc = TSCchain[Smax - PopulatedStackDepth];

            UpdateOperatorMatrix();



            //Implicit Part of RHS
            SystemMatrix.Acc(Tsc.theta1, Stack_OpMatrix[1]);
            SystemAffine.AccV(Tsc.theta1, Stack_OpAffine[1]);



            //Implicit Part of LHS
            SystemMatrix.AccEyeSp(1 / dt);

            // Explicit part of RHS
            Stack_OpMatrix[0].SpMV(-Tsc.theta0, CurrentState, 1.0, SystemAffine);
            SystemAffine.AccV(-Tsc.theta0, Stack_OpAffine[0]);

            //Explicit parts of LHS
            for (int i = 0; i < Tsc.beta.Length; i++)
            {
                SystemAffine.AccV(Tsc.beta[i] * 1 / dt, Stack_u[i]);
            }

            Debug.Assert(SystemMatrix.InfNorm() > 0);
            Debug.Assert(SystemAffine.L2Norm() > 0);

            if (subGrid != null)
            {
                int[] SubVecIdx = Mapping.GetSubvectorIndices(subGrid, true, new int[] { 0 });
                int   L         = SubVecIdx.Length;

                for (int i = 0; i < L; i++)
                {
                    SystemMatrix.ClearRow(SubVecIdx[i]);
                    SystemMatrix[SubVecIdx[i], SubVecIdx[i]] = 1;
                    SystemAffine[SubVecIdx[i]] = 0;
                }
            }
        }
Exemple #5
0
        public void TransformRhsInto <T1, T2>(T1 u_IN, T2 v_OUT)
            where T1 : IList <double>
            where T2 : IList <double>
        {
            if (this.FinerLevel != null)
            {
                throw new NotSupportedException("Only supported on finest level.");
            }
            if (u_IN.Count != this.Mapping.ProblemMapping.LocalLength)
            {
                throw new ArgumentException("Mismatch in length of input vector.", "u");
            }
            if (v_OUT.Count != this.Mapping.LocalLength)
            {
                throw new ArgumentException("Mismatch in length of output vector.", "v");
            }

            int L = this.Mapping.LocalLength;

            double[] uc = new double[L];
            uc.AccV(1.0, u_IN, default(int[]), this.IndexIntoProblemMapping_Local);

            if (this.LeftChangeOfBasis != null)
            {
                this.LeftChangeOfBasis.SpMV(1.0, uc, 0.0, v_OUT);
            }
            else
            {
                v_OUT.SetV(uc);
            }
        }
Exemple #6
0
        /// <summary>
        /// computes the pressure correction.
        /// </summary>
        /// <param name="Pressure">input: current pressure</param>
        /// <param name="VelocityPCorrIn">input: intermediate velocity</param>
        /// <param name="PressurePCorr">output: pressure correction</param>
        /// <param name="RHSContinuity">input: RHS of the continuity equation</param>
        /// <returns></returns>
        double PressureCorrector(double[] Pressure, double[] VelocityPCorrIn, double[] PressurePCorr, double[] RHSContinuity)
        {
            using (new FuncTrace()) {
                // solve Poisson equation
                // ======================

                // Matrix: Div*A^-1*Grad + S
                InitPressureSolver();

                // RHS
                var RHS = new double[Pressure.Length];

                {
                    RHS.AccV(-1.0, RHSContinuity);
                    VelocityDiv.SpMVpara(+1.0, VelocityPCorrIn, 1.0, RHS);
                    Stab.SpMVpara(+1.0, Pressure, 1.0, RHS);
                }

                // solve
                m_PressureSolver.Solve(PressurePCorr, RHS);


                // return
                return(PressurePCorr.L2Norm());
            }
        }
        static void PrlgAndRestTestRec(int p, MultigridMapping[] MgMapSeq)
        {
            var currentLevelMap = MgMapSeq.First();
            var AggBasis        = currentLevelMap.AggBasis[0];

            // allocate vector on full grid
            var Test    = new SinglePhaseField(new Basis(grid, p));
            var PrlgVec = Test.CoordinateVector;

            // init test vector
            Random rnd = new Random();

            double[] RestVec = new double[AggBasis.LocalDim];
            RestVec = AggBasis.LocalDim.ForLoop(i => rnd.NextDouble());

            // prolongate test vector
            AggBasis.ProlongateToFullGrid(PrlgVec, RestVec);

            // calculate restriction of the prolongated vector
            double[] RestVec2 = new double[RestVec.Length];
            AggBasis.RestictFromFullGrid(PrlgVec, RestVec2);

            // original and second restriction should be equal
            RestVec.AccV(-1.0, RestVec2);
            double ErrNorm = RestVec.L2Norm();

            Console.WriteLine("Prolongation/Restriction test (p={1}, level={2}): {0}", ErrNorm, p, currentLevelMap.AggGrid.MgLevel);
            Assert.Less(ErrNorm, 1.0e-8);

            if (MgMapSeq.Length > 1)
            {
                PrlgAndRestTestRec(p, MgMapSeq.Skip(1).ToArray());
            }
        }
Exemple #8
0
        /// <summary>
        /// Finite difference directional derivative Approximate f'(x) w
        /// C.T.Kelley, April 1, 2003
        /// This code comes with no guarantee or warranty of any kind.
        /// </summary>
        /// <param name="SolutionVec">Solution point</param>
        /// <param name="w">Direction</param>
        /// <param name="f0">f0, usually has been calculated earlier</param>
        /// <param name="linearization">True if the Operator should be linearized and evaluated afterwards</param>
        /// <returns></returns>
        public double[] dirder(CoordinateVector SolutionVec, double[] currentX, double[] w, double[] f0, bool linearization = false)
        {
            using (var tr = new FuncTrace()) {
                double epsnew = 1E-7;

                int      n  = SolutionVec.Length;
                double[] fx = new double[f0.Length];

                // Scale the step
                if (w.L2NormPow2().MPISum().Sqrt() == 0)
                {
                    fx.Clear();
                    return(fx);
                }

                var normw = w.L2NormPow2().MPISum().Sqrt();

                double xs = GenericBlas.InnerProd(currentX, w).MPISum() / normw;

                if (xs != 0)
                {
                    epsnew = epsnew * Math.Max(Math.Abs(xs), 1) * Math.Sign(xs);
                }
                epsnew = epsnew / w.L2NormPow2().MPISum().Sqrt();

                var del = currentX.CloneAs();

                del.AccV(epsnew, w);

                double[] temp = new double[SolutionVec.Length];

                temp.CopyEntries(SolutionVec);

                this.CurrentLin.TransformSolFrom(SolutionVec, del);

                // Just evaluate linearized operator
                //var OpAffineRaw = this.LinearizationRHS.CloneAs();
                //this.CurrentLin.OperatorMatrix.SpMV(1.0, new CoordinateVector(SolutionVec.Mapping.Fields.ToArray()), 1.0, OpAffineRaw);
                //CurrentLin.TransformRhsInto(OpAffineRaw, fx);
                if (linearization == false)
                {
                    EvaluateOperator(1.0, SolutionVec.Mapping.Fields, fx);
                }
                //else {
                //    this.m_AssembleMatrix(out OpMtxRaw, out OpAffineRaw, out MassMtxRaw, SolutionVec.Mapping.Fields.ToArray(), true);
                //    OpMtxRaw.SpMV(1.0, new CoordinateVector(SolutionVec.Mapping.Fields.ToArray()), 1.0, OpAffineRaw);
                //    CurrentLin.TransformRhsInto(OpAffineRaw, fx);
                //}

                SolutionVec.CopyEntries(temp);

                // (f1 - f0) / epsnew
                fx.AccV(1, f0);
                fx.ScaleV(1 / epsnew);

                return(fx);
            }
        }
        void DoCallBack <V>(double[] Velocity, double[] Pressure, V RHS)
            where V : IList <double> //
        {
            if (this.IterationCallback != null)
            {
                int      LL  = this.m_MgOp.Mapping.LocalLength;
                double[] sol = new double[LL];
                double[] res = new double[LL];

                res.SetV(RHS);
                sol.AccV(1.0, Velocity, USubMatrixIdx_Row, default(int[]));
                sol.AccV(1.0, Pressure, PSubMatrixIdx_Row, default(int[]));

                this.m_MgOp.OperatorMatrix.SpMV(-1.0, sol, 1.0, res);

                this.IterationCallback(this.NoOfIterations, sol, res, this.m_MgOp);
            }
        }
        /// <summary>
        /// returns the subvector
        /// corresponding to <see cref="BlockMask"/>.
        /// Entries of subvector are taken from the local (<paramref name="locFullVector"/>)
        /// and external (<paramref name="extFullVector"/>) part of the unmasked vector.
        /// </summary>
        /// <param name="extFullVector">input, external part of unmasked vector</param>
        /// <param name="locfullVector">input, local part of unmasked vector</param>
        /// <returns></returns>
        public double[] GetSubVec(IList <double> extFullVector, IList <double> locfullVector)
        {
            if (BMExt == null)
            {
                return(GetSubVec(locfullVector));
            }
            int SubL          = BMExt.LocalDOF + BMLoc.LocalDOF;
            var subvector     = new double[SubL];
            int acc_offset    = BMLoc.LocalDOF;
            int target_offset = m_map.LocalLength;

            if (BMExt != null && BMExt.LocalDOF > 0)
            {
                subvector.AccV(1.0, extFullVector, default(int[]), BMExt.m_LocalMask, acc_index_shift: acc_offset, b_index_shift: (-target_offset));
            }
            if (BMLoc != null && BMLoc.LocalDOF > 0)
            {
                subvector.AccV(1.0, locfullVector, default(int[]), BMLoc.m_LocalMask);
            }
            return(subvector);
        }
Exemple #11
0
        public static void SplitVectorOperations(
            XDGusage UseXdg,
            int DGOrder,
            MatrixShape MShape
            )
        {
            Utils.TestInit((int)UseXdg, DGOrder, (int)MShape);
            Console.WriteLine("SplitVectorOperations({0},{1},{2})", UseXdg, DGOrder, MShape);

            //matrix Erzeugung wie in ExtractDiagonalCellBlocks...
            //Auf der HierarchieEbene, auf der Kopplung ausgesetzt wird kann Auswahl vorgenommen werden
            //bei var: 0 / 1, bei DG: <=1 / >1, bei spec: A / B, bei Cells: odd / even
            //accumulierte Teilergebnisse sind dann == fullM*fullX
            var mop = Utils.CreateTestMGOperator(UseXdg, DGOrder, MShape);
            var map = mop.Mapping;

            double[] Vec = Utils.GetRandomVector(mop.Mapping.LocalLength);

            //Arrange --- setup masking
            SubBlockSelector sbsA = new SubBlockSelector(map);

            sbsA.SetDefaultSplitSelection(MShape, true);
            BlockMask maskA = new BlockMask(sbsA, null);

            SubBlockSelector sbsB = new SubBlockSelector(map);

            sbsB.SetDefaultSplitSelection(MShape, false);
            BlockMask maskB = new BlockMask(sbsB, null);

            double[] VecAB = new double[Vec.Length];

            //Arrange --- some time measurement
            Stopwatch stw = new Stopwatch();

            stw.Reset();

            //Act ---
            stw.Start();
            var VecA = maskA.GetSubVec(Vec);
            var VecB = maskB.GetSubVec(Vec);

            maskA.AccSubVec(VecA, VecAB);
            maskB.AccSubVec(VecB, VecAB);
            stw.Stop();

            Debug.Assert(Vec.L2Norm() != 0);
            double fac = ((MShape == MatrixShape.full_var || MShape == MatrixShape.diagonal_var) && UseXdg == XDGusage.none) ? -2.0 : -1.0;

            VecAB.AccV(fac, Vec);

            //Assert --- are extracted blocks and
            Assert.IsTrue(VecAB.L2Norm() == 0.0, String.Format("L2Norm neq 0!"));
        }
Exemple #12
0
        public static void VectorSplitOperation(
            [Values(XDGusage.none, XDGusage.all)] XDGusage UseXdg,
            [Values(2)] int DGOrder,
            [Values(MatrixShape.full_var_spec, MatrixShape.full_spec, MatrixShape.full)] MatrixShape MShape,
            [Values(4)] int Res)
        {
            Utils.TestInit((int)UseXdg, DGOrder, (int)MShape, Res);
            Console.WriteLine("VectorSplitOperation({0},{1},{2},{3})", UseXdg, DGOrder, MShape, Res);

            //Arrange --- create test matrix, MG mapping
            MultigridOperator mgo   = Utils.CreateTestMGOperator(UseXdg, DGOrder, MShape, Res);
            MultigridMapping  map   = mgo.Mapping;
            BlockMsrMatrix    M     = mgo.OperatorMatrix;
            BlockMsrMatrix    M_ext = BlockMask.GetAllExternalRows(map, M);

            double[] Vec = Utils.GetRandomVector(M_ext.RowPartitioning.LocalLength);

            //Arrange --- setup masking
            SubBlockSelector sbsA = new SubBlockSelector(map);

            sbsA.SetDefaultSplitSelection(MShape, true, false);
            BlockMask maskA = new BlockMask(sbsA, M_ext);

            SubBlockSelector sbsB = new SubBlockSelector(map);

            sbsB.SetDefaultSplitSelection(MShape, false, false);
            BlockMask maskB = new BlockMask(sbsB, M_ext);

            double[] VecAB = new double[Vec.Length];

            //Arrange --- some time measurement
            Stopwatch stw = new Stopwatch();

            stw.Reset();

            //Act ---
            stw.Start();
            var VecA = maskA.GetSubVec(Vec, new double[0]);
            var VecB = maskB.GetSubVec(Vec, new double[0]);

            maskA.AccSubVec(VecA, VecAB, new double[0]);
            maskB.AccSubVec(VecB, VecAB, new double[0]);
            stw.Stop();

            Debug.Assert(Vec.L2Norm() != 0);
            double fac = ((MShape == MatrixShape.full_var || MShape == MatrixShape.diagonal_var) && UseXdg == XDGusage.none) ? -2.0 : -1.0;

            VecAB.AccV(fac, Vec);

            //Assert --- are extracted blocks and
            Assert.IsTrue(VecAB.L2Norm() == 0.0, String.Format("L2Norm neq 0!"));
        }
Exemple #13
0
        public void Solve <U, V>(U X, V B)
            where U : IList <double>
            where V : IList <double> //
        {
            int NoParts = this.BlockIndices.Length;

            for (int iIter = 0; iIter < m_MaxIterations; iIter++)
            {
                this.NoIter++;
                double[] Res = B.ToArray();
                this.MtxFull.SpMV(-1.0, X, 1.0, Res);

                if (IterationCallback != null)
                {
                    IterationCallback(iIter, X.ToArray(), Res.CloneAs(), this.m_MgOp);
                }

                if (CoarseSolver != null)
                {
                    var      XC = X.ToArray().CloneAs();
                    double[] bc = new double[m_MgOp.CoarserLevel.Mapping.TotalLength];// = Res.CloneAs();
                    m_MgOp.CoarserLevel.Restrict(Res.CloneAs(), bc);
                    double[] xc = new double[bc.Length];
                    CoarseSolver.Solve(xc, bc);
                    m_MgOp.CoarserLevel.Prolongate(1, XC, 1, xc);
                    X.AccV(1.0, XC);

                    if (CoarseSolverIsMultiplicative)
                    {
                        Res.SetV(B);
                        this.MtxFull.SpMV(-1.0, X, 1.0, Res);
                    }
                }

                for (int iPart = 0; iPart < NoParts; iPart++)
                {
                    int[] ci = BlockIndices[iPart];
                    int   L  = ci.Length;

                    double[] bi = new double[L];
                    double[] xi = new double[L];
                    bi.AccV(1.0, Res, default(int[]), ci);

                    blockSolvers[iPart].Solve(xi, bi);


                    X.AccV(1.0, xi, ci, default(int[]));
                }
            }
        }
 /// <summary>
 /// returns the subvector of <paramref name="fullVector"/>
 /// corresponding to <see cref="BlockMask"/>.
 /// </summary>
 /// <param name="fullVector">input, unmasked vector</param>
 public double[] GetSubVec(IList <double> fullVector)
 {
     double[] subVector;
     if (m_includeExternalCells)
     {
         if (fullVector.Count() != GetLocalandExternalDOF(m_map))
         {
             throw new ArgumentException("Length of targetVector not equal Length of original");
         }
         subVector = new double[BMLoc.LocalDOF + BMExt.LocalDOF];
         subVector.AccV(1.0, fullVector, default(int[]), BMLoc.m_LocalMask);
         subVector.AccV(1.0, fullVector, default(int[]), BMExt.m_LocalMask, acc_index_shift: BMLoc.LocalDOF);
     }
     else
     {
         if (fullVector.Count() != m_map.LocalLength)
         {
             throw new ArgumentException("Length of targetVector not equal Length of original");
         }
         subVector = new double[BMLoc.LocalDOF];
         subVector.AccV(1.0, fullVector, default(int[]), BMLoc.m_LocalMask);
     }
     return(subVector);
 }
Exemple #15
0
        public static void CellBlockVectorOperations(
            [Values(XDGusage.none, XDGusage.all)] XDGusage UseXdg,
            [Values(2)] int DGOrder,
            [Values(MatrixShape.diagonal, MatrixShape.diagonal_var, MatrixShape.diagonal_spec, MatrixShape.diagonal_var_spec)] MatrixShape MShape
            )
        {
            //matrix Erzeugung wie in ExtractDiagonalCellBlocks...
            //Auf der HierarchieEbene, auf der Kopplung ausgesetzt wird kann Auswahl vorgenommen werden
            //bei var: 0 / 1, bei DG: <=1 / >1, bei spec: A / B, bei Cells: odd / even
            //accumulierte Teilergebnisse sind dann == fullM*fullX

            Utils.TestInit((int)UseXdg, DGOrder, (int)MShape);
            Console.WriteLine("CellBlockVectorOperations({0},{1},{2})", UseXdg, DGOrder, MShape);

            var mop = Utils.CreateTestMGOperator(UseXdg, DGOrder, MShape);
            var map = mop.Mapping;

            double[] Vec = Utils.GetRandomVector(mop.Mapping.LocalLength);

            //Arrange --- setup masking
            SubBlockSelector SBS = new SubBlockSelector(map);

            BlockMask mask = new BlockMask(SBS, null);

            //Arrange --- some time measurement
            Stopwatch stw = new Stopwatch();

            stw.Reset();

            //Assert --- all diagonal blocks are extracted
            //Assert.IsTrue(blocks.Length == map.LocalNoOfBlocks);

            double[] Vec_col = new double[map.LocalLength];

            for (int i = 0; i < map.LocalNoOfBlocks; i++)
            {
                stw.Start();
                double[] Vec_i = mask.GetSubVecOfCell(Vec, i);
                mask.AccSubVecOfCell(Vec_i, i, Vec_col);
                stw.Stop();
            }
            Vec_col.AccV(-1.0, Vec);

            //Assert --- are extracted blocks and
            Assert.IsTrue(Vec_col.L2Norm() == 0.0, String.Format("L2Norm neq 0!"));
        }
Exemple #16
0
        /// <summary>
        /// Calculate Extension
        /// </summary>
        public void ConstructExtension(IList <DGField> InterfaceValue = null, bool nearfield = false)
        {
            using (new FuncTrace()) {
                Extension.Clear(nearfield ? LevelSetTracker.Regions.GetNearFieldMask(1) : null);
                ComputeMatrices(InterfaceValue ?? InterfaceParams, nearfield);

                //Solve System
                double[] RHS = OpAffine.CloneAs();
                RHS.ScaleV(-1.0);

                ISparseSolver slv = Control.solverFactory();

                if (nearfield)
                {
                    SubGrid   subGrid     = LevelSetTracker.Regions.GetNearFieldSubgrid(1);
                    int[]     SubVecIdx   = Extension.Mapping.GetSubvectorIndices(subGrid, true, new int[] { 0 });
                    int       L           = SubVecIdx.Length;
                    MsrMatrix SubMatrix   = new MsrMatrix(L);
                    double[]  SubRHS      = new double[L];
                    double[]  SubSolution = new double[L];

                    OpMatrix.AccSubMatrixTo(1.0, SubMatrix, SubVecIdx, default(int[]), SubVecIdx, default(int[]));


                    SubRHS.Clear();
                    SubSolution.Clear();

                    SubRHS.AccV(1.0, RHS, default(int[]), SubVecIdx);
                    SubSolution.AccV(1.0, Extension.CoordinateVector, default(int[]), SubVecIdx);

                    slv.DefineMatrix(SubMatrix);
                    slv.Solve(SubSolution, SubRHS);

                    Extension.Clear(subGrid.VolumeMask);
                    Extension.CoordinateVector.AccV(1.0, SubSolution, SubVecIdx, default(int[]));
                }
                else
                {
                    slv.DefineMatrix(OpMatrix);
                    slv.Solve(Extension.CoordinateVector, RHS);
                }
                slv.Dispose();
            }
        }
            /// <summary>
            /// Center-of-gravity
            /// </summary>
            public double[] GetCenter(int jCell)
            {
                int    D      = m_Owner.SpatialDimension;
                double VolAcc = 0.0;

                double[] CenAcc = new double[D];

                foreach (int jG in this.AggregateCellToParts[jCell])
                {
                    double Vol    = m_Owner.m_GeomCellData.GetCellVolume(jG);
                    var    g_cent = m_Owner.m_GeomCellData.GetCenter(jG);

                    VolAcc += Vol;
                    CenAcc.AccV(Vol, g_cent);
                }

                CenAcc.ScaleV(1 / VolAcc);
                return(CenAcc);
            }
Exemple #18
0
        public void VelocityPredictor(double[] PressureEstimateIn, double[] VelocityEstimateIn, double[] VelocityPrediction, double[] RHSMomentum)
        {
            using (new FuncTrace()) {
                double m_relax_vel = m_SIMPLEOptions.relax_v;

                //build Matrix
                var PredictorMX = ConvDiff.CloneAs();


                //underrelaxation LHS
                if (m_relax_vel <= 0.0)
                {
                    throw new ArithmeticException("Illegal velocity underrelaxation parameter: " + m_relax_vel);
                }

                PredictorMX.Acc((1 - m_relax_vel) / m_relax_vel, Aapprox);


#if DEBUG
                PredictorMX.CheckForNanOrInfM();
#endif


                // build RHS: b1-grad*p (+ oldVelocities/dt)
                double[] RHS = new double [RHSMomentum.Length];
                RHS.AccV(1.0, RHSMomentum);
                PressureGrad.SpMVpara(-1.0, PressureEstimateIn, 1.0, RHS);

                //underrelaxation RHS
                Aapprox.SpMVpara((1 - m_relax_vel) / m_relax_vel, VelocityEstimateIn, 1.0, RHS);

                // solve
                using (ISparseSolver solver = m_SIMPLEOptions.ViscousSolver) {
                    //Agglomerator.ClearAgglomerated(RHS, VelocityMapping);
                    //double SolverResidual = PC.SolveDirect(VelocityPrediction.CoordinateVector, RHS, solver, false);
                    //solver.Dispose();
                    solver.DefineMatrix(PredictorMX);
                    solver.Solve(VelocityPrediction, RHS);
                }
            }
        }
Exemple #19
0
        public void ImplicitEuler(double dt, SubGrid S, SinglePhaseField inout_Levset)
        {
            var VolMsk = S.VolumeMask;
            var EdgMsk = S.InnerEdgesMask;
            UnsetteledCoordinateMapping Map = inout_Levset.Mapping;

            if (dt <= 0.0)
            {
                throw new ArgumentOutOfRangeException("Timestep size must be greater than 0.");
            }

            MsrMatrix Pmtx = PenaltyMatrix(EdgMsk, inout_Levset.Basis, inout_Levset.Basis);

            Pmtx.Scale(-1.0);

            int[] SubVecIdx = Map.GetSubvectorIndices(S, true, new int[] { 0 });
            int   L         = SubVecIdx.Length;

            MsrMatrix SubMtx = new MsrMatrix(L, L);

            Pmtx.AccSubMatrixTo(1.0, SubMtx, SubVecIdx, default(int[]), SubVecIdx, default(int[]));

            SubMtx.AccEyeSp(1.0 / dt);

            double[] RHS = new double[L];
            double[] SOL = new double[L];

            RHS.AccV(1.0 / dt, inout_Levset.CoordinateVector, default(int[]), SubVecIdx);

            using (var solver = new PARDISOSolver()) {
                solver.DefineMatrix(SubMtx);
                solver.Solve(SOL, RHS);
            }

            inout_Levset.CoordinateVector.ClearEntries(SubVecIdx);
            inout_Levset.CoordinateVector.AccV(1.0, SOL, SubVecIdx, default(int[]));
        }
        /// <summary>
        /// coarsens level <paramref name="ag"/>
        /// </summary>
        public static AggregationGrid Coarsen(IGridData ag)
        {
            using (new FuncTrace()) {
                int J = ag.iLogicalCells.NoOfLocalUpdatedCells;
                int D = ag.SpatialDimension;

                // sort cells of parent grid by size:
                // we want to aggregate the smallest cells at first.
                int[] Perm = J.ForLoop(j => j).OrderBy(j => ag.iLogicalCells.GetCellVolume(j)).ToArray();

                BitArray UsedCellMarker = new BitArray(J);

                List <int[]> Coarsened_ComositeCells = new List <int[]>();
                //List<double> Coarsened_CompositeVolume = new List<double>();
                //List<BoundingBox> Coarsened_CompositeCellBB = new List<BoundingBox>();
                int[]        Parent2Child  = new int[J];
                List <int[]> child2Parrent = new List <int[]>();


                // loop over aggregated cells of parent grid...
                int[][] Neighbourship = ag.iLogicalCells.CellNeighbours;
                for (int i = 0; i < J; i++)
                {
                    int jCell = Perm[i];
                    Debug.Assert(Neighbourship[jCell].Contains(jCell) == false);
                    if (!UsedCellMarker[jCell])
                    {
                        // list of all neighbor cells which were not already aggregated to some other cell:
                        int[] UnusedNeighs = Neighbourship[jCell].Where(j => j < J && !UsedCellMarker[j]).ToArray();
                        int   NN           = UnusedNeighs.Length;

                        if (NN > 0)
                        {
                            double[]      sizes       = new double[NN];
                            BoundingBox[] aggBB       = new BoundingBox[NN];
                            double[]      aggBBaspect = new double[NN];
                            for (int iNeig = 0; iNeig < NN; iNeig++)
                            {
                                int jCellNeigh = UnusedNeighs[iNeig];

                                aggBB[iNeig] = new BoundingBox(D); //ag.CompositeCellBB[jCell].CloneAs();
                                ag.iLogicalCells.GetCellBoundingBox(jCell, aggBB[iNeig]);

                                BoundingBox NeighBB = new BoundingBox(D);
                                ag.iLogicalCells.GetCellBoundingBox(jCellNeigh, NeighBB);

                                aggBB[iNeig].AddBB(NeighBB);
                                sizes[iNeig]       = ag.iLogicalCells.GetCellVolume(jCell) + ag.iLogicalCells.GetCellVolume(jCellNeigh);
                                aggBBaspect[iNeig] = aggBB[iNeig].AspectRatio;
                            }

                            double[] RelSizes   = sizes.CloneAs(); RelSizes.ScaleV(1.0 / sizes.Max());
                            double[] RelAspects = aggBBaspect.CloneAs(); RelAspects.ScaleV(1.0 / aggBBaspect.Max());

                            double[] Quality = new double[NN];
                            Quality.AccV(0.7, RelSizes);
                            Quality.AccV(0.3, RelAspects);

                            int iChoice     = Quality.IndexOfMin(q => q);
                            int jNeigChoice = UnusedNeighs[iChoice];

                            //int[] CCC = ArrayTools.Cat(ag.AggregateCells[jCell], ag.AggregateCells[jNeigChoice]);
                            int[] CCC = new int[] { jCell, jNeigChoice };
                            Coarsened_ComositeCells.Add(CCC);
                            //Coarsened_CompositeCellBB.Add(aggBB[iChoice]);
                            //Coarsened_CompositeVolume.Add(sizes[iChoice]);
                            Debug.Assert(jCell != jNeigChoice);
                            child2Parrent.Add(new int[] { jCell, jNeigChoice });
                            Parent2Child[jCell]       = Coarsened_ComositeCells.Count - 1;
                            Parent2Child[jNeigChoice] = Coarsened_ComositeCells.Count - 1;


                            UsedCellMarker[jNeigChoice] = true;
                            UsedCellMarker[jCell]       = true;
                        }
                        else
                        {
                            // No neighbour available => unable to coarsen

                            Coarsened_ComositeCells.Add(new int[] { jCell });
                            //Coarsened_ComositeCells.Add(ag.AggregateCells[jCell]);
                            //Coarsened_CompositeCellBB.Add(ag.CompositeCellBB[jCell].CloneAs());
                            //Coarsened_CompositeVolume.Add(ag.CompositeVolume[jCell]);
                            child2Parrent.Add(new int[] { jCell });
                            Parent2Child[jCell] = Coarsened_ComositeCells.Count - 1;

                            UsedCellMarker[jCell] = true;
                        }
                    }
                    else
                    {
                        // cell already done.
                        continue;
                    }
                }
                Debug.Assert(UsedCellMarker.ToBoolArray().Where(b => !b).Count() == 0, "some cell was not processed.");

                // return
                // ======
                return(new AggregationGrid(ag, Coarsened_ComositeCells.ToArray()));
            }
        }
        //protected override void TriggerLevelSetUpdate() {
        //    throw new NotImplementedException();
        //}



        private void RKstageExplicit(double PhysTime, double dt, double[][] k, int s, BlockMsrMatrix[] Mass, CoordinateVector u0, double ActualLevSetRelTime, double[] RK_as, double RelTime)
        {
            Debug.Assert(s <= m_RKscheme.Stages);
            for (int i = 0; i < s; i++)
            {
                Debug.Assert(k[i] != null);
            }


            int            Ndof = CurrentStateMapping.LocalLength;
            BlockMsrMatrix System;

            double[] RHS = new double[Ndof];


            if (RelTime > 0)
            {
                //
                // some ordinary stage above stage 0
                //

                if (base.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative ||
                    base.Config_LevelSetHandling == LevelSetHandling.Coupled_Once)
                {
                    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    // Moving interface, RK stage 'i':
                    // (c[s]/dt)*(Ms*us - M0*u0) + sum(k[l]*a[s,l], 0 <= l < s)) = 0
                    // For explicit timestepping, both versions of level-set coupling
                    // will lead to identical results.
                    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    // move level-set:
                    if (Math.Abs(ActualLevSetRelTime - RelTime) > 1.0e-14)
                    {
                        this.m_LsTrk.PushStacks();
                        this.MoveLevelSetAndRelatedStuff(u0.Mapping.Fields.ToArray(), PhysTime, dt * RelTime, IterUnderrelax, Mass, k);

                        this.UpdateAgglom(false);
                        BlockMsrMatrix PM, SM;
                        UpdateMassMatrix(out PM, out SM, PhysTime + dt * RelTime);
                        Mass[1] = SM;
                    }

                    var M0 = Mass[0];
                    var Ms = Mass[1];

                    // left-hand-side
                    if (Ms != null)
                    {
                        System = Ms.CloneAs();
                        System.Scale(1.0 / dt);
                    }
                    else
                    {
                        Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity);
                        System = null;
                    }

                    // right-hand-side
                    if (M0 != null)
                    {
                        M0.SpMV(1.0 / dt, u0, 0.0, RHS);
                    }
                    else
                    {
                        Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity);
                        RHS.SetV(u0, 1.0 / dt);
                    }
                    for (int l = 0; l < s; l++)
                    {
                        if (RK_as[l] != 0.0)
                        {
                            RHS.AccV(-RK_as[l], k[l]);
                        }
                    }
                }
                else if (base.Config_LevelSetHandling == LevelSetHandling.LieSplitting ||
                         base.Config_LevelSetHandling == LevelSetHandling.StrangSplitting ||
                         base.Config_LevelSetHandling == LevelSetHandling.None)
                {
                    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    // Level-Set-Splitting: Mass matrix remains constant during Runge-Kutta
                    // Stage:
                    // (c[s]/dt)*M0*(us - u0) + sum(k[l]*a[s,l], l=0..(s-1)) = 0
                    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    //Debug.Assert(Mass.Length == 1);       // Uncommented for usage in XDGShock
                    var Ms = Mass[0];

                    // left-hand-side
                    if (Ms != null)
                    {
                        System = Ms.CloneAs();
                        System.Scale(1.0 / dt);
                    }
                    else
                    {
                        Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity);
                        System = null;
                    }

                    // right-hand-side
                    if (Ms != null)
                    {
                        Ms.SpMV(1.0 / dt, u0, 0.0, RHS);
                    }
                    else
                    {
                        Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity);
                        RHS.SetV(u0, 1.0 / dt);
                    }
                    for (int l = 0; l < s; l++)
                    {
                        if (RK_as[l] != 0.0)
                        {
                            RHS.AccV(-RK_as[l], k[l]);
                        }
                    }
                }
                else
                {
                    throw new NotImplementedException();
                }

                // solve system
                if (System != null)
                {
                    Debug.Assert(object.ReferenceEquals(m_CurrentAgglomeration.Tracker, m_LsTrk));
                    m_CurrentAgglomeration.ManipulateMatrixAndRHS(System, RHS, this.CurrentStateMapping, this.CurrentStateMapping);
                    BlockSol(System, m_CurrentState, RHS);
                    m_CurrentAgglomeration.Extrapolate(this.CurrentStateMapping);
                }
                else
                {
                    // system is diagonal: 1/dt
                    m_CurrentState.SetV(RHS, dt);
                }
            }
            else
            {
                // +++++++++++++++++++++++++++
                // this is probably stage zero
                // +++++++++++++++++++++++++++

                m_CurrentState.Clear();
                m_CurrentState.Acc(1.0, u0);
            }
        }
        /// <summary>
        /// Matrix/Affine assembly in the case of an implicit RK stage.
        /// </summary>
        protected override void AssembleMatrixCallback(out BlockMsrMatrix System, out double[] Affine, out BlockMsrMatrix PcMassMatrix, DGField[] argCurSt, bool Linearization)
        {
            if (Linearization == false)
            {
                throw new NotImplementedException("todo");
            }

            int Ndof = m_CurrentState.Count;

            // copy data from 'argCurSt' to 'CurrentStateMapping', if necessary
            // -----------------------------------------------------------
            DGField[] locCurSt = CurrentStateMapping.Fields.ToArray();
            if (locCurSt.Length != argCurSt.Length)
            {
                throw new ApplicationException();
            }
            int NF = locCurSt.Length;

            for (int iF = 0; iF < NF; iF++)
            {
                if (object.ReferenceEquals(locCurSt[iF], argCurSt[iF]))
                {
                    // nothing to do
                }
                else
                {
                    locCurSt[iF].Clear();
                    locCurSt[iF].Acc(1.0, argCurSt[iF]);
                }
            }

            // update of level-set
            // ----------------------

            bool updateAgglom = false;

            if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once && m_ImplStParams.m_IterationCounter == 0 ||
                this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative)
            {
                //MoveLevelSetAndRelatedStuff(locCurSt, m_CurrentPhystime, m_CurrentDt, 1.0);
                if (Math.Abs(m_ImplStParams.m_ActualLevSetRelTime - m_ImplStParams.m_RelTime) > 1.0e-14)
                {
                    if (m_ImplStParams.m_IterationCounter <= 0)// only push tracker in the first iter
                    {
                        m_LsTrk.PushStacks();
                    }
                    MoveLevelSetAndRelatedStuff(locCurSt,
                                                m_ImplStParams.m_CurrentPhystime, m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime, IterUnderrelax,
                                                m_ImplStParams.m_Mass, m_ImplStParams.m_k);

                    // note that we need to update the agglomeration
                    updateAgglom = true;
                }
            }

            // update agglomeration
            // --------------------
#if DEBUG
            if (this.Config_LevelSetHandling == LevelSetHandling.LieSplitting || this.Config_LevelSetHandling == LevelSetHandling.StrangSplitting)
            {
                Debug.Assert(m_CurrentAgglomeration != null);
                Debug.Assert(m_PrecondMassMatrix != null);
                // ensure, that, when splitting is used we update the agglomerator in the very first iteration.
            }
#endif
            if (updateAgglom || m_CurrentAgglomeration == null)
            {
                this.UpdateAgglom(m_ImplStParams.m_IterationCounter > 0);



                // update Multigrid-XDG basis
                base.MultigridBasis.UpdateXdgAggregationBasis(m_CurrentAgglomeration);
            }


            // mass matrix update
            // ------------------

            if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity)
            {
                // may occur e.g. if one runs the FSI solver as a pure single-phase solver,
                // i.e. if the Level-Set is outside the domain.

                PcMassMatrix = null;
            }
            else
            {
                // checks:
                Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity ||
                             this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeDependent ||
                             this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeAndSolutionDependent,
                             "Something is not implemented here.");
                if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity &&
                    Config_LevelSetHandling != LevelSetHandling.None)
                {
                    throw new NotSupportedException("Illegal configuration;");
                }

                if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative)
                {
                    if ((this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity && m_PrecondMassMatrix == null) || // compute mass matrix (only once in application lifetime)
                        (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeDependent && m_ImplStParams.m_IterationCounter == 0) || // compute mass matrix once per timestep
                        (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeAndSolutionDependent) // re-compute mass matrix in every iteration
                        )
                    {
                        BlockMsrMatrix PM, SM;
                        UpdateMassMatrix(out PM, out SM, m_ImplStParams.m_CurrentPhystime + m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime);
                        m_ImplStParams.m_Mass[1] = SM;
                        m_PrecondMassMatrix      = PM;
                    }
                }

                PcMassMatrix = m_PrecondMassMatrix;
            }

            // operator matrix update
            // ----------------------

            // we perform the extrapolation to have valid parameters if
            // - the operator matrix depends on these values
            this.m_CurrentAgglomeration.Extrapolate(CurrentStateMapping);

            var OpMatrix = new BlockMsrMatrix(CurrentStateMapping);
            var OpAffine = new double[Ndof];

            this.ComputeOperatorMatrix(OpMatrix, OpAffine, CurrentStateMapping, locCurSt, base.GetAgglomeratedLengthScales(), m_ImplStParams.m_CurrentPhystime + m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime);


            // assemble system
            // ---------------

            double dt = m_ImplStParams.m_CurrentDt;

            // select mass matrix (and some checks)
            double[]       RHS = new double[Ndof];
            BlockMsrMatrix MamaRHS, MamaLHS;
            if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once ||
                this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative)
            {
                Debug.Assert(m_ImplStParams.m_Mass.Length == 2);
                MamaRHS = m_ImplStParams.m_Mass[0];
                MamaLHS = m_ImplStParams.m_Mass[1];
            }
            else if (this.Config_LevelSetHandling == LevelSetHandling.LieSplitting ||
                     this.Config_LevelSetHandling == LevelSetHandling.StrangSplitting ||
                     this.Config_LevelSetHandling == LevelSetHandling.None)
            {
                Debug.Assert(m_ImplStParams.m_Mass.Length == 1);
                MamaRHS = m_ImplStParams.m_Mass[0];
                MamaLHS = m_ImplStParams.m_Mass[0];
            }
            else
            {
                throw new NotImplementedException();
            }

            // right-hand-side, resp. affine vector
            if (MamaRHS != null)
            {
                MamaRHS.SpMV(1.0 / dt, m_ImplStParams.m_u0, 0.0, RHS);
            }
            else
            {
                Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity);
                RHS.SetV(m_ImplStParams.m_u0, 1.0 / dt);
            }
            for (int l = 0; l < m_ImplStParams.m_s; l++)
            {
                if (m_ImplStParams.m_RK_as[l] != 0.0)
                {
                    RHS.AccV(-m_ImplStParams.m_RK_as[l], m_ImplStParams.m_k[l]);
                }
            }

            Affine = RHS;
            Affine.ScaleV(-1.0);
            Affine.AccV(m_ImplStParams.m_RK_as[m_ImplStParams.m_s], OpAffine);

            // left-hand-side
            System = OpMatrix.CloneAs();
            System.Scale(m_ImplStParams.m_RK_as[m_ImplStParams.m_s]);
            if (MamaLHS != null)
            {
                System.Acc(1.0 / dt, MamaLHS);
            }
            else
            {
                System.AccEyeSp(1.0 / dt);
            }

            // perform agglomeration
            // ---------------------
            Debug.Assert(object.ReferenceEquals(m_CurrentAgglomeration.Tracker, m_LsTrk));
            m_CurrentAgglomeration.ManipulateMatrixAndRHS(System, Affine, CurrentStateMapping, CurrentStateMapping);

            // increase iteration counter
            // --------------------------
            m_ImplStParams.m_IterationCounter++;
        }
Exemple #23
0
        /// <summary>
        /// projects some DG field onto this
        /// </summary>
        /// <param name="alpha"></param>
        /// <param name="DGField"></param>
        /// <param name="_cm">optional restriction to computational domain</param>
        /// <remarks>
        /// This method computes an exact
        /// L2-projection of the DG-field onto the SpecFEM-space, so a global linear system, which contains all
        /// DOF's, has to be solved.
        /// In contrast, <see cref="ProjectDGFieldCheaply"/> performs an approximate projection which only involves
        /// local operations for each cell.
        /// </remarks>
        public void ProjectDGField(double alpha, ConventionalDGField DGField, CellMask _cm = null)
        {
            using (var trx = new Transceiver(this.Basis)) {
                CellMask cm = _cm;
                if (cm == null)
                {
                    cm = CellMask.GetFullMask(this.Basis.GridDat);
                }


                int J        = m_Basis.GridDat.Cells.NoOfLocalUpdatedCells;
                var Trafo    = m_Basis.GridDat.ChefBasis.Scaling;
                var C2N      = m_Basis.CellNode_To_Node;
                var MtxM2N   = m_Basis.m_Modal2Nodal;
                var CellData = this.Basis.GridDat.Cells;

                // compute RHS
                // ===========

                var b = MultidimensionalArray.Create(this.m_Basis.NoOfLocalNodes);
                {
                    int[]      _K = m_Basis.NodesPerCell;
                    int        L  = m_Basis.ContainingDGBasis.Length;
                    double[][] _NodalCoordinates = _K.Select(K => new double[K]).ToArray(); // temporary storage for nodal coordinates per cell
                                                                                            // 1st idx: ref. elm., 2nd idx: node index
                    double[] ModalCoordinates = new double[L];

                    foreach (Chunk cnk in cm)
                    {
                        int j0 = cnk.i0;
                        int jE = cnk.JE;
                        for (int j = j0; j < jE; j++)   // loop over cells...
                        {
                            int      iKref            = CellData.GetRefElementIndex(j);
                            double[] NodalCoordinates = _NodalCoordinates[iKref];
                            int      K = _K[iKref];

                            if (!CellData.IsCellAffineLinear(j))
                            {
                                throw new NotSupportedException();
                            }

                            // Get DG coordinates
                            Array.Clear(ModalCoordinates, 0, L);
                            int Lmin = Math.Min(L, DGField.Basis.GetLength(j));
                            for (int l = 0; l < Lmin; l++)
                            {
                                ModalCoordinates[l] = DGField.Coordinates[j, l];
                            }

                            var tr = 1.0 / Trafo[j];

                            // transform
                            //DGField.Coordinates.GetRow(j, ModalCoordinates);
                            ModalCoordinates.ClearEntries();
                            for (int l = 0; l < Lmin; l++)
                            {
                                ModalCoordinates[l] = DGField.Coordinates[j, l];
                            }
                            MtxM2N[iKref].GEMV(tr, ModalCoordinates, 0.0, NodalCoordinates, transpose: true);

                            // collect coordinates for cell 'j':
                            for (int k = 0; k < K; k++)
                            {
                                int _c2n = C2N[j, k];
                                b[_c2n] += NodalCoordinates[k];
                            }
                        }
                    }
                }

                trx.AccumulateGather(b);

                /*
                 *
                 * var bcheck = new double[b.Length];
                 * {
                 *  var polys = this.Basis.NodalBasis;
                 *
                 *
                 *  CellQuadrature.GetQuadrature(new int[] { K },
                 *      this.Basis.GridDat.Context,
                 *      (new CellQuadratureScheme()).Compile(this.Basis.GridDat, this.Basis.ContainingDGBasis.Degree*2),
                 *      delegate(MultidimensionalArray NodesUntransformed) { // Del_CreateNodeSetFamily
                 *          var NSC = this.Basis.GridDat.Context.NSC;
                 *          return new NodeSetController.NodeSetContainer[] { NSC.CreateContainer(NodesUntransformed) };
                 *      },
                 *      delegate(int i0, int Length, int _NoOfNodes, MultidimensionalArray EvalResult) {
                 *          var PolyAtNode = MultidimensionalArray.Create(K, _NoOfNodes);
                 *          for (int k = 0; k < K; k++) {
                 *              polys[k].Evaluate(PolyAtNode.ExtractSubArrayShallow(k, -1), this.Basis.GridDat.Context.NSC.Current_NodeSetFamily[0].NodeSet);
                 *          }
                 *
                 *          var DGFatNodes = MultidimensionalArray.Create(Length, _NoOfNodes);
                 *          DGField.Evaluate(i0, Length, 0, DGFatNodes);
                 *
                 *          //for(int i = 0; i < Length; i++) {
                 *          //    for (int n = 0; n < _NoOfNodes; n++) {
                 *          //        for (int k = 0; k < K; k++) {
                 *          //            for (int l = 0; l < K; l++) {
                 *          //                EvalResult[i, n, k, l] = PolyAtNode[k, n]*PolyAtNode[l, n];
                 *          //            }
                 *          //        }
                 *          //    }
                 *          //}
                 *
                 *          EvalResult.Multiply(1.0, PolyAtNode, DGFatNodes, 0.0, "jnk", "kn", "jn");
                 *
                 *          //double errSum = 0;
                 *          //for (int i = 0; i < Length; i++) {
                 *          //    for (int n = 0; n < _NoOfNodes; n++) {
                 *          //        for (int k = 0; k < K; k++) {
                 *          //            for (int l = 0; l < K; l++) {
                 *          //                double soll = PolyAtNode[k, n]*PolyAtNode[l, n];
                 *          //                errSum += Math.Abs(soll - EvalResult[i, n, k, l]);
                 *          //            }
                 *          //        }
                 *          //    }
                 *          //}
                 *          //Console.WriteLine("errsum = " + errSum);
                 *      },
                 *      delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { // SaveIntegrationResults
                 *          for (int i = 0; i < Length; i++) {
                 *              int jCell = i + i0;
                 *
                 *              for (int k = 0; k < K; k++) {
                 *                  bcheck[C2N[jCell, k]] += ResultsOfIntegration[i, k];
                 *              }
                 *
                 *              //CellMass[jCell] = new FullMatrix(K, K);
                 *              //CellMass[jCell].Initialize(ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1));
                 *          }
                 *      }).Execute();
                 *
                 *
                 *  double f**k = GenericBlas.L2Dist(b, bcheck);
                 *  Console.WriteLine("Distance error = " + f**k);
                 *
                 * }
                 *
                 *
                 */

                if (_cm == null)
                {
                    // full domain projection branch
                    // +++++++++++++++++++++++++++++


                    var x       = new double[this.Basis.NoOfLocalOwnedNodes];
                    var solStat = m_Basis.MassSolver.Solve(x, b.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).To1DArray());

                    {
                        if (solStat.Converged == false)
                        {
                            throw new ArithmeticException("DG -> SpecFEM Projection failed because the Mass matrix solver did not converge.");
                        }


                        double[] chk = b.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).To1DArray();
                        this.Basis.MassMatrix.SpMVpara(-1.0, x, 1.0, chk);
                        double chk_nomr = chk.L2Norm();

                        if (chk_nomr >= 1.0e-8)
                        {
                            throw new ArithmeticException(string.Format("DG -> SpecFEM Projection failed: solver converged, but with high residual {0}.", chk_nomr.ToStringDot()));
                        }
                    }

                    //m_Basis.MassMatrix.SpMV(1.0, b, 0.0, x);
                    m_Coordinates.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).AccVector(alpha, x);
                    //m_Coordinates.AccV(alpha, b);
                }
                else
                {
                    // restricted domain projection branch
                    // +++++++++++++++++++++++++++++++++++

                    List <int> OccupiedRows_Global = new List <int>();
                    //List<int> OccupiedRows_Local = new List<int>();

                    var MM = Basis.ComputeMassMatrix(cm);
                    int i0 = MM.RowPartitioning.i0, iE = MM.RowPartitioning.iE;
                    for (int i = i0; i < iE; i++)
                    {
                        if (MM.GetNoOfNonZerosPerRow(i) > 0)
                        {
                            OccupiedRows_Global.Add(i);
                            //OccupiedRows_Local.Add(i - i0);
                        }
                    }

                    var CompressedPart = new Partitioning(OccupiedRows_Global.Count);
                    var CompressedMM   = new MsrMatrix(CompressedPart);

                    MM.WriteSubMatrixTo(CompressedMM, OccupiedRows_Global, default(int[]), OccupiedRows_Global, default(int[]));

                    var b_sub = new double[OccupiedRows_Global.Count];
                    //try {
                    b_sub.AccV(1.0, b.To1DArray(), default(int[]), OccupiedRows_Global, b_index_shift: -i0);
                    //} catch(Exception e) {
                    //    Debugger.Launch();
                    //}
                    //csMPI.Raw.Barrier(csMPI.Raw._COMM.WORLD);

                    var x_sub = new double[b_sub.Length];

                    var solver = new ilPSP.LinSolvers.monkey.CG();
                    solver.MatrixType      = ilPSP.LinSolvers.monkey.MatrixType.CCBCSR;
                    solver.DevType         = ilPSP.LinSolvers.monkey.DeviceType.CPU;
                    solver.ConvergenceType = ConvergenceTypes.Absolute;
                    solver.Tolerance       = 1.0e-12;
                    solver.DefineMatrix(CompressedMM);

                    var solStat = solver.Solve(x_sub, b_sub.CloneAs());
                    {
                        if (solStat.Converged == false)
                        {
                            throw new ArithmeticException("DG -> SpecFEM Projection failed because the Mass matrix solver did not converge.");
                        }

                        var chk = b_sub;
                        CompressedMM.SpMVpara(-1.0, x_sub, 1.0, chk);
                        double chk_nomr = chk.L2Norm();

                        if (chk_nomr >= 1.0e-8)
                        {
                            throw new ArithmeticException(string.Format("DG -> SpecFEM Projection failed: solver converged, but with high residual {0}.", chk_nomr.ToStringDot()));
                        }
                    }

                    double[] x = new double[this.Basis.NoOfLocalOwnedNodes];
                    x.AccV(1.0, x_sub, OccupiedRows_Global, default(int[]), acc_index_shift: -i0);
                    m_Coordinates.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).AccVector(alpha, x);
                }

                trx.Scatter(this.m_Coordinates);
            }
        }
Exemple #24
0
        /// <summary>
        /// implementation of the CG algorithm
        /// </summary>
        /// <param name="_x"></param>
        /// <param name="_R"></param>
        /// <param name="stats"></param>
        public void Solve <Vec1, Vec2>(Vec1 _x, Vec2 _R)
            where Vec1 : IList <double>
            where Vec2 : IList <double> //
        {
            using (new FuncTrace()) {
                double[] x, R;
                if (_x is double[])
                {
                    x = _x as double[];
                }
                else
                {
                    x = _x.ToArray();
                }
                if (_R is double[])
                {
                    R = _R as double[];
                }
                else
                {
                    R = _R.ToArray();
                }

                int L = x.Length;

                double[] P = new double[L];

                //double[] R = rhs; // rhs is only needed once, so we can use it to store residuals
                double[] V = new double[L];
                double[] Z = new double[L];


                // compute P0, R0
                // ==============
                GenericBlas.dswap(L, x, 1, P, 1);
                m_Matrix.SpMV(-1.0, P, 1.0, R);
                if (IterationCallback != null)
                {
                    IterationCallback(NoOfIterations, P.CloneAs(), R.CloneAs(), this.m_MgOp);
                }
                GenericBlas.dswap(L, x, 1, P, 1);
                if (Precond != null)
                {
                    Precond.Solve(Z, R);
                    P.SetV(Z);
                }
                else
                {
                    P.SetV(R);
                }

                double alpha   = R.InnerProd(P).MPISum();
                double alpha_0 = alpha;
                double ResNorm;

                ResNorm = Math.Sqrt(alpha);

                // iterate
                // =======
                NoOfIterations++; // one iteration has allready been performed (P0, R0)
                for (int n = 1; n < this.m_MaxIterations; n++)
                {
                    if (ResNorm <= m_Tolerance && NoOfIterations >= m_MinIterations)
                    {
                        this.m_Converged = true;
                        break;
                    }
                    NoOfIterations++;

                    if (Math.Abs(alpha) <= double.Epsilon)
                    {
                        // numerical breakdown
                        break;
                    }


                    m_Matrix.SpMV(1.0, P, 0, V);
                    double VxP = V.InnerProd(P).MPISum();
                    //Console.WriteLine("VxP: {0}", VxP);
                    if (double.IsNaN(VxP) || double.IsInfinity(VxP))
                    {
                        throw new ArithmeticException();
                    }
                    double lambda = alpha / VxP;
                    if (double.IsNaN(lambda) || double.IsInfinity(lambda))
                    {
                        throw new ArithmeticException();
                    }


                    x.AccV(lambda, P);

                    R.AccV(-lambda, V);

                    if (IterationCallback != null)
                    {
                        IterationCallback(NoOfIterations, x.CloneAs(), R.CloneAs(), this.m_MgOp);
                    }

                    if (Precond != null)
                    {
                        Z.Clear();
                        Precond.Solve(Z, R);
                    }
                    else
                    {
                        Z.SetV(R);
                    }

                    double alpha_neu = R.InnerProd(Z).MPISum();

                    // compute residual norm
                    ResNorm = R.L2NormPow2().MPISum().Sqrt();

                    P.ScaleV(alpha_neu / alpha);
                    P.AccV(1.0, Z);

                    alpha = alpha_neu;
                }

                if (!object.ReferenceEquals(_x, x))
                {
                    _x.SetV(x);
                }
                if (!object.ReferenceEquals(_R, R))
                {
                    _R.SetV(R);
                }


                return;
            }
        }
Exemple #25
0
        private void AssembleMatrix(double MU_A, double MU_B, out BlockMsrMatrix M, out double[] b, out MultiphaseCellAgglomerator agg, out MassMatrixFactory massFact)
        {
            using (var tr = new FuncTrace()) {
                // create operator
                // ===============

                if (this.Control.SetDefaultDiriBndCnd)
                {
                    this.Control.xLaplaceBCs.g_Diri      = ((CommonParamsBnd inp) => 0.0);
                    this.Control.xLaplaceBCs.IsDirichlet = (inp => true);
                }

                double D                  = this.GridData.SpatialDimension;
                int    p                  = u.Basis.Degree;
                double penalty_base       = (p + 1) * (p + D) / D;
                double penalty_multiplyer = base.Control.penalty_multiplyer;

                XQuadFactoryHelper.MomentFittingVariants momentFittingVariant;
                if (D == 3)
                {
                    momentFittingVariant = XQuadFactoryHelper.MomentFittingVariants.Classic;
                }

                momentFittingVariant = this.Control.CutCellQuadratureType;

                int order = this.u.Basis.Degree * 2;

                XSpatialOperator Op = new XSpatialOperator(1, 1, (A, B, C) => order, "u", "c1");
                var lengthScales    = ((BoSSS.Foundation.Grid.Classic.GridData)GridData).Cells.PenaltyLengthScales;
                var lap             = new XLaplace_Bulk(this.LsTrk, penalty_multiplyer * penalty_base, "u", this.Control.xLaplaceBCs, 1.0, MU_A, MU_B, lengthScales, this.Control.ViscosityMode);
                Op.EquationComponents["c1"].Add(lap);                                                                                          // Bulk form
                Op.EquationComponents["c1"].Add(new XLaplace_Interface(this.LsTrk, MU_A, MU_B, penalty_base * 2, this.Control.ViscosityMode)); // coupling form

                Op.Commit();

                // create agglomeration
                // ====================

                var map = new UnsetteledCoordinateMapping(u.Basis);

                //agg = new MultiphaseCellAgglomerator(
                //    new CutCellMetrics(momentFittingVariant,
                //        QuadOrderFunc.SumOfMaxDegrees(RoundUp: true)(map.BasisS.Select(bs => bs.Degree).ToArray(), new int[0], map.BasisS.Select(bs => bs.Degree).ToArray()),
                //        //this.HMFDegree,
                //        LsTrk, this.LsTrk.SpeciesIdS.ToArray()),
                //    this.Control.AgglomerationThreshold, false);
                agg = LsTrk.GetAgglomerator(this.LsTrk.SpeciesIdS.ToArray(), order, this.Control.AgglomerationThreshold);

                // compute matrix
                // =============
                using (new BlockTrace("XdgMatrixAssembly", tr)) {
                    M = new BlockMsrMatrix(map, map);
                    b = new double[M.RowPartitioning.LocalLength];

                    Op.ComputeMatrixEx(LsTrk,
                                       map, null, map,
                                       M, b, false, 0.0, true,
                                       agg.CellLengthScales, null, null, //out massFact,
                                       this.LsTrk.SpeciesIdS.ToArray());
                }
                // compare with linear evaluation
                // ==============================
                DGField[]        testDomainFieldS = map.BasisS.Select(bb => new XDGField(bb as XDGBasis)).ToArray();
                CoordinateVector test             = new CoordinateVector(testDomainFieldS);

                DGField[]        errFieldS = map.BasisS.Select(bb => new XDGField(bb as XDGBasis)).ToArray();
                CoordinateVector Err       = new CoordinateVector(errFieldS);

                var eval = Op.GetEvaluatorEx(LsTrk,
                                             testDomainFieldS, null, map);

                foreach (var s in this.LsTrk.SpeciesIdS)
                {
                    eval.SpeciesOperatorCoefficients[s].CellLengthScales = agg.CellLengthScales[s];
                }

                eval.time = 0.0;
                int    L = test.Count;
                Random r = new Random();
                for (int i = 0; i < L; i++)
                {
                    test[i] = r.NextDouble();
                }



                double[] R1 = new double[L];
                double[] R2 = new double[L];
                eval.Evaluate(1.0, 1.0, R1);

                R2.AccV(1.0, b);
                M.SpMV(1.0, test, 1.0, R2);

                Err.AccV(+1.0, R1);
                Err.AccV(-1.0, R2);

                double ErrDist = GenericBlas.L2DistPow2(R1, R2).MPISum().Sqrt();

                double Ref = test.L2NormPow2().MPISum().Sqrt();

                Assert.LessOrEqual(ErrDist, Ref * 1.0e-5, "Mismatch between explicit evaluation of XDG operator and matrix.");


                // agglomeration wahnsinn
                // ======================

                agg.ManipulateMatrixAndRHS(M, b, map, map);

                foreach (var S in this.LsTrk.SpeciesNames)
                {
                    Console.WriteLine("  Species {0}: no of agglomerated cells: {1}",
                                      S, agg.GetAgglomerator(this.LsTrk.GetSpeciesId(S)).AggInfo.SourceCells.NoOfItemsLocally);
                }


                // mass matrix factory
                // ===================

                Basis maxB = map.BasisS.ElementAtMax(bss => bss.Degree);
                //massFact = new MassMatrixFactory(maxB, agg);
                massFact = LsTrk.GetXDGSpaceMetrics(this.LsTrk.SpeciesIdS.ToArray(), order).MassMatrixFactory;
            }
        }
Exemple #26
0
        //static void SingleFilter(double[] V) {
        //    for(int i = 0; i < V.Length; i++) {
        //        float vi = (float)(V[i]);
        //        V[i] = vi;
        //    }
        //}


        public void Solve <U, V>(U X, V B)
            where U : IList <double>
            where V : IList <double> //
        {
            using (var tr = new FuncTrace()) {
                int NoParts = this.BlockIndices_Local.Length;

                // --------
                // Reminder: we solve for a correction, the basic idea is:
                //
                // X0 is current solution, state of 'X' at input time
                //    Residual = B - M*X0;
                // now solve (approximately)
                //    M*Xc = Residual,
                // if we would solve exactly, i.e.
                //    Xc = M^{-1}*Residual
                // then X=(X0+Xc) is an exact solution of
                //    M*X = B
                // --------

                double[] Res = new double[B.Count];
                MPIexchange <double[]> ResExchange;
                MPIexchangeInverse <U> XExchange;
                if (Overlap > 0)
                {
                    ResExchange = new MPIexchange <double[]>(this.m_MgOp.Mapping, Res);
                    XExchange   = new MPIexchangeInverse <U>(this.m_MgOp.Mapping, X);
                }
                else
                {
                    ResExchange = null;
                    XExchange   = null;
#if DEBUG
                    foreach (var ciE in BlockIndices_External)
                    {
                        Debug.Assert(ciE == null || ciE.Length <= 0);
                    }
#endif
                }


                int LocLength = m_MgOp.Mapping.LocalLength;

                for (int iIter = 0; iIter < m_MaxIterations; iIter++)
                {
                    this.NoIter++;

                    Res.SetV(B);
                    this.MtxFull.SpMV(-1.0, X, 1.0, Res);

                    if (IterationCallback != null)
                    {
                        IterationCallback(iIter, X.ToArray(), Res.CloneAs(), this.m_MgOp);
                    }

                    using (new BlockTrace("coarse_solve_level" + this.m_MgOp.LevelIndex, tr)) {
                        if (CoarseSolver != null)
                        {
                            var      XC = X.ToArray().CloneAs();
                            double[] bc = new double[m_MgOp.CoarserLevel.Mapping.LocalLength];// = Res.CloneAs();
                            m_MgOp.CoarserLevel.Restrict(Res.CloneAs(), bc);
                            double[] xc = new double[bc.Length];
                            CoarseSolver.Solve(xc, bc);
                            //SingleFilter(xc);
                            m_MgOp.CoarserLevel.Prolongate(1, XC, 1, xc);
                            X.AccV(1.0, XC);

                            if (CoarseSolverIsMultiplicative)
                            {
                                Res.SetV(B);
                                this.MtxFull.SpMV(-1.0, X, 1.0, Res);
                            }
                        }
                    }

                    if (Overlap > 0)
                    {
                        ResExchange.TransceiveStartImReturn();
                        ResExchange.TransceiveFinish(0.0);
                    }

                    using (new BlockTrace("block_solve_level" + this.m_MgOp.LevelIndex, tr)) {
                        for (int iPart = 0; iPart < NoParts; iPart++)
                        {
                            int[] ci  = BlockIndices_Local[iPart];
                            int[] ciE = BlockIndices_External[iPart];
                            int   L   = ci.Length;
                            if (ciE != null)
                            {
                                L += ciE.Length;
                            }

                            double[] bi = new double[L];
                            double[] xi = new double[L];

                            // extract block part of residual
                            bi.AccV(1.0, Res, default(int[]), ci);
                            if (ciE != null && ciE.Length > 0)
                            {
                                bi.AccV(1.0, ResExchange.Vector_Ext, default(int[]), ciE, acc_index_shift: ci.Length, b_index_shift: (-LocLength));
                            }

                            blockSolvers[iPart].Solve(xi, bi);
                            //SingleFilter(xi);

                            // accumulate block solution 'xi' to global solution 'X'
                            X.AccV(1.0, xi, ci, default(int[]));
                            if (ciE != null && ciE.Length > 0)
                            {
                                XExchange.Vector_Ext.AccV(1.0, xi, ciE, default(int[]), acc_index_shift: (-LocLength), b_index_shift: ci.Length);
                            }
                        }
                    }

                    if (Overlap > 0)
                    {
                        // block solutions stored on *external* indices will be accumulated on other processors.
                        XExchange.TransceiveStartImReturn();
                        XExchange.TransceiveFinish(1.0);

                        if (iIter < m_MaxIterations - 1)
                        {
                            XExchange.Vector_Ext.ClearEntries();
                        }
                    }
                }
            }
        }
        public void Solve <U, V>(U X, V B)
            where U : IList <double>
            where V : IList <double> //
        {
            using (new FuncTrace()) {
                // init
                // ====

                int L = this.m_mgop.Mapping.LocalLength;
                if (X.Count != L)
                {
                    throw new ArgumentException();
                }
                if (B.Count != L)
                {
                    throw new ArgumentException();
                }

                var Mtx = this.m_mgop.OperatorMatrix;


                // residual of initial guess
                // =========================

                // history of solutions and residuals (max vector length 'MaxKrylovDim')
                List <double[]> SolHistory = new List <double[]>();
                List <double[]> MxxHistory = new List <double[]>();

                double[] Correction = new double[L];
                double[] Mxx        = new double[L];
                double[] CurrentSol = new double[L];
                double[] CurrentRes = new double[L];

                CurrentSol.SetV(X, 1.0);
                CurrentRes.SetV(B, 1.0);
                Mtx.SpMV(-1.0, CurrentSol, 1.0, CurrentRes);
                int KrylovDim = 0;

                double[] Residual0 = CurrentRes.CloneAs();
                double[] Solution0 = CurrentSol.CloneAs();

                List <double> _R = new List <double>();

                // diagnostic output
                if (this.IterationCallback != null)
                {
                    this.IterationCallback(0, CurrentSol.CloneAs(), CurrentRes.CloneAs(), this.m_mgop);
                }

                // iterations...
                // =============
                double[] PreviousRes = new double[L];

                //MultidimensionalArray raw_Mxx = MultidimensionalArray.Create(L, MaxIter + 1);
                //MultidimensionalArray ortho_Mxx = MultidimensionalArray.Create(L, MaxIter + 1);

                MultidimensionalArray MassMatrix = MultidimensionalArray.Create(MaxKrylovDim, MaxKrylovDim);

                int      PCcounter = 0;
                double[] prevAlpha = null;
                double   crL2      = double.MaxValue;
                for (int iIter = 0; iIter < MaxIter; iIter++)
                {
                    Debug.Assert(SolHistory.Count == MxxHistory.Count);
                    Debug.Assert(SolHistory.Count == KrylovDim);

                    // select preconditioner
                    var Precond = PrecondS[PCcounter];
                    PCcounter++;
                    if (PCcounter >= PrecondS.Length)
                    {
                        PCcounter = 0;
                        m_ThisLevelIterations++; // because we abuse the Orthonormalization to do some multi-grid stuff,
                        //                          we only count every full cycle of preconditiones.
                    }

                    // solve the residual equation: M*Correction = prev. Residual
                    PreviousRes.SetV(CurrentRes);
                    Correction.ClearEntries();
                    Precond.Solve(Correction, PreviousRes);

                    // compute M*Correction
                    Mtx.SpMV(1.0, Correction, 0.0, Mxx);

                    // orthonormalize the Mxx -- vector with respect to the previous ones.
                    Debug.Assert(KrylovDim == MxxHistory.Count);
                    Debug.Assert(KrylovDim == SolHistory.Count);

                    //raw_Mxx.SetColumn(KrylovDim, Mxx);

                    for (int i = 0; i < KrylovDim; i++)
                    {
                        Debug.Assert(!object.ReferenceEquals(Mxx, MxxHistory[i]));
                        double beta = GenericBlas.InnerProd(Mxx, MxxHistory[i]).MPISum();
                        Mxx.AccV(-beta, MxxHistory[i]);
                        Correction.AccV(-beta, SolHistory[i]);
                    }
                    {
                        double gamma = 1.0 / GenericBlas.L2NormPow2(Mxx).MPISum().Sqrt();
                        Mxx.ScaleV(gamma);
                        Correction.ScaleV(gamma);
                    }

                    // the following lines should produce the identity matrix
                    for (int i = 0; i < KrylovDim; i++)
                    {
                        MassMatrix[i, KrylovDim] = GenericBlas.InnerProd(Mxx, MxxHistory[i]).MPISum();
                    }
                    MassMatrix[KrylovDim, KrylovDim] = GenericBlas.L2NormPow2(Mxx).MPISum();
                    //


                    //ortho_Mxx.SetColumn(KrylovDim, Mxx);

                    MxxHistory.Add(Mxx.CloneAs());
                    SolHistory.Add(Correction.CloneAs());
                    KrylovDim++;



                    bool updateEveryIteration = false;


                    // RHS of the minimization problem (LHS is identity matrix)
                    if (!updateEveryIteration)
                    {
                        _R.Add(GenericBlas.InnerProd(MxxHistory.Last(), Residual0).MPISum());
                    }
                    else
                    {
                        _R.Clear();
                        for (int i = 0; i < KrylovDim; i++)
                        {
                            _R.Add(GenericBlas.InnerProd(MxxHistory[i], Residual0).MPISum());
                        }
                    }

                    // compute accelerated solution
                    //double[] alpha = _R.ToArray(); // factors for re-combining solutions
                    double[] alpha;
                    {
                        double[] minimi_rhs = _R.ToArray();
                        var      minimi_lhs = MassMatrix.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { KrylovDim - 1, KrylovDim - 1 }).CloneAs();
                        alpha = new double[KrylovDim];
                        minimi_lhs.Solve(alpha, minimi_rhs);
                    }
                    if (prevAlpha != null)
                    {
                        var del = alpha.GetSubVector(0, prevAlpha.Length);
                        del.AccV(-1.0, prevAlpha);
                    }
                    prevAlpha = alpha;

                    Debug.Assert(alpha.Length == SolHistory.Count);
                    Debug.Assert(alpha.Length == MxxHistory.Count);
                    Debug.Assert(alpha.Length == KrylovDim);
                    CurrentSol.SetV(Solution0, 1.0);
                    for (int i = 0; i < KrylovDim; i++)
                    {
                        CurrentSol.AccV(alpha[i], SolHistory[i]);
                    }

                    // compute new Residual
                    CurrentRes.SetV(B);
                    Mtx.SpMV(-1.0, CurrentSol, 1.0, CurrentRes);
                    crL2 = CurrentRes.L2NormPow2().MPISum().Sqrt();

                    // diagnostic output
                    if (this.IterationCallback != null)
                    {
                        this.IterationCallback(iIter + 1, CurrentSol.CloneAs(), CurrentRes.CloneAs(), this.m_mgop);
                    }

                    //{
                    //    var gdat = m_mgop.BaseGridProblemMapping.GridDat;
                    //    var basis = m_mgop.BaseGridProblemMapping.BasisS[0];

                    //    var dgCurrentSol = new Foundation.SinglePhaseField(basis, "Solution");
                    //    var dgResidual = new Foundation.SinglePhaseField(basis, "Residual");
                    //    var dgCorrection = new Foundation.SinglePhaseField(basis, "Correction");

                    //    m_mgop.TransformRhsFrom(dgResidual.CoordinateVector, CurrentRes);
                    //    m_mgop.TransformSolFrom(dgCurrentSol.CoordinateVector, CurrentSol);
                    //    m_mgop.TransformSolFrom(dgCorrection.CoordinateVector, SolHistory.Last());
                    //    dgCorrection.Scale(alpha.Last());

                    //    Tecplot.Tecplot.PlotFields(new Foundation.DGField[] { dgCurrentSol, dgResidual, dgCorrection},  "OrthoScheme-" + iIter, iIter, 2);

                    //}


                    if (crL2 < Tolerance)
                    {
                        //Console.WriteLine("    Kcy converged:");
                        //for (int iii = 0; iii < KrylovDim; iii++) {
                        //    Console.WriteLine("       fac #" + iii + "  :  " + alpha[iii]);
                        //}
                        if (PCcounter > 0)
                        {
                            m_ThisLevelIterations += 1;
                        }

                        m_Converged = true;
                        break;
                    }

                    if (updateEveryIteration)
                    {
                        Solution0.SetV(CurrentSol);
                        Residual0.SetV(CurrentRes);
                    }

                    if (KrylovDim >= MaxKrylovDim)
                    {
                        if (this.Restarted)
                        {
                            // restarted version of the algorithm
                            // ++++++++++++++++++++++++++++++++++

                            MxxHistory.Clear();
                            SolHistory.Clear();
                            _R.Clear();
                            KrylovDim = 0;
                            Residual0.SetV(CurrentRes);
                            Solution0.SetV(CurrentSol);
                        }
                        else
                        {
                            // throw-away version of the algorithm
                            // +++++++++++++++++++++++++++++++++++

                            int i_leastSig = alpha.IndexOfMin(x => x.Abs());
                            MxxHistory.RemoveAt(i_leastSig);
                            SolHistory.RemoveAt(i_leastSig);
                            KrylovDim--;

                            for (int i = i_leastSig; i < KrylovDim; i++)
                            {
                                for (int j = 0; j <= KrylovDim; j++)
                                {
                                    MassMatrix[i, j] = MassMatrix[i + 1, j];
                                }
                            }
                            for (int i = i_leastSig; i < KrylovDim; i++)
                            {
                                for (int j = 0; j <= KrylovDim; j++)
                                {
                                    MassMatrix[j, i] = MassMatrix[j, i + 1];
                                }
                            }

                            Residual0.SetV(CurrentRes);
                            Solution0.SetV(CurrentSol);

                            _R.Clear();
                            foreach (double[] mxx in MxxHistory)
                            {
                                _R.Add(GenericBlas.InnerProd(mxx, Residual0).MPISum());
                            }
                        }
                    }
                }

                X.SetV(CurrentSol, 1.0);
                //raw_Mxx.SaveToTextFile("C:\\temp\\raw_Mxx.txt");
                //ortho_Mxx.SaveToTextFile("C:\\temp\\ortho_Mxx.txt");
            }
        }
Exemple #28
0
        private static int[][] AggregationKernel(IGridData ag, int AggCellCount)
        {
            int Jloc = ag.iLogicalCells.NoOfLocalUpdatedCells;
            int D    = ag.SpatialDimension;

            if (AggCellCount < 2)
            {
                throw new ArgumentOutOfRangeException();
            }


            // sort cells of parent grid by size:
            // we want to aggregate the smallest cells at first.
            int[] Perm = Jloc.ForLoop(j => j).OrderBy(j => ag.iLogicalCells.GetCellVolume(j)).ToArray();

            BitArray UsedCellMarker = new BitArray(Jloc);

            List <int[]> Coarsened_ComositeCells = new List <int[]>();

            //
            List <int> aggCell         = new List <int>();
            List <int> NeighCandidates = new List <int>();

            // loop over aggregated cells of parent grid...
            int[][] Neighbourship = ag.iLogicalCells.CellNeighbours;
            for (int i = 0; i < Jloc; i++)
            {
                int jCell = Perm[i];        // pick next cell
                Debug.Assert(Neighbourship[jCell].Contains(jCell) == false);
                if (!UsedCellMarker[jCell]) // if the cell is not already agglomerated to another cell

                {
                    aggCell.Clear();
                    aggCell.Add(jCell);
                    UsedCellMarker[jCell] = true;

                    for (int iPass = 1; iPass < AggCellCount; iPass++)
                    {
                        // list of all neighbor cells which were not already aggregated to some other cell:
                        NeighCandidates.Clear();
                        foreach (int j in aggCell)
                        {
                            Debug.Assert(j < Jloc);
                            Debug.Assert(UsedCellMarker[j] == true);
                            foreach (int jNeigh in Neighbourship[j])
                            {
                                if (jNeigh >= Jloc)
                                {
                                    continue;
                                }
                                if (UsedCellMarker[jNeigh] == true)
                                {
                                    continue;
                                }
                                Debug.Assert(aggCell.Contains(jNeigh) == false); // for all cells which are already in 'aggCell', the marker should be true
                                if (!NeighCandidates.Contains(jNeigh))
                                {
                                    NeighCandidates.Add(jNeigh);
                                }
                            }
                        }


                        int NN = NeighCandidates.Count;

                        if (NN > 0)
                        {
                            double[]      sizes       = new double[NN];
                            BoundingBox[] aggBB       = new BoundingBox[NN];
                            double[]      aggBBaspect = new double[NN];
                            for (int iNeig = 0; iNeig < NN; iNeig++)   // loop over all candidates...
                            {
                                int jCellNeigh = NeighCandidates[iNeig];

                                aggBB[iNeig] = new BoundingBox(D); //ag.CompositeCellBB[jCell].CloneAs();
                                foreach (int jTaken in aggCell)
                                {
                                    BoundingBox TempBB = new BoundingBox(D);
                                    ag.iLogicalCells.GetCellBoundingBox(jTaken, TempBB);
                                    aggBB[iNeig].AddBB(TempBB);
                                }

                                BoundingBox NeighBB = new BoundingBox(D);
                                ag.iLogicalCells.GetCellBoundingBox(jCellNeigh, NeighBB);

                                aggBB[iNeig].AddBB(NeighBB);
                                sizes[iNeig]       = ag.iLogicalCells.GetCellVolume(jCell) + ag.iLogicalCells.GetCellVolume(jCellNeigh);
                                aggBBaspect[iNeig] = aggBB[iNeig].AspectRatio;
                            }

                            double[] RelSizes   = sizes.CloneAs(); RelSizes.ScaleV(1.0 / sizes.Max());
                            double[] RelAspects = aggBBaspect.CloneAs(); RelAspects.ScaleV(1.0 / aggBBaspect.Max());

                            double[] Quality = new double[NN];
                            Quality.AccV(0.7, RelSizes);
                            Quality.AccV(0.3, RelAspects);

                            int iChoice     = Quality.IndexOfMin(q => q);
                            int jNeigChoice = NeighCandidates[iChoice];

                            Debug.Assert(aggCell.Contains(jNeigChoice) == false);
                            aggCell.Add(jNeigChoice);
                            UsedCellMarker[jNeigChoice] = true;
                        }
                        else
                        {
                            // No neighbour available => unable to coarsen
                            break;
                        }
                    }

                    // add agglom cell
                    {
                        int[] aggCell_Fix = aggCell.ToArray();
#if DEBUG
                        foreach (int j in aggCell_Fix)
                        {
                            Debug.Assert(j >= 0);
                            Debug.Assert(j < Jloc);
                            Debug.Assert(UsedCellMarker[j] == true);
                        }
#endif
                        Coarsened_ComositeCells.Add(aggCell_Fix);
                    }
                }
                else
                {
                    // cell already done.
                    continue;
                }
            }
            Debug.Assert(UsedCellMarker.ToBoolArray().Where(b => !b).Count() == 0, "some cell was not processed.");
            return(Coarsened_ComositeCells.ToArray());
        }
Exemple #29
0
        public void Solve <V1, V2>(V1 _X, V2 _B)
            where V1 : IList <double>
            where V2 : IList <double>
        {
            using (var tr = new FuncTrace())
            {
                double[] X, B;
                if (_X is double[])
                {
                    X = _X as double[];
                }
                else
                {
                    X = _X.ToArray();
                }
                if (_B is double[])
                {
                    B = _B as double[];
                }
                else
                {
                    B = _B.ToArray();
                }


                double bnrm2 = B.L2NormPow2().MPISum().Sqrt();
                if (bnrm2 == 0.0)
                {
                    bnrm2 = 1.0;
                }

                int Nloc = Matrix.RowPartitioning.LocalLength;
                int Ntot = Matrix.RowPartitioning.TotalLength;

                double[] r = new double[Nloc];
                double[] z = new double[Nloc];

                //r = M \ ( b-A*x );, where M is the precond
                z.SetV(B);
                Matrix.SpMV(-1.0, X, 1.0, z);
                if (IterationCallback != null)
                {
                    IterationCallback(0, X.CloneAs(), z.CloneAs(), this.m_mgop);
                }
                if (this.Precond != null)
                {
                    r.Clear();
                    this.Precond.Solve(r, z);
                }
                else
                {
                    r.SetV(z);
                }

                // Inserted for real residual
                double error2 = z.L2NormPow2().MPISum().Sqrt();

                double error = (r.L2NormPow2().MPISum().Sqrt()) / bnrm2;
                if (error < this.m_Tolerance)
                {
                    if (!object.ReferenceEquals(_X, X))
                    {
                        _X.SetV(X);
                    }
                    B.SetV(z);
                    this.m_Converged = true;
                    return;
                }

                if (MaxKrylovDim <= 0)
                {
                    throw new NotSupportedException("unsupported restart length.");
                }

                int                   m = MaxKrylovDim;
                double[][]            V = (m + 1).ForLoop(i => new double[Nloc]); //   V(1:n,1:m+1) = zeros(n,m+1);
                MultidimensionalArray H = MultidimensionalArray.Create(m + 1, m); //   H(1:m+1,1:m) = zeros(m+1,m);

                double[] cs = new double[m];
                double[] sn = new double[m];
                //double[] s = new double[m+1];
                double[] e1 = new double[Nloc];
                //if(Matrix.RowPartitioning.Rank == 0)
                e1[0] = 1.0;

                double[] s = new double[Nloc], w = new double[Nloc], y;
                double   temp;
                int      iter;
                for (iter = 1; iter <= m_MaxIterations; iter++)
                { // GMRES iterations
                  // r = M \ ( b-A*x );
                    z.SetV(B);
                    Matrix.SpMV(-1.0, X, 1.0, z);

                    error2 = z.L2NormPow2().MPISum().Sqrt();

                    if (this.Precond != null)
                    {
                        r.Clear();
                        this.Precond.Solve(r, z);
                    }
                    else
                    {
                        r.SetV(z);
                    }

                    // V(:,1) = r / norm( r );
                    double norm_r = r.L2NormPow2().MPISum().Sqrt();
                    V[0].SetV(r, alpha: (1.0 / norm_r));

                    //s = norm( r )*e1;
                    s.SetV(e1, alpha: norm_r);

                    int i;

                    #region Gram-Schmidt (construct orthonormal  basis using Gram-Schmidt)
                    for (i = 1; i <= m; i++)
                    {
                        this.NoOfIterations++;

                        #region Arnoldi procdure

                        //w = M \ (A*V(:,i));
                        Matrix.SpMV(1.0, V[i - 1], 0.0, z);
                        if (this.Precond != null)
                        {
                            w.Clear();
                            this.Precond.Solve(w, z);
                        }
                        else
                        {
                            w.SetV(z);
                        }

                        for (int k = 1; k <= i; k++)
                        {
                            H[k - 1, i - 1] = GenericBlas.InnerProd(w, V[k - 1]).MPISum();
                            //w = w - H(k,i)*V(:,k);
                            w.AccV(-H[k - 1, i - 1], V[k - 1]);
                        }

                        double norm_w = w.L2NormPow2().MPISum().Sqrt();
                        H[i + 1 - 1, i - 1] = norm_w; // the +1-1 actually makes me sure I haven't forgotten to subtract -1 when porting the code
                                                      //V(:,i+1) = w / H(i+1,i);
                        V[i + 1 - 1].SetV(w, alpha: (1.0 / norm_w));

                        #endregion

                        #region Givens rotation

                        for (int k = 1; k <= i - 1; k++)
                        {
                            // apply Givens rotation, H is Hessenbergmatrix
                            temp = cs[k - 1] * H[k - 1, i - 1] + sn[k - 1] * H[k + 1 - 1, i - 1];
                            H[k + 1 - 1, i - 1] = -sn[k - 1] * H[k - 1, i - 1] + cs[k - 1] * H[k + 1 - 1, i - 1];
                            H[k - 1, i - 1]     = temp;
                        }
                        //	 [cs(i),sn(i)] = rotmat( H(i,i), H(i+1,i) ); % form i-th rotation matrix
                        rotmat(out cs[i - 1], out sn[i - 1], H[i - 1, i - 1], H[i + 1 - 1, i - 1]);
                        temp                = cs[i - 1] * s[i - 1]; //                       % approximate residual norm
                        H[i - 1, i - 1]     = cs[i - 1] * H[i - 1, i - 1] + sn[i - 1] * H[i + 1 - 1, i - 1];
                        H[i + 1 - 1, i - 1] = 0.0;

                        #endregion

                        // update the residual vector (s == beta in many pseudocodes)
                        s[i + 1 - 1] = -sn[i - 1] * s[i - 1];
                        s[i - 1]     = temp;
                        error        = Math.Abs(s[i + 1 - 1]) / bnrm2;
                        //{
                        //    int rootRank = Matrix.RowPartitioning.FindProcess(i + 1 - 1);
                        //    if (Matrix.RowPartitioning.Rank == rootRank) {


                        //    } else {
                        //        error = double.NaN;
                        //    }
                        //    unsafe {
                        //        csMPI.Raw.Bcast((IntPtr)(&error), 1, csMPI.Raw._DATATYPE.DOUBLE, rootRank, Matrix.RowPartitioning.MPI_Comm);
                        //    }
                        //}

                        //using (StreamWriter writer = new StreamWriter(m_SessionPath + "//GMRES_Stats.txt", true))
                        //{
                        Console.WriteLine(i + "   " + error);
                        //}



                        if (error <= m_Tolerance)
                        {
                            // update approximation and exit
                            //using (StreamWriter writer = new StreamWriter(m_SessionPath + "//GMRES_Stats.txt", true))
                            //{
                            //    writer.WriteLine("");
                            //}

                            //y = H(1:i,1:i) \ s(1:i);
                            y = new double[i];
                            H.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { i - 1, i - 1 })
                            .Solve(y, s.GetSubVector(0, i));



                            // x = x + V(:,1:i)*y;
                            for (int ii = 0; ii < i; ii++)
                            {
                                X.AccV(y[ii], V[ii]);
                            }
                            this.m_Converged = true;
                            break;
                        }
                    }
                    #endregion
                    //Debugger.Launch();


                    if (error <= this.m_Tolerance)
                    {
                        this.m_Converged = true;
                        break;
                    }


                    // y = H(1:m,1:m) \ s(1:m);
                    y = new double[m];
                    H.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { m - 1, m - 1 })
                    .Solve(y, s.GetSubVector(0, m));
                    // update approximation: x = x + V(:,1:m)*y;
                    for (int ii = 0; ii < m; ii++)
                    {
                        X.AccV(y[ii], V[ii]);
                    }

                    // compute residual: r = M \ ( b-A*x )
                    z.SetV(B);
                    Matrix.SpMV(-1.0, X, 1.0, z);
                    if (IterationCallback != null)
                    {
                        error2 = z.L2NormPow2().MPISum().Sqrt();
                        IterationCallback(iter, X.CloneAs(), z.CloneAs(), this.m_mgop);
                        //IterationCallback(this.NoOfIterations, X.CloneAs(), z.CloneAs(), this.m_mgop);
                    }
                    if (this.Precond != null)
                    {
                        r.Clear();
                        this.Precond.Solve(r, z);
                    }
                    else
                    {
                        r.SetV(z);
                    }


                    norm_r       = r.L2NormPow2().MPISum().Sqrt();
                    s[i + 1 - 1] = norm_r;
                    error        = s[i + 1 - 1] / bnrm2; // % check convergence
                    //  if (error2 <= m_Tolerance) Check for error not error2
                    //break;
                }

                if (IterationCallback != null)
                {
                    z.SetV(B);
                    Matrix.SpMV(-1.0, X, 1.0, z);
                    IterationCallback(iter, X.CloneAs(), z.CloneAs(), this.m_mgop);
                }


                if (!object.ReferenceEquals(_X, X))
                {
                    _X.SetV(X);
                }
                B.SetV(z);
            }
        }
        public void Solve <U, V>(U X, V B)
            where U : IList <double>
            where V : IList <double> //
        {
            // init
            // ====

            int L = this.m_mgop.Mapping.LocalLength;

            if (X.Count != L)
            {
                throw new ArgumentException();
            }
            if (B.Count != L)
            {
                throw new ArgumentException();
            }

            var Mtx = this.m_mgop.OperatorMatrix;


            // residual of initial guess
            // =========================

            // history of solutions and residuals (max vector length 'MaxKrylovDim')
            List <double[]> SolHistory = new List <double[]>();
            List <double[]> MxxHistory = new List <double[]>();

            double[] Correction = new double[L];
            double[] Mxx        = new double[L];
            double[] CurrentSol = new double[L];
            double[] CurrentRes = new double[L];

            CurrentSol.SetV(X, 1.0);
            CurrentRes.SetV(B, 1.0);
            Mtx.SpMV(-1.0, CurrentSol, 1.0, CurrentRes);
            int KrylovDim = 0;

            double[] Residual0 = CurrentRes.CloneAs();
            double[] Solution0 = CurrentSol.CloneAs();

            List <double> _R = new List <double>();

            // diagnostic output
            if (this.IterationCallback != null)
            {
                this.IterationCallback(0, CurrentSol.CloneAs(), CurrentRes.CloneAs(), this.m_mgop);
            }

            // iterations...
            // =============
            double[] PreviousRes = new double[L];

            //MultidimensionalArray raw_Mxx = MultidimensionalArray.Create(L, MaxIter + 1);
            //MultidimensionalArray ortho_Mxx = MultidimensionalArray.Create(L, MaxIter + 1);

            MultidimensionalArray MassMatrix = MultidimensionalArray.Create(MaxKrylovDim, MaxKrylovDim);

            int PCcounter = 0;

            for (int iIter = 0; iIter < MaxIter; iIter++)
            {
                m_ThisLevelIterations++;
                Debug.Assert(SolHistory.Count == MxxHistory.Count);
                Debug.Assert(SolHistory.Count == KrylovDim);

                // select preconditioner
                var Precond = PrecondS[PCcounter];
                PCcounter++;
                if (PCcounter >= PrecondS.Length)
                {
                    PCcounter = 0;
                }

                // solve the residual equation: M*Correction = prev. Residual
                PreviousRes.SetV(CurrentRes);
                Correction.ClearEntries();
                Precond.Solve(Correction, PreviousRes);

                // compute M*Correction
                Mtx.SpMV(1.0, Correction, 0.0, Mxx);

                // orthonormalize the Mxx -- vector with respect to the previous ones.
                Debug.Assert(KrylovDim == MxxHistory.Count);
                Debug.Assert(KrylovDim == SolHistory.Count);

                //raw_Mxx.SetColumn(KrylovDim, Mxx);

                for (int i = 0; i < KrylovDim; i++)
                {
                    Debug.Assert(!object.ReferenceEquals(Mxx, MxxHistory[i]));
                    double beta = GenericBlas.InnerProd(Mxx, MxxHistory[i]).MPISum();
                    Mxx.AccV(-beta, MxxHistory[i]);
                    Correction.AccV(-beta, SolHistory[i]);
                }
                {
                    double gamma = 1.0 / GenericBlas.L2NormPow2(Mxx).MPISum().Sqrt();
                    Mxx.ScaleV(gamma);
                    Correction.ScaleV(gamma);
                }

                //
                for (int i = 0; i < KrylovDim; i++)
                {
                    MassMatrix[i, KrylovDim] = GenericBlas.InnerProd(Mxx, MxxHistory[i]).MPISum();
                }
                MassMatrix[KrylovDim, KrylovDim] = GenericBlas.L2NormPow2(Mxx).MPISum();
                //


                //ortho_Mxx.SetColumn(KrylovDim, Mxx);

                MxxHistory.Add(Mxx.CloneAs());
                SolHistory.Add(Correction.CloneAs());
                KrylovDim++;

                // RHS of the minimization problem (LHS is identity matrix)
                _R.Add(GenericBlas.InnerProd(MxxHistory.Last(), Residual0).MPISum());

                // compute accelerated solution
                //double[] alpha = _R.ToArray(); // factors for re-combining solutions
                double[] alpha;
                {
                    double[] minimi_rhs = _R.ToArray();
                    var      minimi_lhs = MassMatrix.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { KrylovDim - 1, KrylovDim - 1 }).CloneAs();
                    alpha = new double[KrylovDim];
                    minimi_lhs.Solve(alpha, minimi_rhs);
                }

                Debug.Assert(alpha.Length == SolHistory.Count);
                Debug.Assert(alpha.Length == MxxHistory.Count);
                Debug.Assert(alpha.Length == KrylovDim);
                CurrentSol.SetV(Solution0, 1.0);
                for (int i = 0; i < KrylovDim; i++)
                {
                    CurrentSol.AccV(alpha[i], SolHistory[i]);
                }

                // compute new Residual
                CurrentRes.SetV(B);
                Mtx.SpMV(-1.0, CurrentSol, 1.0, CurrentRes);
                double crL2 = CurrentRes.L2Norm();

                // diagnostic output
                if (this.IterationCallback != null)
                {
                    this.IterationCallback(iIter + 1, CurrentSol.CloneAs(), CurrentRes.CloneAs(), this.m_mgop);
                }

                if (crL2 < Tolerance)
                {
                    m_Converged = true;
                    break;
                }

                if (KrylovDim >= MaxKrylovDim)
                {
                    if (this.Restarted)
                    {
                        // restarted version of the algorithm
                        // ++++++++++++++++++++++++++++++++++

                        MxxHistory.Clear();
                        SolHistory.Clear();
                        _R.Clear();
                        KrylovDim = 0;
                        Residual0.SetV(CurrentRes);
                        Solution0.SetV(CurrentSol);
                    }
                    else
                    {
                        // throw-away version of the algorithm
                        // +++++++++++++++++++++++++++++++++++

                        int i_leastSig = alpha.IndexOfMin(x => x.Abs());
                        MxxHistory.RemoveAt(i_leastSig);
                        SolHistory.RemoveAt(i_leastSig);
                        KrylovDim--;

                        for (int i = i_leastSig; i < KrylovDim; i++)
                        {
                            for (int j = 0; j <= KrylovDim; j++)
                            {
                                MassMatrix[i, j] = MassMatrix[i + 1, j];
                            }
                        }
                        for (int i = i_leastSig; i < KrylovDim; i++)
                        {
                            for (int j = 0; j <= KrylovDim; j++)
                            {
                                MassMatrix[j, i] = MassMatrix[j, i + 1];
                            }
                        }

                        Residual0.SetV(CurrentRes);
                        Solution0.SetV(CurrentSol);

                        _R.Clear();
                        foreach (double[] mxx in MxxHistory)
                        {
                            _R.Add(GenericBlas.InnerProd(mxx, Residual0).MPISum());
                        }
                    }
                }
            }


            X.SetV(CurrentSol, 1.0);
            //raw_Mxx.SaveToTextFile("C:\\temp\\raw_Mxx.txt");
            //ortho_Mxx.SaveToTextFile("C:\\temp\\ortho_Mxx.txt");
        }