Ejemplo n.º 1
0
        /// <summary>
        /// Overloaded constructor for model grid to construct the grid for specific locations
        /// </summary>
        /// <param name="minLat">Minimum grid latitude (degrees)</param>
        /// <param name="minLon">Minimum grid longitude (degrees, currently -180 to 180)</param>
        /// <param name="maxLat">Maximum grid latitude (degrees)</param>
        /// <param name="maxLon">Maximum grid longitude (degrees, currently -180 to 180)</param>
        /// <param name="latCellSize">Latitudinal size of grid cells</param>
        /// <param name="lonCellSize">Longitudinal size of grid cells</param>
        /// <param name="cellList">List of indices of active cells in the model grid</param>
        /// <param name="enviroStack">List of environmental data layers</param>
        /// <param name="cohortFunctionalGroups">The functional group definitions for cohorts in the model</param>
        /// <param name="stockFunctionalGroups">The functional group definitions for stocks in the model</param>
        /// <param name="globalDiagnostics">Global diagnostic variables</param>
        /// <param name="tracking">Whether process tracking is enabled</param>
        /// <param name="specificLocations">Whether the model is to be run for specific locations</param>
        /// <param name="runInParallel">Whether model grid cells will be run in parallel</param>
        public ModelGrid(float minLat, float minLon, float maxLat, float maxLon, float latCellSize, float lonCellSize, List <uint[]> cellList,
                         SortedList <string, EnviroData> enviroStack, FunctionalGroupDefinitions cohortFunctionalGroups,
                         FunctionalGroupDefinitions stockFunctionalGroups, SortedList <string, double> globalDiagnostics, Boolean tracking,
                         Boolean specificLocations, Boolean runInParallel)
#endif
        {
            // CURRENTLY DEFINING MODEL CELLS BY BOTTOM LEFT CORNER
            _MinLatitude         = minLat;
            _MinLongitude        = minLon;
            _MaxLatitude         = maxLat;
            _MaxLongitude        = maxLon;
            _LatCellSize         = latCellSize;
            _LonCellSize         = lonCellSize;
            _GridCellRarefaction = 1;

            // Check to see if the number of grid cells is an integer
            Debug.Assert((((_MaxLatitude - _MinLatitude) % _LatCellSize) == 0), "Error: number of grid cells is non-integer: check cell size");

            _NumLatCells = (UInt32)((_MaxLatitude - _MinLatitude) / _LatCellSize);
            _NumLonCells = (UInt32)((_MaxLongitude - _MinLongitude) / _LonCellSize);
            _Lats        = new float[_NumLatCells];
            _Lons        = new float[_NumLonCells];

            // Set up latitude and longitude vectors - lower left
            for (int ii = 0; ii < _NumLatCells; ii++)
            {
                _Lats[ii] = _MinLatitude + ii * _LatCellSize;
            }
            for (int jj = 0; jj < _NumLonCells; jj++)
            {
                _Lons[jj] = _MinLongitude + jj * _LonCellSize;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Calculate the proportion of time for which this cohort could be active and assign it to the cohort's properties
        /// </summary>
        /// <param name="actingCohort">The Cohort for which proportion of time active is being calculated</param>
        /// <param name="cellEnvironment">The environmental information for current grid cell</param>
        /// <param name="madingleyCohortDefinitions">Functional group definitions and code to interrogate the cohorts in current grid cell</param>
        /// <param name="currentTimestep">Current timestep index</param>
        /// <param name="currentMonth">Current month</param>
        public void AssignProportionTimeActive(Cohort actingCohort, SortedList <string, double[]> cellEnvironment,
                                               FunctionalGroupDefinitions madingleyCohortDefinitions, uint currentTimestep, uint currentMonth)
        {
            double Realm = cellEnvironment["Realm"][0];

            //Only work on heterotroph cohorts
            if (madingleyCohortDefinitions.GetTraitNames("Heterotroph/Autotroph", actingCohort.FunctionalGroupIndex) == "heterotroph")
            {
                //Check if this is an endotherm or ectotherm
                Boolean Endotherm = madingleyCohortDefinitions.GetTraitNames("Endo/Ectotherm", actingCohort.FunctionalGroupIndex) == "endotherm";
                if (Endotherm)
                {
                    //Assumes the whole timestep is suitable for endotherms to be active - actual time active is therefore the proportion specified for this functional group.
                    actingCohort.ProportionTimeActive = madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("proportion suitable time active", actingCohort.FunctionalGroupIndex);
                }
                else
                {
                    //If ectotherm then use realm specific function
                    if (Realm == 1.0)
                    {
                        actingCohort.ProportionTimeActive = CalculateProportionTimeSuitableTerrestrial(cellEnvironment, currentMonth, Endotherm) *
                                                            madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("proportion suitable time active", actingCohort.FunctionalGroupIndex);
                    }
                    else
                    {
                        actingCohort.ProportionTimeActive = CalculateProportionTimeSuitableMarine(cellEnvironment, currentMonth, Endotherm) *
                                                            madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("proportion suitable time active", actingCohort.FunctionalGroupIndex);
                    }
                }
            }
        }
        /// <summary>
        /// Constructor for process tracker: Initialises the trackers for individual processes
        /// </summary>
        /// <param name="numTimesteps">The number of time steps in the model</param>
        /// <param name="lats">The latitudes of active grid cells in the model</param>
        /// <param name="lons">The longitudes of active grid cells in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="Filenames">The filenames of the output files to write the tracking results to</param>
        /// <param name="trackProcesses">Whether to track processes</param>
        /// <param name="cohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="missingValue">The missing value to use in process tracking output files</param>
        /// <param name="outputFileSuffix">The suffix to be applied to output files from process tracking</param>
        /// <param name="outputPath">The path to the folder to be used for process tracking outputs</param>
        /// <param name="trackerMassBins">The mass bins to use for categorising output data in the process trackers</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="latCellSize">The size of grid cells latitudinally</param>
        /// <param name="lonCellSize">The size of grid cells longitudinally</param>
        public GlobalProcessTracker(uint numTimesteps,
            float[] lats, float[] lons,
            List<uint[]> cellIndices,
            SortedList<string, string> Filenames,
            Boolean trackProcesses,
            FunctionalGroupDefinitions cohortDefinitions,
            FunctionalGroupDefinitions stockDefinitions,
            double missingValue,
            string outputFileSuffix,
            string outputPath, MassBinsHandler trackerMassBins,
            Boolean specificLocations,
            MadingleyModelInitialisation initialisation,
            float latCellSize,
            float lonCellSize)
        {
            // Initialise trackers for ecological processes
            _TrackProcesses = trackProcesses;

            if (_TrackProcesses)
            {
                _TrackNPP = new GlobalNPPTracker(outputPath, lats.Length, lons.Length, lats, lons, latCellSize, lonCellSize,
                    (int)numTimesteps,stockDefinitions.GetNumberOfFunctionalGroups(),outputFileSuffix);

            }
        }
        /// <summary>
        /// Run metabolism
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="trackProcesses">An instance of ProcessTracker to hold diagnostics for metabolism</param>
        /// <param name="partial">Thread-locked variables</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail being used for the current model run</param>
        /// <param name="currentMonth">The current model month</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                         int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas,
                                         FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                         uint currentTimestep, ProcessTracker trackProcesses, ref ThreadLockedParallelVariables partial,
                                         Boolean specificLocations, string outputDetail, uint currentMonth, MadingleyModelInitialisation initialisation)
        {
            double Realm = cellEnvironment["Realm"][0];

            if (madingleyCohortDefinitions.GetTraitNames("Heterotroph/Autotroph", gridCellCohorts[actingCohort].FunctionalGroupIndex) == "heterotroph")
            {
                if (madingleyCohortDefinitions.GetTraitNames("Endo/Ectotherm", gridCellCohorts[actingCohort].FunctionalGroupIndex) == "endotherm")
                {
                    Implementations["basic endotherm"].RunMetabolism(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, currentMonth);
                }
                else
                {
                    Implementations["basic ectotherm"].RunMetabolism(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, currentMonth);
                }
            }

            // If the process tracker is on and output detail is set to high and this cohort has not been merged yet, then record
            // the number of individuals that have died
            if (trackProcesses.TrackProcesses && (outputDetail == "high"))
            {
                trackProcesses.TrackTimestepMetabolism((uint)cellEnvironment["LatIndex"][0],
                                                       (uint)cellEnvironment["LonIndex"][0],
                                                       currentTimestep,
                                                       gridCellCohorts[actingCohort].IndividualBodyMass,
                                                       actingCohort[0],
                                                       cellEnvironment["Temperature"][currentMonth],
                                                       deltas["biomass"]["metabolism"]);
            }
        }
        //Function to bin cohorts according to the mass bins defined for the catch data
        /// <summary>
        /// Bin cohorts according to the mass bins defined for the catch data
        /// Constructs a list of functional group and cohort indices falling within each mass bin
        /// as well as the total biomass available to be fished in each
        /// </summary>
        /// <param name="c">The grid cell cohorts</param>
        /// <param name="fishCatch">Fisheries catch data</param>
        public void BinCohorts(GridCellCohortHandler c, InputCatchData fishCatch, FunctionalGroupDefinitions cohortFGs)
        {
            int mb = 0;

            int[] FishFGs = cohortFGs.GetFunctionalGroupIndex("Endo/Ectotherm", "Ectotherm", false);

            for (int i = 0; i < BinnedCohorts.Length; i++)
            {
                BinnedCohorts[i] = new List <Tuple <int[], double> >();
            }

            foreach (int fg in FishFGs)
            {
                for (int i = 0; i < c[fg].Count(); i++)
                {
                    //Find the mass bin for this cohort
                    mb = fishCatch.MassBins.ToList().FindIndex(a => a >= c[fg, i].AdultMass);
                    if (mb < 0)
                    {
                        mb = fishCatch.UnknownMassBinIndex - 1;
                    }

                    //Check if the current bodymass is greater than the proportion of the adult mass
                    if (c[fg, i].IndividualBodyMass >= c[fg, i].AdultMass * AdultMassProportionFished)
                    {
                        //Calculate the total biomass of this cohort
                        double CohortBiomass = (c[fg, i].IndividualBodyMass + c[fg, i].IndividualReproductivePotentialMass) *
                                               c[fg, i].CohortAbundance;
                        //Add the indices and total biomass to the bins
                        BinnedCohorts[mb].Add(new Tuple <int[], double>(new int[] { fg, i }, CohortBiomass));
                        BinnedTotalModelBiomass[mb] += CohortBiomass;
                    }
                }
            }
        }
        /// <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));
        }
        //Function to bin cohorts according to the mass bins defined for the catch data
        /// <summary>
        /// Bin cohorts according to the mass bins defined for the catch data
        /// Constructs a list of functional group and cohort indices falling within each mass bin
        /// as well as the total biomass available to be fished in each
        /// </summary>
        /// <param name="c">The grid cell cohorts</param>
        /// <param name="fishCatch">Fisheries catch data</param>
        public void BinCohorts(GridCellCohortHandler c, InputCatchData fishCatch, FunctionalGroupDefinitions cohortFGs)
        {
            int mb = 0;

            int[] FishFGs = cohortFGs.GetFunctionalGroupIndex("Endo/Ectotherm", "Ectotherm",false);

            for (int i = 0; i < BinnedCohorts.Length; i++)
            {
                BinnedCohorts[i] = new List<Tuple<int[], double>>();
            }

            foreach (int fg in FishFGs)
            {
                for (int i = 0; i < c[fg].Count(); i++)
                {
                    //Find the mass bin for this cohort
                    mb = fishCatch.MassBins.ToList().FindIndex(a => a >= c[fg,i].AdultMass);
                    if (mb < 0) mb = fishCatch.UnknownMassBinIndex - 1;

                    //Check if the current bodymass is greater than the proportion of the adult mass
                    if (c[fg, i].IndividualBodyMass >= c[fg, i].AdultMass * AdultMassProportionFished)
                    {
                        //Calculate the total biomass of this cohort
                        double CohortBiomass = (c[fg, i].IndividualBodyMass + c[fg, i].IndividualReproductivePotentialMass) *
                                                    c[fg, i].CohortAbundance;
                        //Add the indices and total biomass to the bins
                        BinnedCohorts[mb].Add(new Tuple<int[], double>(new int[] { fg, i }, CohortBiomass));
                        BinnedTotalModelBiomass[mb] += CohortBiomass;
                    }
                }
            }
        }
Ejemplo n.º 8
0
 /// <summary>
 /// Initializes an implementation of eating
 /// </summary>
 /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
 /// <param name="gridCellStocks">The stocks in the current grid cell</param>
 /// <param name="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
 /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
 /// <param name="implementationKey">The name of the implementation of eating to initialize</param>
 /// <remarks>Eating needs to be initialized every time step</remarks>
 public void InitializeEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                         FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                         string implementationKey)
 {
     // Initialize the implementation of the eating process
     Implementations[implementationKey].InitializeEatingPerTimeStep(gridCellCohorts, gridCellStocks,
                                                                    madingleyCohortDefinitions, madingleyStockDefinitions);
 }
 /// <summary>
 /// Initializes an implementation of eating
 /// </summary>
 /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
 /// <param name="gridCellStocks">The stocks in the current grid cell</param>
 /// <param name="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
 /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
 /// <param name="implementationKey">The name of the implementation of eating to initialize</param>
 /// <param name="cellEnvironment">The environment in the current grid cell</param>
 /// <remarks>Eating needs to be initialized every time step</remarks>
 public void InitializeEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, 
     FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, 
     string implementationKey, SortedList<string, double[]> cellEnvironment)
 {
     // Initialize the implementation of the eating process
     Implementations[implementationKey].InitializeEatingPerTimeStep(gridCellCohorts, gridCellStocks,
         madingleyCohortDefinitions, madingleyStockDefinitions,cellEnvironment);
 }
