/// <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 (var tr = new ilPSP.Tracing.FuncTrace()) { if (ABevolver[0].HistoryChangeRate.Count >= order - 1) { // +++++++++++++++++++++++++++++++++++++++++++ // Standard case -- sufficiently large history // +++++++++++++++++++++++++++++++++++++++++++ using (var bt = new BlockTrace("AB_LTS_standard", tr)) { if (!reclusteredByGridRedist) { TryNewClustering(dt); } List <int> numberOfLocalTimeSteps = new List <int>(); double[] clusterDts = new double[CurrentClustering.NumberOfClusters]; // Set the number of sub steps (is calculated in every time step, regardless of whether a reclustering has been performed or not) if (TimeStepConstraints != null) { //dt = CalculateTimeStep(); // If no dtFixed is set if (TimeStepConstraints.First().dtMin != TimeStepConstraints.First().dtMax) { (clusterDts, numberOfLocalTimeSteps) = clusterer.GetPerCluster_dtHarmonicSum_SubSteps(CurrentClustering, Time, TimeStepConstraints, eps: 1.0e-1); dt = clusterDts[0]; } else // dtFixed is set // Not nice, but working { dt = CalculateTimeStep(); numberOfLocalTimeSteps = CurrentClustering.SubStepsInitial; for (int i = 0; i < numberOfLocalTimeSteps.Count; i++) { clusterDts[i] = dt / numberOfLocalTimeSteps[i]; } } } // Log time info if (Logging) { this.log_clusterDts = clusterDts; this.log_clusterSubSteps = numberOfLocalTimeSteps.ToArray(); this.log_clusterElements = CurrentClustering.Clusters.Select(s => s.GlobalNoOfCells).ToArray(); } if (ConsoleOutput) { for (int i = 0; i < numberOfLocalTimeSteps.Count; i++) { Console.WriteLine("Perform(dt):\t\t id={0} -> sub-steps={1}\telements={2}\tdt={3:0.#######E-00}", i, numberOfLocalTimeSteps[i], CurrentClustering.Clusters[i].GlobalNoOfCells, clusterDts[i]); //Console.WriteLine("Perform(dt):\t\t id={0} -> sub-steps={1}\telements={2}\tdt={3}", i, numberOfLocalTimeSteps[i], CurrentClustering.Clusters[i].GlobalNoOfCells, clusterDts[i]); } if (numberOfLocalTimeSteps.Last() > (clusterer.MaxSubSteps + 1) && clusterer.Restrict) { throw new Exception(String.Format("Number of local time steps is larger than {0}! Restriction failed!", clusterer.MaxSubSteps)); } } double[,] CorrectionMatrix = new double[CurrentClustering.NumberOfClusters, CurrentClustering.NumberOfClusters]; // Test code //double[] bla = new double[numberOfLocalTimeSteps.Count]; //for (int i = 0; i < bla.Length; i++) { // bla[i] = dt / numberOfLocalTimeSteps[i]; // if (bla[i] != clusterDts[i]) { // throw new Exception("clusterDts wrong"); // } //} // Saves the results at t_n double[] y0 = new double[Mapping.LocalLength]; CurrentState.CopyTo(y0, 0); double time0 = m_Time; double time1 = m_Time + clusterDts[0]; // 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(clusterDts[i]); } // After evolving each cell update the time with dt_min m_Time = m_Time + clusterDts.Last(); TimestepNumber subTimestep = new TimestepNumber(TimeInfo.TimeStepNumber - 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) { 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); CurrentState[coordinateIndex] = historyDGC_Q[id].Last()[coordinateIndex]; } } } } Dictionary <int, double> myDic = InterpolateBoundaryValues(historyDGC_Q, id, ABevolver[id].Time); foreach (KeyValuePair <int, double> kvp in myDic) { CurrentState[kvp.Key] = kvp.Value; } ABevolver[id].Perform(clusterDts[id]); 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) CurrentState.Clear(); for (int id = 0; id < historyDGC_Q.Length; id++) { CurrentState.axpy <double[]>(historyDGC_Q[id].Last(), 1); } // Update time m_Time = time0 + clusterDts[0]; } } else { // +++++++++++++++++++++++++++++++++++++++++++++++++++++ // Startup - use Runge Rutta until history is sufficient // +++++++++++++++++++++++++++++++++++++++++++++++++++++ using (var rkPhase = new BlockTrace("AB_LTS_Rkstartup", tr)) { 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); CurrentState.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, TimeInfo.TimeStepNumber); } } } } return(dt); }
/// <summary> /// applies the pre-conditioning to the operator matrix /// (passed in the constructor) /// and returns the pre-conditioned matrix /// </summary> /// <param name="LeftPreCond"> /// left pre-conditioning matrix /// </param> /// <param name="RightPreCond"> /// right pre-conditioning matrix /// </param> /// <param name="RightPreCondInv"> /// the inverse of <paramref name="RightPreCond"/> -- usually required to transform an initial guess. /// </param> /// <param name="LeftPreCondInv"></param> /// <param name="MassMatrix"> /// on entry the mass matrix w.r.t. the XDG basis /// </param> /// <param name="OpMatrix"> /// </param> /// <returns> /// List of indefinite row indices. /// </returns> int[] ComputeChangeOfBasis(BlockMsrMatrix OpMatrix, BlockMsrMatrix MassMatrix, out BlockMsrMatrix LeftPreCond, out BlockMsrMatrix RightPreCond, out BlockMsrMatrix LeftPreCondInv, out BlockMsrMatrix RightPreCondInv) { using (var tr = new FuncTrace()) { // test arguments // ============== VerifyConfig(); Debug.Assert(OpMatrix.RowPartitioning.LocalLength == this.Mapping.LocalLength); Debug.Assert(OpMatrix.ColPartition.LocalLength == this.Mapping.LocalLength); Debug.Assert(MassMatrix == null || (MassMatrix.RowPartitioning.LocalLength == this.Mapping.LocalLength)); Debug.Assert(MassMatrix == null || (MassMatrix.ColPartition.LocalLength == this.Mapping.LocalLength)); AggregationGridBasis[] basisS = this.Mapping.AggBasis; int[] Degrees = this.Mapping.DgDegree; List <int> IndefRows = new List <int>(); // compute preconditioner matrices // =============================== using (var bt = new BlockTrace("compute-pc", tr)) { Stopwatch stw_Data = new Stopwatch(); stw_Data.Reset(); Stopwatch stw_Comp = new Stopwatch(); stw_Comp.Reset(); LeftPreCond = new BlockMsrMatrix(OpMatrix._RowPartitioning, OpMatrix._ColPartitioning); RightPreCond = new BlockMsrMatrix(OpMatrix._RowPartitioning, OpMatrix._ColPartitioning); RightPreCondInv = new BlockMsrMatrix(OpMatrix._RowPartitioning, OpMatrix._ColPartitioning); LeftPreCondInv = new BlockMsrMatrix(OpMatrix._RowPartitioning, OpMatrix._ColPartitioning); LeftPreCond.AccEyeSp(1.0); RightPreCond.AccEyeSp(1.0); LeftPreCondInv.AccEyeSp(1.0); RightPreCondInv.AccEyeSp(1.0); int LL = this.m_Config.Length; MultidimensionalArray[] MassBlock = new MultidimensionalArray[LL]; MultidimensionalArray[] OperatorBlock = new MultidimensionalArray[LL]; MultidimensionalArray[] PCleftBlock = new MultidimensionalArray[LL]; MultidimensionalArray[] work = new MultidimensionalArray[LL]; MultidimensionalArray[] PCrightBlock_inv = new MultidimensionalArray[LL]; MultidimensionalArray[] PCleftBlock_inv = new MultidimensionalArray[LL]; MultidimensionalArray[] PCrightBlock = new MultidimensionalArray[LL]; int[][] __i0s = new int[LL][]; int[][] __Lns = new int[LL][]; for (int i = 0; i < LL; i++) { var conf = m_Config[i]; __i0s[i] = new int[conf.VarIndex.Length]; __Lns[i] = new int[conf.VarIndex.Length]; } int J = this.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; int i0 = this.Mapping.Partitioning.i0; for (int jCell = 0; jCell < J; jCell++) // loop over cells... //ReducedRegionCode rrc; //int NoOfSpc = LsTrk.GetNoOfSpecies(jCell, out rrc); //if (this.Mapping.GetLength(jCell) == 0) // // void cell // continue; { for (int i = 0; i < LL; i++) // for each configuration item... { var conf = m_Config[i]; int E = conf.VarIndex.Length; int[] _i0s = __i0s[i]; int[] _Lns = __Lns[i]; //AggregationGridBasis basis = null; int DOF = 0; bool AnyZeroLength = false; for (int e1 = 0; e1 < E; e1++) { int dof_var = this.Mapping.GetLengthForVar(jCell, conf.VarIndex[e1]); DOF += dof_var; AnyZeroLength |= (dof_var == 0); } if (AnyZeroLength && DOF > 0) { throw new ApplicationException(); } if (DOF == 0) { // void cell continue; } for (int e = 0; e < E; e++) { int iVar = conf.VarIndex[e]; _i0s[e] = this.Mapping.LocalUniqueIndex(iVar, jCell, 0) + i0; _Lns[e] = basisS[iVar].GetLength(jCell, Degrees[iVar]); } // extract blocks from operator and mass matrix // -------------------------------------------- stw_Data.Start(); ExtractBlock(_i0s, _Lns, true, MassMatrix, ref MassBlock[i]); ExtractBlock(_i0s, _Lns, true, OpMatrix, ref OperatorBlock[i]); stw_Data.Stop(); double MassBlkNrm = MassBlock[i].InfNorm(); double OperatorBlkNrm = OperatorBlock[i].InfNorm(); int NN = MassBlock[i].NoOfRows; if (MassBlkNrm == 0) { //throw new ArithmeticException("absolute zero Mass block in cell " + jCell + "."); //Console.WriteLine("absolute zero Mass block in cell " + jCell + "."); if (conf.mode == Mode.IdMass_DropIndefinite || conf.mode == Mode.SymPart_DiagBlockEquilib_DropIndefinite) { // we can deal with this ... } else { throw new ArithmeticException("absolute zero Mass block in cell " + jCell + "."); } } //if(OperatorBlkNrm == 0) { // throw new ArithmeticException("absolute zero Operator block in cell " + jCell + "."); //} // mem alloc // --------- if (PCleftBlock[i] == null || PCleftBlock[i].NoOfRows != NN) { PCleftBlock[i] = MultidimensionalArray.Create(NN, NN); } if (PCrightBlock[i] == null || PCrightBlock[i].NoOfRows != NN) { PCrightBlock[i] = MultidimensionalArray.Create(NN, NN); } if (work[i] == null || work[i].NoOfRows != NN) { work[i] = MultidimensionalArray.Create(NN, NN); } // compute precond // --------------- stw_Comp.Start(); int Rank; PCleftBlock[i].Clear(); PCrightBlock[i].Clear(); int[] idr = ComputeChangeOfBasisBlock(_Lns, MassBlock[i], OperatorBlock[i], PCleftBlock[i], PCrightBlock[i], conf.mode, out Rank, work[i]); if (Rank != NN) { IndefRows.AddRange(ConvertRowIndices(jCell, basisS, Degrees, conf, E, _i0s, idr)); } else { Debug.Assert(idr == null); } stw_Comp.Stop(); // write block back // ---------------- stw_Data.Start(); ExtractBlock(_i0s, _Lns, false, LeftPreCond, ref PCleftBlock[i]); ExtractBlock(_i0s, _Lns, false, RightPreCond, ref PCrightBlock[i]); // inverse precond-matrix // ---------------------- // right-inverse: (required for transforming solution guess) if (PCrightBlock_inv[i] == null || PCrightBlock_inv[i].NoOfRows != NN) { PCrightBlock_inv[i] = MultidimensionalArray.Create(NN, NN); } if (Rank == NN) { PCrightBlock[i].InvertTo(PCrightBlock_inv[i]); } else { RankDefInvert(PCrightBlock[i], PCrightBlock_inv[i]); } ExtractBlock(_i0s, _Lns, false, RightPreCondInv, ref PCrightBlock_inv[i]); // left-inverse: (required for analysis purposes, to transform residuals back onto original grid) if (PCleftBlock_inv[i] == null || PCleftBlock_inv[i].NoOfRows != NN) { PCleftBlock_inv[i] = MultidimensionalArray.Create(NN, NN); } if (Rank == NN) { PCleftBlock[i].InvertTo(PCleftBlock_inv[i]); } else { RankDefInvert(PCleftBlock[i], PCleftBlock_inv[i]); } ExtractBlock(_i0s, _Lns, false, LeftPreCondInv, ref PCleftBlock_inv[i]); stw_Data.Stop(); } } bt.LogDummyblock(stw_Data.Elapsed.Ticks, "Change_of_Basis_data_copy"); bt.LogDummyblock(stw_Comp.Elapsed.Ticks, "Change_of_Basis_compute"); } return(IndefRows.ToArray()); } }