protected void ComputeMassMatrixImpl(BlockMsrMatrix MassMatrix, double time) { using (new FuncTrace()) { if (!MassMatrix._RowPartitioning.EqualsPartition(CurrentStateMapping)) { throw new ArgumentException("Internal error."); } if (!MassMatrix._ColPartitioning.EqualsPartition(CurrentStateMapping)) { throw new ArgumentException("Internal error."); } if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity) { MassMatrix.AccEyeSp(1.0); } else { if (TemporalOperator is ConstantXTemporalOperator cxt) { cxt.SetTrackerHack(this.m_LsTrk); } var builder = TemporalOperator.GetMassMatrixBuilder(CurrentStateMapping, CurrentParameters, this.Residuals.Mapping); builder.time = time; builder.ComputeMatrix(MassMatrix, default(double[]), 1.0); // Remark: 1/dt - scaling is applied somewhere else } } }
static void PrlgAndRestMtxTestRec(int p, MultigridMapping[] MgMapSeq) { var currentLevelMap = MgMapSeq.First(); var AggBasis = currentLevelMap.AggBasis[0]; // extract Restriciton and Prolongation Operators BlockMsrMatrix RestOp = new BlockMsrMatrix(MgMapSeq.First(), MgMapSeq.First().ProblemMapping); AggBasis.GetRestrictionMatrix(RestOp, MgMapSeq.First(), 0); BlockMsrMatrix PrlgOp = RestOp.Transpose(); // restriction onto level itself BlockMsrMatrix ShldBeEye = BlockMsrMatrix.Multiply(RestOp, PrlgOp); ShldBeEye.AccEyeSp(-1.0); double ErrNorm = ShldBeEye.InfNorm(); Console.WriteLine("Id norm {0} \t (level {1})", ErrNorm, currentLevelMap.AggGrid.MgLevel); Assert.Less(ErrNorm, 1.0e-8); if (MgMapSeq.Length > 1) { PrlgAndRestMtxTestRec(p, MgMapSeq.Skip(1).ToArray()); } }
private void Setup(MultigridOperator muop, BlockMsrMatrix MassMatrix, double[] __ExactSolution) { if (__ExactSolution != null) { if (__ExactSolution.Length != muop.BaseGridProblemMapping.LocalLength) { throw new ArgumentException(); } } this.SolverOperator = muop; List <AggregationGridBasis[]> aggBasisSeq = new List <AggregationGridBasis[]>(); for (var mo = muop; mo != null; mo = mo.CoarserLevel) { aggBasisSeq.Add(mo.Mapping.AggBasis); } this.ExactSolution = __ExactSolution; int[] Degrees = muop.BaseGridProblemMapping.BasisS.Select(b => b.Degree).ToArray(); BlockMsrMatrix DummyOpMatrix = new BlockMsrMatrix(muop.BaseGridProblemMapping, muop.BaseGridProblemMapping); DummyOpMatrix.AccEyeSp(123); MultigridOperator.ChangeOfBasisConfig[][] config = new MultigridOperator.ChangeOfBasisConfig[1][]; config[0] = new MultigridOperator.ChangeOfBasisConfig[muop.BaseGridProblemMapping.BasisS.Count]; for (int iVar = 0; iVar < config[0].Length; iVar++) { config[0][iVar] = new MultigridOperator.ChangeOfBasisConfig() { Degree = Degrees[iVar], mode = MultigridOperator.Mode.IdMass_DropIndefinite, VarIndex = new int[] { iVar } }; } //this.DecompositionOperator = muop; this.DecompositionOperator_IsOrthonormal = false; this.DecompositionOperator = new MultigridOperator(aggBasisSeq, muop.BaseGridProblemMapping, DummyOpMatrix, MassMatrix, config); this.DecompositionOperator_IsOrthonormal = true; ResNormTrend = new Dictionary <Tuple <int, int, int>, List <double> >(); ErrNormTrend = new Dictionary <Tuple <int, int, int>, List <double> >(); for (var mgop = this.DecompositionOperator; mgop != null; mgop = mgop.CoarserLevel) { int[] _Degrees = mgop.Mapping.DgDegree; for (int iVar = 0; iVar < _Degrees.Length; iVar++) { for (int p = 0; p <= _Degrees[iVar]; p++) { ResNormTrend.Add(new Tuple <int, int, int>(mgop.LevelIndex, iVar, p), new List <double>()); ErrNormTrend.Add(new Tuple <int, int, int>(mgop.LevelIndex, iVar, p), new List <double>()); } } } }
static void RestictionMatrixTestRec(int p, IEnumerable <MultigridMapping> MgMapSeq) { var currentLevelMap = MgMapSeq.First(); AggregationGridBasis AggBasis = currentLevelMap.AggBasis[0]; var map = new UnsetteledCoordinateMapping(new Basis(grid, p)); Random rnd = new Random(); double[] OrigVec = map.LocalLength.ForLoop(i => rnd.NextDouble()); double[] RestVec = new double[AggBasis.LocalDim]; double[] PrlgVec = new double[OrigVec.Length]; double[] RestVec2 = new double[RestVec.Length]; double[] PrlgVec2 = new double[OrigVec.Length]; AggBasis.RestictFromFullGrid(OrigVec, RestVec); AggBasis.ProlongateToFullGrid(PrlgVec, RestVec); BlockMsrMatrix RestOp = new BlockMsrMatrix(MgMapSeq.First(), MgMapSeq.First().ProblemMapping); AggBasis.GetRestrictionMatrix(RestOp, MgMapSeq.First(), 0); RestOp.SpMV(1.0, OrigVec, 0.0, RestVec2); BlockMsrMatrix PrlgOp = RestOp.Transpose(); PrlgOp.SpMV(1.0, RestVec2, 0.0, PrlgVec2); double RestErrNorm = GenericBlas.L2Dist(RestVec2, RestVec); double PrlgErrNorm = GenericBlas.L2Dist(PrlgVec2, PrlgVec); double LostInfNorm = GenericBlas.L2Dist(OrigVec, PrlgVec2); //Console.WriteLine("Rest. matrix test: {0}, Prolong. matrix test {1}, Lost info {2}", RestErrNorm, PrlgErrNorm, LostInfNorm); Assert.IsTrue(RestErrNorm < 1.0e-10); Assert.IsTrue(PrlgErrNorm < 1.0e-10); // restriction onto level itself BlockMsrMatrix RestMtx = currentLevelMap.FromOtherLevelMatrix(currentLevelMap); BlockMsrMatrix ShldBeEye = BlockMsrMatrix.Multiply(RestMtx, RestMtx.Transpose()); ShldBeEye.AccEyeSp(-1.0); double errNorm = ShldBeEye.InfNorm(); Console.WriteLine("Id norm {0} \t (level {1})", errNorm, currentLevelMap.AggGrid.MgLevel); Assert.IsTrue(errNorm < 1.0e-8); // recursion if (MgMapSeq.Count() > 1) { RestictionMatrixTestRec(p, MgMapSeq.Skip(1)); } }
private void AssembleMatrix(double dt, out BlockMsrMatrix SystemMatrix, out double[] SystemAffine) { // Init Matrix and Affine Part SystemMatrix = new BlockMsrMatrix(Mapping); SystemAffine = new double[Mapping.LocalLength]; // choose TimeStepping-Scheme, based on what has been pushed to the stack,yet int Smax = TSCchain[0].S; Debug.Assert(Smax == TSCchain.Length); Tsc = TSCchain[Smax - PopulatedStackDepth]; UpdateOperatorMatrix(); //Implicit Part of RHS SystemMatrix.Acc(Tsc.theta1, Stack_OpMatrix[1]); SystemAffine.AccV(Tsc.theta1, Stack_OpAffine[1]); //Implicit Part of LHS SystemMatrix.AccEyeSp(1 / dt); // Explicit part of RHS Stack_OpMatrix[0].SpMV(-Tsc.theta0, CurrentState, 1.0, SystemAffine); SystemAffine.AccV(-Tsc.theta0, Stack_OpAffine[0]); //Explicit parts of LHS for (int i = 0; i < Tsc.beta.Length; i++) { SystemAffine.AccV(Tsc.beta[i] * 1 / dt, Stack_u[i]); } Debug.Assert(SystemMatrix.InfNorm() > 0); Debug.Assert(SystemAffine.L2Norm() > 0); if (subGrid != null) { int[] SubVecIdx = Mapping.GetSubvectorIndices(subGrid, true, new int[] { 0 }); int L = SubVecIdx.Length; for (int i = 0; i < L; i++) { SystemMatrix.ClearRow(SubVecIdx[i]); SystemMatrix[SubVecIdx[i], SubVecIdx[i]] = 1; SystemAffine[SubVecIdx[i]] = 0; } } }
public XDGTestSetup( int p, double AggregationThreshold, int TrackerWidth, MultigridOperator.Mode mumo, XQuadFactoryHelper.MomentFittingVariants momentFittingVariant, ScalarFunction LevSetFunc = null) { // Level set, tracker and XDG basis // ================================ if (LevSetFunc == null) { LevSetFunc = ((_2D)((x, y) => 0.8 * 0.8 - x * x - y * y)).Vectorize(); } LevSet = new LevelSet(new Basis(grid, 2), "LevelSet"); LevSet.Clear(); LevSet.ProjectField(LevSetFunc); LsTrk = new LevelSetTracker(grid, XQuadFactoryHelper.MomentFittingVariants.Classic, TrackerWidth, new string[] { "A", "B" }, LevSet); LsTrk.UpdateTracker(); XB = new XDGBasis(LsTrk, p); XSpatialOperator Dummy = new XSpatialOperator(1, 0, 1, QuadOrderFunc.SumOfMaxDegrees(RoundUp: true), "C1", "u"); //Dummy.EquationComponents["c1"].Add(new Dummy.Commit(); //Tecplot.PlotFields(new DGField[] { LevSet }, "agglo", 0.0, 3); // operator // ======== Debug.Assert(p <= 4); XDGBasis opXB = new XDGBasis(LsTrk, 4); // we want to have a very precise quad rule var map = new UnsetteledCoordinateMapping(opXB); int quadOrder = Dummy.QuadOrderFunction(map.BasisS.Select(bs => bs.Degree).ToArray(), new int[0], map.BasisS.Select(bs => bs.Degree).ToArray()); //agg = new MultiphaseCellAgglomerator(new CutCellMetrics(momentFittingVariant, quadOrder, LsTrk, LsTrk.SpeciesIdS.ToArray()), AggregationThreshold, false); agg = LsTrk.GetAgglomerator(LsTrk.SpeciesIdS.ToArray(), quadOrder, __AgglomerationTreshold: AggregationThreshold); foreach (var S in LsTrk.SpeciesIdS) { Console.WriteLine("Species {0}, no. of agglomerated cells {1} ", LsTrk.GetSpeciesName(S), agg.GetAgglomerator(S).AggInfo.SourceCells.Count()); } // mass matrix factory // =================== // Basis maxB = map.BasisS.ElementAtMax(b => b.Degree); //MassFact = new MassMatrixFactory(maxB, agg); MassFact = LsTrk.GetXDGSpaceMetrics(LsTrk.SpeciesIdS.ToArray(), quadOrder, 1).MassMatrixFactory; // Test field // ========== // set the test field: this is a polynomial function, // but different for each species; On this field, restriction followed by prolongation should be the identity this.Xdg_uTest = new XDGField(this.XB, "uTest"); Dictionary <SpeciesId, double> dumia = new Dictionary <SpeciesId, double>(); int i = 2; foreach (var Spc in LsTrk.SpeciesIdS) { dumia.Add(Spc, i); i -= 1; } SetTestValue(Xdg_uTest, dumia); // dummy operator matrix which fits polynomial degree p // ==================================================== Xdg_opMtx = new BlockMsrMatrix(Xdg_uTest.Mapping, Xdg_uTest.Mapping); Xdg_opMtx.AccEyeSp(120.0); // XDG Aggregation BasiseS // ======================= //XAggB = MgSeq.Select(agGrd => new XdgAggregationBasis[] { new XdgAggregationBasis(uTest.Basis, agGrd) }).ToArray(); XAggB = new XdgAggregationBasis[MgSeq.Length][]; var _XAggB = AggregationGridBasis.CreateSequence(MgSeq, Xdg_uTest.Mapping.BasisS); for (int iLevel = 0; iLevel < XAggB.Length; iLevel++) { XAggB[iLevel] = new[] { (XdgAggregationBasis)(_XAggB[iLevel][0]) }; XAggB[iLevel][0].Update(agg); } // Multigrid Operator // ================== Xdg_opMtx = new BlockMsrMatrix(Xdg_uTest.Mapping, Xdg_uTest.Mapping); Xdg_opMtx.AccEyeSp(120.0); XdgMultigridOp = new MultigridOperator(XAggB, Xdg_uTest.Mapping, Xdg_opMtx, MassFact.GetMassMatrix(Xdg_uTest.Mapping, false), new MultigridOperator.ChangeOfBasisConfig[][] { new MultigridOperator.ChangeOfBasisConfig[] { new MultigridOperator.ChangeOfBasisConfig() { VarIndex = new int[] { 0 }, mode = mumo, Degree = p } } }); }
/// <summary> /// Matrix/Affine assembly in the case of an implicit RK stage. /// </summary> protected override void AssembleMatrixCallback(out BlockMsrMatrix System, out double[] Affine, out BlockMsrMatrix PcMassMatrix, DGField[] argCurSt, bool Linearization) { if (Linearization == false) { throw new NotImplementedException("todo"); } int Ndof = m_CurrentState.Count; // copy data from 'argCurSt' to 'CurrentStateMapping', if necessary // ----------------------------------------------------------- DGField[] locCurSt = CurrentStateMapping.Fields.ToArray(); if (locCurSt.Length != argCurSt.Length) { throw new ApplicationException(); } int NF = locCurSt.Length; for (int iF = 0; iF < NF; iF++) { if (object.ReferenceEquals(locCurSt[iF], argCurSt[iF])) { // nothing to do } else { locCurSt[iF].Clear(); locCurSt[iF].Acc(1.0, argCurSt[iF]); } } // update of level-set // ---------------------- bool updateAgglom = false; if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once && m_ImplStParams.m_IterationCounter == 0 || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { //MoveLevelSetAndRelatedStuff(locCurSt, m_CurrentPhystime, m_CurrentDt, 1.0); if (Math.Abs(m_ImplStParams.m_ActualLevSetRelTime - m_ImplStParams.m_RelTime) > 1.0e-14) { if (m_ImplStParams.m_IterationCounter <= 0)// only push tracker in the first iter { m_LsTrk.PushStacks(); } MoveLevelSetAndRelatedStuff(locCurSt, m_ImplStParams.m_CurrentPhystime, m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime, IterUnderrelax, m_ImplStParams.m_Mass, m_ImplStParams.m_k); // note that we need to update the agglomeration updateAgglom = true; } } // update agglomeration // -------------------- #if DEBUG if (this.Config_LevelSetHandling == LevelSetHandling.LieSplitting || this.Config_LevelSetHandling == LevelSetHandling.StrangSplitting) { Debug.Assert(m_CurrentAgglomeration != null); Debug.Assert(m_PrecondMassMatrix != null); // ensure, that, when splitting is used we update the agglomerator in the very first iteration. } #endif if (updateAgglom || m_CurrentAgglomeration == null) { this.UpdateAgglom(m_ImplStParams.m_IterationCounter > 0); // update Multigrid-XDG basis base.MultigridBasis.UpdateXdgAggregationBasis(m_CurrentAgglomeration); } // mass matrix update // ------------------ if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity) { // may occur e.g. if one runs the FSI solver as a pure single-phase solver, // i.e. if the Level-Set is outside the domain. PcMassMatrix = null; } else { // checks: Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity || this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeDependent || this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeAndSolutionDependent, "Something is not implemented here."); if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity && Config_LevelSetHandling != LevelSetHandling.None) { throw new NotSupportedException("Illegal configuration;"); } if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { if ((this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity && m_PrecondMassMatrix == null) || // compute mass matrix (only once in application lifetime) (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeDependent && m_ImplStParams.m_IterationCounter == 0) || // compute mass matrix once per timestep (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeAndSolutionDependent) // re-compute mass matrix in every iteration ) { BlockMsrMatrix PM, SM; UpdateMassMatrix(out PM, out SM, m_ImplStParams.m_CurrentPhystime + m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime); m_ImplStParams.m_Mass[1] = SM; m_PrecondMassMatrix = PM; } } PcMassMatrix = m_PrecondMassMatrix; } // operator matrix update // ---------------------- // we perform the extrapolation to have valid parameters if // - the operator matrix depends on these values this.m_CurrentAgglomeration.Extrapolate(CurrentStateMapping); var OpMatrix = new BlockMsrMatrix(CurrentStateMapping); var OpAffine = new double[Ndof]; this.ComputeOperatorMatrix(OpMatrix, OpAffine, CurrentStateMapping, locCurSt, base.GetAgglomeratedLengthScales(), m_ImplStParams.m_CurrentPhystime + m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime); // assemble system // --------------- double dt = m_ImplStParams.m_CurrentDt; // select mass matrix (and some checks) double[] RHS = new double[Ndof]; BlockMsrMatrix MamaRHS, MamaLHS; if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { Debug.Assert(m_ImplStParams.m_Mass.Length == 2); MamaRHS = m_ImplStParams.m_Mass[0]; MamaLHS = m_ImplStParams.m_Mass[1]; } else if (this.Config_LevelSetHandling == LevelSetHandling.LieSplitting || this.Config_LevelSetHandling == LevelSetHandling.StrangSplitting || this.Config_LevelSetHandling == LevelSetHandling.None) { Debug.Assert(m_ImplStParams.m_Mass.Length == 1); MamaRHS = m_ImplStParams.m_Mass[0]; MamaLHS = m_ImplStParams.m_Mass[0]; } else { throw new NotImplementedException(); } // right-hand-side, resp. affine vector if (MamaRHS != null) { MamaRHS.SpMV(1.0 / dt, m_ImplStParams.m_u0, 0.0, RHS); } else { Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity); RHS.SetV(m_ImplStParams.m_u0, 1.0 / dt); } for (int l = 0; l < m_ImplStParams.m_s; l++) { if (m_ImplStParams.m_RK_as[l] != 0.0) { RHS.AccV(-m_ImplStParams.m_RK_as[l], m_ImplStParams.m_k[l]); } } Affine = RHS; Affine.ScaleV(-1.0); Affine.AccV(m_ImplStParams.m_RK_as[m_ImplStParams.m_s], OpAffine); // left-hand-side System = OpMatrix.CloneAs(); System.Scale(m_ImplStParams.m_RK_as[m_ImplStParams.m_s]); if (MamaLHS != null) { System.Acc(1.0 / dt, MamaLHS); } else { System.AccEyeSp(1.0 / dt); } // perform agglomeration // --------------------- Debug.Assert(object.ReferenceEquals(m_CurrentAgglomeration.Tracker, m_LsTrk)); m_CurrentAgglomeration.ManipulateMatrixAndRHS(System, Affine, CurrentStateMapping, CurrentStateMapping); // increase iteration counter // -------------------------- m_ImplStParams.m_IterationCounter++; }
/// <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()); } }