Ejemplo n.º 10
0
 /// <summary>
 /// Track the flow of mass between trophic levels during a herbivory event
 /// </summary>
 /// <param name="latitudeIndex">The latitudinal index of the current grid cell</param>
 /// <param name="longitudeIndex">The longitudinal index of the current grid cell</param>
 /// <param name="toFunctionalGroup">The index of the functional group that the predator belongs to</param>
 /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions of cohorts in the model</param>
 /// <param name="massEaten">The mass eaten during the herbivory event</param>
 /// <param name="predatorBodyMass">The body mass of the predator doing the eating</param>
 /// <param name="initialisation">The Madingley Model initialisation</param>
 /// <param name="marineCell">Whether the current cell is a marine cell</param>
 public void TrackHerbivoryTrophicFlow(uint latitudeIndex, uint longitudeIndex, int toFunctionalGroup,
                                       FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, double massEaten, double predatorBodyMass,
                                       MadingleyModelInitialisation initialisation, Boolean marineCell)
 {
     foreach (var o in this.ProcessTrackers)
     {
         o.TrackHerbivoryTrophicFlow((int)latitudeIndex, (int)longitudeIndex, toFunctionalGroup, massEaten, predatorBodyMass, marineCell);
     }
 }
 /// <summary>
 /// Track the flow of mass between trophic levels during a predation event
 /// </summary>
 /// <param name="latitudeIndex">The latitudinal index of the current grid cell</param>
 /// <param name="longitudeIndex">The longitudinal index of the current grid cell</param>
 /// <param name="fromFunctionalGroup">The index of the functional group being eaten</param>
 /// <param name="toFunctionalGroup">The index of the functional group that the predator belongs to</param>
 /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions of cohorts in the model</param>
 /// <param name="massEaten">The mass eaten during the predation event</param>
 /// <param name="predatorBodyMass">The body mass of the predator doing the eating</param>
 /// <param name="preyBodyMass">The body mass of the prey doing the eating</param>
 /// <param name="initialisation">The Madingley Model initialisation</param>
 /// <param name="marineCell">Whether the current cell is a marine cell</param>
 public void TrackPredationTrophicFlow(uint latitudeIndex, uint longitudeIndex, int fromFunctionalGroup, int toFunctionalGroup,
     FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, double massEaten, double predatorBodyMass, double preyBodyMass,
     MadingleyModelInitialisation initialisation, Boolean marineCell)
 {
     foreach (var o in this.ProcessTrackers)
     {
         o.TrackPredationTrophicFlow((int)latitudeIndex, (int)longitudeIndex, fromFunctionalGroup, toFunctionalGroup, massEaten, predatorBodyMass, preyBodyMass, marineCell);
     }
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Assigns ingested biomass from other ecological processes to reproductive potential mass
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param>
        public void RunReproductiveMassAssignment(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                                  int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas,
                                                  FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                                  uint currentTimestep, ProcessTracker tracker)
        {
            // Biomass per individual in each cohort to be assigned to reproductive potential
            double _BiomassToAssignToReproductivePotential;

            // Net biomass change from other ecological functions this time step
            double NetBiomassFromOtherEcologicalFunctionsThisTimeStep;

            // Reset variable holding net biomass change of individuals in this cohort as a result of other ecological processes
            NetBiomassFromOtherEcologicalFunctionsThisTimeStep = 0.0;

            // Loop over all items in the biomass deltas
            foreach (var Biomass in deltas["biomass"])
            {
                // Add the delta biomass to net biomass
                NetBiomassFromOtherEcologicalFunctionsThisTimeStep += Biomass.Value;
            }

            // If individual body mass after the addition of the net biomass from processes this time step will yield a body mass
            // greater than the adult body mass for this cohort, then assign the surplus to reproductive potential
            if ((gridCellCohorts[actingCohort].IndividualBodyMass + NetBiomassFromOtherEcologicalFunctionsThisTimeStep) > gridCellCohorts[actingCohort].AdultMass)
            {
                // Calculate the biomass for each individual in this cohort to be assigned to reproductive potential
                _BiomassToAssignToReproductivePotential = gridCellCohorts[actingCohort].IndividualBodyMass + NetBiomassFromOtherEcologicalFunctionsThisTimeStep -
                                                          gridCellCohorts[actingCohort].AdultMass;

                // Check that a positive biomass is to be assigned to reproductive potential
                Debug.Assert(_BiomassToAssignToReproductivePotential >= 0.0, "Assignment of negative reproductive potential mass");

                // If this is the first time reproductive potential mass has been assigned for this cohort,
                // then set the maturity time step for this cohort as the current model time step
                if (gridCellCohorts[actingCohort].MaturityTimeStep == uint.MaxValue)
                {
                    gridCellCohorts[actingCohort].MaturityTimeStep = currentTimestep;

                    // Track the generation length for this cohort
                    if (tracker.TrackProcesses && (!gridCellCohorts[actingCohort].Merged))
                    {
                        tracker.TrackMaturity((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                              currentTimestep, gridCellCohorts[actingCohort].BirthTimeStep, gridCellCohorts[actingCohort].JuvenileMass,
                                              gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex);
                    }
                }

                // Assign the specified mass to reproductive potential mass and remove it from individual biomass
                deltas["reproductivebiomass"]["reproduction"] += _BiomassToAssignToReproductivePotential;
                deltas["biomass"]["reproduction"]             -= _BiomassToAssignToReproductivePotential;
            }
            else
            {
                // Cohort has not gained sufficient biomass to assign any to reproductive potential, so take no action
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Run ecological processes that operate on stocks within a single grid cell
        /// </summary>
        ///<param name="gridCellStocks">The stocks in the current grid cell</param>
        ///<param name="actingStock">The acting stock</param>
        ///<param name="cellEnvironment">The stocks in the current grid cell</param>
        ///<param name="environmentalDataUnits">List of units associated with the environmental variables</param>
        ///<param name="humanNPPScenario">The human appropriation of NPP scenario to apply</param>
        ///<param name="madingleyStockDefinitions">The functional group definitions for stocks in the model</param>
        ///<param name="currentTimeStep">The current model time step</param>
        ///<param name="burninSteps">The number of time steps to spin the model up for before applying human impacts</param>
        ///<param name="impactSteps">The number of time steps to apply human impacts for</param>
        ///<param name="globalModelTimeStepUnit">The time step unit used in the model</param>
        ///<param name="trackProcesses">Whether to track properties of ecological processes</param>
        ///<param name="tracker">An instance of the ecological process tracker</param>
        ///<param name="globalTracker">An instance of the global process tracker</param>
        ///<param name="currentMonth">The current model month</param>
        ///<param name="outputDetail">The level of detail to use in outputs</param>
        ///<param name="specificLocations">Whether to run the model for specific locations</param>
        ///<param name="impactCell">Whether this cell should have human impacts applied</param>
        public void RunWithinCellEcology(GridCellStockHandler gridCellStocks, int[] actingStock, SortedList <string, double[]> cellEnvironment,
                                         SortedList <string, string> environmentalDataUnits, Tuple <string, double, double> humanNPPScenario,
                                         FunctionalGroupDefinitions madingleyStockDefinitions,
                                         uint currentTimeStep, uint burninSteps, uint impactSteps, uint recoverySteps, uint instantStep, uint numInstantSteps, string globalModelTimeStepUnit, Boolean trackProcesses,
                                         ProcessTracker tracker,
                                         GlobalProcessTracker globalTracker, uint currentMonth,
                                         string outputDetail, bool specificLocations, Boolean impactCell)
        {
            int ScenarioYear;

            if (currentTimeStep < burninSteps)
            {
                ScenarioYear = 0;
            }
            else
            {
                ScenarioYear = (int)Math.Floor((currentTimeStep - burninSteps) / 12.0);
            }



            if (madingleyStockDefinitions.GetTraitNames("Realm", actingStock[0]) == "marine")
            {
                // Run the autotroph processor
                MarineNPPtoAutotrophStock.ConvertNPPToAutotroph(cellEnvironment, gridCellStocks, actingStock, environmentalDataUnits["LandNPP"],
                                                                environmentalDataUnits["OceanNPP"], currentTimeStep, globalModelTimeStepUnit, tracker, globalTracker, outputDetail, specificLocations, currentMonth);
            }
            else if (madingleyStockDefinitions.GetTraitNames("Realm", actingStock[0]) == "terrestrial")
            {
                // Run the dynamic plant model to update the leaf stock for this time step
                double WetMatterNPP = DynamicPlantModel.UpdateLeafStock(cellEnvironment, gridCellStocks, actingStock, currentTimeStep, madingleyStockDefinitions.
                                                                        GetTraitNames("leaf strategy", actingStock[0]).Equals("deciduous"), globalModelTimeStepUnit, tracker, globalTracker, currentMonth,
                                                                        outputDetail, specificLocations);

                double fhanpp = HANPP.RemoveHumanAppropriatedMatter(WetMatterNPP, cellEnvironment, humanNPPScenario, gridCellStocks, actingStock,
                                                                    currentTimeStep, ScenarioYear, burninSteps, impactSteps, recoverySteps, instantStep, numInstantSteps, impactCell, globalModelTimeStepUnit);

                // Apply human appropriation of NPP
                gridCellStocks[actingStock].TotalBiomass += WetMatterNPP * (1.0 - fhanpp);
                if (globalTracker.TrackProcesses)
                {
                    globalTracker.RecordHANPP((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], (uint)actingStock[0],
                                              fhanpp);
                }

                if (gridCellStocks[actingStock].TotalBiomass < 0.0)
                {
                    gridCellStocks[actingStock].TotalBiomass = 0.0;
                }
            }
            else
            {
                Debug.Fail("Stock must be classified as belonging to either the marine or terrestrial realm");
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Generates the outputs for the current time step
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="currentTimeStep">The current model time step</param>
        /// <param name="currentMonth">The current month in the model run</param>
        /// <param name="timeStepTimer">The timer for the current time step</param>
        /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions of cohorts in the model</param>
        /// <param name="stockFunctionalGroupDefinitions">The functional group definitions of stocks in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="globalDiagnosticVariables">The global diagnostic variables for the model run</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void TimeStepOutputs(ModelGrid ecosystemModelGrid, uint currentTimeStep, uint currentMonth, StopWatch timeStepTimer,
                                    FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions,
                                    List <uint[]> cellIndices, SortedList <string, double> globalDiagnosticVariables, MadingleyModelInitialisation initialisation)
        {
            // Calculate the output variables for this time step
            CalculateOutputs(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, ecosystemModelGrid, cellIndices,
                             globalDiagnosticVariables, initialisation);

            // Generate the time step console outputs
            TimeStepConsoleOutputs(currentTimeStep, currentMonth, timeStepTimer);

            // Generate the time step file outputs
            TimeStepFileOutputs(ecosystemModelGrid, currentTimeStep);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Generates the initial model outputs before the first time step
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions of cohorts in the model</param>
        /// <param name="stockFunctionalGroupDefinitions">The functional group definitions of stocks in the model</param>
        /// <param name="cellIndices">The list of indices of active cells in the model grid</param>
        /// <param name="globalDiagnosticVariables">A list of global diagnostic variables</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void InitialOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions,
                                   FunctionalGroupDefinitions stockFunctionalGroupDefinitions, List <uint[]> cellIndices,
                                   SortedList <string, double> globalDiagnosticVariables, MadingleyModelInitialisation initialisation)
        {
            // Calculate the output variables
            CalculateOutputs(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, ecosystemModelGrid, cellIndices,
                             globalDiagnosticVariables, initialisation);

            // Generate the initial console outputs
            InitialConsoleOutputs();

            // Generate the initial file outputs
            InitialFileOutptus(ecosystemModelGrid);
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Set up the necessary architecture for generating outputs arranged by trait value
        /// </summary>
        /// <param name="cohortFunctionalGroupDefinitions">Functional group definitions for cohorts in the model</param>
        /// <param name="stockFunctionalGroupDefinitions">Functional group definitions for stocks in the model</param>
        private void InitialiseTraitBasedOutputs(FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions
                                                 stockFunctionalGroupDefinitions)
        {
            // Define the cohort traits that will be used to separate outputs
            CohortTraits = new string[3] {
                "Nutrition source", "Endo/Ectotherm", "Reproductive strategy"
            };

            // Declare a sorted dictionary to hold all unique trait values
            CohortTraitValues = new SortedDictionary <string, string[]>();

            // Add all unique trait values to the sorted dictionary
            foreach (string Trait in CohortTraits)
            {
                CohortTraitValues.Add(Trait, cohortFunctionalGroupDefinitions.GetUniqueTraitValues(Trait));
            }

            // Get the list of functional group indices corresponding to each unique trait value
            foreach (string Trait in CohortTraits)
            {
                foreach (string TraitValue in CohortTraitValues[Trait])
                {
                    CohortTraitIndices.Add(TraitValue, cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false));
                }
            }

            // Define the stock traits that will be used to separate outputs
            StockTraits = new string[2] {
                "Heterotroph/Autotroph", "Leaf strategy"
            };

            // Re-initialise the sorted dictionary to hold all unique trait values
            StockTraitValues = new SortedDictionary <string, string[]>();

            // Add all unique stock trait values to the sorted dictionary
            foreach (string Trait in StockTraits)
            {
                StockTraitValues.Add(Trait, stockFunctionalGroupDefinitions.GetUniqueTraitValues(Trait));
            }

            // Get the list of functional group indices corresponding to each unique trait value
            foreach (string Trait in StockTraits)
            {
                foreach (string TraitValue in StockTraitValues[Trait])
                {
                    StockTraitIndices.Add(TraitValue, stockFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false));
                }
            }
        }
        /// <summary>
        /// Run metabolism for the acting cohort
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for the stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunMetabolism(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, 
            int[] actingCohort, SortedList<string, double[]> cellEnvironment, Dictionary<string, Dictionary<string, double>> 
            deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, 
            uint currentTimestep, uint currentMonth)
        {
            // Calculate metabolic loss for an individual and add the value to the delta biomass for metabolism
            deltas["biomass"]["metabolism"] = -CalculateIndividualMetabolicRate(gridCellCohorts[actingCohort].IndividualBodyMass,
                cellEnvironment["Temperature"][currentMonth] + _TemperatureUnitsConvert) * _DeltaT;

            // If metabolic loss is greater than individual body mass after herbivory and predation, then set equal to individual body mass
            deltas["biomass"]["metabolism"] = Math.Max(deltas["biomass"]["metabolism"],-(gridCellCohorts[actingCohort].IndividualBodyMass + deltas["biomass"]["predation"] + deltas["biomass"]["herbivory"]));

            // Add total metabolic loss for all individuals in the cohort to delta biomass for metabolism in the respiratory CO2 pool
            deltas["respiratoryCO2pool"]["metabolism"] = -deltas["biomass"]["metabolism"] * gridCellCohorts[actingCohort].CohortAbundance;
        }
        /// <summary>
        /// Run metabolism for the acting cohort
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for the stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="currentMonth">The current model month</param>
        public void RunMetabolism(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                  int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> >
                                  deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                  uint currentTimestep, uint currentMonth)
        {
            // Calculate metabolic loss for an individual and add the value to the delta biomass for metabolism
            deltas["biomass"]["metabolism"] = -CalculateIndividualMetabolicRate(gridCellCohorts[actingCohort].IndividualBodyMass,
                                                                                cellEnvironment["Temperature"][currentMonth] + _TemperatureUnitsConvert) * _DeltaT;

            // If metabolic loss is greater than individual body mass after herbivory and predation, then set equal to individual body mass
            deltas["biomass"]["metabolism"] = Math.Max(deltas["biomass"]["metabolism"], -(gridCellCohorts[actingCohort].IndividualBodyMass + deltas["biomass"]["predation"] + deltas["biomass"]["herbivory"]));

            // Add total metabolic loss for all individuals in the cohort to delta biomass for metabolism in the respiratory CO2 pool
            deltas["respiratoryCO2pool"]["metabolism"] = -deltas["biomass"]["metabolism"] * gridCellCohorts[actingCohort].CohortAbundance;
        }
Ejemplo n.º 19
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>
        /// Run reproduction
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
        /// <param name="currentTimeStep">The current model time step</param>
        /// <param name="processTracker">An instance of ProcessTracker to hold diagnostics for eating</param>
        /// <param name="partial">Thread-locked variables for the parallelised version</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail being used for this model run</param>
        /// <param name="currentMonth">The current model month</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, 
            int[] actingCohort, SortedList<string, double[]> cellEnvironment, Dictionary<string,Dictionary<string,double>> deltas , 
            FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
            uint currentTimeStep, ProcessTracker processTracker, ref ThreadLockedParallelVariables partial,
            Boolean specificLocations, string outputDetail, uint currentMonth, MadingleyModelInitialisation initialisation)
        {
            // Holds the reproductive strategy of a cohort
            bool _Iteroparous = madingleyCohortDefinitions.GetTraitNames("reproductive strategy", actingCohort[0])=="iteroparity";

            // Assign mass to reproductive potential
            Implementations["reproduction basic"].RunReproductiveMassAssignment(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas,
                madingleyCohortDefinitions, madingleyStockDefinitions, currentTimeStep, processTracker);

            // Run reproductive events. Note that we can't skip juveniles here as they could conceivably grow to adulthood and get enough biomass to reproduce in a single time step
            // due to other ecological processes
            Implementations["reproduction basic"].RunReproductionEvents(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment,
                    deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimeStep, processTracker, ref partial, _Iteroparous, currentMonth);
        }
        /// <summary>
        /// Run reproduction
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
        /// <param name="currentTimeStep">The current model time step</param>
        /// <param name="processTracker">An instance of ProcessTracker to hold diagnostics for eating</param>
        /// <param name="partial">Thread-locked variables for the parallelised version</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail being used for this model run</param>
        /// <param name="currentMonth">The current model month</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                         int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas,
                                         FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                         uint currentTimeStep, ProcessTracker processTracker, ref ThreadLockedParallelVariables partial,
                                         Boolean specificLocations, string outputDetail, uint currentMonth, MadingleyModelInitialisation initialisation)
        {
            // Holds the reproductive strategy of a cohort
            bool _Iteroparous = madingleyCohortDefinitions.GetTraitNames("reproductive strategy", actingCohort[0]) == "iteroparity";

            // Assign mass to reproductive potential
            Implementations["reproduction basic"].RunReproductiveMassAssignment(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas,
                                                                                madingleyCohortDefinitions, madingleyStockDefinitions, currentTimeStep, processTracker);

            // Run reproductive events. Note that we can't skip juveniles here as they could conceivably grow to adulthood and get enough biomass to reproduce in a single time step
            // due to other ecological processes
            Implementations["reproduction basic"].RunReproductionEvents(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment,
                                                                        deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimeStep, processTracker, ref partial, _Iteroparous, currentMonth);
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Run ecological processes that operate on stocks within a single grid cell
        /// </summary>
        ///<param name="gridCellStocks">The stocks in the current grid cell</param>
        ///<param name="actingStock">The acting stock</param>
        ///<param name="cellEnvironment">The stocks in the current grid cell</param>
        ///<param name="environmentalDataUnits">List of units associated with the environmental variables</param>
        ///<param name="humanNPPScenario">The human appropriation of NPP scenario to apply</param>
        ///<param name="madingleyStockDefinitions">The functional group definitions for stocks in the model</param>
        ///<param name="currentTimeStep">The current model time step</param>
        ///<param name="burninSteps">The number of time steps to spin the model up for before applying human impacts</param>
        ///<param name="impactSteps">The number of time steps to apply human impacts for</param>
        ///<param name="globalModelTimeStepUnit">The time step unit used in the model</param>
        ///<param name="trackProcesses">Whether to track properties of ecological processes</param>
        ///<param name="tracker">An instance of the ecological process tracker</param>
        ///<param name="globalTracker">An instance of the global process tracker</param>
        ///<param name="currentMonth">The current model month</param>
        ///<param name="outputDetail">The level of detail to use in outputs</param>
        ///<param name="specificLocations">Whether to run the model for specific locations</param>
        ///<param name="impactCell">Whether this cell should have human impacts applied</param>
        public void RunWithinCellEcology(GridCellStockHandler gridCellStocks, int[] actingStock, SortedList<string, double[]> cellEnvironment,
            SortedList<string, string> environmentalDataUnits, Madingley.Common.ScenarioParameter humanNPPScenario,
            FunctionalGroupDefinitions madingleyStockDefinitions,
            uint currentTimeStep, uint burninSteps, uint impactSteps, uint recoverySteps, uint instantStep, uint numInstantSteps, string globalModelTimeStepUnit, Boolean trackProcesses,
            ProcessTracker tracker,
            GlobalProcessTracker globalTracker, uint currentMonth,
            string outputDetail, bool specificLocations, Boolean impactCell)
        {
            if (madingleyStockDefinitions.GetTraitNames("Realm", actingStock[0]) == "marine")
            {
                // Run the autotroph processor
                MarineNPPtoAutotrophStock.ConvertNPPToAutotroph(cellEnvironment, gridCellStocks, actingStock, environmentalDataUnits["LandNPP"],
                    environmentalDataUnits["OceanNPP"], currentTimeStep, globalModelTimeStepUnit, tracker, globalTracker, outputDetail, specificLocations, currentMonth);
            }
            else if (madingleyStockDefinitions.GetTraitNames("Realm", actingStock[0]) == "terrestrial")
            {

                // Run the dynamic plant model to update the leaf stock for this time step
                double WetMatterNPP = DynamicPlantModel.UpdateLeafStock(cellEnvironment, gridCellStocks, actingStock, currentTimeStep, madingleyStockDefinitions.
                    GetTraitNames("leaf strategy", actingStock[0]).Equals("deciduous"), globalModelTimeStepUnit, tracker, globalTracker, currentMonth,
                    outputDetail, specificLocations);
                /// <summary>

                double fhanpp = HANPP.RemoveHumanAppropriatedMatter(WetMatterNPP, cellEnvironment, humanNPPScenario, gridCellStocks, actingStock,
                    currentTimeStep, burninSteps, impactSteps, recoverySteps, instantStep, numInstantSteps, impactCell, globalModelTimeStepUnit);

                // Apply human appropriation of NPP
                gridCellStocks[actingStock].TotalBiomass += WetMatterNPP * (1.0 - fhanpp);

                if (globalTracker.TrackProcesses)
                {
                    globalTracker.RecordHANPP((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], (uint)actingStock[0],
                        fhanpp);
                }

                if (gridCellStocks[actingStock].TotalBiomass < 0.0) gridCellStocks[actingStock].TotalBiomass = 0.0;

            }
            else
            {
                Debug.Fail("Stock must be classified as belonging to either the marine or terrestrial realm");
            }
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Calculates the variables to output
        /// </summary>
        /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions of cohorts in the model</param>
        /// <param name="stockFunctionalGroupDefinitions">The functional group definitions of stocks in the model</param>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of active cells in the model grid</param>
        /// <param name="globalDiagnosticVariables">Global diagnostic variables</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void CalculateOutputs(FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions
                                     stockFunctionalGroupDefinitions, ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, SortedList <string, double>
                                     globalDiagnosticVariables, MadingleyModelInitialisation initialisation)
        {
            // Get all cohort functional group indices in the model
            int[] CohortFunctionalGroupIndices = cohortFunctionalGroupDefinitions.AllFunctionalGroupsIndex;

            // Get all stock functional group indices in the model
            int[] StockFunctionalGroupIndices = stockFunctionalGroupDefinitions.AllFunctionalGroupsIndex;

            // Reset total abundance, biomass and pool biomasses
            TotalAbundance     = 0.0;
            TotalBiomass       = 0.0;
            TotalLivingBiomass = 0.0;
            OrganicPoolOut     = 0.0;
            RespiratoryPoolOut = 0.0;

            // Add total cohort biomass and total stock biomass to the total biomass tracker
            TotalLivingBiomass += ecosystemModelGrid.StateVariableGridTotal("Biomass", "NA", CohortFunctionalGroupIndices, cellIndices, "cohort", initialisation);
            TotalLivingBiomass += ecosystemModelGrid.StateVariableGridTotal("Biomass", "NA", StockFunctionalGroupIndices, cellIndices, "stock", initialisation);

            // Add total cohort abundance to the total abundance tracker
            TotalAbundance += ecosystemModelGrid.StateVariableGridTotal("Abundance", "NA", CohortFunctionalGroupIndices, cellIndices, "cohort", initialisation);

            // Get total organic pool biomass
            OrganicPoolOut = ecosystemModelGrid.GetEnviroGridTotal("Organic Pool", 0, cellIndices);

            // Get total respiratory pool biomass
            RespiratoryPoolOut = ecosystemModelGrid.GetEnviroGridTotal("Respiratory CO2 Pool", 0, cellIndices);

            // Get total of all biomass
            TotalBiomass = TotalLivingBiomass + RespiratoryPoolOut + OrganicPoolOut;

            // Get number of cohorts and stocks
            TotalNumberOfCohorts = globalDiagnosticVariables["NumberOfCohortsInModel"];
            TotalNumberOfStocks  = globalDiagnosticVariables["NumberOfStocksInModel"];

            // Get numbers of cohort extinctions and productions
            NumberOfCohortsExtinct  = globalDiagnosticVariables["NumberOfCohortsExtinct"];
            NumberOfCohortsProduced = globalDiagnosticVariables["NumberOfCohortsProduced"];
            NumberOfCohortsCombined = globalDiagnosticVariables["NumberOfCohortsCombined"];
        }
        /// <summary>
        /// Set up the herbivory tracker
        /// </summary>
        /// <param name="numTimeSteps">The total number of timesteps for this simulation</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="massFlowsFilename">Filename for outputs of the flows of mass between predators and prey</param>
        /// <param name="cohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="missingValue">The missing value to be used in the output file</param>
        /// <param name="outputFileSuffix">The suffix to be applied to the output file</param>
        /// <param name="outputPath">The path to write the output file to</param>
        /// <param name="trackerMassBins">The mass bin handler containing the mass bins to be used for predation tracking</param>
        public HerbivoryTracker(uint numTimeSteps,
            List<uint[]> cellIndices,
            string massFlowsFilename,
            FunctionalGroupDefinitions cohortDefinitions,
            double missingValue,
            string outputFileSuffix,
            string outputPath, MassBinsHandler trackerMassBins)
        {
            // Assign the missing value
            _MissingValue = missingValue;

            // Get the mass bins to use for the predation tracker and the number of mass bins that this correpsonds to
            _MassBins = trackerMassBins.GetSpecifiedMassBins();
            _NumMassBins = trackerMassBins.NumMassBins;

            // Initialise the array to hold data on mass flows between mass bins
            _MassFlows = new double[_NumMassBins];

            // Define the model time steps to be used in the output file
            TimeSteps = new float[numTimeSteps];
            for (int i = 1; i <= numTimeSteps; i++)
            {
                TimeSteps[i - 1] = i;
            }

            // Initialise the data converter
            DataConverter = new ArraySDSConvert();

            // Initialise the SDS object creator
            SDSCreator = new CreateSDSObject();

            // Create an SDS object to hold the predation tracker data
            MassFlowsDataSet = SDSCreator.CreateSDS("netCDF", massFlowsFilename + outputFileSuffix, outputPath);

            // Define the dimensions to be used in the predation tracker output file
            string[] dimensions = { "Time step", "Herbivore mass bin" };

            // Add the mass flow variable to the predation tracker
            DataConverter.AddVariable(MassFlowsDataSet, "Log mass (g)", 2, dimensions, _MissingValue, TimeSteps, _MassBins);

            
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Set up the predation tracker
        /// </summary>_
        /// <param name="numTimeSteps">The total number of timesteps for this simulation</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="massFlowsFilename">Filename for outputs of the flows of mass between predators and prey</param>
        /// <param name="cohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="missingValue">The missing value to be used in the output file</param>
        /// <param name="outputFileSuffix">The suffix to be applied to the output file</param>
        /// <param name="outputPath">The path to write the output file to</param>
        /// <param name="trackerMassBins">The mass bin handler containing the mass bins to be used for predation tracking</param>
        /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param>
        public PredationTracker(uint numTimeSteps,
                                List <uint[]> cellIndices,
                                string massFlowsFilename,
                                FunctionalGroupDefinitions cohortDefinitions,
                                double missingValue,
                                string outputFileSuffix,
                                string outputPath, MassBinsHandler trackerMassBins, int cellIndex)
        {
            // Assign the missing value
            _MissingValue = missingValue;

            // Get the mass bins to use for the predation tracker and the number of mass bins that this correpsonds to
            _MassBins    = trackerMassBins.GetSpecifiedMassBins();
            _NumMassBins = trackerMassBins.NumMassBins;

            // Initialise the array to hold data on mass flows between mass bins
            _MassFlows = new double[_NumMassBins, _NumMassBins];

            // Define the model time steps to be used in the output file
            float[] TimeSteps = new float[numTimeSteps];
            for (int i = 1; i <= numTimeSteps; i++)
            {
                TimeSteps[i - 1] = i;
            }

            // Initialise the data converter
            DataConverter = new ArraySDSConvert();

            // Initialise the SDS object creator
            SDSCreator = new CreateSDSObject();

            // Create an SDS object to hold the predation tracker data
            MassFlowsDataSet = SDSCreator.CreateSDS("netCDF", massFlowsFilename + outputFileSuffix + "_Cell" + cellIndex, outputPath);

            // Define the dimensions to be used in the predation tracker output file
            string[] dimensions = { "Predator mass bin", "Prey mass bin", "Time steps" };

            // Add the mass flow variable to the predation tracker
            DataConverter.AddVariable(MassFlowsDataSet, "Log mass (g)", 3, dimensions, _MissingValue, _MassBins, _MassBins, TimeSteps);
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Assigns the properties of the current model run
        /// </summary>
        /// <param name="initialisation">An instance of the model initialisation class</param> 
        /// <param name="scenarioParameters">The parameters for the scenarios to run</param>
        /// <param name="scenarioIndex">The index of the scenario that this model is to run</param>
        /// <param name="outputFilesSuffix">The suffix to be applied to all outputs from this model run</param>
        public void AssignModelRunProperties(MadingleyModelInitialisation initialisation, 
            ScenarioParameterInitialisation scenarioParameters, int scenarioIndex,
            string outputFilesSuffix)
#endif
        {
            // Assign the properties of this model run from the same properties in the specified model initialisation
            _GlobalModelTimeStepUnit = initialisation.GlobalModelTimeStepUnit;
            NumTimeSteps = initialisation.NumTimeSteps;
            CellSize = (float)initialisation.CellSize;
            _CellList = initialisation.CellList;
            BottomLatitude = initialisation.BottomLatitude;
            TopLatitude = initialisation.TopLatitude;
            LeftmostLongitude = initialisation.LeftmostLongitude;
            RightmostLongitude = initialisation.RightmostLongitude;
            InitialisationFileStrings = initialisation.InitialisationFileStrings;
            CohortFunctionalGroupDefinitions = initialisation.CohortFunctionalGroupDefinitions;
            StockFunctionalGroupDefinitions = initialisation.StockFunctionalGroupDefinitions;
            EnviroStack = initialisation.EnviroStack;
            OutputFilesSuffix = outputFilesSuffix;
            OutputModelStateTimestep = initialisation.OutputStateTimestep;
            SpecificLocations = initialisation.SpecificLocations;
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Generate new cohorts from reproductive potential mass
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment of the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param>
        /// <param name="partial">Thread-locked variables</param>
        public void RunReproduction(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                    int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> >
                                    deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                    uint currentTimestep, ProcessTracker tracker, ref ThreadLockedParallelVariables partial)
        {
            // Check that the abundance in the cohort to produce is greater than or equal to zero
            Debug.Assert(_OffspringCohortAbundance >= 0.0, "Offspring abundance < 0");

            // Get the adult and juvenile masses of the cohort to produce
            double[] OffspringProperties = GetOffspringCohortProperties(gridCellCohorts, actingCohort,
                                                                        madingleyCohortDefinitions);

            // Update cohort abundance in case juvenile mass has been altered
            _OffspringCohortAbundance = (_OffspringCohortAbundance * gridCellCohorts[actingCohort].JuvenileMass) /
                                        OffspringProperties[0];

            //Create the offspring cohort
            Cohort OffspringCohort = new Cohort((byte)actingCohort[0],
                                                OffspringProperties[0],
                                                OffspringProperties[1],
                                                OffspringProperties[0],
                                                _OffspringCohortAbundance,
                                                (ushort)currentTimestep, ref partial.NextCohortIDThreadLocked);

            // Add the offspring cohort to the grid cell cohorts array
            gridCellCohorts[actingCohort[0]].Add(OffspringCohort);

            // If the cohort has never been merged with another cohort, then add it to the tracker for output as diagnostics
            if ((!gridCellCohorts[actingCohort].Merged) && tracker.TrackProcesses)
            {
                tracker.RecordNewCohort((uint)cellEnvironment["LatIndex"][0],
                                        (uint)cellEnvironment["LonIndex"][0], currentTimestep, _OffspringCohortAbundance,
                                        gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex);
            }

            // Subtract all of the reproductive potential mass of the parent cohort, which has been used to generate the new
            // cohort, from the delta reproductive potential mass
            deltas["reproductivebiomass"]["reproduction"] -= (gridCellCohorts[actingCohort].IndividualReproductivePotentialMass);
        }
        /// <summary>
        /// Generate new cohorts from reproductive potential mass
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment of the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param>
        /// <param name="partial">Thread-locked variables</param>
        public void RunReproduction(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
            int[] actingCohort, SortedList<string, double[]> cellEnvironment, Dictionary<string, Dictionary<string, double>>
            deltas, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
            uint currentTimestep, ProcessTracker tracker, ref ThreadLockedParallelVariables partial)
        {
            // Check that the abundance in the cohort to produce is greater than or equal to zero
            Debug.Assert(_OffspringCohortAbundance >= 0.0, "Offspring abundance < 0");

            // Get the adult and juvenile masses of the cohort to produce
            double[] OffspringProperties = GetOffspringCohortProperties(gridCellCohorts, actingCohort,
                madingleyCohortDefinitions);

            // Update cohort abundance in case juvenile mass has been altered
            _OffspringCohortAbundance = (_OffspringCohortAbundance * gridCellCohorts[actingCohort].JuvenileMass) /
                OffspringProperties[0];

            //Create the offspring cohort
            Cohort OffspringCohort = new Cohort((byte)actingCohort[0],
                                                OffspringProperties[0],
                                                OffspringProperties[1],
                                                OffspringProperties[0],
                                                _OffspringCohortAbundance,
                                                (ushort)currentTimestep, ref partial.NextCohortIDThreadLocked);

            // Add the offspring cohort to the grid cell cohorts array
            gridCellCohorts[actingCohort[0]].Add(OffspringCohort);

            // If the cohort has never been merged with another cohort, then add it to the tracker for output as diagnostics
            if ((!gridCellCohorts[actingCohort].Merged) && tracker.TrackProcesses)
                tracker.RecordNewCohort((uint)cellEnvironment["LatIndex"][0],
                    (uint)cellEnvironment["LonIndex"][0], currentTimestep, _OffspringCohortAbundance,
                    gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex);

            // Subtract all of the reproductive potential mass of the parent cohort, which has been used to generate the new
            // cohort, from the delta reproductive potential mass
            deltas["reproductivebiomass"]["reproduction"] -= (gridCellCohorts[actingCohort].IndividualReproductivePotentialMass);

        }
Ejemplo n.º 29
0
        /// <summary>
        /// Constructor for process tracker: Initialises the trackers for individual processes
        /// </summary>
        /// <param name="numTimesteps">The number of time steps in the model</param>
        /// <param name="lats">The latitudes of active grid cells in the model</param>
        /// <param name="lons">The longitudes of active grid cells in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="Filenames">The filenames of the output files to write the tracking results to</param>
        /// <param name="trackProcesses">Whether to track processes</param>
        /// <param name="cohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="missingValue">The missing value to use in process tracking output files</param>
        /// <param name="outputFileSuffix">The suffix to be applied to output files from process tracking</param>
        /// <param name="outputPath">The path to the folder to be used for process tracking outputs</param>
        /// <param name="trackerMassBins">The mass bins to use for categorising output data in the process trackers</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="latCellSize">The size of grid cells latitudinally</param>
        /// <param name="lonCellSize">The size of grid cells longitudinally</param>
        public GlobalProcessTracker(uint numTimesteps,
                                    float[] lats, float[] lons,
                                    List <uint[]> cellIndices,
                                    SortedList <string, string> Filenames,
                                    Boolean trackProcesses,
                                    FunctionalGroupDefinitions cohortDefinitions,
                                    FunctionalGroupDefinitions stockDefinitions,
                                    double missingValue,
                                    string outputFileSuffix,
                                    string outputPath, MassBinsHandler trackerMassBins,
                                    Boolean specificLocations,
                                    MadingleyModelInitialisation initialisation,
                                    float latCellSize,
                                    float lonCellSize)
        {
            // Initialise trackers for ecological processes
            _TrackProcesses = trackProcesses;

            if (_TrackProcesses)
            {
                _TrackNPP = new GlobalNPPTracker(outputPath, lats.Length, lons.Length, lats, lons, latCellSize, lonCellSize, (int)numTimesteps, stockDefinitions.GetNumberOfFunctionalGroups());
            }
        }
        /// <summary>
        /// Run metabolism
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="trackProcesses">An instance of ProcessTracker to hold diagnostics for metabolism</param>
        /// <param name="partial">Thread-locked variables</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail being used for the current model run</param>
        /// <param name="currentMonth">The current model month</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEcologicalProcess(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, 
            int[] actingCohort, SortedList<string, double[]> cellEnvironment, Dictionary<string, Dictionary<string, double>> deltas, 
            FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, 
            uint currentTimestep, ProcessTracker trackProcesses, ref ThreadLockedParallelVariables partial,
            Boolean specificLocations, string outputDetail, uint currentMonth, MadingleyModelInitialisation initialisation)
        {
            double Realm = cellEnvironment["Realm"][0];
            if (madingleyCohortDefinitions.GetTraitNames("Heterotroph/Autotroph", gridCellCohorts[actingCohort].FunctionalGroupIndex) == "heterotroph")
            {
                if (madingleyCohortDefinitions.GetTraitNames("Endo/Ectotherm", gridCellCohorts[actingCohort].FunctionalGroupIndex) == "endotherm")
                {

                        Implementations["basic endotherm"].RunMetabolism(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, currentMonth);
                }
                else
                {
                        Implementations["basic ectotherm"].RunMetabolism(gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, currentTimestep, currentMonth);

                }

            }

            // If the process tracker is on and output detail is set to high and this cohort has not been merged yet, then record
            // the number of individuals that have died
            if (trackProcesses.TrackProcesses && (outputDetail == "high"))
            {

                trackProcesses.TrackTimestepMetabolism((uint)cellEnvironment["LatIndex"][0],
                                                (uint)cellEnvironment["LonIndex"][0],
                                                currentTimestep,
                                                gridCellCohorts[actingCohort].IndividualBodyMass,
                                                actingCohort[0],
                                                cellEnvironment["Temperature"][currentMonth],
                                                deltas["biomass"]["metabolism"]);

            }
        }
        /// <summary>
        /// Constructor for process tracker: Initialises the trackers for individual processes
        /// </summary>
        /// <param name="numTimesteps">The number of time steps in the model</param>
        /// <param name="lats">The latitudes of active grid cells in the model</param>
        /// <param name="lons">The longitudes of active grid cells in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="Filenames">The filenames of the output files to write the tracking results to</param>
        /// <param name="trackProcesses">Whether to track processes</param>
        /// <param name="cohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="missingValue">The missing value to use in process tracking output files</param>
        /// <param name="outputFileSuffix">The suffix to be applied to output files from process tracking</param>
        /// <param name="outputPath">The path to the folder to be used for process tracking outputs</param>
        /// <param name="trackerMassBins">The mass bins to use for categorising output data in the process trackers</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        /// <param name="latCellSize">The size of grid cells in the latitudinal direction</param>
        /// <param name="lonCellSize">The size of grid cells in the longitudinal direction</param>
        public ProcessTracker(uint numTimesteps,
            float[] lats, float[] lons, 
            List<uint[]> cellIndices,
            SortedList<string,string> Filenames, 
            Boolean trackProcesses, 
            FunctionalGroupDefinitions cohortDefinitions, 
            double missingValue,
            string outputFileSuffix,
            string outputPath, MassBinsHandler trackerMassBins,
            Boolean specificLocations,
            int cellIndex,
            MadingleyModelInitialisation initialisation,
            bool marineCell,
            float latCellSize,
            float lonCellSize)
        {
            // Initialise trackers for ecological processes
            _TrackProcesses = trackProcesses;

            if (_TrackProcesses)
            {
                _TrackReproduction = new ReproductionTracker(numTimesteps, (uint)lats.Length, (uint)lons.Length, cellIndices, Filenames["NewCohortsOutput"], Filenames["MaturityOutput"], outputFileSuffix, outputPath, cellIndex);
                _TrackEating = new EatingTracker((uint)lats.Length, (uint)lons.Length, Filenames["TrophicFlowsOutput"], outputFileSuffix, outputPath, cellIndex, initialisation, marineCell);
                _TrackGrowth = new GrowthTracker(numTimesteps, (uint)lats.Length, (uint)lons.Length, cellIndices, Filenames["GrowthOutput"], outputFileSuffix, outputPath, cellIndex);
                _TrackMortality = new MortalityTracker(numTimesteps, (uint)lats.Length, (uint)lons.Length, cellIndices, Filenames["MortalityOutput"], outputFileSuffix, outputPath, cellIndex);
                _TrackExtinction = new ExtinctionTracker(Filenames["ExtinctionOutput"], outputPath, outputFileSuffix, cellIndex);
                _TrackMetabolism = new MetabolismTracker(Filenames["MetabolismOutput"], outputPath, outputFileSuffix, cellIndex);

                // Initialise the predation and herbivory trackers only for runs with specific locations
                if (specificLocations == true)
                {
                    _TrackPredation = new PredationTracker( numTimesteps, cellIndices, Filenames["PredationFlowsOutput"], cohortDefinitions,
                        missingValue, outputFileSuffix, outputPath, trackerMassBins, cellIndex);
                }
            }
        }
Ejemplo n.º 32
0
        /// <summary>
        /// Constructor for process tracker: Initialises the trackers for individual processes
        /// </summary>
        /// <param name="numTimesteps">The number of time steps in the model</param>
        /// <param name="lats">The latitudes of active grid cells in the model</param>
        /// <param name="lons">The longitudes of active grid cells in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="Filenames">The filenames of the output files to write the tracking results to</param>
        /// <param name="trackProcesses">Whether to track processes</param>
        /// <param name="cohortDefinitions">The definitions for cohort functional groups in the model</param>
        /// <param name="missingValue">The missing value to use in process tracking output files</param>
        /// <param name="outputFileSuffix">The suffix to be applied to output files from process tracking</param>
        /// <param name="outputPath">The path to the folder to be used for process tracking outputs</param>
        /// <param name="trackerMassBins">The mass bins to use for categorising output data in the process trackers</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        /// <param name="latCellSize">The size of grid cells in the latitudinal direction</param>
        /// <param name="lonCellSize">The size of grid cells in the longitudinal direction</param>
        public ProcessTracker(uint numTimesteps,
                              float[] lats, float[] lons,
                              List <uint[]> cellIndices,
                              SortedList <string, string> Filenames,
                              Boolean trackProcesses,
                              FunctionalGroupDefinitions cohortDefinitions,
                              double missingValue,
                              string outputFileSuffix,
                              string outputPath, MassBinsHandler trackerMassBins,
                              Boolean specificLocations,
                              int cellIndex,
                              MadingleyModelInitialisation initialisation,
                              bool marineCell,
                              float latCellSize,
                              float lonCellSize)
        {
            // Initialise trackers for ecological processes
            _TrackProcesses = trackProcesses;

            if (_TrackProcesses)
            {
                _TrackReproduction = new ReproductionTracker(numTimesteps, (uint)lats.Length, (uint)lons.Length, cellIndices, Filenames["NewCohortsOutput"], Filenames["MaturityOutput"], outputFileSuffix, outputPath, cellIndex);
                _TrackEating       = new EatingTracker((uint)lats.Length, (uint)lons.Length, Filenames["TrophicFlowsOutput"], outputFileSuffix, outputPath, cellIndex, initialisation, marineCell);
                _TrackGrowth       = new GrowthTracker(numTimesteps, (uint)lats.Length, (uint)lons.Length, cellIndices, Filenames["GrowthOutput"], outputFileSuffix, outputPath, cellIndex);
                _TrackMortality    = new MortalityTracker(numTimesteps, (uint)lats.Length, (uint)lons.Length, cellIndices, Filenames["MortalityOutput"], outputFileSuffix, outputPath, cellIndex);
                _TrackExtinction   = new ExtinctionTracker(Filenames["ExtinctionOutput"], outputPath, outputFileSuffix, cellIndex);
                _TrackMetabolism   = new MetabolismTracker(Filenames["MetabolismOutput"], outputPath, outputFileSuffix, cellIndex);

                // Initialise the predation and herbivory trackers only for runs with specific locations
                if (specificLocations == true)
                {
                    _TrackPredation = new PredationTracker(numTimesteps, cellIndices, Filenames["PredationFlowsOutput"], cohortDefinitions,
                                                           missingValue, outputFileSuffix, outputPath, trackerMassBins, cellIndex);
                }
            }
        }
Ejemplo n.º 33
0
        /// <summary>
        /// Assigns biomass from body mass to reproductive potential mass
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The position of the acting cohort in the jagged array of grid cell cohorts</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="tracker">An instance of ProcessTracker to hold diagnostics for reproduction</param>
        public void AssignMassToReproductivePotential(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks,
                                                      int[] actingCohort, SortedList <string, double[]> cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas,
                                                      FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions,
                                                      uint currentTimestep, ProcessTracker tracker)
        {
            // If this is the first time reproductive potential mass has been assigned for this cohort,
            // then set the maturity time step for this cohort as the current model time step
            if (gridCellCohorts[actingCohort].MaturityTimeStep == uint.MaxValue)
            {
                gridCellCohorts[actingCohort].MaturityTimeStep = currentTimestep;

                // Track the generation length for this cohort
                if ((!gridCellCohorts[actingCohort].Merged) && tracker.TrackProcesses)
                {
                    tracker.TrackMaturity((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                          currentTimestep, gridCellCohorts[actingCohort].BirthTimeStep, gridCellCohorts[actingCohort].JuvenileMass,
                                          gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex);
                }
            }

            // Assign the specified mass to reproductive potential mass and remove it from individual biomass
            deltas["reproductivebiomass"]["reproduction"] += _BiomassToAssignToReproductivePotential;
            deltas["biomass"]["reproduction"]             -= _BiomassToAssignToReproductivePotential;
        }
        /// <summary>
        /// Write to the output file values of the output variables during the model time steps
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid to get data from</param>
        /// <param name="cohortFunctionalGroupDefinitions">The definitions of the cohort functional groups in the model</param>
        /// <param name="stockFunctionalGroupDefinitions">The definitions of the stock  functional groups in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="cellNumber">The number of the current cell in the list of indices of active cells</param>
        /// <param name="globalDiagnosticVariables">List of global diagnostic variables</param>
        /// <param name="timeStepTimer">The timer for the current time step</param>
        /// <param name="numTimeSteps">The number of time steps in the model run</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="month">The current month in the model run</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        public void TimeStepOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, 
            FunctionalGroupDefinitions stockFunctionalGroupDefinitions, List<uint[]> cellIndices, int cellNumber,
            SortedList<string, double> globalDiagnosticVariables, StopWatch timeStepTimer, uint numTimeSteps, uint currentTimestep, 
            MadingleyModelInitialisation initialisation, uint month, Boolean marineCell)
        {
            // Calculate values of the output variables to be used
            CalculateOutputs(ecosystemModelGrid, cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, cellIndices, cellNumber, globalDiagnosticVariables, initialisation, month, marineCell);

            // Generate the live outputs for this time step
            if (LiveOutputs)
            {
                TimeStepLiveOutputs(numTimeSteps, currentTimestep, ecosystemModelGrid, marineCell);
            }

            // Generate the console outputs for the current time step
            TimeStepConsoleOutputs(currentTimestep, timeStepTimer);

            // Generate the file outputs for the current time step
            TimeStepFileOutputs(ecosystemModelGrid, cohortFunctionalGroupDefinitions, currentTimestep, marineCell, cellIndices,cellNumber);
        }
        /// <summary>
        /// Calculate the actual amount eaten in herbivory, apply the changes to the eaten autotroph stocks, and update deltas for the herbivore cohort
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in this grid cell</param>
        /// <param name="gridCellStocks">The stocks in this grid cell</param>
        /// <param name="actingCohort">The acting cohort</param>
        /// <param name="cellEnvironment">The environmental conditions in this grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks in the model</param>
        /// <param name="trackProcesses">An instance of ProcessTracker to hold diagnostics for herbivory</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail being used in this model run</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEating(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort, SortedList <string, double[]>
                              cellEnvironment, Dictionary <string, Dictionary <string, double> > deltas, FunctionalGroupDefinitions madingleyCohortDefinitions,
                              FunctionalGroupDefinitions madingleyStockDefinitions, ProcessTracker trackProcesses, uint currentTimestep, Boolean specificLocations,
                              string outputDetail, MadingleyModelInitialisation initialisation)
        {
            EdibleScaling = 1.0;
            if (cellEnvironment["Realm"][0] == 1.0)
            {
                EdibleScaling = 0.1;
            }

            // Loop over autotroph functional groups that can be eaten
            foreach (int FunctionalGroup in _FunctionalGroupIndicesToEat)
            {
                // Loop over stocks within the functional groups
                for (int i = 0; i < gridCellStocks[FunctionalGroup].Count; i++)
                {
                    // Get the mass from this stock that is available for eating (assumes only 10% is edible in the terrestrial realm)
                    EdibleMass = gridCellStocks[FunctionalGroup][i].TotalBiomass * EdibleScaling;

                    // Calculate the biomass actually eaten from this stock by the acting cohort
                    _BiomassesEaten[FunctionalGroup][i] = CalculateBiomassesEaten(_PotentialBiomassesEaten[FunctionalGroup][i],
                                                                                  _TimeUnitsToHandlePotentialFoodItems, gridCellCohorts[actingCohort].CohortAbundance, EdibleMass);

                    gridCellCohorts[actingCohort].TrophicIndex += _BiomassesEaten[FunctionalGroup][i];

                    // Remove the biomass eaten from the autotroph stock
                    gridCellStocks[FunctionalGroup][i].TotalBiomass -= _BiomassesEaten[FunctionalGroup][i];

                    // If the model is being run for specific locations and if track processes has been specified, then track the mass flow between
                    // primary producer and herbivore
                    if (specificLocations && trackProcesses.TrackProcesses)
                    {
                        trackProcesses.RecordHerbivoryMassFlow(currentTimestep, _BodyMassHerbivore, _BiomassesEaten[FunctionalGroup][i]);
                    }

                    // If track processes has been specified and the output detail level is set to high and the model is being run for specific locations,
                    // then track the flow of mass between trophic levels
                    if (trackProcesses.TrackProcesses && (outputDetail == "high") && specificLocations)
                    {
                        trackProcesses.TrackHerbivoryTrophicFlow((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                                                 gridCellCohorts[actingCohort].FunctionalGroupIndex, madingleyCohortDefinitions, _BiomassesEaten[FunctionalGroup][i], _BodyMassHerbivore, initialisation, cellEnvironment["Realm"][0] == 2.0);
                    }


                    // Check that the biomass eaten is not a negative value
                    // Commented out for purposes of speed
                    //Debug.Assert(_BiomassesEaten[FunctionalGroup][i] >= 0,
                    //    "Herbivory negative for this herbivore cohort" + actingCohort);

                    // Add the biomass eaten and assimilated by an individual to the delta biomass for the acting cohort
                    deltas["biomass"]["herbivory"] += _BiomassesEaten[FunctionalGroup][i] * AssimilationEfficiency / gridCellCohorts[actingCohort].CohortAbundance;

                    // Move the biomass eaten but not assimilated by an individual into the organic matter pool
                    deltas["organicpool"]["herbivory"] += _BiomassesEaten[FunctionalGroup][i] * (1 - AssimilationEfficiency);
                }

                // Check that the delta biomass from eating for the acting cohort is not negative
                // Commented out for the purposes of speed
                //Debug.Assert(deltas["biomass"]["herbivory"] >= 0, "Delta biomass from herbviory is negative");

                // Calculate the total biomass eaten by the acting (herbivore) cohort
                _TotalBiomassEatenByCohort = deltas["biomass"]["herbivory"] * gridCellCohorts[actingCohort].CohortAbundance;
            }
        }
        /// <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>
        /// Initialises herbivory implementation each time step
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <remarks>This only works if: a) herbivory is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips
        /// It is critical to run this every time step</remarks>
        public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, SortedList <string, double[]>
                                                cellEnvironment)
        {
            // Get the functional group indices of all autotroph stocks
            _FunctionalGroupIndicesToEat = madingleyStockDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "Autotroph", false);

            string[] realm = { "Terrestrial", "Marine" };

            int    realm_index   = (int)cellEnvironment["Realm"][0] - 1;
            string Current_realm = realm[realm_index];
        }
        /// <summary>
        /// Calculate the potential number of prey that could be gained through predation on each cohort in the grid cell
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The acting cohort</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="madingleyCohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks  in the model</param>
        public void GetEatingPotentialTerrestrial(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort,
            SortedList<string, double[]> cellEnvironment, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions
            madingleyStockDefinitions)
        {
            BinnedPreyDensities = new double[gridCellCohorts.Count, NumberOfBins];

            // Set the total eaten by the acting cohort to zero
            _TotalBiomassEatenByCohort = 0.0;

            // Set the total number of units to handle all potential prey individuals eaten to zero
            _TimeUnitsToHandlePotentialFoodItems = 0.0;

            // Get the individual body mass of the acting (predator) cohort
            _BodyMassPredator = gridCellCohorts[actingCohort].IndividualBodyMass;

            // Get the abundance of the acting (predator) cohort
            _AbundancePredator = gridCellCohorts[actingCohort].CohortAbundance;

            // Pre-calculate individual values for this predator
            _SpecificPredatorKillRateConstant = _KillRateConstant * Math.Pow(_BodyMassPredator, (_KillRateConstantMassExponent));
            _SpecificPredatorTimeUnitsEatingPerGlobalTimeStep = _DeltaT * _ProportionOfTimeEating;
            _PredatorAssimilationEfficiency = _AssimilationEfficiency;
            _PredatorNonAssimilation = (1 - _AssimilationEfficiency);

            // When body sizes are less than one gram, we have a flat handling time relationship to stop small things have extraordinarily short handling times
              //  if (_BodyMassPredator > 1.0)
              //  {
                _ReferenceMassRatioScalingTerrestrial = HandlingTimeScalarTerrestrial * Math.Pow(_ReferenceMass / _BodyMassPredator, _HandlingTimeExponentTerrestrial);
              //  }
              //  else
              //  {
              //      _ReferenceMassRatioScalingTerrestrial = HandlingTimeScalarTerrestrial * _ReferenceMass / _BodyMassPredator;

            //            }
                _PredatorAbundanceMultipliedByTimeEating = _AbundancePredator * _SpecificPredatorTimeUnitsEatingPerGlobalTimeStep;

                _PredatorLogOptimalPreyBodySizeRatio = gridCellCohorts[actingCohort[0]][actingCohort[1]].LogOptimalPreyBodySizeRatio;

            LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio = Math.Log(_BodyMassPredator) + _PredatorLogOptimalPreyBodySizeRatio;

            // Calculate the abundance of prey in each of the prey mass bins
            PopulateBinnedPreyAbundance(gridCellCohorts, actingCohort, FunctionalGroupIndicesToEat, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

            // Loop over potential prey functional groups
            foreach (int FunctionalGroup in FunctionalGroupIndicesToEat)
            {

                // Loop over cohorts within the functional group
                for (int i = 0; i < NumberCohortsPerFunctionalGroupNoNewCohorts[FunctionalGroup]; i++)
                {
                    // Get the body mass of individuals in this cohort
                    _BodyMassPrey = gridCellCohorts[FunctionalGroup][i].IndividualBodyMass;

                    // Get the bin number of this prey cohort
                    PreyMassBinNumber = GetBinNumber(_BodyMassPrey, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

                    // Check whether the prey cohort still exists in the model (i.e. body mass > 0)
                    if ((0 < PreyMassBinNumber) && (PreyMassBinNumber < NumberOfBins) && (_BodyMassPrey > 0))
                    {
                        // Calculate the potential abundance from this cohort eaten by the acting cohort
                        _PotentialAbundanceEaten[FunctionalGroup][i] = CalculateExpectedNumberKilledTerrestrial(
                            gridCellCohorts[FunctionalGroup][i].CohortAbundance, _BodyMassPrey, PreyMassBinNumber, FunctionalGroup,
                            _BodyMassPredator, _CarnivoreFunctionalGroups[FunctionalGroup], _OmnivoreFunctionalGroups[FunctionalGroup],
                            _OmnivoreFunctionalGroups[actingCohort[0]], _PredatorLogOptimalPreyBodySizeRatio);

                        // Add the time required to handle the potential abundance eaten from this cohort to the cumulative total for all cohorts
                        _TimeUnitsToHandlePotentialFoodItems += _PotentialAbundanceEaten[FunctionalGroup][i] *
                            CalculateHandlingTimeTerrestrial(_BodyMassPrey);
                    }
                    else
                    {
                        // Assign a potential abundance eaten of zero
                        _PotentialAbundanceEaten[FunctionalGroup][i] = 0.0;
                    }
                }
            }

            // No cannibalism; do this outside the loop to speed up the calculations
            _TimeUnitsToHandlePotentialFoodItems -= PotentialAbundanceEaten[actingCohort[0]][actingCohort[1]] *
                CalculateHandlingTimeTerrestrial(_BodyMassPredator);
            PotentialAbundanceEaten[actingCohort[0]][actingCohort[1]] = 0.0;
        }
        /// <summary>
        /// Apply the changes from predation to prey cohorts, and update deltas for the predator cohort
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The acting cohort</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="deltas">The sorted list to track changes in biomass and abundance of the acting cohort in this grid cell</param>
        /// <param name="madingleyCohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks in the model</param>
        /// <param name="trackProcesses">An instance of ProcessTracker to hold diagnostics for predation</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="outputDetail">The level of output detail used in this model run</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        public void RunEating(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort, SortedList<string, double[]>
            cellEnvironment, Dictionary<string, Dictionary<string, double>> deltas, FunctionalGroupDefinitions madingleyCohortDefinitions,
            FunctionalGroupDefinitions madingleyStockDefinitions, ProcessTracker trackProcesses, uint currentTimestep, Boolean specificLocations,
            string outputDetail, MadingleyModelInitialisation initialisation)
        {
            if (trackProcesses.TrackProcesses)
            {
                Track = (RandomNumberGenerator.GetUniform() > 0.975) ? true : false;
            }

            TempDouble = 0.0;

            // Temporary variable to hold the total time spent eating + 1. Saves an extra calculation in CalculateAbundanceEaten
            double TotalTimeUnitsToHandlePlusOne = TimeUnitsToHandlePotentialFoodItems + 1;

            // Loop over potential prey functional groups
            foreach (int FunctionalGroup in _FunctionalGroupIndicesToEat)
            {

                // Loop over cohorts within the functional group
                for (int i = 0; i < NumberCohortsPerFunctionalGroupNoNewCohorts[FunctionalGroup]; i++)
                {
                    // Get the individual body mass of this cohort
                    _BodyMassPrey = gridCellCohorts[FunctionalGroup][i].IndividualBodyMass;

                     // Calculate the actual abundance of prey eaten from this cohort
                    if (gridCellCohorts[FunctionalGroup][i].CohortAbundance > 0)
                    {

                     // Calculate the actual abundance of prey eaten from this cohort
                    _AbundancesEaten[FunctionalGroup][i] = CalculateAbundanceEaten(_PotentialAbundanceEaten[FunctionalGroup][i], _PredatorAbundanceMultipliedByTimeEating,
                        TotalTimeUnitsToHandlePlusOne, gridCellCohorts[FunctionalGroup][i].CohortAbundance);

                    }
                    else
                        _AbundancesEaten[FunctionalGroup][i] = 0;

                    // Remove number of prey eaten from the prey cohort
                    gridCellCohorts[FunctionalGroup][i].CohortAbundance -= _AbundancesEaten[FunctionalGroup][i];

                    gridCellCohorts[actingCohort].TrophicIndex += (_BodyMassPrey + gridCellCohorts[FunctionalGroup][i].IndividualReproductivePotentialMass) * _AbundancesEaten[FunctionalGroup][i] * gridCellCohorts[FunctionalGroup][i].TrophicIndex;

                    // If the process tracker is set and output detail is set to high and the prey cohort has never been merged,
                    // then track its mortality owing to predation
                    if (trackProcesses.TrackProcesses)
                    {
                        if ((outputDetail == "high") && (gridCellCohorts[FunctionalGroup][i].CohortID.Count == 1)
                        && AbundancesEaten[FunctionalGroup][i] > 0)
                        {
                            trackProcesses.RecordMortality((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], gridCellCohorts
                                [FunctionalGroup][i].BirthTimeStep, currentTimestep, gridCellCohorts[FunctionalGroup][i].IndividualBodyMass,
                                gridCellCohorts[FunctionalGroup][i].AdultMass, gridCellCohorts[FunctionalGroup][i].FunctionalGroupIndex,
                                gridCellCohorts[FunctionalGroup][i].CohortID[0], AbundancesEaten[FunctionalGroup][i], "predation");
                        }

                        // If the model is being run for specific locations and if track processes has been specified, then track the mass flow between
                        // prey and predator
                        if (specificLocations)
                        {
                            trackProcesses.RecordPredationMassFlow(currentTimestep, _BodyMassPrey, _BodyMassPredator, _BodyMassPrey *
                                _AbundancesEaten[FunctionalGroup][i]);

                        if (outputDetail == "high")
                            trackProcesses.TrackPredationTrophicFlow((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                gridCellCohorts[FunctionalGroup][i].FunctionalGroupIndex, gridCellCohorts[actingCohort].FunctionalGroupIndex,
                                madingleyCohortDefinitions, (_AbundancesEaten[FunctionalGroup][i] * _BodyMassPrey), _BodyMassPredator, _BodyMassPrey,
                                initialisation, cellEnvironment["Realm"][0] == 2.0);

                        }

                    }

                    // Check that the abundance eaten from this cohort is not negative
                    // Commented out for the purposes of speed
                    //Debug.Assert( _AbundancesEaten[FunctionalGroup][i].CompareTo(0.0) >= 0,
                    //     "Predation negative for this prey cohort" + actingCohort);

                    // Create a temporary value to speed up the predation function
                    // This is equivalent to the body mass of the prey cohort including reproductive potential mass, times the abundance eaten of the prey cohort,
                    // divided by the abundance of the predator
                    TempDouble += (_BodyMassPrey + gridCellCohorts[FunctionalGroup][i].IndividualReproductivePotentialMass) * _AbundancesEaten[FunctionalGroup][i] / _AbundancePredator;

                }
            }

            // Add the biomass eaten and assimilated by an individual to the delta biomass for the acting (predator) cohort
            deltas["biomass"]["predation"] = TempDouble * _PredatorAssimilationEfficiency;

            // Move the biomass eaten but not assimilated by an individual into the organic matter pool
            deltas["organicpool"]["predation"] = TempDouble * _PredatorNonAssimilation * _AbundancePredator;

            // Check that the delta biomass from eating for the acting cohort is not negative
            //Debug.Assert(deltas["biomass"]["predation"] >= 0, "Predation yields negative biomass");

            // Calculate the total biomass eaten by the acting (predator) cohort
            _TotalBiomassEatenByCohort = deltas["biomass"]["predation"] * _AbundancePredator;
        }
        /// <summary>
        /// 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 });
        }
Ejemplo n.º 41
0
        public static void ToJson(Newtonsoft.Json.JsonWriter jsonWriter, string name, FunctionalGroupDefinitions functionalGroupDefinitions)
        {
            jsonWriter.WritePropertyName(name);
            jsonWriter.WriteStartObject();

            Madingley.Serialization.Common.Writer.PropertyKeyValuePairs(jsonWriter, "IndexLookupFromTrait", functionalGroupDefinitions.IndexLookupFromTrait,
                                                                        (jw, key, value) =>
            {
                Madingley.Serialization.Common.Writer.PropertyInlineKeyValuePairs(jw, key, value,
                                                                                  (jw2, key2, value2) =>
                {
                    Madingley.Serialization.Common.Writer.PropertyArray(jw2, key2, value2, Madingley.Serialization.Common.Writer.WriteInt);
                });
            });

            Madingley.Serialization.Common.Writer.PropertyKeyValuePairs(jsonWriter, "FunctionalGroupProperties", functionalGroupDefinitions.FunctionalGroupProperties,
                                                                        (jw, key, value) =>
            {
                Madingley.Serialization.Common.Writer.PropertyInlineArray(jw, key, value, Madingley.Serialization.Common.Writer.WriteDouble);
            });

            Madingley.Serialization.Common.Writer.PropertyKeyValuePairs(jsonWriter, "TraitLookupFromIndex", functionalGroupDefinitions.IndexLookupFromTrait,
                                                                        (jw, key, value) =>
            {
                Madingley.Serialization.Common.Writer.PropertyInlineKeyValuePairs(jw, key, value,
                                                                                  (jw2, key2, value2) =>
                {
                    Madingley.Serialization.Common.Writer.PropertyArray(jw2, key2, value2, Madingley.Serialization.Common.Writer.WriteInt);
                });
            });

            Madingley.Serialization.Common.Writer.PropertyInlineArray(jsonWriter, "AllFunctionalGroupsIndex", functionalGroupDefinitions.AllFunctionalGroupsIndex, Madingley.Serialization.Common.Writer.WriteInt);

            jsonWriter.WriteEndObject();
        }
        /// <summary>
        /// Set up all outputs (live, console and file) prior to the model run
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid that output data will be derived from</param>
        /// <param name="cohortFunctionalGroupDefinitions">The definitions for cohort functional groups</param>
        /// <param name="stockFunctionalGroupDefinitions">The definitions for stock functional groups</param>
        /// <param name="numTimeSteps">The number of time steps in the model run</param>
        /// <param name="outputFilesSuffix">The suffix to be applied to all output files from the current model run</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="cellIndex">The number of the current grid cell in the list of indices of active cells</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        public void SetUpOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions,
            FunctionalGroupDefinitions stockFunctionalGroupDefinitions, uint numTimeSteps, string outputFilesSuffix, List<uint[]> cellIndices,
            int cellIndex, Boolean marineCell)
        {
            Console.WriteLine("Setting up grid cell outputs...\n");

            // Set the suffix for all output files
            _OutputSuffix = outputFilesSuffix + "_Cell" + cellIndex;

            // Create vector to hold the values of the time dimension
            TimeSteps = new float[numTimeSteps + 1];

            // Set the first value to be -1 (this will hold initial outputs)
            TimeSteps[0] = 0;

            // Fill other values from 0 (this will hold outputs during the model run)
            for (int i = 1; i < numTimeSteps + 1; i++)
            {
                TimeSteps[i] = i;
            }

            // Initialise the trait based outputs
            InitialiseTraitBasedOutputs(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, marineCell);

            // Setup low-level outputs
            SetUpLowLevelOutputs(numTimeSteps, ecosystemModelGrid);

            if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High))
            {
                // Setup medium-level outputs
                SetupMediumLevelOutputs(ecosystemModelGrid, marineCell);

                if (ModelOutputDetail == OutputDetailLevel.High)
                {
                    // Setup high-level outputs
                    SetUpHighLevelOutputs(ecosystemModelGrid, cellIndices,cellIndex, cohortFunctionalGroupDefinitions, marineCell);
                }
            }
        }
        /// <summary>
        /// Write to the output file values of the output variables before the first time step
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid to get data from</param>C:\madingley-ecosystem-model\Madingley\Output and tracking\PredationTracker.cs
        /// <param name="cohortFunctionalGroupDefinitions">The definitions of cohort functional groups in the model</param>
        /// <param name="stockFunctionalGroupDefinitions">The definitions of stock functional groups in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="cellNumber">The number of the current cell in the list of indices of active cells</param>
        /// <param name="globalDiagnosticVariables">List of global diagnostic variables</param>
        /// <param name="numTimeSteps">The number of time steps in the model run</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="month">The current month in the model run</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        public void InitialOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions,
            FunctionalGroupDefinitions stockFunctionalGroupDefinitions, List<uint[]> cellIndices, int cellNumber,
            SortedList<string, double> globalDiagnosticVariables, uint numTimeSteps, MadingleyModelInitialisation initialisation, 
            uint month, Boolean marineCell)
        {
            // Calculate values of the output variables to be used
            CalculateOutputs(ecosystemModelGrid, cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, cellIndices, cellNumber, globalDiagnosticVariables, initialisation, month, marineCell);

            // Generate the intial live outputs
            if (LiveOutputs)
            {
                InitialLiveOutputs(ecosystemModelGrid, marineCell);
            }
            // Generate the intial file outputs
            InitialFileOutputs(ecosystemModelGrid, cohortFunctionalGroupDefinitions, marineCell,cellIndices,cellNumber);
        }
        /// <summary>
        /// Write to the output file values of the output variables at the end of the model run
        /// </summary>
        /// <param name="EcosystemModelGrid">The model grid to get data from</param>
        /// <param name="CohortFunctionalGroupDefinitions">Definitions of the cohort functional groups in the model</param>
        /// <param name="StockFunctionalGroupDefinitions">Definitions of the stock functional groups in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="cellNumber">The number of the current cell in the list of indices of active cells</param>
        /// <param name="GlobalDiagnosticVariables">List of global diagnostic variables</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="month">The current month in the model run</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        public void FinalOutputs(ModelGrid EcosystemModelGrid, FunctionalGroupDefinitions CohortFunctionalGroupDefinitions, 
            FunctionalGroupDefinitions StockFunctionalGroupDefinitions, List<uint[]> cellIndices, int cellNumber, 
            SortedList<string, double> GlobalDiagnosticVariables, MadingleyModelInitialisation initialisation, uint month, Boolean marineCell)
        {
            // Calculate output variables
            CalculateOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, cellIndices,cellNumber, GlobalDiagnosticVariables, initialisation, month, marineCell);

            // Dispose of the dataset objects
            BasicOutputMemory.Clone("msds:nc?file="+ _OutputPath + "BasicOutputs" + _OutputSuffix + ".nc&openMode=create");
            BasicOutputMemory.Dispose();

            if (LiveOutputs)
            {
                DataSetToViewLive.Dispose();
            }

            if (ModelOutputDetail == OutputDetailLevel.High)
            {
                // Dispose of the dataset objects for high detail level outputs
                MassBinsOutputMemory.Clone("msds:nc?file="+ _OutputPath + "MassBinsOutputs" + _OutputSuffix + ".nc&openMode=create");
                MassBinsOutputMemory.Dispose();

                TrackedCohortsOutputMemory.Clone("msds:nc?file="+ _OutputPath + "TrackedCohortsOutputs" + _OutputSuffix + ".nc&openMode=create");
                TrackedCohortsOutputMemory.Dispose();

            }

            Metrics.CloseRserve();
        }
        /// <summary>
        /// Generate file outputs for the current time step
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="currentTimeStep">The current time step</param>
        /// <param name="MarineCell">Whether the current cell is a marine cell</param>
        /// <param name="cellIndices">The list of all cells to run the model for</param>
        /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param>
        private void TimeStepFileOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, 
            uint currentTimeStep, Boolean MarineCell, List<uint[]> cellIndices, int cellIndex)
        {
            Console.WriteLine("Writing grid cell ouputs to file...\n");
            //Write the low level outputs first
            DataConverter.ValueToSDS1D(TotalLivingBiomassDensity, "Total Biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, (int)currentTimeStep + 1);
            DataConverter.ValueToSDS1D(TotalHeterotrophAbundanceDensity, "Heterotroph Abundance density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, (int)currentTimeStep + 1);
            DataConverter.ValueToSDS1D(TotalHeterotrophBiomassDensity, "Heterotroph Biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, (int)currentTimeStep + 1);
            // File outputs for medium and high detail levels
            if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High))
            {
                if (MarineCell)
                {
                    // Loop over all cohort trait value combinations and output abundances, densities and biomasses
                    foreach (string TraitValue in CohortTraitIndicesMarine.Keys)
                    {
                        DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1);
                        DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1);
                    }

                    // Loop over all stock trait value combinations and output biomasses
                    foreach (string TraitValue in StockTraitIndicesMarine.Keys)
                    {
                        DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1);
                    }
                }
                else
                {
                    // Loop over all cohort trait value combinations and output abudnances, densities and biomasses
                    foreach (string TraitValue in CohortTraitIndices.Keys)
                    {
                        DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1);
                        DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1);
                    }

                    // Loop over all stock trait value combinations and output biomasses
                    foreach (string TraitValue in StockTraitIndices.Keys)
                    {
                        DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1);
                    }
                }

                // If ouputting ecosystem metrics has been specified then add these metrics to the output
                if (OutputMetrics)
                {
                    DataConverter.ValueToSDS1D(Metrics.CalculateMeanTrophicLevelCell(ecosystemModelGrid, cellIndices, cellIndex),
                                                "Mean Trophic Level", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid,cohortFunctionalGroupDefinitions, cellIndices, cellIndex,"trophic index"),
                                                "Trophic Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "biomass"),
                                                "Biomass Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                    double[] FunctionalDiversity = Metrics.CalculateFunctionalDiversity(ecosystemModelGrid, cohortFunctionalGroupDefinitions,
                        cellIndices, cellIndex);
                    DataConverter.ValueToSDS1D(FunctionalDiversity[0],
                                                 "Functional Richness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                 BasicOutputMemory, (int)currentTimeStep + 1);
                    DataConverter.ValueToSDS1D(FunctionalDiversity[1],
                                                "Rao Functional Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);

                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[0],
                                                "Biomass Richness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[1],
                                                "Min Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[2],
                                                "Max Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);

                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[0],
                                                "Trophic Richness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[1],
                                                "Min Trophic Index", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[2],
                                                "Max Trophic Index", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);

                    DataConverter.ValueToSDS1D(Metrics.CalculateArithmeticCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, cellIndex),
                                                "Arithmetic Mean Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                    DataConverter.ValueToSDS1D(Metrics.CalculateGeometricCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, cellIndex),
                                                "Geometric Mean Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, (int)currentTimeStep + 1);
                }

                if (TrackMarineSpecifics && MarineCell)
                {
                    DataConverter.ValueToSDS1D(TotalIncomingNPP, "Incoming NPP", "Time step", ecosystemModelGrid.GlobalMissingValue,
                        BasicOutputMemory, (int)currentTimeStep + 1);
                }

                if (currentTimeStep % 600 == 0 && currentTimeStep > 0)
                {
                    BasicOutputMemory.Clone("msds:nc?file=" + _OutputPath + "BasicOutputs" + _OutputSuffix + ".nc&openMode=create");
                    Console.WriteLine("Cloning grid cell ouputs to file...\n");
                }

                // File outputs for high detail level
                if (ModelOutputDetail == OutputDetailLevel.High)
                {

                    if (OutputMetrics)
                    {
                        DataConverter.VectorToSDS2D(Metrics.CalculateTrophicDistribution(ecosystemModelGrid,cellIndices,cellIndex), "Trophic Index Distribution",
                            new string[2] { "Time step", "Trophic Index Bins" }, TimeSteps, Metrics.TrophicIndexBinValues, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, (int)currentTimeStep + 1);
                    }

                    // Loop over trait combinations in the mass bin outputs
                    foreach (var TraitValue in AbundancesInMassBins.Keys)
                    {
                        // Write out abundances in each of the mass bins to the relevant two-dimensional output variables
                        DataConverter.VectorToSDS2D(AbundancesInMassBins[TraitValue], "Log " + TraitValue + " abundance in mass bins",
                            new string[2] { "Time step", "Mass bin" }, TimeSteps, MassBins, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, (int)currentTimeStep + 1);
                        DataConverter.VectorToSDS2D(BiomassesInMassBins[TraitValue], "Log " + TraitValue + " biomass in mass bins",
                            new string[2] { "Time step", "Mass bin" }, TimeSteps, MassBins, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, (int)currentTimeStep + 1);
                        // Write out abundances in combinations of juvenile and adult mass bins to the relevant three-dimensional output variable
                        DataConverter.Array2DToSDS3D(AbundancesInJuvenileAdultMassBins[TraitValue], "Log " + TraitValue + " abundance in juvenile vs adult bins",
                            new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" },
                            (int)currentTimeStep + 1,
                            ecosystemModelGrid.GlobalMissingValue,
                            MassBinsOutputMemory);
                        // Write out biomasses in combinations of juvenile and adult mass bins to the relevant three-dimensional output variable
                        DataConverter.Array2DToSDS3D(BiomassesInJuvenileAdultMassBins[TraitValue], "Log " + TraitValue + " biomass in juvenile vs adult bins",
                            new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" },
                            (int)currentTimeStep + 1,
                            ecosystemModelGrid.GlobalMissingValue,
                            MassBinsOutputMemory);
                    }

                    // Loop over tracked cohorts
                    for (int i = 0; i < TrackedCohorts.Count; i++)
                    {
                        // Add the individual body mass and abundance of the tracked cohort to the output dataset
                        string[] TrackedCohortDimensions = new string[] { "Time step", "Cohort ID" };
                        DataConverter.ValueToSDS2D(TrackedCohortIndividualMasses[i], "Individual body mass", TrackedCohortDimensions,
                            ecosystemModelGrid.GlobalMissingValue, TrackedCohortsOutputMemory, (int)currentTimeStep + 1, i);
                        DataConverter.ValueToSDS2D(TrackedCohortAbundances[i], "Number of individuals", TrackedCohortDimensions,
                            ecosystemModelGrid.GlobalMissingValue, TrackedCohortsOutputMemory, (int)currentTimeStep + 1, i);
                    }

                    if (currentTimeStep % 600 ==0 && currentTimeStep > 0)
                    {
                        MassBinsOutputMemory.Clone("msds:nc?file=" + _OutputPath + "MassBinsOutputs" + _OutputSuffix + ".nc&openMode=create");

                        TrackedCohortsOutputMemory.Clone("msds:nc?file=" + _OutputPath + "TrackedCohortsOutputs" + _OutputSuffix + ".nc&openMode=create");

                    }

                }

            }
        }
        /// <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>
 /// Initialises herbivory implementation each time step
 /// </summary>
 /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
 /// <param name="gridCellStocks">The stocks in the current grid cell</param>
 /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param>
 /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param>
 /// <remarks>This only works if: a) herbivory is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips
 /// It is critical to run this every time step</remarks>
 public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions)
 {
     // Get the functional group indices of all autotroph stocks
     _FunctionalGroupIndicesToEat = madingleyStockDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "Autotroph", false);
 }
        /// <summary>
        /// Calculate outputs associated with low-level outputs
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</param>
        /// <param name="cellIndices">The list of indices of active cells in the model grid</param>
        /// <param name="cellIndex">The position of the current cell in the list of active cells</param>
        /// <param name="globalDiagnosticVariables">The global diagnostic variables for this model run</param>
        /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions of cohorts in the model</param>
        /// <param name="stockFunctionalGroupDefinitions">The functional group definitions of stocks in the model</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="month">The current month in the model run</param>
        /// <param name="MarineCell">Whether the current cell is a marine cell</param>
        private void CalculateLowLevelOutputs(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex, 
            SortedList<string,double> globalDiagnosticVariables, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions,
            FunctionalGroupDefinitions stockFunctionalGroupDefinitions, MadingleyModelInitialisation initialisation, uint month, 
            Boolean MarineCell)
        {
            // Reset the total living biomass
            TotalLivingBiomass = 0.0;

            string[] Keys;

            if (MarineCell)
            {
                // Get the list of cohort trait combinations to consider
                Keys = CohortTraitIndicesMarine.Keys.ToArray();

                // Get biomass, abundance and densities for each of the trait combinations. Note that the GetStateVariableDensity function deals with the assessment of whether cohorts contain individuals
                // of low enough mass to be considered zooplankton in the marine realm
                foreach (string TraitValue in Keys)
                {
                    // Biomass density
                    TotalBiomassDensitiesOut[TraitValue] = ecosystemModelGrid.GetStateVariableDensity("Biomass", TraitValue, CohortTraitIndicesMarine[TraitValue], cellIndices[cellIndex][0], cellIndices[cellIndex][1], "cohort", initialisation) / 1000.0;

                    // Density
                    TotalDensitiesOut[TraitValue] = ecosystemModelGrid.GetStateVariableDensity("Abundance", TraitValue, CohortTraitIndicesMarine[TraitValue], cellIndices[cellIndex][0], cellIndices[cellIndex][1], "cohort", initialisation);
                }
            }
            else
            {
                // Get the list of cohort trait combinations to consider
                Keys = CohortTraitIndices.Keys.ToArray();

                // Get biomass, abundance and densities for each of the trait combinations
                foreach (string TraitValue in Keys)
                {
                    // Biomass density
                    TotalBiomassDensitiesOut[TraitValue] = ecosystemModelGrid.GetStateVariableDensity("Biomass", TraitValue, CohortTraitIndices[TraitValue], cellIndices[cellIndex][0], cellIndices[cellIndex][1], "cohort", initialisation) / 1000.0;

                    // Density
                    TotalDensitiesOut[TraitValue] = ecosystemModelGrid.GetStateVariableDensity("Abundance", TraitValue, CohortTraitIndices[TraitValue], cellIndices[cellIndex][0], cellIndices[cellIndex][1], "cohort", initialisation);
                }
            }

            // Add the total biomass of all cohorts to the total living biomass variable
            TotalLivingBiomass += ecosystemModelGrid.GetStateVariable("Biomass", "NA", cohortFunctionalGroupDefinitions.AllFunctionalGroupsIndex,
                cellIndices[cellIndex][0], cellIndices[cellIndex][1], "cohort", initialisation);
            TotalLivingBiomassDensity = ecosystemModelGrid.GetStateVariableDensity("Biomass", "NA", cohortFunctionalGroupDefinitions.AllFunctionalGroupsIndex, cellIndices[cellIndex][0], cellIndices[cellIndex][1], "cohort", initialisation) / 1000.0;
            TotalHeterotrophAbundanceDensity = ecosystemModelGrid.GetStateVariableDensity("Abundance", "NA", cohortFunctionalGroupDefinitions.AllFunctionalGroupsIndex, cellIndices[cellIndex][0], cellIndices[cellIndex][1], "cohort", initialisation);
            TotalHeterotrophBiomassDensity = TotalLivingBiomassDensity;

            if (MarineCell)
            {
                // Get the list of stock trait combinations to consider
                Keys = StockTraitIndicesMarine.Keys.ToArray();

                // Get biomass and biomass density for each of the trait combinations
                foreach (string TraitValue in Keys)
                {
                    // Density
                    TotalBiomassDensitiesOut[TraitValue] = ecosystemModelGrid.GetStateVariableDensity("Biomass", TraitValue, StockTraitIndicesMarine[TraitValue], cellIndices[cellIndex][0], cellIndices[cellIndex][1], "stock", initialisation) / 1000.0;
                }
            }
            else
            {
                // Get the list of stock trait combinations to consider
                Keys = StockTraitIndices.Keys.ToArray();

                // Get biomass and biomass density for each of the trait combinations
                foreach (string TraitValue in Keys)
                {
                    // Density
                    TotalBiomassDensitiesOut[TraitValue] = ecosystemModelGrid.GetStateVariableDensity("Biomass", TraitValue, StockTraitIndices[TraitValue], cellIndices[cellIndex][0], cellIndices[cellIndex][1], "stock", initialisation) / 1000.0;
                }
            }

            // Add the total biomass of all stocks to the total living biomass variable
            TotalLivingBiomass += ecosystemModelGrid.GetStateVariable("Biomass", "NA", stockFunctionalGroupDefinitions.AllFunctionalGroupsIndex,
                cellIndices[cellIndex][0], cellIndices[cellIndex][1], "stock", initialisation);
            TotalLivingBiomassDensity += ecosystemModelGrid.GetStateVariableDensity("Biomass", "NA", stockFunctionalGroupDefinitions.AllFunctionalGroupsIndex, cellIndices[cellIndex][0], cellIndices[cellIndex][1], "stock", initialisation) / 1000.0;

            if (TrackMarineSpecifics && MarineCell)
            {
                bool varExists;
                TotalIncomingNPP = ecosystemModelGrid.GetEnviroLayer("NPP", month, cellIndices[cellIndex][0], cellIndices[cellIndex][1], out varExists);
            }
        }
        /// <summary>
        /// Calculate the potential number of prey that could be gained through predation on each cohort in the grid cell
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingCohort">The acting cohort</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="madingleyCohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks  in the model</param>
        public void GetEatingPotentialMarine(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort, 
            SortedList<string, double[]> cellEnvironment, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions 
            madingleyStockDefinitions)
        {
            BinnedPreyDensities = new double[gridCellCohorts.Count, NumberOfBins];

            // Set the total eaten by the acting cohort to zero
            _TotalBiomassEatenByCohort = 0.0;

            // Set the total number of units to handle all potential prey individuals eaten to zero
            _TimeUnitsToHandlePotentialFoodItems = 0.0;

            // Get the individual body mass of the acting (predator) cohort
            _BodyMassPredator = gridCellCohorts[actingCohort].IndividualBodyMass;

            // Get the abundance of the acting (predator) cohort
            _AbundancePredator = gridCellCohorts[actingCohort].CohortAbundance;

            // Pre-calculate individual values for this predator to speed things up
            _SpecificPredatorKillRateConstant = _KillRateConstant * Math.Pow(_BodyMassPredator, (_KillRateConstantMassExponent));
            _SpecificPredatorTimeUnitsEatingPerGlobalTimeStep = _DeltaT * _ProportionOfTimeEating;
            _PredatorAssimilationEfficiency = _AssimilationEfficiency;
            _PredatorNonAssimilation = (1 - _AssimilationEfficiency);

            _DietIsAllSpecial = madingleyCohortDefinitions.GetTraitNames("Diet", actingCohort[0]) == "allspecial";

            _PredatorLogOptimalPreyBodySizeRatio = gridCellCohorts[actingCohort[0]][actingCohort[1]].LogOptimalPreyBodySizeRatio;

            // If a filter feeder, then optimal body size is a value not a ratio: convert it to a ratio to ensure that all calculations work correctly
            if (_DietIsAllSpecial)
            {
                // Optimal body size is actually a value, not a ratio, so convert it to a ratio based on the present body size
                _PredatorLogOptimalPreyBodySizeRatio = Math.Log(
                    Math.Exp(gridCellCohorts[actingCohort[0]][actingCohort[1]].LogOptimalPreyBodySizeRatio) / gridCellCohorts[actingCohort[0]][actingCohort[1]].IndividualBodyMass);
            }

            // Calculate the reference mass scaling ratio
            _ReferenceMassRatioScalingMarine = HandlingTimeScalarMarine * Math.Pow(_ReferenceMass / _BodyMassPredator, _HandlingTimeExponentMarine);

            _PredatorAbundanceMultipliedByTimeEating = _AbundancePredator * _SpecificPredatorTimeUnitsEatingPerGlobalTimeStep;

            LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio = Math.Log(_BodyMassPredator) + _PredatorLogOptimalPreyBodySizeRatio;

            // Calculate the abundance of prey in each of the prey mass bins
            PopulateBinnedPreyAbundance(gridCellCohorts, actingCohort, FunctionalGroupIndicesToEat, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

            // Loop over potential prey functional groups
            foreach (int FunctionalGroup in FunctionalGroupIndicesToEat)
            {
                // Eating operates differently for planktivores
                // This can certainly be sped up
                if (_DietIsAllSpecial)
                {
                    // Loop over cohorts within the functional group
                    for (int i = 0; i < NumberCohortsPerFunctionalGroupNoNewCohorts[FunctionalGroup]; i++)
                    {
                        // Get the body mass of individuals in this cohort
                        _BodyMassPrey = gridCellCohorts[FunctionalGroup][i].IndividualBodyMass;

                        // Get the bin number of this prey cohort
                        PreyMassBinNumber = GetBinNumber(_BodyMassPrey, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

                        // Check whether
                        // The prey cohort is within the feeding range of the predator
                        // the prey cohort still exists in the model (i.e. body mass > 0)
                        // Currently having whales etc eat everything, but preferentially feed on very small things (i.e. filter feeders)
                    if ((_PlanktonFunctionalGroups[FunctionalGroup]) && (0 < PreyMassBinNumber) &&
                        (PreyMassBinNumber < NumberOfBins) && (_BodyMassPrey > 0))
                        {
                            // Calculate the potential abundance from this cohort eaten by the acting cohort
                            _PotentialAbundanceEaten[FunctionalGroup][i] = CalculateExpectedNumberKilledMarine(
                                gridCellCohorts[FunctionalGroup][i].CohortAbundance, _BodyMassPrey, PreyMassBinNumber, FunctionalGroup,
                                _BodyMassPredator, _CarnivoreFunctionalGroups[FunctionalGroup], _OmnivoreFunctionalGroups[FunctionalGroup],
                                _OmnivoreFunctionalGroups[actingCohort[0]], _PredatorLogOptimalPreyBodySizeRatio);

                            // Add the time required to handle the potential abundance eaten from this cohort to the cumulative total for all cohorts
                            _TimeUnitsToHandlePotentialFoodItems += _PotentialAbundanceEaten[FunctionalGroup][i] *
                                CalculateHandlingTimeMarine(_BodyMassPrey);
                        }
                        else
                        {
                            // Assign a potential abundance eaten of zero
                            _PotentialAbundanceEaten[FunctionalGroup][i] = 0.0;
                        }
                    }
                }
                else
                {

                    // Loop over cohorts within the functional group
                    for (int i = 0; i < NumberCohortsPerFunctionalGroupNoNewCohorts[FunctionalGroup]; i++)
                    {
                        // Get the body mass of individuals in this cohort
                        _BodyMassPrey = gridCellCohorts[FunctionalGroup][i].IndividualBodyMass;

                        // Get the bin number of this prey cohort
                        PreyMassBinNumber = GetBinNumber(_BodyMassPrey, LogPredatorMassPlusPredatorLogOptimalPreyBodySizeRatio);

                        // Check whether
                        // The prey cohort is within the feeding range of the predator
                        // the prey cohort still exists in the model (i.e. body mass > 0)
                        if ((0 < PreyMassBinNumber) && (PreyMassBinNumber < NumberOfBins) && (_BodyMassPrey > 0))
                        {
                            // Calculate the potential abundance from this cohort eaten by the acting cohort
                            _PotentialAbundanceEaten[FunctionalGroup][i] = CalculateExpectedNumberKilledMarine(
                               gridCellCohorts[FunctionalGroup][i].CohortAbundance, _BodyMassPrey, PreyMassBinNumber, FunctionalGroup,
                               _BodyMassPredator, _CarnivoreFunctionalGroups[FunctionalGroup], _OmnivoreFunctionalGroups[FunctionalGroup],
                               _OmnivoreFunctionalGroups[actingCohort[0]], _PredatorLogOptimalPreyBodySizeRatio);

                            // Add the time required to handle the potential abundance eaten from this cohort to the cumulative total for all cohorts
                            _TimeUnitsToHandlePotentialFoodItems += _PotentialAbundanceEaten[FunctionalGroup][i] *
                                CalculateHandlingTimeMarine(_BodyMassPrey);
                        }
                        else
                        {
                            // Assign a potential abundance eaten of zero
                            _PotentialAbundanceEaten[FunctionalGroup][i] = 0.0;
                        }
                    }
                }

            }

            // No cannibalism; do this outside the loop to speed up the calculations
            _TimeUnitsToHandlePotentialFoodItems -= PotentialAbundanceEaten[actingCohort[0]][actingCohort[1]] *
                CalculateHandlingTimeMarine(_BodyMassPredator);
            PotentialAbundanceEaten[actingCohort[0]][actingCohort[1]] = 0.0;
        }
        /// <summary>
        /// Calculates the variables to output
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid to get output data from</param>
        /// <param name="cohortFunctionalGroupDefinitions">Definitions of the cohort functional groups in the model</param>
        /// <param name="stockFunctionalGroupDefinitions">Definitions of the stock functional groups in the model</param>
        /// <param name="cellIndices">List of indices of active cells in the model grid</param>
        /// <param name="cellNumber">The number of the current cell in the list of indices of active cells</param>
        /// <param name="globalDiagnosticVariables">The sorted list of global diagnostic variables in the model</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="month">The current month in the model run</param>
        /// <param name="marineCell">Whether the current cell is a marine cell</param>
        private void CalculateOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions,
            FunctionalGroupDefinitions stockFunctionalGroupDefinitions, List<uint[]> cellIndices, int cellNumber, SortedList<string, double>
            globalDiagnosticVariables, MadingleyModelInitialisation initialisation, uint month, Boolean marineCell)
        {
            // Calculate low-level outputs
            CalculateLowLevelOutputs(ecosystemModelGrid, cellIndices, cellNumber, globalDiagnosticVariables, cohortFunctionalGroupDefinitions,
                stockFunctionalGroupDefinitions, initialisation, month, marineCell);

            if (ModelOutputDetail == OutputDetailLevel.High)
            {
                // Calculate high-level outputs
                CalculateHighLevelOutputs(ecosystemModelGrid, cellIndices, cellNumber, marineCell);
            }
        }
        /// <summary>
        /// Initialises predation implementation each time step
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param>
        /// <remarks>This only works if: a) predation is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips
        /// It is critical to run this every time step</remarks>
        public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions)
        {
            // Get the functional group indices of all heterotroph cohorts (i.e. potential prey)
            _FunctionalGroupIndicesToEat = madingleyCohortDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "heterotroph", false);

            // Initialise the vector to hold the number of cohorts in each functional group at the start of the time step
            NumberCohortsPerFunctionalGroupNoNewCohorts = new int[gridCellCohorts.Count];

            // Initialise the jagged arrays to hold the potential and actual numbers of prey eaten in each of the grid cell cohorts
            _AbundancesEaten = new double[gridCellCohorts.Count][];
            _PotentialAbundanceEaten = new double[gridCellCohorts.Count][];

            // Initialise the vector to identify carnivore cohorts
            _CarnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length];
            _OmnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length];
            _PlanktonFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length];

            // Loop over rows in the jagged arrays, initialise each vector within the jagged arrays, and calculate the current number of cohorts in
            // each functional group
            for (int i = 0; i < gridCellCohorts.Count; i++)
            {
                // Calculate the current number of cohorts in this functional group
                int NumCohortsThisFG = gridCellCohorts[i].Count;
                NumberCohortsPerFunctionalGroupNoNewCohorts[i] = NumCohortsThisFG;
                // Initialise the jagged arrays
                _AbundancesEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]];
                _PotentialAbundanceEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]];
            }

            // Loop over functional groups that are potential prey and determine which are carnivores
            foreach (int FunctionalGroup in FunctionalGroupIndicesToEat)
                _CarnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "carnivore";

            foreach (int FunctionalGroup in FunctionalGroupIndicesToEat)
                _OmnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "omnivore";

            foreach (int FunctionalGroup in FunctionalGroupIndicesToEat)
                _PlanktonFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Mobility", FunctionalGroup) == "planktonic";
        }
        /// <summary>
        /// Generates the initial file outputs
        /// </summary>
        /// <param name="ecosystemModelGrid">The model grid</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>
        /// <param name="cellIndices">The list of all cells to run the model for</param>
        /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param>
        private void InitialFileOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, 
            Boolean MarineCell, List<uint[]> cellIndices, int cellIndex)
        {
            Console.WriteLine("Writing initial grid cell outputs to memory...");

            //Write the low level outputs first
            DataConverter.ValueToSDS1D(TotalLivingBiomassDensity, "Total Biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, 0);
            DataConverter.ValueToSDS1D(TotalHeterotrophAbundanceDensity, "Heterotroph Abundance density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, 0);
            DataConverter.ValueToSDS1D(TotalHeterotrophBiomassDensity, "Heterotroph Biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, 0);

            // File outputs for medium and high detail levels
            if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High))
            {

                if (MarineCell)
                {
                    foreach (string TraitValue in CohortTraitIndicesMarine.Keys)
                    {
                        // Write densities, biomasses and abundances in different functional groups to the relevant one-dimensional output variables
                        DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, 0);
                        DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, 0);
                    }

                    foreach (string TraitValue in StockTraitIndicesMarine.Keys)
                    {
                        DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                        BasicOutputMemory, 0);
                    }
                }
                else
                {
                    foreach (string TraitValue in CohortTraitIndices.Keys)
                    {
                        // Write densities, biomasses and abundances in different functional groups to the relevant one-dimensional output variables
                        DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, 0);
                        DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step",
                            ecosystemModelGrid.GlobalMissingValue,
                            BasicOutputMemory, 0);
                    }

                    foreach (string TraitValue in StockTraitIndices.Keys)
                    {
                        DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step",
                           ecosystemModelGrid.GlobalMissingValue,
                        BasicOutputMemory, 0);
                    }
                }

                if (OutputMetrics)
                {
                    DataConverter.ValueToSDS1D(Metrics.CalculateMeanTrophicLevelCell(ecosystemModelGrid,cellIndices,cellIndex),
                                                "Mean Trophic Level", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid, cohortFunctionalGroupDefinitions,cellIndices, cellIndex,"trophic index"),
                                                "Trophic Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "biomass"),
                                                "Biomass Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);

                    double[] FunctionalDiversity = Metrics.CalculateFunctionalDiversity(ecosystemModelGrid, cohortFunctionalGroupDefinitions,
                        cellIndices, cellIndex);

                    DataConverter.ValueToSDS1D(FunctionalDiversity[0],
                                                 "Functional Richness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                 BasicOutputMemory, 0);
                    DataConverter.ValueToSDS1D(FunctionalDiversity[1],
                                                "Rao Functional Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);

                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[0],
                                                "Biomass Richness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[1],
                                                "Min Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[2],
                                                "Max Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);

                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[0],
                                                "Trophic Richness", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[1],
                                                "Min Trophic Index", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);
                    DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[2],
                                                "Max Trophic Index", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);

                    DataConverter.ValueToSDS1D(Metrics.CalculateArithmeticCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, cellIndex),
                                                "Arithmetic Mean Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);
                    DataConverter.ValueToSDS1D(Metrics.CalculateGeometricCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, cellIndex),
                                                "Geometric Mean Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue,
                                                BasicOutputMemory, 0);

                }

                if (MarineCell && TrackMarineSpecifics)
                {
                    DataConverter.ValueToSDS1D(TotalIncomingNPP, "Incoming NPP", "Time step", ecosystemModelGrid.GlobalMissingValue,
                        BasicOutputMemory, 0);
                }

                // File outputs for high detail level
                if (ModelOutputDetail == OutputDetailLevel.High)
                {
                    if (OutputMetrics)
                    {
                        DataConverter.VectorToSDS2D(Metrics.CalculateTrophicDistribution(ecosystemModelGrid,cellIndices,cellIndex), "Trophic Index Distribution",
                        new string[2] { "Time step", "Trophic Index Bins" }, TimeSteps, Metrics.TrophicIndexBinValues, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, 0);
                    }

                    foreach (var TraitValue in AbundancesInMassBins.Keys)
                    {
                        DataConverter.VectorToSDS2D(AbundancesInMassBins[TraitValue], "Log " + TraitValue + " abundance in mass bins",
                        new string[2] { "Time step", "Mass bin" }, TimeSteps, MassBins, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, 0);
                        DataConverter.VectorToSDS2D(BiomassesInMassBins[TraitValue], "Log " + TraitValue + " biomass in mass bins",
                        new string[2] { "Time step", "Mass bin" }, TimeSteps, MassBins, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, 0);
                        // Write out abundances in combinations of juvenile and adult mass bins to the relevant three-dimensional output variables
                        DataConverter.Array2DToSDS3D(AbundancesInJuvenileAdultMassBins[TraitValue],
                            "Log " + TraitValue + " abundance in juvenile vs adult bins",
                            new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" },
                            0,
                            ecosystemModelGrid.GlobalMissingValue,
                            MassBinsOutputMemory);
                        DataConverter.Array2DToSDS3D(BiomassesInJuvenileAdultMassBins[TraitValue],
                            "Log " + TraitValue + " biomass in juvenile vs adult bins",
                            new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" },
                            0,
                            ecosystemModelGrid.GlobalMissingValue,
                            MassBinsOutputMemory);
                    }

                    // Write outputs for tracking individual cohorts

                    // Loop over tracked cohorts
                    for (int i = 0; i < TrackedCohorts.Count; i++)
                    {
                        // Add the individual body mass of the tracked cohort to the output dataset
                        string[] TrackedCohortDimensions = new string[] { "Time step", "Cohort ID" };
                        DataConverter.ValueToSDS2D(TrackedCohortIndividualMasses[i], "Individual body mass", TrackedCohortDimensions,
                            ecosystemModelGrid.GlobalMissingValue, TrackedCohortsOutputMemory, 0, i);
                        DataConverter.ValueToSDS2D(TrackedCohortAbundances[i], "Number of individuals", TrackedCohortDimensions,
                            ecosystemModelGrid.GlobalMissingValue, TrackedCohortsOutputMemory, 0, i);
                    }

                }

            }
        }
        /// <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};
        }
