void PerformArtificialDiffusion(double dt, int jCell, SinglePhaseField Phi, MultidimensionalArray DiffMtx, double[] B)
        {
            int N   = this.LevelSetBasis.GetLength(jCell);
            int i0L = this.LevelSetMapping.LocalUniqueCoordinateIndex(0, jCell, 0);

            // extract data from jCell
            double[] u0 = Phi.Coordinates.GetRow(jCell);

            // RHS = (1/dt)*u0 - B
            double[] RHS = u0;
            RHS.ScaleV(1 / dt);
            RHS.AccV(-1.0, B);

            // LHS = (1/dt)*I + DiffMtx
            MultidimensionalArray LHS = DiffMtx.CloneAs();

            LHS.AccEye(1 / dt);

            // solve
            double[] u1 = new double[N];
            LHS.Solve(u1, RHS);

            // return
            Phi.Coordinates.SetRow(jCell, u1);
        }
Beispiel #2
0
        /// <summary>
        /// computes derivatives in various ways and compares them against known values.
        /// </summary>
        protected override double RunSolverOneStep(int TimestepNo, double phystime, double dt)
        {
            base.EndTime       = 0.0;
            base.NoOfTimesteps = 0;

            int D = this.GridData.SpatialDimension;
            int J = this.GridData.iLogicalCells.NoOfLocalUpdatedCells;

            Console.WriteLine("DerivativeTest.exe, test case #" + GRID_CASE + " ******************************");

            //var Fix = this.GridData.iGeomEdges.FaceIndices;
            //for(int iEdge = 0; iEdge < Fix.GetLength(0); iEdge++) {
            //    Debug.Assert(Fix[iEdge, 0] >= 0);
            //    Debug.Assert(Fix[iEdge, 1] >= 0);
            //}

            // sealing test
            // =================

            if (this.GridData is Foundation.Grid.Classic.GridData)
            {
                TestSealing(this.GridData);
            }

            // cell volume and edge area check, if possible
            // ===============================================


            if (this.CellVolume > 0)
            {
                double err      = 0;
                double Treshold = 1.0e-10;


                for (int j = 0; j < J; j++)
                {
                    err += Math.Abs(this.GridData.iLogicalCells.GetCellVolume(j) - this.CellVolume);
                }

                bool passed = (err < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine("Cell volume error: " + err + " passed? " + passed);
                Console.WriteLine("--------------------------------------------");
            }

            if (this.EdgeArea > 0)
            {
                double err      = 0;
                double Treshold = 1.0e-10;

                int E = this.GridData.iLogicalEdges.Count;

                for (int e = 0; e < E; e++)
                {
                    err += Math.Abs(this.GridData.iLogicalEdges.GetEdgeArea(e) - this.EdgeArea);
                }

                bool passed = (err < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine("Edge area error: " + err + " passed? " + passed);
                Console.WriteLine("--------------------------------------------");
            }

            // Orthonormality of basis in physical coords
            // ==========================================

            {
                Basis Bs      = this.f1.Basis;
                int   N       = Bs.Length;
                int   degQuad = this.GridData.iLogicalCells.GetInterpolationDegree(0) * D + Bs.Degree + 3;
                int[] jG2jL   = this.GridData.iGeomCells.GeomCell2LogicalCell;


                // mass matrix: should be identity!
                MultidimensionalArray MassMatrix = MultidimensionalArray.Create(J, N, N);

                // compute mass matrix by quadrature.
                var quad = CellQuadrature.GetQuadrature(new int[] { N, N }, base.GridData,
                                                        (new CellQuadratureScheme()).Compile(base.GridData, degQuad),
                                                        delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) {
                    NodeSet QuadNodes = QR.Nodes;
                    MultidimensionalArray BasisVals = Bs.CellEval(QuadNodes, i0, Length);
                    EvalResult.Multiply(1.0, BasisVals, BasisVals, 0.0, "jknm", "jkn", "jkm");
                },
                                                        delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) {
                    if (jG2jL != null)
                    {
                        for (int i = 0; i < Length; i++)
                        {
                            int jG = i + i0;
                            MassMatrix.ExtractSubArrayShallow(jG2jL[jG], -1, -1)
                            .Acc(1.0, ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1));
                        }
                    }
                    else
                    {
                        MassMatrix.SetSubArray(ResultsOfIntegration, new int[] { i0, 0, 0 }, new int[] { i0 + Length - 1, N - 1, N - 1 });
                    }
                },
                                                        cs: CoordinateSystem.Physical);
                quad.Execute();

                // check that mass matrix is Id.
                int    MaxErrorCell = -1;
                double MaxError     = -1;
                for (int j = 0; j < J; j++)
                {
                    MultidimensionalArray MassMatrix_j = MassMatrix.ExtractSubArrayShallow(j, -1, -1);
                    MassMatrix_j.AccEye(-1.0);

                    double Norm_j = MassMatrix_j.InfNorm();
                    if (Norm_j > MaxError)
                    {
                        MaxError     = Norm_j;
                        MaxErrorCell = j;
                    }
                }

                bool passed = (MaxError < 1.0e-8);
                m_passed = m_passed && passed;
                Console.WriteLine("Mass Matrix, maximum error in Cell #" + MaxErrorCell + ", mass matrix error norm: " + MaxError + " passed? " + passed);
            }

            // Broken Derivatives
            // =================

            double totalVolume = (new SubGrid(CellMask.GetFullMask(this.GridData))).Volume;

            for (int d = 0; d < D; d++)
            {
                // compute
                f1Gradient_Numerical[d].Clear();
                f1Gradient_Numerical[d].Derivative(1.0, f1, d);
                f2Gradient_Numerical[d].Clear();
                f2Gradient_Numerical[d].Derivative(1.0, f2, d);

                // subtract analytical
                var Errfield1 = f1Gradient_Numerical[d].CloneAs();
                Errfield1.Acc(-1, f1Gradient_Analytical[d]);

                var Errfield2 = f2Gradient_Numerical[d].CloneAs();
                Errfield2.Acc(-1, f2Gradient_Analytical[d]);

                Console.WriteLine("Broken Derivatives: ");

                double Treshold = 1.0e-10;
                if (AltRefSol)
                {
                    Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold
                }
                double err1_dx = Errfield1.L2Norm() / totalVolume;
                bool   passed  = (err1_dx < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed));

                double err2_dx = Errfield2.L2Norm() / totalVolume;
                passed   = (err2_dx < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed));

                Console.WriteLine("--------------------------------------------");
            }

            // Flux Derivatives
            // =================
            for (int d = 0; d < D; d++)
            {
                // compute
                f1Gradient_Numerical[d].Clear();
                f1Gradient_Numerical[d].DerivativeByFlux(1.0, f1, d);
                f2Gradient_Numerical[d].Clear();
                f2Gradient_Numerical[d].DerivativeByFlux(1.0, f2, d);

                f1Gradient_Numerical[d].CheckForNanOrInf(true, true, true);
                f2Gradient_Numerical[d].CheckForNanOrInf(true, true, true);

                // subtract analytical
                var Errfield1 = f1Gradient_Numerical[d].CloneAs();
                Errfield1.Acc(-1, f1Gradient_Analytical[d]);

                var Errfield2 = f2Gradient_Numerical[d].CloneAs();
                Errfield2.Acc(-1, f2Gradient_Analytical[d]);

                Console.WriteLine("Flux Derivatives: ");

                double Treshold = 1.0e-10;
                if (AltRefSol)
                {
                    Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold
                }
                double err1_dx = Errfield1.L2Norm() / totalVolume;
                bool   passed  = (err1_dx < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed));

                double err2_dx = Errfield2.L2Norm() / totalVolume;
                passed   = (err2_dx < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed));

                Console.WriteLine("--------------------------------------------");
            }


            // Linear flux Derivatives
            // =======================
            for (int d = 0; d < D; d++)
            {
                double[] korrekto = f1Gradient_Numerical[d].CoordinateVector.ToArray();

                // compute
                DerivativeByFluxLinear(f1, f1Gradient_Numerical[d], d, f1);
                DerivativeByFluxLinear(f2, f2Gradient_Numerical[d], d, f2);

                // subtract analytical
                var Errfield1 = f1Gradient_Numerical[d].CloneAs();
                Errfield1.Acc(-1, f1Gradient_Analytical[d]);

                var Errfield2 = f2Gradient_Numerical[d].CloneAs();
                Errfield2.Acc(-1, f2Gradient_Analytical[d]);

                Console.WriteLine("Linear Flux Derivatives: ");

                double Treshold = 1.0e-10;
                if (AltRefSol)
                {
                    Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold
                }
                double err1_dx = Errfield1.L2Norm() / totalVolume;
                bool   passed  = (err1_dx < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed));

                double err2_dx = Errfield2.L2Norm() / totalVolume;
                passed   = (err2_dx < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed));

                Console.WriteLine("--------------------------------------------");
            }

            // Laplacian, nonlinear
            // ====================

            if (!AltRefSol)
            {
                var Laplace = (new ipLaplace()).Operator(1);

                Laplace.Evaluate(new DGField[] { this.f1 }, new DGField[] { this.Laplace_f1_Numerical });
                Laplace.Evaluate(new DGField[] { this.f2 }, new DGField[] { this.Laplace_f2_Numerical });

                double Treshold = 1.0e-8;

                // subtract analytical
                var Errfield1 = Laplace_f1_Numerical.CloneAs();
                Errfield1.Acc(-1, Laplace_f1_Analytical);

                var Errfield2 = Laplace_f2_Numerical.CloneAs();
                Errfield2.Acc(-1, Laplace_f2_Analytical);

                double err_Lf1 = Errfield1.L2Norm() / totalVolume;
                bool   passed  = (err_Lf1 < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| /\\f1 Numerical - /\\f1 Analytical ||_2 = {0} (nonlinear evaluation), passed? {1}", err_Lf1, passed));

                double err_Lf2 = Errfield2.L2Norm() / totalVolume;
                passed   = (err_Lf2 < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| /\\f2 Numerical - /\\f2 Analytical ||_2 = {0} (nonlinear evaluation), passed? {1}", err_Lf2, passed));

                Console.WriteLine("--------------------------------------------");
            }


            // Laplacian, linear
            // ====================

            if (!AltRefSol)
            {
                var Laplace = (new ipLaplace()).Operator(1);

                var LaplaceMtx    = new BlockMsrMatrix(this.f1.Mapping, this.Laplace_f1_Numerical.Mapping);
                var LaplaceAffine = new double[LaplaceMtx.RowPartitioning.LocalLength];

                Laplace.ComputeMatrix(this.f1.Mapping, null, this.Laplace_f1_Numerical.Mapping,
                                      LaplaceMtx, LaplaceAffine, false);

                this.Laplace_f1_Numerical.CoordinateVector.SetV(LaplaceAffine);
                LaplaceMtx.SpMV(1.0, this.f1.CoordinateVector, 1.0, this.Laplace_f1_Numerical.CoordinateVector);

                this.Laplace_f2_Numerical.CoordinateVector.SetV(LaplaceAffine);
                LaplaceMtx.SpMV(1.0, this.f2.CoordinateVector, 1.0, this.Laplace_f2_Numerical.CoordinateVector);

                // subtract analytical
                var Errfield1 = Laplace_f1_Numerical.CloneAs();
                Errfield1.Acc(-1, Laplace_f1_Analytical);

                var Errfield2 = Laplace_f2_Numerical.CloneAs();
                Errfield2.Acc(-1, Laplace_f2_Analytical);


                double Treshold = 1.0e-8;

                double err_Lf1 = Errfield1.L2Norm() / totalVolume;
                bool   passed  = (err_Lf1 < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| /\\f1 Numerical - /\\f1 Analytical ||_2 = {0} (linear evaluation), passed? {1}", err_Lf1, passed));

                double err_Lf2 = Errfield2.L2Norm() / totalVolume;
                passed   = (err_Lf2 < Treshold);
                m_passed = m_passed && passed;
                Console.WriteLine(string.Format("|| /\\f2 Numerical - /\\f2 Analytical ||_2 = {0} (linear evaluation), passed? {1}", err_Lf2, passed));


                // comparison of finite difference Jacobian and Operator matrix
                if (TestFDJacobian)
                {
                    this.f1.Clear();
                    var FDJbuilder = Laplace.GetFDJacobianBuilder(this.f1.Mapping.Fields, null, this.f1.Mapping,
                                                                  delegate(IEnumerable <DGField> U0, IEnumerable <DGField> Params) {
                        return;
                    });
                    var CheckMatrix = new BlockMsrMatrix(FDJbuilder.CodomainMapping, FDJbuilder.DomainMapping);
                    var CheckAffine = new double[FDJbuilder.CodomainMapping.LocalLength];
                    FDJbuilder.ComputeMatrix(CheckMatrix, CheckAffine);

                    var ErrMatrix = LaplaceMtx.CloneAs();
                    var ErrAffine = LaplaceAffine.CloneAs();
                    ErrMatrix.Acc(-1.0, CheckMatrix);
                    ErrAffine.AccV(-1.0, CheckAffine);
                    double LinfMtx = ErrMatrix.InfNorm();
                    double L2Aff   = ErrAffine.L2NormPow2().MPISum().Sqrt();
                    bool   passed1 = (LinfMtx < 1.0e-3);
                    bool   passed2 = (L2Aff < Treshold);
                    Console.WriteLine("Finite Difference Jacobian: Matrix/Affine delta norm {0} {1}, passed? {2} {3}", LinfMtx, L2Aff, passed1, passed2);
                    m_passed = m_passed && passed1;
                    m_passed = m_passed && passed2;
                }
                Console.WriteLine("--------------------------------------------");
            }



            // finally...
            // =================

            if (m_passed)
            {
                Console.WriteLine("All tests passed. *****************************");
            }
            else
            {
                Console.WriteLine("Some error above threshold. *******************");
            }

            return(0.0); // return some artificial timestep
        }
Beispiel #3
0
        private static int[] ComputeChangeOfBasisBlock(
            int[] BlockLen,
            MultidimensionalArray In_MassMatrixBlock, MultidimensionalArray In_OperatorMatrixBlock,
            MultidimensionalArray OUT_LeftPC, MultidimensionalArray OUT_rightPC, Mode PCMode, out int Rank,
            MultidimensionalArray work) //
        {
            Rank = In_MassMatrixBlock.NoOfCols;

            int[] IndefRows = null;

            switch (PCMode)
            {
            case Mode.Eye: {
                OUT_LeftPC.AccEye(1.0);
                OUT_rightPC.AccEye(1.0);
                break;
            }

            case Mode.DiagBlockEquilib: {
                double symmErr = In_OperatorMatrixBlock.SymmetryError();
                double infNorm = In_OperatorMatrixBlock.InfNorm();

                if (symmErr / infNorm > 1.0e-8)
                {
                    throw new ArithmeticException(string.Format("LDL_DiagBlock is not supported on unsymmetric matrices (Symm-Err: {0:0.####E-00}, Inf-Norm: {1:0.####E-00}, Quotient {2:0.####E-00}).", symmErr, infNorm, symmErr / infNorm));
                }
                SymmInv(In_OperatorMatrixBlock, OUT_LeftPC, OUT_rightPC);
                //In_OperatorMatrixBlock.SymmetricLDLInversion(OUT_rightPC, null);
                //OUT_rightPC.TransposeTo(OUT_LeftPC);
                break;
            }

            case Mode.SymPart_DiagBlockEquilib: {
                var SymmPart = work;
                In_OperatorMatrixBlock.TransposeTo(SymmPart);
                SymmPart.Acc(1.0, In_OperatorMatrixBlock);
                SymmPart.Scale(0.5);

                SymmInv(SymmPart, OUT_LeftPC, OUT_rightPC);
                break;
            }

            case Mode.IdMass: {
                In_MassMatrixBlock.SymmetricLDLInversion(OUT_rightPC, default(double[]));
                OUT_rightPC.TransposeTo(OUT_LeftPC);
                break;
            }

            case Mode.LeftInverse_DiagBlock: {
                In_OperatorMatrixBlock.InvertTo(OUT_LeftPC);
                OUT_rightPC.AccEye(1.0);
                break;
            }

            case Mode.LeftInverse_Mass: {
                In_MassMatrixBlock.InvertTo(OUT_LeftPC);
                OUT_rightPC.AccEye(1.0);
                break;
            }

            case Mode.IdMass_DropIndefinite: {
                int[] ZerosEntries = ModifiedInverseChol(In_MassMatrixBlock, OUT_rightPC, 1.0e-12, false);
                int   NoOfZeros    = ZerosEntries == null ? 0 : ZerosEntries.Length;
                IndefRows = ZerosEntries;
                Rank      = OUT_LeftPC.NoOfCols - NoOfZeros;
                OUT_rightPC.TransposeTo(OUT_LeftPC);
                break;
            }

            case Mode.SymPart_DiagBlockEquilib_DropIndefinite: {
                (Rank, IndefRows) = SymPart_DiagBlockEquilib_DropIndefinite(In_MassMatrixBlock, In_OperatorMatrixBlock, OUT_LeftPC, OUT_rightPC, work);

                break;
            }

            case Mode.SchurComplement: {
                //throw new NotImplementedException("todo");

                int NoVars = BlockLen.Length;
                if (NoVars <= 1)
                {
                    throw new NotSupportedException("The Schur complement requires at least 2 variables, moron!");
                }
                int N1 = BlockLen.Take(NoVars - 1).Sum();
                int N2 = BlockLen.Last();
                int N  = N1 + N2;

                //string TestPath = @"C:\Users\flori\OneDrive\MATLAB\Schur";
                //In_OperatorMatrixBlock.SaveToTextFile(Path.Combine(TestPath, "Opm.txt"));

                Debug.Assert(N == In_OperatorMatrixBlock.NoOfRows);
                Debug.Assert(N == In_OperatorMatrixBlock.NoOfCols);

                (MultidimensionalArray M11, MultidimensionalArray M12, MultidimensionalArray M21, MultidimensionalArray M22) GetSubblox(MultidimensionalArray Mtx)
                {
                    return(
                        Mtx.ExtractSubArrayShallow(new[] { 0, 0 }, new[] { N1 - 1, N1 - 1 }),
                        Mtx.ExtractSubArrayShallow(new[] { 0, N1 }, new[] { N1 - 1, N - 1 }),
                        Mtx.ExtractSubArrayShallow(new[] { N1, 0 }, new[] { N - 1, N1 - 1 }),
                        Mtx.ExtractSubArrayShallow(new[] { N1, N1 }, new[] { N - 1, N - 1 })
                        );
                }

                var OpMtxSub = GetSubblox(In_OperatorMatrixBlock);
                var MamaSub  = GetSubblox(In_MassMatrixBlock);
                var workSub  = GetSubblox(work);
                var lpcSub   = GetSubblox(OUT_LeftPC);
                var rpcSub   = GetSubblox(OUT_rightPC);

                (int Rank11, int[] IndefRows11) = SymPart_DiagBlockEquilib_DropIndefinite(MamaSub.M11, OpMtxSub.M11, lpcSub.M11, rpcSub.M11, workSub.M11);

                // compute lpcSub.M11*OpMtxSub.M11*rpcSub.M11
                // (without additional mem-alloc, yeah!)
                var Diag11 = workSub.M11;
                Diag11.GEMM(1.0, lpcSub.M11, OpMtxSub.M11, 0.0);
                OpMtxSub.M11.GEMM(1.0, Diag11, rpcSub.M11, 0.0);

                // invert diag
                if (Rank11 == N1)
                {
                    OpMtxSub.M11.InvertTo(workSub.M11);
                }
                else
                {
                    RankDefInvert(OpMtxSub.M11, workSub.M11);
                }

                //
                OpMtxSub.M11.GEMM(1.0, rpcSub.M11, OpMtxSub.M11, 0.0);
                workSub.M11.GEMM(1.0, OpMtxSub.M11, lpcSub.M11, 0.0);
                var Q = workSub.M11;

                //
                workSub.M21.GEMM(-1.0, OpMtxSub.M21, Q, 0.0);
                workSub.M12.GEMM(-1.0, Q, OpMtxSub.M12, 0.0);

                //rpcSub.M12.SetMatrix(workSub.M12); rpcSub.M22.AccEye(1.0);
                //lpcSub.M21.SetMatrix(workSub.M21); lpcSub.M22.AccEye(1.0);
                //OUT_LeftPC.SaveToTextFile(Path.Combine(TestPath, "Lpc.txt"));
                //OUT_rightPC.SaveToTextFile(Path.Combine(TestPath, "Rpc.txt"));


                rpcSub.M12.GEMM(1.0, Q, OpMtxSub.M12, 0.0);
                OpMtxSub.M22.GEMM(-1.0, OpMtxSub.M21, rpcSub.M12, 1.0);


                (int Rank22, int[] IndefRows22) = SymPart_DiagBlockEquilib_DropIndefinite(MamaSub.M22, OpMtxSub.M22, lpcSub.M22, rpcSub.M22, workSub.M22);

                lpcSub.M21.GEMM(1.0, lpcSub.M22, workSub.M21, 0.0);
                rpcSub.M12.GEMM(1.0, workSub.M12, rpcSub.M22, 0.0);

                //OUT_LeftPC.SaveToTextFile(Path.Combine(TestPath, "Lpc.txt"));
                //OUT_rightPC.SaveToTextFile(Path.Combine(TestPath, "Rpc.txt"));

                if (IndefRows11 != null && IndefRows22 != null)
                {
                    IndefRows = ArrayTools.Cat(IndefRows11, IndefRows22);
                }
                else if (IndefRows11 != null)
                {
                    IndefRows = IndefRows11;
                }
                else if (IndefRows22 != null)
                {
                    IndefRows = IndefRows22;
                }
                else
                {
                    IndefRows = null;
                }

                Rank = Rank11 + Rank22;
                break;
            }

            /*
             * case Mode.LDL_DiagBlock_DropIndefinite: {
             *      if(In_OperatorMatrixBlock.SymmetryError() / In_OperatorMatrixBlock.InfNorm() > 1.0e-8)
             *          throw new NotSupportedException("LDL_DiagBlock is not supported on unsymmetric matrices");
             *      int N = OUT_LeftPC.NoOfCols;
             *
             *      MultidimensionalArray PL = MultidimensionalArray.Create(N, N);
             *      MultidimensionalArray PR = MultidimensionalArray.Create(N, N);
             *
             *      int zeros1 = CRM114(In_MassMatrixBlock, PR, 1.0e-12);
             *      Rank = N - zeros1;
             *      PR.TransposeTo(PL);
             *
             *      var OpTr = (PL * In_OperatorMatrixBlock) * PR;
             *
             *      MultidimensionalArray QL = MultidimensionalArray.Create(N, N);
             *      MultidimensionalArray QR =  MultidimensionalArray.Create(N, N);
             *      int zeros2 = CRM114(OpTr, QR, 1.0e-12);
             *      QR.TransposeTo(QL);
             *
             *      if(zeros1 != zeros2)
             *          // I want this to fire also in Release mode, therfore i don't use Debug.Assert(...)
             *          throw new ApplicationException();
             *
             *
             *      OUT_LeftPC.GEMM(1.0, QL, PL, 0.0);
             *      OUT_rightPC.GEMM(1.0, PR, QR, 0.0);
             *
             *      //if (zeros1 > 0 || zeros2 > 0) {
             *      //    Console.WriteLine("zeros introduced: " + zeros1 + ", " + zeros2);
             *      //}
             *
             *      break;
             *  }
             */
            default:
                throw new NotImplementedException("Unknown option: " + PCMode);
            }

            return(IndefRows);
        }
Beispiel #4
0
        static void SymmInv(MultidimensionalArray M, MultidimensionalArray L, MultidimensionalArray R)
        {
            L.Clear();
            R.Clear();
            L.AccEye(1.0);
#if DEBUG
            var Mbefore = M.CloneAs();
#endif
            int n = M.NoOfRows;
            unsafe
            {
                void RowScale(double *pS, int i, double alpha, int RowCyc)
                {
                    pS += i * RowCyc;
                    for (int nn = 0; nn < n; nn++)
                    {
                        *pS *= alpha;
                        pS++;
                    }
                }

                void ColScale(double *pS, int i, double alpha, int RowCyc)
                {
                    pS += i;
                    for (int nn = 0; nn < n; nn++)
                    {
                        *pS *= alpha;
                        pS += RowCyc;
                    }
                }

                void RowAdd(double *pS, int iSrc, int iDst, double alpha, int RowCyc)
                {
                    double *pDest = pS + iDst * RowCyc;
                    double *pSrc  = pS + iSrc * RowCyc;

                    for (int l = 0; l < n; l++)
                    {
                        *pDest += *pSrc * alpha;
                        pDest++;
                        pSrc++;
                    }
                }

                void ColAdd(double *pS, int iSrc, int iDst, double alpha, int RowCyc)
                {
                    double *pDest = pS + iDst;
                    double *pSrc  = pS + iSrc;

                    for (int l = 0; l < n; l++)
                    {
                        *pDest += *pSrc * alpha;
                        pDest += RowCyc;
                        pSrc  += RowCyc;
                    }
                }

                fixed(double *_pL = L.Storage, _pM = M.Storage)
                {
                    int RowCycL = n > 1 ? (L.Index(1, 0) - L.Index(0, 0)) : 0;
                    int RowCycM = n > 1 ? (M.Index(1, 0) - M.Index(0, 0)) : 0;

                    double *pL = _pL + L.Index(0, 0);
                    double *pM = _pM + M.Index(0, 0);


                    for (int i = 0; i < n; i++)
                    {
                        double M_ii = M[i, i];
                        if (M_ii == 0.0)
                        {
                            throw new ArithmeticException("Zero diagonal element at " + i + "-th row.");
                        }
                        double scl = 1.0 / Math.Sqrt(Math.Abs(M_ii));
                        //M.RowScale(i, scl);
                        //L.RowScale(i, scl);
                        //M.ColScale(i, scl);
                        RowScale(pM, i, scl, RowCycM);
                        RowScale(pL, i, scl, RowCycL);
                        ColScale(pM, i, scl, RowCycM);

                        double diagsign = Math.Sign(M[i, i]);
                        if (diagsign == 0.0)
                        {
                            throw new ArithmeticException("Zero diagonal element at " + i + "-th row.");
                        }
                        if (Math.Abs(Math.Abs(M[i, i]) - 1.0) > 1.0e-8)
                        {
                            throw new ArithmeticException("Unable to create diagonal 1.0.");
                        }

                        for (int k = i + 1; k < n; k++)
                        {
                            double M_ki = M[k, i];

                            RowAdd(pM, i, k, -M_ki * diagsign, RowCycM);
                            RowAdd(pL, i, k, -M_ki * diagsign, RowCycL);
                            ColAdd(pM, i, k, -M_ki * diagsign, RowCycM);

                            Debug.Assert(Math.Abs(M[k, i]) < 1.0e-8);
                            Debug.Assert(Math.Abs(M[i, k]) < 1.0e-8);
                        }

                        /*
                         * unsafe
                         * {
                         *  fixed (double* B_entries = Lo.Storage)
                         *  {
                         *
                         *      int UPLO = 'L', DIAG = 'N';
                         *      LAPACK.F77_LAPACK.DSYTRF_(ref UPLO, ref DIAG, ref n, B_entries, ref n, out info);
                         *  }
                         * }
                         */
                    }
                }
            }
            L.TransposeTo(R);

#if DEBUG
            var Test = MultidimensionalArray.Create(M.Lengths);
            //var Q = MultidimensionalArray.Create(M.Lengths);
            //Test.AccEye(1.0);
            Test.Multiply(-1.0, L, Mbefore, R, 1.0, "ij", "ik", "kl", "lj");
            for (int i = 0; i < n; i++)
            {
                //Debug.Assert((Test[i, i].Abs() - 1.0).Abs() < 1.0e-8);
                //Test[i, i] -= Math.Sign(Test[i, i]);
                Test[i, i] = 0;
            }

            double TestNorm = Test.InfNorm();
            double scale    = Math.Max(Mbefore.InfNorm(), R.InfNorm());
            Debug.Assert(TestNorm / scale < 1.0e-4);

            /*
             * if(TestNorm / scale >= 1.0e-8) {
             *  var MM = Mbefore.CloneAs();
             *  MultidimensionalArray Lo = MultidimensionalArray.Create(n, n);
             *
             *  for(int j = 0; j < n; j++) {
             *      double Lo_jj = MM[j, j];
             *      for(int k = 0; k < j; k++) {
             *          Lo_jj -= Lo[j, k].Pow2();
             *      }
             *
             *      double sig = Math.Abs(Lo_jj);
             *      Lo[j, j] = Math.Sqrt(Lo_jj * sig);
             *
             *
             *      for(int i = j; i < n; i++) {
             *          double acc = MM[i, j];
             *          for(int k = 0; k < j; k++) {
             *              acc -= Lo[i, k] * Lo[j, k];
             *          }
             *
             *          Lo[i, j] = (1 / (Lo[j, j] * sig)) * acc;
             *      }
             *  }
             *
             *  int info = 0;
             *  unsafe {
             *      fixed(double* B_entries = Lo.Storage) {
             *
             *          int UPLO = 'L', DIAG = 'N';
             *          LAPACK.F77_LAPACK.DTRTRI_(ref UPLO, ref DIAG, ref n, B_entries, ref n, out info);
             *      }
             *  }
             *
             *  MultidimensionalArray Up = MultidimensionalArray.Create(n, n);
             *  Lo.TransposeTo(Up);
             *  Test.Clear();
             *  Test.Multiply(-1.0, Lo, Mbefore, R, 1.0, "ij", "ik", "kl", "lj");
             *
             *
             *  for(int i = 0; i < n; i++) {
             *      //Debug.Assert((Test[i, i].Abs() - 1.0).Abs() < 1.0e-8);
             *      Test[i, i] -= Math.Sign(Test[i, i]);
             *  }
             *
             *  double TestNorm1 = Test.InfNorm();
             *  //double scale = Math.Max(Mbefore.InfNorm(), R.InfNorm());
             *  Console.WriteLine(TestNorm1);
             *
             * }
             */
#endif
        }
Beispiel #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="jCell"></param>
        /// <param name="Stencil_jCell"></param>
        /// <param name="input">input</param>
        /// <param name="output">result</param>
        static void FilterStencilProjection(SinglePhaseField output, int jCell, int[] Stencil_jCells, ConventionalDGField input)
        {
            // implementation notes: Fk, persönliche Notizen, 17oct13
            // ------------------------------------------------------
            if (output.Basis.Degree < output.Basis.Degree)
            {
                throw new ArgumentException();
            }

            int N = output.Basis.Length;   // Basis dimension of 'g' in cell 'jCell'
            int K = Stencil_jCells.Length; // number of cells in stencil

            var ExPolMtx = MultidimensionalArray.Create(K, N, N);

            int[,] CellPairs = new int[K, 2];
            for (int k = 0; k < K; k++)
            {
                CellPairs[k, 0] = jCell;
                CellPairs[k, 1] = Stencil_jCells[k];
            }
            output.Basis.GetExtrapolationMatrices(CellPairs, ExPolMtx, null);

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

            MassMatrix.AccEye(1.0); // Mass matrix in jCell itself

            //for (int k = 0; k < K; k++) { // over stencil members ...
            //    for (int l = 0; l < N; l++) { // over rows of mass matrix ...
            //        for (int m = 0; m < N; m++) { // over columns of mass matrix ...

            //            double mass_lm = 0.0;

            //            for (int i = 0; i < N; i++) {
            //                mass_lm += ExPolMtx[k, i, m]*ExPolMtx[k, i, l];
            //            }

            //            MassMatrix[l, m] += mass_lm;
            //        }
            //    }
            //}
            MassMatrix.Multiply(1.0, ExPolMtx, ExPolMtx, 1.0, "lm", "kim", "kil");


            double[] RHS = new double[N];
            double[] f2  = new double[N];
            for (int n = Math.Min(input.Basis.Length, N) - 1; n >= 0; n--)
            {
                RHS[n] = input.Coordinates[jCell, n];
            }
            for (int k = 0; k < K; k++)
            {
                for (int n = Math.Min(input.Basis.Length, N) - 1; n >= 0; n--)
                {
                    f2[n] = input.Coordinates[Stencil_jCells[k], n];
                }
                for (int l = 0; l < N; l++)
                {
                    double acc = 0;
                    for (int i = 0; i < N; i++)
                    {
                        acc += ExPolMtx[k, i, l] * f2[i];
                    }
                    RHS[l] += acc;
                }
            }

            double[] g1 = new double[N];
            MassMatrix.Solve(g1, RHS);

            output.Coordinates.SetRow(jCell, g1);
        }
        private static int[] ComputeChangeOfBasisBlock(MultidimensionalArray In_MassMatrixBlock, MultidimensionalArray In_OperatorMatrixBlock,
                                                       MultidimensionalArray OUT_LeftPC, MultidimensionalArray OUT_rightPC, Mode PCMode, out int Rank,
                                                       MultidimensionalArray work)
        {
            Rank = In_MassMatrixBlock.NoOfCols;

            int[] IndefRows = null;

            switch (PCMode)
            {
            case Mode.Eye: {
                OUT_LeftPC.AccEye(1.0);
                OUT_rightPC.AccEye(1.0);
                break;
            }

            case Mode.DiagBlockEquilib: {
                double symmErr = In_OperatorMatrixBlock.SymmetryError();
                double infNorm = In_OperatorMatrixBlock.InfNorm();

                if (symmErr / infNorm > 1.0e-8)
                {
                    throw new NotSupportedException(string.Format("LDL_DiagBlock is not supported on unsymmetric matrices (Symm-Err: {0:0.####E-00}, Inf-Norm: {1:0.####E-00}, Quotient {2:0.####E-00}).", symmErr, infNorm, symmErr / infNorm));
                }
                SymmInv(In_OperatorMatrixBlock, OUT_LeftPC, OUT_rightPC);
                break;
            }

            case Mode.SymPart_DiagBlockEquilib: {
                var SymmPart = work;
                In_OperatorMatrixBlock.TransposeTo(SymmPart);
                SymmPart.Acc(1.0, In_OperatorMatrixBlock);
                SymmPart.Scale(0.5);

                SymmInv(SymmPart, OUT_LeftPC, OUT_rightPC);
                break;
            }

            case Mode.IdMass: {
                In_MassMatrixBlock.SymmetricLDLInversion(OUT_rightPC, default(double[]));
                OUT_rightPC.TransposeTo(OUT_LeftPC);
                break;
            }

            case Mode.LeftInverse_DiagBlock: {
                In_OperatorMatrixBlock.InvertTo(OUT_LeftPC);
                OUT_rightPC.AccEye(1.0);
                break;
            }

            case Mode.LeftInverse_Mass: {
                In_MassMatrixBlock.InvertTo(OUT_LeftPC);
                OUT_rightPC.AccEye(1.0);
                break;
            }

            case Mode.IdMass_DropIndefinite: {
                int[] ZerosEntries = ModifiedInverseChol(In_MassMatrixBlock, OUT_rightPC, 1.0e-12, false);
                int   NoOfZeros    = ZerosEntries == null ? 0 : ZerosEntries.Length;
                IndefRows = ZerosEntries;
                Rank      = OUT_LeftPC.NoOfCols - NoOfZeros;
                OUT_rightPC.TransposeTo(OUT_LeftPC);
                break;
            }

            case Mode.SymPart_DiagBlockEquilib_DropIndefinite: {
                var SymmPart = work;
                In_OperatorMatrixBlock.TransposeTo(SymmPart);
                SymmPart.Acc(1.0, In_OperatorMatrixBlock);
                SymmPart.Scale(0.5);

                int[] ZerosEntries = ModifiedInverseChol(In_MassMatrixBlock, OUT_rightPC, 1.0e-12, false);
                int   NoOfZeros    = ZerosEntries == null ? 0 : ZerosEntries.Length;
                IndefRows = ZerosEntries;
                Rank      = OUT_LeftPC.NoOfCols - NoOfZeros;

                if (NoOfZeros == 0)
                {
                    // normal cell -- nix indefinite
                    // +++++++++++++++++++++++++++++

                    SymmInv(SymmPart, OUT_LeftPC, OUT_rightPC);
                }
                else
                {
                    // problem-cell
                    // ++++++++++++++

                    OUT_rightPC.TransposeTo(OUT_LeftPC);

                    SymmPart = IMatrixExtensions.GEMM(OUT_LeftPC, SymmPart, OUT_rightPC);

                    int[] ZerosEntries2 = ModifiedInverseChol(SymmPart, OUT_rightPC, 1.0e-12, true);
                    OUT_rightPC.TransposeTo(OUT_LeftPC);

                    if (!ZerosEntries2.SetEquals(ZerosEntries))
                    {
                        throw new ArithmeticException();
                    }


                    break;
                }

                break;
            }

            /*
             * case Mode.LDL_DiagBlock_DropIndefinite: {
             *      if(In_OperatorMatrixBlock.SymmetryError() / In_OperatorMatrixBlock.InfNorm() > 1.0e-8)
             *          throw new NotSupportedException("LDL_DiagBlock is not supported on unsymmetric matrices");
             *      int N = OUT_LeftPC.NoOfCols;
             *
             *      MultidimensionalArray PL = MultidimensionalArray.Create(N, N);
             *      MultidimensionalArray PR = MultidimensionalArray.Create(N, N);
             *
             *      int zeros1 = CRM114(In_MassMatrixBlock, PR, 1.0e-12);
             *      Rank = N - zeros1;
             *      PR.TransposeTo(PL);
             *
             *      var OpTr = (PL * In_OperatorMatrixBlock) * PR;
             *
             *      MultidimensionalArray QL = MultidimensionalArray.Create(N, N);
             *      MultidimensionalArray QR =  MultidimensionalArray.Create(N, N);
             *      int zeros2 = CRM114(OpTr, QR, 1.0e-12);
             *      QR.TransposeTo(QL);
             *
             *      if(zeros1 != zeros2)
             *          // I want this to fire also in Release mode, therfore i don't use Debug.Assert(...)
             *          throw new ApplicationException();
             *
             *
             *      OUT_LeftPC.GEMM(1.0, QL, PL, 0.0);
             *      OUT_rightPC.GEMM(1.0, PR, QR, 0.0);
             *
             *      //if (zeros1 > 0 || zeros2 > 0) {
             *      //    Console.WriteLine("zeros introduced: " + zeros1 + ", " + zeros2);
             *      //}
             *
             *      break;
             *  }
             */
            default:
                throw new NotImplementedException();
            }

            return(IndefRows);
        }
        static void SymmInv(MultidimensionalArray M, MultidimensionalArray L, MultidimensionalArray R)
        {
            L.Clear();
            R.Clear();
            L.AccEye(1.0);
#if DEBUG
            var Mbefore = M.CloneAs();
#endif

            int n = M.NoOfRows;
            for (int i = 0; i < n; i++)
            {
                double M_ii = M[i, i];
                if (M_ii == 0.0)
                {
                    throw new ArithmeticException("Zero diagonal element at " + i + "-th row.");
                }
                double scl = 1.0 / Math.Sqrt(Math.Abs(M_ii));
                M.RowScale(i, scl);
                L.RowScale(i, scl);
                M.ColScale(i, scl);

                double diagsign = Math.Sign(M[i, i]);
                if (diagsign == 0.0)
                {
                    throw new ArithmeticException("Zero diagonal element at " + i + "-th row.");
                }
                if (Math.Abs(Math.Abs(M[i, i]) - 1.0) > 1.0e-8)
                {
                    throw new ArithmeticException("Unable to create diagonal 1.0.");
                }

                for (int k = i + 1; k < n; k++)
                {
                    double M_ki = M[k, i];

                    M.RowAdd(i, k, -M_ki * diagsign);
                    L.RowAdd(i, k, -M_ki * diagsign);
                    M.ColAdd(i, k, -M_ki * diagsign);

                    Debug.Assert(Math.Abs(M[k, i]) < 1.0e-8);
                    Debug.Assert(Math.Abs(M[i, k]) < 1.0e-8);
                }
            }

            L.TransposeTo(R);

#if DEBUG
            var Test = MultidimensionalArray.Create(M.Lengths);
            //var Q = MultidimensionalArray.Create(M.Lengths);
            //Test.AccEye(1.0);
            Test.Multiply(-1.0, L, Mbefore, R, 1.0, "ij", "ik", "kl", "lj");
            for (int i = 0; i < n; i++)
            {
                //Debug.Assert((Test[i, i].Abs() - 1.0).Abs() < 1.0e-8);
                //Test[i, i] -= Math.Sign(Test[i, i]);
                Test[i, i] = 0;
            }

            double TestNorm = Test.InfNorm();
            double scale    = Math.Max(Mbefore.InfNorm(), R.InfNorm());
            Debug.Assert(TestNorm / scale < 1.0e-4);

            /*
             * if(TestNorm / scale >= 1.0e-8) {
             *  var MM = Mbefore.CloneAs();
             *  MultidimensionalArray Lo = MultidimensionalArray.Create(n, n);
             *
             *  for(int j = 0; j < n; j++) {
             *      double Lo_jj = MM[j, j];
             *      for(int k = 0; k < j; k++) {
             *          Lo_jj -= Lo[j, k].Pow2();
             *      }
             *
             *      double sig = Math.Abs(Lo_jj);
             *      Lo[j, j] = Math.Sqrt(Lo_jj * sig);
             *
             *
             *      for(int i = j; i < n; i++) {
             *          double acc = MM[i, j];
             *          for(int k = 0; k < j; k++) {
             *              acc -= Lo[i, k] * Lo[j, k];
             *          }
             *
             *          Lo[i, j] = (1 / (Lo[j, j] * sig)) * acc;
             *      }
             *  }
             *
             *  int info = 0;
             *  unsafe {
             *      fixed(double* B_entries = Lo.Storage) {
             *
             *          int UPLO = 'L', DIAG = 'N';
             *          LAPACK.F77_LAPACK.DTRTRI_(ref UPLO, ref DIAG, ref n, B_entries, ref n, out info);
             *      }
             *  }
             *
             *  MultidimensionalArray Up = MultidimensionalArray.Create(n, n);
             *  Lo.TransposeTo(Up);
             *  Test.Clear();
             *  Test.Multiply(-1.0, Lo, Mbefore, R, 1.0, "ij", "ik", "kl", "lj");
             *
             *
             *  for(int i = 0; i < n; i++) {
             *      //Debug.Assert((Test[i, i].Abs() - 1.0).Abs() < 1.0e-8);
             *      Test[i, i] -= Math.Sign(Test[i, i]);
             *  }
             *
             *  double TestNorm1 = Test.InfNorm();
             *  //double scale = Math.Max(Mbefore.InfNorm(), R.InfNorm());
             *  Console.WriteLine(TestNorm1);
             *
             * }
             */
#endif
        }
Beispiel #8
0
            /// <summary>
            /// Orthonormalization for curved elements
            /// </summary>
            protected override MultidimensionalArray Compute_OrthonormalizationTrafo(int j0, int Len, int Degree)
            {
                // init
                // ====

                int            iKref    = this.m_Owner.iGeomCells.GetRefElementIndex(j0);
                PolynomialList Polys    = this.GetOrthonormalPolynomials(Degree)[iKref];
                int            N        = Polys.Count;
                CellType       cellType = this.m_Owner.iGeomCells.GetCellType(j0);

#if DEBUG
                // checking
                for (int j = 1; j < Len; j++)
                {
                    int jCell = j + j0;

                    if (this.m_Owner.iGeomCells.GetCellType(jCell) != cellType)
                    {
                        throw new NotSupportedException("All cells in chunk must have same type.");
                    }
                }
#endif
                // storage for result
                MultidimensionalArray NonlinOrtho = MultidimensionalArray.Create(Len, N, N);


                if (m_Owner.iGeomCells.IsCellAffineLinear(j0))
                {
                    // affine-linear branch
                    // ++++++++++++++++++++

                    MultidimensionalArray scl = this.Scaling;

                    for (int j = 0; j < Len; j++)
                    {
                        int jCell = j + j0;

                        double scl_j = scl[jCell];

                        for (int n = 0; n < N; n++)
                        {
                            NonlinOrtho[j, n, n] = scl_j;
                        }
                    }
                }
                else
                {
                    // nonlinear cells branch
                    // ++++++++++++++++++++++

                    // init
                    // ====

                    var Kref = m_Owner.iGeomCells.GetRefElement(j0);
                    int deg; // polynomial degree of integrand: Degree of Jacobi determinat + 2* degree of basis polynomials in ref.-space.
                    {
                        int D = m_Owner.SpatialDimension;
                        deg = Kref.GetInterpolationDegree(cellType);
                        if (deg > 1)
                        {
                            deg -= 1;
                        }
                        deg *= D;
                        deg += 2 * Degree;
                    }
                    var qr = Kref.GetQuadratureRule((int)deg);
                    int K  = qr.NoOfNodes;

                    // evaluate basis polys in ref space
                    // =================================

                    MultidimensionalArray BasisValues = this.EvaluateBasis(qr.Nodes, Degree);
                    Debug.Assert(BasisValues.GetLength(0) == K);
                    if (BasisValues.GetLength(0) > N)
                    {
                        BasisValues = BasisValues.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { K - 1, N - 1 });
                    }

                    // compute \f$ A_{k n m} = \phi_{k n} \phi_{k m} w_{k} \f$
                    // (cell-INdependentd part of mass matrix computation)
                    // ==================================================================

                    MultidimensionalArray A = MultidimensionalArray.Create(K, N, N);
                    A.Multiply(1.0, qr.Weights, BasisValues, BasisValues, 0.0, "knm", "k", "kn", "km");

                    // Determine mass matrix  \f$ M \f$ in all cells by quadrature
                    // \f$ M_{n m} = \sum_{k} J_k A_{k n m} \f$
                    // =====================================================

                    MultidimensionalArray J = m_Owner.JacobianDeterminat.GetValue_Cell(qr.Nodes, j0, Len);

                    // store mass-matrix in 'NonlinOrtho' to save mem alloc
                    NonlinOrtho.Multiply(1.0, A, J, 0.0, "jmn", "knm", "jk");


                    // Compute change-of-basis for all cells
                    // (invese of cholesky)
                    // =====================================


                    for (int j = 0; j < Len; j++)
                    {
                        MultidimensionalArray Mj = NonlinOrtho.ExtractSubArrayShallow(j, -1, -1); // mass-matrix of basis on refrence element in cell j+j0


#if DEBUG
                        MultidimensionalArray MjClone = Mj.CloneAs();
#endif

                        //Mj.InvertSymmetrical();
                        Mj.SymmetricLDLInversion(Mj, null);

                        // clear lower triangular part
                        // Debug.Assert(Mj.NoOfCols == N);
                        for (int n = 1; n < N; n++)
                        {
                            for (int m = 0; m < n; m++)
                            {
                                Mj[n, m] = 0.0;
                            }
                        }
#if DEBUG
                        MultidimensionalArray B  = NonlinOrtho.ExtractSubArrayShallow(j, -1, -1);
                        MultidimensionalArray Bt = B.Transpose();
                        double MjNorm            = MjClone.InfNorm();
                        double Bnorm             = B.InfNorm();


                        MultidimensionalArray check = IMatrixExtensions.GEMM(Bt, MjClone, B);
                        check.AccEye(-1.0);
                        double checkNorm = check.InfNorm();

                        double RelErr = checkNorm / Math.Max(MjNorm, Bnorm);

                        Debug.Assert(RelErr < 1.0e-5, "Fatal error in numerical orthonomalization on nonlinear cell.");
#endif
                    }
                }

                // return
                // =========

                return(NonlinOrtho);
            }