/// <summary> /// Calculates the number of sub-steps for each sub-grid /// </summary> protected Clusterer.Clustering CalculateNumberOfLocalTS(Clusterer.Clustering clustering) { NumberOfLocalTimeSteps.Clear(); double[] sendHmin = new double[clustering.NumberOfClusters]; double[] rcvHmin = new double[clustering.NumberOfClusters]; MultidimensionalArray cellMetric = clusterer.GetStableTimestepSize(clustering.SubGrid); for (int i = 0; i < clustering.NumberOfClusters; i++) { double h_min = double.MaxValue; CellMask volumeMask = clustering.Clusters[i].VolumeMask; foreach (Chunk c in volumeMask) { int JE = c.JE; for (int j = c.i0; j < JE; j++) { h_min = Math.Min(cellMetric[clustering.SubGrid.LocalCellIndex2SubgridIndex[j]], h_min); } } sendHmin[i] = h_min; } // MPI to ensure that each processor has the local time step sizes unsafe { fixed(double *pSend = sendHmin, pRcv = rcvHmin) { csMPI.Raw.Allreduce((IntPtr)(pSend), (IntPtr)(pRcv), clustering.NumberOfClusters, csMPI.Raw._DATATYPE.DOUBLE, csMPI.Raw._OP.MIN, csMPI.Raw._COMM.WORLD); } } int[] numOfSubSteps = new int[clustering.NumberOfClusters]; for (int i = 0; i < numOfSubSteps.Length; i++) { double fraction = rcvHmin[0] / rcvHmin[i]; // Accounting for roundoff errors double eps = 1.0e-2; int subSteps; if (fraction > Math.Floor(fraction) + eps) { subSteps = (int)Math.Ceiling(fraction); } else { subSteps = (int)Math.Floor(fraction); } numOfSubSteps[i] = subSteps; } List <SubGrid> newClusters = new List <SubGrid>(); for (int i = 0; i < clustering.NumberOfClusters; i++) { if (i < clustering.NumberOfClusters - 1 && numOfSubSteps[i] == numOfSubSteps[i + 1]) { // Combine both sub-grids and remove the previous one SubGrid combinedSubGrid = new SubGrid(clustering.Clusters[i].VolumeMask.Union(clustering.Clusters[i + 1].VolumeMask)); newClusters.Add(combinedSubGrid); Debug.WriteLine("CalculateNumberOfLocalTS: Clustering leads to sub-grids which are too similar, i.e. they have the same number of local time steps. They are combined."); NumberOfLocalTimeSteps.Add(numOfSubSteps[i]); i++; } else { newClusters.Add(clustering.Clusters[i]); NumberOfLocalTimeSteps.Add(numOfSubSteps[i]); } } #if DEBUG Console.WriteLine("COMBINING CLUSTERS"); for (int i = 0; i < newClusters.Count; i++) { Console.WriteLine("id=" + i + " -> sub-steps=" + NumberOfLocalTimeSteps[i] + " and elements=" + newClusters[i].GlobalNoOfCells); } #endif return(new Clusterer.Clustering(newClusters, clustering.SubGrid)); }
/// <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); }