/// <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 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> /// 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> /// 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 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"]); } }