/// <summary> /// compiles a cell mask from all cells with a specific color and their direct neighbors /// </summary> /// <param name="gridData"> /// the grid that this mask will be associated with /// </param> /// <param name="ColoredCellsSorted"> /// a list of all cells sorted by color /// </param> /// <param name="CurrentColor"> /// the color which is associated with the Cell Mask /// </param> /// /// <param name="J"> /// the number of locally updated cells /// </param> internal CellMask CellsOneColor(IGridData gridData, List <int[]> ColoredCellsSorted, int CurrentColor, int J, bool FindNeighbours = true) { int[] CellIDCurrentColor = FindCellIDs(ColoredCellsSorted, CurrentColor); BitArray ColoredCells = new BitArray(J); for (int i = 0; i < CellIDCurrentColor.Length; i++) { if (CellIDCurrentColor[i] < J) { ColoredCells[CellIDCurrentColor[i]] = true; } } CellMask ColoredCellMask = new CellMask(gridData, ColoredCells); if (FindNeighbours) { CellMask ColoredCellMaskNeighbour = ColoredCellMask.AllNeighbourCells(); ColoredCellMask = ColoredCellMask.Union(ColoredCellMaskNeighbour); } return(ColoredCellMask); }
/// <summary> /// Computes the new level set field at time <paramref name="Phystime"/> + <paramref name="dt"/>. /// This is a 'driver function' which provides a universal interface to the various level set evolution algorithms. /// It also acts as a callback to the time stepper (see <see cref="m_BDF_Timestepper"/> resp. <see cref="m_RK_Timestepper"/>), /// i.e. it matches the signature of /// <see cref="BoSSS.Solution.XdgTimestepping.DelUpdateLevelset"/>. /// </summary> /// <param name="Phystime"></param> /// <param name="dt"></param> /// <param name="CurrentState"> /// The current solution (velocity and pressure), since the complete solution is provided by the time stepper, /// only the velocity components(supposed to be at the beginning) are used. /// </param> /// <param name="underrelax"> /// </param> public double DelUpdateLevelSet(DGField[] CurrentState, double Phystime, double dt, double underrelax, bool incremental) { using (new FuncTrace()) { //dt *= underrelax; int D = base.Grid.SpatialDimension; int iTimestep = hack_TimestepIndex; DGField[] EvoVelocity = CurrentState.GetSubVector(0, D); // ======================================================== // Backup old level-set, in order to compute the residual // ======================================================== SinglePhaseField LsBkUp = new SinglePhaseField(this.LevSet.Basis); LsBkUp.Acc(1.0, this.LevSet); CellMask oldCC = LsTrk.Regions.GetCutCellMask(); // ==================================================== // set evolution velocity, but only on the CUT-cells // ==================================================== #region Calculate density averaged Velocity for each cell ConventionalDGField[] meanVelocity = GetMeanVelocityFromXDGField(EvoVelocity); #endregion // =================================================================== // backup interface properties (mass conservation, surface changerate) // =================================================================== #region backup interface props double oldSurfVolume = 0.0; double oldSurfLength = 0.0; double SurfChangerate = 0.0; if (this.Control.CheckInterfaceProps) { oldSurfVolume = XNSEUtils.GetSpeciesArea(this.LsTrk, LsTrk.GetSpeciesId("A")); oldSurfLength = XNSEUtils.GetInterfaceLength(this.LsTrk); SurfChangerate = EnergyUtils.GetSurfaceChangerate(this.LsTrk, meanVelocity, this.m_HMForder); } #endregion // ==================================================== // perform level-set evolution // ==================================================== #region level-set evolution // set up for Strang splitting SinglePhaseField DGLevSet_old; if (incremental) { DGLevSet_old = this.DGLevSet.Current.CloneAs(); } else { DGLevSet_old = this.DGLevSet[0].CloneAs(); } // set up for underrelaxation SinglePhaseField DGLevSet_oldIter = this.DGLevSet.Current.CloneAs(); //PlotCurrentState(hack_Phystime, new TimestepNumber(new int[] { hack_TimestepIndex, 0 }), 2); // actual evolution switch (this.Control.Option_LevelSetEvolution) { case LevelSetEvolution.None: throw new ArgumentException("illegal call"); case LevelSetEvolution.FastMarching: { NarrowMarchingBand.Evolve_Mk2( dt, this.LsTrk, DGLevSet_old, this.DGLevSet.Current, this.DGLevSetGradient, meanVelocity, this.ExtensionVelocity.Current.ToArray(), //new DGField[] { LevSetSrc }, this.m_HMForder, iTimestep); //FastMarchReinitSolver = new FastMarchReinit(DGLevSet.Current.Basis); //CellMask Accepted = LsTrk.Regions.GetCutCellMask(); //CellMask ActiveField = LsTrk.Regions.GetNearFieldMask(1); //CellMask NegativeField = LsTrk.Regions.GetSpeciesMask("A"); //FastMarchReinitSolver.FirstOrderReinit(DGLevSet.Current, Accepted, NegativeField, ActiveField); break; } case LevelSetEvolution.Fourier: { Fourier_Timestepper.moveLevelSet(dt, meanVelocity); if (incremental) { Fourier_Timestepper.updateFourierLevSet(); } Fourier_LevSet.ProjectToDGLevelSet(this.DGLevSet.Current, this.LsTrk); break; } case LevelSetEvolution.Prescribed: { this.DGLevSet.Current.Clear(); this.DGLevSet.Current.ProjectField(1.0, this.Control.Phi.Vectorize(Phystime + dt)); break; } case LevelSetEvolution.ScalarConvection: { var LSM = new LevelSetMover(EvoVelocity, this.ExtensionVelocity, this.LsTrk, XVelocityProjection.CutCellVelocityProjectiontype.L2_plain, this.DGLevSet, this.BcMap); int check1 = this.ExtensionVelocity.PushCount; int check2 = this.DGLevSet.PushCount; this.DGLevSet[1].Clear(); this.DGLevSet[1].Acc(1.0, DGLevSet_old); LSM.Advect(dt); if (check1 != this.ExtensionVelocity.PushCount) { throw new ApplicationException(); } if (check2 != this.DGLevSet.PushCount) { throw new ApplicationException(); } break; } case LevelSetEvolution.ExtensionVelocity: { DGLevSetGradient.Clear(); DGLevSetGradient.Gradient(1.0, DGLevSet.Current); ExtVelMover.Advect(dt); // Fast Marching: Specify the Domains first // Perform Fast Marching only on the Far Field if (this.Control.AdaptiveMeshRefinement) { int NoCells = ((GridData)this.GridData).Cells.Count; BitArray Refined = new BitArray(NoCells); for (int j = 0; j < NoCells; j++) { if (((GridData)this.GridData).Cells.GetCell(j).RefinementLevel > 0) { Refined[j] = true; } } CellMask Accepted = new CellMask(this.GridData, Refined); CellMask AcceptedNeigh = Accepted.AllNeighbourCells(); Accepted = Accepted.Union(AcceptedNeigh); CellMask ActiveField = Accepted.Complement(); CellMask NegativeField = LsTrk.Regions.GetSpeciesMask("A"); FastMarchReinitSolver.FirstOrderReinit(DGLevSet.Current, Accepted, NegativeField, ActiveField); } else { CellMask Accepted = LsTrk.Regions.GetNearFieldMask(1); CellMask ActiveField = Accepted.Complement(); CellMask NegativeField = LsTrk.Regions.GetSpeciesMask("A"); FastMarchReinitSolver.FirstOrderReinit(DGLevSet.Current, Accepted, NegativeField, ActiveField); } //SubGrid AcceptedGrid = new SubGrid(Accepted); //ReInitPDE.ReInitialize(Restriction: AcceptedGrid); //CellMask ActiveField = Accepted.Complement(); //CellMask NegativeField = LsTrk.Regions.GetSpeciesMask("A"); //FastMarchReinitSolver.FirstOrderReinit(DGLevSet.Current, Accepted, NegativeField, ActiveField); //ReInitPDE.ReInitialize(); break; } default: throw new ApplicationException(); } // performing underrelaxation if (underrelax < 1.0) { this.DGLevSet.Current.Scale(underrelax); this.DGLevSet.Current.Acc((1.0 - underrelax), DGLevSet_oldIter); } //PlotCurrentState(hack_Phystime, new TimestepNumber(new int[] { hack_TimestepIndex, 1 }), 2); #endregion // ====================== // postprocessing // ======================= if (this.Control.ReInitPeriod > 0 && hack_TimestepIndex % this.Control.ReInitPeriod == 0) { Console.WriteLine("Filtering DG-LevSet"); SinglePhaseField FiltLevSet = new SinglePhaseField(DGLevSet.Current.Basis); FiltLevSet.AccLaidBack(1.0, DGLevSet.Current); Filter(FiltLevSet, 2, oldCC); DGLevSet.Current.Clear(); DGLevSet.Current.Acc(1.0, FiltLevSet); Console.WriteLine("FastMarchReInit performing FirstOrderReInit"); FastMarchReinitSolver = new FastMarchReinit(DGLevSet.Current.Basis); CellMask Accepted = LsTrk.Regions.GetCutCellMask(); CellMask ActiveField = LsTrk.Regions.GetNearFieldMask(1); CellMask NegativeField = LsTrk.Regions.GetSpeciesMask("A"); FastMarchReinitSolver.FirstOrderReinit(DGLevSet.Current, Accepted, NegativeField, ActiveField); } #region ensure continuity // make level set continuous CellMask CC = LsTrk.Regions.GetCutCellMask4LevSet(0); CellMask Near1 = LsTrk.Regions.GetNearMask4LevSet(0, 1); CellMask PosFF = LsTrk.Regions.GetLevelSetWing(0, +1).VolumeMask; ContinuityEnforcer.MakeContinuous(this.DGLevSet.Current, this.LevSet, Near1, PosFF); if (this.Control.Option_LevelSetEvolution == LevelSetEvolution.FastMarching) { CellMask Nearband = Near1.Union(CC); this.DGLevSet.Current.Clear(Nearband); this.DGLevSet.Current.AccLaidBack(1.0, this.LevSet, Nearband); //ContinuityEnforcer.SetFarField(this.DGLevSet.Current, Near1, PosFF); } //PlotCurrentState(hack_Phystime, new TimestepNumber(new int[] { hack_TimestepIndex, 2 }), 2); #endregion for (int d = 0; d < D; d++) { this.XDGvelocity.Velocity[d].UpdateBehaviour = BehaveUnder_LevSetMoovement.AutoExtrapolate; } // =============== // tracker update // =============== this.LsTrk.UpdateTracker(Phystime + dt, incremental: true); // update near field (in case of adaptive mesh refinement) if (this.Control.AdaptiveMeshRefinement && this.Control.Option_LevelSetEvolution == LevelSetEvolution.FastMarching) { Near1 = LsTrk.Regions.GetNearMask4LevSet(0, 1); PosFF = LsTrk.Regions.GetLevelSetWing(0, +1).VolumeMask; ContinuityEnforcer.SetFarField(this.DGLevSet.Current, Near1, PosFF); ContinuityEnforcer.SetFarField(this.LevSet, Near1, PosFF); } // ================================================================== // check interface properties (mass conservation, surface changerate) // ================================================================== if (this.Control.CheckInterfaceProps) { double currentSurfVolume = XNSEUtils.GetSpeciesArea(this.LsTrk, LsTrk.GetSpeciesId("A")); double massChange = ((currentSurfVolume - oldSurfVolume) / oldSurfVolume) * 100; Console.WriteLine("Change of mass = {0}%", massChange); double currentSurfLength = XNSEUtils.GetInterfaceLength(this.LsTrk); double actualSurfChangerate = (currentSurfLength - oldSurfLength) / dt; Console.WriteLine("Interface divergence = {0}", SurfChangerate); Console.WriteLine("actual surface changerate = {0}", actualSurfChangerate); } // ================== // compute residual // ================== var newCC = LsTrk.Regions.GetCutCellMask(); LsBkUp.Acc(-1.0, this.LevSet); double LevSetResidual = LsBkUp.L2Norm(newCC.Union(oldCC)); return(LevSetResidual); } }
/// <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(); } }