/// <summary>
        /// Calculate the potential biomass that could be gained through herbivory on each grid cell autotroph stock
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the grid cell</param>
        /// <param name="gridCellStocks">The stocks in the grid cell</param>
        /// <param name="actingCohort">The acting cohort</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="madingleyCohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks  in the model</param>
        public void GetEatingPotentialMarine(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort, SortedList <string, double[]> cellEnvironment, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions)
        {
            // Set the total biomass eaten by the acting cohort to zero
            _TotalBiomassEatenByCohort = 0.0;

            // Get the individual body mass of the acting cohort
            _BodyMassHerbivore = gridCellCohorts[actingCohort].IndividualBodyMass;

            // Set the total number of units to handle all potential biomass eaten to zero
            _TimeUnitsToHandlePotentialFoodItems = 0.0;

            // Initialise the jagged arrays to hold the potential and actual biomass eaten in each of the grid cell autotroph stocks
            _BiomassesEaten          = new double[gridCellStocks.Count][];
            _PotentialBiomassesEaten = new double[gridCellStocks.Count][];

            // Loop over rows in the jagged arrays and initialise each vector
            for (int i = 0; i < gridCellStocks.Count; i++)
            {
                _BiomassesEaten[i]          = new double[gridCellStocks[i].Count];
                _PotentialBiomassesEaten[i] = new double[gridCellStocks[i].Count];
            }

            // Loop over functional groups that can be eaten
            foreach (int FunctionalGroup in _FunctionalGroupIndicesToEat)
            {
                // Loop over stocks within the functional group
                for (int i = 0; i < gridCellStocks[FunctionalGroup].Count; i++)
                {
                    // Get the mass from this stock that is available for eating (assumes all marine autotrophic organisms are edible)
                    //EdibleMass = gridCellStocks[FunctionalGroup][i].TotalBiomass * 0.1;
                    EdibleMass = gridCellStocks[FunctionalGroup][i].TotalBiomass;

                    // Calculate the potential biomass eaten from this stock by the acting cohort
                    _PotentialBiomassesEaten[FunctionalGroup][i] = CalculatePotentialBiomassEatenMarine(EdibleMass, _BodyMassHerbivore);

                    // Add the time required to handle the potential biomass eaten from this stock to the cumulative total for all stocks
                    _TimeUnitsToHandlePotentialFoodItems += _PotentialBiomassesEaten[FunctionalGroup][i] *
                                                            CalculateHandlingTimeMarine(_BodyMassHerbivore);
                }
            }
        }
        /// <summary>
        /// Calculates the geometric community weighted mean body mass
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of cells to be run in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param>
        /// <returns>geometric community weighted mean body mass</returns>
        public double CalculateGeometricCommunityMeanBodyMass(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double CumulativeAbundance        = 0.0;
            double CumulativeLogBiomass       = 0.0;

            //Retrieve the biomass
            foreach (var CohortList in CellCohorts)
            {
                foreach (Cohort c in CohortList)
                {
                    CumulativeLogBiomass += Math.Log(c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;
                    CumulativeAbundance  += c.CohortAbundance;
                }
            }

            double CWGMBM = Math.Exp(CumulativeLogBiomass / CumulativeAbundance);

            return(CWGMBM);
        }
Exemple #3
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);
        }
Exemple #4
0
        /// <summary>
        /// Create the matrix of prey abundances in each weight bin
        /// </summary>
        /// <param name="gridCellCohorts">Cohorts in this grid cell</param>
        /// <param name="actingCohort">The predator cohort</param>
        /// <param name="functionalGroupIndicesToEat">The functional groups which this predator eats</param>
        /// <param name="logOptimalPreyBodySizeRatio">The (log-transformed) optimal ratio of prey to predator body mass</param>
        private void PopulateBinnedPreyAbundance(GridCellCohortHandler gridCellCohorts, int[] actingCohort, int[] functionalGroupIndicesToEat,
                                                 double logPredatorMassPlusLogPredatorOptimalBodySizeRatio)
        {
            int BinNumber = 0;

            // Loop through prey functional groups
            foreach (var fg in functionalGroupIndicesToEat)
            {
                foreach (var cohort in gridCellCohorts[fg])
                {
                    // Calculate the difference between the actual body size ratio and the optimal ratio,
                    // and then divide by the standard deviation in log ratio space to determine in
                    // which bin to assign the prey item.
                    BinNumber = GetBinNumber(cohort.IndividualBodyMass, logPredatorMassPlusLogPredatorOptimalBodySizeRatio);

                    if ((0 < BinNumber) && (BinNumber < NumberOfBins))
                    {
                        BinnedPreyDensities[fg, BinNumber] += cohort.CohortAbundance / _CellAreaHectares;
                    }
                }
            }
        }
        /// <summary>
        /// Make a record of the properties of the intial model cohorts in the new cohorts output file
        /// </summary>
        public void RecordInitialCohorts()
        {
            int i = 0;
            foreach (uint[] cell in _CellList)
            {
                if (ProcessTrackers[i].TrackProcesses)
                {

                    GridCellCohortHandler TempCohorts = EcosystemModelGrid.GetGridCellCohorts(cell[0], cell[1]);

                    for (int FunctionalGroup = 0; FunctionalGroup < TempCohorts.Count; FunctionalGroup++)
                    {
                        foreach (Cohort item in TempCohorts[FunctionalGroup])
                        {
                            ProcessTrackers[i].RecordNewCohort(cell[0], cell[1], 0, item.CohortAbundance, item.AdultMass, item.FunctionalGroupIndex,
                                new List<uint> { uint.MaxValue }, item.CohortID[0]);
                        }
                    }
                }
                i += 1;
            }
        }
        /// <summary>
        /// Initialises the feeding interactions matrix each timestep
        /// </summary>
        public void InitialiseInteractionsMatrix(GridCellCohortHandler gridCellCohorts)
        {
            int MaxCohorts = 0;

            foreach (var CohortList in gridCellCohorts)
            {
                if (CohortList.Count > MaxCohorts)
                {
                    MaxCohorts = CohortList.Count;
                }
            }

            FeedingInteractionsMatrixPredation = new List <Tuple <int, int, double, double> > [gridCellCohorts.Count, MaxCohorts];
            FeedingInteractionsMatrixHerbivory = new List <Tuple <int, int, double, double> > [gridCellCohorts.Count, MaxCohorts];

            for (int i = 0; i < gridCellCohorts.Count; i++)
            {
                for (int c = 0; c < MaxCohorts; c++)
                {
                    FeedingInteractionsMatrixPredation[i, c] = new List <Tuple <int, int, double, double> >();
                    FeedingInteractionsMatrixHerbivory[i, c] = new List <Tuple <int, int, double, double> >();
                }
            }
        }
