/// <summary>
        /// Test on a Cartesian grid, with an exact polynomial solution.
        /// </summary>
        public static SipControl TestCartesian1(int xRes = 32, double xStretch = 1.0, int yRes = 16, double yStretch = 1.01, int pDG = 2)
        {
            var RR = new SipControl();

            RR.ProjectName = "ipPoison/cartesian";
            RR.savetodb    = false;

            RR.FieldOptions.Add("T", new FieldOpts()
            {
                Degree = pDG, SaveToDB = FieldOpts.SaveToDBOpt.TRUE
            });
            RR.FieldOptions.Add("Tex", new FieldOpts()
            {
                Degree = pDG * 2
            });
            RR.InitialValues_Evaluators.Add("RHS", X => 1.0);
            RR.InitialValues_Evaluators.Add("Tex", X => (0.5 * X[0].Pow2() - 10 * X[0]));
            RR.ExactSolution_provided = true;

            RR.GridFunc = delegate() {
                double[] xNodes = CreateNodes(xRes, xStretch, 0, 10);
                double[] yNodes = CreateNodes(yRes, yStretch, -1, +1);

                var grd = Grid2D.Cartesian2DGrid(xNodes, yNodes);
                grd.EdgeTagNames.Add(1, BoundaryType.Dirichlet.ToString());
                grd.EdgeTagNames.Add(2, BoundaryType.Neumann.ToString());
                grd.DefineEdgeTags(delegate(double[] X) {
                    byte ret;
                    if (Math.Abs(X[0] - 0.0) <= 1.0e-6)
                    {
                        ret = 1;
                    }
                    else
                    {
                        ret = 2;
                    }
                    return(ret);
                });

                return(grd);
            };


            RR.AddBoundaryCondition(BoundaryType.Dirichlet.ToString());
            RR.AddBoundaryCondition(BoundaryType.Neumann.ToString());


            RR.GridPartType = BoSSS.Foundation.Grid.GridPartType.none;


            return(RR);
        }
        /// <summary>
        /// Test on a curved grid.
        /// </summary>
        public static SipControl TestCurved()
        {
            var R = new SipControl();

            R.ProjectName = "ipPoison/curved";
            R.savetodb    = false;

            R.FieldOptions.Add("T", new FieldOpts()
            {
                Degree = 2, SaveToDB = FieldOpts.SaveToDBOpt.TRUE
            });
            R.FieldOptions.Add("Tex", new FieldOpts()
            {
                Degree = 15
            });
            R.InitialValues_Evaluators.Add("RHS", X => 0.0);
            R.InitialValues_Evaluators.Add("Tex", X => (Math.Log(X[0].Pow2() + X[1].Pow2()) / Math.Log(4.0)) + 1.0);
            R.ExactSolution_provided = true;

            R.GridFunc = delegate() {
                var grd = Grid2D.CurvedSquareGrid(GenericBlas.Linspace(1, 2, 3), GenericBlas.Linspace(0, 1, 11), CellType.Square_9, true);
                grd.EdgeTagNames.Add(1, BoundaryType.Dirichlet.ToString());
                grd.DefineEdgeTags(X => 1);
                return(grd);
            };

            R.AddBoundaryCondition(BoundaryType.Dirichlet.ToString(), "T",
                                   delegate(double[] X) {
                double x = X[0], y = X[1];
                return(Math.Sqrt(x * x + y * y));
            });


            return(R);
        }
        /// <summary>
        /// Poisson Equation on a (-1,1)x(-1,1), Dirichlet everywhere
        /// </summary>
        public static SipControl Square(int xRes = 21, int yRes = 16, int deg = 5)
        {
            //Func<double[], double> exRhs = X => 2 * X[0] * X[0] + 2 * X[1] * X[1] - 4;
            //Func<double[], double> exSol = X => (1.0 - X[0] * X[0]) * (1.0 - X[1] * X[1]);

            //Func<double[], double> exSol = X => (1.0 - X[1]);
            //Func<double[], double> exRhs = X => 0.0;

            Func <double[], double> exSol = X => - Math.Cos(X[0] * Math.PI * 0.5) * Math.Cos(X[1] * Math.PI * 0.5);
            Func <double[], double> exRhs = X => (Math.PI * Math.PI * 0.5 * Math.Cos(X[0] * Math.PI * 0.5) * Math.Cos(X[1] * Math.PI * 0.5)); // == - /\ exSol


            var R = new SipControl();

            R.ProjectName = "ipPoison/square";
            R.savetodb    = false;
            //R.DbPath = "D:\\BoSSS-db";

            R.FieldOptions.Add("T", new FieldOpts()
            {
                Degree = deg, SaveToDB = FieldOpts.SaveToDBOpt.TRUE
            });
            R.FieldOptions.Add("Tex", new FieldOpts()
            {
                Degree = 4
            });
            R.InitialValues_Evaluators.Add("RHS", exRhs);
            R.InitialValues_Evaluators.Add("Tex", exSol);
            R.ExactSolution_provided = true;

            R.GridFunc = delegate() {
                double[] xNodes = GenericBlas.Linspace(-1, 1, xRes);
                double[] yNodes = GenericBlas.Linspace(-1, 1, yRes);
                var      grd    = Grid2D.Cartesian2DGrid(xNodes, yNodes);

                grd.EdgeTagNames.Add(1, BoundaryType.Dirichlet.ToString());
                grd.DefineEdgeTags(delegate(double[] X) {
                    byte ret = 1;
                    return(ret);
                });


                return(grd);
            };

            R.AddBoundaryCondition(BoundaryType.Dirichlet.ToString(), "T", exSol);

            R.NoOfSolverRuns = 1;

            return(R);
        }
        /// <summary>
        /// Test on a Cartesian grid, with a sinusodial solution.
        /// </summary>
        /// <param name="Res">
        /// Grid resolution
        /// </param>
        /// <param name="Dim">
        /// spatial dimension
        /// </param>
        /// <param name="deg">
        /// polynomial degree
        /// </param>
        /// <param name="solver_name">
        /// Name of solver to use.
        /// </param>
        public static SipControl TestCartesian2(int Res, int Dim, SolverCodes solver_name = SolverCodes.exp_softpcg_mg, int deg = 3)
        {
            if (Dim != 2 && Dim != 3)
            {
                throw new ArgumentOutOfRangeException();
            }

            var R = new SipControl();

            R.ProjectName = "ipPoison/cartesian";
            R.savetodb    = false;

            R.FieldOptions.Add("T", new FieldOpts()
            {
                Degree = deg, SaveToDB = FieldOpts.SaveToDBOpt.TRUE
            });
            R.FieldOptions.Add("Tex", new FieldOpts()
            {
                Degree = deg * 2
            });
            R.InitialValues_Evaluators.Add("RHS", X => - Math.Sin(X[0]));
            R.InitialValues_Evaluators.Add("Tex", X => Math.Sin(X[0]));
            R.ExactSolution_provided = true;
            R.NoOfMultigridLevels    = int.MaxValue;
            R.solver_name            = solver_name;
            //R.TargetBlockSize = 100;

            R.GridFunc = delegate() {
                GridCommons grd = null;
                if (Dim == 2)
                {
                    double[] xNodes = GenericBlas.Linspace(0, 10, Res * 5 + 1);
                    double[] yNodes = GenericBlas.SinLinSpacing(-1, +1, 0.6, Res + 1);

                    grd = Grid2D.Cartesian2DGrid(xNodes, yNodes);
                }
                else if (Dim == 3)
                {
                    double[] xNodes = GenericBlas.Linspace(0, 10, Res * 5 + 1);
                    double[] yNodes = GenericBlas.SinLinSpacing(-1, +1, 0.6, Res + 1);
                    double[] zNodes = GenericBlas.SinLinSpacing(-1, +1, 0.6, Res + 1);

                    grd = Grid3D.Cartesian3DGrid(xNodes, yNodes, zNodes);
                }
                else
                {
                    throw new NotSupportedException();
                }
                grd.EdgeTagNames.Add(1, BoundaryType.Dirichlet.ToString());
                grd.EdgeTagNames.Add(2, BoundaryType.Neumann.ToString());
                grd.DefineEdgeTags(delegate(double[] X) {
                    byte ret;
                    if (Math.Abs(X[0] - 0.0) <= 1.0e-6)
                    {
                        ret = 1;
                    }
                    else
                    {
                        ret = 2;
                    }
                    return(ret);
                });

                return(grd);
            };

            R.AddBoundaryCondition(BoundaryType.Dirichlet.ToString(), "T",
                                   delegate(double[] X) {
                double x = X[0], y = X[1];

                if (Math.Abs(X[0] - (0.0)) < 1.0e-8)
                {
                    return(0.0);
                }

                throw new ArgumentOutOfRangeException();
            });

            R.AddBoundaryCondition(BoundaryType.Neumann.ToString(), "T",
                                   delegate(double[] X) {
                if (Math.Abs(X[1] - 1.0) < 1.0e-8 || Math.Abs(X[1] + 1.0) < 1.0e-8)     // y = -1, y = +1
                {
                    return(0);
                }

                if (X.Length > 2 && (Math.Abs(X[2] - 1.0) < 1.0e-8 || Math.Abs(X[2] + 1.0) < 1.0e-8))     // z = -1, z = +1
                {
                    return(0);
                }

                if (Math.Abs(X[0] - (+10.0)) < 1.0e-8)
                {
                    return(Math.Cos(10.0));
                }

                throw new ArgumentOutOfRangeException();
            });



            return(R);
        }