private double[] GetAuxAccVec(BlockMaskBase mask, IList <double> fullVector, int iCell)
        {
            int nCell = mask.GetType() == typeof(BlockMaskExt)? iCell - BMLoc.m_StructuredNi0.Length:iCell;

            double[] subVector = new double[mask.GetLengthOfCell(nCell)];
            var      Cidx      = mask.GetLocalidcOfCell(nCell);

            Debug.Assert(subVector.Length == Cidx.Length);
            ArrayTools.GetSubVector <int[], int[], double>(fullVector, subVector, Cidx);
            return(subVector);
        }
        private void AuxAcc <V, W>(BlockMaskBase mask, W subVector, int iCell, V fullVector)
            where V : IList <double>
            where W : IList <double>
        {
            int nCell = mask.GetType() == typeof(BlockMaskExt) ? iCell - BMLoc.m_StructuredNi0.Length : iCell;

            if (nCell >= mask.m_StructuredNi0.Length)
            {
                throw new ArgumentOutOfRangeException("iCell is greater than Cells in mask");
            }
            if (subVector.Count() != mask.GetLengthOfCell(nCell))
            {
                throw new ArgumentException("accVector length is not equal to length of mask");
            }

            var Cidx = mask.GetLocalidcOfCell(nCell);

            Debug.Assert(subVector.Count() == Cidx.Count());
            fullVector.AccV(1.0, subVector, Cidx, default(int[]));
        }
        private void AuxGetSubBlockMatrix(BlockMsrMatrix target, BlockMsrMatrix source, BlockMaskBase mask, bool ignoreCellCoupling, bool ignoreVarCoupling, bool ignoreSpecCoupling)
        {
            bool IsLocalMask = mask.GetType() == typeof(BlockMaskLoc);

            extNi0[][][][] RowNi0s = mask.m_StructuredNi0;
            extNi0[][][][] ColNi0s = this.StructuredNi0;

            int auxIdx = 0;

            for (int iLoc = 0; iLoc < RowNi0s.Length; iLoc++)
            {
                for (int jLoc = 0; jLoc < ColNi0s.Length; jLoc++)
                {
                    if (ignoreCellCoupling && jLoc != iLoc)
                    {
                        continue;
                    }
                    for (int iVar = 0; iVar < RowNi0s[iLoc].Length; iVar++)
                    {
                        for (int jVar = 0; jVar < ColNi0s[jLoc].Length; jVar++)
                        {
                            if (ignoreVarCoupling && jVar != iVar)
                            {
                                continue;
                            }
                            for (int iSpc = 0; iSpc < RowNi0s[iLoc][iVar].Length; iSpc++)
                            {
                                for (int jSpc = 0; jSpc < ColNi0s[jLoc][jVar].Length; jSpc++)
                                {
                                    if (ignoreSpecCoupling && jSpc != iSpc)
                                    {
                                        continue;
                                    }
                                    for (int iMode = 0; iMode < RowNi0s[iLoc][iVar][iSpc].Length; iMode++)
                                    {
                                        int Trgi0 = RowNi0s[iLoc][iVar][iSpc][iMode].Si0;
                                        for (int jMode = 0; jMode < ColNi0s[jLoc][jVar][jSpc].Length; jMode++)
                                        {
                                            extNi0 RowNi0 = RowNi0s[iLoc][iVar][iSpc][iMode];
                                            extNi0 ColNi0 = ColNi0s[jLoc][jVar][jSpc][jMode];
                                            int    Srci0  = IsLocalMask? RowNi0.Gi0: RowNi0.Li0 + source._RowPartitioning.i0 - m_map.LocalLength;
                                            int    Srcj0  = ColNi0.Gi0;

                                            var tmpBlock = MultidimensionalArray.Create(RowNi0.N, ColNi0.N);

                                            int Trgj0 = ColNi0s[jLoc][jVar][jSpc][jMode].Si0;
#if Debug
                                            SubMSR.ReadBlock(SubRowIdx, SubColIdx, tmpBlock);
                                            Debug.Assert(tmpBlock.Sum() == 0);
                                            Debug.Assert(tmpBlock.InfNorm() == 0);
#endif

                                            try {
                                                source.ReadBlock(Srci0, Srcj0,
                                                                 tmpBlock);
                                            } catch (Exception e) {
                                                Console.WriteLine("row: " + Srci0);
                                                Console.WriteLine("col: " + Srcj0);
                                                throw new Exception(e.Message);
                                            }
                                            Debug.Assert(Trgi0 < target.RowPartitioning.LocalLength);
                                            Debug.Assert(Trgj0 < target.ColPartition.LocalLength);


                                            target.AccBlock(Trgi0, Trgj0, 1.0, tmpBlock);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    auxIdx++;
                }
                auxIdx++;
            }
        }
        private MultidimensionalArray[] AuxGetSubBlocks(BlockMsrMatrix source, BlockMaskBase mask, bool ignoreCellCoupling, bool ignoreVarCoupling, bool ignoreSpecCoupling)
        {
            bool IsLocMask = mask.GetType() == typeof(BlockMaskLoc); // if external cells are masked, we have to consider other offsets ...

            int NoOfCells = mask.m_StructuredNi0.Length;
            int size      = ignoreCellCoupling ? NoOfCells : NoOfCells * NoOfCells;

            MultidimensionalArray[] Sblocks = new MultidimensionalArray[size];

            int auxIdx = 0;

            for (int iLoc = 0; iLoc < mask.m_StructuredNi0.Length; iLoc++)
            {
                for (int jLoc = 0; jLoc < mask.m_StructuredNi0.Length; jLoc++)
                {
                    if (ignoreCellCoupling && jLoc != iLoc)
                    {
                        continue;
                    }
                    int CellBlockLen = mask.GetLengthOfCell(jLoc);
                    Sblocks[auxIdx] = MultidimensionalArray.Create(CellBlockLen, CellBlockLen);
                    for (int iVar = 0; iVar < mask.m_StructuredNi0[iLoc].Length; iVar++)
                    {
                        for (int jVar = 0; jVar < mask.m_StructuredNi0[jLoc].Length; jVar++)
                        {
                            if (ignoreVarCoupling && jVar != iVar)
                            {
                                continue;
                            }
                            for (int iSpc = 0; iSpc < mask.m_StructuredNi0[iLoc][iVar].Length; iSpc++)
                            {
                                for (int jSpc = 0; jSpc < mask.m_StructuredNi0[jLoc][jVar].Length; jSpc++)
                                {
                                    if (ignoreSpecCoupling && jSpc != iSpc)
                                    {
                                        continue;
                                    }
                                    for (int iMode = 0; iMode < mask.m_StructuredNi0[iLoc][iVar][iSpc].Length; iMode++)
                                    {
                                        for (int jMode = 0; jMode < mask.m_StructuredNi0[jLoc][jVar][jSpc].Length; jMode++)
                                        {
                                            extNi0 RowNi0   = mask.m_StructuredNi0[iLoc][iVar][iSpc][iMode];
                                            extNi0 ColNi0   = mask.m_StructuredNi0[jLoc][jVar][jSpc][jMode];
                                            int    Targeti0 = IsLocMask ? RowNi0.Gi0 : RowNi0.Li0 + source._RowPartitioning.i0 - m_map.LocalLength;
                                            int    Targetj0 = ColNi0.Gi0;
                                            int    Subi0    = mask.GetRelativeSubBlockOffset(iLoc, iVar, iSpc, iMode);
                                            int    Subj0    = mask.GetRelativeSubBlockOffset(jLoc, jVar, jSpc, jMode);
                                            int    Subie    = Subi0 + RowNi0.N - 1;
                                            int    Subje    = Subj0 + ColNi0.N - 1;

                                            var tmp = Sblocks[auxIdx].ExtractSubArrayShallow(new int[] { Subi0, Subj0 }, new int[] { Subie, Subje });

                                            Debug.Assert((m_map.IsInLocalRange(Targeti0) && m_map.IsInLocalRange(Targetj0) && mask.GetType() == typeof(BlockMaskLoc)) || mask.GetType() == typeof(BlockMaskExt));

                                            try {
                                                source.ReadBlock(Targeti0, Targetj0, tmp
                                                                 );
                                            } catch (Exception e) {
                                                Console.WriteLine("row: " + Targeti0);
                                                Console.WriteLine("col: " + Targetj0);
                                                throw new Exception(e.Message);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    auxIdx++;
                }
            }
            return(Sblocks);
        }