Exemple #7
0
        /// <summary>
        /// Assigns biomass from body mass to 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 in 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>
        public void AssignMassToReproductivePotential(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                                      int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas,
                                                      FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                                      uint currentTimestep, ProcessTracker tracker)
        {
            // If this is the first time reproductive potential mass has been assigned for this cohort,
            // then set the maturity time step for this cohort as the current model time step
            if (gridCellCohorts[actingCohort].MaturityTimeStep == uint.MaxValue)
            {
                gridCellCohorts[actingCohort].MaturityTimeStep = currentTimestep;

                // Track the generation length for this cohort
                if ((!gridCellCohorts[actingCohort].Merged) && tracker.TrackProcesses)
                {
                    tracker.TrackMaturity((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                          currentTimestep, gridCellCohorts[actingCohort].BirthTimeStep, gridCellCohorts[actingCohort].JuvenileMass,
                                          gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex);
                }
            }

            // Assign the specified mass to reproductive potential mass and remove it from individual biomass
            deltas["reproductivebiomass"]["reproduction"] += _BiomassToAssignToReproductivePotential;
            deltas["biomass"]["reproduction"]             -= _BiomassToAssignToReproductivePotential;
        }
Exemple #8
0
        /// <summary>
        /// Gets a state variable density for specified functional groups of specified entity types in a specified grid cell
        /// </summary>
        /// <param name="variableName">The name of the variable to get: 'biomass' or 'abundance'</param>
        /// <param name="traitValue">The functional group trait value to get data for</param>
        /// <param name="functionalGroups">The functional group indices to get the state variable for</param>
        /// <param name="latCellIndex">The latitudinal index of the cell</param>
        /// <param name="lonCellIndex">The longitudinal index of the cell</param>
        /// <param name="stateVariableType">The type of entity to return the state variable for: 'stock' or 'cohort'</param>
        /// <param name="modelInitialisation">The Madingley Model initialisation</param>
        /// <returns>The state variable density for specified functional groups of specified entity types in a specified grid cell</returns>
        public double GetStateVariableDensity(string variableName, string traitValue, int[] functionalGroups, uint latCellIndex,
                                              uint lonCellIndex, string stateVariableType, MadingleyModelInitialisation modelInitialisation)
        {
            double returnValue = 0.0;

            switch (stateVariableType.ToLower())
            {
            case "cohort":

                GridCellCohortHandler TempCohorts = InternalGrid[latCellIndex, lonCellIndex].GridCellCohorts;

                switch (variableName.ToLower())
                {
                case "biomass":
                    if (traitValue != "Zooplankton (all)")
                    {
                        foreach (int f in functionalGroups)
                        {
                            foreach (var item in TempCohorts[f])
                            {
                                returnValue += ((item.IndividualBodyMass + item.IndividualReproductivePotentialMass) * item.CohortAbundance);
                            }
                        }
                    }
                    else
                    {
                        foreach (int f in functionalGroups)
                        {
                            foreach (var item in TempCohorts[f])
                            {
                                if (item.IndividualBodyMass <= modelInitialisation.PlanktonDispersalThreshold)
                                {
                                    returnValue += ((item.IndividualBodyMass + item.IndividualReproductivePotentialMass) * item.CohortAbundance);
                                }
                            }
                        }
                    }
                    break;

                case "abundance":
                    if (traitValue != "Zooplankton (all)")
                    {
                        foreach (int f in functionalGroups)
                        {
                            foreach (var item in TempCohorts[f])
                            {
                                returnValue += item.CohortAbundance;
                            }
                        }
                    }
                    else
                    {
                        foreach (int f in functionalGroups)
                        {
                            foreach (var item in TempCohorts[f])
                            {
                                if (item.IndividualBodyMass <= modelInitialisation.PlanktonDispersalThreshold)
                                {
                                    returnValue += item.CohortAbundance;
                                }
                            }
                        }
                    }
                    break;

                default:
                    Debug.Fail("For cohorts, state variable name must be either 'biomass' or 'abundance'");
                    break;
                }
                break;

            case "stock":
                GridCellStockHandler TempStocks = InternalGrid[latCellIndex, lonCellIndex].GridCellStocks;

                switch (variableName.ToLower())
                {
                case "biomass":
                    foreach (int f in functionalGroups)
                    {
                        foreach (var item in TempStocks[f])
                        {
                            returnValue += item.TotalBiomass;
                        }
                    }
                    break;

                default:
                    Debug.Fail("For stocks, state variable name must be 'biomass'");
                    break;
                }
                break;

            default:
                Debug.Fail("State variable type must be either 'cohort' or 'stock'");
                break;
            }

            return(returnValue / (InternalGrid[latCellIndex, lonCellIndex].CellEnvironment["Cell Area"][0]));
        }
Exemple #9
0
        /// <summary>
        /// Apply the changes from predation to prey cohorts, and update deltas for the predator cohort
        /// </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 acting cohort</param>
        /// <param name="cellEnvironment">The environment in 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 functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks in the model</param>
        /// <param name="trackProcesses">An instance of ProcessTracker to hold diagnostics for predation</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail used in this model run</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEating(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort, SortedList <string, double[]>
                              cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas, FunctionalGroupDefinitions madingleyCohortDefinitions,
                              FunctionalGroupDefinitions madingleyStockDefinitions, ProcessTracker trackProcesses, uint currentTimestep, Boolean specificLocations,
                              string outputDetail, MadingleyModelInitialisation initialisation)
        {
            if (trackProcesses.TrackProcesses)
            {
                Track = (RandomNumberGenerator.GetUniform() > 0.975) ? true : false;
            }


            TempDouble = 0.0;

            // Temporary variable to hold the total time spent eating + 1. Saves an extra calculation in CalculateAbundanceEaten
            double TotalTimeUnitsToHandlePlusOne = TimeUnitsToHandlePotentialFoodItems + 1;

            // Loop over potential prey functional groups
            foreach (int FunctionalGroup in _FunctionalGroupIndicesToEat)
            {
                // Loop over cohorts within the functional group
                for (int i = 0; i < NumberCohortsPerFunctionalGroupNoNewCohorts[FunctionalGroup]; i++)
                {
                    // Get the individual body mass of this cohort
                    _BodyMassPrey = gridCellCohorts[FunctionalGroup][i].IndividualBodyMass;

                    // Calculate the actual abundance of prey eaten from this cohort
                    if (gridCellCohorts[FunctionalGroup][i].CohortAbundance > 0)
                    {
                        // Calculate the actual abundance of prey eaten from this cohort
                        _AbundancesEaten[FunctionalGroup][i] = CalculateAbundanceEaten(_PotentialAbundanceEaten[FunctionalGroup][i], _PredatorAbundanceMultipliedByTimeEating,
                                                                                       TotalTimeUnitsToHandlePlusOne, gridCellCohorts[FunctionalGroup][i].CohortAbundance);
                    }
                    else
                    {
                        _AbundancesEaten[FunctionalGroup][i] = 0;
                    }

                    // Remove number of prey eaten from the prey cohort
                    gridCellCohorts[FunctionalGroup][i].CohortAbundance -= _AbundancesEaten[FunctionalGroup][i];

                    gridCellCohorts[actingCohort].TrophicIndex += (_BodyMassPrey + gridCellCohorts[FunctionalGroup][i].IndividualReproductivePotentialMass) * _AbundancesEaten[FunctionalGroup][i] * gridCellCohorts[FunctionalGroup][i].TrophicIndex;

                    // If the process tracker is set and output detail is set to high and the prey cohort has never been merged,
                    // then track its mortality owing to predation
                    if (trackProcesses.TrackProcesses)
                    {
                        if ((outputDetail == "high") && (gridCellCohorts[FunctionalGroup][i].CohortID.Count == 1) &&
                            AbundancesEaten[FunctionalGroup][i] > 0)
                        {
                            trackProcesses.RecordMortality((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], gridCellCohorts
                                                           [FunctionalGroup][i].BirthTimeStep, currentTimestep, gridCellCohorts[FunctionalGroup][i].IndividualBodyMass,
                                                           gridCellCohorts[FunctionalGroup][i].AdultMass, gridCellCohorts[FunctionalGroup][i].FunctionalGroupIndex,
                                                           gridCellCohorts[FunctionalGroup][i].CohortID[0], AbundancesEaten[FunctionalGroup][i], "predation");
                        }

                        // If the model is being run for specific locations and if track processes has been specified, then track the mass flow between
                        // prey and predator
                        if (specificLocations)
                        {
                            trackProcesses.RecordPredationMassFlow(currentTimestep, _BodyMassPrey, _BodyMassPredator, _BodyMassPrey *
                                                                   _AbundancesEaten[FunctionalGroup][i]);

                            if (outputDetail == "high")
                            {
                                trackProcesses.TrackPredationTrophicFlow((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                                                         gridCellCohorts[FunctionalGroup][i].FunctionalGroupIndex, gridCellCohorts[actingCohort].FunctionalGroupIndex,
                                                                         madingleyCohortDefinitions, (_AbundancesEaten[FunctionalGroup][i] * _BodyMassPrey), _BodyMassPredator, _BodyMassPrey,
                                                                         initialisation, cellEnvironment["Realm"][0] == 2.0);
                            }
                        }
                    }


                    // Check that the abundance eaten from this cohort is not negative
                    // Commented out for the purposes of speed
                    //Debug.Assert( _AbundancesEaten[FunctionalGroup][i].CompareTo(0.0) >= 0,
                    //     "Predation negative for this prey cohort" + actingCohort);

                    // Create a temporary value to speed up the predation function
                    // This is equivalent to the body mass of the prey cohort including reproductive potential mass, times the abundance eaten of the prey cohort,
                    // divided by the abundance of the predator
                    TempDouble += (_BodyMassPrey + gridCellCohorts[FunctionalGroup][i].IndividualReproductivePotentialMass) * _AbundancesEaten[FunctionalGroup][i] / _AbundancePredator;
                }
            }



            // Add the biomass eaten and assimilated by an individual to the delta biomass for the acting (predator) cohort
            deltas["biomass"]["predation"] = TempDouble * _PredatorAssimilationEfficiency;

            // Move the biomass eaten but not assimilated by an individual into the organic matter pool
            deltas["organicpool"]["predation"] = TempDouble * _PredatorNonAssimilation * _AbundancePredator;

            // Check that the delta biomass from eating for the acting cohort is not negative
            //Debug.Assert(deltas["biomass"]["predation"] >= 0, "Predation yields negative biomass");

            // Calculate the total biomass eaten by the acting (predator) cohort
            _TotalBiomassEatenByCohort = deltas["biomass"]["predation"] * _AbundancePredator;
        }
Exemple #10
0
        /// <summary>
        /// Calculate the potential number of prey that could be gained through predation on each cohort in the grid cell
        /// </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 acting cohort</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="madingleyCohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks  in the model</param>
        public void GetEatingPotentialTerrestrial(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort,
                                                  SortedList <string, double[]> cellEnvironment, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions
                                                  madingleyStockDefinitions)
        {
            BinnedPreyDensities = new double[gridCellCohorts.Count, NumberOfBins];

            // Set the total eaten by the acting cohort to zero
            _TotalBiomassEatenByCohort = 0.0;

            // Set the total number of units to handle all potential prey individuals eaten to zero
            _TimeUnitsToHandlePotentialFoodItems = 0.0;

            // Get the individual body mass of the acting (predator) cohort
            _BodyMassPredator = gridCellCohorts[actingCohort].IndividualBodyMass;

            // Get the abundance of the acting (predator) cohort
            _AbundancePredator = gridCellCohorts[actingCohort].CohortAbundance;

            // Pre-calculate individual values for this predator
            _SpecificPredatorKillRateConstant = _KillRateConstant * Math.Pow(_BodyMassPredator, (_KillRateConstantMassExponent));
            _SpecificPredatorTimeUnitsEatingPerGlobalTimeStep = _DeltaT * _ProportionOfTimeEating;
            _PredatorAssimilationEfficiency = _AssimilationEfficiency;
            _PredatorNonAssimilation        = (1 - _AssimilationEfficiency);

            // When body sizes are less than one gram, we have a flat handling time relationship to stop small things have extraordinarily short handling times
            //  if (_BodyMassPredator > 1.0)
            //  {
            _ReferenceMassRatioScalingTerrestrial = HandlingTimeScalarTerrestrial * Math.Pow(_ReferenceMass / _BodyMassPredator, _HandlingTimeExponentTerrestrial);
            //  }
            //  else
            //  {
            //      _ReferenceMassRatioScalingTerrestrial = HandlingTimeScalarTerrestrial * _ReferenceMass / _BodyMassPredator;

//            }
            _PredatorAbundanceMultipliedByTimeEating = _AbundancePredator * _SpecificPredatorTimeUnitsEatingPerGlobalTimeStep;


            _PredatorLogOptimalPreyBodySizeRatio = gridCellCohorts[actingCohort[0]][actingCohort[1]].LogOptimalPreyBodySizeRatio;


            LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio = Math.Log(_BodyMassPredator) + _PredatorLogOptimalPreyBodySizeRatio;

            // Calculate the abundance of prey in each of the prey mass bins
            PopulateBinnedPreyAbundance(gridCellCohorts, actingCohort, FunctionalGroupIndicesToEat, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

            // Loop over potential prey functional groups
            foreach (int FunctionalGroup in FunctionalGroupIndicesToEat)
            {
                // Loop over cohorts within the functional group
                for (int i = 0; i < NumberCohortsPerFunctionalGroupNoNewCohorts[FunctionalGroup]; i++)
                {
                    // Get the body mass of individuals in this cohort
                    _BodyMassPrey = gridCellCohorts[FunctionalGroup][i].IndividualBodyMass;

                    // Get the bin number of this prey cohort
                    PreyMassBinNumber = GetBinNumber(_BodyMassPrey, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

                    // Check whether the prey cohort still exists in the model (i.e. body mass > 0)
                    if ((0 < PreyMassBinNumber) && (PreyMassBinNumber < NumberOfBins) && (_BodyMassPrey > 0))
                    {
                        // Calculate the potential abundance from this cohort eaten by the acting cohort
                        _PotentialAbundanceEaten[FunctionalGroup][i] = CalculateExpectedNumberKilledTerrestrial(
                            gridCellCohorts[FunctionalGroup][i].CohortAbundance, _BodyMassPrey, PreyMassBinNumber, FunctionalGroup,
                            _BodyMassPredator, _CarnivoreFunctionalGroups[FunctionalGroup], _OmnivoreFunctionalGroups[FunctionalGroup],
                            _OmnivoreFunctionalGroups[actingCohort[0]], _PredatorLogOptimalPreyBodySizeRatio);

                        // Add the time required to handle the potential abundance eaten from this cohort to the cumulative total for all cohorts
                        _TimeUnitsToHandlePotentialFoodItems += _PotentialAbundanceEaten[FunctionalGroup][i] *
                                                                CalculateHandlingTimeTerrestrial(_BodyMassPrey);
                    }
                    else
                    {
                        // Assign a potential abundance eaten of zero
                        _PotentialAbundanceEaten[FunctionalGroup][i] = 0.0;
                    }
                }
            }

            // No cannibalism; do this outside the loop to speed up the calculations
            _TimeUnitsToHandlePotentialFoodItems -= PotentialAbundanceEaten[actingCohort[0]][actingCohort[1]] *
                                                    CalculateHandlingTimeTerrestrial(_BodyMassPredator);
            PotentialAbundanceEaten[actingCohort[0]][actingCohort[1]] = 0.0;
        }
Exemple #11
0
        /// <summary>
        /// Record dispersal events in the dispersal tracker
        /// </summary>
        /// <param name="inboundCohorts">The cohorts arriving in a grid cell in the current time step</param>
        /// <param name="outboundCohorts">The cohorts leaving a ce  ll in the current time step</param>
        /// <param name="outboundCohortWeights">The body masses of cohorts leaving the cell in the current time step</param>
        /// <param name="currentTimeStep">The current model time step</param>
        /// <param name="madingleyModelGrid">The model grid</param>
        public void RecordDispersal(uint[, ,] inboundCohorts, uint[, ,] outboundCohorts, List <double>[,] outboundCohortWeights, uint currentTimeStep, ModelGrid madingleyModelGrid)
        {
            // Loop through cells in the grid and write out the necessary data
            for (uint ii = 0; ii < outboundCohorts.GetLength(0); ii++)
            {
                for (uint jj = 0; jj < outboundCohorts.GetLength(1); jj++)
                {
                    double MeanOutboundCohortWeight = new double();

                    // Calculate the mean weight of outbound cohorts (ignoring abundance)
                    if (outboundCohortWeights[ii, jj].Count == 0)
                    {
                        MeanOutboundCohortWeight = 0.0;
                    }
                    else
                    {
                        MeanOutboundCohortWeight = outboundCohortWeights[ii, jj].Average();
                    }

                    // Calculate the mean weight of all cohorts (ignoring abundance)
                    List <double> TempList = new List <double>();

                    GridCellCohortHandler Temp1 = madingleyModelGrid.GetGridCellCohorts(ii, jj);

                    // Loop through functional groups
                    for (int kk = 0; kk < Temp1.Count; kk++)
                    {
                        // Loop through cohorts
                        for (int hh = 0; hh < Temp1[kk].Count; hh++)
                        {
                            // Add the cohort weight to the list
                            TempList.Add(Temp1[kk][hh].IndividualBodyMass);
                        }
                    }

                    // Calculate the mean weight
                    double MeanCohortWeight = new double();
                    if (TempList.Count == 0)
                    {
                        MeanCohortWeight = 0.0;
                    }
                    else
                    {
                        MeanCohortWeight = TempList.Average();
                    }

                    string newline = Convert.ToString(currentTimeStep) + '\t' + Convert.ToString(ii) + '\t' +
                                     Convert.ToString(jj) + '\t' + Convert.ToString(madingleyModelGrid.GetCellLatitude(ii)) + '\t' +
                                     Convert.ToString(madingleyModelGrid.GetCellLongitude(jj)) + '\t' +
                                     Convert.ToString(outboundCohorts[ii, jj, 0]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 1]) + '\t' +
                                     Convert.ToString(outboundCohorts[ii, jj, 2]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 3]) + '\t' +
                                     Convert.ToString(outboundCohorts[ii, jj, 4]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 5]) + '\t' +
                                     Convert.ToString(outboundCohorts[ii, jj, 6]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 7]) + '\t' +
                                     Convert.ToString(inboundCohorts[ii, jj, 0]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 1]) + '\t' +
                                     Convert.ToString(inboundCohorts[ii, jj, 2]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 3]) + '\t' +
                                     Convert.ToString(inboundCohorts[ii, jj, 4]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 5]) + '\t' +
                                     Convert.ToString(inboundCohorts[ii, jj, 6]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 7]) + '\t' +
                                     Convert.ToString(String.Format("{0:.000000}", MeanOutboundCohortWeight) + '\t' +
                                                      Convert.ToString(String.Format("{0:.000000}", MeanCohortWeight)));

                    SyncedDispersalWriter.WriteLine(newline);
                }
            }
        }
