/// <summary>
        /// returns all external rows of <paramref name="M"/>
        /// corresponding to ghost cells of <paramref name="map"/>,
        /// which are located on other Mpi-ranks.
        /// </summary>
        /// <param name="map">Multigrid mapping</param>
        /// <param name="M">matrix distributed according to <paramref name="map"/></param>
        /// <returns></returns>
        public static BlockMsrMatrix GetAllExternalRows(MultigridMapping map, BlockMsrMatrix M)
        {
            var extcells = map.AggGrid.iLogicalCells.NoOfExternalCells.ForLoop(i => i + map.LocalNoOfBlocks);

            var SBS = new SubBlockSelector(map);

            SBS.CellSelector(extcells, false);
            var AllExtMask = new BlockMaskExt(SBS, 0);

            var ExternalRows_BlockI0 = AllExtMask.GetAllSubMatrixCellOffsets();
            var ExternalRows_BlockN  = AllExtMask.GetAllSubMatrixCellLength();
            var ExternalRowsIndices  = AllExtMask.m_GlobalMask;

            BlockPartitioning PermRow = new BlockPartitioning(ExternalRowsIndices.Count, ExternalRows_BlockI0, ExternalRows_BlockN, M.MPI_Comm, i0isLocal: true);

            BlockMsrMatrix Perm = new BlockMsrMatrix(PermRow, M._RowPartitioning);

            for (int iRow = 0; iRow < ExternalRowsIndices.Count; iRow++)
            {
                Debug.Assert(M._RowPartitioning.IsInLocalRange(ExternalRowsIndices[iRow]) == false);
                Perm[iRow + PermRow.i0, ExternalRowsIndices[iRow]] = 1;
            }

#if TEST
            Perm.SaveToTextFileSparseDebug("Perm");
#endif
            return(BlockMsrMatrix.Multiply(Perm, M));
        }
        /// <summary>
        /// generates a masking of subblocks within a <see cref="MultigridMapping"/> according to <see cref="SubBlockSelector"/> <paramref name="sbs"/>
        /// enables applying mask onto matrices and vectors, which comply with this <see cref="MultigridMapping"/>.
        /// (e.g. sub matrix generation, sub vector extraction, etc.).
        /// The smallest unit are dg blocks.
        /// The masking operates on local blocks available on this proc per default,
        /// which can be exceeded to external blocks by providing external rows: <paramref name="ExtRows"/>.
        /// Ghost cells (covert by <see cref="BoSSS.Foundation.Grid.ILogicalCellData.NoOfExternalCells"/>) can be acquired by <see cref="GetAllExternalRows"/>.
        /// </summary>
        /// <param name="sbs">sub block selection defined by dev</param>
        /// <param name="ExtRows">external rows collected from other MPI-processes on this proc</param>
        public BlockMask(SubBlockSelector sbs, BlockMsrMatrix ExtRows = null)
        {
            m_map     = sbs.GetMapping;
            m_ExtRows = ExtRows;
            m_includeExternalCells = (ExtRows != null) && m_map.MpiSize > 1;
            BMLoc = new BlockMaskLoc(sbs);

            if (m_includeExternalCells)
            {
                BMExt = new BlockMaskExt(sbs, BMLoc.LocalDOF);
                SetThisShitUp(new BlockMaskBase[] { BMLoc, BMExt });
            }
            else
            {
                SetThisShitUp(new BlockMaskBase[] { BMLoc });
            }
#if Debug
            CheckIndices();
#endif
        }