//General information public static void Initialize(ILocalSolver FMSolver, SinglePhaseField Phi, GridData GridDat, CellMask ReinitField) { phi = Phi; fMSolver = FMSolver; phi = Phi; gridDat = GridDat; inUseMask = new BitArray(GridDat.Cells.NoOfCells); reinitField = ReinitField.GetBitMask(); queueIDList = new int[GridDat.Cells.NoOfCells]; }
/// <summary> /// Selects all cells in a cell mask. /// </summary> public SubBlockSelectorBase CellSelector(CellMask CM) { if (CM == null) { m_CellFilter = jCell => true; } else { var BitMask = CM.GetBitMask(); this.m_CellFilter = (int jCell) => BitMask[jCell]; } return(this); }
/// <summary> /// Polynomial extrapolation between cells. /// </summary> /// <param name="ExtrapolateTo">contains all cells for which extrapolated values should be computed</param> /// <param name="ExtrapolateFrom">contains all cells with "known values"</param> /// <returns> /// The number of cells (locally) for which the algorithm was not able to extrapolate a value /// </returns> virtual public int CellExtrapolation(CellMask ExtrapolateTo, CellMask ExtrapolateFrom) { MPICollectiveWatchDog.Watch(); int J = this.GridDat.iLogicalCells.NoOfLocalUpdatedCells; int NoOfNeigh; int[] NeighIdx; int[][] CN = this.GridDat.iLogicalCells.CellNeighbours; // mark all cells in which species 'Id' is known // --------------------------------------------- BitArray ValueIsKnown = ExtrapolateFrom.GetBitMaskWithExternal().CloneAs(); CellMask _ExtrapolateTo = ExtrapolateTo.Except(ExtrapolateFrom); BitArray NeedToKnowValue = _ExtrapolateTo.GetBitMask(); this.Clear(_ExtrapolateTo); // repeat until (for species 'Id' the DOF' of) all cells // that contain (at least a fraction of) species 'Id' are known... // ------------------------------------------------------------------ int NoOfCells_ToExtrapolate = _ExtrapolateTo.NoOfItemsLocally; int NoOfCells_ExtrapolatedInSweep = 1; int sweepcnt = 0; List <double> scaling = new List <double>(); List <int[]> CellPairs = new List <int[]>(); BitArray cells_mod_in_sweep = new BitArray(J); while (true) { // MPI-parallel evaluation of termination criterion // ------------------------------------------------ int bool_LocalRun = ((NoOfCells_ToExtrapolate > 0) && (NoOfCells_ExtrapolatedInSweep > 0)) ? 1 : 0; int bool_GlobalRun = 0; unsafe { csMPI.Raw.Allreduce((IntPtr)(&bool_LocalRun), (IntPtr)(&bool_GlobalRun), 1, csMPI.Raw._DATATYPE.INT, csMPI.Raw._OP.MAX, csMPI.Raw._COMM.WORLD); } if (bool_GlobalRun <= 0) { // finished on all MPI processors break; } // MPI-update before local sweep: necessary for consistent result of alg. this.MPIExchange(); if (sweepcnt > 0) { ValueIsKnown.MPIExchange(this.GridDat); } // local work // ---------- if (bool_LocalRun > 0) { sweepcnt++; NoOfCells_ExtrapolatedInSweep = 0; scaling.Clear(); CellPairs.Clear(); cells_mod_in_sweep.SetAll(false); for (int j = 0; j < J; j++) { // determine whether there is something to do for cell 'j' or not ... bool needToKnowSpecies = NeedToKnowValue[j]; bool _mustbeExtrapolated = needToKnowSpecies && !ValueIsKnown[j]; if (_mustbeExtrapolated) { // continuation for this cell is needed // ++++++++++++++++++++++++++++++++++++ // try to find a neighbour NeighIdx = CN[j].CloneAs(); NoOfNeigh = NeighIdx.Length; int FoundNeighs = 0; for (int nn = 0; nn < NoOfNeigh; nn++) { if (ValueIsKnown[NeighIdx[nn]]) { // bingo FoundNeighs++; } else { NeighIdx[nn] = -1; // not usable } } if (FoundNeighs <= 0) { // hope for better luck in next sweep continue; } //Array.Clear(u2, 0, N); for (int nn = 0; nn < NoOfNeigh; nn++) { if (NeighIdx[nn] < 0) { continue; } int _2 = j; // cell to extrapolate TO int _1 = NeighIdx[nn]; // cell to extrapolate FROM CellPairs.Add(new int[] { _1, _2 }); double ooFoundNeighs = 1.0 / (double)FoundNeighs; scaling.Add(ooFoundNeighs); } cells_mod_in_sweep[j] = true; NoOfCells_ExtrapolatedInSweep++; } } int E = CellPairs.Count; int[,] _CellPairs = new int[E, 2]; for (int e = 0; e < E; e++) { _CellPairs.SetRow(e, CellPairs[e]); } double[] preScale = new double[scaling.Count]; preScale.SetAll(1.0); this.CellExtrapolation(_CellPairs, scaling, preScale); for (int j = 0; j < J; j++) { if (cells_mod_in_sweep[j] == true) { ValueIsKnown[j] = true; } } NoOfCells_ToExtrapolate -= NoOfCells_ExtrapolatedInSweep; } } // return // ------ return(NoOfCells_ToExtrapolate); }
/// <summary> /// Extension velocity on un-cut cells. /// </summary> /// <param name="Phi">Input; a signed-distance field.</param> /// <param name="Domain">Cells in which the extension velocity should be computed.</param> /// <param name="cut">Cells in which a value for the extension property is given, must be /// disjoint from and share a boundary with <paramref name="Domain"/>. /// </param> /// <param name="ExtProperty"> /// Input/Output: on cells in <paramref name="cut"/>, valid values for the extension property, /// i.e. boundary values for the extension problem. /// On exit, the result of the marching algorithm is stored in the <paramref name="Domain"/>-cells. /// Multiple extension properties can be constructed at once. /// </param> /// <param name="ExtPropertyMin"> /// Input/Output: Helper array to check the minimum/maximum principle of the extension velocity problem /// - 1st index: extension property index /// - 2nd index: cell index /// On entry, the minimum values for cells in <paramref name="cut"/> must contain valid entries. /// </param> /// <param name="ExtPropertyMax"> /// Analogous to <paramref name="ExtPropertyMin"/>. /// </param> /// <param name="GradPhi"> /// Helper variable to compute the gradient values of <paramref name="Phi"/>. /// </param> public void ConstructExtension(SinglePhaseField Phi, CellMask Domain, CellMask cut, ConventionalDGField[] ExtProperty, double[][] ExtPropertyMin, double[][] ExtPropertyMax, VectorField <SinglePhaseField> GradPhi, int TimestepNo, bool plotMarchingSteps = false) // { using (new FuncTrace()) { Tracer.InstrumentationSwitch = false; // lots of tracing on calls acting on singe cells causes massive overhead (up to 5x slower). Stpw_total.Start(); // check args and init // =================== //ExtVelSolver extVelSlv = null; ExtVelSolver_Geometric extVelSlv = null; if (ExtProperty != null) { if (ExtProperty.Length != ExtPropertyMin.Length) { throw new ArgumentException(); } if (ExtProperty.Length != ExtPropertyMax.Length) { throw new ArgumentException(); } //extVelSlv = new ExtVelSolver(ExtProperty[0].Basis); extVelSlv = new ExtVelSolver_Geometric(ExtProperty[0].Basis); } BitArray Accepted_Mutuable = cut.GetBitMask().CloneAs(); int J = this.GridDat.Cells.NoOfCells; int D = this.GridDat.SpatialDimension; int N = this.LevelSetBasis.Length; int[] DomainCellIndices = Domain.ItemEnum.ToArray(); double[] PhiAvg = new double[DomainCellIndices.Length]; { int L = DomainCellIndices.Length; for (int jSub = 0; jSub < L; jSub++) { int jCell = DomainCellIndices[jSub]; PhiAvg[jSub] = Phi.GetMeanValue(jCell); } Array.Sort(PhiAvg, DomainCellIndices); } if (this.GridDat.MpiSize > 1) { throw new NotSupportedException("Currently not MPI parallel."); } int[] PosDomain, NegDomain; { int median = 0; for (; median < DomainCellIndices.Length; median++) { if (PhiAvg[median] >= 0) { break; } } NegDomain = new int[median]; for (int i = 0; i < median; i++) { NegDomain[i] = DomainCellIndices[median - i - 1]; } PosDomain = new int[DomainCellIndices.Length - median]; Array.Copy(DomainCellIndices, median, PosDomain, 0, PosDomain.Length); Debug.Assert(PosDomain.Length + NegDomain.Length == DomainCellIndices.Length); } if (plotMarchingSteps) { this.plotter.setup(new DGField[] { Phi, ExtProperty[0], ExtProperty[1] }, TimestepNo); this.plotter.plotstep(Accepted_Mutuable); } // perform marching... // =================== // marching loop.. for (int iMinusPlus = -1; iMinusPlus <= 1; iMinusPlus += 2) { double _sign = iMinusPlus; int[] _Domain; switch (iMinusPlus) { case -1: _Domain = NegDomain; break; case +1: _Domain = PosDomain; break; default: throw new Exception(); } for (int iSub = 0; iSub < _Domain.Length; iSub++) { CellMask Accepted = new CellMask(this.GridDat, Accepted_Mutuable); int jCellAccpt = _Domain[iSub]; //this.Stpw_gradientEval.Start(); //gradModule.GradientUpdate(jCellAccpt, Acceped_Mutuable, Phi, GradPhi); //this.Stpw_gradientEval.Stop(); // solve for the extension properties // ---------------------------------- if (ExtProperty != null) { int[] Neighb, dummy33; GridDat.GetCellNeighbours(jCellAccpt, GetCellNeighbours_Mode.ViaEdges, out Neighb, out dummy33); // solve for each component seperately for (int iComp = 0; iComp < ExtProperty.Length; iComp++) { ExtPropertyMax[iComp][jCellAccpt] = -double.MaxValue; ExtPropertyMin[iComp][jCellAccpt] = double.MaxValue; foreach (int jNeig in Neighb) { if (Accepted_Mutuable[jNeig]) { ExtPropertyMax[iComp][jCellAccpt] = Math.Max(ExtPropertyMax[iComp][jCellAccpt], ExtPropertyMax[iComp][jNeig]); ExtPropertyMin[iComp][jCellAccpt] = Math.Min(ExtPropertyMin[iComp][jCellAccpt], ExtPropertyMin[iComp][jNeig]); } } this.Stpw_extVelSolver.Start(); //extVelSlv.ExtVelSolve_Far(Phi, GradPhi, ExtProperty[iComp], ref ExtPropertyMin[iComp][jCellAccpt], ref ExtPropertyMax[iComp][jCellAccpt], jCellAccpt, Accepted, _sign); extVelSlv.ExtVelSolve_Geometric(Phi, ExtProperty[iComp], Accepted_Mutuable, jCellAccpt, _sign); this.Stpw_extVelSolver.Start(); } } Accepted_Mutuable[jCellAccpt] = true; if (plotMarchingSteps) { this.plotter.plotstep(Accepted_Mutuable); } } } Tracer.InstrumentationSwitch = true; Stpw_total.Stop(); } }
/// <summary> /// Reinit on un-cut cells. /// </summary> /// <param name="Phi">The level set</param> /// <param name="ReInitSpecies">Cell mask wich is to be reinitialized</param> /// <param name="sign">Sign of the level set for this <paramref name="ReInitSpecies"/></param> /// <param name="_Accepted">CellMask which is taken as boundray values</param> /// <param name="GradPhi">LEvel Set gradient</param> /// <param name="callBack">A delegate, which might be called after the execution of the reinitialization</param> public void Reinitialize(SinglePhaseField Phi, CellMask ReInitSpecies, double sign, CellMask _Accepted, //ConventionalDGField[] ExtProperty, double[][] ExtPropertyMin, double[][] ExtPropertyMax, VectorField <SinglePhaseField> GradPhi, Action <int> callBack) // { using (new FuncTrace()) { Tracer.InstrumentationSwitch = false; // lots of tracing on calls acting on singe cells causes massive overhead (up to 5x slower). Stpw_total.Start(); SinglePhaseField DiffusionCoeff = new SinglePhaseField(new Basis(this.GridDat, 1), "DiffusionCoeff"); // check args and init // =================== /* * ExtVelSolver extVelSlv = null; * if(ExtProperty != null) { * if(ExtProperty.Length != ExtPropertyMin.Length) * throw new ArgumentException(); * if(ExtProperty.Length != ExtPropertyMax.Length) * throw new ArgumentException(); * * extVelSlv = new ExtVelSolver(ExtProperty[0].Basis); * } */ BitArray Acceped_Mutuable = _Accepted.GetBitMask().CloneAs(); BitArray Trial_Mutuable = ((_Accepted.AllNeighbourCells().Intersect(ReInitSpecies)).Except(_Accepted)).GetBitMask().CloneAs(); BitArray Recalc_Mutuable = Trial_Mutuable.CloneAs(); BitArray PosSpecies_Bitmask = ReInitSpecies.GetBitMask(); int J = this.GridDat.Cells.NoOfCells; int D = this.GridDat.SpatialDimension; int N = this.LevelSetBasis.Length; double _sign = sign >= 0 ? 1.0 : -1.0; double[] PhiAvg = m_PhiAvg; if (PhiAvg == null) { throw new ApplicationException(); } foreach (int jCell in _Accepted.ItemEnum) { PhiAvg[jCell] = Phi.GetMeanValue(jCell); } int NoOfNew; { var Neu = ReInitSpecies.Except(_Accepted); NoOfNew = Neu.NoOfItemsLocally; Phi.Clear(Neu); Phi.AccConstant(_sign, Neu); foreach (int jCell in Neu.ItemEnum) { PhiAvg[jCell] = 1.0e10; } } if (this.GridDat.MpiSize > 1) { throw new NotSupportedException("Currently not MPI parallel."); } for (int d = 0; d < this.GridDat.SpatialDimension; d++) { if (!GradPhi[d].Basis.Equals(Phi.Basis)) { throw new ArgumentException("Level-set and level-set gradient field should have the same DG basis."); // ein grad niedriger wrürde auch genügen... } } // perform marching... // =================== // update gradient for cut-cells GradPhi.Clear(_Accepted); GradPhi.Gradient(1.0, Phi, _Accepted); // marching loop../ int cnt = 0; while (true) { cnt++; CellMask Recalc = new CellMask(this.GridDat, Recalc_Mutuable); CellMask Accepted = new CellMask(this.GridDat, Acceped_Mutuable); CellMask Trial = new CellMask(this.GridDat, Trial_Mutuable); int NoOfTrial = Trial.NoOfItemsLocally; int NoOfAccpt = Accepted.NoOfItemsLocally; int NoOfRcalc = Recalc.NoOfItemsLocally; if (Trial.NoOfItemsLocally <= 0) { //Ploti(Recalc, Accepted, Trial, Phi, Phi_gradient, optEikonalOut, cnt); break; } // Local solver for all 'Recalc'-cells // -------------------------------------- if (Recalc.NoOfItemsLocally > 0) { this.LocalSolve(Accepted, Recalc, Phi, GradPhi, _sign, DiffusionCoeff); } // find the next cell to accept // ---------------------------- // get mean value in all cells foreach (int jCell in Recalc.ItemEnum) { PhiAvg[jCell] = Phi.GetMeanValue(jCell); Recalc_Mutuable[jCell] = false; } //Ploti(Recalc, Accepted, Trial, Phi, Phi_gradient, optEikonalOut, cnt); // find trial-cell with minimum average value // this should be done with heap-sort (see fast-marching algorithm) int jCellAccpt = int.MaxValue; double TrialMin = double.MaxValue; foreach (int jCell in Trial.ItemEnum) { if (PhiAvg[jCell] * _sign < TrialMin) { TrialMin = PhiAvg[jCell] * _sign; jCellAccpt = jCell; } } if (callBack != null) { callBack(cnt); } /* * // update the gradient * // ------------------- * * this.Stpw_gradientEval.Start(); * gradModule.GradientUpdate(jCellAccpt, Acceped_Mutuable, Phi, GradPhi); * this.Stpw_gradientEval.Stop(); * * /* * // solve for the extension properties * // ---------------------------------- * * if(ExtProperty != null) { * int[] Neight, dummy33; * GridDat.Cells.GetCellNeighbours(jCellAccpt, GridData.CellData.GetCellNeighbours_Mode.ViaEdges, out Neight, out dummy33); * * for(int iComp = 0; iComp < ExtProperty.Length; iComp++) { * * ExtPropertyMax[iComp][jCellAccpt] = -double.MaxValue; * ExtPropertyMin[iComp][jCellAccpt] = double.MaxValue; * * foreach(int jNeig in Neight) { * if(Acceped_Mutuable[jNeig]) { * ExtPropertyMax[iComp][jCellAccpt] = Math.Max(ExtPropertyMax[iComp][jCellAccpt], ExtPropertyMax[iComp][jNeig]); * ExtPropertyMin[iComp][jCellAccpt] = Math.Min(ExtPropertyMin[iComp][jCellAccpt], ExtPropertyMin[iComp][jNeig]); * } * } * * this.Stpw_extVelSolver.Start(); * extVelSlv.ExtVelSolve_Far(Phi, GradPhi, ExtProperty[iComp], ref ExtPropertyMin[iComp][jCellAccpt], ref ExtPropertyMax[iComp][jCellAccpt], jCellAccpt, Accepted, _sign); * this.Stpw_extVelSolver.Stop(); * } * } * /* * { * int[] Neight, dummy33; * GridDat.Cells.GetCellNeighbours(jCellAccpt, GridData.CellData.GetCellNeighbours_Mode.ViaEdges, out Neight, out dummy33); * foreach(int jNeig in Neight) { * if(Acceped_Mutuable[jNeig]) { * plotDependencyArrow(cnt, jCellAccpt, jNeig); * } * } * } */ // the mimium is moved to accepted // ------------------------------- Acceped_Mutuable[jCellAccpt] = true; Trial_Mutuable[jCellAccpt] = false; Recalc_Mutuable[jCellAccpt] = false; NoOfNew--; // recalc on all neighbours // ------------------------ int[] Neighs, dummy; this.GridDat.GetCellNeighbours(jCellAccpt, GetCellNeighbours_Mode.ViaEdges, out Neighs, out dummy); foreach (int jNeig in Neighs) { if (!Acceped_Mutuable[jNeig] && PosSpecies_Bitmask[jNeig]) { Trial_Mutuable[jNeig] = true; Recalc_Mutuable[jNeig] = true; } } } if (NoOfNew > 0) { throw new ArithmeticException("Unable to perform reinitialization for all requested cells - maybe they are not reachable from the initialy 'accepted' domain?"); } //PlottAlot("dependencies.csv"); Tracer.InstrumentationSwitch = true; Stpw_total.Stop(); } }
/// <summary> /// produces an edge quadrature rule /// </summary> /// <param name="mask">an edge mask</param> /// <param name="order">desired order</param> /// <returns></returns> public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { // init & checks // ============= if (!(mask is EdgeMask)) { throw new ArgumentException("Expecting an edge mask."); } #if DEBUG var maskBitMask = mask.GetBitMask(); #endif var Edg2Cel = this.grd.iGeomEdges.CellIndices; var Edg2Fac = this.grd.iGeomEdges.FaceIndices; int J = this.grd.Cells.NoOfLocalUpdatedCells; QuadRule DefaultRule = this.RefElement.GetQuadratureRule(order);; int myIKrfeEdge = this.grd.Edges.EdgeRefElements.IndexOf(this.RefElement, (a, b) => object.ReferenceEquals(a, b)); if (myIKrfeEdge < 0) { throw new ApplicationException("fatal error"); } int[] EdgeIndices = mask.ItemEnum.ToArray(); int NoEdg = EdgeIndices.Length; // return value ChunkRulePair <QuadRule>[] Ret = new ChunkRulePair <QuadRule> [NoEdg]; // find cells // ========== BitArray CellBitMask = new BitArray(J); int[] Cells = new int[NoEdg]; // mapping: Edge Index --> Cell Index (both geometrical) int[] Faces = new int[NoEdg]; // mapping: Edge Index --> Face BitArray MaxDomainMask = m_maxDomain.GetBitMask(); { for (int i = 0; i < NoEdg; i++) { int iEdge = EdgeIndices[i]; if (this.grd.Edges.GetRefElementIndex(iEdge) != myIKrfeEdge) { throw new ArgumentException("illegal edge mask"); } if (!(grd.Edges.IsEdgeConformalWithCell1(iEdge) || grd.Edges.IsEdgeConformalWithCell2(iEdge))) { throw new NotSupportedException("For an edge that is not conformal with at least one cell, no edge rule can be created from a cell boundary rule."); } int jCell0 = Edg2Cel[iEdge, 0]; int jCell1 = Edg2Cel[iEdge, 1]; bool conf0 = grd.Edges.IsEdgeConformalWithCell1(iEdge); bool conf1 = grd.Edges.IsEdgeConformalWithCell2(iEdge); // this gives no errors for surface elements in 3D bool Allow0 = MaxDomainMask[jCell0]; bool Allow1 = (jCell1 >= 0 && jCell1 < J) ? MaxDomainMask[jCell1] : false; // //this is required for MPI parallel calculations //bool Allow0 = true;// AllowedCells[jCell0]; //bool Allow1 = (jCell1 >= 0 && jCell1 < J);// ? AllowedCells[jCell1] : false; if (!Allow0 && !Allow1) { // fallback onto default rule, if allowed //if (this.m_DefaultRuleFallbackAllowed) { // Cells[i] = -1; // by a negative index, we mark that we take the default rule // Faces[i] = -1; // Ret[i] = new ChunkRulePair<QuadRule>(Chunk.GetSingleElementChunk(EdgeIndices[i]), DefaultRule); //} else { throw new ArgumentException("unable to find a cell from which the edge rule can be taken."); //} } else { Debug.Assert(Allow0 || Allow1); if (conf0 && Allow0) { // cell 0 is allowed and conformal: // take this, it won't get better CellBitMask[jCell0] = true; Faces[i] = Edg2Fac[iEdge, 0]; Cells[i] = jCell0; } else if (conf1 && Allow1) { // cell 1 is allowed and conformal: // take this, it won't get better CellBitMask[jCell1] = true; Faces[i] = Edg2Fac[iEdge, 1]; Cells[i] = jCell1; } else if (Allow0) { // cell 0 is allowed, but NOT conformal CellBitMask[jCell0] = true; Faces[i] = -Edg2Fac[iEdge, 0]; // by a negative index, we mark a non-conformal edge Cells[i] = jCell0; } else if (Allow1) { // cell 1 is allowed, but NOT conformal CellBitMask[jCell1] = true; Faces[i] = -Edg2Fac[iEdge, 1]; // by a negative index, we mark a non-conformal edge Cells[i] = jCell1; } } } } // get cell boundary rule // ====================== var CellMask = new CellMask(this.grd, CellBitMask); IChunkRulePair <CellBoundaryQuadRule>[] cellBndRule = this.m_cellBndQF.GetQuadRuleSet(CellMask, order).ToArray(); int[] jCell2PairIdx = new int[J]; for (int i = 0; i < cellBndRule.Length; i++) { var chk = cellBndRule[i].Chunk; for (int jCell = chk.JE - 1; jCell >= chk.i0; jCell--) { jCell2PairIdx[jCell] = i + 555; } } int[] iChunk = new int[NoEdg]; // which chunk for which edge? for (int i = 0; i < NoEdg; i++) { if (Cells[i] >= 0) { iChunk[i] = jCell2PairIdx[Cells[i]] - 555; } else { iChunk[i] = int.MinValue; } } // build rule // ========== { for (int i = 0; i < NoEdg; i++) // loop over edges //if (MaxDomainMask[Cells[i]] == false) // Debugger.Break(); //if (Cells[i] >= 0) { { var CellBndR = cellBndRule[iChunk[i]].Rule; QuadRule qrEdge = null; if (Faces[i] >= 0) { qrEdge = this.CombineQr(null, CellBndR, Faces[i]); } else { throw new NotSupportedException("currently no support for non-conformal edges."); } qrEdge.Nodes.LockForever(); qrEdge.Weights.LockForever(); Ret[i] = new ChunkRulePair <QuadRule>(Chunk.GetSingleElementChunk(EdgeIndices[i]), qrEdge); //} else { // Debug.Assert(Ret[i] != null); //} } } // return // ====== #if DEBUG for (int i = 0; i < Ret.Length; i++) { Chunk c = Ret[i].Chunk; for (int e = c.i0; e < c.JE; e++) { Debug.Assert(maskBitMask[e] == true); } } #endif return(Ret); /* * * var EdgesThatConcernMe = grd.Edges.Edges4RefElement[m_cellBndQF.RefElement.FaceSimplex]; * EdgeMask edgMask = (mask as EdgeMask).Intersect(EdgesThatConcernMe); * * var ret = new Dictionary<Chunk, QuadRule>(mask.NoOfItemsLocally); #if DEBUG * var EdgesOfInterest = edgMask.GetBitMask(); * var EdgeTouched = (BitArray)EdgesOfInterest.Clone(); * * edgMask.ToTxtFile("Edges-" + grd.MyRank + ".csv", false); #endif * * * WeightInbalance = 0.0; * * // find all cells that are 'touched' by the edge mask * // -------------------------------------------------- * int J = grd.Cells.NoOfLocalUpdatedCells; * BitArray TouchedCells = new BitArray(J, false); * * var Edg2Cell = grd.Edges.CellIndices; * * int chunkCnt = 0; * foreach (var chnk in mask) { * int EE = chnk.JE; * for (int e = chnk.i0; e < EE; e++) { * if (!(grd.Edges.IsEdgeConformalwithCell1(e) || grd.Edges.IsEdgeConformalwithCell2(e))) { * throw new NotSupportedException("For an edge that is not conformal with at least one cell, no edge rule can be created from a cell boundary rule."); * } * * int j1 = Edg2Cell[e, 0], j2 = Edg2Cell[e, 1]; * TouchedCells[j1] = true; * if (j2 >= 0 && j2 < J) * TouchedCells[j2] = true; * * * Chunk singleEdgeChunk; * singleEdgeChunk.i0 = e; * singleEdgeChunk.Len = 1; * * ret.Add(singleEdgeChunk, null); * } * chunkCnt++; * } * * CellMask celMask = new CellMask(grd, TouchedCells); * celMask.ToTxtFile("CellsU-" + grd.MyRank + ".csv", false); * celMask = celMask.Intersect(m_maxDomain); * celMask.ToTxtFile("Cells-" + grd.MyRank + ".csv", false); * * // create cell boundary rule! * IEnumerable<IChunkRulePair<CellBoundaryQuadRule>> cellBndRule = m_cellBndQF.GetQuadRuleSet(celMask, order); * * //// do MPI communication (get rules for external cells) * //{ * // int size, rank; * // csMPI.Raw.Comm_Rank(csMPI.Raw._COMM.WORLD, out rank); * // csMPI.Raw.Comm_Size(csMPI.Raw._COMM.WORLD, out size); * * // if (size > 1) * // throw new NotSupportedException("currently no MPI support"); * //} * * // assign the cell boundary rule to edges * // -------------------------------------- * var volSplx = m_cellBndQF.RefElement; * int NoOfFaces = volSplx.NoOfFaces; * var Cells2Edge = grd.Cells.Cells2Edges; * var FaceIndices = grd.Edges.FaceIndices; * * int cnt = -1; * foreach (var kv in cellBndRule) { // loop over cell chunks (in the cell boundary rule)... * Chunk chk = kv.Chunk; * CellBoundaryQuadRule qr = kv.Rule; * cnt++; * * int JE = chk.JE; * for (int j = chk.i0; j < JE; j++) { // loop over all cells in chunk... * Debug.Assert(qr.NumbersOfNodesPerFace.Length == NoOfFaces); * var Cells2Edge_j = Cells2Edge[j]; * * for (int _e = Cells2Edge_j.Length - 1; _e >= 0; _e--) { // loop over all edges of cell... * * //if (qr.NumbersOfNodesPerEdge[e] <= 0) * // // no contribution from this edge * // continue; * * bool isInCell = Cells2Edge_j[_e] >= 0; * int iEdge = Math.Abs(Cells2Edge_j[_e]) - 1; * int iFace = FaceIndices[iEdge, isInCell ? 0 : 1]; * * if (isInCell) { * if (!grd.Edges.IsEdgeConformalwithCell1(iEdge)) * // we already tested that at least one cell is conformal with the edge, * // so it is safe to drop this face * continue; * } else { * if (!grd.Edges.IsEdgeConformalwithCell2(iEdge)) * // we already tested that at least one cell is conformal with the edge, * // so it is safe to drop this face * continue; * } * * * Chunk singleEdgeChunk = Chunk.GetSingleElementChunk(iEdge); * * QuadRule qrEdge; * if (ret.TryGetValue(singleEdgeChunk, out qrEdge)) { * // we are interested in this edge! * #if DEBUG * Debug.Assert(EdgesOfInterest[iEdge] == true); * EdgeTouched[iEdge] = false; * * var vtx = this.RefElement.Vertices; * MultidimensionalArray _vtx = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1)); * _vtx.Set(vtx); * * var RefCoord = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1) + 1); * var PhysCoord = MultidimensionalArray.Create(1, vtx.GetLength(0), vtx.GetLength(1) + 1); * * volSplx.TransformFaceCoordinates(iFace, _vtx, RefCoord); * grd.TransformLocal2Global(RefCoord, PhysCoord, j, 1, 0); * #endif * * qrEdge = CombineQr(qrEdge, qr, iFace, j); * * Debug.Assert(qrEdge != null); * ret[singleEdgeChunk] = qrEdge; * } else { * // nop: the edge is not in the 'edgMask'! * continue; * } * } * * } * } * #if DEBUG * (new EdgeMask(this.grd, EdgeTouched)).ToTxtFile("failedEdges-" + grd.MyRank + ".csv", false); * * for (int i = EdgeTouched.Length - 1; i >= 0; i--) * Debug.Assert(EdgeTouched[i] == false); #endif * * return ret.Select(p => new ChunkRulePair<QuadRule>(p.Key, p.Value)); */ }
/// <summary> /// Solution of the extension problem on a single cell in the far-region /// </summary> /// <param name="Phi">Input;</param> /// <param name="GradPhi">Input;</param> /// <param name="ExtProperty"></param> /// <param name="ExtPropertyMin">Input/Output: lower threshold.</param> /// <param name="ExtPropertyMax">Input/Output: upper threshold.</param> /// <param name="jCell"></param> /// <param name="Accepted"></param> /// <param name="signMod"></param> public void ExtVelSolve_Far(SinglePhaseField Phi, VectorField <SinglePhaseField> GradPhi, ConventionalDGField ExtProperty, ref double ExtPropertyMin, ref double ExtPropertyMax, int jCell, CellMask Accepted, double signMod) { GridData gDat = (GridData)(Phi.GridDat); Debug.Assert(signMod.Abs() == 1.0); Debug.Assert(ExtPropertyMin <= ExtPropertyMax); // define cell- and edge-mask for re-compute // ========================================= CellMask cM = new CellMask(gDat, Chunk.GetSingleElementChunk(jCell)); int[] Edges = gDat.iLogicalCells.Cells2Edges[jCell].CloneAs(); for (int i = 0; i < Edges.Length; i++) { Edges[i] = Math.Abs(Edges[i]) - 1; } EdgeMask eM = new EdgeMask(gDat, FromIndEnum(Edges, gDat.iLogicalEdges.Count)); // won't scale. // solve the linear extension problem for 'jCell', eventually increase // diffusion until we are satisfied with the solution // =================================================================== bool MaximumPrincipleFulfilled = false; double DiffusionCoeff = 0; // initially: try without diffusion double mini = double.NaN, maxi = double.NaN; int count = 0; while (MaximumPrincipleFulfilled == false) // as long as we are satisfied with the solution { count++; // compute operator in 'jCell' // --------------------------- int N = ExtProperty.Basis.GetLength(jCell); int i0G = ExtProperty.Mapping.GlobalUniqueCoordinateIndex(0, jCell, 0); int i0L = ExtProperty.Mapping.GlobalUniqueCoordinateIndex(0, jCell, 0); for (int n = 0; n < N; n++) { this.m_ExtvelMatrix.ClearRow(i0G + n); this.m_ExtvelAffine[i0L + n] = 0; } double penaltyBase = ((double)(ExtProperty.Basis.Degree + 1)).Pow2(); var Flux = new ExtensionVelocityForm(Accepted.GetBitMask(), signMod, penaltyBase, gDat.Cells.h_min, jCell, DiffusionCoeff); var op = (Flux).Operator(DegreeOfNonlinearity: 2); // increase diffusion coefficient for next cycle if (DiffusionCoeff == 0) { DiffusionCoeff = 1.0e-3; // should this be minus or plus? } else { DiffusionCoeff *= 10; } op.ComputeMatrixEx(ExtProperty.Mapping, ArrayTools.Cat <DGField>(new DGField[] { ExtProperty, Phi }, GradPhi), ExtProperty.Mapping, this.m_ExtvelMatrix, this.m_ExtvelAffine, OnlyAffine: false, volQuadScheme: (new CellQuadratureScheme(true, cM)), edgeQuadScheme: (new EdgeQuadratureScheme(true, eM)), ParameterMPIExchange: false); // extract operator matrix and RHS // ------------------------------- // the matrix must only have entries in the block-diagonal! MultidimensionalArray Mtx = MultidimensionalArray.Create(N, N); //MultidimensionalArray rhs = MultidimensionalArray.Create(N); double[] rhs = new double[N]; for (int n = 0; n < N; n++) { #if DEBUG int Lr; int[] row_cols = null; double[] row_vals = null; Lr = this.m_ExtvelMatrix.GetRow(i0G + n, ref row_cols, ref row_vals); for (int lr = 0; lr < Lr; lr++) { int ColIndex = row_cols[lr]; double Value = row_vals[lr]; Debug.Assert((ColIndex >= i0G && ColIndex < i0G + N) || (Value == 0.0), "Matrix is expected to be block-diagonal."); } #endif for (int m = 0; m < N; m++) { Mtx[n, m] = this.m_ExtvelMatrix[i0G + n, i0G + m]; } rhs[n] = -this.m_ExtvelAffine[i0L + n]; } // Solve the system, i.e. the local extension-velocity equation // ------------------------------------------------------------ double[] ep = new double[N]; Mtx.Solve(ep, rhs); for (int n = 0; n < N; n++) { ExtProperty.Coordinates[jCell, n] = ep[n]; } // detect violation of maximum principle // ------------------------------------- ExtProperty.GetExtremalValuesInCell(out mini, out maxi, jCell); // define relaxed bounds... double compExtPropertyMin = ExtPropertyMin - (1.0e-8 + ExtPropertyMax - ExtPropertyMin) * 0.2; double compExtPropertyMax = ExtPropertyMax + (1.0e-8 + ExtPropertyMax - ExtPropertyMin) * 0.2; // test if extension velocity solution is within bounds MaximumPrincipleFulfilled = (mini >= compExtPropertyMin) && (maxi <= compExtPropertyMax); if (count > 5) { break; } } if (count > 4) { Console.WriteLine(" ExtVel, cell #{0}, Diff coeff {1}, extremal p. holds? {2} (min/max soll = {3:e4}/{4:e4}, ist = {5:e4}/{6:e4})", jCell, DiffusionCoeff, MaximumPrincipleFulfilled, ExtPropertyMin, ExtPropertyMax, mini, maxi); } // record maxima and minima // ======================== ExtPropertyMax = Math.Max(ExtPropertyMax, maxi); ExtPropertyMin = Math.Min(ExtPropertyMin, mini); }