Exemple #12
0
        /// <summary>
        /// Calculate the potential number of prey that could be gained through predation on each cohort in the grid cell
        /// </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 acting cohort</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="madingleyCohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks  in the model</param>
        public void GetEatingPotentialMarine(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort,
                                             SortedList <string, double[]> cellEnvironment, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions
                                             madingleyStockDefinitions)
        {
            BinnedPreyDensities = new double[gridCellCohorts.Count, NumberOfBins];

            // Set the total eaten by the acting cohort to zero
            _TotalBiomassEatenByCohort = 0.0;

            // Set the total number of units to handle all potential prey individuals eaten to zero
            _TimeUnitsToHandlePotentialFoodItems = 0.0;

            // Get the individual body mass of the acting (predator) cohort
            _BodyMassPredator = gridCellCohorts[actingCohort].IndividualBodyMass;

            // Get the abundance of the acting (predator) cohort
            _AbundancePredator = gridCellCohorts[actingCohort].CohortAbundance;

            // Pre-calculate individual values for this predator to speed things up
            _SpecificPredatorKillRateConstant = _KillRateConstant * Math.Pow(_BodyMassPredator, (_KillRateConstantMassExponent));
            _SpecificPredatorTimeUnitsEatingPerGlobalTimeStep = _DeltaT * _ProportionOfTimeEating;
            _PredatorAssimilationEfficiency = _AssimilationEfficiency;
            _PredatorNonAssimilation        = (1 - _AssimilationEfficiency);

            _DietIsAllSpecial = madingleyCohortDefinitions.GetTraitNames("Diet", actingCohort[0]) == "allspecial";

            _PredatorLogOptimalPreyBodySizeRatio = gridCellCohorts[actingCohort[0]][actingCohort[1]].LogOptimalPreyBodySizeRatio;

            // If a filter feeder, then optimal body size is a value not a ratio: convert it to a ratio to ensure that all calculations work correctly
            if (_DietIsAllSpecial)
            {
                // Optimal body size is actually a value, not a ratio, so convert it to a ratio based on the present body size
                _PredatorLogOptimalPreyBodySizeRatio = Math.Log(
                    Math.Exp(gridCellCohorts[actingCohort[0]][actingCohort[1]].LogOptimalPreyBodySizeRatio) / gridCellCohorts[actingCohort[0]][actingCohort[1]].IndividualBodyMass);
            }


            // Calculate the reference mass scaling ratio
            _ReferenceMassRatioScalingMarine = HandlingTimeScalarMarine * Math.Pow(_ReferenceMass / _BodyMassPredator, _HandlingTimeExponentMarine);

            _PredatorAbundanceMultipliedByTimeEating = _AbundancePredator * _SpecificPredatorTimeUnitsEatingPerGlobalTimeStep;

            LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio = Math.Log(_BodyMassPredator) + _PredatorLogOptimalPreyBodySizeRatio;

            // Calculate the abundance of prey in each of the prey mass bins
            PopulateBinnedPreyAbundance(gridCellCohorts, actingCohort, FunctionalGroupIndicesToEat, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

            // Loop over potential prey functional groups
            foreach (int FunctionalGroup in FunctionalGroupIndicesToEat)
            {
                // Eating operates differently for planktivores
                // This can certainly be sped up
                if (_DietIsAllSpecial)
                {
                    // Loop over cohorts within the functional group
                    for (int i = 0; i < NumberCohortsPerFunctionalGroupNoNewCohorts[FunctionalGroup]; i++)
                    {
                        // Get the body mass of individuals in this cohort
                        _BodyMassPrey = gridCellCohorts[FunctionalGroup][i].IndividualBodyMass;

                        // Get the bin number of this prey cohort
                        PreyMassBinNumber = GetBinNumber(_BodyMassPrey, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);


                        // Check whether
                        // The prey cohort is within the feeding range of the predator
                        // the prey cohort still exists in the model (i.e. body mass > 0)
                        // Currently having whales etc eat everything, but preferentially feed on very small things (i.e. filter feeders)
                        if ((_PlanktonFunctionalGroups[FunctionalGroup]) && (0 < PreyMassBinNumber) &&
                            (PreyMassBinNumber < NumberOfBins) && (_BodyMassPrey > 0))
                        {
                            // Calculate the potential abundance from this cohort eaten by the acting cohort
                            _PotentialAbundanceEaten[FunctionalGroup][i] = CalculateExpectedNumberKilledMarine(
                                gridCellCohorts[FunctionalGroup][i].CohortAbundance, _BodyMassPrey, PreyMassBinNumber, FunctionalGroup,
                                _BodyMassPredator, _CarnivoreFunctionalGroups[FunctionalGroup], _OmnivoreFunctionalGroups[FunctionalGroup],
                                _OmnivoreFunctionalGroups[actingCohort[0]], _PredatorLogOptimalPreyBodySizeRatio);

                            // Add the time required to handle the potential abundance eaten from this cohort to the cumulative total for all cohorts
                            _TimeUnitsToHandlePotentialFoodItems += _PotentialAbundanceEaten[FunctionalGroup][i] *
                                                                    CalculateHandlingTimeMarine(_BodyMassPrey);
                        }
                        else
                        {
                            // Assign a potential abundance eaten of zero
                            _PotentialAbundanceEaten[FunctionalGroup][i] = 0.0;
                        }
                    }
                }
                else
                {
                    // Loop over cohorts within the functional group
                    for (int i = 0; i < NumberCohortsPerFunctionalGroupNoNewCohorts[FunctionalGroup]; i++)
                    {
                        // Get the body mass of individuals in this cohort
                        _BodyMassPrey = gridCellCohorts[FunctionalGroup][i].IndividualBodyMass;

                        // Get the bin number of this prey cohort
                        PreyMassBinNumber = GetBinNumber(_BodyMassPrey, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

                        // Check whether
                        // The prey cohort is within the feeding range of the predator
                        // the prey cohort still exists in the model (i.e. body mass > 0)
                        if ((0 < PreyMassBinNumber) && (PreyMassBinNumber < NumberOfBins) && (_BodyMassPrey > 0))
                        {
                            // Calculate the potential abundance from this cohort eaten by the acting cohort
                            _PotentialAbundanceEaten[FunctionalGroup][i] = CalculateExpectedNumberKilledMarine(
                                gridCellCohorts[FunctionalGroup][i].CohortAbundance, _BodyMassPrey, PreyMassBinNumber, FunctionalGroup,
                                _BodyMassPredator, _CarnivoreFunctionalGroups[FunctionalGroup], _OmnivoreFunctionalGroups[FunctionalGroup],
                                _OmnivoreFunctionalGroups[actingCohort[0]], _PredatorLogOptimalPreyBodySizeRatio);

                            // Add the time required to handle the potential abundance eaten from this cohort to the cumulative total for all cohorts
                            _TimeUnitsToHandlePotentialFoodItems += _PotentialAbundanceEaten[FunctionalGroup][i] *
                                                                    CalculateHandlingTimeMarine(_BodyMassPrey);
                        }
                        else
                        {
                            // Assign a potential abundance eaten of zero
                            _PotentialAbundanceEaten[FunctionalGroup][i] = 0.0;
                        }
                    }
                }
            }

            // No cannibalism; do this outside the loop to speed up the calculations
            _TimeUnitsToHandlePotentialFoodItems -= PotentialAbundanceEaten[actingCohort[0]][actingCohort[1]] *
                                                    CalculateHandlingTimeMarine(_BodyMassPredator);
            PotentialAbundanceEaten[actingCohort[0]][actingCohort[1]] = 0.0;
        }
        /// <summary>
        /// Run eating
        /// </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 in 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 for cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="trackProcesses">An instance of ProcessTracker to hold diagnostics for eating</param>
        /// <param name="partial">Thread-locked variables</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail being used for the current model run</param>
        /// <param name="currentMonth">The current model month</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEcologicalProcess(GridCellCohortHandler gridCellCohorts,
                                         GridCellStockHandler gridCellStocks, int[] actingCohort,
                                         SortedList <string, double[]> cellEnvironment,
                                         Dictionary <string, Dictionary <string, double> > deltas,
                                         FunctionalGroupDefinitions madingleyCohortDefinitions,
                                         FunctionalGroupDefinitions madingleyStockDefinitions,
                                         uint currentTimestep, ProcessTracker trackProcesses,
                                         ref ThreadLockedParallelVariables partial, Boolean specificLocations,
                                         string outputDetail, uint currentMonth, MadingleyModelInitialisation initialisation)
        {
            PreviousTrophicIndex = gridCellCohorts[actingCohort].TrophicIndex;
            //Reset this cohort's trohic index ready for calculation across its feeding this timetsstep
            gridCellCohorts[actingCohort].TrophicIndex = 0.0;

            // Get the nutrition source (herbivory, carnivory or omnivory) of the acting cohort
            string NutritionSource = madingleyCohortDefinitions.GetTraitNames("Nutrition source", gridCellCohorts[actingCohort].FunctionalGroupIndex);

            // Switch to the appropriate eating process(es) given the cohort's nutrition source
            switch (NutritionSource)
            {
            case "herbivore":

                // Get the assimilation efficiency for herbivory for this cohort from the functional group definitions
                Implementations["revised herbivory"].AssimilationEfficiency =
                    madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup
                        ("herbivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex);

                // Get the proportion of time spent eating for this cohort from the functional group definitions
                Implementations["revised herbivory"].ProportionTimeEating = gridCellCohorts[actingCohort].ProportionTimeActive;

                // Calculate the potential biomass available from herbivory
                if (cellEnvironment["Realm"][0] == 2.0)
                {
                    Implementations["revised herbivory"].GetEatingPotentialMarine
                        (gridCellCohorts, gridCellStocks, actingCohort,
                        cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions);
                }
                else
                {
                    Implementations["revised herbivory"].GetEatingPotentialTerrestrial
                        (gridCellCohorts, gridCellStocks, actingCohort,
                        cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions);
                }

                // Run herbivory to apply changes in autotroph biomass from herbivory and add biomass eaten to the delta arrays
                Implementations["revised herbivory"].RunEating
                    (gridCellCohorts, gridCellStocks, actingCohort,
                    cellEnvironment, deltas, madingleyCohortDefinitions,
                    madingleyStockDefinitions, trackProcesses,
                    currentTimestep, specificLocations, outputDetail, initialisation);

                break;

            case "carnivore":

                // Get the assimilation efficiency for predation for this cohort from the functional group definitions
                Implementations["revised predation"].AssimilationEfficiency =
                    madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup
                        ("carnivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex);

                Implementations["revised predation"].ProportionTimeEating = gridCellCohorts[actingCohort].ProportionTimeActive;

                // Calculate the potential biomass available from predation
                if (cellEnvironment["Realm"][0] == 2.0)
                {
                    Implementations["revised predation"].GetEatingPotentialMarine
                        (gridCellCohorts, gridCellStocks, actingCohort,
                        cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions);
                }
                else
                {
                    Implementations["revised predation"].GetEatingPotentialTerrestrial
                        (gridCellCohorts, gridCellStocks, actingCohort,
                        cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions);
                }
                // Run predation to apply changes in prey biomass from predation and add biomass eaten to the delta arrays
                Implementations["revised predation"].RunEating
                    (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas,
                    madingleyCohortDefinitions, madingleyStockDefinitions, trackProcesses,
                    currentTimestep, specificLocations, outputDetail, initialisation);


                break;

            case "omnivore":

                // Get the assimilation efficiency for predation for this cohort from the functional group definitions
                Implementations["revised predation"].AssimilationEfficiency =
                    madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup
                        ("carnivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex);

                // Get the assimilation efficiency for herbivory for this cohort from the functional group definitions
                Implementations["revised herbivory"].AssimilationEfficiency =
                    madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup
                        ("herbivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex);

                // Get the proportion of time spent eating and assign to both the herbivory and predation implementations
                double ProportionTimeEating = gridCellCohorts[actingCohort].ProportionTimeActive;
                Implementations["revised predation"].ProportionTimeEating = ProportionTimeEating;
                Implementations["revised herbivory"].ProportionTimeEating = ProportionTimeEating;

                // Calculate the potential biomass available from herbivory
                if (cellEnvironment["Realm"][0] == 2.0)
                {
                    Implementations["revised herbivory"].GetEatingPotentialMarine
                        (gridCellCohorts, gridCellStocks, actingCohort,
                        cellEnvironment, madingleyCohortDefinitions,
                        madingleyStockDefinitions);
                }
                else
                {
                    Implementations["revised herbivory"].GetEatingPotentialTerrestrial
                        (gridCellCohorts, gridCellStocks, actingCohort,
                        cellEnvironment, madingleyCohortDefinitions,
                        madingleyStockDefinitions);
                }

                // Calculate the potential biomass available from predation
                if (cellEnvironment["Realm"][0] == 2.0)
                {
                    Implementations["revised predation"].GetEatingPotentialMarine
                        (gridCellCohorts, gridCellStocks, actingCohort,
                        cellEnvironment, madingleyCohortDefinitions,
                        madingleyStockDefinitions);
                }
                else
                {
                    Implementations["revised predation"].GetEatingPotentialTerrestrial
                        (gridCellCohorts, gridCellStocks, actingCohort,
                        cellEnvironment, madingleyCohortDefinitions,
                        madingleyStockDefinitions);
                }

                // Calculate the total handling time for all expected kills from predation and expected plant matter eaten in herbivory
                TotalTimeToEatForOmnivores =
                    Implementations["revised herbivory"].TimeUnitsToHandlePotentialFoodItems +
                    Implementations["revised predation"].TimeUnitsToHandlePotentialFoodItems;

                // Assign this total time to the relevant variables in both herbviory and predation, so that actual amounts eaten are calculated correctly
                Implementations["revised herbivory"].TimeUnitsToHandlePotentialFoodItems = TotalTimeToEatForOmnivores;
                Implementations["revised predation"].TimeUnitsToHandlePotentialFoodItems = TotalTimeToEatForOmnivores;

                // Run predation to update prey cohorts and delta biomasses for the acting cohort
                Implementations["revised predation"].RunEating
                    (gridCellCohorts, gridCellStocks, actingCohort,
                    cellEnvironment, deltas, madingleyCohortDefinitions,
                    madingleyStockDefinitions, trackProcesses,
                    currentTimestep, specificLocations, outputDetail, initialisation);

                // Run herbivory to update autotroph biomass and delta biomasses for the acting cohort
                Implementations["revised herbivory"].RunEating
                    (gridCellCohorts, gridCellStocks, actingCohort,
                    cellEnvironment, deltas, madingleyCohortDefinitions,
                    madingleyStockDefinitions, trackProcesses,
                    currentTimestep, specificLocations, outputDetail, initialisation);

                break;

            default:

                // For nutrition source that are not supported, throw an error
                Debug.Fail("The model currently does not contain an eating model for nutrition source:" + NutritionSource);

                break;
            }

            // Check that the biomasses from predation and herbivory in the deltas is a number
            Debug.Assert(!double.IsNaN(deltas["biomass"]["predation"]), "BiomassFromEating is NaN");
            Debug.Assert(!double.IsNaN(deltas["biomass"]["herbivory"]), "BiomassFromEating is NaN");

            double biomassEaten = 0.0;

            if (madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("carnivory assimilation",
                                                                                   gridCellCohorts[actingCohort].FunctionalGroupIndex) > 0)
            {
                biomassEaten += (deltas["biomass"]["predation"] / madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("carnivory assimilation",
                                                                                                                                     gridCellCohorts[actingCohort].FunctionalGroupIndex));
            }
            if (madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("herbivory assimilation",
                                                                                   gridCellCohorts[actingCohort].FunctionalGroupIndex) > 0)
            {
                biomassEaten += (deltas["biomass"]["herbivory"] / madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("herbivory assimilation",
                                                                                                                                     gridCellCohorts[actingCohort].FunctionalGroupIndex));
            }

            if (biomassEaten > 0.0)
            {
                gridCellCohorts[actingCohort].TrophicIndex = 1 +
                                                             (gridCellCohorts[actingCohort].TrophicIndex / (biomassEaten * gridCellCohorts[actingCohort].CohortAbundance));
            }
            else
            {
                gridCellCohorts[actingCohort].TrophicIndex = PreviousTrophicIndex;
            }
        }
Exemple #14
0
 /// <summary>
 /// Calculate the rate of individuals in a cohort that die from background mortality in a model time step
 /// </summary>
 /// <param name="gridCellCohorts">The cohorts 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="bodyMassIncludingChangeThisTimeStep">The body mass of individuals in the acting cohort, including body mass change this time step through eating and mortality</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="currentTimestep">The current model time step</param>
 /// <returns>The rate of individuals in the cohort that die from background mortality</returns>
 public double CalculateMortalityRate(GridCellCohortHandler gridCellCohorts, int[] actingCohort,
                                      double bodyMassIncludingChangeThisTimeStep, Dictionary <string, Dictionary <string, double> > deltas, uint currentTimestep)
 {
     // Convert from mortality rate per mortality formulation time step to mortality rate per model time step
     return(_MortalityRate * DeltaT);
 }
        public uint[] WeightedMassOrderedIndices(GridCellCohortHandler gridCellCohorts, uint[][] cohortIndices, uint numberIndices)
        {
            NonStaticSimpleRNG random = new NonStaticSimpleRNG();

            random.SetSeedFromSystemTime();

            // A vector to hold indices of cohorts in order
            int[] MassOrderedIndices;

            double AboveMinMass = 0;

            double OverallMinMass = 1E9;


            double MaxMass = 0;
            int    MaxFG   = 0;
            int    MaxC    = 0;
            double MinMass = 1E9;
            int    MinFG   = 0;
            int    MinC    = 0;

            for (int ll = 0; ll < gridCellCohorts.Count; ll++)
            {
                // Loop over gridCellCohorts in the functional group
                for (int kk = 0; kk < gridCellCohorts[ll].Count(); kk++)
                {
                    //Check if this cohort is the smallest
                    if (gridCellCohorts[ll][kk].IndividualBodyMass.CompareTo(MaxMass) > 0)
                    {
                        MaxFG   = ll;
                        MaxC    = kk;
                        MaxMass = gridCellCohorts[ll][kk].IndividualBodyMass;
                    }

                    //Check if this cohort is the smallest
                    if (gridCellCohorts[ll][kk].IndividualBodyMass.CompareTo(OverallMinMass) < 0)
                    {
                        MinFG          = ll;
                        MinC           = kk;
                        OverallMinMass = gridCellCohorts[ll][kk].IndividualBodyMass;
                    }
                }
            }

            double MassRange    = MaxMass - OverallMinMass;
            double logMassRange = Math.Log(MaxMass) - Math.Log(OverallMinMass);

            MassOrderedIndices = (int[])(object)this.RandomlyOrderedIndices(numberIndices);//this.MassOrderedIndices(gridCellCohorts,cohortIndices,numberIndices);

            uint[] OrderedIndices = new uint[numberIndices];
            int[]  Acted          = new int[numberIndices];
            int[]  UseIndices;
            int[]  UnActedIndices;
            uint   UnActedCounter;
            double p          = 0;
            int    OrderIndex = 0;

            int[] Cinds;
            do
            {
                //UseIndices = MassOrderedIndices.Where((x,idx) => Acted[idx] == 0).ToArray();
                UseIndices     = new int[numberIndices - Acted.Sum()];
                UnActedIndices = new int[numberIndices - Acted.Sum()];
                UnActedCounter = 0;
                for (int i = 0; i < Acted.Length; i++)
                {
                    if (Acted[i] == 0)
                    {
                        UnActedIndices[UnActedCounter] = i;
                        UnActedCounter++;
                    }
                }

                for (int i = 0; i < UnActedIndices.Length; i++)
                {
                    UseIndices[i] = MassOrderedIndices[UnActedIndices[i]];
                }

                foreach (uint i in UseIndices)
                {
                    Cinds = FindJaggedArrayIndex(i, cohortIndices, numberIndices);

                    p = (Math.Log(gridCellCohorts[Cinds[0]][Cinds[1]].IndividualBodyMass) - Math.Log(OverallMinMass)) / logMassRange;

                    if (random.GetUniform() > p)
                    {
                        OrderedIndices[OrderIndex] = cohortIndices[Cinds[0]][Cinds[1]];
                        OrderIndex++;
                        Acted[Array.FindIndex(MassOrderedIndices, row => row == i)] = 1;
                    }
                }
            } while (Acted.Sum() < (int)(numberIndices * 0.8));

            UseIndices     = new int[numberIndices - Acted.Sum()];
            UnActedIndices = new int[numberIndices - Acted.Sum()];
            UnActedCounter = 0;
            for (int i = 0; i < Acted.Length; i++)
            {
                if (Acted[i] == 0)
                {
                    UnActedIndices[UnActedCounter] = i;
                    UnActedCounter++;
                }
            }

            for (int i = 0; i < UnActedIndices.Length; i++)
            {
                UseIndices[i] = MassOrderedIndices[UnActedIndices[i]];
            }

            foreach (uint i in UseIndices)
            {
                Cinds = FindJaggedArrayIndex(i, cohortIndices, numberIndices);
                OrderedIndices[OrderIndex] = cohortIndices[Cinds[0]][Cinds[1]];
                OrderIndex++;
                Acted[Array.FindIndex(MassOrderedIndices, row => row == i)] = 1;
            }

            //OrderedIndices[OrderIndex] = cohortIndices[MaxFG][MaxC];



            return(OrderedIndices);
        }
Exemple #16
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>
        /// Calculates functional diversity of cohorts in a grid cell as functional richness and functional diveregence (using the Rao Index)
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="cellIndices">The list of cell indices in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell within the list of cells to run</param>
        /// <returns>A pair of values representing the functional richness and functional divergence (functional richness currently disabled!)</returns>
        public double[] CalculateFunctionalDiversity(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions,
                                                     List <uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);

            //Variable to hold the functional richness value for the current cohorts
            double FunctionalRichness;
            //Variable to hold the functional divergence value for the current cohorts
            double RaoFunctionalDivergence = 0.0;

            double[,] Distances = new double[CellCohorts.GetNumberOfCohorts(), CellCohorts.GetNumberOfCohorts()];

            List <string> AllTraitNames = cohortDefinitions.GetAllTraitNames().ToList();

            AllTraitNames.Remove("realm");
            AllTraitNames.Remove("heterotroph/autotroph");
            AllTraitNames.Remove("diet");
            string[] TraitNames = AllTraitNames.ToArray();


            //Define upper and lower limits for body mass
            double MinMass = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min();
            double MaxMass = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max();
            //Define upp and lower limits for trophic index
            double MaxTI = 40.0;
            double MinTI = 1.0;

            // Construct an array of functional trait values for each cohort
            // Rows are specific cohorts
            // Columns are the functional traits (these include different types:
            //      quantative: current mass, trophic index
            //      nominal: diet, reproductive strategy, mobility, metabolism
            Tuple <double[], string[]>[] CohortFunctionalTraits = new Tuple <double[], string[]> [CellCohorts.GetNumberOfCohorts()];
            double[]   IndividualBodyMasses     = new double[CellCohorts.GetNumberOfCohorts()];
            double[]   TrophicIndex             = new double[CellCohorts.GetNumberOfCohorts()];
            string[][] CohortNominalTraitValues = new string[TraitNames.Length][];

            for (int i = 0; i < TraitNames.Length; i++)
            {
                CohortNominalTraitValues[i] = new string[CellCohorts.GetNumberOfCohorts()];
            }

            // Construct a vector of cohort biomass (in case we want to weight by them)
            double[] CohortTotalBiomasses = new double[CellCohorts.GetNumberOfCohorts()];


            string[] TraitValues             = new string[TraitNames.Length];
            double[] QuantitativeTraitValues = new double[2];
            int      CohortNumberCounter     = 0;

            for (int fg = 0; fg < CellCohorts.Count; fg++)
            {
                foreach (Cohort c in CellCohorts[fg])
                {
                    TraitValues = cohortDefinitions.GetTraitValues(TraitNames, fg);
                    for (int ii = 0; ii < TraitValues.Length; ii++)
                    {
                        CohortNominalTraitValues[ii][CohortNumberCounter] = TraitValues[ii];
                    }


                    IndividualBodyMasses[CohortNumberCounter] = c.IndividualBodyMass;
                    TrophicIndex[CohortNumberCounter]         = c.TrophicIndex;

                    QuantitativeTraitValues[0] = c.IndividualBodyMass;
                    QuantitativeTraitValues[1] = c.TrophicIndex;

                    CohortFunctionalTraits[CohortNumberCounter] = new Tuple <double[], string[]>(QuantitativeTraitValues, TraitValues);

                    CohortTotalBiomasses[CohortNumberCounter] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;

                    CohortNumberCounter++;
                }
            }

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

            DistanceList.Add(CalculateDistanceMatrix(IndividualBodyMasses, MaxMass, MinMass));
            DistanceList.Add(CalculateDistanceMatrix(TrophicIndex, MaxTI, MinTI));
            foreach (string[] t in CohortNominalTraitValues)
            {
                DistanceList.Add(CalculateDistanceMatrix(t));
            }

            Distances = CalculateAggregateDistance(DistanceList);

            RaoFunctionalDivergence = RaoEntropy(Distances, CohortTotalBiomasses);

            return(new double[] { 0.0, RaoFunctionalDivergence });
        }
 /// <summary>
 /// Initialize an implementation of reproduction. This is only in here to satisfy the requirements of IEcologicalProcessWithinGridCells
 /// </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="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
 /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
 /// <param name="implementationKey">The name of the reproduction implementation to initialize</param>
 public void InitializeEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, string implementationKey)
 {
 }
Exemple #19
0
        /// <summary>
        /// Remove individuals lost from cohorts through direct harvesting of animals
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="harvestingScenario">The scenario of direct harvesting of animals to apply</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="burninSteps">The number of time steps to spin the model up for before applying the harvesting scenario</param>
        /// <param name="impactSteps">The number of time steps to apply the scenario for</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="impactCell">The index of the cell, within the list of all cells to run, to apply the scenario for</param>
        public void RemoveHarvestedIndividuals(GridCellCohortHandler gridCellCohorts,
                                               Tuple <string, double, double> harvestingScenario, uint currentTimestep, uint burninSteps, uint impactSteps, uint totalSteps,
                                               SortedList <string, double[]> cellEnvironment, Boolean impactCell, string globalModelTimestepUnits, FunctionalGroupDefinitions cohortFGs)
        {
            if (impactCell)
            {
                //If this is marine cell
                if (cellEnvironment["Realm"][0] == 2.0)
                {
                    if (harvestingScenario.Item1 == "no")
                    {
                        // Do not apply any harvesting
                    }
                    else if (harvestingScenario.Item1 == "constant")
                    {
                        double TargetBiomass;
                        if (FisheriesCatch != null)
                        {
                            TargetBiomass = (1000 *
                                             FisheriesCatch.ModelGridCatchTotal[Convert.ToInt32(cellEnvironment["LatIndex"][0]), Convert.ToInt32(cellEnvironment["LonIndex"][0])])
                                            / 12.0;
                        }
                        else
                        {
                            TargetBiomass = harvestingScenario.Item2;
                        }
                        // If the burn-in period has been completed, then apply
                        // the harvesting scenario
                        if (currentTimestep > burninSteps)
                        {
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment);
                        }
                    }
                    else if (harvestingScenario.Item1 == "fish-catch")
                    {
                        //Initialise an instance of ApplyFishingCatches for this cell
                        if (currentTimestep == burninSteps)
                        {
                            ApplyCatches[Convert.ToInt32(cellEnvironment["LatIndex"][0]),
                                         Convert.ToInt32(cellEnvironment["LonIndex"][0])] = new ApplyFishingCatches(FisheriesCatch);
                        }

                        if (currentTimestep > burninSteps)
                        {
                            //Bin the cohorts of the current cell
                            ApplyCatches[Convert.ToInt32(cellEnvironment["LatIndex"][0]),
                                         Convert.ToInt32(cellEnvironment["LonIndex"][0])].BinCohorts(gridCellCohorts, FisheriesCatch, cohortFGs);
                            //Now remove the catch
                            ApplyCatches[Convert.ToInt32(cellEnvironment["LatIndex"][0]),
                                         Convert.ToInt32(cellEnvironment["LonIndex"][0])].ApplyCatches(gridCellCohorts, FisheriesCatch,
                                                                                                       Convert.ToInt32(cellEnvironment["LatIndex"][0]),
                                                                                                       Convert.ToInt32(cellEnvironment["LonIndex"][0]));
                        }
                    }
                }
                else
                {
                    if (harvestingScenario.Item1 == "no")
                    {
                        // Do not apply any harvesting
                    }
                    else if (harvestingScenario.Item1 == "constant")
                    {
                        // If the burn-in period has been completed, then apply
                        // the harvesting scenario
                        if (currentTimestep > burninSteps)
                        {
                            ApplyHarvesting(gridCellCohorts, harvestingScenario.Item2, cellEnvironment);
                        }
                    }
                    else if (harvestingScenario.Item1 == "temporary")
                    {
                        // If the burn-in period has been completed and the period of impact has not elapsed,
                        // then apply the harvesting scenario
                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + impactSteps)))
                        {
                            ApplyHarvesting(gridCellCohorts, harvestingScenario.Item2, cellEnvironment);
                        }
                    }
                    else if (harvestingScenario.Item1 == "escalating")
                    {
                        // If the spin-up period has been completed, then apply a level of harvesting
                        // according to the number of time-steps that have elapsed since the spin-up ended
                        if (currentTimestep > burninSteps)
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(50000, (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.Item2)));

                            // Apply the harvesting scenario using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment);
                        }
                    }
                    else if (harvestingScenario.Item1 == "temp-escalating-declining")
                    {
                        // If the spin-up period has been completed, then apply a level of harvesting
                        // according to the number of time-steps that have elapsed since the spin-up ended
                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + impactSteps)))
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(50000, (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.Item2)));

                            // Apply the harvesting scenario using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment);
                        }
                        else if (currentTimestep > (burninSteps + impactSteps))
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(50000, ((-(totalSteps - currentTimestep) / 12.0) * harvestingScenario.Item2)));

                            // Apply the harvesting scenario using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment);
                        }
                    }
                    else if (harvestingScenario.Item1 == "temp-escalating")
                    {
                        // If the spin-up period has been completed and the period of impact has not elapsed,
                        // then remove a proportion of plant matter
                        // according to the number of time-steps that have elapsed since the spin-up ended
                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + impactSteps)))
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(50000, (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.Item2)));

                            // Apply the harvesting scenarion using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment);
                        }
                    }
                    else if (harvestingScenario.Item1 == "temp-escalating-const-rate")
                    {
                        // If the spin-up period has been completed and the period of impact (specified by the third scenario element
                        // has not elapsed,
                        // then remove a portion of  plant matter
                        // according to the number of time-steps that have elapsed since the spin-up ended

                        int ConstImpactSteps = Convert.ToInt32(harvestingScenario.Item3 * Utilities.ConvertTimeUnits("year", globalModelTimestepUnits));

                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + ConstImpactSteps)))
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(200000, (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.Item2)));

                            // Apply the harvesting scenarion using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment);
                        }
                    }
                    else if (harvestingScenario.Item1 == "temp-escalating-const-rate-duration")
                    {
                        // If the spin-up period has been completed and the period of impact (specified by the third scenario element
                        // has not elapsed,
                        // then remove a proportion of plant matter
                        // according to the number of time-steps that have elapsed since the spin-up ended

                        int ConstImpactSteps = Convert.ToInt32(harvestingScenario.Item3 * Utilities.ConvertTimeUnits("year", globalModelTimestepUnits));

                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + impactSteps)))
                        {
                            //gridCellStocks[actingStock].TotalBiomass -= gridCellStocks[actingStock].TotalBiomass *
                            //    (Math.Min(1.0, (((currentTimestep - burninSteps) / 12.0) * humanNPPScenario.Item2)));

                            double TargetBiomass = (Math.Min(200000,
                                                             Math.Min(((ConstImpactSteps / 12.0) * harvestingScenario.Item2),
                                                                      (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.Item2))));

                            // Apply the harvesting scenarion using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment);
                        }
                    }
                    else
                    {
                        Debug.Fail("There is no method for the harvesting scenario specified");
                    }
                }
            }
        }
