/// <summary>
        /// Calculate trophic evenness using the Rao Index
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of cells to be run in the current simulation</param>
        /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param>
        /// <returns>Trophic evenness</returns>
        public double CalculateFunctionalEvennessRao(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions,
                                                     List <uint[]> cellIndices, int cellIndex, string trait)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);

            double[] EvennessValues = new double[2];

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

            double[] FunctionalTrait    = new double[CellCohorts.GetNumberOfCohorts()];
            double   MaxModelTraitValue = 0;
            double   MinModelTraitValue = 0;

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


            int CohortNumberCounter = 0;

            switch (trait.ToLower())
            {
            case "biomass":
                for (int fg = 0; fg < CellCohorts.Count; fg++)
                {
                    foreach (Cohort c in CellCohorts[fg])
                    {
                        FunctionalTrait[CohortNumberCounter]      = c.IndividualBodyMass;
                        CohortTotalBiomasses[CohortNumberCounter] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;

                        CohortNumberCounter++;
                    }
                }

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

            case "trophic index":
                for (int fg = 0; fg < CellCohorts.Count; fg++)
                {
                    foreach (Cohort c in CellCohorts[fg])
                    {
                        FunctionalTrait[CohortNumberCounter]      = c.IndividualBodyMass;
                        CohortTotalBiomasses[CohortNumberCounter] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;

                        CohortNumberCounter++;
                    }
                }
                MinModelTraitValue = MinTI;
                MaxModelTraitValue = MaxTI;
                break;
            }


            Distances = CalculateDistanceMatrix(FunctionalTrait, MaxModelTraitValue, MinModelTraitValue);

            return(RaoEntropy(Distances, CohortTotalBiomasses));
        }
        public void OutputCurrentModelState(ModelGrid currentModelGrid, List <uint[]> cellIndices, uint currentTimestep)
        {
            GridCellCohortHandler TempCohorts;
            GridCellStockHandler  TempStocks;

            string context;
            string organism;

            context = Convert.ToString(currentTimestep) + "\t";

            foreach (uint[] cell in cellIndices)
            {
                context = Convert.ToString(currentTimestep) + "\t" +
                          Convert.ToString(currentModelGrid.GetCellLatitude(cell[0])) + "\t" +
                          Convert.ToString(currentModelGrid.GetCellLongitude(cell[1])) + "\t";

                TempStocks  = currentModelGrid.GetGridCellStocks(cell[0], cell[1]);
                TempCohorts = currentModelGrid.GetGridCellCohorts(cell[0], cell[1]);

                foreach (List <Stock> ListS in TempStocks)
                {
                    foreach (Stock S in ListS)
                    {
                        organism = "-999\tS" + Convert.ToString(S.FunctionalGroupIndex) + "\t" +
                                   "-999\t-999\t" + Convert.ToString(S.IndividualBodyMass) + "\t" +
                                   Convert.ToString(S.TotalBiomass) + "\t" +
                                   "-999\t-999\t-999\t-999\t-999\t-999";
                        SyncStateWriter.WriteLine(context + organism);
                    }
                }

                foreach (List <Cohort> ListC in TempCohorts)
                {
                    foreach (Cohort C in ListC)
                    {
                        organism = Convert.ToString(C.CohortID) + "\t" +
                                   Convert.ToString(C.FunctionalGroupIndex) + "\t" +
                                   Convert.ToString(C.JuvenileMass) + "\t" +
                                   Convert.ToString(C.AdultMass) + "\t" +
                                   Convert.ToString(C.IndividualBodyMass) + "\t" +
                                   Convert.ToString(C.CohortAbundance) + "\t" +
                                   Convert.ToString(C.IndividualReproductivePotentialMass) + "\t" +
                                   Convert.ToString(C.BirthTimeStep) + "\t" +
                                   Convert.ToString(C.MaturityTimeStep) + "\t" +
                                   Convert.ToString(C.LogOptimalPreyBodySizeRatio) + "\t" +
                                   Convert.ToString(C.MaximumAchievedBodyMass) + "\t" +
                                   Convert.ToString(C.TrophicIndex) + "\t" +
                                   Convert.ToString(C.ProportionTimeActive);

                        SyncStateWriter.WriteLine(context + organism);
                    }
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Run dispersal
        /// </summary>
        public void RunCrossGridCellEcologicalProcess(uint[] cellIndex, ModelGrid gridForDispersal, bool dispersalOnly, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, uint currentMonth)
        {

            // Create a temporary handler for grid cell cohorts
            GridCellCohortHandler WorkingGridCellCohorts;

            // Get the lat and lon indices
            uint ii = cellIndex[0];
            uint jj = cellIndex[1];

            // A boolean to check that the environmental layer exists
            bool varExists;

            // Check to see if the cell is marine
            double CellRealm = gridForDispersal.GetEnviroLayer("Realm", 0, ii, jj, out varExists);

            // Go through all of the cohorts in turn and see if they disperse
            WorkingGridCellCohorts = gridForDispersal.GetGridCellCohorts(ii, jj);

            // Loop through cohorts, and perform dispersal according to cohort type and status
            for (int kk = 0; kk < WorkingGridCellCohorts.Count; kk++)
            {
                // Work through the list of cohorts
                for (int ll = 0; ll < WorkingGridCellCohorts[kk].Count; ll++)
                {
                    // Check to see if the cell is marine and the cohort type is planktonic
                    if (CellRealm == 2.0 &&
                        ((madingleyCohortDefinitions.GetTraitNames("Mobility", WorkingGridCellCohorts[kk][ll].FunctionalGroupIndex) == "planktonic") || (WorkingGridCellCohorts[kk][ll].IndividualBodyMass <= PlanktonThreshold)))
                    {
                        // Run advective dispersal
                        Implementations["basic advective dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth);

                    }
                    // Otherwise, if mature do responsive dispersal
                    else if (WorkingGridCellCohorts[kk][ll].MaturityTimeStep < uint.MaxValue)
                    {
                        // Run diffusive dispersal 
                        Implementations["basic responsive dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth);
                    }
                    // If the cohort is immature, run diffusive dispersal
                    else
                    {
                        Implementations["basic diffusive dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth);
                    }
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Run dispersal
        /// </summary>
        public void RunCrossGridCellEcologicalProcess(uint[] cellIndex, ModelGrid gridForDispersal, bool dispersalOnly, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, uint currentMonth)
        {
            // Create a temporary handler for grid cell cohorts
            GridCellCohortHandler WorkingGridCellCohorts;

            // Get the lat and lon indices
            uint ii = cellIndex[0];
            uint jj = cellIndex[1];

            // A boolean to check that the environmental layer exists
            bool varExists;

            // Check to see if the cell is marine
            double CellRealm = gridForDispersal.GetEnviroLayer("Realm", 0, ii, jj, out varExists);

            // Go through all of the cohorts in turn and see if they disperse
            WorkingGridCellCohorts = gridForDispersal.GetGridCellCohorts(ii, jj);

            // Loop through cohorts, and perform dispersal according to cohort type and status
            for (int kk = 0; kk < WorkingGridCellCohorts.Count; kk++)
            {
                // Work through the list of cohorts
                for (int ll = 0; ll < WorkingGridCellCohorts[kk].Count; ll++)
                {
                    // Check to see if the cell is marine and the cohort type is planktonic
                    if (CellRealm == 2.0 &&
                        ((madingleyCohortDefinitions.GetTraitNames("Mobility", WorkingGridCellCohorts[kk][ll].FunctionalGroupIndex) == "planktonic") || (WorkingGridCellCohorts[kk][ll].IndividualBodyMass <= PlanktonThreshold)))
                    {
                        // Run advective dispersal
                        Implementations["basic advective dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth);
                    }
                    // Otherwise, if mature do responsive dispersal
                    else if (WorkingGridCellCohorts[kk][ll].MaturityTimeStep < uint.MaxValue)
                    {
                        // Run diffusive dispersal
                        Implementations["basic responsive dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth);
                    }
                    // If the cohort is immature, run diffusive dispersal
                    else
                    {
                        Implementations["basic diffusive dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth);
                    }
                }
            }
        }
        /// <summary>
        /// Calculates trophic evenness using the FRO Index of Mouillot et al.
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of cells to be run in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param>
        /// <returns>Trophic evenness</returns>
        /// <remarks>From Mouillot et al (2005) Functional regularity: a neglected aspect of functional diversity, Oecologia</remarks>
        public double CalculateTrophicEvennessFRO(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            List <double[]>       TrophicIndexBiomassDistribution = new List <double[]>();

            double[] TIBiomass;
            double[] EW;

            foreach (var CohortList in CellCohorts)
            {
                foreach (Cohort c in CohortList)
                {
                    TIBiomass    = new double[2];
                    TIBiomass[0] = c.TrophicIndex;
                    TIBiomass[1] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;
                    TrophicIndexBiomassDistribution.Add(TIBiomass);
                }
            }

            TrophicIndexBiomassDistribution = TrophicIndexBiomassDistribution.OrderBy(x => x[0]).ToList();


            //Use the Mouillot Evenness index - Functional Regularity Index or FRO
            //From Mouillot et al (2005) Functional regularity: a neglected aspect of functional diversity, Oecologia

            EW = new double[TrophicIndexBiomassDistribution.Count];
            double TotalEW = 0.0;

            for (int ii = 0; ii < TrophicIndexBiomassDistribution.Count - 1; ii++)
            {
                EW[ii]   = (TrophicIndexBiomassDistribution[ii + 1][0] - TrophicIndexBiomassDistribution[ii][0]) / (TrophicIndexBiomassDistribution[ii + 1][1] + TrophicIndexBiomassDistribution[ii][1]);
                TotalEW += EW[ii];
            }

            double FRO = 0.0;

            for (int ii = 0; ii < TrophicIndexBiomassDistribution.Count - 1; ii++)
            {
                FRO += Math.Min(EW[ii] / TotalEW, 1.0 / (TrophicIndexBiomassDistribution.Count - 1));
            }

            return(FRO);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Return the distribution of biomasses among trophic level bins
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of cell indices to be run in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell in the list of cells to be run</param>
        /// <returns>The distribution of biomasses among trophic level bins</returns>
        public double[] CalculateTrophicDistribution(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);

            double[] TrophicIndexBinMasses = new double[NumberTrophicBins];
            int      BinIndex;

            foreach (var CohortList in CellCohorts)
            {
                foreach (Cohort c in CohortList)
                {
                    BinIndex = _TrophicIndexBinValues.ToList().IndexOf(_TrophicIndexBinValues.Last(x => x < c.TrophicIndex));
                    TrophicIndexBinMasses[BinIndex] += (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;
                }
            }

            return(TrophicIndexBinMasses);
        }
        /// <summary>
        /// Calculates the mean trophic level of all individual organisms in a grid cell
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of cell indices in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell in the list of cells to run</param>
        /// <returns>The mean trophic level of individuals in the grid cell</returns>
        public double CalculateMeanTrophicLevelCell(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double BiomassWeightedTI          = 0.0;
            double TotalBiomass  = 0.0;
            double CohortBiomass = 0.0;

            foreach (var CohortList in CellCohorts)
            {
                foreach (Cohort c in CohortList)
                {
                    CohortBiomass      = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;
                    BiomassWeightedTI += CohortBiomass * c.TrophicIndex;
                    TotalBiomass      += CohortBiomass;
                }
            }

            return(BiomassWeightedTI / TotalBiomass);
        }
        /// <summary>
        /// Calculates the geometric community weighted mean body mass
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of cells to be run in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param>
        /// <returns>geometric community weighted mean body mass</returns>
        public double CalculateGeometricCommunityMeanBodyMass(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double CumulativeAbundance        = 0.0;
            double CumulativeLogBiomass       = 0.0;

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

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

            return(CWGMBM);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Make a record of the properties of the intial model cohorts in the new cohorts output file
        /// </summary>
        public void RecordInitialCohorts()
        {
            int i = 0;
            foreach (uint[] cell in _CellList)
            {
                if (ProcessTrackers[i].TrackProcesses)
                {

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

                    for (int FunctionalGroup = 0; FunctionalGroup < TempCohorts.Count; FunctionalGroup++)
                    {
                        foreach (Cohort item in TempCohorts[FunctionalGroup])
                        {
                            ProcessTrackers[i].RecordNewCohort(cell[0], cell[1], 0, item.CohortAbundance, item.AdultMass, item.FunctionalGroupIndex,
                                new List<uint> { uint.MaxValue }, item.CohortID[0]);
                        }
                    }
                }
                i += 1;
            }
        }
        private double[, , ,] CalculateCurrentCohortState(ModelGrid currentModelState, string variableName, int numLats, int numLons, int numFG, int numCohorts, List<uint[]> cellList)
        {
            //Calculate the cohort state
            double[, , ,] State = new double[numLats, numLons, numFG, numCohorts];
            GridCellCohortHandler CellCohorts;

            for (int cellIndex = 0; cellIndex < cellList.Count; cellIndex++)
            {

                CellCohorts = currentModelState.GetGridCellCohorts(cellList[cellIndex][0], cellList[cellIndex][1]);

                for (int functionalGroupIndex = 0; functionalGroupIndex < CellCohorts.Count; functionalGroupIndex++)
                {
                    for (int cohortIndex = 0; cohortIndex < CellCohorts[functionalGroupIndex].Count; cohortIndex++)
                    {
                        switch (variableName)
                        {
                            case "JuvenileMass":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].JuvenileMass;
                                break;
                            case "AdultMass":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].AdultMass;
                                break;
                            case "IndividualBodyMass":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].IndividualBodyMass;
                                break;
                            case "CohortAbundance":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].CohortAbundance;
                                break;
                            case "BirthTimeStep":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = (double)CellCohorts[functionalGroupIndex][cohortIndex].BirthTimeStep;
                                break;
                            case "MaturityTimeStep":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = (double)CellCohorts[functionalGroupIndex][cohortIndex].MaturityTimeStep;
                                break;
                            case "LogOptimalPreyBodySizeRatio":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].LogOptimalPreyBodySizeRatio;
                                break;
                            case "MaximumAchievedBodyMass":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].MaximumAchievedBodyMass;
                                break;
                            case "Merged":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = (double)CellCohorts[functionalGroupIndex][cohortIndex].BirthTimeStep;
                                break;
                            case "TrophicIndex":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].BirthTimeStep;
                                break;
                            case "ProportionTimeActive":
                                State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].ProportionTimeActive;
                                break;
                        }
                    }

                }
            }

            return State;
        }
        /// <summary>
        /// Record dispersal events in the dispersal tracker
        /// </summary>
        /// <param name="inboundCohorts">The cohorts arriving in a grid cell in the current time step</param>
        /// <param name="outboundCohorts">The cohorts leaving a ce  ll in the current time step</param>
        /// <param name="outboundCohortWeights">The body masses of cohorts leaving the cell in the current time step</param>
        /// <param name="currentTimeStep">The current model time step</param>
        /// <param name="madingleyModelGrid">The model grid</param>
        public void RecordDispersal(uint[, ,] inboundCohorts, uint[, ,] outboundCohorts, List<double>[,] outboundCohortWeights, uint currentTimeStep, ModelGrid madingleyModelGrid)
        {
            // Loop through cells in the grid and write out the necessary data
            for (uint ii = 0; ii < outboundCohorts.GetLength(0); ii++)
            {
                for (uint jj = 0; jj < outboundCohorts.GetLength(1); jj++)
                {
                    double MeanOutboundCohortWeight = new double();

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

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

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

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

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

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

                    SyncedDispersalWriter.WriteLine(newline);
                }
            }
        }
        public double[] CalculateFunctionalRichness(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions,
                                                    List <uint[]> cellIndices, int cellIndex, string trait)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double MinCurrentTraitValue       = double.MaxValue;
            double MaxCurrentTraitValue       = double.MinValue;
            double MinModelTraitValue         = 0.0;
            double MaxModelTraitValue         = 0.0;

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

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

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


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

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

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


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

                break;

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

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

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

            return(NewArray);
        }
        /// <summary>
        /// Calculates the abundances and biomasses within mass bins for all functional groups in the cohort indices array
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="cellIndex">The number of the current cell in the list of indices of active cells</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        private void CalculateMassBinOutputs(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex, Boolean marineCell)
        {
            string[] Keys;
            if (marineCell)
            {
                // Get the cohort trait combinations to consider
                Keys = CohortTraitIndicesMarine.Keys.ToArray();
            }
            else
            {
                // Get the cohort trait combinations to consider
                Keys = CohortTraitIndices.Keys.ToArray();
            }
            // Loop over trait combinations
            foreach (var TraitValue in Keys)
            {
                // Declare vectors to hold abundance and biomass in mass bins for this trait combination
                double[] WorkingAbundanceInMassBins = new double[MassBinNumber];
                double[] WorkingBiomassInMassBins = new double[MassBinNumber];

                // Declare arrays to hold abundance and biomass in juvenile vs. adult mass bins for this trait combination
                double[,] WorkingAbundanceJuvenileAdultMassBins = new double[MassBinNumber, MassBinNumber];
                double[,] WorkingBiomassJuvenileAdultMassBins = new double[MassBinNumber, MassBinNumber];

                // Create a temporary local copy of the cohorts in this grid cell
                GridCellCohortHandler TempCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0],cellIndices[cellIndex][1]);

                if (marineCell)
                {
                    // Loop over functional  groups
                    foreach (int FunctionalGroupIndex in CohortTraitIndicesMarine[TraitValue])
                    {
                        // Loop over all cohorts in this functional  group
                        for (int cohort = 0; cohort < TempCohorts[FunctionalGroupIndex].Count; cohort++)
                        {
                            // Find the appropriate mass bin for the cohort
                            int mb = 0;
                            do
                            {
                                mb++;
                            } while (mb < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass > MassBins[mb]);

                            // Add the cohort's abundance to the approriate mass bin. Note that we have to differentiate here for non-obligate zooplankton, because they are only added in if they are
                            // below the zooplankton mass threshold (or an obligate zooplankton)
                            if (String.Equals(TraitValue, "Zooplankton (all)"))
                            {
                                if (TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass < PlanktonSizeThreshold || CohortTraitIndicesMarine["Obligate zooplankton"].Contains(FunctionalGroupIndex))
                                {
                                    WorkingAbundanceInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance;

                                    // Add the cohort's biomass to the approriate mass bin
                                    WorkingBiomassInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass;

                                    // Find the mass bin appropriate for this cohort's juvenile mass
                                    int j = 0;
                                    do
                                    {
                                        j++;
                                    } while (j < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].JuvenileMass > MassBins[j]);
                                    // Find the mass bin appropriate for this cohort's adult mass
                                    int a = 0;
                                    do
                                    {
                                        a++;
                                    } while (a < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].AdultMass > MassBins[a]);

                                   // Add the cohort's abundance to this adult vs juvenile mass bins
                                    WorkingAbundanceJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance;
                                    // Add the cohort's biomass to this adult vs juvenile mass bins
                                    WorkingBiomassJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass;
                                }
                            }
                            else
                            {
                                WorkingAbundanceInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance;

                                // Add the cohort's biomass to the approriate mass bin
                                WorkingBiomassInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass;

                                // Find the mass bin appropriate for this cohort's juvenile mass
                                int j = 0;
                                do
                                {
                                    j++;
                                } while (j < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].JuvenileMass > MassBins[j]);
                                // Find the mass bin appropriate for this cohort's adult mass
                                int a = 0;
                                do
                                {
                                    a++;
                                } while (a < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].AdultMass > MassBins[a]);

                                // Add the cohort's abundance to this adult vs juvenile mass bins
                                WorkingAbundanceJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance;
                                // Add the cohort's biomass to this adult vs juvenile mass bins
                                WorkingBiomassJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass;
                            }
                        }
                    }

                    //Copy the working vectors and arrays to the sortedlist for the current key value
                    AbundancesInMassBins[TraitValue] = WorkingAbundanceInMassBins;
                    BiomassesInMassBins[TraitValue] = WorkingBiomassInMassBins;
                    AbundancesInJuvenileAdultMassBins[TraitValue] = WorkingAbundanceJuvenileAdultMassBins;
                    BiomassesInJuvenileAdultMassBins[TraitValue] = WorkingBiomassJuvenileAdultMassBins;
                }
                else
                {
                    // Loop over functional  groups
                    foreach (int FunctionalGroupIndex in CohortTraitIndices[TraitValue])
                    {
                        // Loop over all cohorts in this functional  group
                        for (int cohort = 0; cohort < TempCohorts[FunctionalGroupIndex].Count; cohort++)
                        {
                            // Find the appropriate mass bin for the cohort
                            int mb = 0;
                            do
                            {
                                mb++;
                            } while (mb < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass > MassBins[mb]);

                            // Add the cohort's abundance to the approriate mass bin
                            WorkingAbundanceInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance;
                            // Add the cohort's biomass to the approriate mass bin
                            WorkingBiomassInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass;

                            // Find the mass bin appropriate for this cohort's juvenile mass
                            int j = 0;
                            do
                            {
                                j++;
                            } while (j < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].JuvenileMass > MassBins[j]);
                            // Find the mass bin appropriate for this cohort's adult mass
                            int a = 0;
                            do
                            {
                                a++;
                            } while (a < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].AdultMass > MassBins[a]);

                            // Add the cohort's abundance to this adult vs juvenile mass bins
                            WorkingAbundanceJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance;
                            // Add the cohort's biomass to this adult vs juvenile mass bins
                            WorkingBiomassJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass;

                        }
                    }

                    //Copy the working vectors and arrays to the sortedlist for the current key value
                    AbundancesInMassBins[TraitValue] = WorkingAbundanceInMassBins;
                    BiomassesInMassBins[TraitValue] = WorkingBiomassInMassBins;
                    AbundancesInJuvenileAdultMassBins[TraitValue] = WorkingAbundanceJuvenileAdultMassBins;
                    BiomassesInJuvenileAdultMassBins[TraitValue] = WorkingBiomassJuvenileAdultMassBins;
                }
            }

            // Loop over trait combinations and log abundances and body masses
            foreach (var TraitValue in Keys)
            {
                for (int i = 0; i < MassBins.Length; i++)
                {
                    AbundancesInMassBins[TraitValue][i] = (AbundancesInMassBins[TraitValue][i] > 0) ? Math.Log(AbundancesInMassBins[TraitValue][i]) : ecosystemModelGrid.GlobalMissingValue;
                    BiomassesInMassBins[TraitValue][i] = (BiomassesInMassBins[TraitValue][i] > 0) ? Math.Log(BiomassesInMassBins[TraitValue][i]) : ecosystemModelGrid.GlobalMissingValue;
                    for (int j = 0; j < MassBins.Length; j++)
                    {
                        AbundancesInJuvenileAdultMassBins[TraitValue][i, j] = (AbundancesInJuvenileAdultMassBins[TraitValue][i, j] > 0) ? Math.Log(AbundancesInJuvenileAdultMassBins[TraitValue][i, j]) : ecosystemModelGrid.GlobalMissingValue;
                        BiomassesInJuvenileAdultMassBins[TraitValue][i, j] = (BiomassesInJuvenileAdultMassBins[TraitValue][i, j] > 0) ? Math.Log(BiomassesInJuvenileAdultMassBins[TraitValue][i, j]) : ecosystemModelGrid.GlobalMissingValue;
                    }
                }

            }
        }
