예제 #1
0
        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
                }
            }
        }
예제 #2
0
        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());
            }
        }
예제 #3
0
        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>());
                    }
                }
            }
        }
예제 #4
0
        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));
            }
        }
예제 #5
0
        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;
                }
            }
        }
예제 #6
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
                        }
                    }
                });
            }
예제 #7
0
        /// <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++;
        }
예제 #8
0
        /// <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());
            }
        }