예제 #1
0
        /// <summary>
        /// Convert NPP estimate into biomass of an autotroph stock
        /// </summary>
        /// <param name="cellEnvironment">The environment of the current grid cell</param>
        /// <param name="gridCellStockHandler">The stock handler for the current stock</param>
        /// <param name="actingStock">The location of the stock to add biomass to</param>
        /// <param name="terrestrialNPPUnits">The units of the terrestrial NPP data</param>
        /// <param name="oceanicNPPUnits">The units of the oceanic NPP data</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="GlobalModelTimeStepUnit">The time step unit used in the model</param>
        /// <param name="trackProcesses">Whether to output data describing the ecological processes</param>
        /// <param name="globalTracker">Whether to output data describing the global-scale environment</param>
        /// <param name="outputDetail">The level of output detail to use for the outputs</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="currentMonth">The current month in the model run</param>
        public void ConvertNPPToAutotroph(SortedList <string, double[]> cellEnvironment, GridCellStockHandler gridCellStockHandler, int[]
                                          actingStock, string terrestrialNPPUnits, string oceanicNPPUnits, uint currentTimestep, string GlobalModelTimeStepUnit,
                                          ProcessTracker trackProcesses, GlobalProcessTracker globalTracker, string outputDetail, bool specificLocations, uint currentMonth)
        {
            // Get NPP from the cell environment
            double NPP = cellEnvironment["NPP"][currentMonth];

            // If NPP is a mssing value then set to zero
            if (NPP == cellEnvironment["Missing Value"][0])
            {
                NPP = 0.0;
            }

            // Check that this is an ocean cell
            if (cellEnvironment["Realm"][0] == 2.0)
            {
                // Check that the units of oceanic NPP are gC per m2 per day
                Debug.Assert(oceanicNPPUnits == "gC/m2/day", "Oceanic NPP data are not in the correct units for this formulation of the model");

                // Convert to g/cell/month
                NPP *= _MsqToKmSqConversion;

                // Multiply by cell area to get g/cell/day
                NPP *= cellEnvironment["Cell Area"][0];

                // Convert to g wet matter, assuming carbon content of phytoplankton is 10% of wet matter
                NPP *= _PhytoplanktonConversionRatio;

                // Finally convert to g/cell/month and add to the stock totalbiomass
                NPP *= Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "day");
                gridCellStockHandler[actingStock].TotalBiomass += NPP;

                if (trackProcesses.TrackProcesses && (outputDetail == "high") && specificLocations)
                {
                    trackProcesses.TrackPrimaryProductionTrophicFlow((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                                                     NPP);
                }

                if (globalTracker.TrackProcesses)
                {
                    globalTracker.RecordNPP((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], (uint)actingStock[0],
                                            NPP / cellEnvironment["Cell Area"][0]);
                }

                // If the biomass of the autotroph stock has been made less than zero (i.e. because of negative NPP) then reset to zero
                if (gridCellStockHandler[actingStock].TotalBiomass < 0.0)
                {
                    gridCellStockHandler[actingStock].TotalBiomass = 0.0;
                }
            }
            // Else if neither on land or in the ocean
            else
            {
                Debug.Fail("This is not a marine cell!");
                // Set the autotroph biomass to zero
                gridCellStockHandler[actingStock].TotalBiomass = 0.0;
            }
            Debug.Assert(gridCellStockHandler[actingStock].TotalBiomass >= 0.0, "stock negative");
        }
        /// <summary>
        /// Convert NPP estimate into biomass of an autotroph stock
        /// </summary>
        /// <param name="cellEnvironment">The environment of the current grid cell</param>
        /// <param name="gridCellStockHandler">The stock handler for the current stock</param>
        /// <param name="actingStock">The location of the stock to add biomass to</param>
        /// <param name="terrestrialNPPUnits">The units of the terrestrial NPP data</param>
        /// <param name="oceanicNPPUnits">The units of the oceanic NPP data</param>
        /// <param name="currentTimestep">The current model time step</param>
        /// <param name="GlobalModelTimeStepUnit">The time step unit used in the model</param>
        /// <param name="trackProcesses">Whether to output data describing the ecological processes</param>
        /// <param name="globalTracker">Whether to output data describing the global-scale environment</param>
        /// <param name="outputDetail">The level of output detail to use for the outputs</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        /// <param name="currentMonth">The current month in the model run</param>
        public void ConvertNPPToAutotroph(SortedList<string, double[]> cellEnvironment, GridCellStockHandler gridCellStockHandler, int[]
            actingStock, string terrestrialNPPUnits, string oceanicNPPUnits, uint currentTimestep, string GlobalModelTimeStepUnit,
            ProcessTracker trackProcesses, GlobalProcessTracker globalTracker, string outputDetail, bool specificLocations, uint currentMonth)
        {

            // Get NPP from the cell environment
            double NPP = cellEnvironment["NPP"][currentMonth];

            // If NPP is a mssing value then set to zero
            if (NPP == cellEnvironment["Missing Value"][0]) NPP = 0.0;

            // Check that this is an ocean cell
            if (cellEnvironment["Realm"][0] == 2.0)
            {
                // Check that the units of oceanic NPP are gC per m2 per day
                Debug.Assert(oceanicNPPUnits == "gC/m2/day", "Oceanic NPP data are not in the correct units for this formulation of the model");

                // Convert to g/cell/month
                NPP *= _MsqToKmSqConversion;

                // Multiply by cell area to get g/cell/day
                NPP *= cellEnvironment["Cell Area"][0];

                // Convert to g wet matter, assuming carbon content of phytoplankton is 10% of wet matter
                NPP *= _PhytoplanktonConversionRatio;

                // Finally convert to g/cell/month and add to the stock totalbiomass
                NPP *= Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "day");
                gridCellStockHandler[actingStock].TotalBiomass += NPP;

                if (trackProcesses.TrackProcesses && (outputDetail == "high") && specificLocations)
                {
                    trackProcesses.TrackPrimaryProductionTrophicFlow((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                        NPP);
                }

                if (globalTracker.TrackProcesses)
                {
                    globalTracker.RecordNPP((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], (uint)actingStock[0],
                            NPP / cellEnvironment["Cell Area"][0]);
                }

                // If the biomass of the autotroph stock has been made less than zero (i.e. because of negative NPP) then reset to zero
                if (gridCellStockHandler[actingStock].TotalBiomass < 0.0)
                    gridCellStockHandler[actingStock].TotalBiomass = 0.0;
            }
            // Else if neither on land or in the ocean
            else
            {
                Debug.Fail("This is not a marine cell!");
                // Set the autotroph biomass to zero
                gridCellStockHandler[actingStock].TotalBiomass = 0.0;
            }
            Debug.Assert(gridCellStockHandler[actingStock].TotalBiomass >= 0.0, "stock negative");
        }
