Example #1
0
            internal override IEnumerable <List <int> > GetBlocking(MultigridOperator op)
            {
                var MgMap = op.Mapping;

                //if(!M.RowPartitioning.Equals(MgMap.Partitioning))
                //    throw new ArgumentException("Row partitioning mismatch.");
                //if(!M.ColPartition.Equals(MgMap.Partitioning))
                //    throw new ArgumentException("Column partitioning mismatch.");

                var ag = MgMap.AggGrid;

                int JComp = ag.iLogicalCells.NoOfLocalUpdatedCells; // number of local cells

                int[]      xadj   = new int[JComp + 1];
                List <int> adjncy = new List <int>();

                for (int j = 0; j < JComp; j++)
                {
                    int[] neigh_j = ag.iLogicalCells.CellNeighbours[j];
                    foreach (int jNeigh in neigh_j)
                    {
                        //adjncy.AddRange(neigh_j);
                        if (jNeigh < JComp)
                        {
                            adjncy.Add(jNeigh);
                        }
                        else
                        {
                            //Console.WriteLine("Skipping external cell");
                        }
                    }
                    xadj[j + 1] = xadj[j] + neigh_j.Length;
                }

                int MPIrank, MPIsize;

                MPI.Wrappers.csMPI.Raw.Comm_Rank(MPI.Wrappers.csMPI.Raw._COMM.WORLD, out MPIrank);
                MPI.Wrappers.csMPI.Raw.Comm_Size(MPI.Wrappers.csMPI.Raw._COMM.WORLD, out MPIsize);
                //if (MPIrank == 1)
                //    NoOfParts = 1;
                //Debugger.Launch();

                int[] part = new int[JComp];
                {
                    if (NoOfPartsPerProcess > 1)
                    {
                        int   ncon    = 1;
                        int   edgecut = 0;
                        int[] options = null; //new int[] { 0, 0, 0, 0, 0 };
                        METIS.PartGraphKway(
                            ref JComp, ref ncon,
                            xadj,
                            adjncy.ToArray(),
                            null,
                            null,
                            null,
                            ref NoOfPartsPerProcess,
                            null,
                            null,
                            options,
                            ref edgecut,
                            part);
                    }
                    else
                    {
                        part.SetAll(0);
                    }
                }

                {
                    var _Blocks = NoOfPartsPerProcess.ForLoop(i => new List <int>((int)Math.Ceiling(1.1 * JComp / NoOfPartsPerProcess)));
                    for (int j = 0; j < JComp; j++)
                    {
                        _Blocks[part[j]].Add(j);
                    }

                    return(_Blocks);
                }
            }
        /// <summary>
        /// Computes a grid partitioning (which cell should be on which processor)
        /// using the serial METIS library -- work is only done on MPi rank 0.
        /// </summary>
        /// <param name="cellWeightsLocal">
        /// If not null, defines the weight associted with each cell on the current process
        /// </param>
        /// <param name="noOfPartitioningsToChooseFrom">
        /// Tells METIS to compute
        /// </param>
        /// <returns>
        /// Index: local cell index, content: MPI Processor rank;<br/>
        /// This is the suggestion
        /// of ParMETIS for the grid partitioning:
        /// For each local cell index, the returned array contains the MPI
        /// process rank where the cell should be placed.
        /// </returns>
        public int[] ComputePartitionMETIS(int[] cellWeightsLocal = null, int noOfPartitioningsToChooseFrom = 1)
        {
            using (new FuncTrace()) {
                int size = this.Size;
                int rank = this.MyRank;

                if (size == 1)
                {
                    return(new int[NoOfUpdateCells]);
                }

                if (this.NumberOfCells_l > int.MaxValue)
                {
                    throw new Exception(String.Format(
                                            "Grid contains more than {0} cells and can thus not be partitioned using METIS. Use ParMETIS instead.",
                                            int.MaxValue));
                }
                int J = (rank == 0) ? this.NumberOfCells : 0;

                // Setup communication; all send to rank 0
                SerialisationMessenger sms = new SerialisationMessenger(csMPI.Raw._COMM.WORLD);
                if (rank != 0)
                {
                    sms.SetCommPath(0);
                }
                sms.CommitCommPaths();

                // Assemble adjacency lists on rank 0
                IEnumerable <Neighbour>[] neighboursGlobal = new IEnumerable <Neighbour> [J];
                {
                    IEnumerable <Neighbour>[] neighboursLocal = GetCellNeighbourship(IncludeBcCells: false).Take(NoOfUpdateCells).ToArray();
                    if (rank == 0)
                    {
                        int localOffset = m_CellPartitioning.GetI0Offest(rank);
                        int localLength = m_CellPartitioning.GetLocalLength(rank);

                        for (int i = 0; i < localLength; i++)
                        {
                            neighboursGlobal[localOffset + i] = neighboursLocal[i];
                        }
                    }
                    else
                    {
                        sms.Transmitt(0, neighboursLocal);
                    }

                    while (sms.GetNext(out int senderRank, out IEnumerable <Neighbour>[] neighbours))
                    {
                        int localOffset = m_CellPartitioning.GetI0Offest(senderRank);
                        int localLength = m_CellPartitioning.GetLocalLength(senderRank);

                        if (neighbours.Length != localLength)
                        {
                            throw new Exception();
                        }

                        for (int i = 0; i < localLength; i++)
                        {
                            neighboursGlobal[localOffset + i] = neighbours[i];
                        }
                    }
                }

                // Gather global weights on rank 0
                int[] cellWeightsGlobal = null;
                if (cellWeightsLocal != null)
                {
                    cellWeightsGlobal = new int[J];
                    if (rank == 0)
                    {
                        int localOffset = m_CellPartitioning.GetI0Offest(rank);
                        int localLength = m_CellPartitioning.GetLocalLength(rank);

                        for (int i = 0; i < localLength; i++)
                        {
                            cellWeightsGlobal[localOffset + i] = cellWeightsLocal[i];
                        }
                    }
                    else
                    {
                        sms.Transmitt(0, cellWeightsLocal);
                    }

                    while (sms.GetNext(out int senderRank, out int[] cellWeights))
                    {
                        int localOffset = m_CellPartitioning.GetI0Offest(senderRank);
                        int localLength = m_CellPartitioning.GetLocalLength(senderRank);

                        if (cellWeights.Length != localLength)
                        {
                            throw new Exception();
                        }

                        for (int i = 0; i < localLength; i++)
                        {
                            cellWeightsGlobal[localOffset + i] = cellWeights[i];
                        }
                    }
                }

                int[] globalResult = new int[J];
                if (rank == 0)
                {
                    int[]      xadj   = new int[J + 1];
                    List <int> adjncy = new List <int>(J * m_RefElements[0].NoOfFaces);
                    for (int j = 0; j < J; j++)
                    {
                        var cNj = neighboursGlobal[j];
                        int E   = cNj.Count();

                        for (int e = 0; e < E; e++)
                        {
                            var NN = cNj.ElementAt(e);

                            if (NN.Neighbour_GlobalIndex >= 0 &&
                                !NN.IsPeriodicNeighbour)
                            {
                                adjncy.Add((int)NN.Neighbour_GlobalIndex);
                            }
                        }
                        xadj[j + 1] = adjncy.Count;
                    }

                    // Call METIS
                    int nparts = size;
                    Debug.Assert((cellWeightsGlobal == null) == (cellWeightsLocal == null));
                    int ncon   = 1;  // One weight per vertex/cell
                    int objval = -1; // Value of the objective function at return time

                    int[] Options = new int[METIS.METIS_NOPTIONS];
                    Options[(int)METIS.OptionCodes.METIS_OPTION_NCUTS]   = noOfPartitioningsToChooseFrom; // 5 cuts
                    Options[(int)METIS.OptionCodes.METIS_OPTION_NITER]   = 10;                            // This is the default refinement iterations
                    Options[(int)METIS.OptionCodes.METIS_OPTION_UFACTOR] = 30;                            // Maximum imbalance of 3 percent (this is the default kway clustering)

                    METIS.ReturnCodes status = (METIS.ReturnCodes)METIS.PartGraphKway(
                        nvtxs: ref J,
                        ncon: ref ncon,
                        xadj: xadj,
                        adjncy: adjncy.ToArray(),
                        vwgt: cellWeightsGlobal, // if null, METIS assumes all have weight 1
                        vsize: null,             // No information about communication size
                        adjwgt: null,            // No edge weights
                        nparts: ref nparts,
                        tpwgts: null,            // No weights for partition constraints
                        ubvec: null,             // No imbalance tolerance for constraints
                        options: Options,
                        objval: ref objval,
                        part: globalResult);

                    if (status != METIS.ReturnCodes.METIS_OK)
                    {
                        throw new Exception(String.Format(
                                                "Error partitioning the mesh. METIS reported {0}",
                                                status));
                    }

                    int[] CountCheck = new int[size];
                    int   J2         = this.NumberOfCells;
                    for (int i = 0; i < J2; i++)
                    {
                        CountCheck[globalResult[i]]++;
                    }
                    for (int rnk = 0; rnk < size; rnk++)
                    {
                        if (CountCheck[rnk] <= 0)
                        {
                            throw new ApplicationException("METIS produced illegal partitioning - 0 cells on process " + rnk + ".");
                        }
                    }
                }

                int[] localLengths = new int[size];
                for (int p = 0; p < localLengths.Length; p++)
                {
                    localLengths[p] = this.CellPartitioning.GetLocalLength(p);
                }
                int[] localResult = globalResult.MPIScatterv(localLengths);

                return(localResult);
            }
        }