Ejemplo n.º 54
0
        /// <summary>
        /// Remove individuals lost from cohorts through direct harvesting of animals
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the current grid cell</param>
        /// <param name="harvestingScenario">The scenario of direct harvesting of animals to apply</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="burninSteps">The number of time steps to spin the model up for before applying the harvesting scenario</param>
        /// <param name="impactSteps">The number of time steps to apply the scenario for</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="impactCell">The index of the cell, within the list of all cells to run, to apply the scenario for</param>
        public void RemoveHarvestedIndividuals(GridCellCohortHandler gridCellCohorts,
            Madingley.Common.ScenarioParameter harvestingScenario, uint currentTimestep, uint burninSteps, uint impactSteps, uint totalSteps,
            SortedList<string, double[]> cellEnvironment, Boolean impactCell, string globalModelTimestepUnits, FunctionalGroupDefinitions cohortFGs)
        {
            if (impactCell)
            {

                //If this is marine cell
                if (cellEnvironment["Realm"][0] == 2.0)
                {
                    if (harvestingScenario.ParamString == "no")
                    {
                        // Do not apply any harvesting
                    }
                    else if (harvestingScenario.ParamString == "constant")
                    {
                        double TargetBiomass;
                        if (FisheriesCatch != null)
                        {
                            TargetBiomass = (1000 *
                            FisheriesCatch.ModelGridCatchTotal[Convert.ToInt32(cellEnvironment["LatIndex"][0]), Convert.ToInt32(cellEnvironment["LonIndex"][0])])
                            / 12.0;
                        }
                        else
                        {
                            TargetBiomass = harvestingScenario.ParamDouble1;
                        }
                        // If the burn-in period has been completed, then apply
                        // the harvesting scenario
                        if (currentTimestep > burninSteps)
                        {
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment, currentTimestep);
                        }
                    }
                    else if (harvestingScenario.ParamString == "fish-catch")
                    {
                        //Initialise an instance of ApplyFishingCatches for this cell
                        if (currentTimestep == burninSteps)
                            ApplyCatches[Convert.ToInt32(cellEnvironment["LatIndex"][0]),
                            Convert.ToInt32(cellEnvironment["LonIndex"][0])] = new ApplyFishingCatches(FisheriesCatch);

                        if (currentTimestep > burninSteps)
                        {
                            //Bin the cohorts of the current cell
                            ApplyCatches[Convert.ToInt32(cellEnvironment["LatIndex"][0]),
                            Convert.ToInt32(cellEnvironment["LonIndex"][0])].BinCohorts(gridCellCohorts, FisheriesCatch, cohortFGs);
                            //Now remove the catch
                            ApplyCatches[Convert.ToInt32(cellEnvironment["LatIndex"][0]),
                            Convert.ToInt32(cellEnvironment["LonIndex"][0])].ApplyCatches(gridCellCohorts, FisheriesCatch,
                                Convert.ToInt32(cellEnvironment["LatIndex"][0]),
                                Convert.ToInt32(cellEnvironment["LonIndex"][0]));
                        }
                    }

                }
                else
                {

                    if (harvestingScenario.ParamString == "no")
                    {
                        // Do not apply any harvesting
                    }
                    else if (harvestingScenario.ParamString == "constant")
                    {
                        // If the burn-in period has been completed, then apply
                        // the harvesting scenario
                        if (currentTimestep > burninSteps)
                        {
                            ApplyHarvesting(gridCellCohorts, harvestingScenario.ParamDouble1, cellEnvironment, currentTimestep);
                        }
                    }
                    else if (harvestingScenario.ParamString == "temporary")
                    {
                        // If the burn-in period has been completed and the period of impact has not elapsed,
                        // then apply the harvesting scenario
                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + impactSteps)))
                        {
                            ApplyHarvesting(gridCellCohorts, harvestingScenario.ParamDouble1, cellEnvironment, currentTimestep);
                        }
                    }
                    else if (harvestingScenario.ParamString == "escalating")
                    {
                        // If the spin-up period has been completed, then apply a level of harvesting
                        // according to the number of time-steps that have elapsed since the spin-up ended
                        if (currentTimestep > burninSteps)
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(50000, (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.ParamDouble1)));

                            // Apply the harvesting scenario using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment, currentTimestep);
                        }

                    }
                    else if (harvestingScenario.ParamString == "temp-escalating-declining")
                    {
                        // If the spin-up period has been completed, then apply a level of harvesting
                        // according to the number of time-steps that have elapsed since the spin-up ended
                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + impactSteps)))
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(50000, (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.ParamDouble1)));

                            // Apply the harvesting scenario using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment, currentTimestep);
                        }
                        else if (currentTimestep > (burninSteps + impactSteps))
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(50000, ((-(totalSteps - currentTimestep) / 12.0) * harvestingScenario.ParamDouble1)));

                            // Apply the harvesting scenario using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment, currentTimestep);
                        }

                    }
                    else if (harvestingScenario.ParamString == "temp-escalating")
                    {
                        // If the spin-up period has been completed and the period of impact has not elapsed,
                        // then remove a proportion of plant matter
                        // according to the number of time-steps that have elapsed since the spin-up ended
                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + impactSteps)))
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(50000, (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.ParamDouble1)));

                            // Apply the harvesting scenarion using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment, currentTimestep);
                        }
                    }
                    else if (harvestingScenario.ParamString == "temp-escalating-const-rate")
                    {
                        // If the spin-up period has been completed and the period of impact (specified by the third scenario element
                        // has not elapsed,
                        // then remove a portion of  plant matter
                        // according to the number of time-steps that have elapsed since the spin-up ended

                        int ConstImpactSteps = Convert.ToInt32(harvestingScenario.ParamDouble2 * Utilities.ConvertTimeUnits("year", globalModelTimestepUnits));

                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + ConstImpactSteps)))
                        {
                            // Calculate the target biomass for harvesting based on the number of time steps that have elapsed since the spin-up
                            double TargetBiomass = (Math.Min(200000, (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.ParamDouble1)));

                            // Apply the harvesting scenarion using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment, currentTimestep);
                        }
                    }
                    else if (harvestingScenario.ParamString == "temp-escalating-const-rate-duration")
                    {
                        // If the spin-up period has been completed and the period of impact (specified by the third scenario element
                        // has not elapsed,
                        // then remove a proportion of plant matter
                        // according to the number of time-steps that have elapsed since the spin-up ended

                        int ConstImpactSteps = Convert.ToInt32(harvestingScenario.ParamDouble2 * Utilities.ConvertTimeUnits("year", globalModelTimestepUnits));

                        if ((currentTimestep > burninSteps) && (currentTimestep <= (burninSteps + impactSteps)))
                        {
                            //gridCellStocks[actingStock].TotalBiomass -= gridCellStocks[actingStock].TotalBiomass *
                            //    (Math.Min(1.0, (((currentTimestep - burninSteps) / 12.0) * humanNPPScenario.Item2)));

                            double TargetBiomass = (Math.Min(200000,
                                            Math.Min(((ConstImpactSteps / 12.0) * harvestingScenario.ParamDouble1),
                                            (((currentTimestep - burninSteps) / 12.0) * harvestingScenario.ParamDouble1))));

                            // Apply the harvesting scenarion using the calculated target biomass
                            ApplyHarvesting(gridCellCohorts, TargetBiomass, cellEnvironment, currentTimestep);
                        }
                    }
                    else
                    {
                        Debug.Fail("There is no method for the harvesting scenario specified");
                    }

                }
            }
        }
        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>
        /// Assigns the properties of the current model run
        /// </summary>
        /// <param name="initialisation">An instance of the model initialisation class</param> 
        /// <param name="scenarioParameters">The parameters for the scenarios to run</param>
        /// <param name="scenarioIndex">The index of the scenario that this model is to run</param>
        /// <param name="outputFilesSuffix">The suffix to be applied to all outputs from this model run</param>
        public void AssignModelRunProperties(MadingleyModelInitialisation initialisation, 
            ScenarioParameterInitialisation scenarioParameters, int scenarioIndex,
            string outputFilesSuffix)
        {
            // Assign the properties of this model run from the same properties in the specified model initialisation
            _GlobalModelTimeStepUnit = initialisation.GlobalModelTimeStepUnit;
            NumTimeSteps = initialisation.NumTimeSteps;
            NumBurninSteps = initialisation.BurninTimeSteps;
            NumImpactSteps = initialisation.ImpactTimeSteps;
            NumRecoverySteps = initialisation.RecoveryTimeSteps;
            CellSize = (float)initialisation.CellSize;
            _CellList = initialisation.CellList;
            BottomLatitude = initialisation.BottomLatitude;
            TopLatitude = initialisation.TopLatitude;
            LeftmostLongitude = initialisation.LeftmostLongitude;
            RightmostLongitude = initialisation.RightmostLongitude;
            RunGridCellsInParallel = initialisation.RunCellsInParallel;
            DrawRandomly = initialisation.DrawRandomly;
            _ExtinctionThreshold = initialisation.ExtinctionThreshold;
            MergeDifference = initialisation.MergeDifference;
            InitialisationFileStrings = initialisation.InitialisationFileStrings;
            CohortFunctionalGroupDefinitions = initialisation.CohortFunctionalGroupDefinitions;
            StockFunctionalGroupDefinitions = initialisation.StockFunctionalGroupDefinitions;
            EnviroStack = initialisation.EnviroStack;
            _HumanNPPScenario = scenarioParameters.scenarioParameters.ElementAt(scenarioIndex).Item3["npp"];
            _TemperatureScenario = scenarioParameters.scenarioParameters.ElementAt(scenarioIndex).Item3["temperature"];
            _HarvestingScenario = scenarioParameters.scenarioParameters.ElementAt(scenarioIndex).Item3["harvesting"];
            OutputFilesSuffix = outputFilesSuffix;
            EnvironmentalDataUnits = initialisation.Units;
            OutputModelStateTimestep = initialisation.OutputStateTimestep;
            SpecificLocations = initialisation.SpecificLocations;

            // Initialise the cohort ID to zero
            NextCohortID = 0;
        }
        /// <summary>
        /// Calculate the potential biomass that could be gained through herbivory on each grid cell autotroph stock
        /// </summary>
        /// <param name="gridCellCohorts">The cohorts in the grid cell</param>
        /// <param name="gridCellStocks">The stocks in the grid cell</param>
        /// <param name="actingCohort">The acting cohort</param>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="madingleyCohortDefinitions">The functional group definitions for cohorts in the model</param>
        /// <param name="madingleyStockDefinitions">The functional group definitions for stocks  in the model</param>
        public void GetEatingPotentialMarine(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, int[] actingCohort, SortedList <string, double[]> cellEnvironment, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions)
        {
            // Set the total biomass eaten by the acting cohort to zero
            _TotalBiomassEatenByCohort = 0.0;

            // Get the individual body mass of the acting cohort
            _BodyMassHerbivore = gridCellCohorts[actingCohort].IndividualBodyMass;

            // Set the total number of units to handle all potential biomass eaten to zero
            _TimeUnitsToHandlePotentialFoodItems = 0.0;

            // Initialise the jagged arrays to hold the potential and actual biomass eaten in each of the grid cell autotroph stocks
            _BiomassesEaten          = new double[gridCellStocks.Count][];
            _PotentialBiomassesEaten = new double[gridCellStocks.Count][];

            // Loop over rows in the jagged arrays and initialise each vector
            for (int i = 0; i < gridCellStocks.Count; i++)
            {
                _BiomassesEaten[i]          = new double[gridCellStocks[i].Count];
                _PotentialBiomassesEaten[i] = new double[gridCellStocks[i].Count];
            }

            // Loop over functional groups that can be eaten
            foreach (int FunctionalGroup in _FunctionalGroupIndicesToEat)
            {
                // Loop over stocks within the functional group
                for (int i = 0; i < gridCellStocks[FunctionalGroup].Count; i++)
                {
                    // Get the mass from this stock that is available for eating (assumes all marine autotrophic organisms are edible)
                    //EdibleMass = gridCellStocks[FunctionalGroup][i].TotalBiomass * 0.1;
                    EdibleMass = gridCellStocks[FunctionalGroup][i].TotalBiomass;

                    // Calculate the potential biomass eaten from this stock by the acting cohort
                    _PotentialBiomassesEaten[FunctionalGroup][i] = CalculatePotentialBiomassEatenMarine(EdibleMass, _BodyMassHerbivore);

                    // Add the time required to handle the potential biomass eaten from this stock to the cumulative total for all stocks
                    _TimeUnitsToHandlePotentialFoodItems += _PotentialBiomassesEaten[FunctionalGroup][i] *
                                                            CalculateHandlingTimeMarine(_BodyMassHerbivore);
                }
            }
        }
        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);
        }
