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); }
/// <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 }
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); }
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 }
/// <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 }
/// <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); }