/// <summary> /// Output the mortality profile of a cohort becoming extinct /// </summary> /// <param name="cohortID">The ID of the cohort becoming extinct</param> public void OutputMortalityProfile(uint cohortID) { string CohortIDString = Convert.ToString(cohortID); if (MortalityList.ContainsKey(CohortIDString)) { if (RandomNumberGenerator.GetUniform() > 0.95) { var Lines = ((IEnumerable)MortalityList[CohortIDString]).Cast <object>().ToList(); foreach (var Line in Lines) { SyncMortalityWriter.WriteLine(Line); } } MortalityList.Remove(CohortIDString); } /* * if (MortalityList.ContainsKey(StringCID)) * { * lock (MortalityList.SyncRoot) * { * var Lines = ((IEnumerable)MortalityList[StringCID]).Cast<object>().ToList(); * // Loop over mortality events for the specified cohort and write these to the output file * foreach (var Line in Lines) * { * SyncMortalityWriter.WriteLine(Line); * } * * // Remove the cohort from the list of mortality profiles * MortalityList.Remove(Convert.ToString(cohortID)); * } * } */ }
/// <summary> /// Generate a random value to see if a cohort disperses /// </summary> /// <param name="dispersalProbability">The probability of dispersal</param> /// <returns>Returns either the random value, if it less than dispersal probability, or -1</returns> protected double CheckForDispersal(double dispersalProbability) { // Randomly check to see if dispersal occurs double RandomValue = RandomNumberGenerator.GetUniform(); if (dispersalProbability >= RandomValue) { return(RandomValue); } else { return(-1.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; }
/// <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); }
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); }