Ejemplo n.º 59
0
 /// <summary>
 /// Overloaded constructor for model grid to construct the grid for specific locations
 /// </summary>
 /// <param name="minLat">Minimum grid latitude (degrees)</param>
 /// <param name="minLon">Minimum grid longitude (degrees, currently -180 to 180)</param>
 /// <param name="maxLat">Maximum grid latitude (degrees)</param>
 /// <param name="maxLon">Maximum grid longitude (degrees, currently -180 to 180)</param>
 /// <param name="latCellSize">Latitudinal size of grid cells</param>
 /// <param name="lonCellSize">Longitudinal size of grid cells</param>
 /// <param name="cellList">List of indices of active cells in the model grid</param>
 /// <param name="cohortFunctionalGroups">The functional group definitions for cohorts in the model</param>
 /// <param name="stockFunctionalGroups">The functional group definitions for stocks in the model</param>
 /// <param name="globalDiagnostics">Global diagnostic variables</param>
 /// <param name="tracking">Whether process tracking is enabled</param>
 /// <param name="specificLocations">Whether the model is to be run for specific locations</param>
 /// <param name="runInParallel">Whether model grid cells will be run in parallel</param>
 public ModelGrid(float minLat, float minLon, float maxLat, float maxLon, float latCellSize, float lonCellSize, List <uint[]> cellList,
                  FunctionalGroupDefinitions cohortFunctionalGroups,
                  FunctionalGroupDefinitions stockFunctionalGroups, SortedList <string, double> globalDiagnostics, Boolean tracking,
                  Boolean specificLocations, Boolean runInParallel)
