/// <summary> /// Run reproduction /// </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="processTracker">An instance of ProcessTracker to hold diagnostics for eating</param> /// <param name="partial">Thread-locked variables for the parallelised version</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 this 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 processTracker, ref ThreadLockedParallelVariables partial, Boolean specificLocations, string outputDetail, uint currentMonth, MadingleyModelInitialisation initialisation) { // Holds the reproductive strategy of a cohort bool _Iteroparous = madingleyCohortDefinitions.GetTraitNames("reproductive strategy", actingCohort[0])=="iteroparity"; // Assign mass to reproductive potential Implementations["reproduction basic"].RunReproductiveMassAssignment(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimeStep, processTracker); // Run reproductive events. Note that we can't skip juveniles here as they could conceivably grow to adulthood and get enough biomass to reproduce in a single time step // due to other ecological processes Implementations["reproduction basic"].RunReproductionEvents(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimeStep, processTracker, ref partial, _Iteroparous, currentMonth); }
/// <summary> /// Generate new cohorts from reproductive potential mass /// </summary> /// <param name="gridCellCohorts">The cohorts in the current grid cell</param> /// <param name="gridCellStocks">The stocks in the current grid cell</param> /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param> /// <param name="cellEnvironment">The environment of the current grid cell</param> /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param> /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param> /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param> /// <param name="currentTimestep">The current model time step</param> /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param> /// <param name="partial">Thread-locked variables</param> public void RunReproduction(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort, SortedList<string, double[]> cellEnvironment, Dictionary<string, Dictionary<string, double>> deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, uint currentTimestep, ProcessTracker tracker, ref ThreadLockedParallelVariables partial) { // Check that the abundance in the cohort to produce is greater than or equal to zero Debug.Assert(_OffspringCohortAbundance >= 0.0, "Offspring abundance < 0"); // Get the adult and juvenile masses of the cohort to produce double[] OffspringProperties = GetOffspringCohortProperties(gridCellCohorts, actingCohort, madingleyCohortDefinitions); // Update cohort abundance in case juvenile mass has been altered _OffspringCohortAbundance = (_OffspringCohortAbundance * gridCellCohorts[actingCohort].JuvenileMass) / OffspringProperties[0]; //Create the offspring cohort Cohort OffspringCohort = new Cohort((byte)actingCohort[0], OffspringProperties[0], OffspringProperties[1], OffspringProperties[0], _OffspringCohortAbundance, (ushort)currentTimestep, ref partial.NextCohortIDThreadLocked); // Add the offspring cohort to the grid cell cohorts array gridCellCohorts[actingCohort[0]].Add(OffspringCohort); // If the cohort has never been merged with another cohort, then add it to the tracker for output as diagnostics if ((!gridCellCohorts[actingCohort].Merged) && tracker.TrackProcesses) tracker.RecordNewCohort((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], currentTimestep, _OffspringCohortAbundance, gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex); // Subtract all of the reproductive potential mass of the parent cohort, which has been used to generate the new // cohort, from the delta reproductive potential mass deltas["reproductivebiomass"]["reproduction"] -= (gridCellCohorts[actingCohort].IndividualReproductivePotentialMass); }
/// <summary> /// Run metabolism /// </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 metabolism</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) { double Realm = cellEnvironment["Realm"][0]; if (madingleyCohortDefinitions.GetTraitNames("Heterotroph/Autotroph", gridCellCohorts[actingCohort].FunctionalGroupIndex) == "heterotroph") { if (madingleyCohortDefinitions.GetTraitNames("Endo/Ectotherm", gridCellCohorts[actingCohort].FunctionalGroupIndex) == "endotherm") { Implementations["basic endotherm"].RunMetabolism(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, currentMonth); } else { Implementations["basic ectotherm"].RunMetabolism(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, currentMonth); } } // 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")) { trackProcesses.TrackTimestepMetabolism((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], currentTimestep, gridCellCohorts[actingCohort].IndividualBodyMass, actingCohort[0], cellEnvironment["Temperature"][currentMonth], deltas["biomass"]["metabolism"]); } }
/// <summary> /// Run processes for cells sequentially /// </summary> public void RunCellsSequentially(MadingleyModelInitialisation initialisation) { // Instantiate a class to hold thread locked global diagnostic variables ThreadLockedParallelVariables singleThreadDiagnostics = new ThreadLockedParallelVariables { Extinctions = 0, Productions = 0, NextCohortIDThreadLocked = NextCohortID }; if (initialisation.RunRealm == "") { for (int ii = 0; ii < _CellList.Count; ii++) { RunCell(ii, singleThreadDiagnostics, initialisation.DispersalOnly, initialisation); } } else { if (initialisation.RunRealm == "marine") { for (int ii = 0; ii < _CellList.Count; ii++) { if (EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["Realm"][0] == 2.0) RunCell(ii, singleThreadDiagnostics, initialisation.DispersalOnly, initialisation); } } else if (initialisation.RunRealm == "terrestrial") { for (int ii = 0; ii < _CellList.Count; ii++) { if (EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["Realm"][0] == 1.0) RunCell(ii, singleThreadDiagnostics, initialisation.DispersalOnly, initialisation); } } else { Console.WriteLine("Run Single Realm needs to be 'marine', 'terrestrial', or blank"); Console.ReadKey(); } } // Update the variable tracking cohort unique IDs NextCohortID = singleThreadDiagnostics.NextCohortIDThreadLocked; // Take the results from the thread local variables and apply to the global diagnostic variables GlobalDiagnosticVariables["NumberOfCohortsExtinct"] = singleThreadDiagnostics.Extinctions - singleThreadDiagnostics.Combinations; GlobalDiagnosticVariables["NumberOfCohortsProduced"] = singleThreadDiagnostics.Productions; GlobalDiagnosticVariables["NumberOfCohortsInModel"] = GlobalDiagnosticVariables["NumberOfCohortsInModel"] + singleThreadDiagnostics.Productions - singleThreadDiagnostics.Extinctions; GlobalDiagnosticVariables["NumberOfCohortsCombined"] = singleThreadDiagnostics.Combinations; }
/// <summary> /// A method to run the main ecosystem model loop in parallel (latitudinal strips) /// </summary> /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param> /// <param name="partial">A threadlockedparallelvariable that is used to pass global diagnostic information back with locking or race conditions</param> /// <param name="dispersalOnly">Whether to run dispersal only (i.e. to turn all other ecological processes off</param> /// <param name="initialisation">The Madingley Model intialisation</param> /// <remarks>Note that variables and instances of classes that are written to within this method MUST be local within this method to prevent /// race issues and multiple threads attempting to write to the same variable when running the program in parallel</remarks> public void RunCell(int cellIndex, ThreadLockedParallelVariables partial, Boolean dispersalOnly, MadingleyModelInitialisation initialisation) { // Apply any climate change impacts ClimateChangeSimulator.ApplyTemperatureScenario( EcosystemModelGrid.GetCellEnvironment(_CellList[cellIndex][0], _CellList[cellIndex][1]), _TemperatureScenario,CurrentTimeStep,CurrentMonth,NumBurninSteps,NumImpactSteps, ((initialisation.ImpactCellIndices.Contains((uint)cellIndex) || initialisation.ImpactAll))); // Create a temporary internal copy of the grid cell cohorts GridCellCohortHandler WorkingGridCellCohorts = EcosystemModelGrid.GetGridCellCohorts(_CellList[cellIndex][0], _CellList[cellIndex][1]); // Create a temporary internal copy of the grid cell stocks GridCellStockHandler WorkingGridCellStocks = EcosystemModelGrid.GetGridCellStocks(_CellList[cellIndex][0], _CellList[cellIndex][1]); // Run stock ecology RunWithinCellStockEcology(_CellList[cellIndex][0], _CellList[cellIndex][1], WorkingGridCellStocks, cellIndex, initialisation); // Run within cell ecology if we are not doing dispersal only if (dispersalOnly) { // Run cohort ecology RunWithinCellDispersalOnly(_CellList[cellIndex][0], _CellList[cellIndex][1], partial, WorkingGridCellCohorts, WorkingGridCellStocks); } else { // Run cohort ecology RunWithinCellCohortEcology(_CellList[cellIndex][0], _CellList[cellIndex][1], partial, WorkingGridCellCohorts, WorkingGridCellStocks, InitialisationFileStrings["OutputDetail"], cellIndex, initialisation); } // Apply any direct harvesting impacts HarvestingSimulator.RemoveHarvestedIndividuals(WorkingGridCellCohorts, _HarvestingScenario, CurrentTimeStep, NumBurninSteps, NumImpactSteps,NumTimeSteps, EcosystemModelGrid.GetCellEnvironment(_CellList[cellIndex][0], _CellList[cellIndex][1]), (initialisation.ImpactCellIndices.Contains((uint)cellIndex) || initialisation.ImpactAll), _GlobalModelTimeStepUnit, CohortFunctionalGroupDefinitions); // For runs with specific locations and where track processes has been specified, write out mass flows data and reset the mass flow tracker // for the next time step if (SpecificLocations && ProcessTrackers[cellIndex].TrackProcesses) { ProcessTrackers[cellIndex].EndTimeStepPredationTracking(CurrentTimeStep); ProcessTrackers[cellIndex].EndTimeStepHerbvioryTracking(CurrentTimeStep); } }
private void RunWithinCellDispersalOnly(uint latCellIndex, uint lonCellIndex, ThreadLockedParallelVariables partial, GridCellCohortHandler workingGridCellCohorts, GridCellStockHandler workingGridCellStocks) { // Merge cohorts. Requires cohorts to be identical, for testing purposes (remember that they don't grow etc) // SHOULD ONLY BE RUN FOR RESPONSIVE DISPERSAL TESTING //partial.Combinations = Merger.MergeForResponsiveDispersalOnly(workingGridCellCohorts); // Loop over cohorts and remove any whose abundance is below the extinction threshold for (int kk = 0; kk < CohortFunctionalGroupDefinitions.GetNumberOfFunctionalGroups(); kk++) { // Create a list to hold the cohorts to remove List<int> CohortIndicesToRemove = new List<int>(); // Loop through each cohort in the functional group for (int ll = 0; ll < workingGridCellCohorts[kk].Count; ll++) { // If cohort abundance is less than the extinction threshold then add to the list for extinction if (workingGridCellCohorts[kk][ll].CohortAbundance <= _ExtinctionThreshold) { CohortIndicesToRemove.Add(ll); partial.Extinctions += 1; } } // Note that we don't keep track of the organic biomass pool if running dispersal only, since there are cohorts with strange biomasses for (int ll = (CohortIndicesToRemove.Count - 1); ll >= 0; ll--) { // Remove the extinct cohort from the list of cohorts workingGridCellCohorts[kk].RemoveAt(CohortIndicesToRemove[ll]); } } // Write out the updated cohort numbers after all ecological processes have occured EcosystemModelGrid.SetGridCellCohorts(workingGridCellCohorts, latCellIndex, lonCellIndex); }
private void RunWithinCellCohortEcology(uint latCellIndex, uint lonCellIndex, ThreadLockedParallelVariables partial, GridCellCohortHandler workingGridCellCohorts, GridCellStockHandler workingGridCellStocks,string outputDetail, int cellIndex, MadingleyModelInitialisation initialisation) { // Local instances of classes EcologyCohort MadingleyEcologyCohort = new EcologyCohort(); Activity CohortActivity = new Activity(); CohortMerge CohortMerger = new CohortMerge(DrawRandomly); // A list of the original cohorts inside a particular grid cell int[] OriginalGridCellCohortsNumbers; // A vector to hold the order in which cohorts will act uint[] RandomCohortOrder; // A jagged array to keep track of cohorts that are being worked on uint[][] CohortIndices; // The location of the acting cohort int[] ActingCohort = new int[2]; // Temporary local variables int EcosystemModelParallelTempval1; int EcosystemModelParallelTempval2; // Boolean to pass into function to get cell environmental data to check if the specified variable exists bool VarExists; // variable to track cohort number uint TotalCohortNumber = 0; // Fill in the array with the number of cohorts per functional group before ecological processes are run OriginalGridCellCohortsNumbers = new int[workingGridCellCohorts.Count]; for (int i = 0; i < workingGridCellCohorts.Count; i++) { OriginalGridCellCohortsNumbers[i] = workingGridCellCohorts[i].Count; } // Initialize ecology for stocks and cohorts MadingleyEcologyCohort.InitializeEcology(EcosystemModelGrid.GetCellEnvironment(latCellIndex, lonCellIndex)["Cell Area"][0], _GlobalModelTimeStepUnit, DrawRandomly); // Create a jagged array indexed by functional groups to hold cohort indices CohortIndices = new uint[CohortFunctionalGroupDefinitions.GetNumberOfFunctionalGroups()][]; // Loop over functional groups for (int ll = 0; ll < CohortFunctionalGroupDefinitions.GetNumberOfFunctionalGroups(); ll++) { // Dimension the number of columns in each row of the jagged array to equal number of gridCellCohorts in each functional group if (workingGridCellCohorts[ll] == null) { CohortIndices[ll] = new uint[0]; } else { CohortIndices[ll] = new uint[workingGridCellCohorts[ll].Count()]; } // Loop over gridCellCohorts in the functional group for (int kk = 0; kk < CohortIndices[ll].Count(); kk++) { // Fill jagged array with indices for each cohort CohortIndices[ll][kk] = TotalCohortNumber; TotalCohortNumber += 1; } } if (DrawRandomly) { // Randomly order the cohort indices RandomCohortOrder = Utilities.RandomlyOrderedIndices(TotalCohortNumber); } else { RandomCohortOrder = Utilities.NonRandomlyOrderedCohorts(TotalCohortNumber, CurrentTimeStep); } // Diagnostic biological variables don't need to be reset every cohort, but rather every grid cell EcosystemModelParallelTempval2 = 0; // Initialise eating formulations MadingleyEcologyCohort.EatingFormulations["Basic eating"].InitializeEcologicalProcess(workingGridCellCohorts, workingGridCellStocks, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, "revised predation"); MadingleyEcologyCohort.EatingFormulations["Basic eating"].InitializeEcologicalProcess(workingGridCellCohorts, workingGridCellStocks , CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, "revised herbivory"); // Loop over randomly ordered gridCellCohorts to implement biological functions for (int ll = 0; ll < RandomCohortOrder.Length; ll++) { // Locate the randomly chosen cohort within the array of lists of gridCellCohorts in the grid cell ActingCohort = Utilities.FindJaggedArrayIndex(RandomCohortOrder[ll], CohortIndices, TotalCohortNumber); // Perform all biological functions except dispersal (which is cross grid cell) if (workingGridCellCohorts[ActingCohort].CohortAbundance.CompareTo(_ExtinctionThreshold) > 0) { // Calculate number of cohorts in this functional group in this grid cell before running ecology EcosystemModelParallelTempval1 = workingGridCellCohorts[ActingCohort[0]].Count; CohortActivity.AssignProportionTimeActive(workingGridCellCohorts[ActingCohort], EcosystemModelGrid.GetCellEnvironment(latCellIndex, lonCellIndex), CohortFunctionalGroupDefinitions, CurrentTimeStep, CurrentMonth); // Run ecology MadingleyEcologyCohort.RunWithinCellEcology(workingGridCellCohorts, workingGridCellStocks, ActingCohort, EcosystemModelGrid.GetCellEnvironment(latCellIndex, lonCellIndex), EcosystemModelGrid.GetCellDeltas(latCellIndex, lonCellIndex), CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, CurrentTimeStep, ProcessTrackers[cellIndex], ref partial, SpecificLocations,outputDetail, CurrentMonth, initialisation); // Update the properties of the acting cohort MadingleyEcologyCohort.UpdateEcology(workingGridCellCohorts, workingGridCellStocks, ActingCohort, EcosystemModelGrid.GetCellEnvironment(latCellIndex, lonCellIndex), EcosystemModelGrid.GetCellDeltas( latCellIndex, lonCellIndex), CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, CurrentTimeStep, ProcessTrackers[cellIndex]); // Add newly produced cohorts to the tracking variable EcosystemModelParallelTempval2 += workingGridCellCohorts[ActingCohort[0]].Count - EcosystemModelParallelTempval1; // Check that the mass of individuals in this cohort is still >= 0 after running ecology Debug.Assert(workingGridCellCohorts[ActingCohort].IndividualBodyMass >= 0.0, "Biomass < 0 for this cohort"); } // Check that the mass of individuals in this cohort is still >= 0 after running ecology Debug.Assert(workingGridCellCohorts[ActingCohort].IndividualBodyMass >= 0.0, "Biomass < 0 for this cohort"); } // Update diagnostics of productions partial.Productions += EcosystemModelParallelTempval2; RunExtinction(latCellIndex, lonCellIndex, partial, workingGridCellCohorts, cellIndex); // Merge cohorts, if necessary if (workingGridCellCohorts.GetNumberOfCohorts() > initialisation.MaxNumberOfCohorts) { partial.Combinations = CohortMerger.MergeToReachThresholdFast(workingGridCellCohorts, workingGridCellCohorts.GetNumberOfCohorts(), initialisation.MaxNumberOfCohorts); //Run extinction a second time to remove those cohorts that have been set to zero abundance when merging RunExtinction(latCellIndex, lonCellIndex, partial, workingGridCellCohorts, cellIndex); } else partial.Combinations = 0; // Write out the updated cohort numbers after all ecological processes have occured EcosystemModelGrid.SetGridCellCohorts(workingGridCellCohorts, latCellIndex, lonCellIndex); }
/// <summary> /// Carries out extinction on cohorts that have an abundance below a defined extinction threshold /// </summary> private void RunExtinction(uint latCellIndex, uint lonCellIndex, ThreadLockedParallelVariables partial, GridCellCohortHandler workingGridCellCohorts, int cellIndex) { bool VarExists; // Loop over cohorts and remove any whose abundance is below the extinction threshold for (int kk = 0; kk < CohortFunctionalGroupDefinitions.GetNumberOfFunctionalGroups(); kk++) { // Create a list to hold the cohorts to remove List<int> CohortIndicesToRemove = new List<int>(); // Loop through each cohort in the functional group for (int ll = 0; ll < workingGridCellCohorts[kk].Count; ll++) { // If cohort abundance is less than the extinction threshold then add to the list for extinction if (workingGridCellCohorts[kk][ll].CohortAbundance.CompareTo(_ExtinctionThreshold) <= 0 || workingGridCellCohorts[kk][ll].IndividualBodyMass.CompareTo(0.0) == 0) { CohortIndicesToRemove.Add(ll); partial.Extinctions += 1; // If track processes is set and output detail is set to high and the cohort being made extinct has never been merged, // then output its mortality profile if (ProcessTrackers[cellIndex].TrackProcesses && (InitialisationFileStrings["OutputDetail"] == "high") && (workingGridCellCohorts[kk][ll].CohortID.Count == 1)) { ProcessTrackers[cellIndex].OutputMortalityProfile(workingGridCellCohorts[kk][ll].CohortID[0]); } } } // Code to add the biomass to the biomass pool and dispose of the cohort for (int ll = (CohortIndicesToRemove.Count - 1); ll >= 0; ll--) { // Add biomass of the extinct cohort to the organic matter pool EcosystemModelGrid.SetEnviroLayer("Organic Pool", 0, EcosystemModelGrid.GetEnviroLayer("Organic Pool", 0, latCellIndex, lonCellIndex, out VarExists) + (workingGridCellCohorts[kk][CohortIndicesToRemove[ll]].IndividualBodyMass + workingGridCellCohorts[kk][CohortIndicesToRemove[ll]].IndividualReproductivePotentialMass) * workingGridCellCohorts[kk][CohortIndicesToRemove[ll]].CohortAbundance, latCellIndex, lonCellIndex); Debug.Assert(EcosystemModelGrid.GetEnviroLayer("Organic Pool", 0, latCellIndex, lonCellIndex, out VarExists) > 0, "Organic pool < 0"); if (ProcessTrackers[cellIndex].TrackProcesses && SpecificLocations == true) ProcessTrackers[cellIndex].RecordExtinction(latCellIndex, lonCellIndex, CurrentTimeStep, workingGridCellCohorts[kk][CohortIndicesToRemove[ll]].Merged, workingGridCellCohorts[kk][CohortIndicesToRemove[ll]].CohortID); // Remove the extinct cohort from the list of cohorts workingGridCellCohorts[kk].RemoveAt(CohortIndicesToRemove[ll]); } } }
/// <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; } }
/// <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> /// 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); }
/// <summary> /// Run ecological processes that operate on cohorts within a single 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="deltas">A sorted list of deltas to track changes in abundances and biomasses during the ecological processes</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 the process tracker</param> /// <param name="partial">Thread-locked local 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 this model run</param> /// <param name="currentMonth">The current model month</param> /// <param name="initialisation">The Madingley Model initialisation</param> public void RunWithinCellEcology(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) { // RUN EATING _EatingFormulations["Basic eating"].RunEcologicalProcess(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, trackProcesses, ref partial, specificLocations, outputDetail, currentMonth, initialisation); // RUN METABOLISM - THIS TIME TAKE THE METABOLIC LOSS TAKING INTO ACCOUNT WHAT HAS BEEN INGESTED THROUGH EATING _MetabolismFormulations["Basic metabolism"].RunEcologicalProcess(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, trackProcesses, ref partial, specificLocations, outputDetail, currentMonth, initialisation); // RUN REPRODUCTION - TAKING INTO ACCOUNT NET BIOMASS CHANGES RESULTING FROM EATING AND METABOLISING _ReproductionFormulations["Basic reproduction"].RunEcologicalProcess(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, trackProcesses, ref partial, specificLocations, outputDetail, currentMonth, initialisation); // RUN MORTALITY - TAKING INTO ACCOUNT NET BIOMASS CHANGES RESULTING FROM EATING, METABOLISM AND REPRODUCTION _MortalityFormulations["Basic mortality"].RunEcologicalProcess(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, trackProcesses, ref partial, specificLocations, outputDetail, currentMonth, initialisation); }