public bool TryNewClustering(double dt) { bool reclustered = false; if (ABevolver[0].HistoryChangeRate.Count >= order - 1) { if (adaptive) { if (TimeInfo.TimeStepNumber % reclusteringInterval == 0) { // Fix for update problem of artificial viscosity RaiseOnBeforeComputechangeRate(Time, dt); //#if DEBUG Console.WriteLine("\n-------------------------------------------------------------------------------------------"); Console.WriteLine("### BUILD NEW CLUSTERING FOR TESTING ###"); //#endif // Necessary in order to use the number of sub-grids specified by the user for the reclustering in each time step // Otherwise the value could be changed by the constructor of the parent class (AdamsBashforthLTS.cs) --> CreateSubGrids() Clusterer.Clustering newClustering = clusterer.CreateClustering(numberOfClustersInitial, this.TimeStepConstraints, this.SubGrid); newClustering = clusterer.TuneClustering(newClustering, Time, this.TimeStepConstraints); // Might remove sub-grids when their time step sizes are too similar reclustered = clusterer.CheckForNewClustering(CurrentClustering, newClustering); //#if DEBUG //Console.WriteLine("########################################"); Console.WriteLine("-------------------------------------------------------------------------------------------"); //#endif // After the intitial phase, activate adaptive mode for all ABevolve objects foreach (ABevolve abE in ABevolver) { abE.adaptive = true; } if (reclustered) { Console.WriteLine("### RECLUSTERING ###"); CurrentClustering = newClustering; ShortenHistories(ABevolver); ABevolve[] oldABevolver = ABevolver; CreateNewABevolver(); CopyHistoriesOfABevolver(oldABevolver); } GetBoundaryTopology(); } } } return(reclustered); }
public IBMAdamsBashforthLTS(SpatialOperator standardOperator, SpatialOperator boundaryOperator, CoordinateMapping fieldsMap, CoordinateMapping boundaryParameterMap, ISpeciesMap ibmSpeciesMap, IBMControl control, IList <TimeStepConstraint> timeStepConstraints, int reclusteringInterval, bool fluxCorrection) : base(standardOperator, fieldsMap, boundaryParameterMap, control.ExplicitOrder, control.NumberOfSubGrids, true, timeStepConstraints, reclusteringInterval: reclusteringInterval, fluxCorrection: fluxCorrection, subGrid: ibmSpeciesMap.SubGrid) { this.speciesMap = ibmSpeciesMap as ImmersedSpeciesMap; if (this.speciesMap == null) { throw new ArgumentException( "Only supported for species maps of type 'ImmersedSpeciesMap'", "speciesMap"); } this.standardOperator = standardOperator; this.boundaryOperator = boundaryOperator; this.boundaryParameterMap = boundaryParameterMap; this.fieldsMap = fieldsMap; this.control = control; agglomerationPatternHasChanged = true; cutCells = speciesMap.Tracker.Regions.GetCutCellMask(); cutAndTargetCells = cutCells.Union(speciesMap.Agglomerator.AggInfo.TargetCells); // Normal LTS constructor NumberOfLocalTimeSteps = new List <int>(control.NumberOfSubGrids); clusterer = new Clusterer(this.gridData, this.TimeStepConstraints); CurrentClustering = clusterer.CreateClustering(control.NumberOfSubGrids, speciesMap.SubGrid); CurrentClustering = CalculateNumberOfLocalTS(CurrentClustering); // Might remove sub-grids when time step sizes are too similar ABevolver = new IBMABevolve[CurrentClustering.NumberOfClusters]; for (int i = 0; i < ABevolver.Length; i++) { ABevolver[i] = new IBMABevolve(standardOperator, boundaryOperator, fieldsMap, boundaryParameterMap, speciesMap, control.ExplicitOrder, control.LevelSetQuadratureOrder, control.CutCellQuadratureType, sgrd: CurrentClustering.Clusters[i], adaptive: this.adaptive); ABevolver[i].OnBeforeComputeChangeRate += (t1, t2) => this.RaiseOnBeforeComputechangeRate(t1, t2); } GetBoundaryTopology(); #if DEBUG for (int i = 0; i < CurrentClustering.NumberOfClusters; i++) { Console.WriteLine("IBM AB LTS ctor: id=" + i + " -> sub-steps=" + NumberOfLocalTimeSteps[i] + " and elements=" + CurrentClustering.Clusters[i].GlobalNoOfCells); } #endif // Start-up phase needs an IBM Runge-Kutta time stepper RungeKuttaScheme = new IBMSplitRungeKutta(standardOperator, boundaryOperator, fieldsMap, boundaryParameterMap, speciesMap, timeStepConstraints); }
//################# Hack for saving to database in every (A)LTS sub-step /// <summary> /// Standard constructor for the (adaptive) local time stepping algorithm /// </summary> /// <param name="spatialOp">Spatial operator</param> /// <param name="Fieldsmap">Coordinate mapping for the variable fields</param> /// <param name="Parameters">optional parameter fields, can be null if <paramref name="spatialOp"/> contains no parameters; must match the parameter field list of <paramref name="spatialOp"/>, see <see cref="BoSSS.Foundation.SpatialOperator.ParameterVar"/></param> /// <param name="order">LTS/AB order</param> /// <param name="numOfClusters">Amount of sub-grids/clusters to be used for LTS</param> /// <param name="timeStepConstraints">Time step constraints for later usage as metric</param> /// <param name="subGrid">Sub-grids, e.g., from previous time steps</param> /// <param name="fluxCorrection">Bool for triggering the fluss correction</param> /// <param name="reclusteringInterval">Interval for potential reclustering</param> /// <param name="saveToDBCallback">Hack for plotting all sub-steps</param> /// <remarks>Uses the k-Mean clustering, see <see cref="BoSSS.Solution.Utils.Kmeans"/>, to generate the element groups</remarks> public AdamsBashforthLTS(SpatialOperator spatialOp, CoordinateMapping Fieldsmap, CoordinateMapping Parameters, int order, int numOfClusters, IList <TimeStepConstraint> timeStepConstraints = null, SubGrid subGrid = null, bool fluxCorrection = true, int reclusteringInterval = 0, Action <TimestepNumber, double> saveToDBCallback = null, int initialTimestepNumber = 1) : base(spatialOp, Fieldsmap, Parameters, order, timeStepConstraints, subGrid) { if (reclusteringInterval != 0) { numberOfClustersInitial = numOfClusters; this.timestepNumber = initialTimestepNumber; this.adaptive = true; } // Add OnBeforeComputeChangeRate (AV) to start-up phase time stepper RungeKuttaScheme.OnBeforeComputeChangeRate += (t1, t2) => this.RaiseOnBeforeComputechangeRate(t1, t2); this.reclusteringInterval = reclusteringInterval; this.gridData = Fieldsmap.Fields.First().GridDat; this.fluxCorrection = fluxCorrection; NumberOfLocalTimeSteps = new List <int>(numOfClusters); clusterer = new Clusterer(this.gridData, this.TimeStepConstraints); CurrentClustering = clusterer.CreateClustering(numOfClusters, this.SubGrid); // Might remove clusters when their centres are too close CurrentClustering = CalculateNumberOfLocalTS(CurrentClustering); // Might remove clusters when time step sizes are too similar ABevolver = new ABevolve[CurrentClustering.NumberOfClusters]; for (int i = 0; i < ABevolver.Length; i++) { ABevolver[i] = new ABevolve(spatialOp, Fieldsmap, Parameters, order, adaptive: this.adaptive, sgrd: CurrentClustering.Clusters[i]); ABevolver[i].OnBeforeComputeChangeRate += (t1, t2) => this.RaiseOnBeforeComputechangeRate(t1, t2); } GetBoundaryTopology(); #if DEBUG for (int i = 0; i < CurrentClustering.NumberOfClusters; i++) { Console.WriteLine("AB LTS Ctor: id=" + i + " -> sub-steps=" + NumberOfLocalTimeSteps[i] + " and elements=" + CurrentClustering.Clusters[i].GlobalNoOfCells); } #endif // Saving time steps in subgrids //this.saveToDBCallback = saveToDBCallback; }
////################# Hack for saving to database in every (A)LTS sub-step //private Action<TimestepNumber, double> saveToDBCallback; ////################# Hack for saving to database in every (A)LTS sub-step /// <summary> /// Standard constructor for the (adaptive) local time stepping algorithm /// </summary> /// <param name="spatialOp">Spatial operator</param> /// <param name="Fieldsmap">Coordinate mapping for the variable fields</param> /// <param name="Parameters">optional parameter fields, can be null if <paramref name="spatialOp"/> contains no parameters; must match the parameter field list of <paramref name="spatialOp"/>, see <see cref="BoSSS.Foundation.SpatialOperator.ParameterVar"/></param> /// <param name="order">LTS/AB order</param> /// <param name="numOfClusters">Amount of sub-grids/clusters to be used for LTS</param> /// <param name="timeStepConstraints">Time step constraints for later usage as metric</param> /// <param name="subGrid">Sub-grids, e.g., from previous time steps</param> /// <param name="fluxCorrection">Bool for triggering the fluss correction</param> /// <param name="reclusteringInterval">Interval for potential reclustering</param> /// <param name="saveToDBCallback">Hack for plotting all sub-steps</param> /// <remarks>Uses the k-Mean clustering, see <see cref="BoSSS.Solution.Utils.Kmeans"/>, to generate the element groups</remarks> public AdamsBashforthLTS(SpatialOperator spatialOp, CoordinateMapping Fieldsmap, CoordinateMapping Parameters, int order, int numOfClusters, IList <TimeStepConstraint> timeStepConstraints = null, SubGrid subGrid = null, bool fluxCorrection = true, int reclusteringInterval = 0, Action <TimestepNumber, double> saveToDBCallback = null, int maxNumOfSubSteps = 0, bool forceReclustering = false, bool logging = false, bool consoleOutput = false) : base(spatialOp, Fieldsmap, Parameters, order, timeStepConstraints, subGrid) { this.forceReclustering = forceReclustering; this.Logging = logging; this.ConsoleOutput = consoleOutput; if (reclusteringInterval != 0) { NumberOfClustersInitial = numOfClusters; this.adaptive = true; } // Add OnBeforeComputeChangeRate (AV) to start-up phase time stepper RungeKuttaScheme.OnBeforeComputeChangeRate += (t1, t2) => this.RaiseOnBeforeComputechangeRate(t1, t2); this.reclusteringInterval = reclusteringInterval; this.gridData = Fieldsmap.Fields.First().GridDat; this.fluxCorrection = fluxCorrection; if (ConsoleOutput) { Console.WriteLine("### This is ABLTS ctor ###"); } clusterer = new Clusterer(this.gridData, maxNumOfSubSteps); CurrentClustering = clusterer.CreateClustering(numOfClusters, this.TimeStepConstraints, this.SubGrid); // Might remove clusters when their centres are too close CurrentClustering = clusterer.TuneClustering(CurrentClustering, Time, this.TimeStepConstraints); // Might remove clusters when their time step sizes are too similar ABevolver = new ABevolve[CurrentClustering.NumberOfClusters]; for (int i = 0; i < ABevolver.Length; i++) { ABevolver[i] = new ABevolve(spatialOp, Fieldsmap, Parameters, order, adaptive: this.adaptive, sgrd: CurrentClustering.Clusters[i]); ABevolver[i].OnBeforeComputeChangeRate += (t1, t2) => this.RaiseOnBeforeComputechangeRate(t1, t2); } GetBoundaryTopology(); // Saving time steps in subgrids //this.saveToDBCallback = saveToDBCallback; }
/// <summary> /// Performs a time step /// </summary> /// <param name="dt">Time step size that equals -1, if no fixed time step is prescribed</param> public override double Perform(double dt) { using (new ilPSP.Tracing.FuncTrace()) { if (ABevolver[0].HistoryChangeRate.Count >= order - 1) { bool reclustered = false; if (adaptive) { if (timestepNumber % reclusteringInterval == 0) { // Fix for update problem of artificial viscosity RaiseOnBeforeComputechangeRate(Time, dt); Clusterer.Clustering oldClustering = CurrentClustering; // Necessary in order to use the number of sub-grids specified by the user for the reclustering in each time step // Otherwise the value could be changed by the constructor of the parent class (AdamsBashforthLTS.cs) --> CreateSubGrids() CurrentClustering = clusterer.CreateClustering(numberOfClustersInitial, this.SubGrid); CurrentClustering = CalculateNumberOfLocalTS(CurrentClustering); // Might remove sub-grids when time step sizes are too similar reclustered = clusterer.CheckForNewClustering(oldClustering, CurrentClustering); // After the intitial phase, activate adaptive mode for all ABevolve objects foreach (ABevolve abE in ABevolver) { abE.adaptive = true; } if (reclustered) { ShortenHistories(ABevolver); ABevolve[] oldABevolver = ABevolver; CreateNewABevolver(); CopyHistoriesOfABevolver(oldABevolver); } GetBoundaryTopology(); #if DEBUG if (reclustered) { Console.WriteLine("RECLUSTERING"); } #endif } } // Number of substeps could have changed if (TimeStepConstraints != null) { dt = CalculateTimeStep(); } double[,] CorrectionMatrix = new double[CurrentClustering.NumberOfClusters, CurrentClustering.NumberOfClusters]; // Saves the results at t_n double[] y0 = new double[Mapping.LocalLength]; DGCoordinates.CopyTo(y0, 0); double time0 = m_Time; double time1 = m_Time + dt; TimestepNumber subTimestep = new TimestepNumber(timestepNumber - 1); // Evolves each sub-grid with its own time step (only one step) // (The result is not written to m_DGCoordinates!) for (int i = 0; i < ABevolver.Length; i++) { //localABevolve[i].completeBndFluxes.Clear(); //if (localABevolve[i].completeBndFluxes.Any(x => x != 0.0)) Console.WriteLine("Not all Bnd fluxes were used in correction step!!!"); ABevolver[i].Perform(dt / (double)NumberOfLocalTimeSteps[i]); } // After evolving each cell update the time with dt_min m_Time = m_Time + dt / (double)NumberOfLocalTimeSteps[CurrentClustering.NumberOfClusters - 1]; if (saveToDBCallback != null) { subTimestep = subTimestep.NextIteration(); saveToDBCallback(subTimestep, m_Time); } // Saves the history of DG_Coordinates for each cluster Queue <double[]>[] historyDGC_Q = new Queue <double[]> [CurrentClustering.NumberOfClusters]; for (int i = 0; i < historyDGC_Q.Length; i++) { historyDGC_Q[i] = ABevolver[i].HistoryDGCoordinate; } if (!adaptive) { // Saves DtHistory for each cluster historyTime_Q = new Queue <double> [CurrentClustering.NumberOfClusters]; for (int i = 0; i < historyTime_Q.Length; i++) { historyTime_Q[i] = ABevolver[i].HistoryTime; } } // Perform the local time steps for (int localTS = 1; localTS < NumberOfLocalTimeSteps.Last(); localTS++) { for (int id = 1; id < CurrentClustering.NumberOfClusters; id++) { //Evolve Condition: Is "ABevolve.Time" at "AB_LTS.Time"? if ((ABevolver[id].Time - m_Time) < 1e-10) { double localDt = dt / NumberOfLocalTimeSteps[id]; foreach (Chunk chunk in CurrentClustering.Clusters[id].VolumeMask) { foreach (int cell in chunk.Elements) { // f == each field // n == basis polynomial foreach (DGField f in Mapping.Fields) { for (int n = 0; n < f.Basis.GetLength(cell); n++) { int coordinateIndex = Mapping.LocalUniqueCoordinateIndex(f, cell, n); DGCoordinates[coordinateIndex] = historyDGC_Q[id].Last()[coordinateIndex]; } } } } Dictionary <int, double> myDic = InterpolateBoundaryValues(historyDGC_Q, id, ABevolver[id].Time); foreach (KeyValuePair <int, double> kvp in myDic) { DGCoordinates[kvp.Key] = kvp.Value; } ABevolver[id].Perform(localDt); m_Time = ABevolver.Min(s => s.Time); if (saveToDBCallback != null) { subTimestep = subTimestep.NextIteration(); saveToDBCallback(subTimestep, m_Time); } } // Are we at an (intermediate-) syncronization levels? // For conservatvity, we have to correct the values of the larger cell cluster if (fluxCorrection) { for (int idCoarse = 0; idCoarse < id; idCoarse++) { if (Math.Abs(ABevolver[id].Time - ABevolver[idCoarse].Time) < 1e-10 && !(Math.Abs(ABevolver[idCoarse].Time - CorrectionMatrix[idCoarse, id]) < 1e-10)) { if (fluxCorrection) { CorrectFluxes(idCoarse, id, historyDGC_Q); } CorrectionMatrix[idCoarse, id] = ABevolver[idCoarse].Time; } } } } } // Finalize step // Use unmodified values in history of DGCoordinates (DGCoordinates could have been modified by // InterpolateBoundaryValues, should be resetted afterwards) DGCoordinates.Clear(); for (int id = 0; id < historyDGC_Q.Length; id++) { DGCoordinates.axpy <double[]>(historyDGC_Q[id].Last(), 1); } // Update time m_Time = time0 + dt; } else { double[] currentChangeRate = new double[Mapping.LocalLength]; double[] upDGC = new double[Mapping.LocalLength]; // Save time history if (adaptive) { for (int i = 0; i < ABevolver.Length; i++) { double[] currentTime = new double[ABevolver[i].ABSubGrid.LocalNoOfCells]; for (int j = 0; j < currentTime.Length; j++) { currentTime[j] = m_Time; } ABevolver[i].historyTimePerCell.Enqueue(currentTime); } } else { if (ABevolver[0].HistoryTime.Count == 0) { for (int i = 0; i < ABevolver.Length; i++) { ABevolver[i].HistoryTime.Enqueue(m_Time); } } } // Needed for the history for (int i = 0; i < CurrentClustering.NumberOfClusters; i++) { double[] localCurrentChangeRate = new double[currentChangeRate.Length]; double[] edgeFlux = new double[gridData.iGeomEdges.Count * Mapping.Fields.Count]; ABevolver[i].ComputeChangeRate(localCurrentChangeRate, m_Time, 0, edgeFlux); ABevolver[i].HistoryChangeRate.Enqueue(localCurrentChangeRate); ABevolver[i].HistoryBoundaryFluxes.Enqueue(edgeFlux); } dt = RungeKuttaScheme.Perform(dt); DGCoordinates.CopyTo(upDGC, 0); // Saves ChangeRateHistory for AB LTS // Only entries for the specific cluster for (int i = 0; i < CurrentClustering.NumberOfClusters; i++) { ABevolver[i].HistoryDGCoordinate.Enqueue(OrderValuesByCluster(CurrentClustering.Clusters[i], upDGC)); if (!adaptive) { ABevolver[i].HistoryTime.Enqueue(RungeKuttaScheme.Time); } } // RK is a global timeStep // -> time update for all other timeStepper with rk.Time m_Time = RungeKuttaScheme.Time; foreach (ABevolve ab in ABevolver) { ab.ResetTime(m_Time, timestepNumber); } } } if (adaptive) { timestepNumber++; } return(dt); }