Beispiel #1
0
            /// <summary>
            /// Creates an execution mask (volume mask) which only contains cells
            /// that are at least partly occupied by species
            /// <paramref name="speciesId"/>;
            /// </summary>
            /// <remarks>
            /// Note: The method is so complex because we do <b>not</b> want to
            /// consider the whole narrow-band because it may contain additional
            /// cells on the "other" side of the level set!
            /// </remarks>
            /// <param name="speciesId">
            /// The name of the species
            /// </param>
            /// <returns>
            /// A volume mask containing only cells with at least a portion of
            /// species <paramref name="speciesId"/>
            /// </returns>
            public CellMask GetSpeciesMask(SpeciesId speciesId)
            {
                if (m_SpeciesMask == null)
                {
                    m_SpeciesMask = new Dictionary <SpeciesId, CellMask>();
                }
                if (!m_SpeciesMask.ContainsKey(speciesId))
                {
                    int                J         = m_owner.m_gDat.Grid.NoOfUpdateCells;
                    BitArray           mask      = new BitArray(J);
                    LevelSetSignCode[] signCodes = m_owner.GetLevelSetSignCodes(speciesId);

                    if (signCodes.Length == 0)
                    {
                        throw new ArgumentException("Unknown species " + speciesId, "speciesName");
                    }

                    for (int jCell = 0; jCell < J; jCell++)
                    {
                        bool matchesOne = IsSpeciesPresentInCell(speciesId, jCell);

                        // mask[i] = matches would also do it but a set operation on
                        // a BitMask is heavier than this ugly additional if statement
                        if (matchesOne)
                        {
                            mask[jCell] = true;
                        }
                    }

                    m_SpeciesMask.Add(speciesId, new CellMask(m_owner.m_gDat, mask));
                }

                return(m_SpeciesMask[speciesId]);
            }
Beispiel #2
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();
            }
        }