/// <summary>
        /// Determines if the specified cell is part of the specified patch
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="patch"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        private static bool CellInPatch(Cell cell, TransitionPatch patch)
        {
            if (cell == null)
            {
                return(false);
            }

            if (patch.AllCells.ContainsKey(cell.CellId))
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Grows a transition patch
        /// </summary>
        /// <param name="transitionedCells"></param>
        /// <param name="patchCells"></param>
        /// <param name="initiationCell"></param>
        /// <param name="patch"></param>
        /// <param name="transitionGroup"></param>
        /// <param name="iteration"></param>
        /// <param name="timestep"></param>
        /// <remarks></remarks>
        private void GrowTransitionPatch(
            Dictionary <int, Cell> transitionedCells, Dictionary <int, Cell> patchCells, Cell initiationCell,
            TransitionPatch patch, TransitionGroup transitionGroup, int iteration, int timestep)
        {
            double                 PatchSize   = 0.0;
            Queue <Cell>           PatchQueue  = new Queue <Cell>();
            Dictionary <int, Cell> QueuedCells = new Dictionary <int, Cell>();

            PatchQueue.Enqueue(initiationCell);
            QueuedCells.Add(initiationCell.CellId, initiationCell);

            while (PatchQueue.Count > 0)
            {
                Cell CurrentCell = PatchQueue.Dequeue();

                Debug.Assert(!patchCells.ContainsKey(CurrentCell.CellId));
                Debug.Assert(!patch.AllCells.ContainsKey(CurrentCell.CellId));

                patchCells.Add(CurrentCell.CellId, CurrentCell);
                patch.AllCells.Add(CurrentCell.CellId, CurrentCell);

                PatchSize += this.m_AmountPerCell;

                this.AddNeighboringPatchCell(transitionedCells, patchCells, QueuedCells, PatchQueue, this.GetCellNorth(CurrentCell), transitionGroup, iteration, timestep);
                this.AddNeighboringPatchCell(transitionedCells, patchCells, QueuedCells, PatchQueue, this.GetCellNortheast(CurrentCell), transitionGroup, iteration, timestep);
                this.AddNeighboringPatchCell(transitionedCells, patchCells, QueuedCells, PatchQueue, this.GetCellEast(CurrentCell), transitionGroup, iteration, timestep);
                this.AddNeighboringPatchCell(transitionedCells, patchCells, QueuedCells, PatchQueue, this.GetCellSoutheast(CurrentCell), transitionGroup, iteration, timestep);
                this.AddNeighboringPatchCell(transitionedCells, patchCells, QueuedCells, PatchQueue, this.GetCellSouth(CurrentCell), transitionGroup, iteration, timestep);
                this.AddNeighboringPatchCell(transitionedCells, patchCells, QueuedCells, PatchQueue, this.GetCellSouthwest(CurrentCell), transitionGroup, iteration, timestep);
                this.AddNeighboringPatchCell(transitionedCells, patchCells, QueuedCells, PatchQueue, this.GetCellWest(CurrentCell), transitionGroup, iteration, timestep);
                this.AddNeighboringPatchCell(transitionedCells, patchCells, QueuedCells, PatchQueue, this.GetCellNorthwest(CurrentCell), transitionGroup, iteration, timestep);
            }

            patch.Size = PatchSize;

            foreach (var PatchCell in patch.AllCells.Values)
            {
                if (this.IsPatchEdgeCell(PatchCell, patch))
                {
                    patch.EdgeCells.Add(PatchCell.CellId, PatchCell);
                }
            }

            Debug.Assert(patch.EdgeCells.Count() > 0);
            Debug.Assert(patch.AllCells.Count() > 0);
            Debug.Assert(patch.AllCells.Count() >= patch.EdgeCells.Count());
        }
        /// <summary>
        /// Updates the patch membership for the specified transition group and cell
        /// </summary>
        /// <param name="transitionGroupId"></param>
        /// <param name="cell"></param>
        /// <remarks>
        /// This function will also remove a patch if its cell collection becomes empty.
        /// </remarks>
        private void UpdateCellPatchMembership(int transitionGroupId, Cell cell)
        {
            TransitionGroup TransitionGroup = this.m_TransitionGroups[transitionGroupId];

            if (TransitionGroup.PatchPrioritization != null)
            {
                TransitionPatch Patch = null;

                if (
                    TransitionGroup.PatchPrioritization.PatchPrioritizationType == PatchPrioritizationType.Smallest ||
                    TransitionGroup.PatchPrioritization.PatchPrioritizationType == PatchPrioritizationType.SmallestEdgesOnly)
                {
                    Patch = TransitionGroup.PatchPrioritization.TransitionPatches.First();
                }
                else
                {
                    Patch = TransitionGroup.PatchPrioritization.TransitionPatches.Last();
                }

                if (Patch.AllCells.ContainsKey(cell.CellId))
                {
                    Patch.AllCells.Remove(cell.CellId);
                }

                if (Patch.EdgeCells.ContainsKey(cell.CellId))
                {
                    Patch.EdgeCells.Remove(cell.CellId);
                }

                if (
                    TransitionGroup.PatchPrioritization.PatchPrioritizationType == PatchPrioritizationType.LargestEdgesOnly ||
                    TransitionGroup.PatchPrioritization.PatchPrioritizationType == PatchPrioritizationType.SmallestEdgesOnly)
                {
                    if (Patch.EdgeCells.Count() == 0)
                    {
                        TransitionGroup.PatchPrioritization.TransitionPatches.Remove(Patch);
                    }
                }
                else if (Patch.AllCells.Count() == 0)
                {
                    Debug.Assert(Patch.EdgeCells.Count() == 0);
                    TransitionGroup.PatchPrioritization.TransitionPatches.Remove(Patch);
                }
            }
        }
        /// <summary>
        /// Determines if the specified cell is a edge cell in the specified patch
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="patch"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        private bool IsPatchEdgeCell(Cell cell, TransitionPatch patch)
        {
            if (!CellInPatch(this.GetCellNorth(cell), patch))
            {
                return(true);
            }

            if (!CellInPatch(this.GetCellNortheast(cell), patch))
            {
                return(true);
            }

            if (!CellInPatch(this.GetCellEast(cell), patch))
            {
                return(true);
            }

            if (!CellInPatch(this.GetCellSoutheast(cell), patch))
            {
                return(true);
            }

            if (!CellInPatch(this.GetCellSouth(cell), patch))
            {
                return(true);
            }

            if (!CellInPatch(this.GetCellSouthwest(cell), patch))
            {
                return(true);
            }

            if (!CellInPatch(this.GetCellWest(cell), patch))
            {
                return(true);
            }

            if (!CellInPatch(this.GetCellNorthwest(cell), patch))
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Selects a patch initiation cell
        /// </summary>
        /// <param name="transitionGroup"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        private Cell SelectPatchInitiationCell(TransitionGroup transitionGroup)
        {
            Debug.Assert(this.IsSpatial);

            PatchPrioritization    pp      = transitionGroup.PatchPrioritization;
            List <TransitionPatch> patches = pp.TransitionPatches;

            if (patches.Count == 0)
            {
                return(null);
            }

            TransitionPatch Patch = patches[0];

            if (pp.PatchPrioritizationType == PatchPrioritizationType.Largest ||
                pp.PatchPrioritizationType == PatchPrioritizationType.LargestEdgesOnly)
            {
                Patch = patches[patches.Count - 1];
            }

            if (pp.PatchPrioritizationType == PatchPrioritizationType.SmallestEdgesOnly ||
                pp.PatchPrioritizationType == PatchPrioritizationType.LargestEdgesOnly)
            {
                if (Patch.EdgeCells.ContainsKey(Patch.SeedCell.CellId))
                {
                    return(Patch.SeedCell);
                }
                else
                {
                    return(Patch.EdgeCells.Values.ElementAt(0));
                }
            }
            else
            {
                if (Patch.AllCells.ContainsKey(Patch.SeedCell.CellId))
                {
                    return(Patch.SeedCell);
                }
                else
                {
                    return(Patch.AllCells.Values.ElementAt(0));
                }
            }
        }
        /// <summary>
        /// Fills the transition patches for the specified transition group
        /// </summary>
        /// <param name="transitionedCells"></param>
        /// <param name="stratum"></param>
        /// <param name="transitionGroup"></param>
        /// <param name="iteration"></param>
        /// <param name="timestep"></param>
        /// <remarks></remarks>
        private void FillTransitionPatches(
            Dictionary <int, Cell> transitionedCells, Stratum stratum,
            TransitionGroup transitionGroup, int iteration, int timestep)
        {
            Debug.Assert(this.IsSpatial);

            if (transitionGroup.PatchPrioritization == null)
            {
                return;
            }

            Debug.Assert(transitionGroup.PatchPrioritization.TransitionPatches.Count == 0);

            Dictionary <int, Cell> patchCells = new Dictionary <int, Cell>();

            foreach (Cell SimulationCell in stratum.Cells.Values)
            {
                Debug.Assert(SimulationCell.StratumId != 0);
                Debug.Assert(SimulationCell.StateClassId != 0);

                if (patchCells.ContainsKey(SimulationCell.CellId) | transitionedCells.ContainsKey(SimulationCell.CellId))
                {
                    continue;
                }

                if (this.SelectTransitionPathway(SimulationCell, transitionGroup.TransitionGroupId, iteration, timestep) == null)
                {
                    continue;
                }

                TransitionPatch Patch = new TransitionPatch(SimulationCell);

                this.GrowTransitionPatch(transitionedCells, patchCells, SimulationCell, Patch, transitionGroup, iteration, timestep);

                transitionGroup.PatchPrioritization.TransitionPatches.Add(Patch);
            }

            transitionGroup.PatchPrioritization.TransitionPatches.Sort((TransitionPatch p1, TransitionPatch p2) =>
            {
                return(p1.Size.CompareTo(p2.Size));
            });
        }