Example #1
0
        //
        public static IEnumerable<Tuple<int, int>> FindAgglomeration(LevelSetTracker Tracker, SpeciesId spId, double AgglomerationThreshold,
            MultidimensionalArray CellVolumes, MultidimensionalArray edgeArea,
            bool AgglomerateNewborn, bool AgglomerateDeceased, bool ExceptionOnFailedAgglomeration,
            MultidimensionalArray[] oldCellVolumes, double[] oldTs__AgglomerationTreshold, double NewbornAndDecasedThreshold)
        {
            using (var tracer = new FuncTrace()) {
                MPICollectiveWatchDog.Watch();

                // init
                // =======

                GridData grdDat = Tracker.GridDat;
                int[,] Edge2Cell = grdDat.Edges.CellIndices;
                byte[] EdgeTags = grdDat.Edges.EdgeTags;
                var Cell2Edge = grdDat.Cells.Cells2Edges;
                int myMpiRank = Tracker.GridDat.MpiRank;
                int NoOfEdges = grdDat.Edges.Count;
                int Jup = grdDat.Cells.NoOfLocalUpdatedCells;
                int Jtot = grdDat.Cells.Count;
                Partitioning CellPart = Tracker.GridDat.CellPartitioning;
                int i0 = CellPart.i0;
                var GidxExt = Tracker.GridDat.Parallel.GlobalIndicesExternalCells;
                var GidxExt2Lidx = Tracker.GridDat.Parallel.Global2LocalIdx;
                //double[] RefVolumes = grdDat.Grid.RefElements.Select(Kref => Kref.Volume).ToArray();

                if (CellVolumes.GetLength(0) != Jtot)
                    throw new ArgumentException();
                if (edgeArea.GetLength(0) != NoOfEdges)
                    throw new ArgumentException();

                double EmptyEdgeTreshold = 1.0e-10; // edges with a measure blow or equal to this threshold are
                // considered to be 'empty', therefore they should not be used for agglomeration;
                //                                     there is, as always, an exception: if all inner edges which belong to a
                //                                     cell that should be agglomerated, the criterion mentioned above must be ignored.

                // determine agglomeration cells
                // ================================
                var _AccEdgesMask = new BitArray(NoOfEdges);
                var AgglomCellsBitmask = new BitArray(Jup);
                var _AgglomCellsEdges = new BitArray(NoOfEdges);
                //var _AllowedEdges =  new BitArray(NoOfEdges); _AllowedEdges.SetAll(true); // AllowedEdges.GetBitMask();
                var AgglomerationPairs = new List<CellAgglomerator.AgglomerationPair>();
                {

                    // mask for the cells in which we -- potentially -- want to do agglomeration
                    var AggCandidates = Tracker.Regions.GetSpeciesMask(spId).GetBitMaskWithExternal().CloneAs();

                    // pass 1: determine agglomeration sources
                    // ---------------------------------------

                    List<int> AgglomCellsList = new List<int>();
                    {
                        // for the present timestep
                        // - - - - - - - - - - - - -

                        CellMask suspectsForAgg = Tracker.Regions.GetCutCellMask().Intersect(Tracker.Regions.GetSpeciesMask(spId));
                        foreach (int jCell in suspectsForAgg.ItemEnum) {
                            double totVol = grdDat.Cells.GetCellVolume(jCell);

                            double spcVol = CellVolumes[jCell];
                            double alpha = AgglomerationThreshold;
                            spcVol = Math.Max(spcVol, 0.0);
                            double frac = spcVol / totVol;
                            //if (!(frac >= 0.0 && frac <= 1.00000001))
                            //    throw new Exception("Strange volume fraction: cell " + jCell + ", species" + spId.ToString() + ", volume fraction =" + frac + ".");
                            frac = Math.Min(1.0, Math.Max(0.0, frac));

                            if (frac < alpha) {
                                // cell 'jCell' should be agglomerated to some other cell
                                AgglomCellsBitmask[jCell] = true;
                                AgglomCellsList.Add(jCell);
                            }
                        }
                    }

                    int NoTimeLev = oldTs__AgglomerationTreshold != null ? oldTs__AgglomerationTreshold.Length : 0;
                    if (NoTimeLev > 0) {
                        // for the previous timestep
                        // - - - - - - - - - - - - -

                        //ushort[][] PrevRegions = new ushort[NoTimeLev][];
                        //CellMask suspectsForAgg = Tracker.PreviousRegions.GetSpeciesMask(spId);
                        //CellMask[] suspectsForAgg = new CellMask[NoTimeLev];
                        //for(int itl = 0; itl < NoTimeLev; itl++) {
                        //    PrevRegions[itl] = Tracker.RegionsHistory[-itl].LevelSetRegionsCode;
                        //    suspectsForAgg[itl] = Tracker.RegionsHistory[-itl].GetSpeciesMask(spId);
                        //}

                        LevelSetSignCode[] signCodes = Tracker.GetLevelSetSignCodes(spId);
                        int NoOfLevSets = Tracker.LevelSets.Count;

                        for (int iTimeLev = 0; iTimeLev < NoTimeLev; iTimeLev++) {
                            CellMask suspectsForAgg = Tracker.RegionsHistory[-iTimeLev].GetSpeciesMask(spId);
                            foreach (int jCell in suspectsForAgg.ItemEnum) {

                                double totVol = grdDat.Cells.GetCellVolume(jCell);
                                double spcVol = oldCellVolumes[iTimeLev][jCell];
                                double alpha = oldTs__AgglomerationTreshold[iTimeLev];
                                spcVol = Math.Max(spcVol, 0.0);
                                double frac = spcVol / totVol;
                                frac = Math.Min(1.0, Math.Max(0.0, frac));

                                if (frac < alpha) {
                                    // cell 'jCell' should be agglomerated to some other cell
                                    if (!AgglomCellsBitmask[jCell]) {
                                        AgglomCellsBitmask[jCell] = true;
                                        AgglomCellsList.Add(jCell);
                                    }
                                }
                            }
                        }
                    }

                    if (AgglomerateNewborn) {

                        for (int j = 0; j < Jup; j++) {
                            double vol = grdDat.Cells.GetCellVolume(j);
                            double volNewFrac_j = Math.Max(CellVolumes[j], 0.0) / vol;
                            volNewFrac_j = Math.Min(1.0, Math.Max(0.0, volNewFrac_j));

                            if (volNewFrac_j > NewbornAndDecasedThreshold) {
                                for (int nTs = 0; nTs < oldCellVolumes.Length; nTs++) {

                                    double volOldFrac_j = Math.Max(oldCellVolumes[nTs][j], 0.0) / vol;
                                    volOldFrac_j = Math.Min(1.0, Math.Max(0.0, volOldFrac_j));
                                    if (volOldFrac_j <= NewbornAndDecasedThreshold) {
                                        // cell exists at new time, but not at some old time -> newborn

                                        int jNewbornCell = j;
                                        AggCandidates[jNewbornCell] = false;
                                        if (!AgglomCellsBitmask[jNewbornCell]) {
                                            AgglomCellsList.Add(jNewbornCell);
                                            AgglomCellsBitmask[jNewbornCell] = true;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (AgglomerateDeceased) {

                        for (int j = 0; j < Jup; j++) {
                            double vol = grdDat.Cells.GetCellVolume(j);
                            double volNewFrac_j = Math.Max(CellVolumes[j], 0.0) / vol;
                            volNewFrac_j = Math.Min(1.0, Math.Max(0.0, volNewFrac_j));

                            if (volNewFrac_j <= NewbornAndDecasedThreshold) {
                                for (int nTs = 0; nTs < oldCellVolumes.Length; nTs++) {

                                    double volOldFrac_j = Math.Max(oldCellVolumes[nTs][j], 0.0) / vol;
                                    volOldFrac_j = Math.Min(1.0, Math.Max(0.0, volOldFrac_j));
                                    if (volOldFrac_j > NewbornAndDecasedThreshold) {
                                        // cell does not exist at new time, but at some old time -> decased

                                        int jNewbornCell = j;
                                        AggCandidates[jNewbornCell] = false;
                                        if (!AgglomCellsBitmask[jNewbornCell]) {
                                            AgglomCellsList.Add(jNewbornCell);
                                            AgglomCellsBitmask[jNewbornCell] = true;
                                        }
                                    }

                                }
                            }

                        }

                    }
                    //*/

                    /*
                    if (AgglomerateNewborn || AgglomerateDeceased) {
                        //CellMask oldSpeciesCells = this.Tracker.LevelSetData.PreviousSubGrids[spId].VolumeMask;
                        CellMask newSpeciesCells = Tracker.Regions.GetSpeciesMask(spId);

                        // only accept cells with positive volume (new species cells)
                        BitArray newSpeciesCellsBitmask = newSpeciesCells.GetBitMask().CloneAs();
                        Debug.Assert(newSpeciesCellsBitmask.Count == Jup);
                        for (int j = 0; j < Jup; j++) {
                            double vol = grdDat.Cells.GetCellVolume(j);
                            double volFrac_j = Math.Max(CellVolumes[j], 0.0) / vol;
                            volFrac_j = Math.Min(1.0, Math.Max(0.0, volFrac_j));

                            if (volFrac_j > NewbornAndDecasedThreshold) {
                                Debug.Assert(newSpeciesCellsBitmask[j] == true);
                            } else {
                                newSpeciesCellsBitmask[j] = false;
                            }
                        }
                        newSpeciesCells = new CellMask(grdDat, newSpeciesCellsBitmask);

                        // only accept cells with positive volume (old species cells)
                        BitArray oldSpeciesCellsBitmask = new BitArray(Jup); //  oldSpeciesCells.GetBitMask().CloneAs();
                        //Debug.Assert(oldSpeciesCellsBitmask.Count == Jup);
                        for (int nTs = 0; nTs < oldCellVolumes.Length; nTs++) {
                            MultidimensionalArray _oldCellVolumes = oldCellVolumes[nTs];

                            for (int j = 0; j < Jup; j++) {
                                double vol = grdDat.Cells.GetCellVolume(j);
                                double volFrac_j = Math.Max(_oldCellVolumes[j],0.0) / vol;
                                volFrac_j = Math.Min(1.0, Math.Max(0.0, volFrac_j));

                                if (volFrac_j > NewbornAndDecasedThreshold) {
                                    //Debug.Assert(oldSpeciesCellsBitmask[j] == true);
                                    oldSpeciesCellsBitmask[j] = true;
                                } else {
                                    //oldSpeciesCellsBitmask[j] = false;
                                }
                            }
                        }
                        var oldSpeciesCells = new CellMask(grdDat, oldSpeciesCellsBitmask);

                        // find newborn and decased
                        CellMask newBorn = newSpeciesCells.Except(oldSpeciesCells);
                        CellMask deceased = oldSpeciesCells.Except(newSpeciesCells);

                        foreach (int jNewbornCell in newBorn.ItemEnum) {
                            AggCandidates[jNewbornCell] = false;
                            if (!AgglomCellsBitmask[jNewbornCell]) {
                                AgglomCellsList.Add(jNewbornCell);
                                AgglomCellsBitmask[jNewbornCell] = true;
                            }
                            //Console.WriteLine("  agglom newborn: " + jNewbornCell);
                        }

                        foreach (int jDeceasedCell in deceased.ItemEnum) {
                            AggCandidates[jDeceasedCell] = false;
                            if (!AgglomCellsBitmask[jDeceasedCell]) {
                                AgglomCellsList.Add(jDeceasedCell);
                                AgglomCellsBitmask[jDeceasedCell] = true;
                            }
                            //Console.WriteLine("  agglom deceased: " + jDeceasedCell);
                        }

                    }
                    //*/

                    // pass 2: determine agglomeration targets
                    // ---------------------------------------

                    foreach (int jCell in AgglomCellsList) {
                        var Cell2Edge_jCell = Cell2Edge[jCell];

                        // cell 'jCell' should be agglomerated to some other cell
                        Debug.Assert(AgglomCellsBitmask[jCell] == true);

                        double frac_neigh_max = -1.0;
                        int e_max = -1;
                        int jEdge_max = int.MinValue;
                        int jCellNeigh_max = int.MinValue;

                        int NoOfEdges_4_jCell = Cell2Edge_jCell.Length;

                        // determine if there is a non-empty edge which connects cell 'jCell'
                        // to some other cell
                        bool NonEmptyEdgeAvailable = false;
                        for (int e = 0; e < NoOfEdges_4_jCell; e++) { // loop over faces/neighbour cells...
                            int iEdge = Cell2Edge_jCell[e];
                            int OtherCell;
                            if (iEdge < 0) {
                                // cell 'jCell' is the OUT-cell of edge 'iEdge'
                                OtherCell = 0;
                                iEdge *= -1;
                            } else {
                                OtherCell = 1;
                            }
                            iEdge--;
                            int jCellNeigh = Edge2Cell[iEdge, OtherCell];

                            double EdgeArea_iEdge = edgeArea[iEdge];
                            if (jCellNeigh >= 0 && EdgeArea_iEdge > EmptyEdgeTreshold)
                                NonEmptyEdgeAvailable = true;
                        }

                        for (int e = 0; e < NoOfEdges_4_jCell; e++) { // loop over faces/neighbour cells...
                            int iEdge = Cell2Edge_jCell[e];
                            int OtherCell, ThisCell;
                            if (iEdge < 0) {
                                // cell 'jCell' is the OUT-cell of edge 'iEdge'
                                OtherCell = 0;
                                ThisCell = 1;
                                iEdge *= -1;
                            } else {
                                OtherCell = 1;
                                ThisCell = 0;
                            }
                            iEdge--;

                            double EdgeArea_iEdge = edgeArea[iEdge];

                            _AgglomCellsEdges[iEdge] = true;

                            Debug.Assert(Edge2Cell[iEdge, ThisCell] == jCell);

                            int jCellNeigh = Edge2Cell[iEdge, OtherCell];
                            if (jCellNeigh < 0 || EdgeTags[iEdge] >= GridCommons.FIRST_PERIODIC_BC_TAG || (EdgeArea_iEdge <= EmptyEdgeTreshold && NonEmptyEdgeAvailable)) {
                                // boundary edge, no neighbour for agglomeration
                                Debug.Assert(Edge2Cell[iEdge, ThisCell] == jCell, "sollte aber so sein");
                                continue;
                            }

                            if (!AggCandidates[jCellNeigh])
                                // not suitable for agglomeration
                                continue;

                            // volume fraction of neighbour cell
                            double spcVol_neigh = CellVolumes[jCellNeigh];
                            //double totVol_neigh = RefVolumes[grdDat.Cells.GetRefElementIndex(jCellNeigh)];
                            double totVol_neigh = grdDat.Cells.GetCellVolume(jCellNeigh);
                            double frac_neigh = spcVol_neigh / totVol_neigh;

                            // max?
                            if (frac_neigh > frac_neigh_max) {
                                frac_neigh_max = frac_neigh;
                                e_max = e;
                                jCellNeigh_max = jCellNeigh;
                                jEdge_max = iEdge;
                            }
                        }

                        if (jCellNeigh_max < 0) {
                            string message = ("Agglomeration failed - no candidate for agglomeration found");
                            if (ExceptionOnFailedAgglomeration)
                                throw new Exception(message);
                            else
                                Console.WriteLine(message);
                        } else {
                            _AccEdgesMask[jEdge_max] = true;

                            int jCellNeighRank;
                            if (jCellNeigh_max < Jup) {
                                jCellNeighRank = myMpiRank;
                            } else {
                                jCellNeighRank = CellPart.FindProcess(GidxExt[jCellNeigh_max - Jup]);
                            }

                            AgglomerationPairs.Add(new CellAgglomerator.AgglomerationPair() {
                                jCellTarget = jCellNeigh_max,
                                jCellSource = jCell,
                                OwnerRank4Target = jCellNeighRank,
                                OwnerRank4Source = myMpiRank
                            });
                        }
                    }
                }

                // store & return
                // ================
                return AgglomerationPairs.Select(pair => new Tuple<int, int>(pair.jCellSource, pair.jCellTarget)).ToArray();
            }
        }
Example #2
0
        /// <summary>
        /// performs a parallel inversion of this permutation
        /// </summary>
        /// <returns></returns>
        public Permutation Invert()
        {
            using (new FuncTrace()) {
                Permutation inv         = new Permutation(this);
                int         localLength = m_Partition.LocalLength; //m_LocalLengths[m_Master.MyRank];
                int         size;
                MPI.Wrappers.csMPI.Raw.Comm_Size(m_Comm, out size);


                inv.m_Values = new long[localLength];
                long myi0Offset = m_Partition.i0; //m_i0Offset[m_Master.MyRank];

                Many2ManyMessenger <PermutationEntry> m2m = new Many2ManyMessenger <PermutationEntry>(m_Comm);
                int[] NoOfItemsToSent = new int[size];


                // calc i0's for each process
                // ==========================

                long[] i0 = new long[size + 1];
                for (int i = 1; i <= size; i++)
                {
                    i0[i] = i0[i - 1] + m_Partition.GetLocalLength(i - 1);// m_LocalLengths[i - 1];
                }
                // do local inversion and collect items
                // ====================================
                List <PermutationEntry>[] itemsToSend = new List <PermutationEntry> [size];
                for (int p = 0; p < size; p++)
                {
                    itemsToSend[p] = new List <PermutationEntry>();
                }

                for (int i = 0; i < localLength; i++)
                {
                    // decide wether inversion of entry i is local or has to be transmitted ...
                    if (m_Values[i] >= myi0Offset && m_Values[i] < (myi0Offset + localLength))
                    {
                        // local
                        inv.m_Values[this.m_Values[i] - myi0Offset] = i + myi0Offset;
                    }
                    else
                    {
                        // transmit

                        // find target processor
                        int targProc = m_Partition.FindProcess(m_Values[i]);

                        NoOfItemsToSent[targProc]++;

                        // collect item
                        PermutationEntry pe;
                        pe.Index   = myi0Offset + i;
                        pe.PermVal = m_Values[i];
                        itemsToSend[targProc].Add(pe);
                    }
                }


                // setup messenger
                // ===============

                for (int i = 0; i < size; i++)
                {
                    if (NoOfItemsToSent[i] > 0)
                    {
                        m2m.SetCommPath(i, NoOfItemsToSent[i]);
                    }
                }
                m2m.CommitCommPaths();

                // transmit data
                // =============

                //csMPI.Raw.Barrier(csMPI.Raw.MPI_COMM_WORLD);
                //Console.WriteLine("one");
                //csMPI.Raw.Barrier(csMPI.Raw.MPI_COMM_WORLD);
                //Console.WriteLine("two");
                //csMPI.Raw.Barrier(csMPI.Raw.MPI_COMM_WORLD);
                //Console.WriteLine("three");

                m2m.StartTransmission(1);

                for (int p = 0; p < size; p++)
                {
                    if (NoOfItemsToSent[p] <= 0)
                    {
                        continue;
                    }

                    //Many2ManyMessenger.Buffer<PermEntry> sndbuf = new Many2ManyMessenger.Buffer<PermEntry>(m2m, false, p);
                    PermutationEntry[] items = itemsToSend[p].ToArray();
                    m2m.SendBuffers(p).CopyFrom(items, 0);

                    m2m.TransmittData(p);
                }

                m2m.FinishBlocking();

                // invert received items
                // =====================


                for (int p = 0; p < size; p++)
                {
                    Many2ManyMessenger <PermutationEntry> .Buffer rcvbuf = m2m.ReceiveBuffers(p);
                    if (rcvbuf == null)
                    {
                        continue; // no data from process no. p
                    }
                    int cnt = rcvbuf.Count;

                    PermutationEntry[] items = new PermutationEntry[cnt];
                    rcvbuf.CopyTo(items, 0);


                    for (int i = 0; i < cnt; i++)
                    {
                        inv.m_Values[items[i].PermVal - myi0Offset] = items[i].Index;
                    }
                }


                // finalize
                // ========
                m2m.Dispose();
                return(inv);
            }
        }