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; } }
void TestAgglomeration_Projection(int quadOrder, MultiphaseCellAgglomerator Agg) { var Bmask = LsTrk.Regions.GetSpeciesMask("B"); var BbitMask = Bmask.GetBitMask(); var XDGmetrics = LsTrk.GetXDGSpaceMetrics(new SpeciesId[] { LsTrk.GetSpeciesId("B") }, quadOrder, 1); int degree = Math.Max(0, this.u.Basis.Degree - 1); _2D SomePolynomial; if (degree == 0) { SomePolynomial = (x, y) => 3.2; } else if (degree == 1) { SomePolynomial = (x, y) => 3.2 + x - 2.4 * y; } else { SomePolynomial = (x, y) => x * x + y * y; } // ------------------------------------------------ // project the polynomial onto a single-phase field // ------------------------------------------------ SinglePhaseField NonAgglom = new SinglePhaseField(new Basis(this.GridData, degree), "NonAgglom"); NonAgglom.ProjectField(1.0, SomePolynomial.Vectorize(), new CellQuadratureScheme(true, Bmask)); // ------------------------------------------------ // project the polynomial onto the aggomerated XDG-field // ------------------------------------------------ var qsh = XDGmetrics.XQuadSchemeHelper; // Compute the inner product of 'SomePolynomial' with the cut-cell-basis, ... SinglePhaseField xt = new SinglePhaseField(NonAgglom.Basis, "test"); xt.ProjectField(1.0, SomePolynomial.Vectorize(), qsh.GetVolumeQuadScheme(this.LsTrk.GetSpeciesId("B")).Compile(this.GridData, Agg.CutCellQuadratureOrder)); CoordinateMapping map = xt.Mapping; // ... change to the cut-cell-basis, ... double[] xVec = xt.CoordinateVector.ToArray(); Agg.ManipulateMatrixAndRHS(default(MsrMatrix), xVec, map, null); { double[] xVec2 = xVec.CloneAs(); Agg.ClearAgglomerated(xVec2, map); // clearing should have no effect now. double Err3 = GenericBlas.L2DistPow2(xVec, xVec2).MPISum().Sqrt(); Assert.LessOrEqual(Err3, 0.0); } // ... multiply with the inverse mass-matrix, ... var Mfact = XDGmetrics.MassMatrixFactory; BlockMsrMatrix MassMtx = Mfact.GetMassMatrix(map, false); Agg.ManipulateMatrixAndRHS(MassMtx, default(double[]), map, map); var InvMassMtx = MassMtx.InvertBlocks(OnlyDiagonal: true, Subblocks: true, ignoreEmptyBlocks: true, SymmetricalInversion: true); double[] xAggVec = new double[xVec.Length]; InvMassMtx.SpMV(1.0, xVec, 0.0, xAggVec); // ... and extrapolate. // Since we projected a polynomial, the projection is exact and after extrapolation, must be equal // to the polynomial. xt.CoordinateVector.SetV(xAggVec); Agg.Extrapolate(xt.Mapping); // ------------------------------------------------ // check the error // ------------------------------------------------ //double Err2 = xt.L2Error(SomePolynomial.Vectorize(), new CellQuadratureScheme(domain: Bmask)); double Err2 = NonAgglom.L2Error(xt); Console.WriteLine("Agglom: projection and extrapolation error: " + Err2); Assert.LessOrEqual(Err2, 1.0e-10); }
protected override double RunSolverOneStep(int TimestepNo, double phystime, double dt) { Console.WriteLine(" Timestep # " + TimestepNo + ", phystime = " + phystime); //phystime = 1.8; LsUpdate(phystime); // operator-matrix assemblieren MsrMatrix OperatorMatrix = new MsrMatrix(u.Mapping, u.Mapping); double[] Affine = new double[OperatorMatrix.RowPartitioning.LocalLength]; // Agglomerator setup MultiphaseCellAgglomerator Agg = LsTrk.GetAgglomerator(new SpeciesId[] { LsTrk.GetSpeciesId("B") }, QuadOrder, this.THRESHOLD); // plausibility of cell length scales if (SER_PAR_COMPARISON) { TestLengthScales(QuadOrder, TimestepNo); } Console.WriteLine("Inter-Process agglomeration? " + Agg.GetAgglomerator(LsTrk.GetSpeciesId("B")).AggInfo.InterProcessAgglomeration); if (this.THRESHOLD > 0.01) { TestAgglomeration_Extraploation(Agg); TestAgglomeration_Projection(QuadOrder, Agg); } CheckExchange(true); CheckExchange(false); // operator matrix assembly XSpatialOperatorMk2.XEvaluatorLinear mtxBuilder = Op.GetMatrixBuilder(base.LsTrk, u.Mapping, null, u.Mapping); mtxBuilder.time = 0.0; mtxBuilder.ComputeMatrix(OperatorMatrix, Affine); Agg.ManipulateMatrixAndRHS(OperatorMatrix, Affine, u.Mapping, u.Mapping); // mass matrix factory var Mfact = LsTrk.GetXDGSpaceMetrics(new SpeciesId[] { LsTrk.GetSpeciesId("B") }, QuadOrder, 1).MassMatrixFactory;// new MassMatrixFactory(u.Basis, Agg); // Mass matrix/Inverse Mass matrix //var MassInv = Mfact.GetMassMatrix(u.Mapping, new double[] { 1.0 }, true, LsTrk.GetSpeciesId("B")); var Mass = Mfact.GetMassMatrix(u.Mapping, new double[] { 1.0 }, false, LsTrk.GetSpeciesId("B")); Agg.ManipulateMatrixAndRHS(Mass, default(double[]), u.Mapping, u.Mapping); var MassInv = Mass.InvertBlocks(OnlyDiagonal: true, Subblocks: true, ignoreEmptyBlocks: true, SymmetricalInversion: false); // test that operator depends only on B-species values double DepTest = LsTrk.Regions.GetSpeciesSubGrid("B").TestMatrixDependency(OperatorMatrix, u.Mapping, u.Mapping); Console.WriteLine("Matrix dependency test: " + DepTest); Assert.LessOrEqual(DepTest, 0.0); // diagnostic output Console.WriteLine("Number of Agglomerations (all species): " + Agg.TotalNumberOfAgglomerations); Console.WriteLine("Number of Agglomerations (species 'B'): " + Agg.GetAgglomerator(LsTrk.GetSpeciesId("B")).AggInfo.SourceCells.NoOfItemsLocally.MPISum()); // operator auswerten: double[] x = new double[Affine.Length]; BLAS.daxpy(x.Length, 1.0, Affine, 1, x, 1); OperatorMatrix.SpMVpara(1.0, u.CoordinateVector, 1.0, x); MassInv.SpMV(1.0, x, 0.0, du_dx.CoordinateVector); Agg.GetAgglomerator(LsTrk.GetSpeciesId("B")).Extrapolate(du_dx.Mapping); // markieren, wo ueberhaupt A und B sind Bmarker.AccConstant(1.0, LsTrk.Regions.GetSpeciesSubGrid("B").VolumeMask); Amarker.AccConstant(+1.0, LsTrk.Regions.GetSpeciesSubGrid("A").VolumeMask); if (usePhi0 && usePhi1) { Xmarker.AccConstant(+1.0, LsTrk.Regions.GetSpeciesSubGrid("X").VolumeMask); } // compute error ERR.Clear(); ERR.Acc(1.0, du_dx_Exact, LsTrk.Regions.GetSpeciesSubGrid("B").VolumeMask); ERR.Acc(-1.0, du_dx, LsTrk.Regions.GetSpeciesSubGrid("B").VolumeMask); double L2Err = ERR.L2Norm(LsTrk.Regions.GetSpeciesSubGrid("B").VolumeMask); Console.WriteLine("L2 Error: " + L2Err); XERR.Clear(); XERR.GetSpeciesShadowField("B").Acc(1.0, ERR, LsTrk.Regions.GetSpeciesSubGrid("B").VolumeMask); double xL2Err = XERR.L2Norm(); Console.WriteLine("L2 Error (in XDG space): " + xL2Err); // check error double ErrorThreshold = 1.0e-1; if (this.MomentFittingVariant == XQuadFactoryHelper.MomentFittingVariants.OneStepGaussAndStokes) { ErrorThreshold = 1.0e-6; // HMF is designed for such integrands and should perform close to machine accuracy; on general integrands, the precision is different. } bool IsPassed = ((L2Err <= ErrorThreshold || this.THRESHOLD <= ErrorThreshold) && xL2Err <= ErrorThreshold); if (IsPassed) { Console.WriteLine("Test PASSED"); } else { Console.WriteLine("Test FAILED: check errors."); //PlotCurrentState(phystime, TimestepNo, 3); } if (TimestepNo > 1) { if (this.THRESHOLD > ErrorThreshold) { // without agglomeration, the error in very tiny cut-cells may be large over the whole cell // However, the error in the XDG-space should be small under all circumstances Assert.LessOrEqual(L2Err, ErrorThreshold, "DG L2 error of computing du_dx"); } Assert.LessOrEqual(xL2Err, ErrorThreshold, "XDG L2 error of computing du_dx"); } // return/Ende base.NoOfTimesteps = 17; //base.NoOfTimesteps = 2; dt = 0.3; return(dt); }