Ejemplo n.º 14
0
        public void OutputCurrentModelState(ModelGrid currentModelGrid, List <uint[]> cellIndices, uint currentTimestep)
        {
            GridCellCohortHandler TempCohorts;
            GridCellStockHandler  TempStocks;

            string context;
            string organism;

            context = Convert.ToString(currentTimestep) + "\t";

            using (var StateWriter = File.AppendText(this.FileName))
            {
                foreach (uint[] cell in cellIndices)
                {
                    context = Convert.ToString(currentTimestep) + "\t" +
                              Convert.ToString(currentModelGrid.GetCellLatitude(cell[0])) + "\t" +
                              Convert.ToString(currentModelGrid.GetCellLongitude(cell[1])) + "\t";

                    TempStocks  = currentModelGrid.GetGridCellStocks(cell[0], cell[1]);
                    TempCohorts = currentModelGrid.GetGridCellCohorts(cell[0], cell[1]);

                    foreach (List <Stock> ListS in TempStocks)
                    {
                        foreach (Stock S in ListS)
                        {
                            organism = "-999\tS" + Convert.ToString(S.FunctionalGroupIndex) + "\t" +
                                       "-999\t-999\t" + Convert.ToString(S.IndividualBodyMass) + "\t" +
                                       Convert.ToString(S.TotalBiomass / S.IndividualBodyMass) + "\t" +
                                       "-999\t-999\t-999\t-999\t-999\t-999";
                            StateWriter.WriteLine(context + organism);
                        }
                    }

                    foreach (List <Cohort> ListC in TempCohorts)
                    {
                        foreach (Cohort C in ListC)
                        {
#if true
                            var cohortIds = C.CohortID.Select(id => Convert.ToString(id));

                            organism = String.Join(";", cohortIds) + "\t" +
#else
                            organism = Convert.ToString(C.CohortID) + "\t" +
#endif
                                       Convert.ToString(C.FunctionalGroupIndex) + "\t" +
                                       Convert.ToString(C.JuvenileMass) + "\t" +
                                       Convert.ToString(C.AdultMass) + "\t" +
                                       Convert.ToString(C.IndividualBodyMass) + "\t" +
                                       Convert.ToString(C.CohortAbundance) + "\t" +
                                       Convert.ToString(C.BirthTimeStep) + "\t" +
                                       Convert.ToString(C.MaturityTimeStep) + "\t" +
                                       Convert.ToString(C.LogOptimalPreyBodySizeRatio) + "\t" +
                                       Convert.ToString(C.MaximumAchievedBodyMass) + "\t" +
                                       Convert.ToString(C.TrophicIndex) + "\t" +
                                       Convert.ToString(C.ProportionTimeActive);

                            StateWriter.WriteLine(context + organism);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Return the distribution of biomasses among trophic level bins
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of cell indices to be run in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell in the list of cells to be run</param>
        /// <returns>The distribution of biomasses among trophic level bins</returns>
        public double[] CalculateTrophicDistribution(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double[] TrophicIndexBinMasses = new double[NumberTrophicBins];
            int BinIndex;

            foreach (var CohortList in CellCohorts)
            {
                foreach (Cohort c in CohortList)
                {
                    BinIndex = _TrophicIndexBinValues.ToList().IndexOf(_TrophicIndexBinValues.Last(x => x < c.TrophicIndex));
                    TrophicIndexBinMasses[BinIndex] += (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;
                }
            }

            return TrophicIndexBinMasses;
        }
        /// <summary>
        /// Calculates the geometric community weighted mean body mass
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of cells to be run in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param>
        /// <returns>geometric community weighted mean body mass</returns>
        public double CalculateGeometricCommunityMeanBodyMass(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double CumulativeAbundance = 0.0;
            double CumulativeLogBiomass = 0.0;

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

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

            return (CWGMBM);
        }
        /// <summary>
        /// Calculate trophic evenness using the Rao Index
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of cells to be run in the current simulation</param>
        /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param>
        /// <returns>Trophic evenness</returns>
        public double CalculateFunctionalEvennessRao(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions,
            List<uint[]> cellIndices, int cellIndex, string trait)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);

            double[] EvennessValues = new double[2];

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

            double[] FunctionalTrait = new double[CellCohorts.GetNumberOfCohorts()];
            double MaxModelTraitValue=0;
            double MinModelTraitValue=0;

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

            int CohortNumberCounter = 0;
            switch (trait.ToLower())
            {
                case "biomass":
                    for (int fg = 0; fg < CellCohorts.Count; fg++)
                    {
                        foreach (Cohort c in CellCohorts[fg])
                        {

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

                            CohortNumberCounter++;
                        }
                    }

                    //Define upper and lower limits for body mass
                    MinModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min();
                    MaxModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max();
                    break;
                case "trophic index":
                    for (int fg = 0; fg < CellCohorts.Count; fg++)
                    {
                        foreach (Cohort c in CellCohorts[fg])
                        {

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

                            CohortNumberCounter++;
                        }
                    }
                    MinModelTraitValue = MinTI;
                    MaxModelTraitValue = MaxTI;
                    break;
            }

            Distances = CalculateDistanceMatrix(FunctionalTrait, MaxModelTraitValue, MinModelTraitValue);

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

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

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

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

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


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

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

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

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


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

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


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

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

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

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

                    CohortNumberCounter++;
                }
            }

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

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

            Distances = CalculateAggregateDistance(DistanceList);

            RaoFunctionalDivergence = RaoEntropy(Distances, CohortTotalBiomasses);

            return(new double[] { 0.0, RaoFunctionalDivergence });
        }
        public void OutputCurrentModelState(ModelGrid currentModelGrid, FunctionalGroupDefinitions functionalGroupHandler, List<uint[]> cellIndices, uint currentTimestep, int maximumNumberOfCohorts, string filename)
        {

            float[] Latitude = currentModelGrid.Lats;

            float[] Longitude = currentModelGrid.Lons;

            float[] CohortFunctionalGroup = new float[functionalGroupHandler.GetNumberOfFunctionalGroups()];
            for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
            {
                CohortFunctionalGroup[fg] = fg;
            }

            int CellCohortNumber = 0;
            GridCellCohortHandler CellCohorts;
            for (int cellIndex = 0; cellIndex < cellIndices.Count; cellIndex++)
            {
                CellCohorts = currentModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
                for (int i = 0; i < CellCohorts.Count; i++)
                {
                    if (CellCohorts[i].Count > CellCohortNumber) CellCohortNumber = CellCohorts[i].Count;
                }
            }

            int MaxNumberCohorts = Math.Max(CellCohortNumber, maximumNumberOfCohorts);

            float[] Cohort = new float[MaxNumberCohorts];
            for (int c = 0; c < Cohort.Length; c++)
            {
                Cohort[c] = c;
            }

            //Define an array for stock functional group - there are only three currently
            float[] StockFunctionalGroup = new float[] { 1, 2, 3 };

            //Define an array for index of stocks - there is only one currently
            float[] Stock = new float[] { 1 };

            string Filename = filename + "_" + currentTimestep.ToString() + Simulation.ToString();

            StateOutput = SDSCreator.CreateSDS("netCDF", Filename, _OutputPath);

            //Define the cohort properties for output
            string[] CohortProperties = new string[]
            {"JuvenileMass", "AdultMass", "IndividualBodyMass", "CohortAbundance",
             "BirthTimeStep", "MaturityTimeStep", "LogOptimalPreyBodySizeRatio",
             "MaximumAchievedBodyMass","Merged","TrophicIndex","ProportionTimeActive"};

            //define the dimensions for cohort outputs
            string[] dims = new string[] { "Latitude", "Longitude", "Cohort Functional Group", "Cohort" };

            // Add the variables for each cohort property
            // Then calculate the state for this property and put the data to this variable
            foreach (string v in CohortProperties)
            {
                DataConverter.AddVariable(StateOutput, "Cohort" + v, 4,
                dims, currentModelGrid.GlobalMissingValue, Latitude,
                Longitude, CohortFunctionalGroup, Cohort);

                StateOutput.PutData<double[, , ,]>("Cohort" + v,
                    CalculateCurrentCohortState(currentModelGrid, v, Latitude.Length, Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length, cellIndices));

                StateOutput.Commit();
            }

            //Define the stock properties for output
            string[] StockProperties = new string[] { "IndividualBodyMass", "TotalBiomass" };

            //define the dimensions for cohort outputs
            dims = new string[] { "Latitude", "Longitude", "Stock Functional Group", "Stock" };

            // Add the variables for each stock property
            // Then calculate the state for this property and put the data to this variable
            foreach (string v in StockProperties)
            {
                DataConverter.AddVariable(StateOutput, "Stock" + v, 4,
                dims, currentModelGrid.GlobalMissingValue, Latitude,
                Longitude, StockFunctionalGroup, Stock);

                StateOutput.PutData<double[, , ,]>("Stock" + v,
                    CalculateCurrentStockState(currentModelGrid, v, Latitude.Length, Longitude.Length, StockFunctionalGroup.Length, Stock.Length, cellIndices));

                StateOutput.Commit();
            }

            //Close this data set
            StateOutput.Dispose();
        }
        private double[, , ,] CalculateCurrentCohortState(ModelGrid currentModelState, string variableName, int numLats, int numLons, int numFG, int numCohorts, List <uint[]> cellList)
        {
            //Calculate the cohort state
            double[, , ,] State = new double[numLats, numLons, numFG, numCohorts];
            GridCellCohortHandler CellCohorts;

            for (int cellIndex = 0; cellIndex < cellList.Count; cellIndex++)
            {
                CellCohorts = currentModelState.GetGridCellCohorts(cellList[cellIndex][0], cellList[cellIndex][1]);

                for (int functionalGroupIndex = 0; functionalGroupIndex < CellCohorts.Count; functionalGroupIndex++)
                {
                    for (int cohortIndex = 0; cohortIndex < CellCohorts[functionalGroupIndex].Count; cohortIndex++)
                    {
                        switch (variableName)
                        {
                        case "JuvenileMass":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].JuvenileMass;
                            break;

                        case "AdultMass":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].AdultMass;
                            break;

                        case "IndividualBodyMass":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].IndividualBodyMass;
                            break;

                        case "CohortAbundance":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].CohortAbundance;
                            break;

                        case "BirthTimeStep":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = (double)CellCohorts[functionalGroupIndex][cohortIndex].BirthTimeStep;
                            break;

                        case "MaturityTimeStep":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = (double)CellCohorts[functionalGroupIndex][cohortIndex].MaturityTimeStep;
                            break;

                        case "LogOptimalPreyBodySizeRatio":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].LogOptimalPreyBodySizeRatio;
                            break;

                        case "MaximumAchievedBodyMass":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].MaximumAchievedBodyMass;
                            break;

                        case "Merged":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = Convert.ToDouble(CellCohorts[functionalGroupIndex][cohortIndex].Merged);
                            break;

                        case "TrophicIndex":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].TrophicIndex;
                            break;

                        case "ProportionTimeActive":
                            State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].ProportionTimeActive;
                            break;
                        }
                    }
                }
            }

            return(State);
        }
        public void OutputCurrentModelState(ModelGrid currentModelGrid, FunctionalGroupDefinitions functionalGroupHandler, List <uint[]> cellIndices, uint currentTimestep, int maximumNumberOfCohorts, string filename)
        {
            float[] Latitude = currentModelGrid.Lats;

            float[] Longitude = currentModelGrid.Lons;

            float[] CohortFunctionalGroup = new float[functionalGroupHandler.GetNumberOfFunctionalGroups()];
            for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++)
            {
                CohortFunctionalGroup[fg] = fg;
            }

            int CellCohortNumber = 0;
            GridCellCohortHandler CellCohorts;

            for (int cellIndex = 0; cellIndex < cellIndices.Count; cellIndex++)
            {
                CellCohorts = currentModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
                for (int i = 0; i < CellCohorts.Count; i++)
                {
                    if (CellCohorts[i].Count > CellCohortNumber)
                    {
                        CellCohortNumber = CellCohorts[i].Count;
                    }
                }
            }

            int MaxNumberCohorts = Math.Max(CellCohortNumber, maximumNumberOfCohorts);

            float[] Cohort = new float[MaxNumberCohorts];
            for (int c = 0; c < Cohort.Length; c++)
            {
                Cohort[c] = c;
            }

            //Define an array for stock functional group - there are only three currently
            float[] StockFunctionalGroup = new float[] { 1, 2, 3 };

            //Define an array for index of stocks - there is only one currently
            float[] Stock = new float[] { 1 };

            string Filename = filename + "_" + currentTimestep.ToString() + Simulation.ToString();

            StateOutput = SDSCreator.CreateSDS("netCDF", Filename, _OutputPath);

            //Define the cohort properties for output
            string[] CohortProperties = new string[]
            { "JuvenileMass", "AdultMass", "IndividualBodyMass", "IndividualReproductivePotentialMass", "CohortAbundance",
              "BirthTimeStep", "MaturityTimeStep", "LogOptimalPreyBodySizeRatio",
              "MaximumAchievedBodyMass", "Merged", "TrophicIndex", "ProportionTimeActive" };

            //define the dimensions for cohort outputs
            string[] dims = new string[] { "Latitude", "Longitude", "Cohort Functional Group", "Cohort" };

            // Add the variables for each cohort property
            // Then calculate the state for this property and put the data to this variable
            foreach (string v in CohortProperties)
            {
                DataConverter.AddVariable(StateOutput, "Cohort" + v, 4,
                                          dims, currentModelGrid.GlobalMissingValue, Latitude,
                                          Longitude, CohortFunctionalGroup, Cohort);

                StateOutput.PutData <double[, , , ]>("Cohort" + v,
                                                     CalculateCurrentCohortState(currentModelGrid, v, Latitude.Length, Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length, cellIndices));

                StateOutput.Commit();
            }

            //Define the stock properties for output
            string[] StockProperties = new string[] { "IndividualBodyMass", "TotalBiomass" };


            //define the dimensions for cohort outputs
            dims = new string[] { "Latitude", "Longitude", "Stock Functional Group", "Stock" };

            // Add the variables for each stock property
            // Then calculate the state for this property and put the data to this variable
            foreach (string v in StockProperties)
            {
                DataConverter.AddVariable(StateOutput, "Stock" + v, 4,
                                          dims, currentModelGrid.GlobalMissingValue, Latitude,
                                          Longitude, StockFunctionalGroup, Stock);

                StateOutput.PutData <double[, , , ]>("Stock" + v,
                                                     CalculateCurrentStockState(currentModelGrid, v, Latitude.Length, Longitude.Length, StockFunctionalGroup.Length, Stock.Length, cellIndices));

                StateOutput.Commit();
            }

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

            //Variable to hold the functional richness value for the current cohorts
            double FunctionalRichness;
            //Variable to hold the functional divergence value for the current cohorts
            double RaoFunctionalDivergence = 0.0;
            double[,] Distances= new double[CellCohorts.GetNumberOfCohorts(), CellCohorts.GetNumberOfCohorts()];

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

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

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

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

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

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

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

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

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

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

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

                    CohortNumberCounter++;
                }
            }

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

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

            Distances = CalculateAggregateDistance(DistanceList);

            RaoFunctionalDivergence = RaoEntropy(Distances, CohortTotalBiomasses);

            return new double[] {0.0,RaoFunctionalDivergence};
        }
        public void OutputCurrentModelState(ModelGrid currentModelGrid, List<uint[]> cellIndices, uint currentTimestep)
        {

            GridCellCohortHandler TempCohorts;
            GridCellStockHandler TempStocks;

            string context;
            string organism;

            context = Convert.ToString(currentTimestep) + "\t";

            using (var StateWriter = File.AppendText(this.FileName))
            {
                foreach (uint[] cell in cellIndices)
                {
                    context = Convert.ToString(currentTimestep) + "\t" +
                            Convert.ToString(currentModelGrid.GetCellLatitude(cell[0])) + "\t" +
                                Convert.ToString(currentModelGrid.GetCellLongitude(cell[1])) + "\t";

                    TempStocks = currentModelGrid.GetGridCellStocks(cell[0], cell[1]);
                    TempCohorts = currentModelGrid.GetGridCellCohorts(cell[0], cell[1]);

                    foreach (List<Stock> ListS in TempStocks)
                    {
                        foreach (Stock S in ListS)
                        {
                            organism = "-999\tS" + Convert.ToString(S.FunctionalGroupIndex) + "\t" +
                                        "-999\t-999\t" + Convert.ToString(S.IndividualBodyMass) + "\t" +
                                        Convert.ToString(S.TotalBiomass / S.IndividualBodyMass) + "\t" +
                                        "-999\t-999\t-999\t-999\t-999\t-999";
                            StateWriter.WriteLine(context + organism);
                        }
                    }

                    foreach (List<Cohort> ListC in TempCohorts)
                    {
                        foreach (Cohort C in ListC)
                        {
#if true
                            var cohortIds = C.CohortID.Select(id => Convert.ToString(id));

                            organism = String.Join(";", cohortIds) + "\t" +
#else
                            organism = Convert.ToString(C.CohortID) + "\t" +
#endif
 Convert.ToString(C.FunctionalGroupIndex) + "\t" +
                                        Convert.ToString(C.JuvenileMass) + "\t" +
                                        Convert.ToString(C.AdultMass) + "\t" +
                                        Convert.ToString(C.IndividualBodyMass) + "\t" +
                                        Convert.ToString(C.CohortAbundance) + "\t" +
                                        Convert.ToString(C.BirthTimeStep) + "\t" +
                                        Convert.ToString(C.MaturityTimeStep) + "\t" +
                                        Convert.ToString(C.LogOptimalPreyBodySizeRatio) + "\t" +
                                        Convert.ToString(C.MaximumAchievedBodyMass) + "\t" +
                                        Convert.ToString(C.TrophicIndex) + "\t" +
                                        Convert.ToString(C.ProportionTimeActive);

                            StateWriter.WriteLine(context + organism);
                        }
                    }
                }
            }
        }
        public double[] CalculateFunctionalRichness(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions, 
            List<uint[]> cellIndices, int cellIndex, string trait)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double MinCurrentTraitValue = double.MaxValue;
            double MaxCurrentTraitValue = double.MinValue;
            double MinModelTraitValue = 0.0;
            double MaxModelTraitValue = 0.0;

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

                    foreach (var CohortList in CellCohorts)
                    {
                        foreach (var cohort in CohortList)
                        {

                            if (cohort.IndividualBodyMass < MinCurrentTraitValue) MinCurrentTraitValue = cohort.IndividualBodyMass;

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

                        }
                    }

                    //Define upper and lower limits for body mass
                    MinModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min();
                    MaxModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max();
                    break;
                case "trophic index":
                    foreach (var CohortList in CellCohorts)
                    {
                        foreach (var cohort in CohortList)
                        {

                            if (cohort.TrophicIndex < MinCurrentTraitValue) MinCurrentTraitValue = cohort.TrophicIndex;

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

                        }
                    }

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

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

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

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

            return NewArray;
        }
        /// <summary>
        /// Sets up the outputs associated with the high level of output detail
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The indices of active cells in the model grid</param>
        /// <param name="cellNumber">The index of the current cell in the list of active cells</param>
        /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        private void SetUpHighLevelOutputs(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellNumber,
            FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, Boolean marineCell)
        {
            // Create an SDS object for outputs by mass bin
            // MassBinsOutput = SDSCreator.CreateSDS("netCDF", "MassBins" + _OutputSuffix, _OutputPath);
            MassBinsOutputMemory = SDSCreator.CreateSDSInMemory(true);

            // Add relevant output variables to the mass bin output file
            string[] MassBinDimensions = { "Time step", "Mass bin" };
            string[] DoubleMassBinDimensions = new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" };

            if (OutputMetrics)
            {
                DataConverter.AddVariable(MassBinsOutputMemory, "Trophic Index Distribution", 2, new string[] {"Time step","Trophic Index Bins"}, ecosystemModelGrid.GlobalMissingValue, TimeSteps, Metrics.TrophicIndexBinValues);
            }

            if (marineCell)
            {
                foreach (string TraitValue in CohortTraitIndicesMarine.Keys)
                {
                    DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins);
                    DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins);
                    DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps);
                    DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps);
                }
            }
            else
            {
                foreach (string TraitValue in CohortTraitIndices.Keys)
                {
                    DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins);
                    DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins);
                    DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps);
                    DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps);
                }
            }

            // Create an SDS object in memory for tracked cohorts outputs
            // TrackedCohortsOutput = SDSCreator.CreateSDS("netCDF", "TrackedCohorts" + _OutputSuffix, _OutputPath);
            TrackedCohortsOutputMemory = SDSCreator.CreateSDSInMemory(true);

            // Initialise list to hold tracked cohorts
            TrackedCohorts = new List<uint>();

            // Identify cohorts to track
            GridCellCohortHandler TempCohorts = null;
            bool FoundCohorts = false;

            // Get a local copy of the cohorts in the grid cell
            TempCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellNumber][0], cellIndices[cellNumber][1]);

            // Loop over functional groups and check whether any cohorts exist in this grid cell
            foreach (var CohortList in TempCohorts)
            {
                if (CohortList.Count > 0)
                {
                    FoundCohorts = true;
                    break;
                }
            }

            // If there are some cohorts in the grid cell, then setup the tracked cohorts
            if (FoundCohorts)
            {
                // Initialise stream writer to hold details of tracked cohorts
                StreamWriter sw = new StreamWriter(_OutputPath + "TrackedCohortProperties" + _OutputSuffix + ".txt");
                sw.WriteLine("Output ID\tCohort ID\tFunctional group index\tNutrition source\tDiet\tRealm\tMobility\tJuvenile mass\tAdult mass");

                // Counter for tracked cohorts
                int TrackedCohortCounter = 0;

                for (int i = 0; i < TempCohorts.Count; i++)
                {
                    if (TempCohorts[i].Count > 0)
                    {
                        for (int j = 0; j < TempCohorts[i].Count; j++)
                        {
                            // Write out properties of the selected cohort
                            sw.WriteLine(Convert.ToString(TrackedCohortCounter) + '\t' + Convert.ToString(TempCohorts[i][j].CohortID[0]) + '\t' + i + '\t' +
                                cohortFunctionalGroupDefinitions.GetTraitNames("Nutrition source", i) + '\t' + cohortFunctionalGroupDefinitions.
                                GetTraitNames("Diet", i) + '\t' + cohortFunctionalGroupDefinitions.GetTraitNames("Realm", i) + '\t' +
                                cohortFunctionalGroupDefinitions.GetTraitNames("Mobility", i) + '\t' + TempCohorts[i][j].JuvenileMass + '\t' +
                                TempCohorts[i][j].AdultMass);

                            // Add the ID of the cohort to the list of tracked cohorts
                            TrackedCohorts.Add(TempCohorts[i][j].CohortID[0]);

                            // Increment the counter of tracked cohorts
                            TrackedCohortCounter++;
                        }
                    }
                }

                // Generate an array of floating points to index the tracked cohorts in the output file
                float[] OutTrackedCohortIDs = new float[TrackedCohortCounter];
                for (int i = 0; i < TrackedCohortCounter; i++)
                {
                    OutTrackedCohortIDs[i] = i;
                }

                // Set up outputs for tracked cohorts
                string[] TrackedCohortsDimensions = { "Time step", "Cohort ID" };

                // Add output variables for the tracked cohorts output
                DataConverter.AddVariable(TrackedCohortsOutputMemory, "Individual body mass", 2, TrackedCohortsDimensions,
                ecosystemModelGrid.GlobalMissingValue, TimeSteps, OutTrackedCohortIDs);
                DataConverter.AddVariable(TrackedCohortsOutputMemory, "Number of individuals", 2, TrackedCohortsDimensions,
                ecosystemModelGrid.GlobalMissingValue, TimeSteps, OutTrackedCohortIDs);

                // Dispose of the streamwriter
                sw.Dispose();
            }

                // Get a list of all possible combinations of trait values as a jagged array
            string[][] TraitValueSearch;

                if (marineCell)
                    TraitValueSearch = CalculateAllCombinations(CohortTraitValuesMarine[CohortTraits[0]], CohortTraitValuesMarine[CohortTraits[1]]);
                else
                    TraitValueSearch = CalculateAllCombinations(CohortTraitValues[CohortTraits[0]], CohortTraitValues[CohortTraits[1]]);

                // Add the functional group indices of these trait combinations to the list of indices of the trait values to consider,
                // keyed with a concatenated version of the trait values
                string TraitValueJoin = "";
                string[] TimeDimension = { "Time step" };
                for (int i = 0; i < TraitValueSearch.Count(); i++)
                {
                    TraitValueJoin = "";
                    foreach (string TraitValue in TraitValueSearch[i])
                    {
                        TraitValueJoin += TraitValue + " ";
                    }

                    if (marineCell)
                    {
                        // Only add indices of marine functional groups
                        int[] TempIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(CohortTraits, TraitValueSearch[i], true);
                        Boolean[] TempIndices2 = new Boolean[TempIndices.GetLength(0)];
                        for (int ii = 0; ii < TempIndices.GetLength(0); ii++)
                        {
                            if (cohortFunctionalGroupDefinitions.GetTraitNames("Realm", TempIndices[ii]).Equals("Marine", StringComparison.OrdinalIgnoreCase))
                            {
                                TempIndices2[ii] = true;
                            }
                        }

                        // Extract only the indices which are marine
                        int[] TempIndices3 = Enumerable.Range(0, TempIndices2.Length).Where(zz => TempIndices2[zz]).ToArray();

                        if (TempIndices3.Length > 0)
                        {
                            // Extract the values at these indices
                            for (int ii = 0; ii < TempIndices3.Length; ii++)
                            {
                                TempIndices3[ii] = TempIndices[TempIndices3[ii]];
                            }

                            // Add in the indices for this functional group and this realm
                            CohortTraitIndices.Add(TraitValueJoin, TempIndices3);

                            DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps);
                            DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps);
                            DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins);
                            DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins);
                            DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps);
                            DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps);

                            TotalBiomassDensitiesOut.Add(TraitValueJoin, 0.0);
                            TotalDensitiesOut.Add(TraitValueJoin, 0.0);
                        }
                    }
                    else
                    {
                        // Only add indices of terrestrial functional groups
                        int[] TempIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(CohortTraits, TraitValueSearch[i], true);
                        Boolean[] TempIndices2 = new Boolean[TempIndices.GetLength(0)];
                        for (int ii = 0; ii < TempIndices.GetLength(0); ii++)
                        {
                            if (cohortFunctionalGroupDefinitions.GetTraitNames("Realm", TempIndices[ii]).Equals("Terrestrial", StringComparison.OrdinalIgnoreCase))
                            {
                                TempIndices2[ii] = true;
                            }
                        }

                        // Extract only the indices which are terrestrial
                        int[] TempIndices3 = Enumerable.Range(0, TempIndices2.Length).Where(zz => TempIndices2[zz]).ToArray();

                        if (TempIndices3.Length > 0)
                        {
                            // Extract the values at these indices
                            for (int ii = 0; ii < TempIndices3.Length; ii++)
                            {
                                TempIndices3[ii] = TempIndices[TempIndices3[ii]];
                            }

                            // Add in the indices for this functional group and this realm
                            CohortTraitIndices.Add(TraitValueJoin, TempIndices3);

                            DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps);
                            DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps);
                            DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins);
                            DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins);
                            DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps);
                            DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps);

                            TotalBiomassDensitiesOut.Add(TraitValueJoin, 0.0);
                            TotalDensitiesOut.Add(TraitValueJoin, 0.0);
                        }
                    }
                }
        }
        /// <summary>
        /// Calculates the mean trophic level of all individual organisms in a grid cell
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of cell indices in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell in the list of cells to run</param>
        /// <returns>The mean trophic level of individuals in the grid cell</returns>
        public double CalculateMeanTrophicLevelCell(ModelGrid ecosystemModelGrid,List<uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            double BiomassWeightedTI = 0.0;
            double TotalBiomass = 0.0;
            double CohortBiomass = 0.0;

            foreach (var CohortList in CellCohorts)
            {
                foreach (Cohort c in CohortList)
                {
                    CohortBiomass = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;
                    BiomassWeightedTI += CohortBiomass * c.TrophicIndex;
                    TotalBiomass += CohortBiomass;
                }
            }

            return BiomassWeightedTI/TotalBiomass;
        }
        /// <summary>
        /// Calculate outputs associated with high-level outputs
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="cellIndex">The number of the current cell in the list of active cells</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        private void CalculateHighLevelOutputs(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex, Boolean marineCell)
        {
            // Calcalate the outputs arranged by mass bin
            CalculateMassBinOutputs(ecosystemModelGrid, cellIndices, cellIndex, marineCell);

            // Declare vectors to hold properties of tracked cohorts
            TrackedCohortIndividualMasses = new double[TrackedCohorts.Count];
            TrackedCohortAbundances = new double[TrackedCohorts.Count];

            // Get a temporary local copy of the cohorts in the grid cell
            GridCellCohortHandler TempCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);

            // Loop over functional groups in the grid cell cohorts
            for (int j = 0; j < TempCohorts.Count; j++)
            {
                // Loop over cohorts within this functional group
                for (int k = 0; k < TempCohorts[j].Count; k++)
                {
                    // Loop over all cohort IDs
                    foreach (uint CohortID in TempCohorts[j][k].CohortID)
                    {
                        // Check whether the cohort ID corresponds to a tracked cohort
                        if (TrackedCohorts.Contains(CohortID))
                        {
                            // Get the position of the cohort in the list of tracked cohorts
                            int position = TrackedCohorts.FindIndex(
                                delegate(uint i)
                                {
                                    return i == CohortID;
                                });
                            // Add the body mass and abundance of the tracked cohort to the appropriate position in the output vector
                            TrackedCohortIndividualMasses[position] = TempCohorts[j][k].IndividualBodyMass;
                            TrackedCohortAbundances[position] = TempCohorts[j][k].CohortAbundance;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Calculates trophic evenness using the FRO Index of Mouillot et al.
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of cells to be run in the current model simulation</param>
        /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param>
        /// <returns>Trophic evenness</returns>
        /// <remarks>From Mouillot et al (2005) Functional regularity: a neglected aspect of functional diversity, Oecologia</remarks>
        public double CalculateTrophicEvennessFRO(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex)
        {
            //Get the cohorts for the specified cell
            GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]);
            List<double[]> TrophicIndexBiomassDistribution = new List<double[]>();
            double[] TIBiomass;
            double[] EW;

            foreach (var CohortList in CellCohorts)
            {
                foreach (Cohort c in CohortList)
                {
                    TIBiomass = new double[2];
                    TIBiomass[0] = c.TrophicIndex;
                    TIBiomass[1] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance;
                    TrophicIndexBiomassDistribution.Add(TIBiomass);
                }
            }

            TrophicIndexBiomassDistribution = TrophicIndexBiomassDistribution.OrderBy(x => x[0]).ToList();

            //Use the Mouillot Evenness index - Functional Regularity Index or FRO
            //From Mouillot et al (2005) Functional regularity: a neglected aspect of functional diversity, Oecologia

            EW = new double[TrophicIndexBiomassDistribution.Count];
            double TotalEW = 0.0 ;

            for (int ii = 0; ii < TrophicIndexBiomassDistribution.Count-1; ii++)
            {
                EW[ii] = (TrophicIndexBiomassDistribution[ii + 1][0] - TrophicIndexBiomassDistribution[ii][0]) / (TrophicIndexBiomassDistribution[ii + 1][1] + TrophicIndexBiomassDistribution[ii][1]);
                TotalEW += EW[ii];
            }

            double FRO = 0.0;

            for (int ii = 0; ii < TrophicIndexBiomassDistribution.Count - 1; ii++)
            {
                FRO += Math.Min(EW[ii]/TotalEW,1.0/(TrophicIndexBiomassDistribution.Count-1));
            }

            return FRO;
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Record dispersal events in the dispersal tracker
        /// </summary>
        /// <param name="inboundCohorts">The cohorts arriving in a grid cell in the current time step</param>
        /// <param name="outboundCohorts">The cohorts leaving a ce  ll in the current time step</param>
        /// <param name="outboundCohortWeights">The body masses of cohorts leaving the cell in the current time step</param>
        /// <param name="currentTimeStep">The current model time step</param>
        /// <param name="madingleyModelGrid">The model grid</param>
        public void RecordDispersal(uint[, ,] inboundCohorts, uint[, ,] outboundCohorts, List <double>[,] outboundCohortWeights, uint currentTimeStep, ModelGrid madingleyModelGrid)
        {
            // Loop through cells in the grid and write out the necessary data
            for (uint ii = 0; ii < outboundCohorts.GetLength(0); ii++)
            {
                for (uint jj = 0; jj < outboundCohorts.GetLength(1); jj++)
                {
                    double MeanOutboundCohortWeight = new double();

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

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

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

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

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

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

                    SyncedDispersalWriter.WriteLine(newline);
                }
            }
        }