private void RunWithinCellCohortEcology(uint latCellIndex, uint lonCellIndex, ThreadLockedParallelVariables partial, 
            GridCellCohortHandler workingGridCellCohorts, GridCellStockHandler workingGridCellStocks,string outputDetail, int cellIndex, MadingleyModelInitialisation initialisation)
        {
            // Local instances of classes
            EcologyCohort MadingleyEcologyCohort = new EcologyCohort();
            Activity CohortActivity = new Activity();
            CohortMerge CohortMerger = new CohortMerge(DrawRandomly);

            // A list of the original cohorts inside a particular grid cell
            int[] OriginalGridCellCohortsNumbers;
            // A vector to hold the order in which cohorts will act
            uint[] RandomCohortOrder;
            // A jagged array to keep track of cohorts that are being worked on
            uint[][] CohortIndices;
            // The location of the acting cohort
            int[] ActingCohort = new int[2];
            // Temporary local variables
            int EcosystemModelParallelTempval1;
            int EcosystemModelParallelTempval2;
            // Boolean to pass into function to get cell environmental data to check if the specified variable exists
            bool VarExists;
            // variable to track cohort number
            uint TotalCohortNumber = 0;

            // Fill in the array with the number of cohorts per functional group before ecological processes are run
            OriginalGridCellCohortsNumbers = new int[workingGridCellCohorts.Count];

            for (int i = 0; i < workingGridCellCohorts.Count; i++)
            {
                OriginalGridCellCohortsNumbers[i] = workingGridCellCohorts[i].Count;
            }

            // Initialize ecology for stocks and cohorts
            MadingleyEcologyCohort.InitializeEcology(EcosystemModelGrid.GetCellEnvironment(latCellIndex, lonCellIndex)["Cell Area"][0],
                _GlobalModelTimeStepUnit, DrawRandomly);

            // Create a jagged array indexed by functional groups to hold cohort indices
            CohortIndices = new uint[CohortFunctionalGroupDefinitions.GetNumberOfFunctionalGroups()][];

            // Loop over functional groups
            for (int ll = 0; ll < CohortFunctionalGroupDefinitions.GetNumberOfFunctionalGroups(); ll++)
            {
                // Dimension the number of columns in each row of the jagged array to equal number of gridCellCohorts in each functional group
                if (workingGridCellCohorts[ll] == null)
                {
                    CohortIndices[ll] = new uint[0];
                }
                else
                {
                    CohortIndices[ll] = new uint[workingGridCellCohorts[ll].Count()];
                }
                // Loop over gridCellCohorts in the functional group
                for (int kk = 0; kk < CohortIndices[ll].Count(); kk++)
                {
                    // Fill jagged array with indices for each cohort
                    CohortIndices[ll][kk] = TotalCohortNumber;
                    TotalCohortNumber += 1;
                }

            }

            if (DrawRandomly)
            {
                // Randomly order the cohort indices
                RandomCohortOrder = Utilities.RandomlyOrderedIndices(TotalCohortNumber);
            }
            else
            {
                RandomCohortOrder = Utilities.NonRandomlyOrderedCohorts(TotalCohortNumber, CurrentTimeStep);
            }

            // Diagnostic biological variables don't need to be reset every cohort, but rather every grid cell
            EcosystemModelParallelTempval2 = 0;

            // Initialise eating formulations
            MadingleyEcologyCohort.EatingFormulations["Basic eating"].InitializeEcologicalProcess(workingGridCellCohorts, workingGridCellStocks,
                CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, "revised predation");
            MadingleyEcologyCohort.EatingFormulations["Basic eating"].InitializeEcologicalProcess(workingGridCellCohorts, workingGridCellStocks
                , CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, "revised herbivory");

            // Loop over randomly ordered gridCellCohorts to implement biological functions
            for (int ll = 0; ll < RandomCohortOrder.Length; ll++)
            {

                // Locate the randomly chosen cohort within the array of lists of gridCellCohorts in the grid cell
                ActingCohort = Utilities.FindJaggedArrayIndex(RandomCohortOrder[ll], CohortIndices, TotalCohortNumber);

                // Perform all biological functions except dispersal (which is cross grid cell)
                if (workingGridCellCohorts[ActingCohort].CohortAbundance.CompareTo(_ExtinctionThreshold) > 0)
                {
                    // Calculate number of cohorts in this functional group in this grid cell before running ecology
                    EcosystemModelParallelTempval1 = workingGridCellCohorts[ActingCohort[0]].Count;

                    CohortActivity.AssignProportionTimeActive(workingGridCellCohorts[ActingCohort], EcosystemModelGrid.GetCellEnvironment(latCellIndex, lonCellIndex), CohortFunctionalGroupDefinitions, CurrentTimeStep, CurrentMonth);

                    // Run ecology
                    MadingleyEcologyCohort.RunWithinCellEcology(workingGridCellCohorts, workingGridCellStocks,
                        ActingCohort, EcosystemModelGrid.GetCellEnvironment(latCellIndex, lonCellIndex),
                        EcosystemModelGrid.GetCellDeltas(latCellIndex, lonCellIndex),
                        CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, CurrentTimeStep,
                        ProcessTrackers[cellIndex], ref partial, SpecificLocations,outputDetail, CurrentMonth, initialisation);

                    // Update the properties of the acting cohort
                    MadingleyEcologyCohort.UpdateEcology(workingGridCellCohorts, workingGridCellStocks, ActingCohort,
                        EcosystemModelGrid.GetCellEnvironment(latCellIndex, lonCellIndex), EcosystemModelGrid.GetCellDeltas(
                        latCellIndex, lonCellIndex), CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, CurrentTimeStep,
                        ProcessTrackers[cellIndex]);

                    // Add newly produced cohorts to the tracking variable
                    EcosystemModelParallelTempval2 += workingGridCellCohorts[ActingCohort[0]].Count - EcosystemModelParallelTempval1;

                    // Check that the mass of individuals in this cohort is still >= 0 after running ecology
                    Debug.Assert(workingGridCellCohorts[ActingCohort].IndividualBodyMass >= 0.0, "Biomass < 0 for this cohort");
                }

                // Check that the mass of individuals in this cohort is still >= 0 after running ecology
                Debug.Assert(workingGridCellCohorts[ActingCohort].IndividualBodyMass >= 0.0, "Biomass < 0 for this cohort");
            }

            // Update diagnostics of productions
            partial.Productions += EcosystemModelParallelTempval2;

            RunExtinction(latCellIndex, lonCellIndex, partial, workingGridCellCohorts, cellIndex);

            // Merge cohorts, if necessary
            if (workingGridCellCohorts.GetNumberOfCohorts() > initialisation.MaxNumberOfCohorts)
            {
                partial.Combinations = CohortMerger.MergeToReachThresholdFast(workingGridCellCohorts, workingGridCellCohorts.GetNumberOfCohorts(), initialisation.MaxNumberOfCohorts);

                //Run extinction a second time to remove those cohorts that have been set to zero abundance when merging
                RunExtinction(latCellIndex, lonCellIndex, partial, workingGridCellCohorts, cellIndex);
            }
            else
                partial.Combinations = 0;

            // Write out the updated cohort numbers after all ecological processes have occured
            EcosystemModelGrid.SetGridCellCohorts(workingGridCellCohorts, latCellIndex, lonCellIndex);
        }
        /// <summary>
        /// Copy parameter values to a text file in the specified output directory
        /// </summary>
        /// <param name="outputDirectory">THe directory for outputs</param>
        public void CopyParameterValues(string outputDirectory)
        {
            // Create a stream write object to write the parameter values to
            StreamWriter sw = new StreamWriter(outputDirectory + "Parameters.txt");

            // Write out the column headings
            sw.WriteLine("Ecological process\tParameter name\tParameter value");

            // Create dummy instances of the ecological processes
            RevisedHerbivory DummyHerbivory = new RevisedHerbivory(0.0, _GlobalModelTimeStepUnit);
            RevisedPredation DummyPredation = new RevisedPredation(0.0, _GlobalModelTimeStepUnit);
            MetabolismEndotherm DummyEndoMetabolism = new MetabolismEndotherm(_GlobalModelTimeStepUnit);
            MetabolismEctotherm DummyEctoMetabolism = new MetabolismEctotherm(_GlobalModelTimeStepUnit);
            BackgroundMortality DummyBackgroundMortality = new BackgroundMortality(_GlobalModelTimeStepUnit);
            SenescenceMortality DummySenescenceMortality = new SenescenceMortality(_GlobalModelTimeStepUnit);
            StarvationMortality DummyStarvationMortality = new StarvationMortality(_GlobalModelTimeStepUnit);
            ReproductionBasic DummyReproduction = new ReproductionBasic(_GlobalModelTimeStepUnit, _DrawRandomly);
            DiffusiveDispersal DummyDiffusiveDispersal = new DiffusiveDispersal(_GlobalModelTimeStepUnit, _DrawRandomly);
            RevisedTerrestrialPlantModel DummyPlantModel = new RevisedTerrestrialPlantModel();
            Activity DummyActivityModel = new Activity();

            // Call the methods in these processes that write the parameter values out
            DummyHerbivory.WriteOutParameterValues(sw);
            DummyPredation.WriteOutParameterValues(sw);
            DummyEndoMetabolism.WriteOutParameterValues(sw);
            DummyEctoMetabolism.WriteOutParameterValues(sw);
            DummyBackgroundMortality.WriteOutParameterValues(sw);
            DummySenescenceMortality.WriteOutParameterValues(sw);
            DummyStarvationMortality.WriteOutParameterValues(sw);
            DummyReproduction.WriteOutParameterValues(sw);
            DummyDiffusiveDispersal.WriteOutParameterValues(sw);
            DummyPlantModel.WriteOutParameterValues(sw);
            DummyActivityModel.WriteOutParameterValues(sw);

            sw.Dispose();
        }