/// <summary>
        /// Calculate the distance between two cohorts in multi-dimensional trait space (body mass, adult mass, juvenile mass)
        /// </summary>
        /// <param name="Cohort1">The first cohort to calculate distance to</param>
        /// <param name="Cohort2">The cohort to compare to</param>
        /// <returns>The relative distance in trait space</returns>
        public double CalculateDistance(Cohort Cohort1, Cohort Cohort2)
        {
            double AdultMassDistance = Math.Abs(Cohort1.AdultMass - Cohort2.AdultMass)/Cohort1.AdultMass;
            double JuvenileMassDistance = Math.Abs(Cohort1.JuvenileMass - Cohort2.JuvenileMass)/Cohort1.JuvenileMass;
            double CurrentMassDistance = Math.Abs(Cohort1.IndividualBodyMass - Cohort2.IndividualBodyMass)/Cohort1.IndividualBodyMass;

            return Math.Sqrt((AdultMassDistance * AdultMassDistance) + (JuvenileMassDistance * JuvenileMassDistance) +
                (CurrentMassDistance * CurrentMassDistance));
        }
        /// <summary>
        /// Run responsive dispersal
        /// </summary>
        /// <param name="cellIndices">The longitudinal and latitudinal indices of the current grid cell</param>
        /// <param name="gridForDispersal">The model grid to run dispersal for</param>
        /// <param name="cohortToDisperse">The cohort for which to apply the dispersal process</param>
        /// <param name="actingCohortFunctionalGroup">The functional group index of the acting cohort</param>
        /// <param name="actingCohortNumber">The position of the acting cohort within the functional group in the array of grid cell cohorts</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunDispersal(uint[] cellIndices, ModelGrid gridForDispersal, Cohort cohortToDisperse, 
            int actingCohortFunctionalGroup, int actingCohortNumber, uint currentMonth)
        {
            // Starvation driven dispersal takes precedence over density driven dispersal (i.e. a cohort can't do both). Also, the delta
            // arrays only allow each cohort to perform one type of dispersal each time step
            bool CohortDispersed = false;

            // Check for starvation-driven dispersal
            CohortDispersed = CheckStarvationDispersal(gridForDispersal, cellIndices[0], cellIndices[1], cohortToDisperse, actingCohortFunctionalGroup, actingCohortNumber);

            if (!CohortDispersed)
            {
                // Check for density driven dispersal
                CheckDensityDrivenDispersal(gridForDispersal, cellIndices[0], cellIndices[1], cohortToDisperse, actingCohortFunctionalGroup, actingCohortNumber);
            }
        }