Ejemplo n.º 60
0
        /// <summary>
        /// Record the flow of biomass between trophic levels during predation
        /// </summary>
        /// <param name="latIndex">The latitudinal index of the current grid cell</param>
        /// <param name="lonIndex">The longitudinal index of the current grid cell</param>
        /// <param name="fromFunctionalGroup">The index of the functional group that the biomass is flowing from (i.e. the prey)</param>
        /// <param name="toFunctionalGroup">The index of the functional group that the biomass is flowing to (i.e. the predator)</param>
        /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions of cohorts in the model</param>
        /// <param name="massEaten">The total biomass eaten by the predator cohort</param>
        /// <param name="predatorBodyMass">The body mass of the predator doing the eating</param>
        /// <param name="preyBodyMass">The body mass of the prey being eaten</param>
        /// <param name="initialisation">The Madingley Model initialisation</param>
        /// <param name="MarineCell">Whether the current cell is a marine cell</param>
        public void RecordPredationTrophicFlow(uint latIndex, uint lonIndex, int fromFunctionalGroup, int toFunctionalGroup,
                                               FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, double massEaten, double predatorBodyMass, double preyBodyMass,
                                               MadingleyModelInitialisation initialisation, Boolean MarineCell)
        {
            int fromIndex = 0;
            int toIndex   = 0;

            if (initialisation.TrackMarineSpecifics && MarineCell)
            {
                // Get the trophic level index of the functional group that mass is flowing from
                switch (cohortFunctionalGroupDefinitions.GetTraitNames("nutrition source", fromFunctionalGroup))
                {
                case "herbivore":
                    switch (cohortFunctionalGroupDefinitions.GetTraitNames("mobility", fromFunctionalGroup))
                    {
                    case "planktonic":
                        fromIndex = 4;
                        break;

                    default:
                        switch (cohortFunctionalGroupDefinitions.GetTraitNames("endo/ectotherm", fromFunctionalGroup))
                        {
                        case "endotherm":
                            switch (cohortFunctionalGroupDefinitions.GetTraitNames("diet", fromFunctionalGroup))
                            {
                            case "allspecial":
                                fromIndex = 6;
                                break;

                            default:
                                fromIndex = 1;
                                break;
                            }
                            break;

                        default:
                            if (preyBodyMass <= initialisation.PlanktonDispersalThreshold)
                            {
                                fromIndex = 5;
                            }
                            else
                            {
                                fromIndex = 1;
                            }
                            break;
                        }
                        break;
                    }
                    break;

                case "omnivore":
                    switch (cohortFunctionalGroupDefinitions.GetTraitNames("mobility", fromFunctionalGroup))
                    {
                    case "planktonic":
                        fromIndex = 4;
                        break;

                    default:
                        switch (cohortFunctionalGroupDefinitions.GetTraitNames("endo/ectotherm", fromFunctionalGroup))
                        {
                        case "endotherm":
                            switch (cohortFunctionalGroupDefinitions.GetTraitNames("diet", fromFunctionalGroup))
                            {
                            case "allspecial":
                                fromIndex = 6;
                                break;

                            default:
                                fromIndex = 2;
                                break;
                            }
                            break;

                        default:
                            if (preyBodyMass <= initialisation.PlanktonDispersalThreshold)
                            {
                                fromIndex = 5;
                            }
                            else
                            {
                                fromIndex = 2;
                            }
                            break;
                        }
                        break;
                    }
                    break;

                case "carnivore":
                    switch (cohortFunctionalGroupDefinitions.GetTraitNames("mobility", fromFunctionalGroup))
                    {
                    case "planktonic":
                        fromIndex = 4;
                        break;

                    default:
                        switch (cohortFunctionalGroupDefinitions.GetTraitNames("endo/ectotherm", fromFunctionalGroup))
                        {
                        case "endotherm":
                            switch (cohortFunctionalGroupDefinitions.GetTraitNames("diet", fromFunctionalGroup))
                            {
                            case "allspecial":
                                fromIndex = 6;
                                break;

                            default:
                                fromIndex = 3;
                                break;
                            }
                            break;

                        default:
                            if (preyBodyMass <= initialisation.PlanktonDispersalThreshold)
                            {
                                fromIndex = 5;
                            }
                            else
                            {
                                fromIndex = 3;
                            }
                            break;
                        }
                        break;
                    }
                    break;

                default:
                    Debug.Fail("Specified nutrition source is not supported");
                    break;
                }

                // Get the trophic level index of the functional group that mass is flowing to
                switch (cohortFunctionalGroupDefinitions.GetTraitNames("nutrition source", toFunctionalGroup))
                {
                case "omnivore":
                    switch (cohortFunctionalGroupDefinitions.GetTraitNames("mobility", toFunctionalGroup))
                    {
                    case "planktonic":
                        toIndex = 4;
                        break;

                    default:
                        switch (cohortFunctionalGroupDefinitions.GetTraitNames("endo/ectotherm", toFunctionalGroup))
                        {
                        case "endotherm":
                            switch (cohortFunctionalGroupDefinitions.GetTraitNames("diet", toFunctionalGroup))
                            {
                            case "allspecial":
                                toIndex = 6;
                                break;

                            default:
                                toIndex = 2;
                                break;
                            }
                            break;

                        default:
                            if (predatorBodyMass <= initialisation.PlanktonDispersalThreshold)
                            {
                                toIndex = 5;
                            }
                            else
                            {
                                toIndex = 2;
                            }
                            break;
                        }
                        break;
                    }
                    break;

                case "carnivore":
                    switch (cohortFunctionalGroupDefinitions.GetTraitNames("mobility", toFunctionalGroup))
                    {
                    case "planktonic":
                        toIndex = 4;
                        break;

                    default:
                        switch (cohortFunctionalGroupDefinitions.GetTraitNames("endo/ectotherm", toFunctionalGroup))
                        {
                        case "endotherm":
                            switch (cohortFunctionalGroupDefinitions.GetTraitNames("diet", toFunctionalGroup))
                            {
                            case "allspecial":
                                toIndex = 6;
                                break;

                            default:
                                toIndex = 3;
                                break;
                            }
                            break;

                        default:
                            if (predatorBodyMass <= initialisation.PlanktonDispersalThreshold)
                            {
                                toIndex = 5;
                            }
                            else
                            {
                                toIndex = 3;
                            }
                            break;
                        }
                        break;
                    }
                    break;

                default:
                    Debug.Fail("Specified nutrition source is not supported");
                    break;
                }
            }
            else
            {
                // Get the trophic level index of the functional group that mass is flowing from
                switch (cohortFunctionalGroupDefinitions.GetTraitNames("nutrition source", fromFunctionalGroup))
                {
                case "herbivore":
                    fromIndex = 1;
                    break;

                case "omnivore":
                    fromIndex = 2;
                    break;

                case "carnivore":
                    fromIndex = 3;
                    break;

                default:
                    Debug.Fail("Specified nutrition source is not supported");
                    break;
                }

                // Get the trophic level index of the functional group that mass is flowing to
                switch (cohortFunctionalGroupDefinitions.GetTraitNames("nutrition source", toFunctionalGroup))
                {
                case "herbivore":
                    toIndex = 1;
                    break;

                case "omnivore":
                    toIndex = 2;
                    break;

                case "carnivore":
                    toIndex = 3;
                    break;

                default:
                    Debug.Fail("Specified nutrition source is not supported");
                    break;
                }
            }

            // Add the flow of matter to the matrix of mass flows
            TrophicMassFlows[latIndex, lonIndex, fromIndex, toIndex] += massEaten;
        }