Exemple #20
0
        /// <summary>
        /// Update the individual and reproductive body masses of the acting cohort according to the delta biomasses from the ecological processes
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts 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="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">A process tracker</param>
        /// <param name="cellEnvironment">The cell environment</param>
        private void UpdateBiomass(GridCellCohortHandler gridCellCohorts, int[] actingCohort, Dictionary <string, Dictionary <string, double> > deltas,
                                   uint currentTimestep, ProcessTracker tracker, SortedList <string, double[]> cellEnvironment)
        {
            // Extract the biomass deltas from the sorted list of all deltas
            Dictionary <string, double> deltaBiomass = deltas["biomass"];

            if (tracker.TrackProcesses)
            {
                // Calculate net growth of individuals in this cohort
                double growth = deltaBiomass["predation"] + deltaBiomass["herbivory"] + deltaBiomass["metabolism"];
                tracker.TrackTimestepGrowth((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], currentTimestep,
                                            gridCellCohorts[actingCohort].IndividualBodyMass, gridCellCohorts[actingCohort].FunctionalGroupIndex, growth, deltaBiomass["metabolism"], deltaBiomass["predation"], deltaBiomass["herbivory"]);
            }

            // Get all keys from the biomass deltas sorted list
            string[] KeyStrings = deltaBiomass.Keys.ToArray();

            // Variable to calculate net biomass change to check that cohort individual body mass will not become negative
            double NetBiomass = 0.0;

            // Loop over all biomass deltas
            foreach (string key in KeyStrings)
            {
                // Update net biomass change
                NetBiomass += deltaBiomass[key];
            }

            double  BiomassCheck   = 0.0;
            Boolean NetToBeApplied = true;

            // If cohort abundance is greater than zero, then check that the calculated net biomas will not make individual body mass become negative
            if (gridCellCohorts[actingCohort].CohortAbundance.CompareTo(0.0) > 0)
            {
                string output = "Biomass going negative, acting cohort: " + actingCohort[0].ToString() + ", " + actingCohort[1].ToString();
                BiomassCheck = gridCellCohorts[actingCohort].IndividualBodyMass + NetBiomass;
                Debug.Assert((BiomassCheck).CompareTo(0.0) >= 0, output);
            }

            //Loop over all keys in the abundance deltas sorted list
            foreach (string key in KeyStrings)
            {
                // If cohort abundance is zero, then set cohort individual body mass to zero and reset the biomass delta to zero,
                // otherwise update cohort individual body mass and reset the biomass delta to zero
                if (gridCellCohorts[actingCohort].CohortAbundance.CompareTo(0.0) == 0)
                {
                    gridCellCohorts[actingCohort].IndividualBodyMass = 0.0;
                    deltaBiomass[key] = 0.0;
                }
                else
                {
                    if (NetToBeApplied)
                    {
                        gridCellCohorts[actingCohort].IndividualBodyMass += NetBiomass;
                        NetToBeApplied = false;
                    }

                    //gridCellCohorts[actingCohort].IndividualBodyMass += deltaBiomass[key];
                    deltaBiomass[key] = 0.0;
                }
            }

            // Check that individual body mass is still greater than zero
            Debug.Assert(gridCellCohorts[actingCohort].IndividualBodyMass.CompareTo(0.0) >= 0, "biomass < 0");

            // If the current individual body mass is the largest that has been achieved by this cohort, then update the maximum achieved
            // body mass tracking variable for the cohort
            if (gridCellCohorts[actingCohort].IndividualBodyMass > gridCellCohorts[actingCohort].MaximumAchievedBodyMass)
            {
                gridCellCohorts[actingCohort].MaximumAchievedBodyMass = gridCellCohorts[actingCohort].IndividualBodyMass;
            }

            // Extract the reproductive biomass deltas from the sorted list of all deltas
            Dictionary <string, double> deltaReproductiveBiomass = deltas["reproductivebiomass"];

            // Get all keys from the biomass deltas sorted list
            string[] KeyStrings2 = deltas["reproductivebiomass"].Keys.ToArray();

            // Variable to calculate net reproductive biomass change to check that cohort individual body mass will not become negative
            double NetReproductiveBiomass = 0.0;

            // Loop over all reproductive biomass deltas
            foreach (string key in KeyStrings2)
            {
                // Update net reproductive biomass change
                NetReproductiveBiomass += deltaReproductiveBiomass[key];
            }

            //Loop over all keys in the abundance deltas sorted list
            foreach (string key in KeyStrings2)
            {
                // If cohort abundance is zero, then set cohort reproductive body mass to zero and reset the biomass delta to zero,
                // otherwise update cohort reproductive body mass and reset the biomass delta to zero
                if (gridCellCohorts[actingCohort].CohortAbundance.CompareTo(0.0) == 0)
                {
                    gridCellCohorts[actingCohort].IndividualReproductivePotentialMass = 0.0;
                    deltaReproductiveBiomass[key] = 0.0;
                }
                else
                {
                    gridCellCohorts[actingCohort].IndividualReproductivePotentialMass += deltaReproductiveBiomass[key];
                    deltaReproductiveBiomass[key] = 0.0;
                }
            }

            // Note that maturity time step is set in TReproductionBasic
        }
        public double[] CalculateFunctionalRichness(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions,
                                                    List <uint[]> cellIndices, int cellIndex, string trait)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double MinCurrentTraitValue       = double.MaxValue;
            double MaxCurrentTraitValue       = double.MinValue;
            double MinModelTraitValue         = 0.0;
            double MaxModelTraitValue         = 0.0;

            switch (trait.ToLower())
            {
            case "biomass":

                foreach (var CohortList in CellCohorts)
                {
                    foreach (var cohort in CohortList)
                    {
                        if (cohort.IndividualBodyMass < MinCurrentTraitValue)
                        {
                            MinCurrentTraitValue = cohort.IndividualBodyMass;
                        }

                        if (cohort.IndividualBodyMass > MaxCurrentTraitValue)
                        {
                            MaxCurrentTraitValue = cohort.IndividualBodyMass;
                        }
                    }
                }


                //Define upper and lower limits for body mass
                MinModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min();
                MaxModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max();
                break;

            case "trophic index":
                foreach (var CohortList in CellCohorts)
                {
                    foreach (var cohort in CohortList)
                    {
                        if (cohort.TrophicIndex < MinCurrentTraitValue)
                        {
                            MinCurrentTraitValue = cohort.TrophicIndex;
                        }

                        if (cohort.TrophicIndex > MaxCurrentTraitValue)
                        {
                            MaxCurrentTraitValue = cohort.TrophicIndex;
                        }
                    }
                }


                //Define upper and lower limits for body mass
                MinModelTraitValue = MinTI;
                MaxModelTraitValue = MaxTI;

                break;

            default:
                Debug.Fail("Trait not recognised in calculation of ecosystem metrics: " + trait);
                break;
            }

            Debug.Assert((MaxModelTraitValue - MinModelTraitValue) > 0.0, "Division by zero or negative model trait values in calculation of functional richness");

            double[] NewArray = { (MaxCurrentTraitValue - MinCurrentTraitValue) / (MaxModelTraitValue - MinModelTraitValue), MinCurrentTraitValue, MaxCurrentTraitValue };

            return(NewArray);
        }
        /// <summary>
        /// Run mortality
        /// </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 in 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 for cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="trackProcesses">An instance of ProcessTracker to hold diagnostics for mortality</param>
        /// <param name="partial">Thread-locked variables</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level output detail being used for the current model run</param>
        /// <param name="currentMonth">The current model month</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                         int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas,
                                         FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                         uint currentTimestep, ProcessTracker trackProcesses, ref ThreadLockedParallelVariables partial,
                                         Boolean specificLocations, string outputDetail, uint currentMonth, MadingleyModelInitialisation initialisation)
        {
            // Variables to hold the mortality rates
            double MortalityRateBackground;
            double MortalityRateSenescence;
            double MortalityRateStarvation;

            // Variable to hold the total abundance lost to all forms of mortality
            double MortalityTotal;

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

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

            // Calculate the body mass of individuals in this cohort including mass gained through eating this time step, up to but not exceeding adult body mass for this cohort.
            // Should be fine because these deductions are made in the reproduction implementation, but use Math.Min to double check.

            BodyMassIncludingChangeThisTimeStep = 0.0;

            // Loop over all items in the biomass deltas
            foreach (var Biomass in deltas["biomass"])
            {
                // Add the delta biomass to net biomass
                BodyMassIncludingChangeThisTimeStep += Biomass.Value;
            }
            BodyMassIncludingChangeThisTimeStep = Math.Min(gridCellCohorts[actingCohort].AdultMass, BodyMassIncludingChangeThisTimeStep + gridCellCohorts[actingCohort].IndividualBodyMass);

            // Temporary variable to hold net reproductive biomass change of individuals in this cohort as a result of other ecological processes
            ReproductiveMassIncludingChangeThisTimeStep = 0.0;

            // Loop over all items in the biomass deltas
            foreach (var Biomass in deltas["reproductivebiomass"])
            {
                // Add the delta biomass to net biomass
                ReproductiveMassIncludingChangeThisTimeStep += Biomass.Value;
            }

            ReproductiveMassIncludingChangeThisTimeStep += gridCellCohorts[actingCohort].IndividualReproductivePotentialMass;

            // Check to see if the cohort has already been killed by predation etc
            if ((BodyMassIncludingChangeThisTimeStep).CompareTo(0.0) <= 0)
            {
                // If individual body mass is not greater than zero, then all individuals become extinct
                MortalityTotal = gridCellCohorts[actingCohort].CohortAbundance;
            }
            else
            {
                // Calculate background mortality rate
                MortalityRateBackground = Implementations["basic background mortality"].CalculateMortalityRate(gridCellCohorts,
                                                                                                               actingCohort, BodyMassIncludingChangeThisTimeStep, deltas, currentTimestep);

                // If the cohort has matured, then calculate senescence mortality rate, otherwise set rate to zero
                if (gridCellCohorts[actingCohort].MaturityTimeStep != uint.MaxValue)
                {
                    MortalityRateSenescence = Implementations["basic senescence mortality"].CalculateMortalityRate(gridCellCohorts,
                                                                                                                   actingCohort, BodyMassIncludingChangeThisTimeStep, deltas, currentTimestep);
                }
                else
                {
                    MortalityRateSenescence = 0.0;
                }

                // Calculate the starvation mortality rate based on individual body mass and maximum body mass ever
                // achieved by this cohort
                MortalityRateStarvation = Implementations["basic starvation mortality"].CalculateMortalityRate(gridCellCohorts, actingCohort, BodyMassIncludingChangeThisTimeStep, deltas, currentTimestep);

                // Calculate the number of individuals that suffer mortality this time step from all sources of mortality
                MortalityTotal = (1 - Math.Exp(-MortalityRateBackground - MortalityRateSenescence -
                                               MortalityRateStarvation)) * gridCellCohorts[actingCohort].CohortAbundance;
            }

            // If the process tracker is on and output detail is set to high and this cohort has not been merged yet, then record
            // the number of individuals that have died
            if (trackProcesses.TrackProcesses && (outputDetail == "high") && (!gridCellCohorts[actingCohort].Merged))
            {
                trackProcesses.RecordMortality((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], gridCellCohorts[actingCohort].BirthTimeStep,
                                               currentTimestep, gridCellCohorts[actingCohort].IndividualBodyMass, gridCellCohorts[actingCohort].AdultMass,
                                               gridCellCohorts[actingCohort].FunctionalGroupIndex,
                                               gridCellCohorts[actingCohort].CohortID[0], MortalityTotal, "sen/bg/starv");
            }

            // Remove individuals that have died from the delta abundance for this cohort
            deltas["abundance"]["mortality"] = -MortalityTotal;

            // Add the biomass of individuals that have died to the delta biomass in the organic pool (including reproductive
            // potential mass, and mass gained through eating, and excluding mass lost through metabolism)
            deltas["organicpool"]["mortality"] = MortalityTotal * (BodyMassIncludingChangeThisTimeStep + ReproductiveMassIncludingChangeThisTimeStep);
        }
