public static double rhoDinvA(MsrMatrix A, out MsrMatrix DinvA) { double rho; // extract diagonal matrix double[] Diag = A.GetDiagVector(); int n = Diag.Length; // % form (D^-1) A //Diag = spdiags(1./Diag, 0, n, n); //DinvA = Diag*A; DinvA = new MsrMatrix(A.RowPartitioning, A.ColPartition); int i0 = A.RowPartitioning.i0; int Lr; int[] ColumnIdx = null; double[] Values = null; for (int i = 0; i < n; i++) { Lr = A.GetRow(i + i0, ref ColumnIdx, ref Values); for (int k = 0; k < Lr; k++) { Values[k] *= 1.0 / Diag[i]; } DinvA.SetRow(i + i0, ColumnIdx, Values, Lr); } #if DEBUG for (int i = 0; i < n; i++) { Debug.Assert(Math.Abs(1.0 - DinvA[i + i0, i + i0]) < BLAS.MachineEps * 10); } #endif // estimate the largest eigen value from Arnoldi iteration int kk = 20; var rand = new Random(0); double[] v0 = n.ForLoop(i => rand.NextDouble()); double[][] V; double[,] H; int kact; arnoldi(out V, out H, out kact, DinvA, v0, kk, false); kk = Math.Min(H.GetLength(0), H.GetLength(1)); H = H.GetSubMatrix(0, kk, 0, kk); rho = MaxAbsEigen(H); return(rho); }
private static void CheckMatrix(MsrMatrix MM, int iRow0, int N, int iRow) { int[] Cols = null; double[] Vals = null; int LR = MM.GetRow(iRow, ref Cols, ref Vals); int cMin = int.MaxValue; int cMax = int.MinValue; for (int lr = 0; lr < LR; lr++) { if (Vals[lr] != 0.0) { cMin = Math.Min(cMin, Cols[lr]); cMax = Math.Max(cMax, Cols[lr]); } } Debug.Assert(cMin >= iRow0); Debug.Assert(cMax < iRow0 + N); }
private static MsrMatrix ColumnPermute(MsrMatrix M, int[] ColPerm) { MsrMatrix M2; M2 = new MsrMatrix(M.RowPartitioning, M.ColPartition); int[] ColIdx = null; double[] MtxVals = null; int LR; for (int i = M2.RowPartitioning.i0; i < M2.RowPartitioning.iE; i++) { //var row = M.GetRow(i); LR = M.GetRow(i, ref ColIdx, ref MtxVals); for (int lr = 0; lr < LR; lr++) { int iCol = ColIdx[lr]; int icol_Targ = ColPerm[iCol]; M2[i, icol_Targ] = MtxVals[lr]; } } return(M2); }
/// <summary> /// /// </summary> /// <param name="jCell"></param> /// <param name="AcceptedMask"></param> /// <param name="Phi"></param> /// <param name="gradPhi"></param> /// <param name="__DiffusionCoeff">Output: if artificial diffusion is turned</param> /// <param name="MaxAllowedPhi">Input: upper threshold for the values of <paramref name="Phi"/> in cell <see cref="jCell"/>.</param> /// <param name="MinAllowedPhi">Input: lower threshold for the values of <paramref name="Phi"/> in cell <see cref="jCell"/>.</param> /// <returns></returns> public bool LocalSolve_Iterative(int jCell, BitArray AcceptedMask, SinglePhaseField Phi, VectorField <SinglePhaseField> gradPhi, SinglePhaseField __DiffusionCoeff, double MaxAllowedPhi, double MinAllowedPhi) { //this.LocalSolve_Geometric(jCell, AcceptedMask, Phi, +1, out MinAllowedPhi, out MaxAllowedPhi);) { int N = this.LevelSetBasis.GetLength(jCell); int i0G = this.LevelSetMapping.GlobalUniqueCoordinateIndex(0, jCell, 0); int i0L = this.LevelSetMapping.LocalUniqueCoordinateIndex(0, jCell, 0); SinglePhaseField __AcceptedMask = new SinglePhaseField(new Basis(this.GridDat, 0), "accepted"); for (int j = 0; j < AcceptedMask.Length; j++) { __AcceptedMask.SetMeanValue(j, AcceptedMask[j] ? 1.0 : 0.0); } // subgrid on which we are working, consisting only of one cell SubGrid jCellGrid = new SubGrid(new CellMask(this.GridDat, Chunk.GetSingleElementChunk(jCell))); // create spatial operator IEvaluatorNonLin evo; { SpatialOperator op = new SpatialOperator(1, 2, 1, QuadOrderFunc.NonLinear(2), "Phi", "dPhi_dx0", "dPhi_dx1", "cod1"); op.EquationComponents["cod1"].Add(new ReinitOperator()); op.EdgeQuadraturSchemeProvider = g => (new EdgeQuadratureScheme(domain: EdgeMask.GetEmptyMask(g))); op.VolumeQuadraturSchemeProvider = g => (new CellQuadratureScheme(domain: jCellGrid.VolumeMask)); op.Commit(); evo = op.GetEvaluatorEx(Phi.Mapping.Fields, gradPhi.Mapping.Fields, Phi.Mapping); evo.ActivateSubgridBoundary(jCellGrid.VolumeMask, subGridBoundaryTreatment: SubGridBoundaryModes.InnerEdge); } // create artificial diffusion operator MultidimensionalArray DiffMtx; double[] DiffRhs; SpatialOperator dop; { double penaltyBase = this.LevelSetBasis.Degree + 2; penaltyBase = penaltyBase.Pow2(); dop = (new ArtificialViscosity(AcceptedMask, penaltyBase, GridDat.Cells.h_min, jCell, -1.0)).Operator(1); MsrMatrix _DiffMtx = new MsrMatrix(this.LevelSetMapping, this.LevelSetMapping); double[] _DiffRhs = new double[this.LevelSetMapping.LocalLength]; dop.ComputeMatrixEx(this.LevelSetMapping, new DGField[] { Phi, null, null }, this.LevelSetMapping, _DiffMtx, _DiffRhs, OnlyAffine: false, edgeQuadScheme: (new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask)), volQuadScheme: (new CellQuadratureScheme(domain: jCellGrid.VolumeMask))); // extract matrix for 'jCell' DiffMtx = MultidimensionalArray.Create(N, N); DiffRhs = new double[N]; for (int n = 0; n < N; n++) { #if DEBUG int Lr; int[] row_cols = null; double[] row_vals = null; Lr = _DiffMtx.GetRow(i0G + n, ref row_cols, ref row_vals); for (int lr = 0; lr < Lr; lr++) { int ColIndex = row_cols[lr]; double Value = row_vals[lr]; Debug.Assert((ColIndex >= i0G && ColIndex < i0G + N) || (Value == 0.0), "Matrix is expected to be block-diagonal."); } #endif for (int m = 0; m < N; m++) { DiffMtx[n, m] = _DiffMtx[i0G + n, i0G + m]; } DiffRhs[n] = _DiffRhs[i0L + n]; } #if DEBUG var Test = DiffMtx.Transpose(); Test.Acc(-1.0, DiffMtx); Debug.Assert(Test.InfNorm() <= 1.0e-8); #endif } // find 'good' initial value by geometric solve AND // thresholds for the maximum an minimal value of Phi double Range = MaxAllowedPhi - MinAllowedPhi; MinAllowedPhi -= 0.1 * Range; MaxAllowedPhi += 0.1 * Range; // timestep for pseudo-timestepping double dt = 0.5 * this.GridDat.Cells.h_min[jCell] / (((double)(this.LevelSetBasis.Degree)).Pow2()); DGField[] PlotFields = new DGField[] { Phi, gradPhi[0], gradPhi[1], __DiffusionCoeff, __AcceptedMask }; //Tecplot.Tecplot.PlotFields(Params, "itt_0", "EllipicReinit", 0, 3); double[] PrevVal = new double[N]; double[] NextVal = new double[N]; Phi.Coordinates.GetRow(jCell, PrevVal); // pseudo-timestepping //if(jCell == 80) // Tecplot.Tecplot.PlotFields(PlotFields, "itt_0", "EllipicReinit", 0, 3); //Console.Write(" Local solve cell " + jCell + " ... "); bool converged = false; double DiffusionCoeff = 0; int IterGrowCount = 0; // number of iterations in which the residual grew double LastResi = double.NaN; for (int iIter = 0; iIter < 1000; iIter++) { //Console.Write(" Local solve iteration " + iIter + " ... "); PerformRKstep(dt, jCell, AcceptedMask, Phi, gradPhi, evo); __DiffusionCoeff.SetMeanValue(jCell, DiffusionCoeff); if (jCell == 80) { DiffusionCoeff = 0.1; } if (DiffusionCoeff > 0) { //Console.WriteLine(" Diffusion on."); double[] _DiffRhs = new double[this.LevelSetMapping.LocalLength]; dop.ComputeMatrixEx(this.LevelSetMapping, new DGField[] { Phi, gradPhi[0], gradPhi[1] }, this.LevelSetMapping, default(MsrMatrix), _DiffRhs, OnlyAffine: true, edgeQuadScheme: (new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask)), volQuadScheme: (new CellQuadratureScheme(domain: CellMask.GetEmptyMask(this.GridDat)))); // extract matrix for 'jCell' for (int n = 0; n < N; n++) { DiffRhs[n] = _DiffRhs[i0L + n]; } PerformArtificialDiffusion(dt * DiffusionCoeff, jCell, Phi, DiffMtx, DiffRhs); } Phi.Coordinates.GetRow(jCell, NextVal); double resi = Math.Sqrt(GenericBlas.L2DistPow2(NextVal, PrevVal) / GenericBlas.L2NormPow2(PrevVal)); double[] A = NextVal; NextVal = PrevVal; PrevVal = A; if (iIter > 0 && resi > LastResi) { IterGrowCount++; } else { IterGrowCount = 0; } LastResi = resi; if (resi < 1.0e-10) { converged = true; break; } double maxPhi, minPhi; Phi.GetExtremalValuesInCell(out minPhi, out maxPhi, jCell); bool MinAlarm = minPhi < MinAllowedPhi; bool Maxalarm = maxPhi > MaxAllowedPhi; bool GrowAlarm = IterGrowCount > 4; bool IterAlarm = iIter >= 50; if (MinAlarm || Maxalarm || GrowAlarm) { // Diffusion coefficient should be increased if (DiffusionCoeff == 0) { DiffusionCoeff = 1.0e-2; } else { if (DiffusionCoeff < 1.0e3) { DiffusionCoeff *= 2; } } //Console.WriteLine(" increasing Diffusion: {0}, Alarms : {1}{2}{3}{4}", DiffusionCoeff, MinAlarm ? 1 : 0, Maxalarm ? 1 : 0, GrowAlarm ? 1 : 0, IterAlarm ? 1 : 0); } //if(jCell == 80 && iIter < 100) // Tecplot.Tecplot.PlotFields(PlotFields, "itt_" + (iIter + 1), "EllipicReinit", iIter + 1, 3); } return(converged); }
private void ApproximationMatrix() { this.Aapprox = null; this.AapproxInverse = null; //MsrMatrix AapproxComp = null; /* * switch(m_SIMPLEOptions.Option_Approximation_Predictor) { * case ApproxPredictor.MassMatrix: * case ApproxPredictor.LocalizedOperator: { break; } * default: { * Aapprox = ConvDiff.CloneAs(); * //switch (m_SIMPLEOptions.Option_Timestepper) { * // case Timestepper.Steady: break; * // case Timestepper.ImplicitEuler: { * // Aapprox.Acc(1.0 / dt, MassMatrix); * // break; * // } * // default: { * // throw new NotImplementedException("Unknown Timestepper"); * // } * //} * AapproxComp = new MsrMatrix(USubMatrixIdx.Length, USubMatrixIdx.Length, MassMatrix.RowPartitioning.BlockSize / (2 * D), MassMatrix.ColPartition.BlockSize / (2 * D)); * Aapprox.WriteSubMatrixTo(AapproxComp, USubMatrixIdx, default(int[]), USubMatrixIdx, default(int[])); * break; * } * } */ switch (m_SIMPLEOptions.Option_Approximation_Predictor) { case ApproxPredictor.MassMatrix: { BlockMsrMatrix MM; if (!double.IsPositiveInfinity(this.m_SIMPLEOptions.dt)) { // instationary SIMPLE //MM = this.m_MgOp.MassMatrix.CloneAs(); // hier muss ich mir nochmal was überlegen -- // für einige Präkond.-Optionen // (genau jene, welche die XDG-Basen für beide Phasen in Cut-Zellen mischen), // wie etwa // MultigridOperator.Mode.SymPart_DiagBlockEquilib // ist eine Block-Skalierung mit rho_A und rho_B // inkonsistent! // throw new NotImplementedException("todo"); } else { MM = this.m_MgOp.MassMatrix; } Aapprox = new MsrMatrix(this.ConvDiff.RowPartitioning); this.m_MgOp.MassMatrix.WriteSubMatrixTo(Aapprox, this.USubMatrixIdx_Row, default(int[]), this.USubMatrixIdx_Row, default(int[])); //AapproxInverse = MassMatrixInv._ToMsrMatrix();// Aapprox.Invert(); //switch(m_SIMPLEOptions.Option_Timestepper) { // case Timestepper.Steady: break; // case Timestepper.ImplicitEuler: { // Aapprox.Scale(1 + 1.0 / dt); // AapproxInverse.Scale(1 / (1 + 1.0 / dt)); // /*#if DEBUG // var CheckMX = AapproxInverse * Aapprox; // foreach (int i in USubMatrixIdx) { // if (Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-10) throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix"); // } // #endif*/ // break; // } // default: { // throw new NotImplementedException("Unknown Timestepper"); // } //} break; } case ApproxPredictor.Exact: { if (this.LsTrk.GridDat.CellPartitioning.MpiSize > 1) { throw new NotSupportedException("Not implemented for MPI-parallel runs."); } //RowIdx = VelocityMapping.GetSubvectorIndices(this.LsTrk, D.ForLoop(d => d), _SpcIds: this.LsTrk.SpeciesIdS, drk: this.TransportAgglomerator); //ColIdx = RowIdx; if (USubMatrixIdx_Row.Length > 4500) { Console.WriteLine(string.Format("WARNING: you don't really want to invert a {0}x{0} matrix.", USubMatrixIdx_Row.Length)); } this.Aapprox = this.ConvDiff; MultidimensionalArray AapproxFull = Aapprox.ToFullMatrixOnProc0(); MultidimensionalArray AapproxInverseFull = AapproxFull.GetInverse(); this.AapproxInverse = new MsrMatrix(new Partitioning(USubMatrixIdx_Row.Length)); this.AapproxInverse.AccDenseMatrix(1.0, AapproxInverseFull); break; } case ApproxPredictor.Diagonal: { /* * Aapprox = new MsrMatrix(ConvDiff.RowPartitioning, ConvDiff.ColPartition); * AapproxInverse = new MsrMatrix(ConvDiff.RowPartitioning, ConvDiff.ColPartition); * foreach(int i in USubMatrixIdx) { * int[] j = new int[] { i }; * double Value = ConvDiff.GetValues(i, j)[0]; * //Value += MassMatrix.GetValues(i, j)[0]; * Aapprox.SetDiagonalElement(i, Value); * if(Value == 0) { * AapproxInverse.SetDiagonalElement(i, 0); * } else { * AapproxInverse.SetDiagonalElement(i, 1 / Value); * } * } #if DEBUG * Aapprox.VerifyDataStructure(); * AapproxInverse.VerifyDataStructure(); * var CheckMX = AapproxInverse * Aapprox; * foreach(int i in USubMatrixIdx) { * if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-13) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix"); * } #endif * break; */ throw new NotImplementedException("todo"); } case ApproxPredictor.BlockDiagonal: { /* * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp); * var AapproxCompInvBD = AapproxCompBD.Invert(); * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(Aapprox, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); * //#if DEBUG * Aapprox.VerifyDataStructure(); * AapproxInverse.VerifyDataStructure(); * var CheckMX = AapproxInverse * Aapprox; * foreach(int i in USubMatrixIdx) { * if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix"); * } * //#endif * * break; */ throw new NotImplementedException("todo"); } case ApproxPredictor.BlockSum: { /* * Console.WriteLine("BlockSum is not properly tested yet and did not work in previous tests"); * int AccdBlockSize = ConvDiff.RowPartitioning.BlockSize / (2 * D); * var AapproxBD = new BlockDiagonalMatrix(ConvDiff.RowPartitioning); * var Aapprox = new MsrMatrix(ConvDiff.RowPartitioning); * int[] indexer = new int[AccdBlockSize]; * for(int i = 0; i < indexer.Length; i++) { * indexer[i] = i; * } * int[] rowindexer = indexer.CloneAs(); * * * for(int i = 0; i < ConvDiff.NoOfRows / AccdBlockSize; i++) { * int[] colindexer = indexer.CloneAs(); * for(int j = 0; j < ConvDiff.NoOfCols / AccdBlockSize; j++) { * ConvDiff.AccSubMatrixTo(1.0, Aapprox, rowindexer, rowindexer, colindexer, rowindexer); * for(int r = 0; r < indexer.Length; r++) { * colindexer[r] += AccdBlockSize; * } * } * for(int r = 0; r < indexer.Length; r++) { * rowindexer[r] += AccdBlockSize; * } * } * //if (m_SIMPLEOptions.Option_Timestepper == Timestepper.ImplicitEuler) { * // Aapprox.Acc(1 / dt, MassMatrix); * //} * AapproxComp = new MsrMatrix(USubMatrixIdx.Length, USubMatrixIdx.Length, AccdBlockSize, AccdBlockSize); * Aapprox.WriteSubMatrixTo(AapproxComp, USubMatrixIdx, default(int[]), USubMatrixIdx, default(int[])); * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp); * var AapproxCompInvBD = AapproxCompBD.Invert(); * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); #if DEBUG * Aapprox.VerifyDataStructure(); * AapproxInverse.VerifyDataStructure(); * * // Check copying back and forth * var CheckAapproxComp = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * AapproxComp.WriteSubMatrixTo(CheckAapproxComp, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); * CheckAapproxComp.Acc(-1.0, Aapprox); * if(CheckAapproxComp.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix"); * * //Check Transformation to BlockdiagonalMatrix * var CheckAapproxCompBD = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(CheckAapproxCompBD, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); * CheckAapproxCompBD.Acc(-1.0, Aapprox); * if(CheckAapproxCompBD.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix"); * * //Check Matrix Inversion * var CheckMX = AapproxInverse * Aapprox; * foreach(int i in USubMatrixIdx) { * if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix"); * } #endif * break; */ throw new NotImplementedException("todo"); } case ApproxPredictor.Neumann: { /* * Console.WriteLine("Neumann did not work in previous Tests, Series does typically not converge"); * int serieslength = 10; * * Aapprox = ConvDiff.CloneAs(); * //if (m_SIMPLEOptions.Option_Timestepper != Timestepper.Steady) { * // Aapprox.Acc(1.0 / dt, MassMatrix); * //} * var B = Aapprox.CloneAs(); * double ScalingFactor = Aapprox.InfNorm(); * B.Scale((-1.0 / ScalingFactor.Pow(0))); //Scaling Power up to 4 tried * B.AccEyeSp(1.0); * AapproxInverse = B; * AapproxInverse.AccEyeSp(1.0); * MsrMatrix OldMoment = B; * for(int i = 0; i <= serieslength; i++) { * var NewMoment = OldMoment * B; * AapproxInverse.Acc(1.0, NewMoment); * //Debug * Console.WriteLine("MomentNumber #{0}, InfNormOf Inverse #{1}", i, NewMoment.InfNorm()); * OldMoment = NewMoment; * } * AapproxInverse.Scale((1.0 / ScalingFactor.Pow(0))); //Scaling Power up to 4 tried * break; */ throw new NotImplementedException("todo"); } case ApproxPredictor.LocalizedOperator: { /* * Console.WriteLine("Localized Operator did not work in previous Tests"); * double[] LocalizedOpAffine; * MultiphaseCellAgglomerator LocalizedAgglomerator; * Aapprox = new MsrMatrix(MassMatrix.RowPartitioning, MassMatrix.ColPartition); * TransportOpLocalized.AssembleMatrix( * out Aapprox, out LocalizedOpAffine, * out LocalizedAgglomerator, out TransportMassFact, * this.Velocity.Current, null, * this.LevSet, null, Curv, * VelocityMapping, VelocityMapping); * if(Option_Timestepper == Timestepper.ImplicitEuler) { * Aapprox.Acc(1 / dt, MassMatrix); * } * * var DiagAverage = Aapprox.GetDiagVector().Average(); * foreach(int i in RowIdx) { * if(Aapprox.GetDiagonalElement(i) == 0.0) { * //Aapprox.SetDiagonalElement(i, MassMatrix.GetDiagonalElement(i)); * Aapprox.SetDiagonalElement(i, DiagAverage); * } * } * AapproxComp = new MsrMatrix(RowIdx.Length, RowIdx.Length, MassMatrix.RowPartitioning.BlockSize / (2 * D), MassMatrix.ColPartition.BlockSize / (2 * D)); * Aapprox.WriteSubMatrixTo(AapproxComp, RowIdx, default(int[]), ColIdx, default(int[])); * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp); * var AapproxCompInvBD = AapproxCompBD.Invert(); * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), RowIdx, default(int[]), ColIdx); * //AapproxComp._ToMsrMatrix().WriteSubMatrixTo(Aapprox, default(int[]), RowIdx, default(int[]), ColIdx); * * #if DEBUG * Aapprox.VerifyDataStructure(); * AapproxInverse.VerifyDataStructure(); * var CheckAapproxCompBD = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(CheckAapproxCompBD, default(int[]), RowIdx, default(int[]), ColIdx); * CheckAapproxCompBD.Acc(-1.0, Aapprox); * if(CheckAapproxCompBD.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix"); * var CheckMX = AapproxInverse * Aapprox; * foreach(int i in RowIdx) { * if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix"); * } #endif * break; */ throw new NotImplementedException("todo"); } default: throw new NotImplementedException("todo"); } if (this.AapproxInverse == null) { // block-inversion is required. // ++++++++++++++++++++++++++++ int D = this.LsTrk.GridDat.SpatialDimension; this.AapproxInverse = new MsrMatrix(this.Aapprox.RowPartitioning, this.Aapprox.ColPartition); //int N = this.m_MgOp.Mapping.AggBasis.GetMinimalLength(this.m_MgOp.Mapping.DgDegree[0]); //Debug.Assert(this.Aapprox.RowPartitioning.LocalLength % N == 0); MultidimensionalArray Block = new MultidimensionalArray(2); MultidimensionalArray InvBlock = new MultidimensionalArray(2); int iRow0 = this.Aapprox.RowPartitioning.i0; int JAGG = this.m_MgOp.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; int[] DegreeS = this.m_MgOp.Mapping.DgDegree; for (int jagg = 0; jagg < JAGG; jagg++) // loop over aggregate cells... { for (int d = 0; d < D; d++) // loop over velocity components... { int N = this.m_MgOp.Mapping.AggBasis[d].GetLength(jagg, DegreeS[d]); if (Block.GetLength(0) != N) { Block.Allocate(N, N); InvBlock.Allocate(N, N); } for (int n = 0; n < N; n++) { #if DEBUG int iRow = iRow0 + n; { int[] Cols = null; double[] Vals = null; int LR = Aapprox.GetRow(iRow, ref Cols, ref Vals); int cMin = int.MaxValue; int cMax = int.MinValue; for (int lr = 0; lr < LR; lr++) { if (Vals[lr] != 0.0) { cMin = Math.Min(cMin, Cols[lr]); cMax = Math.Max(cMax, Cols[lr]); } } Debug.Assert(cMin >= iRow0); Debug.Assert(cMax < iRow0 + N); } #endif for (int m = 0; m < N; m++) { Block[n, m] = this.Aapprox[iRow0 + n, iRow0 + m]; } } Block.InvertTo(InvBlock); for (int n = 0; n < N; n++) { for (int m = 0; m < N; m++) { this.AapproxInverse[iRow0 + n, iRow0 + m] = InvBlock[n, m]; } } iRow0 += N; } } Debug.Assert(iRow0 == this.Aapprox.RowPartitioning.iE); } #if DEBUG var CheckMX = AapproxInverse * Aapprox; double TRESH = Math.Max(AapproxInverse.InfNorm(), Aapprox.InfNorm()) * 1.0e-10; for (int iRow = CheckMX.RowPartitioning.i0; iRow < CheckMX.RowPartitioning.iE; iRow++) { if (Math.Abs(CheckMX.GetDiagonalElement(iRow) - 1.0) > TRESH) { throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix"); } } #endif }
void ExtractMatrices() { // dispose old solver, if required // =============================== if (this.m_PressureSolver != null) { this.m_PressureSolver.Dispose(); this.m_PressureSolver = null; } // sub-matrices for the Potential Solver // ===================================== int VelocityLength = this.USubMatrixIdx_Row.Length; int PressureLength = this.PSubMatrixIdx_Row.Length; this.PressureGrad = new MsrMatrix(VelocityLength, PressureLength, 1, 1); this.VelocityDiv = new MsrMatrix(PressureLength, VelocityLength, 1, 1); this.Stab = new MsrMatrix(PressureLength, PressureLength, 1, 1); var WholeSystemMatrix = this.m_MgOp.OperatorMatrix; WholeSystemMatrix.WriteSubMatrixTo(PressureGrad, USubMatrixIdx_Row, default(int[]), PSubMatrixIdx_Row, default(int[])); WholeSystemMatrix.WriteSubMatrixTo(VelocityDiv, PSubMatrixIdx_Row, default(int[]), USubMatrixIdx_Row, default(int[])); WholeSystemMatrix.WriteSubMatrixTo(Stab, PSubMatrixIdx_Row, default(int[]), PSubMatrixIdx_Row, default(int[])); // inverse mass matrix // =================== if (this.m_SIMPLEOptions.PotentialSolver_UseMassMatrix) { // extract the mass-matrix block for the velocity part // --------------------------------------------------- MsrMatrix MM = new MsrMatrix(this.PressureGrad.RowPartitioning, this.VelocityDiv.ColPartition); this.m_MgOp.MassMatrix.WriteSubMatrixTo(MM, this.USubMatrixIdx_Row, default(int[]), this.USubMatrixIdx_Row, default(int[])); // invert mass matrix // ------------------ int D = this.LsTrk.GridDat.SpatialDimension; this.invMM = new MsrMatrix(MM.RowPartitioning, MM.ColPartition); MultidimensionalArray Block = new MultidimensionalArray(2); MultidimensionalArray InvBlock = new MultidimensionalArray(2); int iRow0 = MM.RowPartitioning.i0; int JAGG = this.m_MgOp.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; int[] DegreeS = this.m_MgOp.Mapping.DgDegree; for (int jagg = 0; jagg < JAGG; jagg++) // loop over aggregate cells... { for (int d = 0; d < D; d++) // loop over velocity components... { int N = this.m_MgOp.Mapping.AggBasis[d].GetLength(jagg, DegreeS[d]); if (Block.GetLength(0) != N) { Block.Allocate(N, N); InvBlock.Allocate(N, N); } for (int n = 0; n < N; n++) { #if DEBUG int iRow = iRow0 + n; { int[] Cols = null; double[] Vals = null; int LR = MM.GetRow(iRow, ref Cols, ref Vals); int cMin = int.MaxValue; int cMax = int.MinValue; for (int lr = 0; lr < LR; lr++) { if (Vals[lr] != 0.0) { cMin = Math.Min(cMin, Cols[lr]); cMax = Math.Max(cMax, Cols[lr]); } } Debug.Assert(cMin >= iRow0); Debug.Assert(cMax < iRow0 + N); } #endif for (int m = 0; m < N; m++) { Block[n, m] = MM[iRow0 + n, iRow0 + m]; } } Block.InvertTo(InvBlock); for (int n = 0; n < N; n++) { for (int m = 0; m < N; m++) { this.invMM[iRow0 + n, iRow0 + m] = InvBlock[n, m]; } } iRow0 += N; } } Debug.Assert(iRow0 == MM.RowPartitioning.iE); #if DEBUG var CheckMX = MM * invMM; double TRESH = Math.Max(MM.InfNorm(), invMM.InfNorm()) * 1.0e-10; for (int iRow = CheckMX.RowPartitioning.i0; iRow < CheckMX.RowPartitioning.iE; iRow++) { if (Math.Abs(CheckMX.GetDiagonalElement(iRow) - 1.0) > TRESH) { throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix"); } } #endif } }