예제 #1
0
        /// <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);
            }
        }
예제 #3
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;
        }
예제 #4
0
        /// <summary>
        /// Merge cohorts until below a specified threshold number of cohorts in each grid cell
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts within this grid cell</param>
        /// <param name="TotalNumberOfCohorts">The total number of cohorts in this grid cell</param>
        /// <param name="TargetCohortThreshold">The target threshold to reduce the number of cohorts to</param>
        /// <returns>The number of cohorts that have been merged</returns>
        public int MergeToReachThreshold(GridCellCohortHandler gridCellCohorts, int TotalNumberOfCohorts, int TargetCohortThreshold)
        {
            // A list of shortest distances between pairs of cohorts
            List <Tuple <double, int, int[]> > ShortestDistances = new List <Tuple <double, int, int[]> >();

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

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

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

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

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

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

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

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

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

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

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

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

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

                    CurrentListPosition++;
                }
            }

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

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

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

            CurrentListPosition = 0;

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

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

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

                MergeCounter++;
                CurrentListPosition++;

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

            return(MergeCounter);
        }
        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);
        }