예제 #3
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");
            }
        }
        /// <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");
            }
        }
        /// <summary>
        /// Update the leaf stock during a time step given the environmental conditions in the grid cell
        /// </summary>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingStock">The position of the acting stock in the array of grid cell stocks</param>
        /// <param name="currentTimeStep">The current model time step</param>
        /// <param name="deciduous">Whether the acting stock consists of deciduous leaves</param>
        /// <param name="GlobalModelTimeStepUnit">The time step unit used in the model</param>
        /// <param name="tracker">Whether to track properties of the ecological processes</param>
        /// <param name="globalTracker">Whether to output data describing the global environment</param>
        /// <param name="currentMonth">The current model month</param>
        /// <param name="outputDetail">The level of detail to use in model outputs</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        public double UpdateLeafStock(SortedList <string, double[]> cellEnvironment, GridCellStockHandler gridCellStocks, int[] actingStock,
                                      uint currentTimeStep, bool deciduous, string GlobalModelTimeStepUnit, ProcessTracker tracker, GlobalProcessTracker globalTracker,
                                      uint currentMonth, string outputDetail, bool specificLocations)
        {
            // ESTIMATE ANNUAL LEAF CARBON FIXATION ASSUMING ENVIRONMENT THROUGHOUT THE YEAR IS THE SAME AS IN THIS MONTH

            // Calculate annual NPP
            double NPP = this.CalculateMiamiNPP(cellEnvironment["Temperature"].Average(), cellEnvironment["Precipitation"].Sum());

            // Calculate fractional allocation to structural tissue
            double FracStruct = this.CalculateFracStruct(NPP);

            // Estimate monthly NPP based on seasonality layer
            NPP *= cellEnvironment["Seasonality"][currentMonth];


            // Calculate leaf mortality rates
            double AnnualLeafMortRate;
            double MonthlyLeafMortRate;
            double TimeStepLeafMortRate;

            if (deciduous)
            {
                // Calculate annual deciduous leaf mortality
                AnnualLeafMortRate = this.CalculateDeciduousAnnualLeafMortality(cellEnvironment["Temperature"].Average());

                // For deciduous plants monthly leaf mortality is weighted by temperature deviance from the average, to capture seasonal patterns
                double[] ExpTempDev    = new double[12];
                double   SumExpTempDev = 0.0;
                double[] TempDev       = new double[12];
                double   Weight;
                for (int i = 0; i < 12; i++)
                {
                    TempDev[i]     = cellEnvironment["Temperature"][i] - cellEnvironment["Temperature"].Average();
                    ExpTempDev[i]  = Math.Exp(-TempDev[i] / 3);
                    SumExpTempDev += ExpTempDev[i];
                }
                Weight = ExpTempDev[currentMonth] / SumExpTempDev;
                MonthlyLeafMortRate  = AnnualLeafMortRate * Weight;
                TimeStepLeafMortRate = MonthlyLeafMortRate * Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "month");
            }
            else
            {
                // Calculate annual evergreen leaf mortality
                AnnualLeafMortRate = this.CalculateEvergreenAnnualLeafMortality(cellEnvironment["Temperature"].Average());

                // For evergreen plants, leaf mortality is assumed to be equal throughout the year
                MonthlyLeafMortRate  = AnnualLeafMortRate * (1.0 / 12.0);
                TimeStepLeafMortRate = MonthlyLeafMortRate * Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "month");
            }

            // Calculate fine root mortality rate
            double AnnualFRootMort = this.CalculateFineRootMortalityRate(cellEnvironment["Temperature"][currentMonth]);

            // Calculate the NPP allocated to non-structural tissues
            double FracNonStruct = (1 - FracStruct);

            // Calculate the fractional allocation to leaves
            double FracLeaves = FracNonStruct * this.CalculateLeafFracAllocation(AnnualLeafMortRate, AnnualFRootMort);

            // Calculate the fractional allocation of NPP to evergreen plant matter
            double FracEvergreen = this.CalculateFracEvergreen(cellEnvironment["Fraction Year Frost"][0]);

            // Update NPP depending on whether the acting stock is deciduous or evergreen
            if (deciduous)
            {
                NPP *= (1 - FracEvergreen);
            }
            else
            {
                NPP *= FracEvergreen;
            }

            // Calculate the fire mortality rate
            double FireMortRate = this.CalculateFireMortalityRate(NPP, cellEnvironment["Fraction Year Fire"][0]);

            // Calculate the structural mortality rate
            double StMort = this.CalculateStructuralMortality(cellEnvironment["AET"][currentMonth] * 12);

            // Calculate leaf C fixation
            double LeafCFixation = NPP * FracLeaves;

            // Convert from carbon to leaf wet matter
            double WetMatterIncrement = this.ConvertToLeafWetMass(LeafCFixation, cellEnvironment["Cell Area"][0]);

            // Convert from the monthly time step used for this process to the global model time step unit
            WetMatterIncrement *= Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "month");



            // Add the leaf wet matter to the acting stock
            //gridCellStocks[actingStock].TotalBiomass += Math.Max(-gridCellStocks[actingStock].TotalBiomass, WetMatterIncrement);
            double NPPWetMatter = Math.Max(-gridCellStocks[actingStock].TotalBiomass, WetMatterIncrement);


            // If the processer tracker is enabled and output detail is high and the model is being run for specific locations, then track the biomass gained through primary production
            if (tracker.TrackProcesses && (outputDetail == "high") && specificLocations)
            {
                tracker.TrackPrimaryProductionTrophicFlow((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                                                          Math.Max(-gridCellStocks[actingStock].TotalBiomass, WetMatterIncrement));
            }

            if (globalTracker.TrackProcesses)
            {
                globalTracker.RecordNPP((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], (uint)actingStock[0],
                                        this.ConvertToLeafWetMass(NPP, cellEnvironment["Cell Area"][0]) *
                                        Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "month") / cellEnvironment["Cell Area"][0]);
            }
            // Calculate fractional leaf mortality
            double LeafMortFrac = 1 - Math.Exp(-TimeStepLeafMortRate);

            // Update the leaf stock biomass owing to the leaf mortality
            gridCellStocks[actingStock].TotalBiomass *= (1 - LeafMortFrac);
            NPPWetMatter *= (1 - LeafMortFrac);

            return(NPPWetMatter);
        }
        /// <summary>
        /// Initializes the ecosystem model
        /// </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 being run</param>
        /// <param name="outputFilesSuffix">The suffix to be applied to all outputs from this model run</param>
        /// <param name="globalModelTimeStepUnit">The time step unit used in the model</param>
        /// <param name="simulation">The index of the simulation being run</param>
        public MadingleyModel(MadingleyModelInitialisation initialisation, ScenarioParameterInitialisation scenarioParameters, int scenarioIndex,
            string outputFilesSuffix, string globalModelTimeStepUnit, int simulation)
        {
            // Assign the properties for this model run
            AssignModelRunProperties(initialisation, scenarioParameters, scenarioIndex, outputFilesSuffix);

            // Set up list of global diagnostics
            SetUpGlobalDiagnosticsList();

            // Set up the model grid
            SetUpModelGrid(initialisation, scenarioParameters, scenarioIndex, simulation);

            // Set up model outputs
            SetUpOutputs(initialisation, simulation, scenarioIndex);

            // Make the initial outputs
            InitialOutputs(outputFilesSuffix, initialisation, CurrentMonth);

            // Instance the array of process trackers
            ProcessTrackers = new ProcessTracker[_CellList.Count];

            // Temporary variables
            Boolean varExists;

            // Set up process trackers for each grid cell
            for (int i = 0; i < _CellList.Count; i++)
            {
                ProcessTrackers[i] = new ProcessTracker(NumTimeSteps,
                EcosystemModelGrid.Lats, EcosystemModelGrid.Lons,
                _CellList,
                initialisation.ProcessTrackingOutputs,
                initialisation.TrackProcesses,
                CohortFunctionalGroupDefinitions,
                EcosystemModelGrid.GlobalMissingValue,
                outputFilesSuffix,
                initialisation.OutputPath, initialisation.ModelMassBins,
                SpecificLocations, i, initialisation,
                EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0,
                EcosystemModelGrid.LatCellSize,
                EcosystemModelGrid.LonCellSize);
            }

            // Set up a cross cell process tracker
            TrackCrossCellProcesses = new CrossCellProcessTracker(initialisation.TrackCrossCellProcesses, "DispersalData", initialisation.OutputPath, outputFilesSuffix);

            //Set up a global process tracker
            if (SpecificLocations) initialisation.TrackGlobalProcesses = false;

            TrackGlobalProcesses = new GlobalProcessTracker(NumTimeSteps,
                EcosystemModelGrid.Lats, EcosystemModelGrid.Lons,
                _CellList,
                initialisation.ProcessTrackingOutputs,
                initialisation.TrackGlobalProcesses,
                CohortFunctionalGroupDefinitions,
                StockFunctionalGroupDefinitions,
                EcosystemModelGrid.GlobalMissingValue,
                outputFilesSuffix,
                initialisation.OutputPath, initialisation.ModelMassBins,
                SpecificLocations, initialisation,
                EcosystemModelGrid.LatCellSize,
                EcosystemModelGrid.LonCellSize);

            //Set-up the instance of OutputModelState
            WriteModelState = new OutputModelState(initialisation, outputFilesSuffix, simulation);

            if (SpecificLocations) initialisation.RunRealm = "";

            // Record the initial cohorts in the process trackers
            RecordInitialCohorts();

            // Initialise the class for cross-grid-cell ecology
            MadingleyEcologyCrossGridCell = new EcologyCrossGridCell();

            // Initialise the time step timer
            TimeStepTimer = new StopWatch();
            EcologyTimer = new StopWatch();
            OutputTimer = new StopWatch();

            // Set the global model time step unit
            _GlobalModelTimeStepUnit = globalModelTimeStepUnit;

            // Initialise the utility functions
            Utilities = new UtilityFunctions();

            // Initialise the climate change impacts class
            ClimateChangeSimulator = new ClimateChange();

            // Initialise the harvesting impacts class
            HarvestingSimulator = new Harvesting(EcosystemModelGrid.Lats, EcosystemModelGrid.Lons, (float)EcosystemModelGrid.LatCellSize);
        }
        /// <summary>
        /// Update the leaf stock during a time step given the environmental conditions in the grid cell
        /// </summary>
        /// <param name="cellEnvironment">The environment in the current grid cell</param>
        /// <param name="gridCellStocks">The stocks in the current grid cell</param>
        /// <param name="actingStock">The position of the acting stock in the array of grid cell stocks</param>
        /// <param name="currentTimeStep">The current model time step</param>
        /// <param name="deciduous">Whether the acting stock consists of deciduous leaves</param>
        /// <param name="GlobalModelTimeStepUnit">The time step unit used in the model</param>
        /// <param name="tracker">Whether to track properties of the ecological processes</param>
        /// <param name="globalTracker">Whether to output data describing the global environment</param>
        /// <param name="currentMonth">The current model month</param>
        /// <param name="outputDetail">The level of detail to use in model outputs</param>
        /// <param name="specificLocations">Whether the model is being run for specific locations</param>
        public double UpdateLeafStock(SortedList<string, double[]> cellEnvironment, GridCellStockHandler gridCellStocks, int[] actingStock,
            uint currentTimeStep, bool deciduous, string GlobalModelTimeStepUnit, ProcessTracker tracker, GlobalProcessTracker globalTracker, 
            uint currentMonth, string outputDetail, bool specificLocations)
        {
            // ESTIMATE ANNUAL LEAF CARBON FIXATION ASSUMING ENVIRONMENT THROUGHOUT THE YEAR IS THE SAME AS IN THIS MONTH

            // Calculate annual NPP
            double NPP = this.CalculateMiamiNPP(cellEnvironment["Temperature"].Average(), cellEnvironment["Precipitation"].Sum());

            // Calculate fractional allocation to structural tissue
            double FracStruct = this.CalculateFracStruct(NPP);

            // Estimate monthly NPP based on seasonality layer
            NPP *= cellEnvironment["Seasonality"][currentMonth];

            // Calculate leaf mortality rates
            double AnnualLeafMortRate;
            double MonthlyLeafMortRate;
            double TimeStepLeafMortRate;

            if (deciduous)
            {
                // Calculate annual deciduous leaf mortality
                AnnualLeafMortRate = this.CalculateDeciduousAnnualLeafMortality(cellEnvironment["Temperature"].Average());

                // For deciduous plants monthly leaf mortality is weighted by temperature deviance from the average, to capture seasonal patterns
                double[] ExpTempDev = new double[12];
                double SumExpTempDev = 0.0;
                double[] TempDev = new double[12];
                double Weight;
                for (int i = 0; i < 12; i++)
                {
                    TempDev[i] = cellEnvironment["Temperature"][i] - cellEnvironment["Temperature"].Average();
                    ExpTempDev[i] = Math.Exp(-TempDev[i] / 3);
                    SumExpTempDev += ExpTempDev[i];
                }
                Weight = ExpTempDev[currentMonth] / SumExpTempDev;
                MonthlyLeafMortRate = AnnualLeafMortRate * Weight;
                TimeStepLeafMortRate = MonthlyLeafMortRate * Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "month");
            }
            else
            {
                // Calculate annual evergreen leaf mortality
                AnnualLeafMortRate = this.CalculateEvergreenAnnualLeafMortality(cellEnvironment["Temperature"].Average());

                // For evergreen plants, leaf mortality is assumed to be equal throughout the year
                MonthlyLeafMortRate = AnnualLeafMortRate * (1.0 / 12.0);
                TimeStepLeafMortRate = MonthlyLeafMortRate * Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "month");
            }

            // Calculate fine root mortality rate
            double AnnualFRootMort = this.CalculateFineRootMortalityRate(cellEnvironment["Temperature"][currentMonth]);

            // Calculate the NPP allocated to non-structural tissues
            double FracNonStruct = (1 - FracStruct);

            // Calculate the fractional allocation to leaves
            double FracLeaves = FracNonStruct * this.CalculateLeafFracAllocation(AnnualLeafMortRate, AnnualFRootMort);

            // Calculate the fractional allocation of NPP to evergreen plant matter
            double FracEvergreen = this.CalculateFracEvergreen(cellEnvironment["Fraction Year Frost"][0]);

            // Update NPP depending on whether the acting stock is deciduous or evergreen
            if (deciduous)
            {
                NPP *= (1 - FracEvergreen);
            }
            else
            {
                NPP *= FracEvergreen;
            }

            // Calculate the fire mortality rate
            double FireMortRate = this.CalculateFireMortalityRate(NPP, cellEnvironment["Fraction Year Fire"][0]);

            // Calculate the structural mortality rate
            double StMort = this.CalculateStructuralMortality(cellEnvironment["AET"][currentMonth] * 12);

            // Calculate leaf C fixation
            double LeafCFixation = NPP * FracLeaves;

            // Convert from carbon to leaf wet matter
            double WetMatterIncrement = this.ConvertToLeafWetMass(LeafCFixation, cellEnvironment["Cell Area"][0]);

            // Convert from the monthly time step used for this process to the global model time step unit
            WetMatterIncrement *= Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "month");

            // Add the leaf wet matter to the acting stock
            //gridCellStocks[actingStock].TotalBiomass += Math.Max(-gridCellStocks[actingStock].TotalBiomass, WetMatterIncrement);
            double NPPWetMatter = Math.Max(-gridCellStocks[actingStock].TotalBiomass, WetMatterIncrement);

            // If the processer tracker is enabled and output detail is high and the model is being run for specific locations, then track the biomass gained through primary production
            if (tracker.TrackProcesses && (outputDetail == "high") && specificLocations)
            {
                tracker.TrackPrimaryProductionTrophicFlow((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],
                    Math.Max(-gridCellStocks[actingStock].TotalBiomass, WetMatterIncrement));

            }

            if (globalTracker.TrackProcesses)
            {
                globalTracker.RecordNPP((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0],(uint)actingStock[0],
                    this.ConvertToLeafWetMass(NPP, cellEnvironment["Cell Area"][0]) *
                    Utilities.ConvertTimeUnits(GlobalModelTimeStepUnit, "month")/cellEnvironment["Cell Area"][0]);
            }
            // Calculate fractional leaf mortality
            double LeafMortFrac = 1 - Math.Exp(-TimeStepLeafMortRate);

            // Update the leaf stock biomass owing to the leaf mortality
            gridCellStocks[actingStock].TotalBiomass *= (1 - LeafMortFrac);
            NPPWetMatter *= (1 - LeafMortFrac);

            return (NPPWetMatter);
        }