Exemple #23
0
        /// <summary>
        /// Merge cohorts for responsive dispersal only; merges identical cohorts, no matter how many times they have been merged before
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <returns>Number of cohorts merged</returns>
        public int MergeForResponsiveDispersalOnly(GridCellCohortHandler gridCellCohorts)
        {
            // Variable to track the total number of cohorts merged
            int NumberCombined = 0;

            //Loop over all functional groups
            for (int i = 0; i < gridCellCohorts.Count; i++)
            {
                // Loop over each cohort in each functional group
                for (int j = 0; j < gridCellCohorts[i].Count; j++)
                {
                    // If that cohort has abundance greater than zero  then check if there are similar cohorts that could be merged with it
                    if (gridCellCohorts[i][j].CohortAbundance > 0)
                    {
                        // Loop over all cohorts above the jth in the cohort list
                        for (int k = j + 1; k < gridCellCohorts[i].Count; k++)
                        {
                            // Check that kth cohort has abunance and that the two cohorts being compared do not represent a juvenile adult pairing
                            if (gridCellCohorts[i][k].CohortAbundance > 0 &&
                                ((gridCellCohorts[i][j].MaturityTimeStep == uint.MaxValue && gridCellCohorts[i][k].MaturityTimeStep == uint.MaxValue) ||
                                 (gridCellCohorts[i][j].MaturityTimeStep < uint.MaxValue && gridCellCohorts[i][k].MaturityTimeStep < uint.MaxValue)))
                            {
                                //Check that the individual masses are widentical
                                if (gridCellCohorts[i][j].IndividualBodyMass == gridCellCohorts[i][k].IndividualBodyMass)
                                {
                                    //Check that the adult masses are similar
                                    if (gridCellCohorts[i][j].AdultMass == gridCellCohorts[i][k].AdultMass)
                                    {
                                        //Check that the juvenile masses are similar
                                        if (gridCellCohorts[i][j].JuvenileMass == gridCellCohorts[i][k].JuvenileMass)
                                        {
                                            //Check that the Maximum achieved mass is similar
                                            if (gridCellCohorts[i][j].MaximumAchievedBodyMass == gridCellCohorts[i][k].MaximumAchievedBodyMass)
                                            {
                                                // In half of cases, add the abundance of the second cohort to that of the first and maintain the properties of the first
                                                if (RandomNumberGenerator.GetUniform() < 0.5)
                                                {
                                                    // Add the abundance of the second cohort to that of the first
                                                    gridCellCohorts[i][j].CohortAbundance += (gridCellCohorts[i][k].CohortAbundance * gridCellCohorts[i][k].IndividualBodyMass) / gridCellCohorts[i][j].IndividualBodyMass;
                                                    // Set the abundance of the second cohort to zero
                                                    gridCellCohorts[i][k].CohortAbundance = 0.0;
                                                    // Add the reproductive potential mass of the second cohort to that of the first
                                                    gridCellCohorts[i][j].IndividualReproductivePotentialMass += (gridCellCohorts[i][k].IndividualReproductivePotentialMass * gridCellCohorts[i][k].CohortAbundance) / gridCellCohorts[i][j].CohortAbundance;
                                                    // Designate both cohorts as having merged
                                                    gridCellCohorts[i][j].Merged = true;
                                                    gridCellCohorts[i][k].Merged = true;
                                                }
                                                // In all other cases, add the abundance of the first cohort to that of the second and maintain the properties of the second
                                                else
                                                {
                                                    // Add the abundance of the first cohort to that of the second
                                                    gridCellCohorts[i][k].CohortAbundance += (gridCellCohorts[i][j].CohortAbundance * gridCellCohorts[i][j].IndividualBodyMass) / gridCellCohorts[i][k].IndividualBodyMass;
                                                    // Set the abundance of the second cohort to zero
                                                    gridCellCohorts[i][j].CohortAbundance = 0.0;
                                                    // Add the reproductive potential mass of the second cohort to that of the first
                                                    gridCellCohorts[i][k].IndividualReproductivePotentialMass += (gridCellCohorts[i][j].IndividualReproductivePotentialMass * gridCellCohorts[i][j].CohortAbundance) / gridCellCohorts[i][k].CohortAbundance;
                                                    // Designate both cohorts as having merged
                                                    gridCellCohorts[i][j].Merged = true;
                                                    gridCellCohorts[i][k].Merged = true;
                                                }
                                                // Increment the number of cohorts combined
                                                NumberCombined += 1;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(NumberCombined);
        }
        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>
 /// Initialises herbivory implementation each time step
 /// </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="madingleyCohortDefinitions">The definitions for cohorts in the model</param>
 /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param>
 /// <remarks>This only works if: a) herbivory is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips
 /// It is critical to run this every time step</remarks>
 public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions)
 {
     // Get the functional group indices of all autotroph stocks
     _FunctionalGroupIndicesToEat = madingleyStockDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "Autotroph", false);
 }
Exemple #26
0
        /// <summary>
        /// Merge cohorts until below a specified threshold number of cohorts in each grid cell
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts within this grid cell</param>
        /// <param name="TotalNumberOfCohorts">The total number of cohorts in this grid cell</param>
        /// <param name="TargetCohortThreshold">The target threshold to reduce the number of cohorts to</param>
        /// <returns>The number of cohorts that have been merged</returns>
        public int MergeToReachThreshold(GridCellCohortHandler gridCellCohorts, int TotalNumberOfCohorts, int TargetCohortThreshold)
        {
            // A list of shortest distances between pairs of cohorts
            List <Tuple <double, int, int[]> > ShortestDistances = new List <Tuple <double, int, int[]> >();

            // A holding list
            //     List<Tuple<double, int, int[]>> HoldingList = new List<Tuple<double, int, int[]>>();

            // Vector of lists of shortest distances in each functional group
            //     List<Tuple<double, int, int[]>>[] ShortestDistancesPerFunctionalGroup = new List<Tuple<double, int, int[]>>[gridCellCohorts.Count];

            // Temporary
            List <Tuple <double, int, int[]> >[] ShortestDistancesPerFunctionalGroup2 = new List <Tuple <double, int, int[]> > [gridCellCohorts.Count];

            // How many cohorts to remove to hit the threshold
            int NumberToRemove = TotalNumberOfCohorts - TargetCohortThreshold;

            // Holds the pairwise distances between two cohorts; the functional group of the cohorts; the cohort IDs of each cohort
            Tuple <double, int, int[]> PairwiseDistance;

            // Loop through functional groups
            for (int ff = 0; ff < gridCellCohorts.Count; ff++)
            {
                // Temporary
                ShortestDistancesPerFunctionalGroup2[ff] = new List <Tuple <double, int, int[]> >();

                // Loop through cohorts within functional groups
                for (int cc = 0; cc < gridCellCohorts[ff].Count - 1; cc++)
                {
                    // Loop through comparison cohorts
                    for (int dd = cc + 1; dd < gridCellCohorts[ff].Count; dd++)
                    {
                        // Randomly select which cohort is to be merge to & calculate distance between cohort pair
                        if (RandomNumberGenerator.GetUniform() < 0.5)
                        {
                            PairwiseDistance = new Tuple <double, int, int[]>(CalculateDistance(gridCellCohorts[ff][cc], gridCellCohorts[ff][dd]), ff, new int[] { cc, dd });
                        }
                        else
                        {
                            PairwiseDistance = new Tuple <double, int, int[]>(CalculateDistance(gridCellCohorts[ff][cc], gridCellCohorts[ff][dd]), ff, new int[] { dd, cc });
                        }

                        // Temporary
                        ShortestDistancesPerFunctionalGroup2[ff].Add(PairwiseDistance);
                    }
                }

                // Temporary
                ShortestDistancesPerFunctionalGroup2[ff] = ShortestDistancesPerFunctionalGroup2[ff].OrderBy(x => x.Item1).ToList();
            }

            // Hold the current position in the shortest distance list
            int        CurrentListPosition = 0;
            List <int> IndicesToRemove;

            // Now that the shortest distances have been calculated, do the merging execution
            int FunctionalGroup;
            int CohortToMergeFrom;
            int CohortToMergeTo;

            // Temporary
            for (int gg = 0; gg < gridCellCohorts.Count; gg++)
            {
                IndicesToRemove     = new List <int>();
                CurrentListPosition = 0;
                while (CurrentListPosition < ShortestDistancesPerFunctionalGroup2[gg].Count)
                {
                    CohortToMergeFrom = ShortestDistancesPerFunctionalGroup2[gg][CurrentListPosition].Item3[1];
                    CohortToMergeTo   = ShortestDistancesPerFunctionalGroup2[gg][CurrentListPosition].Item3[0];

                    for (int cc = ShortestDistancesPerFunctionalGroup2[gg].Count - 1; cc > CurrentListPosition; cc--)
                    {
                        if (ShortestDistancesPerFunctionalGroup2[gg][cc].Item3[0] == CohortToMergeFrom ||
                            ShortestDistancesPerFunctionalGroup2[gg][cc].Item3[1] == CohortToMergeFrom)
                        {
                            ShortestDistancesPerFunctionalGroup2[gg].RemoveAt(cc);
                        }
                    }

                    CurrentListPosition++;
                }
            }

            // Compile all shortest distances into a single list for merging purposes - note that we only need to do a limited number of merges
            for (int gg = 0; gg < gridCellCohorts.Count; gg++)
            {
                foreach (var distance in ShortestDistancesPerFunctionalGroup2[gg])
                {
                    ShortestDistances.Add(distance);
                }
            }

            ShortestDistances = ShortestDistances.OrderBy(x => x.Item1).ToList();

            // Counts the number of merges that have happened
            int MergeCounter = 0;

            CurrentListPosition = 0;

            // While merging does not reach threshold, and while there are still elements in the list
            while ((MergeCounter < NumberToRemove) && (CurrentListPosition < ShortestDistances.Count))
            {
                // Get pairwise traits
                FunctionalGroup   = ShortestDistances[CurrentListPosition].Item2;
                CohortToMergeFrom = ShortestDistances[CurrentListPosition].Item3[1];
                CohortToMergeTo   = ShortestDistances[CurrentListPosition].Item3[0];

                // Check whether either cohort has already merged to something else this timestep merge
                // execution, and hence is empty
                //          if ((gridCellCohorts[FunctionalGroup][CohortToMergeFrom].CohortAbundance.CompareTo(0.0) > 0) ||
                //              (gridCellCohorts[FunctionalGroup][CohortToMergeTo].CohortAbundance.CompareTo(0.0) > 0))
                //          {

                // Add the abundance of the second cohort to that of the first
                gridCellCohorts[FunctionalGroup][CohortToMergeTo].CohortAbundance += (gridCellCohorts[FunctionalGroup][CohortToMergeFrom].CohortAbundance * gridCellCohorts[FunctionalGroup][CohortToMergeFrom].IndividualBodyMass) / gridCellCohorts[FunctionalGroup][CohortToMergeTo].IndividualBodyMass;
                // Add the reproductive potential mass of the second cohort to that of the first
                gridCellCohorts[FunctionalGroup][CohortToMergeTo].IndividualReproductivePotentialMass += (gridCellCohorts[FunctionalGroup][CohortToMergeFrom].IndividualReproductivePotentialMass * gridCellCohorts[FunctionalGroup][CohortToMergeFrom].CohortAbundance) / gridCellCohorts[FunctionalGroup][CohortToMergeTo].CohortAbundance;
                // Set the abundance of the second cohort to zero
                gridCellCohorts[FunctionalGroup][CohortToMergeFrom].CohortAbundance = 0.0;
                // Designate both cohorts as having merged
                gridCellCohorts[FunctionalGroup][CohortToMergeTo].Merged   = true;
                gridCellCohorts[FunctionalGroup][CohortToMergeFrom].Merged = true;

                MergeCounter++;
                CurrentListPosition++;

                //       }
                //   else
                //   {
                //        CurrentListPosition++;
                //      }
            }

            return(MergeCounter);
        }
        /// <summary>
        /// Calculate the actual amount eaten in herbivory, apply the changes to the eaten autotroph stocks, and update deltas for the herbivore cohort
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in this grid cell</param>
        /// <param name="gridCellStocks">The stocks in this grid cell</param>
        /// <param name="actingCohort">The acting cohort</param>
        /// <param name="cellEnvironment">The environmental conditions in this 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 functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks in the model</param>
        /// <param name="trackProcesses">An instance of ProcessTracker to hold diagnostics for herbivory</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail being used in this model run</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEating(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort, SortedList <string, double[]>
                              cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas, FunctionalGroupDefinitions madingleyCohortDefinitions,
                              FunctionalGroupDefinitions madingleyStockDefinitions, ProcessTracker trackProcesses, uint currentTimestep, Boolean specificLocations,
                              string outputDetail, MadingleyModelInitialisation initialisation)
        {
            EdibleScaling = 1.0;
            if (cellEnvironment["Realm"][0] == 1.0)
            {
                EdibleScaling = 0.1;
            }

            // Loop over autotroph functional groups that can be eaten
            foreach (int FunctionalGroup in _FunctionalGroupIndicesToEat)
            {
                // Loop over stocks within the functional groups
                for (int i = 0; i < gridCellStocks[FunctionalGroup].Count; i++)
                {
                    // Get the mass from this stock that is available for eating (assumes only 10% is edible in the terrestrial realm)
                    EdibleMass = gridCellStocks[FunctionalGroup][i].TotalBiomass * EdibleScaling;

                    // Calculate the biomass actually eaten from this stock by the acting cohort
                    _BiomassesEaten[FunctionalGroup][i] = CalculateBiomassesEaten(_PotentialBiomassesEaten[FunctionalGroup][i],
                                                                                  _TimeUnitsToHandlePotentialFoodItems, gridCellCohorts[actingCohort].CohortAbundance, EdibleMass);

                    gridCellCohorts[actingCohort].TrophicIndex += _BiomassesEaten[FunctionalGroup][i];

                    // Remove the biomass eaten from the autotroph stock
                    gridCellStocks[FunctionalGroup][i].TotalBiomass -= _BiomassesEaten[FunctionalGroup][i];

                    // If the model is being run for specific locations and if track processes has been specified, then track the mass flow between
                    // primary producer and herbivore
                    if (specificLocations && trackProcesses.TrackProcesses)
                    {
                        trackProcesses.RecordHerbivoryMassFlow(currentTimestep, _BodyMassHerbivore, _BiomassesEaten[FunctionalGroup][i]);
                    }

                    // If track processes has been specified and the output detail level is set to high and the model is being run for specific locations,
                    // then track the flow of mass between trophic levels
                    if (trackProcesses.TrackProcesses && (outputDetail == "high") && specificLocations)
                    {
                        trackProcesses.TrackHerbivoryTrophicFlow((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                                                 gridCellCohorts[actingCohort].FunctionalGroupIndex, madingleyCohortDefinitions, _BiomassesEaten[FunctionalGroup][i], _BodyMassHerbivore, initialisation, cellEnvironment["Realm"][0] == 2.0);
                    }


                    // Check that the biomass eaten is not a negative value
                    // Commented out for purposes of speed
                    //Debug.Assert(_BiomassesEaten[FunctionalGroup][i] >= 0,
                    //    "Herbivory negative for this herbivore cohort" + actingCohort);

                    // Add the biomass eaten and assimilated by an individual to the delta biomass for the acting cohort
                    deltas["biomass"]["herbivory"] += _BiomassesEaten[FunctionalGroup][i] * AssimilationEfficiency / gridCellCohorts[actingCohort].CohortAbundance;

                    // Move the biomass eaten but not assimilated by an individual into the organic matter pool
                    deltas["organicpool"]["herbivory"] += _BiomassesEaten[FunctionalGroup][i] * (1 - AssimilationEfficiency);
                }

                // Check that the delta biomass from eating for the acting cohort is not negative
                // Commented out for the purposes of speed
                //Debug.Assert(deltas["biomass"]["herbivory"] >= 0, "Delta biomass from herbviory is negative");

                // Calculate the total biomass eaten by the acting (herbivore) cohort
                _TotalBiomassEatenByCohort = deltas["biomass"]["herbivory"] * gridCellCohorts[actingCohort].CohortAbundance;
            }
        }
 /// <summary>
 /// Initialize an implementation of mortality. This is only in here to satisfy the requirements of IEcologicalProcessAcrossGridCells
 /// </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="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
 /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
 /// <param name="implementationKey">The name of the implementation of mortality to initialize</param>
 public void InitializeEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                         FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                         string implementationKey, SortedList <string, double[]> cellEnvironmen)
 {
 }