Ejemplo n.º 3
0
 public static Madingley.Common.Cohort ConvertCohortData(Cohort cohort)
 {
     return new Madingley.Common.Cohort(
         cohort.FunctionalGroupIndex,
         (int)cohort.BirthTimeStep,
         (int)cohort.MaturityTimeStep,
         cohort.CohortID.Select(cs => (int)cs).ToArray(),
         cohort.JuvenileMass,
         cohort.AdultMass,
         cohort.IndividualBodyMass,
         cohort.IndividualReproductivePotentialMass,
         cohort.MaximumAchievedBodyMass,
         cohort.CohortAbundance,
         cohort.Merged,
         cohort.ProportionTimeActive,
         cohort.TrophicIndex,
         cohort.LogOptimalPreyBodySizeRatio);
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Run diffusive dispersal
        /// </summary>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="gridForDispersal">The model grid to run dispersal for</param>
        /// <param name="cohortToDisperse">The cohort for which to run the dispersal process for</param>
        /// <param name="actingCohortFunctionalGroup">The functional group index of the acting cohort</param>
        /// <param name="actingCohortNumber">The position of the cohort within the functional group in the array of grid cell cohorts</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunDispersal(uint[] cellIndices, ModelGrid gridForDispersal, Cohort cohortToDisperse,
                                 int actingCohortFunctionalGroup, int actingCohortNumber, uint currentMonth)
        {
            // Calculate dispersal speed for the cohort
            double DispersalSpeed = CalculateDispersalSpeed(cohortToDisperse.IndividualBodyMass);

            // A double to indicate whether or not the cohort has dispersed, and if it has dispersed, where to
            double CohortDispersed = 0;

            // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step
            uint ExitDirection  = new uint();
            uint EntryDirection = new uint();

            ExitDirection = 9999;

            // Get the probability of dispersal
            double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, cellIndices[0], cellIndices[1], DispersalSpeed);

            // Check to see if it does disperse
            CohortDispersed = CheckForDispersal(DispersalArray[0]);

            // If it does, check to see where it will end up
            if (CohortDispersed > 0)
            {
                // Check to see if the direction is actually dispersable
                uint[] DestinationCell = CellToDisperseTo(gridForDispersal, cellIndices[0], cellIndices[1], DispersalArray, CohortDispersed, DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                if (DestinationCell[0] < 999999)
                {
                    // Update the delta array of cohorts
                    gridForDispersal.DeltaFunctionalGroupDispersalArray[cellIndices[0], cellIndices[1]].Add((uint)actingCohortFunctionalGroup);
                    gridForDispersal.DeltaCohortNumberDispersalArray[cellIndices[0], cellIndices[1]].Add((uint)actingCohortNumber);

                    // Update the delta array of cells to disperse to
                    gridForDispersal.DeltaCellToDisperseToArray[cellIndices[0], cellIndices[1]].Add(DestinationCell);

                    // Update the delta array of exit and entry directions
                    gridForDispersal.DeltaCellExitDirection[cellIndices[0], cellIndices[1]].Add(ExitDirection);
                    gridForDispersal.DeltaCellEntryDirection[cellIndices[0], cellIndices[1]].Add(EntryDirection);
                }
            }
        }
        /// <summary>
        /// Run diffusive dispersal
        /// </summary>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="gridForDispersal">The model grid to run dispersal for</param>
        /// <param name="cohortToDisperse">The cohort for which to run the dispersal process for</param>
        /// <param name="actingCohortFunctionalGroup">The functional group index of the acting cohort</param>
        /// <param name="actingCohortNumber">The position of the cohort within the functional group in the array of grid cell cohorts</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunDispersal(uint[] cellIndices, ModelGrid gridForDispersal, Cohort cohortToDisperse,
            int actingCohortFunctionalGroup, int actingCohortNumber, uint currentMonth)
        {
            // Calculate dispersal speed for the cohort         
            double DispersalSpeed = CalculateDispersalSpeed(cohortToDisperse.IndividualBodyMass);

            // A double to indicate whether or not the cohort has dispersed, and if it has dispersed, where to
            double CohortDispersed = 0;

            // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step
            uint ExitDirection = new uint();
            uint EntryDirection = new uint();
            ExitDirection = 9999;

            // Get the probability of dispersal
            double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, cellIndices[0], cellIndices[1], DispersalSpeed);

            // Check to see if it does disperse
            CohortDispersed = CheckForDispersal(DispersalArray[0]);

            // If it does, check to see where it will end up
            if (CohortDispersed > 0)
            {
                // Check to see if the direction is actually dispersable
                uint[] DestinationCell = CellToDisperseTo(gridForDispersal, cellIndices[0], cellIndices[1], DispersalArray, CohortDispersed, DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                if (DestinationCell[0] < 999999)
                {
                    // Update the delta array of cohorts
                    gridForDispersal.DeltaFunctionalGroupDispersalArray[cellIndices[0], cellIndices[1]].Add((uint)actingCohortFunctionalGroup);
                    gridForDispersal.DeltaCohortNumberDispersalArray[cellIndices[0], cellIndices[1]].Add((uint)actingCohortNumber);

                    // Update the delta array of cells to disperse to
                    gridForDispersal.DeltaCellToDisperseToArray[cellIndices[0], cellIndices[1]].Add(DestinationCell);

                    // Update the delta array of exit and entry directions
                    gridForDispersal.DeltaCellExitDirection[cellIndices[0], cellIndices[1]].Add(ExitDirection);
                    gridForDispersal.DeltaCellEntryDirection[cellIndices[0], cellIndices[1]].Add(EntryDirection);
                }
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Generate new cohorts from reproductive potential mass
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment of the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param>
        /// <param name="partial">Thread-locked variables</param>
        public void RunReproduction(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                    int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> >
                                    deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                    uint currentTimestep, ProcessTracker tracker, ref ThreadLockedParallelVariables partial)
        {
            // Check that the abundance in the cohort to produce is greater than or equal to zero
            Debug.Assert(_OffspringCohortAbundance >= 0.0, "Offspring abundance < 0");

            // Get the adult and juvenile masses of the cohort to produce
            double[] OffspringProperties = GetOffspringCohortProperties(gridCellCohorts, actingCohort,
                                                                        madingleyCohortDefinitions);

            // Update cohort abundance in case juvenile mass has been altered
            _OffspringCohortAbundance = (_OffspringCohortAbundance * gridCellCohorts[actingCohort].JuvenileMass) /
                                        OffspringProperties[0];

            //Create the offspring cohort
            Cohort OffspringCohort = new Cohort((byte)actingCohort[0],
                                                OffspringProperties[0],
                                                OffspringProperties[1],
                                                OffspringProperties[0],
                                                _OffspringCohortAbundance,
                                                (ushort)currentTimestep, ref partial.NextCohortIDThreadLocked);

            // Add the offspring cohort to the grid cell cohorts array
            gridCellCohorts[actingCohort[0]].Add(OffspringCohort);

            // If the cohort has never been merged with another cohort, then add it to the tracker for output as diagnostics
            if ((!gridCellCohorts[actingCohort].Merged) && tracker.TrackProcesses)
            {
                tracker.RecordNewCohort((uint)cellEnvironment["LatIndex"][0],
                                        (uint)cellEnvironment["LonIndex"][0], currentTimestep, _OffspringCohortAbundance,
                                        gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex);
            }

            // Subtract all of the reproductive potential mass of the parent cohort, which has been used to generate the new
            // cohort, from the delta reproductive potential mass
            deltas["reproductivebiomass"]["reproduction"] -= (gridCellCohorts[actingCohort].IndividualReproductivePotentialMass);
        }
        /// <summary>
        /// Generate new cohorts from reproductive potential mass
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment of the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param>
        /// <param name="partial">Thread-locked variables</param>
        public void RunReproduction(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
            int[] actingCohort, SortedList<string, double[]> cellEnvironment, Dictionary<string, Dictionary<string, double>>
            deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
            uint currentTimestep, ProcessTracker tracker, ref ThreadLockedParallelVariables partial)
        {
            // Check that the abundance in the cohort to produce is greater than or equal to zero
            Debug.Assert(_OffspringCohortAbundance >= 0.0, "Offspring abundance < 0");

            // Get the adult and juvenile masses of the cohort to produce
            double[] OffspringProperties = GetOffspringCohortProperties(gridCellCohorts, actingCohort,
                madingleyCohortDefinitions);

            // Update cohort abundance in case juvenile mass has been altered
            _OffspringCohortAbundance = (_OffspringCohortAbundance * gridCellCohorts[actingCohort].JuvenileMass) /
                OffspringProperties[0];

            //Create the offspring cohort
            Cohort OffspringCohort = new Cohort((byte)actingCohort[0],
                                                OffspringProperties[0],
                                                OffspringProperties[1],
                                                OffspringProperties[0],
                                                _OffspringCohortAbundance,
                                                (ushort)currentTimestep, ref partial.NextCohortIDThreadLocked);

            // Add the offspring cohort to the grid cell cohorts array
            gridCellCohorts[actingCohort[0]].Add(OffspringCohort);

            // If the cohort has never been merged with another cohort, then add it to the tracker for output as diagnostics
            if ((!gridCellCohorts[actingCohort].Merged) && tracker.TrackProcesses)
                tracker.RecordNewCohort((uint)cellEnvironment["LatIndex"][0],
                    (uint)cellEnvironment["LonIndex"][0], currentTimestep, _OffspringCohortAbundance,
                    gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex);

            // Subtract all of the reproductive potential mass of the parent cohort, which has been used to generate the new
            // cohort, from the delta reproductive potential mass
            deltas["reproductivebiomass"]["reproduction"] -= (gridCellCohorts[actingCohort].IndividualReproductivePotentialMass);

        }
Ejemplo n.º 8
0
        public static void ToJson(Newtonsoft.Json.JsonWriter jsonWriter, Cohort cohort)
        {
            Action <Newtonsoft.Json.JsonWriter, uint> WriteUInt = (jsonWriter2, value) =>
            {
                Madingley.Serialization.Common.Writer.WriteInt(jsonWriter2, (int)value);
            };

            jsonWriter.WriteStartObject();
            Madingley.Serialization.Common.Writer.PropertyInt(jsonWriter, "_BirthTimeStep", (int)cohort._BirthTimeStep);
            Madingley.Serialization.Common.Writer.PropertyInt(jsonWriter, "_MaturityTimeStep", (int)cohort._MaturityTimeStep);
            Madingley.Serialization.Common.Writer.PropertyInlineArray(jsonWriter, "_CohortID", cohort._CohortID, WriteUInt);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_JuvenileMass", cohort._JuvenileMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_AdultMass", cohort._AdultMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_IndividualBodyMass", cohort._IndividualBodyMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_IndividualReproductivePotentialMass", cohort._IndividualReproductivePotentialMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_MaximumAchievedBodyMass", cohort._MaximumAchievedBodyMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_CohortAbundance", cohort._CohortAbundance);
            Madingley.Serialization.Common.Writer.PropertyInt(jsonWriter, "_FunctionalGroupIndex", cohort._FunctionalGroupIndex);
            Madingley.Serialization.Common.Writer.PropertyBoolean(jsonWriter, "_Merged", cohort._Merged);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_ProportionTimeActive", cohort._ProportionTimeActive);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_TrophicIndex", cohort._TrophicIndex);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_LogOptimalPreyBodySizeRatio", cohort._LogOptimalPreyBodySizeRatio);
            jsonWriter.WriteEndObject();
        }
        public InputModelState(string outputPath, string filename, ModelGrid ecosystemModelGrid, List<uint[]> cellList)
        {
            //Set the input state flag to be true
            _InputState = true;

            // Construct the string required to access the file using Scientific Dataset
            string _ReadFileString = "msds:nc?file=input/ModelStates/" + filename +".nc&openMode=readOnly";

            // Open the data file using Scientific Dataset
            DataSet StateDataSet = DataSet.Open(_ReadFileString);

            float[] Latitude = StateDataSet.GetData<float[]>("Latitude");
            float[] Longitude = StateDataSet.GetData<float[]>("Longitude");
            float[] CohortFunctionalGroup = StateDataSet.GetData<float[]>("Cohort Functional Group");
            float[] Cohort = StateDataSet.GetData<float[]>("Cohort");

            float[] StockFunctionalGroup = StateDataSet.GetData<float[]>("Stock Functional Group");
            float[] Stock = StateDataSet.GetData<float[]>("Stock");

            // Check that the longitudes and latitudes in the input state match the cell environment
            for (int la = 0; la < Latitude.Length; la++)
            {
                Debug.Assert(ecosystemModelGrid.GetCellEnvironment((uint)la, 0)["Latitude"][0] == Latitude[la],
                    "Error: input-state grid doesn't match current model grid");
            }
            for (int lo = 0; lo < Longitude.Length; lo++)
            {
                Debug.Assert(ecosystemModelGrid.GetCellEnvironment(0, (uint)lo)["Longitude"][0] == Longitude[lo],
                    "Error: input-state grid doesn't match current model grid");
            }

            List<double[,,]> CohortJuvenileMass = new List<double[,,]>();
            List<double[,,]> CohortAdultMass = new List<double[,,]>();
            List<double[,,]> CohortIndividualBodyMass = new List<double[,,]>();
            List<double[,,]> CohortCohortAbundance = new List<double[,,]>();
            List<double[,,]> CohortLogOptimalPreyBodySizeRatio = new List<double[,,]>();
            List<double[,,]> CohortBirthTimeStep = new List<double[,,]>();
            List<double[,,]> CohortProportionTimeActive = new List<double[,,]>();
            List<double[,,]> CohortTrophicIndex = new List<double[,,]>();

            double[,,,] tempData = new double[Latitude.Length, Longitude.Length,
                CohortFunctionalGroup.Length, Cohort.Length];

            tempData = StateDataSet.GetData<double[,,,]>("CohortJuvenileMass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortJuvenileMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortJuvenileMass[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData<double[,,,]>("CohortAdultMass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortAdultMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortAdultMass[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData<double[,,,]>("CohortIndividualBodyMass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortIndividualBodyMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortIndividualBodyMass[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData<double[,,,]>("CohortCohortAbundance");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortCohortAbundance.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortCohortAbundance[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData<double[,,,]>("CohortLogOptimalPreyBodySizeRatio");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortLogOptimalPreyBodySizeRatio.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortLogOptimalPreyBodySizeRatio[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData<double[,,,]>("CohortBirthTimeStep");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortBirthTimeStep.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortBirthTimeStep[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData<double[,,,]>("CohortProportionTimeActive");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortProportionTimeActive.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortProportionTimeActive[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData<double[,,,]>("CohortTrophicIndex");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortTrophicIndex.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortTrophicIndex[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            _GridCellCohorts = new GridCellCohortHandler[Latitude.Length, Longitude.Length];

            long temp = 0;

            for (int cell = 0; cell < cellList.Count; cell++)
            {
                _GridCellCohorts[cellList[cell][0], cellList[cell][1]] = new GridCellCohortHandler(CohortFunctionalGroup.Length);

                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    _GridCellCohorts[cellList[cell][0], cellList[cell][1]][fg] = new List<Cohort>();
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        if (CohortCohortAbundance[(int)cellList[cell][0]][cellList[cell][1],fg,c] > 0.0)
                        {
                            Cohort TempCohort = new Cohort(
                                (byte)fg,
                                CohortJuvenileMass[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                CohortAdultMass[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                CohortIndividualBodyMass[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                CohortCohortAbundance[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                Math.Exp(CohortLogOptimalPreyBodySizeRatio[(int)cellList[cell][0]][cellList[cell][1], fg, c]),
                                Convert.ToUInt16(CohortBirthTimeStep[(int)cellList[cell][0]][cellList[cell][1], fg, c]),
                                CohortProportionTimeActive[(int)cellList[cell][0]][cellList[cell][1], fg, c], ref temp,
                                CohortTrophicIndex[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                false);

                            _GridCellCohorts[cellList[cell][0], cellList[cell][1]][fg].Add(TempCohort);
                        }
                    }
                }

            }

            CohortJuvenileMass.RemoveRange(0, CohortJuvenileMass.Count);
            CohortAdultMass.RemoveRange(0, CohortAdultMass.Count);
            CohortIndividualBodyMass.RemoveRange(0, CohortIndividualBodyMass.Count);
            CohortCohortAbundance.RemoveRange(0, CohortCohortAbundance.Count);
            CohortLogOptimalPreyBodySizeRatio.RemoveRange(0, CohortLogOptimalPreyBodySizeRatio.Count);
            CohortBirthTimeStep.RemoveRange(0, CohortBirthTimeStep.Count);
            CohortProportionTimeActive.RemoveRange(0, CohortProportionTimeActive.Count);
            CohortTrophicIndex.RemoveRange(0, CohortTrophicIndex.Count);

            List<double[,,]> StockIndividualBodyMass = new List<double[,,]>();
            List<double[,,]> StockTotalBiomass = new List<double[,,]>();

            double[,,,] tempData2 = new double[Latitude.Length, Longitude.Length,
                StockFunctionalGroup.Length,Stock.Length];

            tempData2 = StateDataSet.GetData<double[,,,]>("StockIndividualBodyMass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                StockIndividualBodyMass.Add(new double[Longitude.Length, StockFunctionalGroup.Length, Stock.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < StockFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Stock.Length; c++)
                    {
                        StockIndividualBodyMass[(int)cell[0]][cell[1], fg, c] = tempData2[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData2 = StateDataSet.GetData<double[,,,]>("StockTotalBiomass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                StockTotalBiomass.Add(new double[Longitude.Length, StockFunctionalGroup.Length, Stock.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < StockFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Stock.Length; c++)
                    {
                        StockTotalBiomass[(int)cell[0]][cell[1], fg, c] = tempData2[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            _GridCellStocks = new GridCellStockHandler[Latitude.Length, Longitude.Length];

            for (int cell = 0; cell < cellList.Count; cell++)
            {
                _GridCellStocks[cellList[cell][0], cellList[cell][1]] = new GridCellStockHandler(StockFunctionalGroup.Length);

                for (int fg = 0; fg < StockFunctionalGroup.Length; fg++)
                {
                    _GridCellStocks[cellList[cell][0], cellList[cell][1]][fg] = new List<Stock>();
                    for (int c = 0; c < Stock.Length; c++)
                    {
                        if (StockTotalBiomass[(int)cellList[cell][0]][cellList[cell][1], fg, c] > 0.0)
                        {
                            Stock TempStock = new Stock(
                                (byte)fg,
                                StockIndividualBodyMass[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                StockTotalBiomass[(int)cellList[cell][0]][cellList[cell][1], fg, c]);

                            _GridCellStocks[cellList[cell][0], cellList[cell][1]][fg].Add(TempStock);
                        }
                    }
                }

            }
        }
 public Cohort(Cohort c)
 {
     _FunctionalGroupIndex = c._FunctionalGroupIndex;
     _JuvenileMass = c._JuvenileMass;
     _AdultMass = c._AdultMass;
     _IndividualBodyMass = c._IndividualBodyMass;
     _CohortAbundance = c._CohortAbundance;
     _BirthTimeStep = c._BirthTimeStep;
     _MaturityTimeStep = c._MaturityTimeStep;
     _LogOptimalPreyBodySizeRatio = c._LogOptimalPreyBodySizeRatio;
     _MaximumAchievedBodyMass = c._MaximumAchievedBodyMass;
     _Merged = c._Merged;
     _TrophicIndex = c._TrophicIndex;
     _ProportionTimeActive = c._ProportionTimeActive;
     _CohortID = c.CohortID;
 }
        private bool CheckStarvationDispersal(ModelGrid gridForDispersal, uint latIndex, uint lonIndex, Cohort cohortToDisperse, int functionalGroup, int cohortNumber)
        {
            // A boolean to check whether a cohort has dispersed
            bool CohortHasDispersed = false;

            // Check for starvation driven dispersal
            // What is the present body mass of the cohort?
            // Note that at present we are just tracking starvation for adults
            double IndividualBodyMass = cohortToDisperse.IndividualBodyMass;
            double AdultMass = cohortToDisperse.AdultMass;

            // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step
            uint ExitDirection = new uint();
            uint EntryDirection = new uint();
            ExitDirection = 9999;

            // Assume a linear relationship between probability of dispersal and body mass loss, up to _StarvationDispersalBodyMassThreshold
            // at which point the cohort will try to disperse every time step
            if (IndividualBodyMass < AdultMass)
            {
                double ProportionalPresentMass = IndividualBodyMass / AdultMass;

                // If the body mass loss is greater than the starvation dispersal body mass threshold, then the cohort tries to disperse
                if (ProportionalPresentMass < _StarvationDispersalBodyMassThreshold)
                {
                    // Cohort tries to disperse
                    double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, latIndex, lonIndex, CalculateDispersalSpeed(AdultMass));
                    double CohortDispersed = CheckForDispersal(DispersalArray[0]);
                    if (CohortDispersed > 0)
                    {
                        uint[] DestinationCell = CellToDisperseTo(gridForDispersal, latIndex, lonIndex, DispersalArray, DispersalArray[0], DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                        // Update the delta array of cells to disperse to, if the cohort moves
                        if (DestinationCell[0] < 999999)
                        {
                            // Update the delta array of cohorts
                            gridForDispersal.DeltaFunctionalGroupDispersalArray[latIndex, lonIndex].Add((uint)functionalGroup);
                            gridForDispersal.DeltaCohortNumberDispersalArray[latIndex, lonIndex].Add((uint)cohortNumber);

                            // Update the delta array of cells to disperse to
                            gridForDispersal.DeltaCellToDisperseToArray[latIndex, lonIndex].Add(DestinationCell);

                            // Update the delta array of exit and entry directions
                            gridForDispersal.DeltaCellExitDirection[latIndex, lonIndex].Add(ExitDirection);
                            gridForDispersal.DeltaCellEntryDirection[latIndex, lonIndex].Add(EntryDirection);
                        }
                    }

                    // Note that regardless of whether or not it succeeds, if a cohort tries to disperse, it is counted as having dispersed for 
                    // the purposes of not then allowing it to disperse based on its density.
                    CohortHasDispersed = true;
                }

                // Otherwise, the cohort has a chance of trying to disperse proportional to its mass loss
                else
                {
                    // Cohort tries to disperse with a particular probability
                    // Draw a random number
                    if (((1.0 - ProportionalPresentMass) / (1.0 - _StarvationDispersalBodyMassThreshold)) > RandomNumberGenerator.GetUniform())
                    {
                        // Cohort tries to disperse
                        double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, latIndex, lonIndex, CalculateDispersalSpeed(AdultMass));
                        double CohortDispersed = CheckForDispersal(DispersalArray[0]);
                        if (CohortDispersed > 0)
                        {
                            uint[] DestinationCell = CellToDisperseTo(gridForDispersal, latIndex, lonIndex, DispersalArray, DispersalArray[0], DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                            // Update the delta array of cells to disperse to, if the cohort moves
                            if (DestinationCell[0] < 999999)
                            {
                                // Update the delta array of cohorts
                                gridForDispersal.DeltaFunctionalGroupDispersalArray[latIndex, lonIndex].Add((uint)functionalGroup);
                                gridForDispersal.DeltaCohortNumberDispersalArray[latIndex, lonIndex].Add((uint)cohortNumber);

                                // Update the delta array of cells to disperse to
                                gridForDispersal.DeltaCellToDisperseToArray[latIndex, lonIndex].Add(DestinationCell);

                                // Update the delta array of exit and entry directions
                                gridForDispersal.DeltaCellExitDirection[latIndex, lonIndex].Add(ExitDirection);
                                gridForDispersal.DeltaCellEntryDirection[latIndex, lonIndex].Add(EntryDirection);
                            }
                        }

                        CohortHasDispersed = true;
                    }
                }

            }
            return CohortHasDispersed;
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Generate new cohorts from reproductive potential mass
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment of the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param>
        /// <param name="partial">Thread-locked variables</param>
        /// <param name="iteroparous">Whether the acting cohort is iteroparous, as opposed to semelparous</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunReproductionEvents(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                          int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> >
                                          deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                          uint currentTimestep, ProcessTracker tracker, ref ThreadLockedParallelVariables partial, bool iteroparous, uint currentMonth)
        {
            // Adult non-reproductive biomass lost by semelparous organisms
            double AdultMassLost;

            // Offspring cohort abundance
            double _OffspringCohortAbundance;

            // Mass ratio of body mass + reproductive mass to adult body mass
            double CurrentMassRatio;

            // Individual body mass including change this time step as a result of other ecological processes
            double BodyMassIncludingChangeThisTimeStep;

            // Offspring juvenile and adult body masses
            double[] OffspringJuvenileAndAdultBodyMasses = new double[2];

            // Offspring cohort
            Cohort OffspringCohort;

            // Individual reproductive mass including change this time step as a result of other ecological processes
            double ReproductiveMassIncludingChangeThisTimeStep;


            // Calculate the biomass of an individual in this cohort including changes this time step from other ecological processes
            BodyMassIncludingChangeThisTimeStep = 0.0;

            foreach (var Biomass in deltas["biomass"])
            {
                // Add the delta biomass to net biomass
                BodyMassIncludingChangeThisTimeStep += Biomass.Value;
            }

            BodyMassIncludingChangeThisTimeStep += gridCellCohorts[actingCohort].IndividualBodyMass;

            // Calculate the reproductive biomass of an individual in this cohort including changes this time step from other ecological processes
            ReproductiveMassIncludingChangeThisTimeStep = 0.0;

            foreach (var ReproBiomass in deltas["reproductivebiomass"])
            {
                // Add the delta reproductive biomass to net biomass
                ReproductiveMassIncludingChangeThisTimeStep += ReproBiomass.Value;
            }

            ReproductiveMassIncludingChangeThisTimeStep += gridCellCohorts[actingCohort].IndividualReproductivePotentialMass;

            // Get the current ratio of total individual mass (including reproductive potential) to adult body mass
            CurrentMassRatio = (BodyMassIncludingChangeThisTimeStep + ReproductiveMassIncludingChangeThisTimeStep) / gridCellCohorts[actingCohort].AdultMass;

            // Must have enough mass to hit reproduction threshold criterion, and either (1) be in breeding season, or (2) be a marine cell (no breeding season in marine cells)
            if ((CurrentMassRatio > _MassRatioThreshold) && ((cellEnvironment["Breeding Season"][currentMonth] == 1.0) || ((cellEnvironment["Realm"][0] == 2.0))))
            {
                // Iteroparous and semelparous organisms have different strategies
                if (iteroparous)
                {
                    // Iteroparous organisms do not allocate any of their current non-reproductive biomass to reproduction
                    AdultMassLost = 0.0;

                    // Calculate the number of offspring that could be produced given the reproductive potential mass of individuals
                    _OffspringCohortAbundance = gridCellCohorts[actingCohort].CohortAbundance * ReproductiveMassIncludingChangeThisTimeStep /
                                                gridCellCohorts[actingCohort].JuvenileMass;
                }
                else
                {
                    // Semelparous organisms allocate a proportion of their current non-reproductive biomass (including the effects of other ecological processes) to reproduction
                    AdultMassLost = _SemelparityAdultMassAllocation * BodyMassIncludingChangeThisTimeStep;

                    // Calculate the number of offspring that could be produced given the reproductive potential mass of individuals
                    _OffspringCohortAbundance = gridCellCohorts[actingCohort].CohortAbundance * (AdultMassLost + ReproductiveMassIncludingChangeThisTimeStep) /
                                                gridCellCohorts[actingCohort].JuvenileMass;
                }

                // Check that the abundance in the cohort to produce is greater than or equal to zero
                Debug.Assert(_OffspringCohortAbundance >= 0.0, "Offspring abundance < 0");

                // Get the adult and juvenile masses of the offspring cohort
                OffspringJuvenileAndAdultBodyMasses = GetOffspringCohortProperties(gridCellCohorts, actingCohort, madingleyCohortDefinitions);

                // Update cohort abundance in case juvenile mass has been altered through 'evolution'
                _OffspringCohortAbundance = (_OffspringCohortAbundance * gridCellCohorts[actingCohort].JuvenileMass) / OffspringJuvenileAndAdultBodyMasses[0];

                double TrophicIndex;
                switch (madingleyCohortDefinitions.GetTraitNames("nutrition source", actingCohort[0]))
                {
                case "herbivore":
                    TrophicIndex = 2;
                    break;

                case "omnivore":
                    TrophicIndex = 2.5;
                    break;

                case "carnivore":
                    TrophicIndex = 3;
                    break;

                default:
                    Debug.Fail("Unexpected nutrition source trait value when assigning trophic index");
                    TrophicIndex = 0.0;
                    break;
                }

                // Create the offspring cohort
                OffspringCohort = new Cohort((byte)actingCohort[0], OffspringJuvenileAndAdultBodyMasses[0], OffspringJuvenileAndAdultBodyMasses[1], OffspringJuvenileAndAdultBodyMasses[0],
                                             _OffspringCohortAbundance, Math.Exp(gridCellCohorts[actingCohort].LogOptimalPreyBodySizeRatio),
                                             (ushort)currentTimestep, gridCellCohorts[actingCohort].ProportionTimeActive, ref partial.NextCohortIDThreadLocked, TrophicIndex, tracker.TrackProcesses);

                // Add the offspring cohort to the grid cell cohorts array
                gridCellCohorts[actingCohort[0]].Add(OffspringCohort);

                // If track processes has been specified then add the new cohort to the process tracker
                if (tracker.TrackProcesses)
                {
                    tracker.RecordNewCohort((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                            currentTimestep, _OffspringCohortAbundance, gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex,
                                            gridCellCohorts[actingCohort].CohortID, (uint)partial.NextCohortIDThreadLocked);
                }

                // Subtract all of the reproductive potential mass of the parent cohort, which has been used to generate the new
                // cohort, from the delta reproductive potential mass and delta adult body mass
                deltas["reproductivebiomass"]["reproduction"] -= ReproductiveMassIncludingChangeThisTimeStep;
                deltas["biomass"]["reproduction"]             -= AdultMassLost;
            }
            else
            {
                // Organism is not large enough, or it is not the breeding season, so take no action
            }
        }
        /// <summary>
        /// Generate new cohorts from reproductive potential mass
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment of the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param>
        /// <param name="partial">Thread-locked variables</param>
        /// <param name="iteroparous">Whether the acting cohort is iteroparous, as opposed to semelparous</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunReproductionEvents(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
            int[] actingCohort, SortedList<string, double[]> cellEnvironment, Dictionary<string, Dictionary<string, double>>
            deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
            uint currentTimestep, ProcessTracker tracker, ref ThreadLockedParallelVariables partial, bool iteroparous, uint currentMonth)
        {
            // Adult non-reproductive biomass lost by semelparous organisms
            double AdultMassLost;

            // Offspring cohort abundance
            double _OffspringCohortAbundance;

            // Mass ratio of body mass + reproductive mass to adult body mass
            double CurrentMassRatio;

            // Individual body mass including change this time step as a result of other ecological processes
            double BodyMassIncludingChangeThisTimeStep;

            // Offspring juvenile and adult body masses
            double[] OffspringJuvenileAndAdultBodyMasses = new double[2];

            // Offspring cohort
            Cohort OffspringCohort;

            // Individual reproductive mass including change this time step as a result of other ecological processes
            double ReproductiveMassIncludingChangeThisTimeStep;

            // Calculate the biomass of an individual in this cohort including changes this time step from other ecological processes  
            BodyMassIncludingChangeThisTimeStep = 0.0;

            foreach (var Biomass in deltas["biomass"])
            {
                // Add the delta biomass to net biomass
                BodyMassIncludingChangeThisTimeStep += Biomass.Value;

            }

            BodyMassIncludingChangeThisTimeStep += gridCellCohorts[actingCohort].IndividualBodyMass;

            // Calculate the reproductive biomass of an individual in this cohort including changes this time step from other ecological processes  
            ReproductiveMassIncludingChangeThisTimeStep = 0.0;

            foreach (var ReproBiomass in deltas["reproductivebiomass"])
            {
                // Add the delta reproductive biomass to net biomass
                ReproductiveMassIncludingChangeThisTimeStep += ReproBiomass.Value;
            }

            ReproductiveMassIncludingChangeThisTimeStep += gridCellCohorts[actingCohort].IndividualReproductivePotentialMass;

            // Get the current ratio of total individual mass (including reproductive potential) to adult body mass
            CurrentMassRatio = (BodyMassIncludingChangeThisTimeStep + ReproductiveMassIncludingChangeThisTimeStep) / gridCellCohorts[actingCohort].AdultMass;

            // Must have enough mass to hit reproduction threshold criterion, and either (1) be in breeding season, or (2) be a marine cell (no breeding season in marine cells)
            if ((CurrentMassRatio > _MassRatioThreshold) && ((cellEnvironment["Breeding Season"][currentMonth] == 1.0) || ((cellEnvironment["Realm"][0] == 2.0))))
            {
                // Iteroparous and semelparous organisms have different strategies
                if (iteroparous)
                {
                    // Iteroparous organisms do not allocate any of their current non-reproductive biomass to reproduction
                    AdultMassLost = 0.0;

                    // Calculate the number of offspring that could be produced given the reproductive potential mass of individuals
                    _OffspringCohortAbundance = gridCellCohorts[actingCohort].CohortAbundance * ReproductiveMassIncludingChangeThisTimeStep /
                        gridCellCohorts[actingCohort].JuvenileMass;
                }
                else
                {
                    // Semelparous organisms allocate a proportion of their current non-reproductive biomass (including the effects of other ecological processes) to reproduction
                    AdultMassLost = _SemelparityAdultMassAllocation * BodyMassIncludingChangeThisTimeStep;

                    // Calculate the number of offspring that could be produced given the reproductive potential mass of individuals
                    _OffspringCohortAbundance = gridCellCohorts[actingCohort].CohortAbundance * (AdultMassLost + ReproductiveMassIncludingChangeThisTimeStep) /
                        gridCellCohorts[actingCohort].JuvenileMass;
                }

                // Check that the abundance in the cohort to produce is greater than or equal to zero
                Debug.Assert(_OffspringCohortAbundance >= 0.0, "Offspring abundance < 0");

                // Get the adult and juvenile masses of the offspring cohort
                OffspringJuvenileAndAdultBodyMasses = GetOffspringCohortProperties(gridCellCohorts, actingCohort, madingleyCohortDefinitions);

                // Update cohort abundance in case juvenile mass has been altered through 'evolution'
                _OffspringCohortAbundance = (_OffspringCohortAbundance * gridCellCohorts[actingCohort].JuvenileMass) / OffspringJuvenileAndAdultBodyMasses[0];

                double TrophicIndex;
                switch (madingleyCohortDefinitions.GetTraitNames("nutrition source", actingCohort[0]))
                {
                    case "herbivore":
                        TrophicIndex = 2;
                        break;
                    case "omnivore":
                        TrophicIndex = 2.5;
                        break;
                    case "carnivore":
                        TrophicIndex = 3;
                        break;
                    default:
                        Debug.Fail("Unexpected nutrition source trait value when assigning trophic index");
                        TrophicIndex = 0.0;
                        break;
                }

                // Create the offspring cohort
                OffspringCohort = new Cohort((byte)actingCohort[0], OffspringJuvenileAndAdultBodyMasses[0], OffspringJuvenileAndAdultBodyMasses[1], OffspringJuvenileAndAdultBodyMasses[0],
                                                    _OffspringCohortAbundance, Math.Exp(gridCellCohorts[actingCohort].LogOptimalPreyBodySizeRatio),
                                                    (ushort)currentTimestep, gridCellCohorts[actingCohort].ProportionTimeActive, ref partial.NextCohortIDThreadLocked, TrophicIndex, tracker.TrackProcesses);

                // Add the offspring cohort to the grid cell cohorts array
                gridCellCohorts[actingCohort[0]].Add(OffspringCohort);

                // If track processes has been specified then add the new cohort to the process tracker 
                if (tracker.TrackProcesses)
                    tracker.RecordNewCohort((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                        currentTimestep, _OffspringCohortAbundance, gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex,
                        gridCellCohorts[actingCohort].CohortID, (uint)partial.NextCohortIDThreadLocked);

                // Subtract all of the reproductive potential mass of the parent cohort, which has been used to generate the new
                // cohort, from the delta reproductive potential mass and delta adult body mass
                deltas["reproductivebiomass"]["reproduction"] -= ReproductiveMassIncludingChangeThisTimeStep;
                deltas["biomass"]["reproduction"] -= AdultMassLost;

            }
            else
            {
                // Organism is not large enough, or it is not the breeding season, so take no action
            }

        }
        private void CheckDensityDrivenDispersal(ModelGrid gridForDispersal, uint latIndex, uint lonIndex, Cohort cohortToDisperse, int functionalGroup, int cohortNumber)
        {
            // Check the population density
            double NumberOfIndividuals = cohortToDisperse.CohortAbundance;

            // Get the cell area, in kilometres squared
            double CellArea = gridForDispersal.GetCellEnvironment(latIndex, lonIndex)["Cell Area"][0];

            // If below the density threshold
            if ((NumberOfIndividuals / CellArea) < _DensityThresholdScaling / cohortToDisperse.AdultMass)
            {
                // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step
                uint ExitDirection  = new uint();
                uint EntryDirection = new uint();
                ExitDirection = 9999;

                // Check to see if it disperses (based on the same movement scaling as used in diffusive movement)
                // Calculate dispersal speed for that cohort
                double DispersalSpeed = CalculateDispersalSpeed(cohortToDisperse.IndividualBodyMass);

                // Cohort tries to disperse
                double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, latIndex, lonIndex, CalculateDispersalSpeed(cohortToDisperse.AdultMass));

                double CohortDispersed = CheckForDispersal(DispersalArray[0]);

                if (CohortDispersed > 0)
                {
                    uint[] DestinationCell = CellToDisperseTo(gridForDispersal, latIndex, lonIndex, DispersalArray, DispersalArray[0], DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                    // Update the delta array of cells to disperse to, if the cohort moves
                    if (DestinationCell[0] < 999999)
                    {
                        // Update the delta array of cohorts
                        gridForDispersal.DeltaFunctionalGroupDispersalArray[latIndex, lonIndex].Add((uint)functionalGroup);
                        gridForDispersal.DeltaCohortNumberDispersalArray[latIndex, lonIndex].Add((uint)cohortNumber);

                        // Update the delta array of cells to disperse to
                        gridForDispersal.DeltaCellToDisperseToArray[latIndex, lonIndex].Add(DestinationCell);

                        // Update the delta array of exit and entry directions
                        gridForDispersal.DeltaCellExitDirection[latIndex, lonIndex].Add(ExitDirection);
                        gridForDispersal.DeltaCellEntryDirection[latIndex, lonIndex].Add(EntryDirection);
                    }
                }
            }
        }
        private bool CheckStarvationDispersal(ModelGrid gridForDispersal, uint latIndex, uint lonIndex, Cohort cohortToDisperse, int functionalGroup, int cohortNumber)
        {
            // A boolean to check whether a cohort has dispersed
            bool CohortHasDispersed = false;

            // Check for starvation driven dispersal
            // What is the present body mass of the cohort?
            // Note that at present we are just tracking starvation for adults
            double IndividualBodyMass = cohortToDisperse.IndividualBodyMass;
            double AdultMass          = cohortToDisperse.AdultMass;

            // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step
            uint ExitDirection  = new uint();
            uint EntryDirection = new uint();

            ExitDirection = 9999;

            // Assume a linear relationship between probability of dispersal and body mass loss, up to _StarvationDispersalBodyMassThreshold
            // at which point the cohort will try to disperse every time step
            if (IndividualBodyMass < AdultMass)
            {
                double ProportionalPresentMass = IndividualBodyMass / AdultMass;

                // If the body mass loss is greater than the starvation dispersal body mass threshold, then the cohort tries to disperse
                if (ProportionalPresentMass < _StarvationDispersalBodyMassThreshold)
                {
                    // Cohort tries to disperse
                    double[] DispersalArray  = CalculateDispersalProbability(gridForDispersal, latIndex, lonIndex, CalculateDispersalSpeed(AdultMass));
                    double   CohortDispersed = CheckForDispersal(DispersalArray[0]);
                    if (CohortDispersed > 0)
                    {
                        uint[] DestinationCell = CellToDisperseTo(gridForDispersal, latIndex, lonIndex, DispersalArray, DispersalArray[0], DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                        // Update the delta array of cells to disperse to, if the cohort moves
                        if (DestinationCell[0] < 999999)
                        {
                            // Update the delta array of cohorts
                            gridForDispersal.DeltaFunctionalGroupDispersalArray[latIndex, lonIndex].Add((uint)functionalGroup);
                            gridForDispersal.DeltaCohortNumberDispersalArray[latIndex, lonIndex].Add((uint)cohortNumber);

                            // Update the delta array of cells to disperse to
                            gridForDispersal.DeltaCellToDisperseToArray[latIndex, lonIndex].Add(DestinationCell);

                            // Update the delta array of exit and entry directions
                            gridForDispersal.DeltaCellExitDirection[latIndex, lonIndex].Add(ExitDirection);
                            gridForDispersal.DeltaCellEntryDirection[latIndex, lonIndex].Add(EntryDirection);
                        }
                    }

                    // Note that regardless of whether or not it succeeds, if a cohort tries to disperse, it is counted as having dispersed for
                    // the purposes of not then allowing it to disperse based on its density.
                    CohortHasDispersed = true;
                }

                // Otherwise, the cohort has a chance of trying to disperse proportional to its mass loss
                else
                {
                    // Cohort tries to disperse with a particular probability
                    // Draw a random number
                    if (((1.0 - ProportionalPresentMass) / (1.0 - _StarvationDispersalBodyMassThreshold)) > RandomNumberGenerator.GetUniform())
                    {
                        // Cohort tries to disperse
                        double[] DispersalArray  = CalculateDispersalProbability(gridForDispersal, latIndex, lonIndex, CalculateDispersalSpeed(AdultMass));
                        double   CohortDispersed = CheckForDispersal(DispersalArray[0]);
                        if (CohortDispersed > 0)
                        {
                            uint[] DestinationCell = CellToDisperseTo(gridForDispersal, latIndex, lonIndex, DispersalArray, DispersalArray[0], DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                            // Update the delta array of cells to disperse to, if the cohort moves
                            if (DestinationCell[0] < 999999)
                            {
                                // Update the delta array of cohorts
                                gridForDispersal.DeltaFunctionalGroupDispersalArray[latIndex, lonIndex].Add((uint)functionalGroup);
                                gridForDispersal.DeltaCohortNumberDispersalArray[latIndex, lonIndex].Add((uint)cohortNumber);

                                // Update the delta array of cells to disperse to
                                gridForDispersal.DeltaCellToDisperseToArray[latIndex, lonIndex].Add(DestinationCell);

                                // Update the delta array of exit and entry directions
                                gridForDispersal.DeltaCellExitDirection[latIndex, lonIndex].Add(ExitDirection);
                                gridForDispersal.DeltaCellEntryDirection[latIndex, lonIndex].Add(EntryDirection);
                            }
                        }

                        CohortHasDispersed = true;
                    }
                }
            }
            return(CohortHasDispersed);
        }
        /// <summary>
        /// Calculate the proportion of time for which this cohort could be active and assign it to the cohort's properties
        /// </summary>
        /// <param name="actingCohort">The Cohort for which proportion of time active is being calculated</param>
        /// <param name="cellEnvironment">The environmental information for current grid cell</param>
        /// <param name="madingleyCohortDefinitions">Functional group definitions and code to interrogate the cohorts in current grid cell</param>
        /// <param name="currentTimestep">Current timestep index</param>
        /// <param name="currentMonth">Current month</param>
        public void AssignProportionTimeActive(Cohort actingCohort, SortedList<string, double[]> cellEnvironment,
            FunctionalGroupDefinitions madingleyCohortDefinitions,uint currentTimestep, uint currentMonth)
        {
            double Realm = cellEnvironment["Realm"][0];

            //Only work on heterotroph cohorts
            if (madingleyCohortDefinitions.GetTraitNames("Heterotroph/Autotroph", actingCohort.FunctionalGroupIndex) == "heterotroph")
            {
                //Check if this is an endotherm or ectotherm
                Boolean Endotherm = madingleyCohortDefinitions.GetTraitNames("Endo/Ectotherm", actingCohort.FunctionalGroupIndex) == "endotherm";
                if (Endotherm)
                {
                    //Assumes the whole timestep is suitable for endotherms to be active - actual time active is therefore the proportion specified for this functional group.
                    actingCohort.ProportionTimeActive = madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("proportion suitable time active", actingCohort.FunctionalGroupIndex);
                }
                else
                {
                    //If ectotherm then use realm specific function
                    if (Realm == 1.0)
                    {
                        actingCohort.ProportionTimeActive = CalculateProportionTimeSuitableTerrestrial(cellEnvironment, currentMonth, Endotherm) *
                            madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("proportion suitable time active", actingCohort.FunctionalGroupIndex);
                    }
                    else
                    {
                        actingCohort.ProportionTimeActive = CalculateProportionTimeSuitableMarine(cellEnvironment, currentMonth, Endotherm) *
                            madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("proportion suitable time active", actingCohort.FunctionalGroupIndex);
                    }

                }

            }
        }
        /// <summary>
        /// Seed grid cell with cohorts, as specified in the model input files
        /// </summary>
        /// <param name="functionalGroups">The functional group definitions for cohorts in the grid cell</param>
        /// <param name="cellEnvironment">The environment in the grid cell</param>
        /// <param name="globalDiagnostics">A list of global diagnostic variables</param>
        /// <param name="nextCohortID">YThe unique ID to assign to the next cohort produced</param>
        /// <param name="tracking">boolean to indicate if cohorts are to be tracked in this model</param>
        /// <param name="totalCellTerrestrialCohorts">The total number of cohorts to be seeded in each terrestrial grid cell</param>
        /// <param name="totalCellMarineCohorts">The total number of cohorts to be seeded in each marine grid cell</param>
        /// <param name="DrawRandomly">Whether the model is set to use random draws</param>
        /// <param name="ZeroAbundance">Set this parameter to 'true' if you want to seed the cohorts with zero abundance</param>
        private void SeedGridCellCohorts(ref FunctionalGroupDefinitions functionalGroups, ref SortedList<string, double[]>
            cellEnvironment, SortedList<string, double> globalDiagnostics, Int64 nextCohortID, Boolean tracking, double totalCellTerrestrialCohorts, 
            double totalCellMarineCohorts, Boolean DrawRandomly, Boolean ZeroAbundance)
        {
            // Set the seed for the random number generator from the system time
            RandomNumberGenerator.SetSeedFromSystemTime();

            // StreamWriter tempsw = new StreamWriter("C://Temp//adult_juvenile_masses.txt");
            // tempsw.WriteLine("adult mass\tjuvenilemass");

            // Define local variables
            double CohortJuvenileMass;
            double CohortAdultMassRatio;
            double CohortAdultMass;
            double ExpectedLnAdultMassRatio;
            int[] FunctionalGroupsToUse;
            double NumCohortsThisCell;
            double TotalNewBiomass =0.0;

            // Get the minimum and maximum possible body masses for organisms in each functional group
            double[] MassMinima = functionalGroups.GetBiologicalPropertyAllFunctionalGroups("minimum mass");
            double[] MassMaxima = functionalGroups.GetBiologicalPropertyAllFunctionalGroups("maximum mass");
            string[] NutritionSource = functionalGroups.GetTraitValuesAllFunctionalGroups("nutrition source");

            double[] ProportionTimeActive = functionalGroups.GetBiologicalPropertyAllFunctionalGroups("proportion suitable time active");

            //Variable for altering the juvenile to adult mass ratio for marine cells when handling certain functional groups eg baleen whales
            double Scaling = 0.0;

            Int64 CohortIDIncrementer = nextCohortID;

            // Check which realm the cell is in
            if (cellEnvironment["Realm"][0] == 1.0)
            {
                // Get the indices of all terrestrial functional groups
                FunctionalGroupsToUse = functionalGroups.GetFunctionalGroupIndex("realm", "terrestrial", true);
                NumCohortsThisCell = totalCellTerrestrialCohorts;
            }
            else
            {
                // Get the indices of all marine functional groups
                FunctionalGroupsToUse = functionalGroups.GetFunctionalGroupIndex("realm", "marine", true);
                NumCohortsThisCell = totalCellMarineCohorts;
            }
            Debug.Assert(cellEnvironment["Realm"][0] > 0.0, "Missing realm for grid cell");

            if (NumCohortsThisCell > 0)
            {
                // Loop over all functional groups in the model
                for (int FunctionalGroup = 0; FunctionalGroup < functionalGroups.GetNumberOfFunctionalGroups(); FunctionalGroup++)
                {

                    // Create a new list to hold the cohorts in the grid cell
                    _GridCellCohorts[FunctionalGroup] = new List<Cohort>();

                    // If it is a functional group that corresponds to the current realm, then seed cohorts
                    if (FunctionalGroupsToUse.Contains(FunctionalGroup))
                    {
                        // Loop over the initial number of cohorts
                        double NumberOfCohortsInThisFunctionalGroup = 1.0;
                        if (!ZeroAbundance)
                        {
                            NumberOfCohortsInThisFunctionalGroup = functionalGroups.GetBiologicalPropertyOneFunctionalGroup("initial number of gridcellcohorts", FunctionalGroup);
                        }
                        for (int jj = 0; jj < NumberOfCohortsInThisFunctionalGroup; jj++)
                        {
                            // Check whether the model is set to randomly draw the body masses of new cohorts
                            if (DrawRandomly)
                            {
                                // Draw adult mass from a log-normal distribution with mean -6.9 and standard deviation 10.0,
                                // within the bounds of the minimum and maximum body masses for the functional group
                                CohortAdultMass = Math.Pow(10, (RandomNumberGenerator.GetUniform() * (Math.Log10(MassMaxima[FunctionalGroup]) - Math.Log10(50 * MassMinima[FunctionalGroup])) + Math.Log10(50 * MassMinima[FunctionalGroup])));

                                // Terrestrial and marine organisms have different optimal prey/predator body mass ratios
                                if (cellEnvironment["Realm"][0] == 1.0)
                                    // Optimal prey body size 10%
                                    OptimalPreyBodySizeRatio = Math.Max(0.01, RandomNumberGenerator.GetNormal(0.1, 0.02));
                                else
                                {
                                    if (functionalGroups.GetTraitNames("Diet", FunctionalGroup) == "allspecial")
                                    {
                                        // Note that for this group
                                        // it is actually (despite the name) not an optimal prey body size ratio, but an actual body size.
                                        // This is because it is invariant as the predator (filter-feeding baleen whale) grows.
                                        // See also the predation classes.
                                        OptimalPreyBodySizeRatio = Math.Max(0.00001, RandomNumberGenerator.GetNormal(0.0001, 0.1));
                                    }
                                    else
                                    {
                                        // Optimal prey body size or marine organisms is 10%
                                        OptimalPreyBodySizeRatio = Math.Max(0.01, RandomNumberGenerator.GetNormal(0.1, 0.02));
                                    }

                                }

                                // Draw from a log-normal distribution with mean 10.0 and standard deviation 5.0, then add one to obtain
                                // the ratio of adult to juvenile body mass, and then calculate juvenile mass based on this ratio and within the
                                // bounds of the minimum and maximum body masses for this functional group
                                if (cellEnvironment["Realm"][0] == 1.0)
                                {
                                    do
                                    {
                                        ExpectedLnAdultMassRatio = 2.24 + 0.13 * Math.Log(CohortAdultMass);
                                        CohortAdultMassRatio = 1.0 + RandomNumberGenerator.GetLogNormal(ExpectedLnAdultMassRatio, 0.5);
                                        CohortJuvenileMass = CohortAdultMass * 1.0 / CohortAdultMassRatio;
                                    } while (CohortAdultMass <= CohortJuvenileMass || CohortJuvenileMass < MassMinima[FunctionalGroup]);
                                }
                                // In the marine realm, have a greater difference between the adult and juvenile body masses, on average
                                else
                                {
                                    uint Counter = 0;
                                    Scaling = 0.2;
                                    // Use the scaling to deal with baleen whales not having such a great difference
                                    do
                                    {

                                        ExpectedLnAdultMassRatio = 2.5 + Scaling * Math.Log(CohortAdultMass);
                                        CohortAdultMassRatio = 1.0 + 10 * RandomNumberGenerator.GetLogNormal(ExpectedLnAdultMassRatio, 0.5);
                                        CohortJuvenileMass = CohortAdultMass * 1.0 / CohortAdultMassRatio;
                                        Counter++;
                                        if (Counter > 10)
                                        {
                                            Scaling -= 0.01;
                                            Counter = 0;
                                        }
                                    } while (CohortAdultMass <= CohortJuvenileMass || CohortJuvenileMass < MassMinima[FunctionalGroup]);
                                }
                            }
                            else
                            {
                                // Use the same seed for the random number generator every time
                                RandomNumberGenerator.SetSeed((uint)(jj + 1), (uint)((jj + 1) * 3));

                                // Draw adult mass from a log-normal distribution with mean -6.9 and standard deviation 10.0,
                                // within the bounds of the minimum and maximum body masses for the functional group
                                CohortAdultMass = Math.Pow(10, (RandomNumberGenerator.GetUniform() * (Math.Log10(MassMaxima[FunctionalGroup]) - Math.Log10(50 * MassMinima[FunctionalGroup])) + Math.Log10(50 * MassMinima[FunctionalGroup])));

                                OptimalPreyBodySizeRatio = Math.Max(0.01, RandomNumberGenerator.GetNormal(0.1, 0.02));

                                // Draw from a log-normal distribution with mean 10.0 and standard deviation 5.0, then add one to obtain
                                // the ratio of adult to juvenile body mass, and then calculate juvenile mass based on this ratio and within the
                                // bounds of the minimum and maximum body masses for this functional group
                                if (cellEnvironment["Realm"][0] == 1.0)
                                {
                                    do
                                    {
                                        ExpectedLnAdultMassRatio = 2.24 + 0.13 * Math.Log(CohortAdultMass);
                                        CohortAdultMassRatio = 1.0 + RandomNumberGenerator.GetLogNormal(ExpectedLnAdultMassRatio, 0.5);
                                        CohortJuvenileMass = CohortAdultMass * 1.0 / CohortAdultMassRatio;
                                    } while (CohortAdultMass <= CohortJuvenileMass || CohortJuvenileMass < MassMinima[FunctionalGroup]);

                                }
                                // In the marine realm, have a greater difference between the adult and juvenile body masses, on average
                                else
                                {
                                    do
                                    {
                                        ExpectedLnAdultMassRatio = 2.24 + 0.13 * Math.Log(CohortAdultMass);
                                        CohortAdultMassRatio = 1.0 + 10 * RandomNumberGenerator.GetLogNormal(ExpectedLnAdultMassRatio, 0.5);
                                        CohortJuvenileMass = CohortAdultMass * 1.0 / CohortAdultMassRatio;
                                    } while (CohortAdultMass <= CohortJuvenileMass || CohortJuvenileMass < MassMinima[FunctionalGroup]);
                                }
                            }

                            // An instance of Cohort to hold the new cohort
                            Cohort NewCohort;
                            //double NewBiomass = Math.Pow(0.2, (Math.Log10(CohortAdultMass))) * (1.0E9 * _CellEnvironment["Cell Area"][0]) / NumCohortsThisCell;
                            // 3000*(0.6^log(mass)) gives individual cohort biomass density in g ha-1
                            // * 100 to give g km-2
                            // * cell area to give g grid cell
                            //*3300/NumCohortsThisCell scales total initial biomass in the cell to some approximately reasonable mass
                            double NewBiomass = (3300 / NumCohortsThisCell) * 100 * 3000 *
                                Math.Pow(0.6, (Math.Log10(CohortJuvenileMass))) * (_CellEnvironment["Cell Area"][0]);
                            TotalNewBiomass += NewBiomass;
                            double NewAbund = 0.0;
                            if (!ZeroAbundance)
                            {
                                NewAbund = NewBiomass / CohortJuvenileMass;
                            }

                            /*
                            // TEMPORARILY MARINE ONLY
                            if (cellEnvironment["Realm"][0] == 1)
                            {
                                NewAbund = 0.0;
                            }
                            */
                            double TrophicIndex;
                            switch (NutritionSource[FunctionalGroup])
                            {
                                case "herbivore":
                                    TrophicIndex = 2;
                                    break;
                                case "omnivore":
                                    TrophicIndex = 2.5;
                                    break;
                                case "carnivore":
                                    TrophicIndex = 3;
                                    break;
                                default:
                                    Debug.Fail("Unexpected nutrition source trait value when assigning trophic index");
                                    TrophicIndex = 0.0;
                                    break;
                            }

                            // Initialise the new cohort with the relevant properties
                            NewCohort = new Cohort((byte)FunctionalGroup, CohortJuvenileMass, CohortAdultMass, CohortJuvenileMass, NewAbund,
                            OptimalPreyBodySizeRatio, (ushort)0, ProportionTimeActive[FunctionalGroup], ref CohortIDIncrementer,TrophicIndex, tracking);

                            // Add the new cohort to the list of grid cell cohorts
                            _GridCellCohorts[FunctionalGroup].Add(NewCohort);

                            // TEMPORARY
                            /*
                            // Check whether the model is set to randomly draw the body masses of new cohorts
                            if ((Longitude % 4 == 0) && (Latitude % 4 == 0))
                            {
                                if (DrawRandomly)
                                {
                                    CohortAdultMass = 100000;
                                    CohortJuvenileMass = 100000;
                                }
                                else
                                {
                                    CohortAdultMass = 100000;
                                    CohortJuvenileMass = 100000;
                                }

                                // An instance of Cohort to hold the new cohort
                                Cohort NewCohort;
                                double NewBiomass = (1.0E7 * _CellEnvironment["Cell Area"][0]) / NumCohortsThisCell;
                                double NewAbund = 0.0;
                                NewAbund = 3000;

                                // Initialise the new cohort with the relevant properties
                                NewCohort = new Cohort((byte)FunctionalGroup, CohortJuvenileMass, CohortAdultMass, CohortJuvenileMass, NewAbund,
                                    (ushort)0, ref nextCohortID, tracking);

                                // Add the new cohort to the list of grid cell cohorts
                                _GridCellCohorts[FunctionalGroup].Add(NewCohort);
                            }
                            */

                            // Incrememt the variable tracking the total number of cohorts in the model
                            globalDiagnostics["NumberOfCohortsInModel"]++;

                        }

                    }
                }

            }
            else
            {
                                // Loop over all functional groups in the model
                for (int FunctionalGroup = 0; FunctionalGroup < functionalGroups.GetNumberOfFunctionalGroups(); FunctionalGroup++)
                {

                    // Create a new list to hold the cohorts in the grid cell
                    _GridCellCohorts[FunctionalGroup] = new List<Cohort>();
                }
            }

            // tempsw.Dispose();
        }
        private void CheckDensityDrivenDispersal(ModelGrid gridForDispersal, uint latIndex, uint lonIndex, Cohort cohortToDisperse, int functionalGroup, int cohortNumber)
        {
            // Check the population density
            double NumberOfIndividuals = cohortToDisperse.CohortAbundance;

            // Get the cell area, in kilometres squared
            double CellArea = gridForDispersal.GetCellEnvironment(latIndex, lonIndex)["Cell Area"][0];

            // If below the density threshold
            if ((NumberOfIndividuals / CellArea) < _DensityThresholdScaling / cohortToDisperse.AdultMass)
            {
                // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step
                uint ExitDirection = new uint();
                uint EntryDirection = new uint();
                ExitDirection = 9999;

                // Check to see if it disperses (based on the same movement scaling as used in diffusive movement)
                // Calculate dispersal speed for that cohort
                double DispersalSpeed = CalculateDispersalSpeed(cohortToDisperse.IndividualBodyMass);

                // Cohort tries to disperse
                double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, latIndex, lonIndex, CalculateDispersalSpeed(cohortToDisperse.AdultMass));

                double CohortDispersed = CheckForDispersal(DispersalArray[0]);

                if (CohortDispersed > 0)
                {
                    uint[] DestinationCell = CellToDisperseTo(gridForDispersal, latIndex, lonIndex, DispersalArray, DispersalArray[0], DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                    // Update the delta array of cells to disperse to, if the cohort moves
                    if (DestinationCell[0] < 999999)
                    {
                        // Update the delta array of cohorts
                        gridForDispersal.DeltaFunctionalGroupDispersalArray[latIndex, lonIndex].Add((uint)functionalGroup);
                        gridForDispersal.DeltaCohortNumberDispersalArray[latIndex, lonIndex].Add((uint)cohortNumber);

                        // Update the delta array of cells to disperse to
                        gridForDispersal.DeltaCellToDisperseToArray[latIndex, lonIndex].Add(DestinationCell);

                        // Update the delta array of exit and entry directions
                        gridForDispersal.DeltaCellExitDirection[latIndex, lonIndex].Add(ExitDirection);
                        gridForDispersal.DeltaCellEntryDirection[latIndex, lonIndex].Add(EntryDirection);
                    }
                }
            }
        }
Ejemplo n.º 19
0
        public static void ToJson(Newtonsoft.Json.JsonWriter jsonWriter, Cohort cohort)
        {
            Action<Newtonsoft.Json.JsonWriter, uint> WriteUInt = (jsonWriter2, value) =>
            {
                Madingley.Serialization.Common.Writer.WriteInt(jsonWriter2, (int)value);
            };

            jsonWriter.WriteStartObject();
            Madingley.Serialization.Common.Writer.PropertyInt(jsonWriter, "_BirthTimeStep", (int)cohort._BirthTimeStep);
            Madingley.Serialization.Common.Writer.PropertyInt(jsonWriter, "_MaturityTimeStep", (int)cohort._MaturityTimeStep);
            Madingley.Serialization.Common.Writer.PropertyInlineArray(jsonWriter, "_CohortID", cohort._CohortID, WriteUInt);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_JuvenileMass", cohort._JuvenileMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_AdultMass", cohort._AdultMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_IndividualBodyMass", cohort._IndividualBodyMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_IndividualReproductivePotentialMass", cohort._IndividualReproductivePotentialMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_MaximumAchievedBodyMass", cohort._MaximumAchievedBodyMass);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_CohortAbundance", cohort._CohortAbundance);
            Madingley.Serialization.Common.Writer.PropertyInt(jsonWriter, "_FunctionalGroupIndex", cohort._FunctionalGroupIndex);
            Madingley.Serialization.Common.Writer.PropertyBoolean(jsonWriter, "_Merged", cohort._Merged);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_ProportionTimeActive", cohort._ProportionTimeActive);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_TrophicIndex", cohort._TrophicIndex);
            Madingley.Serialization.Common.Writer.PropertyDouble(jsonWriter, "_LogOptimalPreyBodySizeRatio", cohort._LogOptimalPreyBodySizeRatio);
            jsonWriter.WriteEndObject();
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Run advective dispersal
        /// </summary>
        /// <param name="cellIndex">The longitudinal and latitudinal indices of the focal grid cell</param>
        /// <param name="gridForDispersal">The model grid to run dispersal for</param>
        /// <param name="cohortToDisperse">The cohort to run dispersal for</param>
        /// <param name="actingCohortFunctionalGroup">The functional group index of the acting cohort</param>
        /// <param name="actingCohortNumber">The position of the acting cohort wihtin the functional group in the array of grid cell cohorts</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunDispersal(uint[] cellIndex, ModelGrid gridForDispersal, Cohort cohortToDisperse, int actingCohortFunctionalGroup,
                                 int actingCohortNumber, uint currentMonth)
        {
            // An array to hold the dispersal information
            double[] DispersalArray = new double[6];

            // A double to indicate whether or not the cohort has dispersed, and if it has dispersed, where to
            double CohortDispersed = 0;

            // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step
            uint ExitDirection  = new uint();
            uint EntryDirection = new uint();

            ExitDirection = 9999;

            // An array to hold the present cohort location for the intermediate steps that occur before the final dispersal this time step
            uint[] PresentLocation = { cellIndex[0], cellIndex[1] };

            // Get the u speed and the v speed from the cell data
            double uAdvectiveSpeed = gridForDispersal.GetEnviroLayer("uVel", currentMonth, PresentLocation[0], PresentLocation[1],
                                                                     out varExists);

            Debug.Assert(uAdvectiveSpeed != -9999);

            double vAdvectiveSpeed = gridForDispersal.GetEnviroLayer("vVel", currentMonth, PresentLocation[0], PresentLocation[1],
                                                                     out varExists);

            Debug.Assert(vAdvectiveSpeed != -9999);

            uAdvectiveSpeed = RescaleDispersalSpeed(uAdvectiveSpeed);
            vAdvectiveSpeed = RescaleDispersalSpeed(vAdvectiveSpeed);


            // Loop through a number of times proportional to the rescaled dispersal
            for (int mm = 0; mm < _AdvectionTimeStepsPerModelTimeStep; mm++)
            {
                // Get the probability of dispersal
                DispersalArray = CalculateDispersalProbability(gridForDispersal, PresentLocation[0], PresentLocation[1],
                                                               currentMonth, uAdvectiveSpeed, vAdvectiveSpeed);

                // Check to see if it does disperse
                CohortDispersed = CheckForDispersal(DispersalArray[0]);

                // If it does, check to see where it will end up
                if (CohortDispersed > 0)
                {
                    // Check to see if the direction is actually dispersable
                    uint[] DestinationCell = CellToDisperseTo(gridForDispersal, PresentLocation[0], PresentLocation[1],
                                                              DispersalArray, CohortDispersed, DispersalArray[4], DispersalArray[5], ref ExitDirection,
                                                              ref EntryDirection);

                    // If it is, go ahead and update the cohort location
                    if (DestinationCell[0] < 999999)
                    {
                        PresentLocation = DestinationCell;

                        // Get the u speed and the v speed from the cell data
                        uAdvectiveSpeed = gridForDispersal.GetEnviroLayer("uVel", currentMonth, PresentLocation[0],
                                                                          PresentLocation[1], out varExists);
                        vAdvectiveSpeed = gridForDispersal.GetEnviroLayer("vVel", currentMonth, PresentLocation[0],
                                                                          PresentLocation[1], out varExists);
                        uAdvectiveSpeed = RescaleDispersalSpeed(uAdvectiveSpeed);
                        vAdvectiveSpeed = RescaleDispersalSpeed(vAdvectiveSpeed);
                    }
                }
            }


            // Update the dipersal deltas for this cohort, if necessary
            if ((cellIndex[0] != PresentLocation[0]) || (cellIndex[1] != PresentLocation[1]))
            {
                // Update the delta array of cohorts
                gridForDispersal.DeltaFunctionalGroupDispersalArray[cellIndex[0], cellIndex[1]].Add((uint)actingCohortFunctionalGroup);
                gridForDispersal.DeltaCohortNumberDispersalArray[cellIndex[0], cellIndex[1]].Add((uint)actingCohortNumber);

                // Update the delta array of cells to disperse to
                gridForDispersal.DeltaCellToDisperseToArray[cellIndex[0], cellIndex[1]].Add(PresentLocation);

                // Update the delta array of exit and entry directions
                gridForDispersal.DeltaCellExitDirection[cellIndex[0], cellIndex[1]].Add(ExitDirection);
                gridForDispersal.DeltaCellEntryDirection[cellIndex[0], cellIndex[1]].Add(EntryDirection);
            }
        }
        public InputModelState(string outputPath, string filename, ModelGrid ecosystemModelGrid, List <uint[]> cellList)
        {
            //Set the input state flag to be true
            _InputState = true;

            // Construct the string required to access the file using Scientific Dataset
            string _ReadFileString = "msds:nc?file=input/ModelStates/" + filename + ".nc&openMode=readOnly";

            // Open the data file using Scientific Dataset
            DataSet StateDataSet = DataSet.Open(_ReadFileString);


            float[] Latitude              = StateDataSet.GetData <float[]>("Latitude");
            float[] Longitude             = StateDataSet.GetData <float[]>("Longitude");
            float[] CohortFunctionalGroup = StateDataSet.GetData <float[]>("Cohort Functional Group");
            float[] Cohort = StateDataSet.GetData <float[]>("Cohort");

            float[] StockFunctionalGroup = StateDataSet.GetData <float[]>("Stock Functional Group");
            float[] Stock = StateDataSet.GetData <float[]>("Stock");


            // Check that the longitudes and latitudes in the input state match the cell environment
            for (int la = 0; la < Latitude.Length; la++)
            {
                Debug.Assert(ecosystemModelGrid.GetCellEnvironment((uint)la, 0)["Latitude"][0] == Latitude[la],
                             "Error: input-state grid doesn't match current model grid");
            }
            for (int lo = 0; lo < Longitude.Length; lo++)
            {
                Debug.Assert(ecosystemModelGrid.GetCellEnvironment(0, (uint)lo)["Longitude"][0] == Longitude[lo],
                             "Error: input-state grid doesn't match current model grid");
            }

            List <double[, , ]> CohortJuvenileMass                = new List <double[, , ]>();
            List <double[, , ]> CohortAdultMass                   = new List <double[, , ]>();
            List <double[, , ]> CohortIndividualBodyMass          = new List <double[, , ]>();
            List <double[, , ]> CohortCohortAbundance             = new List <double[, , ]>();
            List <double[, , ]> CohortLogOptimalPreyBodySizeRatio = new List <double[, , ]>();
            List <double[, , ]> CohortBirthTimeStep               = new List <double[, , ]>();
            List <double[, , ]> CohortProportionTimeActive        = new List <double[, , ]>();
            List <double[, , ]> CohortTrophicIndex                = new List <double[, , ]>();

            double[,,,] tempData = new double[Latitude.Length, Longitude.Length,
                                              CohortFunctionalGroup.Length, Cohort.Length];

            tempData = StateDataSet.GetData <double[, , , ]>("CohortJuvenileMass");


            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortJuvenileMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortJuvenileMass[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }


            tempData = StateDataSet.GetData <double[, , , ]>("CohortAdultMass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortAdultMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortAdultMass[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData <double[, , , ]>("CohortIndividualBodyMass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortIndividualBodyMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortIndividualBodyMass[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData <double[, , , ]>("CohortCohortAbundance");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortCohortAbundance.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortCohortAbundance[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData <double[, , , ]>("CohortLogOptimalPreyBodySizeRatio");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortLogOptimalPreyBodySizeRatio.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortLogOptimalPreyBodySizeRatio[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData <double[, , , ]>("CohortBirthTimeStep");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortBirthTimeStep.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortBirthTimeStep[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData <double[, , , ]>("CohortProportionTimeActive");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortProportionTimeActive.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortProportionTimeActive[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData = StateDataSet.GetData <double[, , , ]>("CohortTrophicIndex");

            for (int la = 0; la < Latitude.Length; la++)
            {
                CohortTrophicIndex.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        CohortTrophicIndex[(int)cell[0]][cell[1], fg, c] = tempData[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            _GridCellCohorts = new GridCellCohortHandler[Latitude.Length, Longitude.Length];

            long temp = 0;

            for (int cell = 0; cell < cellList.Count; cell++)
            {
                _GridCellCohorts[cellList[cell][0], cellList[cell][1]] = new GridCellCohortHandler(CohortFunctionalGroup.Length);

                for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
                {
                    _GridCellCohorts[cellList[cell][0], cellList[cell][1]][fg] = new List <Cohort>();
                    for (int c = 0; c < Cohort.Length; c++)
                    {
                        if (CohortCohortAbundance[(int)cellList[cell][0]][cellList[cell][1], fg, c] > 0.0)
                        {
                            Cohort TempCohort = new Cohort(
                                (byte)fg,
                                CohortJuvenileMass[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                CohortAdultMass[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                CohortIndividualBodyMass[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                CohortCohortAbundance[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                Math.Exp(CohortLogOptimalPreyBodySizeRatio[(int)cellList[cell][0]][cellList[cell][1], fg, c]),
                                Convert.ToUInt16(CohortBirthTimeStep[(int)cellList[cell][0]][cellList[cell][1], fg, c]),
                                CohortProportionTimeActive[(int)cellList[cell][0]][cellList[cell][1], fg, c], ref temp,
                                CohortTrophicIndex[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                false);

                            _GridCellCohorts[cellList[cell][0], cellList[cell][1]][fg].Add(TempCohort);
                        }
                    }
                }
            }

            CohortJuvenileMass.RemoveRange(0, CohortJuvenileMass.Count);
            CohortAdultMass.RemoveRange(0, CohortAdultMass.Count);
            CohortIndividualBodyMass.RemoveRange(0, CohortIndividualBodyMass.Count);
            CohortCohortAbundance.RemoveRange(0, CohortCohortAbundance.Count);
            CohortLogOptimalPreyBodySizeRatio.RemoveRange(0, CohortLogOptimalPreyBodySizeRatio.Count);
            CohortBirthTimeStep.RemoveRange(0, CohortBirthTimeStep.Count);
            CohortProportionTimeActive.RemoveRange(0, CohortProportionTimeActive.Count);
            CohortTrophicIndex.RemoveRange(0, CohortTrophicIndex.Count);

            List <double[, , ]> StockIndividualBodyMass = new List <double[, , ]>();
            List <double[, , ]> StockTotalBiomass       = new List <double[, , ]>();

            double[,,,] tempData2 = new double[Latitude.Length, Longitude.Length,
                                               StockFunctionalGroup.Length, Stock.Length];

            tempData2 = StateDataSet.GetData <double[, , , ]>("StockIndividualBodyMass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                StockIndividualBodyMass.Add(new double[Longitude.Length, StockFunctionalGroup.Length, Stock.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < StockFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Stock.Length; c++)
                    {
                        StockIndividualBodyMass[(int)cell[0]][cell[1], fg, c] = tempData2[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            tempData2 = StateDataSet.GetData <double[, , , ]>("StockTotalBiomass");

            for (int la = 0; la < Latitude.Length; la++)
            {
                StockTotalBiomass.Add(new double[Longitude.Length, StockFunctionalGroup.Length, Stock.Length]);
            }

            foreach (uint[] cell in cellList)
            {
                for (int fg = 0; fg < StockFunctionalGroup.Length; fg++)
                {
                    for (int c = 0; c < Stock.Length; c++)
                    {
                        StockTotalBiomass[(int)cell[0]][cell[1], fg, c] = tempData2[
                            cell[0], cell[1], fg, c];
                    }
                }
            }

            _GridCellStocks = new GridCellStockHandler[Latitude.Length, Longitude.Length];

            for (int cell = 0; cell < cellList.Count; cell++)
            {
                _GridCellStocks[cellList[cell][0], cellList[cell][1]] = new GridCellStockHandler(StockFunctionalGroup.Length);

                for (int fg = 0; fg < StockFunctionalGroup.Length; fg++)
                {
                    _GridCellStocks[cellList[cell][0], cellList[cell][1]][fg] = new List <Stock>();
                    for (int c = 0; c < Stock.Length; c++)
                    {
                        if (StockTotalBiomass[(int)cellList[cell][0]][cellList[cell][1], fg, c] > 0.0)
                        {
                            Stock TempStock = new Stock(
                                (byte)fg,
                                StockIndividualBodyMass[(int)cellList[cell][0]][cellList[cell][1], fg, c],
                                StockTotalBiomass[(int)cellList[cell][0]][cellList[cell][1], fg, c]);

                            _GridCellStocks[cellList[cell][0], cellList[cell][1]][fg].Add(TempStock);
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Add a new cohort to an existing list of cohorts in the grid cell - or create a new list if there is not one present
 /// </summary>
 /// <param name="latIndex">Latitude index of the grid cell</param>
 /// <param name="lonIndex">Longitude index of the grid cell</param>
 /// <param name="functionalGroup">Functional group of the cohort (i.e. array index)</param>
 /// <param name="cohortToAdd">The cohort object to add</param>
 public void AddNewCohortToGridCell(uint latIndex, uint lonIndex, int functionalGroup, Cohort cohortToAdd)
 {
     InternalGrid[latIndex, lonIndex].GridCellCohorts[functionalGroup].Add(cohortToAdd);
 }
        /// <summary>
        /// Run advective dispersal
        /// </summary>
        /// <param name="cellIndex">The longitudinal and latitudinal indices of the focal grid cell</param>
        /// <param name="gridForDispersal">The model grid to run dispersal for</param>
        /// <param name="cohortToDisperse">The cohort to run dispersal for</param>
        /// <param name="actingCohortFunctionalGroup">The functional group index of the acting cohort</param>
        /// <param name="actingCohortNumber">The position of the acting cohort wihtin the functional group in the array of grid cell cohorts</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunDispersal(uint[] cellIndex, ModelGrid gridForDispersal, Cohort cohortToDisperse, int actingCohortFunctionalGroup,
            int actingCohortNumber, uint currentMonth)
        {
            // An array to hold the dispersal information
            double[] DispersalArray = new double[6];

            // A double to indicate whether or not the cohort has dispersed, and if it has dispersed, where to
            double CohortDispersed = 0;

            // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step
            uint ExitDirection = new uint();
            uint EntryDirection = new uint();
            ExitDirection = 9999;

            // An array to hold the present cohort location for the intermediate steps that occur before the final dispersal this time step
            uint[] PresentLocation = { cellIndex[0], cellIndex[1] };

            // Get the u speed and the v speed from the cell data
            double uAdvectiveSpeed = gridForDispersal.GetEnviroLayer("uVel", currentMonth, PresentLocation[0], PresentLocation[1], out varExists);
            Debug.Assert(uAdvectiveSpeed != -9999);

            double vAdvectiveSpeed = gridForDispersal.GetEnviroLayer("vVel", currentMonth, PresentLocation[0], PresentLocation[1], out varExists);
            Debug.Assert(vAdvectiveSpeed != -9999);

            uAdvectiveSpeed = RescaleDispersalSpeed(uAdvectiveSpeed);
            vAdvectiveSpeed = RescaleDispersalSpeed(vAdvectiveSpeed);

            // Loop through a number of times proportional to the rescaled dispersal
            for (int mm = 0; mm < _AdvectionTimeStepsPerModelTimeStep; mm++)
            {
                // Get the probability of dispersal
                DispersalArray = CalculateDispersalProbability(gridForDispersal, PresentLocation[0], PresentLocation[1], currentMonth, uAdvectiveSpeed, vAdvectiveSpeed);

                // Check to see if it does disperse
                CohortDispersed = CheckForDispersal(DispersalArray[0]);

                // If it does, check to see where it will end up
                if (CohortDispersed > 0)
                {
                    // Check to see if the direction is actually dispersable
                    uint[] DestinationCell = CellToDisperseTo(gridForDispersal, PresentLocation[0], PresentLocation[1], DispersalArray, CohortDispersed, DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection);

                    // If it is, go ahead and update the cohort location
                    if (DestinationCell[0] < 999999)
                    {
                        PresentLocation = DestinationCell;

                        // Get the u speed and the v speed from the cell data
                        uAdvectiveSpeed = gridForDispersal.GetEnviroLayer("uVel", currentMonth, PresentLocation[0], PresentLocation[1], out varExists);
                        vAdvectiveSpeed = gridForDispersal.GetEnviroLayer("vVel", currentMonth, PresentLocation[0], PresentLocation[1], out varExists);
                        uAdvectiveSpeed = RescaleDispersalSpeed(uAdvectiveSpeed);
                        vAdvectiveSpeed = RescaleDispersalSpeed(vAdvectiveSpeed);
                    }
                }
            }

            // Update the dipersal deltas for this cohort, if necessary
            if ((cellIndex[0] != PresentLocation[0]) || (cellIndex[1] != PresentLocation[1]))
            {
                // Update the delta array of cohorts
                gridForDispersal.DeltaFunctionalGroupDispersalArray[cellIndex[0], cellIndex[1]].Add((uint)actingCohortFunctionalGroup);
                gridForDispersal.DeltaCohortNumberDispersalArray[cellIndex[0], cellIndex[1]].Add((uint)actingCohortNumber);

                // Update the delta array of cells to disperse to
                gridForDispersal.DeltaCellToDisperseToArray[cellIndex[0], cellIndex[1]].Add(PresentLocation);

                // Update the delta array of exit and entry directions
                gridForDispersal.DeltaCellExitDirection[cellIndex[0], cellIndex[1]].Add(ExitDirection);
                gridForDispersal.DeltaCellEntryDirection[cellIndex[0], cellIndex[1]].Add(EntryDirection);
            }
        }