예제 #8
0
        /// <summary>
        /// Initializes the ecosystem model
        /// </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 being run</param>
        /// <param name="outputFilesSuffix">The suffix to be applied to all outputs from this model run</param>
        /// <param name="globalModelTimeStepUnit">The time step unit used in the model</param>
        /// <param name="simulation">The index of the simulation being run</param>
        public MadingleyModel(MadingleyModelInitialisation initialisation, ScenarioParameterInitialisation scenarioParameters, int scenarioIndex,
            string outputFilesSuffix, string globalModelTimeStepUnit, int simulation)
        {         
            // Assign the properties for this model run
            AssignModelRunProperties(initialisation, scenarioParameters, scenarioIndex, outputFilesSuffix);
#endif

            // Set up the model grid
#if true
            this._CellList = initialisation.CellList.ToList();
            SetUpModelGrid(initialisation);
            EcosystemModelGrid.SetGridCells(gridCells, this._CellList);
#else
            SetUpModelGrid(initialisation, scenarioParameters, scenarioIndex, simulation);
#endif

            // Set up model outputs
            SetUpOutputs(initialisation, simulation, scenarioIndex);

            // Make the initial outputs
            InitialOutputs(outputFilesSuffix, initialisation, CurrentMonth);

            // Instance the array of process trackers
            ProcessTrackers = new ProcessTracker[_CellList.Count];

            // Temporary variables
            Boolean varExists;

            // Set up process trackers for each grid cell
            for (int i = 0; i < _CellList.Count; i++)
            {
                ProcessTrackers[i] = new ProcessTracker(NumTimeSteps,
                EcosystemModelGrid.Lats, EcosystemModelGrid.Lons,
                _CellList,
                initialisation.ProcessTrackingOutputs,
                initialisation.TrackProcesses,
                CohortFunctionalGroupDefinitions,
                EcosystemModelGrid.GlobalMissingValue,
                outputFilesSuffix,
                initialisation.OutputPath, initialisation.ModelMassBins,
                SpecificLocations, i, initialisation,
                EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0,
                EcosystemModelGrid.LatCellSize,
                EcosystemModelGrid.LonCellSize);
            }

            // Set up a cross cell process tracker
            TrackCrossCellProcesses = new CrossCellProcessTracker(initialisation.TrackCrossCellProcesses, "DispersalData", initialisation.OutputPath, outputFilesSuffix);

            //Set up a global process tracker
            if (SpecificLocations) initialisation.TrackGlobalProcesses = false;

            TrackGlobalProcesses = new GlobalProcessTracker(NumTimeSteps,
                EcosystemModelGrid.Lats, EcosystemModelGrid.Lons,
                _CellList,
                initialisation.ProcessTrackingOutputs,
                initialisation.TrackGlobalProcesses,
                CohortFunctionalGroupDefinitions,
                StockFunctionalGroupDefinitions,
                EcosystemModelGrid.GlobalMissingValue,
                outputFilesSuffix,
                initialisation.OutputPath, initialisation.ModelMassBins,
                SpecificLocations, initialisation,
                EcosystemModelGrid.LatCellSize,
                EcosystemModelGrid.LonCellSize);

            //Set-up the instance of OutputModelState
            WriteModelState = new OutputModelState(initialisation, outputFilesSuffix, simulation);

            if (SpecificLocations) initialisation.RunRealm = "";

            // Record the initial cohorts in the process trackers
            RecordInitialCohorts();

            // Initialise the time step timer
            TimeStepTimer = new StopWatch();
            EcologyTimer = new StopWatch();
            OutputTimer = new StopWatch();

            // Set the global model time step unit
            _GlobalModelTimeStepUnit = globalModelTimeStepUnit;
        }