void TestAgglomeration_Extraploation(MultiphaseCellAgglomerator Agg) { _2D SomePolynomial; if (this.u.Basis.Degree == 0) { SomePolynomial = (x, y) => 3.2; } else if (this.u.Basis.Degree == 1) { SomePolynomial = (x, y) => 3.2 + x - 2.4 * y; } else { SomePolynomial = (x, y) => x * x + y * y; } // ======================================================== // extrapolate polynomial function for species B of a XDG-field // ======================================================== var Bmask = LsTrk.Regions.GetSpeciesMask("B"); XDGField xt = new XDGField(new XDGBasis(this.LsTrk, this.u.Basis.Degree), "XDG-test"); xt.GetSpeciesShadowField("B").ProjectField(1.0, SomePolynomial.Vectorize(), new CellQuadratureScheme(true, Bmask)); double[] bkupVec = xt.CoordinateVector.ToArray(); Agg.ClearAgglomerated(xt.Mapping); Agg.Extrapolate(xt.Mapping); double Err = GenericBlas.L2DistPow2(bkupVec, xt.CoordinateVector).MPISum().Sqrt(); Console.WriteLine("Agglom: extrapolation error: " + Err); Assert.LessOrEqual(Err, 1.0e-10); // ======================================================== // extrapolate polynomial function for a single-phase-field // ======================================================== SinglePhaseField xt2 = new SinglePhaseField(this.u.Basis, "DG-test"); xt2.ProjectField(SomePolynomial); double[] bkupVec2 = xt2.CoordinateVector.ToArray(); Agg.ClearAgglomerated(xt2.Mapping); Agg.Extrapolate(xt2.Mapping); double Err2 = GenericBlas.L2DistPow2(bkupVec, xt.CoordinateVector).MPISum().Sqrt(); Console.WriteLine("Agglom: extrapolation error: " + Err2); Assert.LessOrEqual(Err2, 1.0e-10); }
/// <summary> /// Updates the XDG component of an aggregation basis according to the new aggomeration. /// </summary> public static void UpdateXdgAggregationBasis(this AggregationGridBasis[][] MultigridBasis, MultiphaseCellAgglomerator CurrentAgglomeration) { bool useX = false; var _XdgAggregationBasis = new XdgAggregationBasis[MultigridBasis.Length]; for (int iLevel = 0; iLevel < MultigridBasis.Length; iLevel++) { XdgAggregationBasis[] xab = MultigridBasis[iLevel].Where(b => b is XdgAggregationBasis).Select(b => ((XdgAggregationBasis)b)).ToArray(); if (xab != null && xab.Length > 0) { for (int ib = 1; ib < xab.Length; ib++) { if (!(object.ReferenceEquals(xab[ib].DGBasis.GridDat, CurrentAgglomeration.Tracker.GridDat))) { throw new ApplicationException(); } if (!object.ReferenceEquals(xab[0], xab[ib])) { throw new ArgumentException("One should only use one XDG aggregation basis per multigrid level."); } } _XdgAggregationBasis[iLevel] = xab[0]; useX = true; } } if (useX) { foreach (var xmgb in _XdgAggregationBasis) { xmgb.Update(CurrentAgglomeration); } } }
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); }
/// <summary> /// defines how species in the agglomerated cells /// map to species in the base grid cells. /// </summary> private void UpdateSpeciesMapping(MultiphaseCellAgglomerator Agglomerator) { Debug.Assert(object.ReferenceEquals(Agglomerator.Tracker, this.XDGBasis.Tracker)); var LsTrk = this.XDGBasis.Tracker; int GlobalNoOfSpc = LsTrk.SpeciesIdS.Count; var agg = base.AggGrid; int[][] compCells = agg.iLogicalCells.AggregateCellToParts; int JAGG = compCells.Length; Debug.Assert(JAGG == agg.iLogicalCells.Count); int JAGGup = agg.iLogicalCells.NoOfLocalUpdatedCells; this.UsedSpecies = Agglomerator.SpeciesList.ToArray(); if (NoOfSpecies == null) { NoOfSpecies = new int[JAGG]; SpeciesIndexMapping = new int[JAGG][, ]; } else { Debug.Assert(NoOfSpecies.Length == JAGG); Array.Clear(NoOfSpecies, 0, JAGG); } if (AggCellsSpecies == null) { AggCellsSpecies = new SpeciesId[JAGG][]; } //if (CoarseToFineSpeciesIndex == null && agg.MgLevel > 0) // CoarseToFineSpeciesIndex = new int[JAGG][,]; Dictionary <SpeciesId, BitArray> agglomeratedCells = new Dictionary <SpeciesId, BitArray>(); foreach (var SpId in Agglomerator.SpeciesList) { agglomeratedCells.Add(SpId, Agglomerator.GetAgglomerator(SpId).AggInfo.SourceCells.GetBitMaskWithExternal()); } // temp buffer int[] _NoOfSpecies = new int[agg.jCellCoarse2jCellFine[0].Length]; ReducedRegionCode[] _RRcs = new ReducedRegionCode[agg.iLogicalCells.AggregateCellToParts[0].Length]; SpeciesId[] allPresentSpecies = new SpeciesId[LsTrk.TotalNoOfSpecies]; // loop over all aggregate (multigrid) cells... for (int jagg = 0; jagg < JAGGup; jagg++) { int[] compCell = compCells[jagg]; int K = compCell.Length; // buffer sizes if (K > _NoOfSpecies.Length) { int newLen = (int)Math.Ceiling(K * 1.2); Array.Resize(ref _NoOfSpecies, newLen); Array.Resize(ref _RRcs, newLen); } // check no of species: int MaxNoOfSpecies = 0; // number of species in the composite cell for (int k = 0; k < K; k++) // loop over original cells in composite cell { int jCell = compCell[k]; _NoOfSpecies[k] = LsTrk.Regions.GetNoOfSpecies(jCell, out _RRcs[k]); MaxNoOfSpecies = Math.Max(_NoOfSpecies[k], MaxNoOfSpecies); } if (MaxNoOfSpecies == 1) { // only one species -- use single-phase implementation in underlying class this.SpeciesIndexMapping[jagg] = null; this.NoOfSpecies[jagg] = 1; //this.XCompositeBasis[jagg] = null; this.AggCellsSpecies[jagg] = null; //this.CoarseToFineSpeciesIndex[jagg] = null; } else { //LsTrk.ContainesSpecies int w = 0; // counter for found species if (this.SpeciesIndexMapping[jagg] == null || this.SpeciesIndexMapping[jagg].GetLength(0) != w) { this.SpeciesIndexMapping[jagg] = new int[0, compCell.Length]; } ArrayTools.SetAll(this.SpeciesIndexMapping[jagg], -897645); // collect all species which are present in the composite cell 'jagg': // ------------------------------------------------------------------- for (int k = 0; k < K; k++) // loop over all base cells in the aggregate cell 'jagg' { var rrc = _RRcs[k]; int jCell = compCell[k]; // base cell index for (int iSpc = _NoOfSpecies[k] - 1; iSpc >= 0; iSpc--) { SpeciesId spId = LsTrk.GetSpeciesIdFromIndex(rrc, iSpc); bool isPresent = LsTrk.Regions.IsSpeciesPresentInCell(spId, jCell); bool isAgglomerated = agglomeratedCells.ContainsKey(spId) ? agglomeratedCells[spId][jCell] : false; bool isUsed = Array.IndexOf(this.UsedSpecies, spId) >= 0; if (isUsed && isPresent && !isAgglomerated) { bool bfound = false; int z; for (z = 0; z < w; z++) // loop over species found so far... { if (allPresentSpecies[z] == spId) { bfound = true; break; } } if (!bfound) { // species not found -> add to list allPresentSpecies[w] = spId; z = w; w++; } // z is the species index in the composite cell // iSpc is the species index in 'jCell' Resize2DArray(ref this.SpeciesIndexMapping[jagg], w, K, -897645); this.SpeciesIndexMapping[jagg][z, k] = iSpc; } } } this.AggCellsSpecies[jagg] = allPresentSpecies.GetSubVector(0, w); this.NoOfSpecies[jagg] = w; Debug.Assert(this.NoOfSpecies[jagg] == this.SpeciesIndexMapping[jagg].GetLength(0)); } Debug.Assert(this.NoOfSpecies[jagg] >= 0); Debug.Assert(this.NoOfSpecies[jagg] <= this.UsedSpecies.Length); } // MPI exchange for external cells // note: external aggregation cells may be incomplete, i.e. not have all parts, only those known to parent NoOfSpecies.MPIExchange(this.AggGrid); }
public void Update(MultiphaseCellAgglomerator Agglomerator) { using (new FuncTrace()) { //if(!this.XDGBasis.IsSubBasis(mmf.MaxBasis)) // throw new ArgumentException(); var LsTrk = this.XDGBasis.Tracker; var CCBit = LsTrk.Regions.GetCutCellMask().GetBitMask(); int N = this.DGBasis.Length; int JAGG = base.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; UpdateSpeciesMapping(Agglomerator); // mass matrix in the aggregate cell, before we orthonormalize: var AggCellMMb4Ortho = MultidimensionalArray.Create(N, N); for (int jagg = 0; jagg < JAGG; jagg++) { int NoOfSpc_jagg = this.NoOfSpecies[jagg]; int[] AggCell = base.AggGrid.iLogicalCells.AggregateCellToParts[jagg]; int K = AggCell.Length; int[,] sim = this.SpeciesIndexMapping[jagg]; Debug.Assert((sim == null) || (sim.GetLength(0) == NoOfSpc_jagg)); Debug.Assert((sim == null) || (sim.GetLength(1) == K)); if (sim == null) { // nothing to do. // +++++++++++++++++++++++++++++++++++++++++++++++ this.XCompositeBasis[jagg] = null; } else { // the cut-cell may require some special treatment // +++++++++++++++++++++++++++++++++++++++++++++++ for (int iSpc_agg = 0; iSpc_agg < NoOfSpc_jagg; iSpc_agg++) // loop over all species in aggregate cell { bool emptyCell = false; // true: at least one of the base cells which form // aggregate cell 'jagg' is empty with respect to the 'iSpc_agg'--th species. // => this will alter the projection operator. for (int k = 0; k < K; k++) { if (sim[iSpc_agg, k] < 0) { emptyCell = true; break; } } #if DEBUG { bool NonEmpty = false; for (int k = 0; k < K; k++) { if (sim[iSpc_agg, k] >= 0) { NonEmpty = true; break; } } Debug.Assert(NonEmpty); // there should be at least one non-empty base cell (for species 'iSpc_agg') // in aggregate cell 'jagg' } #endif if (this.XCompositeBasis[jagg] == null || (this.XCompositeBasis[jagg].Length != NoOfSpc_jagg)) { this.XCompositeBasis[jagg] = new MultidimensionalArray[NoOfSpc_jagg]; } if (emptyCell) { // compute mass matrix in aggregate cell 'jagg' for species index 'iSpc_agg' // ------------------------------------------------------------------------- AggCellMMb4Ortho.Clear(); for (int k = 0; k < K; k++) // loop over the base cells in the aggregate cell { if (sim[iSpc_agg, k] >= 0) { var ExPolMtx = base.CompositeBasis[jagg].ExtractSubArrayShallow(k, -1, -1); AggCellMMb4Ortho.Multiply(1.0, ExPolMtx, ExPolMtx, 1.0, "lm", "im", "il"); } } // change to orthonormal basis // --------------------------- MultidimensionalArray B = MultidimensionalArray.Create(N, N); AggCellMMb4Ortho.SymmetricLDLInversion(B, default(double[])); if (this.XCompositeBasis[jagg][iSpc_agg] == null) { this.XCompositeBasis[jagg][iSpc_agg] = MultidimensionalArray.Create(K, N, N); } var X_ExPolMtx = this.XCompositeBasis[jagg][iSpc_agg]; var NonX_ExPolMtx = CompositeBasis[jagg]; X_ExPolMtx.Allocate(NonX_ExPolMtx.Lengths); // should not reallocate if lengths stay the same; X_ExPolMtx.Multiply(1.0, NonX_ExPolMtx, B, 0.0, "imn", "imk", "kn"); } else { // no empty cell with respect to species 'iSpc_agg' in aggregate cell // --> non-XDG projector can be used. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ this.XCompositeBasis[jagg][iSpc_agg] = null; } } } } } }
// Local Variables for Iteration // <summary> // Counter for Iteration Steps // </summary> //double OldResidual = double.MaxValue; //int divergencecounter = 0; ///// <summary> ///// Checks for Reaching Max. Number of Iterations and Divergence of Algorithm ///// </summary> ///// <param name="Residual">Change Rate of the Algorithm</param> ///// <returns>Reaching Max Iterations, Aborts when diverged</returns> //public bool CheckAbortCriteria(double Residual, int IterationCounter) { // if (Residual <= ConvergenceCriterion) { // Console.WriteLine("EllipticReInit converged after {0} Iterations ", IterationCounter); // return true; // } // if (Residual >= OldResidual) divergencecounter++; // else divergencecounter = 0; // if (IterationCounter >= MaxIteration) { // Console.WriteLine("Elliptic Reinit Max Iterations Reached"); // return true; // }; // if (divergencecounter > MaxIteration / 2) { // Console.WriteLine("Elliptic Reinit diverged - Aborting"); // throw new ApplicationException(); // } // OldResidual = Residual; // IterationCounter++; // return false; //} //bool PreviouslyOnSubgrid = false; /// <summary> /// Updates the Operator Matrix after level-set motion /// </summary> /// <param name="Restriction"> /// The subgrid, on which the ReInit is performed /// </param> /// <param name="IncludingInterface"> /// !! Not yet functional !! /// True, if the subgrid contains the interface, this causes all external edges of the subgrid to be treated as boundaries /// False, for the rest of the domain, thus the flux to the adjacent cells wil be evaluated /// </param> public void UpdateOperators(SubGrid Restriction = null, bool IncludingInterface = true) { if (!IncludingInterface) { throw new NotImplementedException("Untested, not yet functional!"); } using (new FuncTrace()) { //using (var slv = new ilPSP.LinSolvers.MUMPS.MUMPSSolver()) { //using (var slv = new ilPSP.LinSolvers.PARDISO.PARDISOSolver()) { //using (var slv = new ilPSP.LinSolvers.HYPRE.GMRES()) { if (Control.Upwinding) { OldPhi.Clear(); OldPhi.Acc(1.0, Phi); //Calculate LevelSetGradient.Clear(); LevelSetGradient.Gradient(1.0, Phi, Restriction?.VolumeMask); //LevelSetGradient.Gradient(1.0, Phi); //LevelSetGradient.GradientByFlux(1.0, Phi); MeanLevelSetGradient.Clear(); MeanLevelSetGradient.AccLaidBack(1.0, LevelSetGradient, Restriction?.VolumeMask); //MeanLevelSetGradient.AccLaidBack(1.0, LevelSetGradient); } if (slv != null) { slv.Dispose(); } slv = Control.solverFactory(); OpMatrix_interface.Clear(); OpAffine_interface.Clear(); // Build the Quadrature-Scheme for the interface operator // Note: The HMF-Quadrature over a surface is formally a volume quadrature, since it uses the volume quadrature nodes. //XSpatialOperatorExtensions.ComputeMatrixEx(Operator_interface, ////Operator_interface.ComputeMatrixEx( // LevelSetTracker, // Phi.Mapping, // null, // Phi.Mapping, // OpMatrix_interface, // OpAffine_interface, // false, // 0, // false, // subGrid:Restriction, // whichSpc: LevelSetTracker.GetSpeciesId("A") // ); XSpatialOperatorMk2.XEvaluatorLinear mtxBuilder = Operator_interface.GetMatrixBuilder(LevelSetTracker, Phi.Mapping, null, Phi.Mapping); MultiphaseCellAgglomerator dummy = LevelSetTracker.GetAgglomerator(LevelSetTracker.SpeciesIdS.ToArray(), Phi.Basis.Degree * 2 + 2, 0.0); //mtxBuilder.SpeciesOperatorCoefficients[LevelSetTracker.GetSpeciesId("A")].CellLengthScales = dummy.CellLengthScales[LevelSetTracker.GetSpeciesId("A")]; mtxBuilder.CellLengthScales.Add(LevelSetTracker.GetSpeciesId("A"), dummy.CellLengthScales[LevelSetTracker.GetSpeciesId("A")]); mtxBuilder.time = 0; mtxBuilder.MPITtransceive = false; mtxBuilder.ComputeMatrix(OpMatrix_interface, OpAffine_interface); // Regenerate OpMatrix for subgrid -> adjacent cells must be trated as boundary if (Restriction != null) { OpMatrix_bulk.Clear(); OpAffine_bulk.Clear(); //Operator_bulk.ComputeMatrix( // Phi.Mapping, // parameterFields, // Phi.Mapping, // OpMatrix_bulk, OpAffine_bulk, // OnlyAffine: false, sgrd: Restriction); EdgeQuadratureScheme edgescheme; //if (Control.Upwinding) { // edgescheme = new EdgeQuadratureScheme(true, IncludingInterface ? Restriction.AllEdgesMask : null); //} //else { edgescheme = new EdgeQuadratureScheme(true, IncludingInterface ? Restriction.InnerEdgesMask : null); //} Operator_bulk.ComputeMatrixEx(Phi.Mapping, parameterFields, Phi.Mapping, OpMatrix_bulk, OpAffine_bulk, false, 0, edgeQuadScheme: edgescheme, volQuadScheme: new CellQuadratureScheme(true, IncludingInterface ? Restriction.VolumeMask : null) ); //PreviouslyOnSubgrid = true; } // recalculate full Matrix //else if (PreviouslyOnSubgrid) { else { OpMatrix_bulk.Clear(); OpAffine_bulk.Clear(); Operator_bulk.ComputeMatrixEx(Phi.Mapping, parameterFields, Phi.Mapping, OpMatrix_bulk, OpAffine_bulk, false, 0 ); //PreviouslyOnSubgrid = false; } /// Compose the Matrix /// This is symmetric due to the symmetry of the SIP and the penalty term OpMatrix.Clear(); OpMatrix.Acc(1.0, OpMatrix_bulk); OpMatrix.Acc(1.0, OpMatrix_interface); OpMatrix.AssumeSymmetric = !Control.Upwinding; //OpMatrix.AssumeSymmetric = false; /// Compose the RHS of the above operators. (-> Boundary Conditions) /// This does NOT include the Nonlinear RHS, which will be added later OpAffine.Clear(); OpAffine.AccV(1.0, OpAffine_bulk); OpAffine.AccV(1.0, OpAffine_interface); #if Debug ilPSP.Connectors.Matlab.BatchmodeConnector matlabConnector; matlabConnector = new BatchmodeConnector(); #endif if (Restriction != null) { SubVecIdx = Phi.Mapping.GetSubvectorIndices(Restriction, true, new int[] { 0 }); int L = SubVecIdx.Length; SubMatrix = new MsrMatrix(L); SubRHS = new double[L]; SubSolution = new double[L]; OpMatrix.AccSubMatrixTo(1.0, SubMatrix, SubVecIdx, default(int[]), SubVecIdx, default(int[])); slv.DefineMatrix(SubMatrix); #if Debug Console.WriteLine("ConditionNumber of ReInit-Matrix is " + SubMatrix.condest().ToString("E")); #endif } else { slv.DefineMatrix(OpMatrix); #if Debug Console.WriteLine("ConditionNumber of ReInit-Matrix is " + OpMatrix.condest().ToString("E")); #endif } } }
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; } }
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); }
protected virtual void DelComputeOperatorMatrix(BlockMsrMatrix OpMatrix, double[] OpAffine, UnsetteledCoordinateMapping Mapping, DGField[] CurrentState, MultiphaseCellAgglomerator Agglomerator, double phystime) { OpMatrix.Clear(); OpAffine.ClearEntries(); Op.ComputeMatrixEx(base.LsTrk, u.Mapping, null, uResidual.Mapping, OpMatrix, OpAffine, false, phystime, false, XQuadFactoryHelper.MomentFittingVariants.OneStepGaussAndStokes, base.LsTrk.SpeciesIdS.ToArray()); }
/// <summary> /// Mainly, comparison of single-core vs MPI-parallel run /// </summary> void TestLengthScales(int quadOrder, int TimestepNo) { string name_disc = $"t{TimestepNo}-alpha{this.THRESHOLD}-p{this.DEGREE}-q{MomentFittingVariant}"; var spcA = LsTrk.GetSpeciesId("A"); var spcB = LsTrk.GetSpeciesId("B"); var species = new[] { spcA, spcB }; //MultiphaseCellAgglomerator.CheckFile = $"InsideMpagg-{name_disc}.csv"; MultiphaseCellAgglomerator Agg = LsTrk.GetAgglomerator(species, quadOrder, this.THRESHOLD); int RefMPIsize = 1; // check level-set coordinates // =========================== { var LsChecker = new TestingIO(this.GridData, $"LevelSets-{name_disc}.csv", RefMPIsize); LsChecker.AddDGField(this.Phi0); LsChecker.AddDGField(this.Phi1); LsChecker.DoIOnow(); Assert.Less(LsChecker.AbsError(this.Phi0), 1.0e-8, "Mismatch in level-set 0 between single-core and parallel run."); Assert.Less(LsChecker.AbsError(this.Phi1), 1.0e-8, "Mismatch in level-set 1 between single-core and parallel run."); } // check equality of agglomeration // =============================== // Note: agglomeration in parallel and serial mode is not necessarily equal - but very often it is. // Therefore, we need to check whether the agglomeration is equal or not, // in order to know whether agglomerated length scales should be compared or not. bool[] equalAggAsinReferenceRun; { var aggoCheck = new TestingIO(this.GridData, $"Agglom-{name_disc}.csv", RefMPIsize); long[] GiDs = GridData.CurrentGlobalIdPermutation.Values; int J = GridData.iLogicalCells.NoOfLocalUpdatedCells; long[] extGiDs = GridData.iParallel.GlobalIndicesExternalCells; for (int iSpc = 0; iSpc < species.Length; iSpc++) { var spc = species[iSpc]; var spcN = LsTrk.GetSpeciesName(spc); var ai = Agg.GetAgglomerator(spc).AggInfo; var srcMask = ai.SourceCells.GetBitMask(); var aggPairs = ai.AgglomerationPairs; aggoCheck.AddColumn($"SourceCells{spcN}", delegate(double[] X, int j, int jG) { if (srcMask[j]) { var pair = aggPairs.Single(cap => cap.jCellSource == j); if (pair.jCellTarget < J) { return((double)GiDs[pair.jCellTarget]); } else { return((double)extGiDs[pair.jCellTarget - J]); } } return(0.0); }); } aggoCheck.DoIOnow(); equalAggAsinReferenceRun = new bool[species.Length]; for (int iSpc = 0; iSpc < species.Length; iSpc++) { var spc = species[iSpc]; var spcN = LsTrk.GetSpeciesName(spc); equalAggAsinReferenceRun[iSpc] = aggoCheck.AbsError($"SourceCells{spcN}") < 0.1; if (equalAggAsinReferenceRun[iSpc] == false) { Console.WriteLine("Different agglomeration between single-core and parallel run for species " + spcN + "."); } } //Agg.PlotAgglomerationPairs($"-aggPairs-{name_disc}-MPI{MPIRank + 1}of{MPISize}"); } // compare length scales // ===================== csMPI.Raw.Comm_Rank(csMPI.Raw._COMM.WORLD, out int rank); foreach (ICutCellMetrics ccm in new ICutCellMetrics[] { Agg.NonAgglomeratedMetrics, Agg }) // loop over non-agglom and agglomerated metrics { string name; bool Agglom; if (object.ReferenceEquals(ccm, Agg)) { name = "Agglomerated"; Agglom = true; } else { name = "Nonagglom"; Agglom = false; } MultidimensionalArray CellSurfaceA = ccm.CellSurface[spcA]; MultidimensionalArray CellVolumeA = ccm.CutCellVolumes[spcA]; MultidimensionalArray CellSurfaceB = ccm.CellSurface[spcB]; MultidimensionalArray CellVolumeB = ccm.CutCellVolumes[spcB]; string FileName = $"{name}LengthScales-{name_disc}.csv"; var Checker = new TestingIO(this.GridData, FileName, RefMPIsize); Checker.AddColumn("CellSurfA", (double[] X, int j, int jG) => CellSurfaceA[j]); Checker.AddColumn("CellVolA", (double[] X, int j, int jG) => CellVolumeA[j]); Checker.AddColumn("CellSurfB", (double[] X, int j, int jG) => CellSurfaceB[j]); Checker.AddColumn("CellVolB", (double[] X, int j, int jG) => CellVolumeB[j]); Checker.DoIOnow(); if (this.MPISize == 1) { var Checker2 = new TestingIO(this.GridData, FileName, int.MaxValue); Checker2.AddColumn("CellSurfA", (double[] X, int j, int jG) => CellSurfaceA[j]); Checker2.AddColumn("CellVolA", (double[] X, int j, int jG) => CellVolumeA[j]); Checker2.AddColumn("CellSurfB", (double[] X, int j, int jG) => CellSurfaceB[j]); Checker2.AddColumn("CellVolB", (double[] X, int j, int jG) => CellVolumeB[j]); Checker2.DoIOnow(); foreach (string s in Checker2.ColumnNames) { Assert.Less(Checker2.RelError(s), 1.0e-10, "'TestingUtils.Compare' itself is f****d up."); } } double srfA = Checker.RelError("CellSurfA") * ((!Agglom || equalAggAsinReferenceRun[0]) ? 1.0 : 0.0); double volA = Checker.RelError("CellVolA") * ((!Agglom || equalAggAsinReferenceRun[0]) ? 1.0 : 0.0); double srfB = Checker.RelError("CellSurfB") * ((!Agglom || equalAggAsinReferenceRun[1]) ? 1.0 : 0.0); double volB = Checker.RelError("CellVolB") * ((!Agglom || equalAggAsinReferenceRun[1]) ? 1.0 : 0.0); if (srfA + volA + srfB + volB > 0.001) { Console.WriteLine($"Mismatch in {name} cell surface for species A between single-core and parallel run: {srfA}."); Console.WriteLine($"Mismatch in {name} cell volume for species A between single-core and parallel run: {volA}."); Console.WriteLine($"Mismatch in {name} cell surface for species B between single-core and parallel run: {srfB}."); Console.WriteLine($"Mismatch in {name} cell volume for species B between single-core and parallel run: {volB}."); } Assert.Less(srfA, BLAS.MachineEps.Sqrt(), $"Mismatch in {name} cell surface for species A between single-core and parallel run."); Assert.Less(volA, BLAS.MachineEps.Sqrt(), $"Mismatch in {name} cell volume for species A between single-core and parallel run."); Assert.Less(srfB, BLAS.MachineEps.Sqrt(), $"Mismatch in {name} cell surface for species B between single-core and parallel run."); Assert.Less(volB, BLAS.MachineEps.Sqrt(), $"Mismatch in {name} cell volume for species B between single-core and parallel run."); } }
/// <summary> /// Discards old quadrature information /// </summary> /// <param name="value"></param> public void OnNext(LevelSetTracker.LevelSetRegions value) { this.MaMaFactCache.Clear(); this.cellAgglomeration = null; }
/// <summary> /// Constructor for XDG solvers /// </summary> public OpAnalysisBase(LevelSetTracker LsTrk, BlockMsrMatrix Mtx, double[] RHS, UnsetteledCoordinateMapping Mapping, MultiphaseCellAgglomerator CurrentAgglomeration, BlockMsrMatrix _mass, IEnumerable <MultigridOperator.ChangeOfBasisConfig[]> OpConfig, ISpatialOperator abstractOperator) { int RHSlen = Mapping.TotalLength; m_map = Mapping; // mapping VarGroup = Mapping.BasisS.Count.ForLoop(i => i); //default: all dependent variables are included in operator matrix m_LsTrk = LsTrk; m_OpMtx = Mtx.CloneAs(); localRHS = RHS.CloneAs(); // create the Dummy XDG aggregation basis var baseGrid = Mapping.GridDat; var mgSeq = Foundation.Grid.Aggregation.CoarseningAlgorithms.CreateSequence(baseGrid, 1); AggregationGridBasis[][] XAggB = AggregationGridBasis.CreateSequence(mgSeq, Mapping.BasisS); // XAggB.UpdateXdgAggregationBasis(CurrentAgglomeration); // create multigrid operator m_MultigridOp = new MultigridOperator(XAggB, Mapping, m_OpMtx, _mass, OpConfig, abstractOperator.DomainVar.Select(varName => abstractOperator.FreeMeanValue[varName]).ToArray()); }
/// <summary> /// Create Spatial Operators and build the corresponding Matrices /// </summary> public void ComputeMatrices(IList <DGField> InterfaceParams, bool nearfield) { OpMatrix = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine = new double[OpMatrix.RowPartitioning.LocalLength]; OpMatrix_bulk = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine_bulk = new double[OpMatrix.RowPartitioning.LocalLength]; OpMatrix_interface = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine_interface = new double[OpMatrix.RowPartitioning.LocalLength]; //LevelSetTracker.GetLevelSetGradients(0,); // bulk part of the matrix //Operator_bulk.ComputeMatrix( // Extension.Mapping, // LevelSetGradient.ToArray(), // Extension.Mapping, // OpMatrix_bulk, OpAffine_bulk, // OnlyAffine: false, sgrd: null); switch (Control.FluxVariant) { case FluxVariant.GradientBased: // Flux Direction based on Mean Level Set Gradient BulkParams = new List <DGField> { }; // Hack, to make ArrayTools.Cat produce a List of DGFields // second Hack: Does only work, when InterfaceParams is according to a single component flux, // else, we will have to change the boundary edge flux BulkParams = ArrayTools.Cat(BulkParams, LevelSetGradient.ToArray(), Phi, MeanLevelSetGradient.ToArray(), InterfaceParams.ToArray()); MeanLevelSetGradient.Clear(); MeanLevelSetGradient.AccLaidBack(1.0, LevelSetGradient); break; case FluxVariant.ValueBased: // Flux Direction Based on Cell-Averaged Level-Set Value BulkParams = ArrayTools.Cat(LevelSetGradient.ToArray(), Phi, MeanLevelSet); MeanLevelSet.Clear(); MeanLevelSet.AccLaidBack(1.0, Phi); break; case FluxVariant.SWIP: BulkParams = LevelSetGradient.ToArray(); break; default: throw new Exception(); } // Build Operator Operator_bulk.ComputeMatrixEx(Extension.Mapping, BulkParams, Extension.Mapping, OpMatrix_bulk, OpAffine_bulk, OnlyAffine: false, time: 0.0, edgeQuadScheme: new EdgeQuadratureScheme(true, nearfield ? LevelSetTracker.Regions.GetNearFieldSubgrid(1).InnerEdgesMask : null), volQuadScheme: new CellQuadratureScheme(true, nearfield ? LevelSetTracker.Regions.GetNearFieldSubgrid(1).VolumeMask : null) ); //Operator_interface.ComputeMatrixEx( // LevelSetTracker, // Extension.Mapping, // InterfaceParams, // Extension.Mapping, // OpMatrix_interface, // OpAffine_interface, // OnlyAffine: false, // time: 0, // MPIParameterExchange: false, // whichSpc: LevelSetTracker.GetSpeciesId("A") // ); Operator_interface.OperatorCoefficientsProvider = delegate(LevelSetTracker lstrk, SpeciesId spc, int quadOrder, int TrackerHistoryIdx, double time) { var r = new CoefficientSet() { }; //throw new NotImplementedException("todo"); return(r); }; XSpatialOperatorMk2.XEvaluatorLinear mtxBuilder = Operator_interface.GetMatrixBuilder(LevelSetTracker, Extension.Mapping, InterfaceParams, Extension.Mapping); MultiphaseCellAgglomerator dummy = LevelSetTracker.GetAgglomerator(LevelSetTracker.SpeciesIdS.ToArray(), 2 * Extension.Basis.Degree + 2, 0.0); mtxBuilder.CellLengthScales.Add(LevelSetTracker.GetSpeciesId("A"), dummy.CellLengthScales[LevelSetTracker.GetSpeciesId("A")]); mtxBuilder.time = 0; mtxBuilder.MPITtransceive = false; mtxBuilder.ComputeMatrix(OpMatrix_interface, OpAffine_interface); #if DEBUG OpMatrix_bulk.CheckForNanOrInfM(); OpAffine_bulk.CheckForNanOrInfV(); OpMatrix_interface.CheckForNanOrInfM(); OpAffine_interface.CheckForNanOrInfV(); #endif //Only for Debugging purposes Debug.Assert(OpMatrix_interface.GetDiagVector().L2Norm() > 0, "L2-Norm of Diagonal of InterfaceOperator is 0"); Debug.Assert(OpMatrix_bulk.GetDiagVector().L2Norm() > 0, "L2-Norm of Diagonal of BulkOperator is 0"); #if DEBUG //Console.WriteLine( "L2-Norm of Diagonal of InterfaceOperator is {0}", OpMatrix_interface.GetDiagVector().L2Norm() ); #endif OpMatrix.Clear(); OpMatrix.Acc(1.0, OpMatrix_bulk); OpMatrix.Acc(1.0, OpMatrix_interface); //Console.WriteLine("Op-Matrix Symmetry-Deviation: {0}", OpMatrix.SymmetryDeviation()); OpMatrix.AssumeSymmetric = false; OpAffine.Clear(); OpAffine.AccV(1.0, OpAffine_bulk); OpAffine.AccV(1.0, OpAffine_interface); #if DEBUG //Console.WriteLine("Condition Number of Extension Operator {0}", OpMatrix.condest()); #endif }
/// <summary> /// Discards old quadrature information /// </summary> /// <param name="value"></param> public void OnNext(LevelSetTracker.LevelSetRegions value) { this.MassMatrixFactory = null; this.cellAgglomeration = null; }