/// <summary> /// Rhs corrector, cf. right-hand side of Eq. (17) in /// B. Klein, F. Kummer, M. Keil, and M. Oberlack, /// An extension of the SIMPLE based discontinuous Galerkin solver to unsteady incompressible flows, J. Comput. Phys., 2013. /// </summary> /// <param name="dt"></param> /// <param name="SpatialComponent"></param> /// <returns></returns> protected override IList <double> DefineRhs(double dt, int SpatialComponent) { double[] Rhs = new double[m_DivB4.DOFLocal]; // calculate mass defect m_DivB4.Clear(); SolverUtils.CalculateMassDefect_Divergence(m_VelocityDivergence, m_Velocity_Intrmed, m_DivB4); Rhs.AccV(1.0, m_DivB4.CoordinateVector); // pressure stabilization if (base.m_solverConf.Control.PressureStabilizationScaling > 0.0) { double[] PressureStabi = new double[Rhs.Length]; m_PressureStabilization.OperatorMatrix.SpMVpara(1.0, m_Pressure.CoordinateVector, 0.0, PressureStabi); Rhs.AccV(1.0, PressureStabi); } // reference point pressure if (base.m_solverConf.Control.PressureReferencePoint != null) { BoSSS.Solution.NSECommon.SolverUtils.SetRefPtPressure_Rhs(Rhs, base.m_solverConf.PressureReferencePointIndex, m_MatAsmblyCorrector.i0); } return(Rhs); }
protected override IList <double> DefineRhs(double dt, int SpatialComponent) { double[] Rhs = new double[DivB4.DOFLocal]; // calculate mass defect DivB4.Clear(); SolverUtils.CalculateMassDefect_Divergence(VelocityDivergence, Velocity_Intrmed, DivB4); Rhs.AccV(1.0, DivB4.CoordinateVector); // time derivative density if (base.m_solverConf.Control.Algorithm == SolutionAlgorithms.Unsteady_SIMPLE) { SinglePhaseField DensitySummand = new SinglePhaseField(DivB4.Basis); BDF.ComputeDensitySummand(dt, base.m_solverConf.BDFOrder, Temperature, EoS, DensitySummand); Rhs.AccV(1.0, DensitySummand.CoordinateVector); } // reference point pressure if (base.m_solverConf.Control.PressureReferencePoint != null) { BoSSS.Solution.NSECommon.SolverUtils.SetRefPtPressure_Rhs(Rhs, base.m_solverConf.PressureReferencePointIndex, MatAsmblyCorrector.i0); } return(Rhs); }
private void recomb(double[] Velocity, double[] Pressure, List <double[]> Z, List <double[]> Q) { int L = this.USubMatrixIdx_Row.Length + this.PSubMatrixIdx_Row.Length; if (this.m_SIMPLEOptions.CorrrectionMode == SimpleCorrectionMode.ResidualMinimization) { double[] Z1 = new double[L]; if (Velocity != null) { Z1.AccV(1.0, Velocity, this.USubMatrixIdx_Row, default(int[])); } if (Pressure != null) { Z1.AccV(1.0, Pressure, this.PSubMatrixIdx_Row, default(int[])); } double[] Q1 = new double[L]; this.m_MgOp.OperatorMatrix.SpMV(1.0, Z1, 0.0, Q1); Z.Add(Z1); Q.Add(Q1); } else if (this.m_SIMPLEOptions.CorrrectionMode == SimpleCorrectionMode.ResidualMinimization_perSpecies) { if (this.PSpcSubMatrix_Row.Length != this.USpcSubMatrix_Row.Length) { throw new ApplicationException(); } int NoOfSpc = PSpcSubMatrix_Row.Length; for (int iSpc = 0; iSpc < NoOfSpc; iSpc++) { double[] Z4 = new double[L]; if (Velocity != null) { Z4.AccV(1.0, Velocity, this.USpcSubMatrix_Row[iSpc], default(int[])); } if (Pressure != null) { Z4.AccV(1.0, Pressure, this.PSpcSubMatrix_Row[iSpc], default(int[])); } double[] Q4 = new double[L]; this.m_MgOp.OperatorMatrix.SpMV(1.0, Z4, 0.0, Q4); Z.Add(Z4); Q.Add(Q4); } } else { throw new NotImplementedException(); } }
private void AssembleMatrix(double dt, out BlockMsrMatrix SystemMatrix, out double[] SystemAffine) { // Init Matrix and Affine Part SystemMatrix = new BlockMsrMatrix(Mapping); SystemAffine = new double[Mapping.LocalLength]; // choose TimeStepping-Scheme, based on what has been pushed to the stack,yet int Smax = TSCchain[0].S; Debug.Assert(Smax == TSCchain.Length); Tsc = TSCchain[Smax - PopulatedStackDepth]; UpdateOperatorMatrix(); //Implicit Part of RHS SystemMatrix.Acc(Tsc.theta1, Stack_OpMatrix[1]); SystemAffine.AccV(Tsc.theta1, Stack_OpAffine[1]); //Implicit Part of LHS SystemMatrix.AccEyeSp(1 / dt); // Explicit part of RHS Stack_OpMatrix[0].SpMV(-Tsc.theta0, CurrentState, 1.0, SystemAffine); SystemAffine.AccV(-Tsc.theta0, Stack_OpAffine[0]); //Explicit parts of LHS for (int i = 0; i < Tsc.beta.Length; i++) { SystemAffine.AccV(Tsc.beta[i] * 1 / dt, Stack_u[i]); } Debug.Assert(SystemMatrix.InfNorm() > 0); Debug.Assert(SystemAffine.L2Norm() > 0); if (subGrid != null) { int[] SubVecIdx = Mapping.GetSubvectorIndices(subGrid, true, new int[] { 0 }); int L = SubVecIdx.Length; for (int i = 0; i < L; i++) { SystemMatrix.ClearRow(SubVecIdx[i]); SystemMatrix[SubVecIdx[i], SubVecIdx[i]] = 1; SystemAffine[SubVecIdx[i]] = 0; } } }
public void TransformRhsInto <T1, T2>(T1 u_IN, T2 v_OUT) where T1 : IList <double> where T2 : IList <double> { if (this.FinerLevel != null) { throw new NotSupportedException("Only supported on finest level."); } if (u_IN.Count != this.Mapping.ProblemMapping.LocalLength) { throw new ArgumentException("Mismatch in length of input vector.", "u"); } if (v_OUT.Count != this.Mapping.LocalLength) { throw new ArgumentException("Mismatch in length of output vector.", "v"); } int L = this.Mapping.LocalLength; double[] uc = new double[L]; uc.AccV(1.0, u_IN, default(int[]), this.IndexIntoProblemMapping_Local); if (this.LeftChangeOfBasis != null) { this.LeftChangeOfBasis.SpMV(1.0, uc, 0.0, v_OUT); } else { v_OUT.SetV(uc); } }
/// <summary> /// computes the pressure correction. /// </summary> /// <param name="Pressure">input: current pressure</param> /// <param name="VelocityPCorrIn">input: intermediate velocity</param> /// <param name="PressurePCorr">output: pressure correction</param> /// <param name="RHSContinuity">input: RHS of the continuity equation</param> /// <returns></returns> double PressureCorrector(double[] Pressure, double[] VelocityPCorrIn, double[] PressurePCorr, double[] RHSContinuity) { using (new FuncTrace()) { // solve Poisson equation // ====================== // Matrix: Div*A^-1*Grad + S InitPressureSolver(); // RHS var RHS = new double[Pressure.Length]; { RHS.AccV(-1.0, RHSContinuity); VelocityDiv.SpMVpara(+1.0, VelocityPCorrIn, 1.0, RHS); Stab.SpMVpara(+1.0, Pressure, 1.0, RHS); } // solve m_PressureSolver.Solve(PressurePCorr, RHS); // return return(PressurePCorr.L2Norm()); } }
static void PrlgAndRestTestRec(int p, MultigridMapping[] MgMapSeq) { var currentLevelMap = MgMapSeq.First(); var AggBasis = currentLevelMap.AggBasis[0]; // allocate vector on full grid var Test = new SinglePhaseField(new Basis(grid, p)); var PrlgVec = Test.CoordinateVector; // init test vector Random rnd = new Random(); double[] RestVec = new double[AggBasis.LocalDim]; RestVec = AggBasis.LocalDim.ForLoop(i => rnd.NextDouble()); // prolongate test vector AggBasis.ProlongateToFullGrid(PrlgVec, RestVec); // calculate restriction of the prolongated vector double[] RestVec2 = new double[RestVec.Length]; AggBasis.RestictFromFullGrid(PrlgVec, RestVec2); // original and second restriction should be equal RestVec.AccV(-1.0, RestVec2); double ErrNorm = RestVec.L2Norm(); Console.WriteLine("Prolongation/Restriction test (p={1}, level={2}): {0}", ErrNorm, p, currentLevelMap.AggGrid.MgLevel); Assert.Less(ErrNorm, 1.0e-8); if (MgMapSeq.Length > 1) { PrlgAndRestTestRec(p, MgMapSeq.Skip(1).ToArray()); } }
/// <summary> /// Finite difference directional derivative Approximate f'(x) w /// C.T.Kelley, April 1, 2003 /// This code comes with no guarantee or warranty of any kind. /// </summary> /// <param name="SolutionVec">Solution point</param> /// <param name="w">Direction</param> /// <param name="f0">f0, usually has been calculated earlier</param> /// <param name="linearization">True if the Operator should be linearized and evaluated afterwards</param> /// <returns></returns> public double[] dirder(CoordinateVector SolutionVec, double[] currentX, double[] w, double[] f0, bool linearization = false) { using (var tr = new FuncTrace()) { double epsnew = 1E-7; int n = SolutionVec.Length; double[] fx = new double[f0.Length]; // Scale the step if (w.L2NormPow2().MPISum().Sqrt() == 0) { fx.Clear(); return(fx); } var normw = w.L2NormPow2().MPISum().Sqrt(); double xs = GenericBlas.InnerProd(currentX, w).MPISum() / normw; if (xs != 0) { epsnew = epsnew * Math.Max(Math.Abs(xs), 1) * Math.Sign(xs); } epsnew = epsnew / w.L2NormPow2().MPISum().Sqrt(); var del = currentX.CloneAs(); del.AccV(epsnew, w); double[] temp = new double[SolutionVec.Length]; temp.CopyEntries(SolutionVec); this.CurrentLin.TransformSolFrom(SolutionVec, del); // Just evaluate linearized operator //var OpAffineRaw = this.LinearizationRHS.CloneAs(); //this.CurrentLin.OperatorMatrix.SpMV(1.0, new CoordinateVector(SolutionVec.Mapping.Fields.ToArray()), 1.0, OpAffineRaw); //CurrentLin.TransformRhsInto(OpAffineRaw, fx); if (linearization == false) { EvaluateOperator(1.0, SolutionVec.Mapping.Fields, fx); } //else { // this.m_AssembleMatrix(out OpMtxRaw, out OpAffineRaw, out MassMtxRaw, SolutionVec.Mapping.Fields.ToArray(), true); // OpMtxRaw.SpMV(1.0, new CoordinateVector(SolutionVec.Mapping.Fields.ToArray()), 1.0, OpAffineRaw); // CurrentLin.TransformRhsInto(OpAffineRaw, fx); //} SolutionVec.CopyEntries(temp); // (f1 - f0) / epsnew fx.AccV(1, f0); fx.ScaleV(1 / epsnew); return(fx); } }
void DoCallBack <V>(double[] Velocity, double[] Pressure, V RHS) where V : IList <double> // { if (this.IterationCallback != null) { int LL = this.m_MgOp.Mapping.LocalLength; double[] sol = new double[LL]; double[] res = new double[LL]; res.SetV(RHS); sol.AccV(1.0, Velocity, USubMatrixIdx_Row, default(int[])); sol.AccV(1.0, Pressure, PSubMatrixIdx_Row, default(int[])); this.m_MgOp.OperatorMatrix.SpMV(-1.0, sol, 1.0, res); this.IterationCallback(this.NoOfIterations, sol, res, this.m_MgOp); } }
/// <summary> /// returns the subvector /// corresponding to <see cref="BlockMask"/>. /// Entries of subvector are taken from the local (<paramref name="locFullVector"/>) /// and external (<paramref name="extFullVector"/>) part of the unmasked vector. /// </summary> /// <param name="extFullVector">input, external part of unmasked vector</param> /// <param name="locfullVector">input, local part of unmasked vector</param> /// <returns></returns> public double[] GetSubVec(IList <double> extFullVector, IList <double> locfullVector) { if (BMExt == null) { return(GetSubVec(locfullVector)); } int SubL = BMExt.LocalDOF + BMLoc.LocalDOF; var subvector = new double[SubL]; int acc_offset = BMLoc.LocalDOF; int target_offset = m_map.LocalLength; if (BMExt != null && BMExt.LocalDOF > 0) { subvector.AccV(1.0, extFullVector, default(int[]), BMExt.m_LocalMask, acc_index_shift: acc_offset, b_index_shift: (-target_offset)); } if (BMLoc != null && BMLoc.LocalDOF > 0) { subvector.AccV(1.0, locfullVector, default(int[]), BMLoc.m_LocalMask); } return(subvector); }
public static void SplitVectorOperations( XDGusage UseXdg, int DGOrder, MatrixShape MShape ) { Utils.TestInit((int)UseXdg, DGOrder, (int)MShape); Console.WriteLine("SplitVectorOperations({0},{1},{2})", UseXdg, DGOrder, MShape); //matrix Erzeugung wie in ExtractDiagonalCellBlocks... //Auf der HierarchieEbene, auf der Kopplung ausgesetzt wird kann Auswahl vorgenommen werden //bei var: 0 / 1, bei DG: <=1 / >1, bei spec: A / B, bei Cells: odd / even //accumulierte Teilergebnisse sind dann == fullM*fullX var mop = Utils.CreateTestMGOperator(UseXdg, DGOrder, MShape); var map = mop.Mapping; double[] Vec = Utils.GetRandomVector(mop.Mapping.LocalLength); //Arrange --- setup masking SubBlockSelector sbsA = new SubBlockSelector(map); sbsA.SetDefaultSplitSelection(MShape, true); BlockMask maskA = new BlockMask(sbsA, null); SubBlockSelector sbsB = new SubBlockSelector(map); sbsB.SetDefaultSplitSelection(MShape, false); BlockMask maskB = new BlockMask(sbsB, null); double[] VecAB = new double[Vec.Length]; //Arrange --- some time measurement Stopwatch stw = new Stopwatch(); stw.Reset(); //Act --- stw.Start(); var VecA = maskA.GetSubVec(Vec); var VecB = maskB.GetSubVec(Vec); maskA.AccSubVec(VecA, VecAB); maskB.AccSubVec(VecB, VecAB); stw.Stop(); Debug.Assert(Vec.L2Norm() != 0); double fac = ((MShape == MatrixShape.full_var || MShape == MatrixShape.diagonal_var) && UseXdg == XDGusage.none) ? -2.0 : -1.0; VecAB.AccV(fac, Vec); //Assert --- are extracted blocks and Assert.IsTrue(VecAB.L2Norm() == 0.0, String.Format("L2Norm neq 0!")); }
public static void VectorSplitOperation( [Values(XDGusage.none, XDGusage.all)] XDGusage UseXdg, [Values(2)] int DGOrder, [Values(MatrixShape.full_var_spec, MatrixShape.full_spec, MatrixShape.full)] MatrixShape MShape, [Values(4)] int Res) { Utils.TestInit((int)UseXdg, DGOrder, (int)MShape, Res); Console.WriteLine("VectorSplitOperation({0},{1},{2},{3})", UseXdg, DGOrder, MShape, Res); //Arrange --- create test matrix, MG mapping MultigridOperator mgo = Utils.CreateTestMGOperator(UseXdg, DGOrder, MShape, Res); MultigridMapping map = mgo.Mapping; BlockMsrMatrix M = mgo.OperatorMatrix; BlockMsrMatrix M_ext = BlockMask.GetAllExternalRows(map, M); double[] Vec = Utils.GetRandomVector(M_ext.RowPartitioning.LocalLength); //Arrange --- setup masking SubBlockSelector sbsA = new SubBlockSelector(map); sbsA.SetDefaultSplitSelection(MShape, true, false); BlockMask maskA = new BlockMask(sbsA, M_ext); SubBlockSelector sbsB = new SubBlockSelector(map); sbsB.SetDefaultSplitSelection(MShape, false, false); BlockMask maskB = new BlockMask(sbsB, M_ext); double[] VecAB = new double[Vec.Length]; //Arrange --- some time measurement Stopwatch stw = new Stopwatch(); stw.Reset(); //Act --- stw.Start(); var VecA = maskA.GetSubVec(Vec, new double[0]); var VecB = maskB.GetSubVec(Vec, new double[0]); maskA.AccSubVec(VecA, VecAB, new double[0]); maskB.AccSubVec(VecB, VecAB, new double[0]); stw.Stop(); Debug.Assert(Vec.L2Norm() != 0); double fac = ((MShape == MatrixShape.full_var || MShape == MatrixShape.diagonal_var) && UseXdg == XDGusage.none) ? -2.0 : -1.0; VecAB.AccV(fac, Vec); //Assert --- are extracted blocks and Assert.IsTrue(VecAB.L2Norm() == 0.0, String.Format("L2Norm neq 0!")); }
public void Solve <U, V>(U X, V B) where U : IList <double> where V : IList <double> // { int NoParts = this.BlockIndices.Length; for (int iIter = 0; iIter < m_MaxIterations; iIter++) { this.NoIter++; double[] Res = B.ToArray(); this.MtxFull.SpMV(-1.0, X, 1.0, Res); if (IterationCallback != null) { IterationCallback(iIter, X.ToArray(), Res.CloneAs(), this.m_MgOp); } if (CoarseSolver != null) { var XC = X.ToArray().CloneAs(); double[] bc = new double[m_MgOp.CoarserLevel.Mapping.TotalLength];// = Res.CloneAs(); m_MgOp.CoarserLevel.Restrict(Res.CloneAs(), bc); double[] xc = new double[bc.Length]; CoarseSolver.Solve(xc, bc); m_MgOp.CoarserLevel.Prolongate(1, XC, 1, xc); X.AccV(1.0, XC); if (CoarseSolverIsMultiplicative) { Res.SetV(B); this.MtxFull.SpMV(-1.0, X, 1.0, Res); } } for (int iPart = 0; iPart < NoParts; iPart++) { int[] ci = BlockIndices[iPart]; int L = ci.Length; double[] bi = new double[L]; double[] xi = new double[L]; bi.AccV(1.0, Res, default(int[]), ci); blockSolvers[iPart].Solve(xi, bi); X.AccV(1.0, xi, ci, default(int[])); } } }
/// <summary> /// returns the subvector of <paramref name="fullVector"/> /// corresponding to <see cref="BlockMask"/>. /// </summary> /// <param name="fullVector">input, unmasked vector</param> public double[] GetSubVec(IList <double> fullVector) { double[] subVector; if (m_includeExternalCells) { if (fullVector.Count() != GetLocalandExternalDOF(m_map)) { throw new ArgumentException("Length of targetVector not equal Length of original"); } subVector = new double[BMLoc.LocalDOF + BMExt.LocalDOF]; subVector.AccV(1.0, fullVector, default(int[]), BMLoc.m_LocalMask); subVector.AccV(1.0, fullVector, default(int[]), BMExt.m_LocalMask, acc_index_shift: BMLoc.LocalDOF); } else { if (fullVector.Count() != m_map.LocalLength) { throw new ArgumentException("Length of targetVector not equal Length of original"); } subVector = new double[BMLoc.LocalDOF]; subVector.AccV(1.0, fullVector, default(int[]), BMLoc.m_LocalMask); } return(subVector); }
public static void CellBlockVectorOperations( [Values(XDGusage.none, XDGusage.all)] XDGusage UseXdg, [Values(2)] int DGOrder, [Values(MatrixShape.diagonal, MatrixShape.diagonal_var, MatrixShape.diagonal_spec, MatrixShape.diagonal_var_spec)] MatrixShape MShape ) { //matrix Erzeugung wie in ExtractDiagonalCellBlocks... //Auf der HierarchieEbene, auf der Kopplung ausgesetzt wird kann Auswahl vorgenommen werden //bei var: 0 / 1, bei DG: <=1 / >1, bei spec: A / B, bei Cells: odd / even //accumulierte Teilergebnisse sind dann == fullM*fullX Utils.TestInit((int)UseXdg, DGOrder, (int)MShape); Console.WriteLine("CellBlockVectorOperations({0},{1},{2})", UseXdg, DGOrder, MShape); var mop = Utils.CreateTestMGOperator(UseXdg, DGOrder, MShape); var map = mop.Mapping; double[] Vec = Utils.GetRandomVector(mop.Mapping.LocalLength); //Arrange --- setup masking SubBlockSelector SBS = new SubBlockSelector(map); BlockMask mask = new BlockMask(SBS, null); //Arrange --- some time measurement Stopwatch stw = new Stopwatch(); stw.Reset(); //Assert --- all diagonal blocks are extracted //Assert.IsTrue(blocks.Length == map.LocalNoOfBlocks); double[] Vec_col = new double[map.LocalLength]; for (int i = 0; i < map.LocalNoOfBlocks; i++) { stw.Start(); double[] Vec_i = mask.GetSubVecOfCell(Vec, i); mask.AccSubVecOfCell(Vec_i, i, Vec_col); stw.Stop(); } Vec_col.AccV(-1.0, Vec); //Assert --- are extracted blocks and Assert.IsTrue(Vec_col.L2Norm() == 0.0, String.Format("L2Norm neq 0!")); }
/// <summary> /// Calculate Extension /// </summary> public void ConstructExtension(IList <DGField> InterfaceValue = null, bool nearfield = false) { using (new FuncTrace()) { Extension.Clear(nearfield ? LevelSetTracker.Regions.GetNearFieldMask(1) : null); ComputeMatrices(InterfaceValue ?? InterfaceParams, nearfield); //Solve System double[] RHS = OpAffine.CloneAs(); RHS.ScaleV(-1.0); ISparseSolver slv = Control.solverFactory(); if (nearfield) { SubGrid subGrid = LevelSetTracker.Regions.GetNearFieldSubgrid(1); int[] SubVecIdx = Extension.Mapping.GetSubvectorIndices(subGrid, true, new int[] { 0 }); int L = SubVecIdx.Length; MsrMatrix SubMatrix = new MsrMatrix(L); double[] SubRHS = new double[L]; double[] SubSolution = new double[L]; OpMatrix.AccSubMatrixTo(1.0, SubMatrix, SubVecIdx, default(int[]), SubVecIdx, default(int[])); SubRHS.Clear(); SubSolution.Clear(); SubRHS.AccV(1.0, RHS, default(int[]), SubVecIdx); SubSolution.AccV(1.0, Extension.CoordinateVector, default(int[]), SubVecIdx); slv.DefineMatrix(SubMatrix); slv.Solve(SubSolution, SubRHS); Extension.Clear(subGrid.VolumeMask); Extension.CoordinateVector.AccV(1.0, SubSolution, SubVecIdx, default(int[])); } else { slv.DefineMatrix(OpMatrix); slv.Solve(Extension.CoordinateVector, RHS); } slv.Dispose(); } }
/// <summary> /// Center-of-gravity /// </summary> public double[] GetCenter(int jCell) { int D = m_Owner.SpatialDimension; double VolAcc = 0.0; double[] CenAcc = new double[D]; foreach (int jG in this.AggregateCellToParts[jCell]) { double Vol = m_Owner.m_GeomCellData.GetCellVolume(jG); var g_cent = m_Owner.m_GeomCellData.GetCenter(jG); VolAcc += Vol; CenAcc.AccV(Vol, g_cent); } CenAcc.ScaleV(1 / VolAcc); return(CenAcc); }
public void VelocityPredictor(double[] PressureEstimateIn, double[] VelocityEstimateIn, double[] VelocityPrediction, double[] RHSMomentum) { using (new FuncTrace()) { double m_relax_vel = m_SIMPLEOptions.relax_v; //build Matrix var PredictorMX = ConvDiff.CloneAs(); //underrelaxation LHS if (m_relax_vel <= 0.0) { throw new ArithmeticException("Illegal velocity underrelaxation parameter: " + m_relax_vel); } PredictorMX.Acc((1 - m_relax_vel) / m_relax_vel, Aapprox); #if DEBUG PredictorMX.CheckForNanOrInfM(); #endif // build RHS: b1-grad*p (+ oldVelocities/dt) double[] RHS = new double [RHSMomentum.Length]; RHS.AccV(1.0, RHSMomentum); PressureGrad.SpMVpara(-1.0, PressureEstimateIn, 1.0, RHS); //underrelaxation RHS Aapprox.SpMVpara((1 - m_relax_vel) / m_relax_vel, VelocityEstimateIn, 1.0, RHS); // solve using (ISparseSolver solver = m_SIMPLEOptions.ViscousSolver) { //Agglomerator.ClearAgglomerated(RHS, VelocityMapping); //double SolverResidual = PC.SolveDirect(VelocityPrediction.CoordinateVector, RHS, solver, false); //solver.Dispose(); solver.DefineMatrix(PredictorMX); solver.Solve(VelocityPrediction, RHS); } } }
public void ImplicitEuler(double dt, SubGrid S, SinglePhaseField inout_Levset) { var VolMsk = S.VolumeMask; var EdgMsk = S.InnerEdgesMask; UnsetteledCoordinateMapping Map = inout_Levset.Mapping; if (dt <= 0.0) { throw new ArgumentOutOfRangeException("Timestep size must be greater than 0."); } MsrMatrix Pmtx = PenaltyMatrix(EdgMsk, inout_Levset.Basis, inout_Levset.Basis); Pmtx.Scale(-1.0); int[] SubVecIdx = Map.GetSubvectorIndices(S, true, new int[] { 0 }); int L = SubVecIdx.Length; MsrMatrix SubMtx = new MsrMatrix(L, L); Pmtx.AccSubMatrixTo(1.0, SubMtx, SubVecIdx, default(int[]), SubVecIdx, default(int[])); SubMtx.AccEyeSp(1.0 / dt); double[] RHS = new double[L]; double[] SOL = new double[L]; RHS.AccV(1.0 / dt, inout_Levset.CoordinateVector, default(int[]), SubVecIdx); using (var solver = new PARDISOSolver()) { solver.DefineMatrix(SubMtx); solver.Solve(SOL, RHS); } inout_Levset.CoordinateVector.ClearEntries(SubVecIdx); inout_Levset.CoordinateVector.AccV(1.0, SOL, SubVecIdx, default(int[])); }
/// <summary> /// coarsens level <paramref name="ag"/> /// </summary> public static AggregationGrid Coarsen(IGridData ag) { using (new FuncTrace()) { int J = ag.iLogicalCells.NoOfLocalUpdatedCells; int D = ag.SpatialDimension; // sort cells of parent grid by size: // we want to aggregate the smallest cells at first. int[] Perm = J.ForLoop(j => j).OrderBy(j => ag.iLogicalCells.GetCellVolume(j)).ToArray(); BitArray UsedCellMarker = new BitArray(J); List <int[]> Coarsened_ComositeCells = new List <int[]>(); //List<double> Coarsened_CompositeVolume = new List<double>(); //List<BoundingBox> Coarsened_CompositeCellBB = new List<BoundingBox>(); int[] Parent2Child = new int[J]; List <int[]> child2Parrent = new List <int[]>(); // loop over aggregated cells of parent grid... int[][] Neighbourship = ag.iLogicalCells.CellNeighbours; for (int i = 0; i < J; i++) { int jCell = Perm[i]; Debug.Assert(Neighbourship[jCell].Contains(jCell) == false); if (!UsedCellMarker[jCell]) { // list of all neighbor cells which were not already aggregated to some other cell: int[] UnusedNeighs = Neighbourship[jCell].Where(j => j < J && !UsedCellMarker[j]).ToArray(); int NN = UnusedNeighs.Length; if (NN > 0) { double[] sizes = new double[NN]; BoundingBox[] aggBB = new BoundingBox[NN]; double[] aggBBaspect = new double[NN]; for (int iNeig = 0; iNeig < NN; iNeig++) { int jCellNeigh = UnusedNeighs[iNeig]; aggBB[iNeig] = new BoundingBox(D); //ag.CompositeCellBB[jCell].CloneAs(); ag.iLogicalCells.GetCellBoundingBox(jCell, aggBB[iNeig]); BoundingBox NeighBB = new BoundingBox(D); ag.iLogicalCells.GetCellBoundingBox(jCellNeigh, NeighBB); aggBB[iNeig].AddBB(NeighBB); sizes[iNeig] = ag.iLogicalCells.GetCellVolume(jCell) + ag.iLogicalCells.GetCellVolume(jCellNeigh); aggBBaspect[iNeig] = aggBB[iNeig].AspectRatio; } double[] RelSizes = sizes.CloneAs(); RelSizes.ScaleV(1.0 / sizes.Max()); double[] RelAspects = aggBBaspect.CloneAs(); RelAspects.ScaleV(1.0 / aggBBaspect.Max()); double[] Quality = new double[NN]; Quality.AccV(0.7, RelSizes); Quality.AccV(0.3, RelAspects); int iChoice = Quality.IndexOfMin(q => q); int jNeigChoice = UnusedNeighs[iChoice]; //int[] CCC = ArrayTools.Cat(ag.AggregateCells[jCell], ag.AggregateCells[jNeigChoice]); int[] CCC = new int[] { jCell, jNeigChoice }; Coarsened_ComositeCells.Add(CCC); //Coarsened_CompositeCellBB.Add(aggBB[iChoice]); //Coarsened_CompositeVolume.Add(sizes[iChoice]); Debug.Assert(jCell != jNeigChoice); child2Parrent.Add(new int[] { jCell, jNeigChoice }); Parent2Child[jCell] = Coarsened_ComositeCells.Count - 1; Parent2Child[jNeigChoice] = Coarsened_ComositeCells.Count - 1; UsedCellMarker[jNeigChoice] = true; UsedCellMarker[jCell] = true; } else { // No neighbour available => unable to coarsen Coarsened_ComositeCells.Add(new int[] { jCell }); //Coarsened_ComositeCells.Add(ag.AggregateCells[jCell]); //Coarsened_CompositeCellBB.Add(ag.CompositeCellBB[jCell].CloneAs()); //Coarsened_CompositeVolume.Add(ag.CompositeVolume[jCell]); child2Parrent.Add(new int[] { jCell }); Parent2Child[jCell] = Coarsened_ComositeCells.Count - 1; UsedCellMarker[jCell] = true; } } else { // cell already done. continue; } } Debug.Assert(UsedCellMarker.ToBoolArray().Where(b => !b).Count() == 0, "some cell was not processed."); // return // ====== return(new AggregationGrid(ag, Coarsened_ComositeCells.ToArray())); } }
//protected override void TriggerLevelSetUpdate() { // throw new NotImplementedException(); //} private void RKstageExplicit(double PhysTime, double dt, double[][] k, int s, BlockMsrMatrix[] Mass, CoordinateVector u0, double ActualLevSetRelTime, double[] RK_as, double RelTime) { Debug.Assert(s <= m_RKscheme.Stages); for (int i = 0; i < s; i++) { Debug.Assert(k[i] != null); } int Ndof = CurrentStateMapping.LocalLength; BlockMsrMatrix System; double[] RHS = new double[Ndof]; if (RelTime > 0) { // // some ordinary stage above stage 0 // if (base.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative || base.Config_LevelSetHandling == LevelSetHandling.Coupled_Once) { // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Moving interface, RK stage 'i': // (c[s]/dt)*(Ms*us - M0*u0) + sum(k[l]*a[s,l], 0 <= l < s)) = 0 // For explicit timestepping, both versions of level-set coupling // will lead to identical results. // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // move level-set: if (Math.Abs(ActualLevSetRelTime - RelTime) > 1.0e-14) { this.m_LsTrk.PushStacks(); this.MoveLevelSetAndRelatedStuff(u0.Mapping.Fields.ToArray(), PhysTime, dt * RelTime, IterUnderrelax, Mass, k); this.UpdateAgglom(false); BlockMsrMatrix PM, SM; UpdateMassMatrix(out PM, out SM, PhysTime + dt * RelTime); Mass[1] = SM; } var M0 = Mass[0]; var Ms = Mass[1]; // left-hand-side if (Ms != null) { System = Ms.CloneAs(); System.Scale(1.0 / dt); } else { Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity); System = null; } // right-hand-side if (M0 != null) { M0.SpMV(1.0 / dt, u0, 0.0, RHS); } else { Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity); RHS.SetV(u0, 1.0 / dt); } for (int l = 0; l < s; l++) { if (RK_as[l] != 0.0) { RHS.AccV(-RK_as[l], k[l]); } } } else if (base.Config_LevelSetHandling == LevelSetHandling.LieSplitting || base.Config_LevelSetHandling == LevelSetHandling.StrangSplitting || base.Config_LevelSetHandling == LevelSetHandling.None) { // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Level-Set-Splitting: Mass matrix remains constant during Runge-Kutta // Stage: // (c[s]/dt)*M0*(us - u0) + sum(k[l]*a[s,l], l=0..(s-1)) = 0 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //Debug.Assert(Mass.Length == 1); // Uncommented for usage in XDGShock var Ms = Mass[0]; // left-hand-side if (Ms != null) { System = Ms.CloneAs(); System.Scale(1.0 / dt); } else { Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity); System = null; } // right-hand-side if (Ms != null) { Ms.SpMV(1.0 / dt, u0, 0.0, RHS); } else { Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity); RHS.SetV(u0, 1.0 / dt); } for (int l = 0; l < s; l++) { if (RK_as[l] != 0.0) { RHS.AccV(-RK_as[l], k[l]); } } } else { throw new NotImplementedException(); } // solve system if (System != null) { Debug.Assert(object.ReferenceEquals(m_CurrentAgglomeration.Tracker, m_LsTrk)); m_CurrentAgglomeration.ManipulateMatrixAndRHS(System, RHS, this.CurrentStateMapping, this.CurrentStateMapping); BlockSol(System, m_CurrentState, RHS); m_CurrentAgglomeration.Extrapolate(this.CurrentStateMapping); } else { // system is diagonal: 1/dt m_CurrentState.SetV(RHS, dt); } } else { // +++++++++++++++++++++++++++ // this is probably stage zero // +++++++++++++++++++++++++++ m_CurrentState.Clear(); m_CurrentState.Acc(1.0, u0); } }
/// <summary> /// Matrix/Affine assembly in the case of an implicit RK stage. /// </summary> protected override void AssembleMatrixCallback(out BlockMsrMatrix System, out double[] Affine, out BlockMsrMatrix PcMassMatrix, DGField[] argCurSt, bool Linearization) { if (Linearization == false) { throw new NotImplementedException("todo"); } int Ndof = m_CurrentState.Count; // copy data from 'argCurSt' to 'CurrentStateMapping', if necessary // ----------------------------------------------------------- DGField[] locCurSt = CurrentStateMapping.Fields.ToArray(); if (locCurSt.Length != argCurSt.Length) { throw new ApplicationException(); } int NF = locCurSt.Length; for (int iF = 0; iF < NF; iF++) { if (object.ReferenceEquals(locCurSt[iF], argCurSt[iF])) { // nothing to do } else { locCurSt[iF].Clear(); locCurSt[iF].Acc(1.0, argCurSt[iF]); } } // update of level-set // ---------------------- bool updateAgglom = false; if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once && m_ImplStParams.m_IterationCounter == 0 || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { //MoveLevelSetAndRelatedStuff(locCurSt, m_CurrentPhystime, m_CurrentDt, 1.0); if (Math.Abs(m_ImplStParams.m_ActualLevSetRelTime - m_ImplStParams.m_RelTime) > 1.0e-14) { if (m_ImplStParams.m_IterationCounter <= 0)// only push tracker in the first iter { m_LsTrk.PushStacks(); } MoveLevelSetAndRelatedStuff(locCurSt, m_ImplStParams.m_CurrentPhystime, m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime, IterUnderrelax, m_ImplStParams.m_Mass, m_ImplStParams.m_k); // note that we need to update the agglomeration updateAgglom = true; } } // update agglomeration // -------------------- #if DEBUG if (this.Config_LevelSetHandling == LevelSetHandling.LieSplitting || this.Config_LevelSetHandling == LevelSetHandling.StrangSplitting) { Debug.Assert(m_CurrentAgglomeration != null); Debug.Assert(m_PrecondMassMatrix != null); // ensure, that, when splitting is used we update the agglomerator in the very first iteration. } #endif if (updateAgglom || m_CurrentAgglomeration == null) { this.UpdateAgglom(m_ImplStParams.m_IterationCounter > 0); // update Multigrid-XDG basis base.MultigridBasis.UpdateXdgAggregationBasis(m_CurrentAgglomeration); } // mass matrix update // ------------------ if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity) { // may occur e.g. if one runs the FSI solver as a pure single-phase solver, // i.e. if the Level-Set is outside the domain. PcMassMatrix = null; } else { // checks: Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity || this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeDependent || this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeAndSolutionDependent, "Something is not implemented here."); if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity && Config_LevelSetHandling != LevelSetHandling.None) { throw new NotSupportedException("Illegal configuration;"); } if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { if ((this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity && m_PrecondMassMatrix == null) || // compute mass matrix (only once in application lifetime) (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeDependent && m_ImplStParams.m_IterationCounter == 0) || // compute mass matrix once per timestep (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeAndSolutionDependent) // re-compute mass matrix in every iteration ) { BlockMsrMatrix PM, SM; UpdateMassMatrix(out PM, out SM, m_ImplStParams.m_CurrentPhystime + m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime); m_ImplStParams.m_Mass[1] = SM; m_PrecondMassMatrix = PM; } } PcMassMatrix = m_PrecondMassMatrix; } // operator matrix update // ---------------------- // we perform the extrapolation to have valid parameters if // - the operator matrix depends on these values this.m_CurrentAgglomeration.Extrapolate(CurrentStateMapping); var OpMatrix = new BlockMsrMatrix(CurrentStateMapping); var OpAffine = new double[Ndof]; this.ComputeOperatorMatrix(OpMatrix, OpAffine, CurrentStateMapping, locCurSt, base.GetAgglomeratedLengthScales(), m_ImplStParams.m_CurrentPhystime + m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime); // assemble system // --------------- double dt = m_ImplStParams.m_CurrentDt; // select mass matrix (and some checks) double[] RHS = new double[Ndof]; BlockMsrMatrix MamaRHS, MamaLHS; if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { Debug.Assert(m_ImplStParams.m_Mass.Length == 2); MamaRHS = m_ImplStParams.m_Mass[0]; MamaLHS = m_ImplStParams.m_Mass[1]; } else if (this.Config_LevelSetHandling == LevelSetHandling.LieSplitting || this.Config_LevelSetHandling == LevelSetHandling.StrangSplitting || this.Config_LevelSetHandling == LevelSetHandling.None) { Debug.Assert(m_ImplStParams.m_Mass.Length == 1); MamaRHS = m_ImplStParams.m_Mass[0]; MamaLHS = m_ImplStParams.m_Mass[0]; } else { throw new NotImplementedException(); } // right-hand-side, resp. affine vector if (MamaRHS != null) { MamaRHS.SpMV(1.0 / dt, m_ImplStParams.m_u0, 0.0, RHS); } else { Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity); RHS.SetV(m_ImplStParams.m_u0, 1.0 / dt); } for (int l = 0; l < m_ImplStParams.m_s; l++) { if (m_ImplStParams.m_RK_as[l] != 0.0) { RHS.AccV(-m_ImplStParams.m_RK_as[l], m_ImplStParams.m_k[l]); } } Affine = RHS; Affine.ScaleV(-1.0); Affine.AccV(m_ImplStParams.m_RK_as[m_ImplStParams.m_s], OpAffine); // left-hand-side System = OpMatrix.CloneAs(); System.Scale(m_ImplStParams.m_RK_as[m_ImplStParams.m_s]); if (MamaLHS != null) { System.Acc(1.0 / dt, MamaLHS); } else { System.AccEyeSp(1.0 / dt); } // perform agglomeration // --------------------- Debug.Assert(object.ReferenceEquals(m_CurrentAgglomeration.Tracker, m_LsTrk)); m_CurrentAgglomeration.ManipulateMatrixAndRHS(System, Affine, CurrentStateMapping, CurrentStateMapping); // increase iteration counter // -------------------------- m_ImplStParams.m_IterationCounter++; }
/// <summary> /// projects some DG field onto this /// </summary> /// <param name="alpha"></param> /// <param name="DGField"></param> /// <param name="_cm">optional restriction to computational domain</param> /// <remarks> /// This method computes an exact /// L2-projection of the DG-field onto the SpecFEM-space, so a global linear system, which contains all /// DOF's, has to be solved. /// In contrast, <see cref="ProjectDGFieldCheaply"/> performs an approximate projection which only involves /// local operations for each cell. /// </remarks> public void ProjectDGField(double alpha, ConventionalDGField DGField, CellMask _cm = null) { using (var trx = new Transceiver(this.Basis)) { CellMask cm = _cm; if (cm == null) { cm = CellMask.GetFullMask(this.Basis.GridDat); } int J = m_Basis.GridDat.Cells.NoOfLocalUpdatedCells; var Trafo = m_Basis.GridDat.ChefBasis.Scaling; var C2N = m_Basis.CellNode_To_Node; var MtxM2N = m_Basis.m_Modal2Nodal; var CellData = this.Basis.GridDat.Cells; // compute RHS // =========== var b = MultidimensionalArray.Create(this.m_Basis.NoOfLocalNodes); { int[] _K = m_Basis.NodesPerCell; int L = m_Basis.ContainingDGBasis.Length; double[][] _NodalCoordinates = _K.Select(K => new double[K]).ToArray(); // temporary storage for nodal coordinates per cell // 1st idx: ref. elm., 2nd idx: node index double[] ModalCoordinates = new double[L]; foreach (Chunk cnk in cm) { int j0 = cnk.i0; int jE = cnk.JE; for (int j = j0; j < jE; j++) // loop over cells... { int iKref = CellData.GetRefElementIndex(j); double[] NodalCoordinates = _NodalCoordinates[iKref]; int K = _K[iKref]; if (!CellData.IsCellAffineLinear(j)) { throw new NotSupportedException(); } // Get DG coordinates Array.Clear(ModalCoordinates, 0, L); int Lmin = Math.Min(L, DGField.Basis.GetLength(j)); for (int l = 0; l < Lmin; l++) { ModalCoordinates[l] = DGField.Coordinates[j, l]; } var tr = 1.0 / Trafo[j]; // transform //DGField.Coordinates.GetRow(j, ModalCoordinates); ModalCoordinates.ClearEntries(); for (int l = 0; l < Lmin; l++) { ModalCoordinates[l] = DGField.Coordinates[j, l]; } MtxM2N[iKref].GEMV(tr, ModalCoordinates, 0.0, NodalCoordinates, transpose: true); // collect coordinates for cell 'j': for (int k = 0; k < K; k++) { int _c2n = C2N[j, k]; b[_c2n] += NodalCoordinates[k]; } } } } trx.AccumulateGather(b); /* * * var bcheck = new double[b.Length]; * { * var polys = this.Basis.NodalBasis; * * * CellQuadrature.GetQuadrature(new int[] { K }, * this.Basis.GridDat.Context, * (new CellQuadratureScheme()).Compile(this.Basis.GridDat, this.Basis.ContainingDGBasis.Degree*2), * delegate(MultidimensionalArray NodesUntransformed) { // Del_CreateNodeSetFamily * var NSC = this.Basis.GridDat.Context.NSC; * return new NodeSetController.NodeSetContainer[] { NSC.CreateContainer(NodesUntransformed) }; * }, * delegate(int i0, int Length, int _NoOfNodes, MultidimensionalArray EvalResult) { * var PolyAtNode = MultidimensionalArray.Create(K, _NoOfNodes); * for (int k = 0; k < K; k++) { * polys[k].Evaluate(PolyAtNode.ExtractSubArrayShallow(k, -1), this.Basis.GridDat.Context.NSC.Current_NodeSetFamily[0].NodeSet); * } * * var DGFatNodes = MultidimensionalArray.Create(Length, _NoOfNodes); * DGField.Evaluate(i0, Length, 0, DGFatNodes); * * //for(int i = 0; i < Length; i++) { * // for (int n = 0; n < _NoOfNodes; n++) { * // for (int k = 0; k < K; k++) { * // for (int l = 0; l < K; l++) { * // EvalResult[i, n, k, l] = PolyAtNode[k, n]*PolyAtNode[l, n]; * // } * // } * // } * //} * * EvalResult.Multiply(1.0, PolyAtNode, DGFatNodes, 0.0, "jnk", "kn", "jn"); * * //double errSum = 0; * //for (int i = 0; i < Length; i++) { * // for (int n = 0; n < _NoOfNodes; n++) { * // for (int k = 0; k < K; k++) { * // for (int l = 0; l < K; l++) { * // double soll = PolyAtNode[k, n]*PolyAtNode[l, n]; * // errSum += Math.Abs(soll - EvalResult[i, n, k, l]); * // } * // } * // } * //} * //Console.WriteLine("errsum = " + errSum); * }, * delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { // SaveIntegrationResults * for (int i = 0; i < Length; i++) { * int jCell = i + i0; * * for (int k = 0; k < K; k++) { * bcheck[C2N[jCell, k]] += ResultsOfIntegration[i, k]; * } * * //CellMass[jCell] = new FullMatrix(K, K); * //CellMass[jCell].Initialize(ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1)); * } * }).Execute(); * * * double f**k = GenericBlas.L2Dist(b, bcheck); * Console.WriteLine("Distance error = " + f**k); * * } * * */ if (_cm == null) { // full domain projection branch // +++++++++++++++++++++++++++++ var x = new double[this.Basis.NoOfLocalOwnedNodes]; var solStat = m_Basis.MassSolver.Solve(x, b.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).To1DArray()); { if (solStat.Converged == false) { throw new ArithmeticException("DG -> SpecFEM Projection failed because the Mass matrix solver did not converge."); } double[] chk = b.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).To1DArray(); this.Basis.MassMatrix.SpMVpara(-1.0, x, 1.0, chk); double chk_nomr = chk.L2Norm(); if (chk_nomr >= 1.0e-8) { throw new ArithmeticException(string.Format("DG -> SpecFEM Projection failed: solver converged, but with high residual {0}.", chk_nomr.ToStringDot())); } } //m_Basis.MassMatrix.SpMV(1.0, b, 0.0, x); m_Coordinates.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).AccVector(alpha, x); //m_Coordinates.AccV(alpha, b); } else { // restricted domain projection branch // +++++++++++++++++++++++++++++++++++ List <int> OccupiedRows_Global = new List <int>(); //List<int> OccupiedRows_Local = new List<int>(); var MM = Basis.ComputeMassMatrix(cm); int i0 = MM.RowPartitioning.i0, iE = MM.RowPartitioning.iE; for (int i = i0; i < iE; i++) { if (MM.GetNoOfNonZerosPerRow(i) > 0) { OccupiedRows_Global.Add(i); //OccupiedRows_Local.Add(i - i0); } } var CompressedPart = new Partitioning(OccupiedRows_Global.Count); var CompressedMM = new MsrMatrix(CompressedPart); MM.WriteSubMatrixTo(CompressedMM, OccupiedRows_Global, default(int[]), OccupiedRows_Global, default(int[])); var b_sub = new double[OccupiedRows_Global.Count]; //try { b_sub.AccV(1.0, b.To1DArray(), default(int[]), OccupiedRows_Global, b_index_shift: -i0); //} catch(Exception e) { // Debugger.Launch(); //} //csMPI.Raw.Barrier(csMPI.Raw._COMM.WORLD); var x_sub = new double[b_sub.Length]; var solver = new ilPSP.LinSolvers.monkey.CG(); solver.MatrixType = ilPSP.LinSolvers.monkey.MatrixType.CCBCSR; solver.DevType = ilPSP.LinSolvers.monkey.DeviceType.CPU; solver.ConvergenceType = ConvergenceTypes.Absolute; solver.Tolerance = 1.0e-12; solver.DefineMatrix(CompressedMM); var solStat = solver.Solve(x_sub, b_sub.CloneAs()); { if (solStat.Converged == false) { throw new ArithmeticException("DG -> SpecFEM Projection failed because the Mass matrix solver did not converge."); } var chk = b_sub; CompressedMM.SpMVpara(-1.0, x_sub, 1.0, chk); double chk_nomr = chk.L2Norm(); if (chk_nomr >= 1.0e-8) { throw new ArithmeticException(string.Format("DG -> SpecFEM Projection failed: solver converged, but with high residual {0}.", chk_nomr.ToStringDot())); } } double[] x = new double[this.Basis.NoOfLocalOwnedNodes]; x.AccV(1.0, x_sub, OccupiedRows_Global, default(int[]), acc_index_shift: -i0); m_Coordinates.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).AccVector(alpha, x); } trx.Scatter(this.m_Coordinates); } }
/// <summary> /// implementation of the CG algorithm /// </summary> /// <param name="_x"></param> /// <param name="_R"></param> /// <param name="stats"></param> public void Solve <Vec1, Vec2>(Vec1 _x, Vec2 _R) where Vec1 : IList <double> where Vec2 : IList <double> // { using (new FuncTrace()) { double[] x, R; if (_x is double[]) { x = _x as double[]; } else { x = _x.ToArray(); } if (_R is double[]) { R = _R as double[]; } else { R = _R.ToArray(); } int L = x.Length; double[] P = new double[L]; //double[] R = rhs; // rhs is only needed once, so we can use it to store residuals double[] V = new double[L]; double[] Z = new double[L]; // compute P0, R0 // ============== GenericBlas.dswap(L, x, 1, P, 1); m_Matrix.SpMV(-1.0, P, 1.0, R); if (IterationCallback != null) { IterationCallback(NoOfIterations, P.CloneAs(), R.CloneAs(), this.m_MgOp); } GenericBlas.dswap(L, x, 1, P, 1); if (Precond != null) { Precond.Solve(Z, R); P.SetV(Z); } else { P.SetV(R); } double alpha = R.InnerProd(P).MPISum(); double alpha_0 = alpha; double ResNorm; ResNorm = Math.Sqrt(alpha); // iterate // ======= NoOfIterations++; // one iteration has allready been performed (P0, R0) for (int n = 1; n < this.m_MaxIterations; n++) { if (ResNorm <= m_Tolerance && NoOfIterations >= m_MinIterations) { this.m_Converged = true; break; } NoOfIterations++; if (Math.Abs(alpha) <= double.Epsilon) { // numerical breakdown break; } m_Matrix.SpMV(1.0, P, 0, V); double VxP = V.InnerProd(P).MPISum(); //Console.WriteLine("VxP: {0}", VxP); if (double.IsNaN(VxP) || double.IsInfinity(VxP)) { throw new ArithmeticException(); } double lambda = alpha / VxP; if (double.IsNaN(lambda) || double.IsInfinity(lambda)) { throw new ArithmeticException(); } x.AccV(lambda, P); R.AccV(-lambda, V); if (IterationCallback != null) { IterationCallback(NoOfIterations, x.CloneAs(), R.CloneAs(), this.m_MgOp); } if (Precond != null) { Z.Clear(); Precond.Solve(Z, R); } else { Z.SetV(R); } double alpha_neu = R.InnerProd(Z).MPISum(); // compute residual norm ResNorm = R.L2NormPow2().MPISum().Sqrt(); P.ScaleV(alpha_neu / alpha); P.AccV(1.0, Z); alpha = alpha_neu; } if (!object.ReferenceEquals(_x, x)) { _x.SetV(x); } if (!object.ReferenceEquals(_R, R)) { _R.SetV(R); } return; } }
private void AssembleMatrix(double MU_A, double MU_B, out BlockMsrMatrix M, out double[] b, out MultiphaseCellAgglomerator agg, out MassMatrixFactory massFact) { using (var tr = new FuncTrace()) { // create operator // =============== if (this.Control.SetDefaultDiriBndCnd) { this.Control.xLaplaceBCs.g_Diri = ((CommonParamsBnd inp) => 0.0); this.Control.xLaplaceBCs.IsDirichlet = (inp => true); } double D = this.GridData.SpatialDimension; int p = u.Basis.Degree; double penalty_base = (p + 1) * (p + D) / D; double penalty_multiplyer = base.Control.penalty_multiplyer; XQuadFactoryHelper.MomentFittingVariants momentFittingVariant; if (D == 3) { momentFittingVariant = XQuadFactoryHelper.MomentFittingVariants.Classic; } momentFittingVariant = this.Control.CutCellQuadratureType; int order = this.u.Basis.Degree * 2; XSpatialOperator Op = new XSpatialOperator(1, 1, (A, B, C) => order, "u", "c1"); var lengthScales = ((BoSSS.Foundation.Grid.Classic.GridData)GridData).Cells.PenaltyLengthScales; var lap = new XLaplace_Bulk(this.LsTrk, penalty_multiplyer * penalty_base, "u", this.Control.xLaplaceBCs, 1.0, MU_A, MU_B, lengthScales, this.Control.ViscosityMode); Op.EquationComponents["c1"].Add(lap); // Bulk form Op.EquationComponents["c1"].Add(new XLaplace_Interface(this.LsTrk, MU_A, MU_B, penalty_base * 2, this.Control.ViscosityMode)); // coupling form Op.Commit(); // create agglomeration // ==================== var map = new UnsetteledCoordinateMapping(u.Basis); //agg = new MultiphaseCellAgglomerator( // new CutCellMetrics(momentFittingVariant, // QuadOrderFunc.SumOfMaxDegrees(RoundUp: true)(map.BasisS.Select(bs => bs.Degree).ToArray(), new int[0], map.BasisS.Select(bs => bs.Degree).ToArray()), // //this.HMFDegree, // LsTrk, this.LsTrk.SpeciesIdS.ToArray()), // this.Control.AgglomerationThreshold, false); agg = LsTrk.GetAgglomerator(this.LsTrk.SpeciesIdS.ToArray(), order, this.Control.AgglomerationThreshold); // compute matrix // ============= using (new BlockTrace("XdgMatrixAssembly", tr)) { M = new BlockMsrMatrix(map, map); b = new double[M.RowPartitioning.LocalLength]; Op.ComputeMatrixEx(LsTrk, map, null, map, M, b, false, 0.0, true, agg.CellLengthScales, null, null, //out massFact, this.LsTrk.SpeciesIdS.ToArray()); } // compare with linear evaluation // ============================== DGField[] testDomainFieldS = map.BasisS.Select(bb => new XDGField(bb as XDGBasis)).ToArray(); CoordinateVector test = new CoordinateVector(testDomainFieldS); DGField[] errFieldS = map.BasisS.Select(bb => new XDGField(bb as XDGBasis)).ToArray(); CoordinateVector Err = new CoordinateVector(errFieldS); var eval = Op.GetEvaluatorEx(LsTrk, testDomainFieldS, null, map); foreach (var s in this.LsTrk.SpeciesIdS) { eval.SpeciesOperatorCoefficients[s].CellLengthScales = agg.CellLengthScales[s]; } eval.time = 0.0; int L = test.Count; Random r = new Random(); for (int i = 0; i < L; i++) { test[i] = r.NextDouble(); } double[] R1 = new double[L]; double[] R2 = new double[L]; eval.Evaluate(1.0, 1.0, R1); R2.AccV(1.0, b); M.SpMV(1.0, test, 1.0, R2); Err.AccV(+1.0, R1); Err.AccV(-1.0, R2); double ErrDist = GenericBlas.L2DistPow2(R1, R2).MPISum().Sqrt(); double Ref = test.L2NormPow2().MPISum().Sqrt(); Assert.LessOrEqual(ErrDist, Ref * 1.0e-5, "Mismatch between explicit evaluation of XDG operator and matrix."); // agglomeration wahnsinn // ====================== agg.ManipulateMatrixAndRHS(M, b, map, map); foreach (var S in this.LsTrk.SpeciesNames) { Console.WriteLine(" Species {0}: no of agglomerated cells: {1}", S, agg.GetAgglomerator(this.LsTrk.GetSpeciesId(S)).AggInfo.SourceCells.NoOfItemsLocally); } // mass matrix factory // =================== Basis maxB = map.BasisS.ElementAtMax(bss => bss.Degree); //massFact = new MassMatrixFactory(maxB, agg); massFact = LsTrk.GetXDGSpaceMetrics(this.LsTrk.SpeciesIdS.ToArray(), order).MassMatrixFactory; } }
//static void SingleFilter(double[] V) { // for(int i = 0; i < V.Length; i++) { // float vi = (float)(V[i]); // V[i] = vi; // } //} public void Solve <U, V>(U X, V B) where U : IList <double> where V : IList <double> // { using (var tr = new FuncTrace()) { int NoParts = this.BlockIndices_Local.Length; // -------- // Reminder: we solve for a correction, the basic idea is: // // X0 is current solution, state of 'X' at input time // Residual = B - M*X0; // now solve (approximately) // M*Xc = Residual, // if we would solve exactly, i.e. // Xc = M^{-1}*Residual // then X=(X0+Xc) is an exact solution of // M*X = B // -------- double[] Res = new double[B.Count]; MPIexchange <double[]> ResExchange; MPIexchangeInverse <U> XExchange; if (Overlap > 0) { ResExchange = new MPIexchange <double[]>(this.m_MgOp.Mapping, Res); XExchange = new MPIexchangeInverse <U>(this.m_MgOp.Mapping, X); } else { ResExchange = null; XExchange = null; #if DEBUG foreach (var ciE in BlockIndices_External) { Debug.Assert(ciE == null || ciE.Length <= 0); } #endif } int LocLength = m_MgOp.Mapping.LocalLength; for (int iIter = 0; iIter < m_MaxIterations; iIter++) { this.NoIter++; Res.SetV(B); this.MtxFull.SpMV(-1.0, X, 1.0, Res); if (IterationCallback != null) { IterationCallback(iIter, X.ToArray(), Res.CloneAs(), this.m_MgOp); } using (new BlockTrace("coarse_solve_level" + this.m_MgOp.LevelIndex, tr)) { if (CoarseSolver != null) { var XC = X.ToArray().CloneAs(); double[] bc = new double[m_MgOp.CoarserLevel.Mapping.LocalLength];// = Res.CloneAs(); m_MgOp.CoarserLevel.Restrict(Res.CloneAs(), bc); double[] xc = new double[bc.Length]; CoarseSolver.Solve(xc, bc); //SingleFilter(xc); m_MgOp.CoarserLevel.Prolongate(1, XC, 1, xc); X.AccV(1.0, XC); if (CoarseSolverIsMultiplicative) { Res.SetV(B); this.MtxFull.SpMV(-1.0, X, 1.0, Res); } } } if (Overlap > 0) { ResExchange.TransceiveStartImReturn(); ResExchange.TransceiveFinish(0.0); } using (new BlockTrace("block_solve_level" + this.m_MgOp.LevelIndex, tr)) { for (int iPart = 0; iPart < NoParts; iPart++) { int[] ci = BlockIndices_Local[iPart]; int[] ciE = BlockIndices_External[iPart]; int L = ci.Length; if (ciE != null) { L += ciE.Length; } double[] bi = new double[L]; double[] xi = new double[L]; // extract block part of residual bi.AccV(1.0, Res, default(int[]), ci); if (ciE != null && ciE.Length > 0) { bi.AccV(1.0, ResExchange.Vector_Ext, default(int[]), ciE, acc_index_shift: ci.Length, b_index_shift: (-LocLength)); } blockSolvers[iPart].Solve(xi, bi); //SingleFilter(xi); // accumulate block solution 'xi' to global solution 'X' X.AccV(1.0, xi, ci, default(int[])); if (ciE != null && ciE.Length > 0) { XExchange.Vector_Ext.AccV(1.0, xi, ciE, default(int[]), acc_index_shift: (-LocLength), b_index_shift: ci.Length); } } } if (Overlap > 0) { // block solutions stored on *external* indices will be accumulated on other processors. XExchange.TransceiveStartImReturn(); XExchange.TransceiveFinish(1.0); if (iIter < m_MaxIterations - 1) { XExchange.Vector_Ext.ClearEntries(); } } } } }
public void Solve <U, V>(U X, V B) where U : IList <double> where V : IList <double> // { using (new FuncTrace()) { // init // ==== int L = this.m_mgop.Mapping.LocalLength; if (X.Count != L) { throw new ArgumentException(); } if (B.Count != L) { throw new ArgumentException(); } var Mtx = this.m_mgop.OperatorMatrix; // residual of initial guess // ========================= // history of solutions and residuals (max vector length 'MaxKrylovDim') List <double[]> SolHistory = new List <double[]>(); List <double[]> MxxHistory = new List <double[]>(); double[] Correction = new double[L]; double[] Mxx = new double[L]; double[] CurrentSol = new double[L]; double[] CurrentRes = new double[L]; CurrentSol.SetV(X, 1.0); CurrentRes.SetV(B, 1.0); Mtx.SpMV(-1.0, CurrentSol, 1.0, CurrentRes); int KrylovDim = 0; double[] Residual0 = CurrentRes.CloneAs(); double[] Solution0 = CurrentSol.CloneAs(); List <double> _R = new List <double>(); // diagnostic output if (this.IterationCallback != null) { this.IterationCallback(0, CurrentSol.CloneAs(), CurrentRes.CloneAs(), this.m_mgop); } // iterations... // ============= double[] PreviousRes = new double[L]; //MultidimensionalArray raw_Mxx = MultidimensionalArray.Create(L, MaxIter + 1); //MultidimensionalArray ortho_Mxx = MultidimensionalArray.Create(L, MaxIter + 1); MultidimensionalArray MassMatrix = MultidimensionalArray.Create(MaxKrylovDim, MaxKrylovDim); int PCcounter = 0; double[] prevAlpha = null; double crL2 = double.MaxValue; for (int iIter = 0; iIter < MaxIter; iIter++) { Debug.Assert(SolHistory.Count == MxxHistory.Count); Debug.Assert(SolHistory.Count == KrylovDim); // select preconditioner var Precond = PrecondS[PCcounter]; PCcounter++; if (PCcounter >= PrecondS.Length) { PCcounter = 0; m_ThisLevelIterations++; // because we abuse the Orthonormalization to do some multi-grid stuff, // we only count every full cycle of preconditiones. } // solve the residual equation: M*Correction = prev. Residual PreviousRes.SetV(CurrentRes); Correction.ClearEntries(); Precond.Solve(Correction, PreviousRes); // compute M*Correction Mtx.SpMV(1.0, Correction, 0.0, Mxx); // orthonormalize the Mxx -- vector with respect to the previous ones. Debug.Assert(KrylovDim == MxxHistory.Count); Debug.Assert(KrylovDim == SolHistory.Count); //raw_Mxx.SetColumn(KrylovDim, Mxx); for (int i = 0; i < KrylovDim; i++) { Debug.Assert(!object.ReferenceEquals(Mxx, MxxHistory[i])); double beta = GenericBlas.InnerProd(Mxx, MxxHistory[i]).MPISum(); Mxx.AccV(-beta, MxxHistory[i]); Correction.AccV(-beta, SolHistory[i]); } { double gamma = 1.0 / GenericBlas.L2NormPow2(Mxx).MPISum().Sqrt(); Mxx.ScaleV(gamma); Correction.ScaleV(gamma); } // the following lines should produce the identity matrix for (int i = 0; i < KrylovDim; i++) { MassMatrix[i, KrylovDim] = GenericBlas.InnerProd(Mxx, MxxHistory[i]).MPISum(); } MassMatrix[KrylovDim, KrylovDim] = GenericBlas.L2NormPow2(Mxx).MPISum(); // //ortho_Mxx.SetColumn(KrylovDim, Mxx); MxxHistory.Add(Mxx.CloneAs()); SolHistory.Add(Correction.CloneAs()); KrylovDim++; bool updateEveryIteration = false; // RHS of the minimization problem (LHS is identity matrix) if (!updateEveryIteration) { _R.Add(GenericBlas.InnerProd(MxxHistory.Last(), Residual0).MPISum()); } else { _R.Clear(); for (int i = 0; i < KrylovDim; i++) { _R.Add(GenericBlas.InnerProd(MxxHistory[i], Residual0).MPISum()); } } // compute accelerated solution //double[] alpha = _R.ToArray(); // factors for re-combining solutions double[] alpha; { double[] minimi_rhs = _R.ToArray(); var minimi_lhs = MassMatrix.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { KrylovDim - 1, KrylovDim - 1 }).CloneAs(); alpha = new double[KrylovDim]; minimi_lhs.Solve(alpha, minimi_rhs); } if (prevAlpha != null) { var del = alpha.GetSubVector(0, prevAlpha.Length); del.AccV(-1.0, prevAlpha); } prevAlpha = alpha; Debug.Assert(alpha.Length == SolHistory.Count); Debug.Assert(alpha.Length == MxxHistory.Count); Debug.Assert(alpha.Length == KrylovDim); CurrentSol.SetV(Solution0, 1.0); for (int i = 0; i < KrylovDim; i++) { CurrentSol.AccV(alpha[i], SolHistory[i]); } // compute new Residual CurrentRes.SetV(B); Mtx.SpMV(-1.0, CurrentSol, 1.0, CurrentRes); crL2 = CurrentRes.L2NormPow2().MPISum().Sqrt(); // diagnostic output if (this.IterationCallback != null) { this.IterationCallback(iIter + 1, CurrentSol.CloneAs(), CurrentRes.CloneAs(), this.m_mgop); } //{ // var gdat = m_mgop.BaseGridProblemMapping.GridDat; // var basis = m_mgop.BaseGridProblemMapping.BasisS[0]; // var dgCurrentSol = new Foundation.SinglePhaseField(basis, "Solution"); // var dgResidual = new Foundation.SinglePhaseField(basis, "Residual"); // var dgCorrection = new Foundation.SinglePhaseField(basis, "Correction"); // m_mgop.TransformRhsFrom(dgResidual.CoordinateVector, CurrentRes); // m_mgop.TransformSolFrom(dgCurrentSol.CoordinateVector, CurrentSol); // m_mgop.TransformSolFrom(dgCorrection.CoordinateVector, SolHistory.Last()); // dgCorrection.Scale(alpha.Last()); // Tecplot.Tecplot.PlotFields(new Foundation.DGField[] { dgCurrentSol, dgResidual, dgCorrection}, "OrthoScheme-" + iIter, iIter, 2); //} if (crL2 < Tolerance) { //Console.WriteLine(" Kcy converged:"); //for (int iii = 0; iii < KrylovDim; iii++) { // Console.WriteLine(" fac #" + iii + " : " + alpha[iii]); //} if (PCcounter > 0) { m_ThisLevelIterations += 1; } m_Converged = true; break; } if (updateEveryIteration) { Solution0.SetV(CurrentSol); Residual0.SetV(CurrentRes); } if (KrylovDim >= MaxKrylovDim) { if (this.Restarted) { // restarted version of the algorithm // ++++++++++++++++++++++++++++++++++ MxxHistory.Clear(); SolHistory.Clear(); _R.Clear(); KrylovDim = 0; Residual0.SetV(CurrentRes); Solution0.SetV(CurrentSol); } else { // throw-away version of the algorithm // +++++++++++++++++++++++++++++++++++ int i_leastSig = alpha.IndexOfMin(x => x.Abs()); MxxHistory.RemoveAt(i_leastSig); SolHistory.RemoveAt(i_leastSig); KrylovDim--; for (int i = i_leastSig; i < KrylovDim; i++) { for (int j = 0; j <= KrylovDim; j++) { MassMatrix[i, j] = MassMatrix[i + 1, j]; } } for (int i = i_leastSig; i < KrylovDim; i++) { for (int j = 0; j <= KrylovDim; j++) { MassMatrix[j, i] = MassMatrix[j, i + 1]; } } Residual0.SetV(CurrentRes); Solution0.SetV(CurrentSol); _R.Clear(); foreach (double[] mxx in MxxHistory) { _R.Add(GenericBlas.InnerProd(mxx, Residual0).MPISum()); } } } } X.SetV(CurrentSol, 1.0); //raw_Mxx.SaveToTextFile("C:\\temp\\raw_Mxx.txt"); //ortho_Mxx.SaveToTextFile("C:\\temp\\ortho_Mxx.txt"); } }
private static int[][] AggregationKernel(IGridData ag, int AggCellCount) { int Jloc = ag.iLogicalCells.NoOfLocalUpdatedCells; int D = ag.SpatialDimension; if (AggCellCount < 2) { throw new ArgumentOutOfRangeException(); } // sort cells of parent grid by size: // we want to aggregate the smallest cells at first. int[] Perm = Jloc.ForLoop(j => j).OrderBy(j => ag.iLogicalCells.GetCellVolume(j)).ToArray(); BitArray UsedCellMarker = new BitArray(Jloc); List <int[]> Coarsened_ComositeCells = new List <int[]>(); // List <int> aggCell = new List <int>(); List <int> NeighCandidates = new List <int>(); // loop over aggregated cells of parent grid... int[][] Neighbourship = ag.iLogicalCells.CellNeighbours; for (int i = 0; i < Jloc; i++) { int jCell = Perm[i]; // pick next cell Debug.Assert(Neighbourship[jCell].Contains(jCell) == false); if (!UsedCellMarker[jCell]) // if the cell is not already agglomerated to another cell { aggCell.Clear(); aggCell.Add(jCell); UsedCellMarker[jCell] = true; for (int iPass = 1; iPass < AggCellCount; iPass++) { // list of all neighbor cells which were not already aggregated to some other cell: NeighCandidates.Clear(); foreach (int j in aggCell) { Debug.Assert(j < Jloc); Debug.Assert(UsedCellMarker[j] == true); foreach (int jNeigh in Neighbourship[j]) { if (jNeigh >= Jloc) { continue; } if (UsedCellMarker[jNeigh] == true) { continue; } Debug.Assert(aggCell.Contains(jNeigh) == false); // for all cells which are already in 'aggCell', the marker should be true if (!NeighCandidates.Contains(jNeigh)) { NeighCandidates.Add(jNeigh); } } } int NN = NeighCandidates.Count; if (NN > 0) { double[] sizes = new double[NN]; BoundingBox[] aggBB = new BoundingBox[NN]; double[] aggBBaspect = new double[NN]; for (int iNeig = 0; iNeig < NN; iNeig++) // loop over all candidates... { int jCellNeigh = NeighCandidates[iNeig]; aggBB[iNeig] = new BoundingBox(D); //ag.CompositeCellBB[jCell].CloneAs(); foreach (int jTaken in aggCell) { BoundingBox TempBB = new BoundingBox(D); ag.iLogicalCells.GetCellBoundingBox(jTaken, TempBB); aggBB[iNeig].AddBB(TempBB); } BoundingBox NeighBB = new BoundingBox(D); ag.iLogicalCells.GetCellBoundingBox(jCellNeigh, NeighBB); aggBB[iNeig].AddBB(NeighBB); sizes[iNeig] = ag.iLogicalCells.GetCellVolume(jCell) + ag.iLogicalCells.GetCellVolume(jCellNeigh); aggBBaspect[iNeig] = aggBB[iNeig].AspectRatio; } double[] RelSizes = sizes.CloneAs(); RelSizes.ScaleV(1.0 / sizes.Max()); double[] RelAspects = aggBBaspect.CloneAs(); RelAspects.ScaleV(1.0 / aggBBaspect.Max()); double[] Quality = new double[NN]; Quality.AccV(0.7, RelSizes); Quality.AccV(0.3, RelAspects); int iChoice = Quality.IndexOfMin(q => q); int jNeigChoice = NeighCandidates[iChoice]; Debug.Assert(aggCell.Contains(jNeigChoice) == false); aggCell.Add(jNeigChoice); UsedCellMarker[jNeigChoice] = true; } else { // No neighbour available => unable to coarsen break; } } // add agglom cell { int[] aggCell_Fix = aggCell.ToArray(); #if DEBUG foreach (int j in aggCell_Fix) { Debug.Assert(j >= 0); Debug.Assert(j < Jloc); Debug.Assert(UsedCellMarker[j] == true); } #endif Coarsened_ComositeCells.Add(aggCell_Fix); } } else { // cell already done. continue; } } Debug.Assert(UsedCellMarker.ToBoolArray().Where(b => !b).Count() == 0, "some cell was not processed."); return(Coarsened_ComositeCells.ToArray()); }
public void Solve <V1, V2>(V1 _X, V2 _B) where V1 : IList <double> where V2 : IList <double> { using (var tr = new FuncTrace()) { double[] X, B; if (_X is double[]) { X = _X as double[]; } else { X = _X.ToArray(); } if (_B is double[]) { B = _B as double[]; } else { B = _B.ToArray(); } double bnrm2 = B.L2NormPow2().MPISum().Sqrt(); if (bnrm2 == 0.0) { bnrm2 = 1.0; } int Nloc = Matrix.RowPartitioning.LocalLength; int Ntot = Matrix.RowPartitioning.TotalLength; double[] r = new double[Nloc]; double[] z = new double[Nloc]; //r = M \ ( b-A*x );, where M is the precond z.SetV(B); Matrix.SpMV(-1.0, X, 1.0, z); if (IterationCallback != null) { IterationCallback(0, X.CloneAs(), z.CloneAs(), this.m_mgop); } if (this.Precond != null) { r.Clear(); this.Precond.Solve(r, z); } else { r.SetV(z); } // Inserted for real residual double error2 = z.L2NormPow2().MPISum().Sqrt(); double error = (r.L2NormPow2().MPISum().Sqrt()) / bnrm2; if (error < this.m_Tolerance) { if (!object.ReferenceEquals(_X, X)) { _X.SetV(X); } B.SetV(z); this.m_Converged = true; return; } if (MaxKrylovDim <= 0) { throw new NotSupportedException("unsupported restart length."); } int m = MaxKrylovDim; double[][] V = (m + 1).ForLoop(i => new double[Nloc]); // V(1:n,1:m+1) = zeros(n,m+1); MultidimensionalArray H = MultidimensionalArray.Create(m + 1, m); // H(1:m+1,1:m) = zeros(m+1,m); double[] cs = new double[m]; double[] sn = new double[m]; //double[] s = new double[m+1]; double[] e1 = new double[Nloc]; //if(Matrix.RowPartitioning.Rank == 0) e1[0] = 1.0; double[] s = new double[Nloc], w = new double[Nloc], y; double temp; int iter; for (iter = 1; iter <= m_MaxIterations; iter++) { // GMRES iterations // r = M \ ( b-A*x ); z.SetV(B); Matrix.SpMV(-1.0, X, 1.0, z); error2 = z.L2NormPow2().MPISum().Sqrt(); if (this.Precond != null) { r.Clear(); this.Precond.Solve(r, z); } else { r.SetV(z); } // V(:,1) = r / norm( r ); double norm_r = r.L2NormPow2().MPISum().Sqrt(); V[0].SetV(r, alpha: (1.0 / norm_r)); //s = norm( r )*e1; s.SetV(e1, alpha: norm_r); int i; #region Gram-Schmidt (construct orthonormal basis using Gram-Schmidt) for (i = 1; i <= m; i++) { this.NoOfIterations++; #region Arnoldi procdure //w = M \ (A*V(:,i)); Matrix.SpMV(1.0, V[i - 1], 0.0, z); if (this.Precond != null) { w.Clear(); this.Precond.Solve(w, z); } else { w.SetV(z); } for (int k = 1; k <= i; k++) { H[k - 1, i - 1] = GenericBlas.InnerProd(w, V[k - 1]).MPISum(); //w = w - H(k,i)*V(:,k); w.AccV(-H[k - 1, i - 1], V[k - 1]); } double norm_w = w.L2NormPow2().MPISum().Sqrt(); H[i + 1 - 1, i - 1] = norm_w; // the +1-1 actually makes me sure I haven't forgotten to subtract -1 when porting the code //V(:,i+1) = w / H(i+1,i); V[i + 1 - 1].SetV(w, alpha: (1.0 / norm_w)); #endregion #region Givens rotation for (int k = 1; k <= i - 1; k++) { // apply Givens rotation, H is Hessenbergmatrix temp = cs[k - 1] * H[k - 1, i - 1] + sn[k - 1] * H[k + 1 - 1, i - 1]; H[k + 1 - 1, i - 1] = -sn[k - 1] * H[k - 1, i - 1] + cs[k - 1] * H[k + 1 - 1, i - 1]; H[k - 1, i - 1] = temp; } // [cs(i),sn(i)] = rotmat( H(i,i), H(i+1,i) ); % form i-th rotation matrix rotmat(out cs[i - 1], out sn[i - 1], H[i - 1, i - 1], H[i + 1 - 1, i - 1]); temp = cs[i - 1] * s[i - 1]; // % approximate residual norm H[i - 1, i - 1] = cs[i - 1] * H[i - 1, i - 1] + sn[i - 1] * H[i + 1 - 1, i - 1]; H[i + 1 - 1, i - 1] = 0.0; #endregion // update the residual vector (s == beta in many pseudocodes) s[i + 1 - 1] = -sn[i - 1] * s[i - 1]; s[i - 1] = temp; error = Math.Abs(s[i + 1 - 1]) / bnrm2; //{ // int rootRank = Matrix.RowPartitioning.FindProcess(i + 1 - 1); // if (Matrix.RowPartitioning.Rank == rootRank) { // } else { // error = double.NaN; // } // unsafe { // csMPI.Raw.Bcast((IntPtr)(&error), 1, csMPI.Raw._DATATYPE.DOUBLE, rootRank, Matrix.RowPartitioning.MPI_Comm); // } //} //using (StreamWriter writer = new StreamWriter(m_SessionPath + "//GMRES_Stats.txt", true)) //{ Console.WriteLine(i + " " + error); //} if (error <= m_Tolerance) { // update approximation and exit //using (StreamWriter writer = new StreamWriter(m_SessionPath + "//GMRES_Stats.txt", true)) //{ // writer.WriteLine(""); //} //y = H(1:i,1:i) \ s(1:i); y = new double[i]; H.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { i - 1, i - 1 }) .Solve(y, s.GetSubVector(0, i)); // x = x + V(:,1:i)*y; for (int ii = 0; ii < i; ii++) { X.AccV(y[ii], V[ii]); } this.m_Converged = true; break; } } #endregion //Debugger.Launch(); if (error <= this.m_Tolerance) { this.m_Converged = true; break; } // y = H(1:m,1:m) \ s(1:m); y = new double[m]; H.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { m - 1, m - 1 }) .Solve(y, s.GetSubVector(0, m)); // update approximation: x = x + V(:,1:m)*y; for (int ii = 0; ii < m; ii++) { X.AccV(y[ii], V[ii]); } // compute residual: r = M \ ( b-A*x ) z.SetV(B); Matrix.SpMV(-1.0, X, 1.0, z); if (IterationCallback != null) { error2 = z.L2NormPow2().MPISum().Sqrt(); IterationCallback(iter, X.CloneAs(), z.CloneAs(), this.m_mgop); //IterationCallback(this.NoOfIterations, X.CloneAs(), z.CloneAs(), this.m_mgop); } if (this.Precond != null) { r.Clear(); this.Precond.Solve(r, z); } else { r.SetV(z); } norm_r = r.L2NormPow2().MPISum().Sqrt(); s[i + 1 - 1] = norm_r; error = s[i + 1 - 1] / bnrm2; // % check convergence // if (error2 <= m_Tolerance) Check for error not error2 //break; } if (IterationCallback != null) { z.SetV(B); Matrix.SpMV(-1.0, X, 1.0, z); IterationCallback(iter, X.CloneAs(), z.CloneAs(), this.m_mgop); } if (!object.ReferenceEquals(_X, X)) { _X.SetV(X); } B.SetV(z); } }
public void Solve <U, V>(U X, V B) where U : IList <double> where V : IList <double> // { // init // ==== int L = this.m_mgop.Mapping.LocalLength; if (X.Count != L) { throw new ArgumentException(); } if (B.Count != L) { throw new ArgumentException(); } var Mtx = this.m_mgop.OperatorMatrix; // residual of initial guess // ========================= // history of solutions and residuals (max vector length 'MaxKrylovDim') List <double[]> SolHistory = new List <double[]>(); List <double[]> MxxHistory = new List <double[]>(); double[] Correction = new double[L]; double[] Mxx = new double[L]; double[] CurrentSol = new double[L]; double[] CurrentRes = new double[L]; CurrentSol.SetV(X, 1.0); CurrentRes.SetV(B, 1.0); Mtx.SpMV(-1.0, CurrentSol, 1.0, CurrentRes); int KrylovDim = 0; double[] Residual0 = CurrentRes.CloneAs(); double[] Solution0 = CurrentSol.CloneAs(); List <double> _R = new List <double>(); // diagnostic output if (this.IterationCallback != null) { this.IterationCallback(0, CurrentSol.CloneAs(), CurrentRes.CloneAs(), this.m_mgop); } // iterations... // ============= double[] PreviousRes = new double[L]; //MultidimensionalArray raw_Mxx = MultidimensionalArray.Create(L, MaxIter + 1); //MultidimensionalArray ortho_Mxx = MultidimensionalArray.Create(L, MaxIter + 1); MultidimensionalArray MassMatrix = MultidimensionalArray.Create(MaxKrylovDim, MaxKrylovDim); int PCcounter = 0; for (int iIter = 0; iIter < MaxIter; iIter++) { m_ThisLevelIterations++; Debug.Assert(SolHistory.Count == MxxHistory.Count); Debug.Assert(SolHistory.Count == KrylovDim); // select preconditioner var Precond = PrecondS[PCcounter]; PCcounter++; if (PCcounter >= PrecondS.Length) { PCcounter = 0; } // solve the residual equation: M*Correction = prev. Residual PreviousRes.SetV(CurrentRes); Correction.ClearEntries(); Precond.Solve(Correction, PreviousRes); // compute M*Correction Mtx.SpMV(1.0, Correction, 0.0, Mxx); // orthonormalize the Mxx -- vector with respect to the previous ones. Debug.Assert(KrylovDim == MxxHistory.Count); Debug.Assert(KrylovDim == SolHistory.Count); //raw_Mxx.SetColumn(KrylovDim, Mxx); for (int i = 0; i < KrylovDim; i++) { Debug.Assert(!object.ReferenceEquals(Mxx, MxxHistory[i])); double beta = GenericBlas.InnerProd(Mxx, MxxHistory[i]).MPISum(); Mxx.AccV(-beta, MxxHistory[i]); Correction.AccV(-beta, SolHistory[i]); } { double gamma = 1.0 / GenericBlas.L2NormPow2(Mxx).MPISum().Sqrt(); Mxx.ScaleV(gamma); Correction.ScaleV(gamma); } // for (int i = 0; i < KrylovDim; i++) { MassMatrix[i, KrylovDim] = GenericBlas.InnerProd(Mxx, MxxHistory[i]).MPISum(); } MassMatrix[KrylovDim, KrylovDim] = GenericBlas.L2NormPow2(Mxx).MPISum(); // //ortho_Mxx.SetColumn(KrylovDim, Mxx); MxxHistory.Add(Mxx.CloneAs()); SolHistory.Add(Correction.CloneAs()); KrylovDim++; // RHS of the minimization problem (LHS is identity matrix) _R.Add(GenericBlas.InnerProd(MxxHistory.Last(), Residual0).MPISum()); // compute accelerated solution //double[] alpha = _R.ToArray(); // factors for re-combining solutions double[] alpha; { double[] minimi_rhs = _R.ToArray(); var minimi_lhs = MassMatrix.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { KrylovDim - 1, KrylovDim - 1 }).CloneAs(); alpha = new double[KrylovDim]; minimi_lhs.Solve(alpha, minimi_rhs); } Debug.Assert(alpha.Length == SolHistory.Count); Debug.Assert(alpha.Length == MxxHistory.Count); Debug.Assert(alpha.Length == KrylovDim); CurrentSol.SetV(Solution0, 1.0); for (int i = 0; i < KrylovDim; i++) { CurrentSol.AccV(alpha[i], SolHistory[i]); } // compute new Residual CurrentRes.SetV(B); Mtx.SpMV(-1.0, CurrentSol, 1.0, CurrentRes); double crL2 = CurrentRes.L2Norm(); // diagnostic output if (this.IterationCallback != null) { this.IterationCallback(iIter + 1, CurrentSol.CloneAs(), CurrentRes.CloneAs(), this.m_mgop); } if (crL2 < Tolerance) { m_Converged = true; break; } if (KrylovDim >= MaxKrylovDim) { if (this.Restarted) { // restarted version of the algorithm // ++++++++++++++++++++++++++++++++++ MxxHistory.Clear(); SolHistory.Clear(); _R.Clear(); KrylovDim = 0; Residual0.SetV(CurrentRes); Solution0.SetV(CurrentSol); } else { // throw-away version of the algorithm // +++++++++++++++++++++++++++++++++++ int i_leastSig = alpha.IndexOfMin(x => x.Abs()); MxxHistory.RemoveAt(i_leastSig); SolHistory.RemoveAt(i_leastSig); KrylovDim--; for (int i = i_leastSig; i < KrylovDim; i++) { for (int j = 0; j <= KrylovDim; j++) { MassMatrix[i, j] = MassMatrix[i + 1, j]; } } for (int i = i_leastSig; i < KrylovDim; i++) { for (int j = 0; j <= KrylovDim; j++) { MassMatrix[j, i] = MassMatrix[j, i + 1]; } } Residual0.SetV(CurrentRes); Solution0.SetV(CurrentSol); _R.Clear(); foreach (double[] mxx in MxxHistory) { _R.Add(GenericBlas.InnerProd(mxx, Residual0).MPISum()); } } } } X.SetV(CurrentSol, 1.0); //raw_Mxx.SaveToTextFile("C:\\temp\\raw_Mxx.txt"); //ortho_Mxx.SaveToTextFile("C:\\temp\\ortho_Mxx.txt"); }