/// <summary> /// To achieve a conservative time stepping scheme, we have to correct the DG coordinates of /// large interface cells /// </summary> /// <param name="coarseID">Cluster ID of the large cells</param> /// <param name="fineID">Cluster ID of the small cells</param> /// <param name="historyDGC_Q">History of the DG coordinates</param> protected void CorrectFluxes(int coarseID, int fineID, Queue <double[]>[] historyDGC_Q) { // Gather edgeFlux data double[] edgeBndFluxCoarse = ABevolver[coarseID].CompleteBoundaryFluxes; double[] edgeBndFluxFine = ABevolver[fineID].CompleteBoundaryFluxes; int[] LocalCellIdx2SubgridIdx = CurrentClustering.Clusters[coarseID].LocalCellIndex2SubgridIndex; CellMask CellMaskCoarse = CurrentClustering.Clusters[coarseID].VolumeMask; //Only the edges of coarseID and fineID are needed EdgeMask unionEdgeMask = CurrentClustering.Clusters[coarseID].BoundaryEdgesMask.Intersect(CurrentClustering.Clusters[fineID].BoundaryEdgesMask); int cellCoarse; int cellFine; MultidimensionalArray basisScale = gridData.ChefBasis.Scaling; int noOfFields = Mapping.Fields.Count; //loop over all BoundaryEdges of the coarse sgrd { foreach (int edge in unionEdgeMask.ItemEnum) { int cell1 = gridData.iLogicalEdges.CellIndices[edge, 0]; int cell2 = gridData.iLogicalEdges.CellIndices[edge, 1]; if (LocalCellIdx2SubgridIdx[cell1] >= 0) // <- check for MPI save operation //cell1 is coarse { cellCoarse = cell1; cellFine = cell2; } else { // cell2 is coarse cellCoarse = cell2; cellFine = cell1; } // Just do correction on real coarseCells, no ghost cells if (CellMaskCoarse.Contains(cellCoarse)) { // cell at boundary // f== each field // n== basis polynomial for (int f = 0; f < noOfFields; f++) { int n = 0; //only 0-mode is accumulated, the rest is not needed int indexCoarse = Mapping.LocalUniqueCoordinateIndex(f, cellCoarse, n); int indexEdge = noOfFields * edge + f; double basisScaling = basisScale[cellCoarse] / basisScale[cellFine]; // edgefluxCorrection = Flux from coarse -> fine + Flux from fine -> coarse double edgeDG_Correction = edgeBndFluxCoarse[indexEdge] * basisScaling + edgeBndFluxFine[indexEdge]; // Update Fluxes double fluxScaling = 1.0 / ABevolver[coarseID].ABCoefficients[0]; ABevolver[coarseID].CurrentChangeRate[indexCoarse] += fluxScaling * edgeDG_Correction; ABevolver[coarseID].HistoryBoundaryFluxes.Last()[indexEdge] -= fluxScaling * edgeDG_Correction / basisScaling; //Update local DGCoordinates historyDGC_Q[coarseID].Last()[indexCoarse] -= edgeDG_Correction; //We used this edge, now clear data in completeBndFluxes //otherwise it will be used again in a next intermediate synchronization edgeBndFluxCoarse[indexEdge] = 0.0; edgeBndFluxFine[indexEdge] = 0.0; } } } } }
static internal void ComputeMassMatrixBlocks( IEnumerable <SpeciesId> _SpeciesIds, out Dictionary <SpeciesId, MassMatrixBlockContainer> Result, Basis b, XDGSpaceMetrics homie) { using (var tracer = new FuncTrace()) { if (b is XDGBasis) { throw new ArgumentException(); } var ctx = homie.GridDat; Result = new Dictionary <SpeciesId, MassMatrixBlockContainer>(); var schemeHelper = homie.XQuadSchemeHelper; int Nnx = b.Length; int quadorder = homie.CutCellQuadOrder; // define domains and allocate memory // ================================== foreach (var Species in _SpeciesIds) // loop over species... // interation dom { var _IntegrationDomain = homie.LevelSetRegions.GetSpeciesMask(Species).Intersect(homie.LevelSetRegions.GetCutCellMask()); // domain for mass-matrix blocks (include agglomeration targets) var _BlockDomain = _IntegrationDomain; //.Union(Agg.GetAgglomerator(Species).AggInfo.AllAffectedCells); // alloc mem for blocks var _MassMatrixBlocksSpc = MultidimensionalArray.Create(_BlockDomain.NoOfItemsLocally, Nnx, Nnx); // Subgrid index to cell index int[] _jSub2jCell = _BlockDomain.ItemEnum.ToArray(); // cell to subgrid index //Dictionary<int, int> _jCell2jSub; //if (Agg.GetAgglomerator(Species).AggInfo.AgglomerationPairs.Length > 0) { // _jCell2jSub = new Dictionary<int, int>(); // for (int i = 0; i < _jSub2jCell.Length; i++) { // _jCell2jSub.Add(_jSub2jCell[i], i); // } //} else { // _jCell2jSub = null; //} Result.Add(Species, new MassMatrixBlockContainer() { IntegrationDomain = _IntegrationDomain, MassMatrixBlocks = _MassMatrixBlocksSpc, //jCell2jSub = _jCell2jSub, jSub2jCell = _jSub2jCell }); } // compute blocks // ============== foreach (var Species in _SpeciesIds) { // get quad scheme CellQuadratureScheme scheme = schemeHelper.GetVolumeQuadScheme(Species, IntegrationDomain: Result[Species].IntegrationDomain); // result storage var MassMatrixBlocksSpc = Result[Species].MassMatrixBlocks; tracer.Info("mass matrix quad order: " + quadorder); // compute the products of the basis functions: int BlockCnt = -1; int[] BlockCell = Result[Species].jSub2jCell; CellMask speciesCells = homie.LevelSetRegions.GetSpeciesMask(Species); CellQuadrature.GetQuadrature( new int[] { Nnx, Nnx }, ctx, scheme.Compile(ctx, quadorder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { // Del_Evaluate // ~~~~~~~~~~~~~ var BasisVal = b.CellEval(QR.Nodes, i0, Length); EvalResult.Multiply(1.0, BasisVal, BasisVal, 0.0, "ikmn", "ikm", "ikn"); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { // Del_SaveIntegrationResults // ~~~~~~~~~~~~~~~~~~~~~~~~~~ for (int i = 0; i < Length; i++) { int jCell = i0 + i; BlockCnt++; // insert ID block in agglomeration target cells (if necessary): // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - var Block = MassMatrixBlocksSpc.ExtractSubArrayShallow(BlockCnt, -1, -1); while (BlockCell[BlockCnt] < jCell) { // agglomeration source/target cell that is not cut // mass matrix is identity (full) or zero (void) Block.Clear(); if (speciesCells.Contains(BlockCell[BlockCnt])) { // cell is full for (int nn = 0; nn < Nnx; nn++) { Block[nn, nn] = 1.0; } } BlockCnt++; Block = MassMatrixBlocksSpc.ExtractSubArrayShallow(BlockCnt, -1, -1); } // store computed block // - - - - - - - - - - - Debug.Assert(BlockCell[BlockCnt] == jCell); MassMatrixBlocksSpc.ExtractSubArrayShallow(BlockCnt, -1, -1) .Set(ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1)); #if DEBUG for (int n = 0; n < Nnx; n++) { for (int m = 0; m < Nnx; m++) { Debug.Assert(Block[n, m] == Block[m, n]); } } #endif } }).Execute(); // ------------------------------------ quadrature end. BlockCnt++; while (BlockCnt < MassMatrixBlocksSpc.GetLength(0)) { // agglomeration source/target cell that is not cut // mass matrix is identity (full) or zero (void) var Block = MassMatrixBlocksSpc.ExtractSubArrayShallow(BlockCnt, -1, -1); Block.Clear(); if (speciesCells.Contains(BlockCell[BlockCnt])) { // cell is full for (int nn = 0; nn < Nnx; nn++) { Block[nn, nn] = 1.0; } } BlockCnt++; } /* * // test mass matrix for positive definiteness * { * int JSUB = MassMatrixBlocksSpc.GetLength(0); * SubGrid Idom = null; * * int failCount = 0; * var PosDefiniteTest = new FullMatrix(Nnx, Nnx); * * for (int jsub = 0; jsub < JSUB; jsub++) { * PosDefiniteTest.Clear(); * PosDefiniteTest.Acc(MassMatrixBlocksSpc.ExtractSubArrayShallow(jsub, -1, -1), 1.0); * * try { * PosDefiniteTest.Clear(); * PosDefiniteTest.Acc(MassMatrixBlocksSpc.ExtractSubArrayShallow(jsub, -1, -1), 1.0); * PosDefiniteTest.InvertSymmetrical(); * * //PosDefiniteTest.Clear(); * //PosDefiniteTest.AccEye(1.0); * //PosDefiniteTest.Acc(MassMatrixBlocksSpc.ExtractSubArrayShallow(jsub, -1, -1), -1.0); * //PosDefiniteTest.InvertSymmetrical(); * } catch (ArithmeticException ae) { * if (Idom == null) * Idom = new SubGrid(scheme.Domain); * * int jCell = Idom.SubgridIndex2LocalCellIndex[jsub]; * long Gid = Tracker.GridDat.Cells.GetCell(jCell).GlobalID; * * * double volFrac = Tracker.GetSpeciesVolume(jCell, Species)/ctx.Cells.GetCellVolume(jCell); * * var errString = string.Format("Indefinite mass matrix in cell: globalId = {0}, local index = {1}, species {2}; \n cell volume fraction: {3};\n [{4}]", Gid, jCell, Tracker.GetSpeciesName(Species), volFrac, ae.Message); * tracer.Logger.Error(errString); * //Console.WriteLine(errString); * failCount++; * } * } * * if (failCount > 0) { * var errString = string.Format("Indefinite mass matrix in {0} of {1} cut cells", failCount, JSUB); * tracer.Logger.Error(errString); * Console.WriteLine(errString); * } else { * Console.WriteLine("No indefinite mass matrix blocks"); * } * * } * // */ // backup before agglomeration (required if we wanna treat e.g. velocity in DG and pressure in XDG) //MultidimensionalArray[] massMatrixBlocksB4Agglom = new MultidimensionalArray[Result[Species].jSub2jCell.Length]; //Result[Species].MassMatrixBlocks_B4Agglom = massMatrixBlocksB4Agglom; //var _jCell2jSub = Result[Species].jCell2jSub; //int J = ctx.Cells.NoOfLocalUpdatedCells; //foreach (var pair in Agg.GetAgglomerator(Species).AggInfo.AgglomerationPairs) { // foreach (int jCell in new int[] { pair.jCellSource, pair.jCellTarget }) { // create a backup of source and target cell // if (jCell >= J) // continue; // int jSub = _jCell2jSub[jCell]; // if (massMatrixBlocksB4Agglom[jSub] == null) { // massMatrixBlocksB4Agglom[jSub] = MassMatrixBlocksSpc.ExtractSubArrayShallow(jSub, -1, -1).CloneAs(); // } // } //} // agglomeration //Agg.GetAgglomerator(Species).ManipulateMassMatrixBlocks(MassMatrixBlocksSpc, b, Result[Species].jSub2jCell, Result[Species].jCell2jSub); //throw new NotImplementedException("todo"); } } }