public void EndRun() { MadingleyModelInitialisation initialisation = this.ModelInitialisation; // Temporary Boolean varExists; #endif if (TrackGlobalProcesses.TrackProcesses) TrackGlobalProcesses.CloseNPPFile(); // Loop over cells and close process trackers for (int i = 0; i < _CellList.Count; i++) { if (ProcessTrackers[i].TrackProcesses) ProcessTrackers[i].CloseStreams(SpecificLocations); } // Write the final global outputs GlobalOutputs.FinalOutputs(); if (SpecificLocations) { // Loop over grid cells and write the final grid cell outputs for (int i = 0; i < _CellList.Count; i++) { CellOutputs[i].FinalOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, i, GlobalDiagnosticVariables, initialisation, CurrentMonth, EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0); } } else { // Write the final grid outputs GridOutputs.FinalOutputs(); } }
public static MadingleyModelInitialisation ConvertInitialisation( Madingley.Common.ModelState m, Madingley.Common.Configuration d, Madingley.Common.Environment e) { var i = new MadingleyModelInitialisation("", "", "", ""); i.GlobalModelTimeStepUnit = d.GlobalModelTimeStepUnit; i.NumTimeSteps = (uint)d.NumTimeSteps; i.BurninTimeSteps = (uint)d.BurninTimeSteps; i.ImpactTimeSteps = (uint)d.ImpactTimeSteps; i.RecoveryTimeSteps = (uint)d.RecoveryTimeSteps; i.CellSize = e.CellSize; i.BottomLatitude = (float)e.BottomLatitude; i.TopLatitude = (float)e.TopLatitude; i.LeftmostLongitude = (float)e.LeftmostLongitude; i.RightmostLongitude = (float)e.RightmostLongitude; i.RunCellsInParallel = d.RunCellsInParallel; i.RunSimulationsInParallel = d.RunSimulationsInParallel; i.RunRealm = d.RunRealm; i.DrawRandomly = d.DrawRandomly; i.ExtinctionThreshold = d.ExtinctionThreshold; i.MaxNumberOfCohorts = d.MaxNumberOfCohorts; i.DispersalOnly = d.DispersalOnly; i.PlanktonDispersalThreshold = d.PlanktonDispersalThreshold; i.SpecificLocations = e.SpecificLocations; i.InitialisationFileStrings = new SortedList <string, string>(); i.InitialisationFileStrings["OutputDetail"] = "high"; i.InitialisationFileStrings["DispersalOnlyType"] = d.DispersalOnlyType; i.CohortFunctionalGroupDefinitions = ConvertFunctionalGroupDefinitions(d.CohortFunctionalGroupDefinitions); i.StockFunctionalGroupDefinitions = ConvertFunctionalGroupDefinitions(d.StockFunctionalGroupDefinitions); if (m != null) { i.EnviroStack = ConvertEnvironment(m.GridCells); } else { i.EnviroStack = ConvertEnvironment(e.CellEnvironment); } i.CellList = e.FocusCells.Select(a => new UInt32[] { (uint)a.Item1, (uint)a.Item2 }).ToList(); i.TrackProcesses = true; i.TrackCrossCellProcesses = true; i.TrackGlobalProcesses = true; i.Units = new SortedList <string, string>(e.Units); i.ImpactCellIndices = d.ImpactCellIndices.Select(ii => (uint)ii).ToList(); i.ImpactAll = d.ImpactAll; if (m != null) { i.ModelStates = ConvertModelStates(m, d, e); i.InputState = true; i.InputGlobalDiagnosticVariables = new SortedList <string, double>(m.GlobalDiagnosticVariables); } else { i.ModelStates = null; i.InputState = false; } return(i); }
/// <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> /// Constructor for the global output class /// </summary> /// <param name="outputDetail">The level of detail to be used in model outputs</param> /// <param name="modelInitialisation">Model intialisation object</param> public OutputGlobal(string outputDetail, MadingleyModelInitialisation modelInitialisation) { // Set the output path _OutputPath = modelInitialisation.OutputPath; // Set the output detail level if (outputDetail == "low") { ModelOutputDetail = OutputDetailLevel.Low; } else if (outputDetail == "medium") { ModelOutputDetail = OutputDetailLevel.Medium; } else if (outputDetail == "high") { ModelOutputDetail = OutputDetailLevel.High; } else { Debug.Fail("Specified output detail level is not valid, must be 'low', 'medium' or 'high'"); } // Initialise the data converter DataConverter = new ArraySDSConvert(); // Initialise the SDS object creator SDSCreator = new CreateSDSObject(); }
/// <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); } }
/// <summary> /// Sets up the model grid within a Madingley 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> public void SetUpModelGrid(MadingleyModelInitialisation initialisation, ScenarioParameterInitialisation scenarioParameters, int scenarioIndex, int simulation) #endif { // If the intialisation file contains a column pointing to another file of specific locations, and if this column is not blank then read the // file indicated if (SpecificLocations) { // Set up the model grid using these locations #if true EcosystemModelGrid = new ModelGrid(BottomLatitude, LeftmostLongitude, TopLatitude, RightmostLongitude, CellSize, CellSize, _CellList, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, GlobalDiagnosticVariables, initialisation.TrackProcesses, SpecificLocations, RunGridCellsInParallel); #else EcosystemModelGrid = new ModelGrid(BottomLatitude, LeftmostLongitude, TopLatitude, RightmostLongitude, CellSize, CellSize, _CellList, EnviroStack, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, GlobalDiagnosticVariables, initialisation.TrackProcesses, SpecificLocations,RunGridCellsInParallel); #endif } else { EcologyTimer = new StopWatch(); EcologyTimer.Start(); // Set up a full model grid (i.e. not for specific locations) // Set up the model grid using these locations #if true EcosystemModelGrid = new ModelGrid(BottomLatitude, LeftmostLongitude, TopLatitude, RightmostLongitude, CellSize, CellSize, _CellList, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, GlobalDiagnosticVariables, initialisation.TrackProcesses, SpecificLocations, RunGridCellsInParallel); #else EcosystemModelGrid = new ModelGrid(BottomLatitude, LeftmostLongitude, TopLatitude, RightmostLongitude, CellSize, CellSize, _CellList, EnviroStack, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, GlobalDiagnosticVariables, initialisation.TrackProcesses, SpecificLocations, RunGridCellsInParallel); #endif EcologyTimer.Stop(); Console.WriteLine("Time to initialise cells: {0}", EcologyTimer.GetElapsedTimeSecs()); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Madingley Model memory usage post grid cell seed: {0}", GC.GetTotalMemory(true) / 1E9, " (G Bytes)\n"); Console.ForegroundColor = ConsoleColor.White; } Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Madingley Model memory usage pre Collect: {0}", Math.Round(GC.GetTotalMemory(true) / 1E9, 2), " (GBytes)"); Console.ForegroundColor = ConsoleColor.White; GC.Collect(); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Madingley Model memory usage post Collect: {0}", Math.Round(GC.GetTotalMemory(true) / 1E9, 5), " (GBytes)\n"); Console.ForegroundColor = ConsoleColor.White; }
/// <summary> /// Initalise the ecological processes /// </summary> public void InitializeCrossGridCellEcology(string globalModelTimeStepUnit, Boolean drawRandomly, MadingleyModelInitialisation modelInitialisation) { // Initialise dispersal formulations _DispersalFormulations = new SortedList<string, IEcologicalProcessAcrossGridCells>(); // Declare and attach dispersal formulations Dispersal DispersalFormulation = new Dispersal(drawRandomly, globalModelTimeStepUnit, modelInitialisation); _DispersalFormulations.Add("Basic dispersal", DispersalFormulation); // Initialise apply ecology ApplyCrossGridCellEcologicalProcessResults = new ApplyCrossGridCellEcology(); }
/// <summary> /// Get the total of a state variable for specific cells /// </summary> /// <param name="variableName">The name of the variable</param> /// <param name="traitValue">The functional group trait value to get data for</param> /// <param name="functionalGroups">A vector of functional group indices to consider</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="stateVariableType">A string indicating the type of state variable; 'cohort' or 'stock'</param> /// <param name="initialisation">The Madingley Model intialisation</param> /// <returns>Summed value of variable over whole grid</returns> /// <todo>Overload to work with vector and array state variables</todo> public double StateVariableGridTotal(string variableName, string traitValue, int[] functionalGroups, List <uint[]> cellIndices, string stateVariableType, MadingleyModelInitialisation initialisation) { double tempVal = 0; double[,] TempStateVariable = this.GetStateVariableGrid(variableName, traitValue, functionalGroups, cellIndices, stateVariableType, initialisation); // Loop through and sum values across a grid, excluding missing values for (int ii = 0; ii < cellIndices.Count; ii++) { tempVal += TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]]; } return(tempVal); }
/// <summary> /// Initializes the ecosystem model /// </summary> /// <param name="initialisation">An instance of the model initialisation class</param> /// <param name="outputFilesSuffix">The suffix to be applied to all outputs from this model run</param> /// <param name="simulation">The index of the simulation being run</param> /// <param name="modelState">Existing model state or null</param> public MadingleyModel( MadingleyModelInitialisation initialisation, string outputFilesSuffix, int simulation, Madingley.Common.ModelState modelState) { this.ModelInitialisation = initialisation; var scenarioIndex = 0; var globalModelTimeStepUnit = initialisation.GlobalModelTimeStepUnit; this.GlobalDiagnosticVariables = new SortedList<string, double>(modelState.GlobalDiagnosticVariables); var gridCells = Converters.ConvertGridCells(modelState.GridCells); // Assign the properties for this model run AssignModelRunProperties(initialisation, outputFilesSuffix);
public OutputGrid(string outputDetail, MadingleyModelInitialisation modelInitialisation) { // Set the output path _OutputPath = modelInitialisation.OutputPath; // Initialise the grid viewer GridViewer = new ViewGrid(); // Set the output detail level if (outputDetail == "low") { ModelOutputDetail = OutputDetailLevel.Low; } else if (outputDetail == "medium") { ModelOutputDetail = OutputDetailLevel.Medium; } else if (outputDetail == "high") { ModelOutputDetail = OutputDetailLevel.High; } else { Debug.Fail("Specified output detail level is not valid, must be 'low', 'medium' or 'high'"); } // Get whether to track marine specifics OutputMetrics = modelInitialisation.OutputMetrics; //Initialise the EcosystemMetrics class Metrics = new EcosytemMetrics(); // Initialise the data converter DataConverter = new ArraySDSConvert(); // Initialise the SDS object creator SDSCreator = new CreateSDSObject(); // Set the local variable designating whether to display live outputs during this model run if (modelInitialisation.LiveOutputs) { LiveOutputs = true; } Utils = new UtilityFunctions(); }
/// <summary> /// Set up the tracker for outputing properties of the eating process /// </summary> /// <param name="numLats">The number of latitudes in the model grid</param> /// <param name="numLons">The number of longitudes in the model grid</param> /// <param name="trophicFlowsFilename">The filename to write data on trophic flows to</param> /// <param name="outputFilesSuffix">The suffix to apply to output files from this simulation</param> /// <param name="outputPath">The file path to write all outputs to</param> /// <param name="cellIndex">The index of the current cell within the list of all grid cells in this simulation</param> /// <param name="initialisation">The instance of the MadingleyModelInitialisation class for this simulation</param> /// <param name="MarineCell">Whether the current cell is a marine cell</param> public EatingTracker(uint numLats, uint numLons, string trophicFlowsFilename, string outputFilesSuffix, string outputPath, int cellIndex, MadingleyModelInitialisation initialisation, Boolean MarineCell) { this.FileName = outputPath + trophicFlowsFilename + outputFilesSuffix + "_Cell" + cellIndex + ".txt"; using (var TrophicFlowsWriter = new StreamWriter(this.FileName)) { TrophicFlowsWriter.WriteLine("Latitude\tLongitude\ttime_step\tfromIndex\ttoIndex\tmass_eaten_g"); } // Initialise array to hold mass flows among trophic levels if (initialisation.TrackMarineSpecifics && MarineCell) // 0 = autotrophs, 1 = non-planktonic herbivores, 2 = non-planktonic omnivores, 3 = non-planktonic carnivores, 4 = obligate zooplankton, 5 = non-obligate zooplankton, 6 = baleen whales TrophicMassFlows = new double[numLats, numLons, 7, 7]; else TrophicMassFlows = new double[numLats, numLons, 4, 4]; }
/// <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> /// Sets up the model outputs /// </summary> /// <param name="initialisation">An instance of the model initialisation class</param> /// <param name="simulation">The index of the simulation being run</param> /// <param name="scenarioIndex">The index of the scenario being run</param> public void SetUpOutputs(MadingleyModelInitialisation initialisation, int simulation, int scenarioIndex) { // Initialise the global outputs GlobalOutputs = new OutputGlobal(InitialisationFileStrings["OutputDetail"], initialisation); // Create new outputs class instances (if the model is run for the whold model grid then select the grid view for the live output, // if the model is run for specific locations then use the graph view) if (SpecificLocations) { // Initialise the vector of outputs instances CellOutputs = new OutputCell[_CellList.Count]; for (int i = 0; i < _CellList.Count; i++) { CellOutputs[i] = new OutputCell(InitialisationFileStrings["OutputDetail"], initialisation, i); } #if false // Spawn a dataset viewer instance for each cell to display live model results if (initialisation.LiveOutputs) { for (int i = 0; i < _CellList.Count; i++) { CellOutputs[i].SpawnDatasetViewer(NumTimeSteps); } } #endif } else { GridOutputs = new OutputGrid(InitialisationFileStrings["OutputDetail"], initialisation); #if false // Spawn dataset viewer to display live grid results if (initialisation.LiveOutputs) { GridOutputs.SpawnDatasetViewer(); } #endif } }
/// <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> /// Constructor for Dispersal: fills the list of available implementations of dispersal /// </summary> public Dispersal(Boolean DrawRandomly, string globalModelTimeStepUnit, MadingleyModelInitialisation modelInitialisation) { // Initialise the list of dispersal implementations Implementations = new SortedList<string, IDispersalImplementation>(); // Add the basic advective dispersal implementation to the list of implementations AdvectiveDispersal AdvectiveDispersalImplementation = new AdvectiveDispersal(globalModelTimeStepUnit, DrawRandomly); Implementations.Add("basic advective dispersal", AdvectiveDispersalImplementation); // Add the basic advective dispersal implementation to the list of implementations DiffusiveDispersal DiffusiveDispersalImplementation = new DiffusiveDispersal(globalModelTimeStepUnit, DrawRandomly); Implementations.Add("basic diffusive dispersal", DiffusiveDispersalImplementation); // Add the basic advective dispersal implementation to the list of implementations ResponsiveDispersal ResponsiveDispersalImplementation = new ResponsiveDispersal(globalModelTimeStepUnit, DrawRandomly); Implementations.Add("basic responsive dispersal", ResponsiveDispersalImplementation); // Get the weight threshold below which organisms are dispersed planktonically PlanktonThreshold = modelInitialisation.PlanktonDispersalThreshold; }
public OutputModelState(MadingleyModelInitialisation modelInitialisation, string suffix, int simulation) { //Initialise output path and variables // Set the output path _OutputPath = modelInitialisation.OutputPath; // Initialise the data converter DataConverter = new ArraySDSConvert(); // Initialise the SDS object creator SDSCreator = new CreateSDSObject(); StateWriter = new StreamWriter(_OutputPath + "State" + suffix + simulation.ToString() + ".txt"); // Create a threadsafe textwriter to write outputs to the Maturity stream SyncStateWriter = TextWriter.Synchronized(StateWriter); SyncStateWriter.WriteLine("TimeStep\tLatitude\tLongitude\tID" + "\tFunctionalGroup\tJuvenileMass\tAdultMass\tIndividualBodyMass\tCohortAbundance\tBirthTimeStep" + "\tMaturityTimeStep\tLogOptimalPreyBodySizeRatio\tMaximumAchievedBodyMass\tTrophicIndex\tProportionTimeActive"); Simulation = simulation; }
/// <summary> /// Set up the tracker for outputing properties of the eating process /// </summary> /// <param name="numLats">The number of latitudes in the model grid</param> /// <param name="numLons">The number of longitudes in the model grid</param> /// <param name="trophicFlowsFilename">The filename to write data on trophic flows to</param> /// <param name="outputFilesSuffix">The suffix to apply to output files from this simulation</param> /// <param name="outputPath">The file path to write all outputs to</param> /// <param name="cellIndex">The index of the current cell within the list of all grid cells in this simulation</param> /// <param name="initialisation">The instance of the MadingleyModelInitialisation class for this simulation</param> /// <param name="MarineCell">Whether the current cell is a marine cell</param> public EatingTracker(uint numLats, uint numLons, string trophicFlowsFilename, string outputFilesSuffix, string outputPath, int cellIndex, MadingleyModelInitialisation initialisation, Boolean MarineCell) { this.FileName = outputPath + trophicFlowsFilename + outputFilesSuffix + "_Cell" + cellIndex + ".txt"; using (var TrophicFlowsWriter = new StreamWriter(this.FileName)) { TrophicFlowsWriter.WriteLine("Latitude\tLongitude\ttime_step\tfromIndex\ttoIndex\tmass_eaten_g"); } // Initialise array to hold mass flows among trophic levels if (initialisation.TrackMarineSpecifics && MarineCell) { // 0 = autotrophs, 1 = non-planktonic herbivores, 2 = non-planktonic omnivores, 3 = non-planktonic carnivores, 4 = obligate zooplankton, 5 = non-obligate zooplankton, 6 = baleen whales TrophicMassFlows = new double[numLats, numLons, 7, 7]; } else { TrophicMassFlows = new double[numLats, numLons, 4, 4]; } }
public OutputModelState(MadingleyModelInitialisation modelInitialisation, string suffix, int simulation) { //Initialise output path and variables // Set the output path _OutputPath = modelInitialisation.OutputPath; // Initialise the data converter DataConverter = new ArraySDSConvert(); // Initialise the SDS object creator SDSCreator = new CreateSDSObject(); StateWriter = new StreamWriter(_OutputPath + "State" + suffix + simulation.ToString() + ".txt"); // Create a threadsafe textwriter to write outputs to the Maturity stream SyncStateWriter = TextWriter.Synchronized(StateWriter); SyncStateWriter.WriteLine("TimeStep\tLatitude\tLongitude\tID" + "\tFunctionalGroup\tJuvenileMass\tAdultMass\tIndividualBodyMass\tCohortAbundance\tReproductiveMass\tBirthTimeStep" + "\tMaturityTimeStep\tLogOptimalPreyBodySizeRatio\tMaximumAchievedBodyMass\tTrophicIndex\tProportionTimeActive"); Simulation = simulation; }
/// <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; }
/// <summary> /// Constructor for Dispersal: fills the list of available implementations of dispersal /// </summary> public Dispersal(Boolean DrawRandomly, string globalModelTimeStepUnit, MadingleyModelInitialisation modelInitialisation) { // Initialise the list of dispersal implementations Implementations = new SortedList <string, IDispersalImplementation>(); // Add the basic advective dispersal implementation to the list of implementations AdvectiveDispersal AdvectiveDispersalImplementation = new AdvectiveDispersal(globalModelTimeStepUnit, DrawRandomly); Implementations.Add("basic advective dispersal", AdvectiveDispersalImplementation); // Add the basic advective dispersal implementation to the list of implementations DiffusiveDispersal DiffusiveDispersalImplementation = new DiffusiveDispersal(globalModelTimeStepUnit, DrawRandomly); Implementations.Add("basic diffusive dispersal", DiffusiveDispersalImplementation); // Add the basic advective dispersal implementation to the list of implementations ResponsiveDispersal ResponsiveDispersalImplementation = new ResponsiveDispersal(globalModelTimeStepUnit, DrawRandomly); Implementations.Add("basic responsive dispersal", ResponsiveDispersalImplementation); // Get the weight threshold below which organisms are dispersed planktonically PlanktonThreshold = modelInitialisation.PlanktonDispersalThreshold; }
public OutputModelState(MadingleyModelInitialisation modelInitialisation, string suffix, int simulation) { //Initialise output path and variables // Set the output path _OutputPath = modelInitialisation.OutputPath; // Initialise the data converter DataConverter = new ArraySDSConvert(); // Initialise the SDS object creator SDSCreator = new CreateSDSObject(); this.FileName = _OutputPath + "State" + suffix + simulation.ToString() + ".txt"; using (var StateWriter = new StreamWriter(this.FileName)) { StateWriter.WriteLine("TimeStep\tLatitude\tLongitude\tID" + "\tFunctionalGroup\tJuvenileMass\tAdultMass\tIndividualBodyMass\tCohortAbundance\tBirthTimeStep" + "\tMaturityTimeStep\tLogOptimalPreyBodySizeRatio\tMaximumAchievedBodyMass\tTrophicIndex\tProportionTimeActive"); } Simulation = simulation; }
/// <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); } } }
/// <summary> /// Generates the initial outputs for this model run /// </summary> /// <param name="outputFilesSuffix">The suffix to be applied to all outputs from this model run</param> /// <param name="initialisation">The Madingley Model initialisation</param> /// <param name="month">The current month in the model run</param> public void InitialOutputs(string outputFilesSuffix, MadingleyModelInitialisation initialisation, uint month) { // Set up global outputs for all model runs GlobalOutputs.SetupOutputs(NumTimeSteps, EcosystemModelGrid, OutputFilesSuffix); // Create initial global outputs GlobalOutputs.InitialOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, GlobalDiagnosticVariables, initialisation); // Temporary Boolean varExists; if (SpecificLocations) { for (int i = 0; i < _CellList.Count; i++) { // Set up grid cell outputs CellOutputs[i].SetUpOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, NumTimeSteps, OutputFilesSuffix, _CellList, i, EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0); // Create initial grid cell outputs CellOutputs[i].InitialOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, i, GlobalDiagnosticVariables, NumTimeSteps, initialisation, month, EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0); } } else { // Set up grid outputs GridOutputs.SetupOutputs(EcosystemModelGrid, OutputFilesSuffix, NumTimeSteps, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions); // Create initial grid outputs GridOutputs.InitialOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, initialisation); } }
/// <summary> /// Runs a single simulation of the Madingley model /// </summary> /// <param name="scenarios">Parameter information and simulation number for all scenarios to be run</param> /// <param name="scenarioIndex">The index of the scenario to be run in this simulation</param> /// <param name="initialiseMadingley">Model initialization information for all simulations</param> /// <param name="outputFileSuffix">Suffix to be applied to the names of files written out by this simulation</param> /// <param name="simulation">The index of the simulation being run</param> public void RunSimulation(ScenarioParameterInitialisation scenarios, int scenarioIndex, MadingleyModelInitialisation initialiseMadingley, string outputFileSuffix, int simulation) { // Declare an instance of the class that runs a Madingley model simulation MadingleyModel MadingleyEcosystemModel; // Declare and start a timer StopWatch s = new StopWatch(); s.Start(); StopWatch t = new StopWatch(); t.Start(); // Initialize the instance of MadingleyModel MadingleyEcosystemModel = new MadingleyModel(initialiseMadingley, scenarios, scenarioIndex, outputFileSuffix, initialiseMadingley.GlobalModelTimeStepUnit, simulation); t.Stop(); // Run the simulation MadingleyEcosystemModel.RunMadingley(initialiseMadingley); // Stop the timer and write out the time taken to run this simulation s.Stop(); Console.WriteLine("Model run finished"); Console.WriteLine("Total elapsed time was {0} seconds", s.GetElapsedTimeSecs()); Console.WriteLine("Model setup time was {0} seconds", t.GetElapsedTimeSecs()); Console.WriteLine("Model run time was {0} seconds", s.GetElapsedTimeSecs() - t.GetElapsedTimeSecs()); }
/// <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> /// Run ecological processes for stocks in a specified grid cell /// </summary> /// <param name="latCellIndex">The latitudinal index of the cell to run stock ecology for</param> /// <param name="lonCellIndex">The longitudinal index of the cell to run stock ecology for</param> /// <param name="workingGridCellStocks">A copy of the cohorts in the current grid cell</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> private void RunWithinCellStockEcology(uint latCellIndex, uint lonCellIndex, GridCellStockHandler workingGridCellStocks, int cellIndex, MadingleyModelInitialisation initialisation) { // Create a local instance of the stock ecology class EcologyStock MadingleyEcologyStock = new EcologyStock(); // Initialise stock ecology MadingleyEcologyStock.InitializeEcology(); //The location of the acting stock int[] ActingStock = new int[2]; // Get the list of functional group indices for autotroph stocks int[] AutotrophStockFunctionalGroups = StockFunctionalGroupDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "Autotroph", false). ToArray(); // Loop over autotroph functional groups foreach (int FunctionalGroup in AutotrophStockFunctionalGroups) { for (int ll = 0; ll < workingGridCellStocks[FunctionalGroup].Count; ll++) { // Get the position of the acting stock ActingStock[0] = FunctionalGroup; ActingStock[1] = ll; // Run stock ecology MadingleyEcologyStock.RunWithinCellEcology(workingGridCellStocks, ActingStock, EcosystemModelGrid.GetCellEnvironment( latCellIndex, lonCellIndex), EnvironmentalDataUnits, _HumanNPPScenario, StockFunctionalGroupDefinitions, CurrentTimeStep, NumBurninSteps, NumImpactSteps, initialisation.RecoveryTimeSteps, initialisation.InstantaneousTimeStep, initialisation.NumInstantaneousTimeStep, _GlobalModelTimeStepUnit, ProcessTrackers[cellIndex].TrackProcesses, ProcessTrackers[cellIndex], TrackGlobalProcesses, CurrentMonth, InitialisationFileStrings["OutputDetail"],SpecificLocations,((initialisation.ImpactCellIndices.Contains((uint)cellIndex) || (initialisation.ImpactAll)))); } } }
/// <summary> /// Sets up the model outputs /// </summary> /// <param name="initialisation">An instance of the model initialisation class</param> /// <param name="simulation">The index of the simulation being run</param> /// <param name="scenarioIndex">The index of the scenario being run</param> public void SetUpOutputs(MadingleyModelInitialisation initialisation, int simulation, int scenarioIndex) { // Initialise the global outputs GlobalOutputs = new OutputGlobal(InitialisationFileStrings["OutputDetail"], initialisation); // Create new outputs class instances (if the model is run for the whold model grid then select the grid view for the live output, // if the model is run for specific locations then use the graph view) if (SpecificLocations) { // Initialise the vector of outputs instances CellOutputs = new OutputCell[_CellList.Count]; for (int i = 0; i < _CellList.Count; i++) { CellOutputs[i] = new OutputCell(InitialisationFileStrings["OutputDetail"], initialisation, i); } // Spawn a dataset viewer instance for each cell to display live model results if (initialisation.LiveOutputs) { for (int i = 0; i < _CellList.Count; i++) { CellOutputs[i].SpawnDatasetViewer(NumTimeSteps); } } } else { GridOutputs = new OutputGrid(InitialisationFileStrings["OutputDetail"], initialisation); // Spawn dataset viewer to display live grid results if (initialisation.LiveOutputs) { GridOutputs.SpawnDatasetViewer(); } } }
/// <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> /// 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; }
/// <summary> /// Write flows of matter among trophic levels to the output file at the end of the time step /// </summary> /// <param name="currentTimeStep">The current time step</param> /// <param name="numLats">The latitudinal dimension of the model grid in number of cells</param> /// <param name="numLons">The longitudinal dimension of the model grid in number of cells</param> /// <param name="initialisation">The Madingley Model initialisation</param> /// <param name="MarineCell">Whether the current cell is a marine cell</param> public void WriteTrophicFlows(uint currentTimeStep, uint numLats, uint numLons, MadingleyModelInitialisation initialisation, Boolean MarineCell) { using (var TrophicFlowsWriter = File.AppendText(this.FileName)) { for (int lat = 0; lat < numLats; lat++) { for (int lon = 0; lon < numLons; lon++) { for (int i = 0; i < TrophicMassFlows.GetLength(2); i++) { for (int j = 0; j < TrophicMassFlows.GetLength(3); j++) { if (TrophicMassFlows[lat, lon, i, j] > 0) { TrophicFlowsWriter.WriteLine(Convert.ToString(lat) + '\t' + Convert.ToString(lon) + '\t' + Convert.ToString(currentTimeStep) + '\t' + Convert.ToString(i) + '\t' + Convert.ToString(j) + '\t' + Convert.ToString(TrophicMassFlows[lat, lon, i, j])); } } } } } } // Initialise array to hold mass flows among trophic levels if (initialisation.TrackMarineSpecifics && MarineCell) { TrophicMassFlows = new double[numLats, numLons, 7, 7]; } else { TrophicMassFlows = new double[numLats, numLons, 4, 4]; } }
/// <summary> /// Runs the specified number of simulations for each of the specified scenarios /// </summary> /// <param name="simulationInitialisationFilename">Filename of the file from which to read initialisation information</param> /// <param name="scenarios">Contains scenario information for this set of simulations</param> /// <param name="outputPath">The path to which outputs should be written</param> public void RunAllSimulations(string simulationInitialisationFilename, string definitionsFilename, string outputsFilename, ScenarioParameterInitialisation scenarios, string outputPath) { // Declare an instance of the class for initializing the Madingley model MadingleyModelInitialisation InitialiseMadingley = new MadingleyModelInitialisation(simulationInitialisationFilename, definitionsFilename, outputsFilename, outputPath); // Specify the output path in this instance InitialiseMadingley.OutputPath = outputPath; // List to hold the names of the scenarios to run List <string> ScenarioNames = new List <string>(); // String variable to hold the index suffix to apply to output files for a given simulation string OutputFilesSuffix; // Loop over scenario names and add the name of the scenario to the list of scenarion names foreach (var scenario in scenarios.scenarioParameters) { ScenarioNames.Add(scenario.Item1); } // Check whether there is only one simulation to run if (scenarios.scenarioNumber == 1 && scenarios.scenarioParameters.ElementAt(scenarios.scenarioNumber - 1).Item2 == 1) { // For a single simulation // Set-up the suffix for the output files OutputFilesSuffix = "_"; // Loop over the parameters for this scenario for (int i = 0; i < ScenarioNames.Count; i++) { // Add the parameter information to the suffix for this simulation OutputFilesSuffix += ScenarioNames[0] + "_"; } // Add a zero index to the end of the suffix OutputFilesSuffix += "0"; //Run the simulation RunSimulation(scenarios, 0, InitialiseMadingley, OutputFilesSuffix, 0); } else { if (InitialiseMadingley.RunSimulationsInParallel) { // Loop over specified scenarios iteratively for (int ScenarioIndex = 0; ScenarioIndex < scenarios.scenarioNumber; ScenarioIndex++) { //Create an array of new MadingleyModel instances for simulations under this scenario combination MadingleyModel[] MadingleyEcosystemModels = new MadingleyModel [scenarios.scenarioParameters.ElementAt(ScenarioIndex).Item2]; for (int simulation = 0; simulation < scenarios.scenarioParameters.ElementAt(ScenarioIndex).Item2; simulation++) { // Set up the suffix for the output files OutputFilesSuffix = "_"; // Add the scenario label to the suffix for the output files OutputFilesSuffix += ScenarioNames[ScenarioIndex] + "_"; // Add the simulation index number to the suffix OutputFilesSuffix += simulation.ToString(); // Initialize the instance of MadingleyModel MadingleyEcosystemModels[simulation] = new MadingleyModel(InitialiseMadingley, scenarios, ScenarioIndex, OutputFilesSuffix, InitialiseMadingley.GlobalModelTimeStepUnit, simulation); } // Loop over the specified number of simulations for each scenario //for (int simulation = 0; simulation< scenarios.scenarioSimulationsNumber[ScenarioIndex]; simulation++) Parallel.For(0, scenarios.scenarioParameters.ElementAt(ScenarioIndex).Item2, simulation => { // Declare and start a timer StopWatch s = new StopWatch(); s.Start(); // Run the simulation MadingleyEcosystemModels[simulation].RunMadingley(InitialiseMadingley); // Stop the timer and write out the time taken to run this simulation s.Stop(); Console.WriteLine("Model run finished"); Console.WriteLine("Total elapsed time was {0} seconds", s.GetElapsedTimeSecs()); }); } } else { //Run simulations sequentially // Loop over specified scenarios for (int ScenarioIndex = 0; ScenarioIndex < scenarios.scenarioNumber; ScenarioIndex++) { // Loop over the specified number of simulations for each scenario for (int simulation = 0; simulation < scenarios.scenarioParameters.ElementAt(ScenarioIndex).Item2; simulation++) { // Set up the suffix for the output files OutputFilesSuffix = "_"; // Add the scenario label to the suffix for the output files OutputFilesSuffix += ScenarioNames[ScenarioIndex] + "_"; // Add the simulation index number to the suffix OutputFilesSuffix += simulation.ToString(); // Run the current simulation RunSimulation(scenarios, ScenarioIndex, InitialiseMadingley, OutputFilesSuffix, simulation); } } } } }
/// <summary> /// Write trophic flow data from the current time step to file /// </summary> /// <param name="currentTimeStep">The current model time step</param> /// <param name="numLats">The number of grid cells, latitudinally, in the simulation</param> /// <param name="numLons">The number of grid cells, longitudinally, in the simulation</param> /// <param name="initialisation">The Madingley Model initialisation</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> public void WriteTimeStepTrophicFlows(uint currentTimeStep, uint numLats, uint numLons, MadingleyModelInitialisation initialisation, Boolean marineCell) { _TrackEating.WriteTrophicFlows(currentTimeStep, numLats, numLons, initialisation, marineCell); }
/// <summary> /// Track the flow of mass between trophic levels during a herbivory event /// </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="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 latIndex, uint lonIndex, int toFunctionalGroup, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, double massEaten, double predatorBodyMass, MadingleyModelInitialisation initialisation, Boolean marineCell) { _TrackEating.RecordHerbivoryTrophicFlow(latIndex, lonIndex, toFunctionalGroup, cohortFunctionalGroupDefinitions, massEaten, predatorBodyMass, initialisation, marineCell); }
/// <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); } } }
/// <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> /// 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 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> /// 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> /// A method to run the main ecosystem model loop in parallel (latitudinal strips) /// </summary> /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param> /// <param name="partial">A threadlockedparallelvariable that is used to pass global diagnostic information back with locking or race conditions</param> /// <param name="dispersalOnly">Whether to run dispersal only (i.e. to turn all other ecological processes off</param> /// <param name="initialisation">The Madingley Model intialisation</param> /// <remarks>Note that variables and instances of classes that are written to within this method MUST be local within this method to prevent /// race issues and multiple threads attempting to write to the same variable when running the program in parallel</remarks> public void RunCell(int cellIndex, ThreadLockedParallelVariables partial, Boolean dispersalOnly, MadingleyModelInitialisation initialisation) { // Apply any climate change impacts ClimateChangeSimulator.ApplyTemperatureScenario( EcosystemModelGrid.GetCellEnvironment(_CellList[cellIndex][0], _CellList[cellIndex][1]), _TemperatureScenario,CurrentTimeStep,CurrentMonth,NumBurninSteps,NumImpactSteps, ((initialisation.ImpactCellIndices.Contains((uint)cellIndex) || initialisation.ImpactAll))); // Create a temporary internal copy of the grid cell cohorts GridCellCohortHandler WorkingGridCellCohorts = EcosystemModelGrid.GetGridCellCohorts(_CellList[cellIndex][0], _CellList[cellIndex][1]); // Create a temporary internal copy of the grid cell stocks GridCellStockHandler WorkingGridCellStocks = EcosystemModelGrid.GetGridCellStocks(_CellList[cellIndex][0], _CellList[cellIndex][1]); // Run stock ecology RunWithinCellStockEcology(_CellList[cellIndex][0], _CellList[cellIndex][1], WorkingGridCellStocks, cellIndex, initialisation); // Run within cell ecology if we are not doing dispersal only if (dispersalOnly) { // Run cohort ecology RunWithinCellDispersalOnly(_CellList[cellIndex][0], _CellList[cellIndex][1], partial, WorkingGridCellCohorts, WorkingGridCellStocks); } else { // Run cohort ecology RunWithinCellCohortEcology(_CellList[cellIndex][0], _CellList[cellIndex][1], partial, WorkingGridCellCohorts, WorkingGridCellStocks, InitialisationFileStrings["OutputDetail"], cellIndex, initialisation); } // Apply any direct harvesting impacts HarvestingSimulator.RemoveHarvestedIndividuals(WorkingGridCellCohorts, _HarvestingScenario, CurrentTimeStep, NumBurninSteps, NumImpactSteps,NumTimeSteps, EcosystemModelGrid.GetCellEnvironment(_CellList[cellIndex][0], _CellList[cellIndex][1]), (initialisation.ImpactCellIndices.Contains((uint)cellIndex) || initialisation.ImpactAll), _GlobalModelTimeStepUnit, CohortFunctionalGroupDefinitions); // For runs with specific locations and where track processes has been specified, write out mass flows data and reset the mass flow tracker // for the next time step if (SpecificLocations && ProcessTrackers[cellIndex].TrackProcesses) { ProcessTrackers[cellIndex].EndTimeStepPredationTracking(CurrentTimeStep); ProcessTrackers[cellIndex].EndTimeStepHerbvioryTracking(CurrentTimeStep); } }
/// <summary> /// Run processes for cells sequentially /// </summary> public void RunCellsSequentially(MadingleyModelInitialisation initialisation) { // Instantiate a class to hold thread locked global diagnostic variables ThreadLockedParallelVariables singleThreadDiagnostics = new ThreadLockedParallelVariables { Extinctions = 0, Productions = 0, NextCohortIDThreadLocked = NextCohortID }; if (initialisation.RunRealm == "") { for (int ii = 0; ii < _CellList.Count; ii++) { RunCell(ii, singleThreadDiagnostics, initialisation.DispersalOnly, initialisation); } } else { if (initialisation.RunRealm == "marine") { for (int ii = 0; ii < _CellList.Count; ii++) { if (EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["Realm"][0] == 2.0) RunCell(ii, singleThreadDiagnostics, initialisation.DispersalOnly, initialisation); } } else if (initialisation.RunRealm == "terrestrial") { for (int ii = 0; ii < _CellList.Count; ii++) { if (EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["Realm"][0] == 1.0) RunCell(ii, singleThreadDiagnostics, initialisation.DispersalOnly, initialisation); } } else { Console.WriteLine("Run Single Realm needs to be 'marine', 'terrestrial', or blank"); Console.ReadKey(); } } // Update the variable tracking cohort unique IDs NextCohortID = singleThreadDiagnostics.NextCohortIDThreadLocked; // Take the results from the thread local variables and apply to the global diagnostic variables GlobalDiagnosticVariables["NumberOfCohortsExtinct"] = singleThreadDiagnostics.Extinctions - singleThreadDiagnostics.Combinations; GlobalDiagnosticVariables["NumberOfCohortsProduced"] = singleThreadDiagnostics.Productions; GlobalDiagnosticVariables["NumberOfCohortsInModel"] = GlobalDiagnosticVariables["NumberOfCohortsInModel"] + singleThreadDiagnostics.Productions - singleThreadDiagnostics.Extinctions; GlobalDiagnosticVariables["NumberOfCohortsCombined"] = singleThreadDiagnostics.Combinations; }
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> /// Run the global ecosystem model /// </summary> /// <param name="initialisation">The initialization details for the current set of model simulations</param> public void RunMadingley(MadingleyModelInitialisation initialisation) { // Write out model run details to the console Console.WriteLine("Running model"); Console.WriteLine("Number of time steps is: {0}", NumTimeSteps); Console.WriteLine(" "); Console.WriteLine(" "); // Temporary variable Boolean varExists; // Run the model for (UInt32 hh = 0; hh < NumTimeSteps; hh += 1) { Console.WriteLine("Running time step {0}...",hh + 1); // Start the timer TimeStepTimer.Start(); // Get current time step and month CurrentTimeStep = hh; CurrentMonth = Utilities.GetCurrentMonth(hh,_GlobalModelTimeStepUnit); // Initialise cross grid cell ecology MadingleyEcologyCrossGridCell.InitializeCrossGridCellEcology(_GlobalModelTimeStepUnit, DrawRandomly, initialisation); EcologyTimer.Start(); // Loop over grid cells and run biological processes if (RunGridCellsInParallel) { // Run cells in parallel RunCellsInParallel(initialisation); } else { // Run cells in sequence RunCellsSequentially(initialisation); } EcologyTimer.Stop(); Console.WriteLine("Within grid ecology took: {0}" ,EcologyTimer.GetElapsedTimeSecs()); // Run the garbage collector. Note that it works in the background so may take a little while // Needs to be done to ensure cohorts are deleted properly GC.Collect(); if (TrackGlobalProcesses.TrackProcesses) { for (uint ii = 0; ii < StockFunctionalGroupDefinitions.GetNumberOfFunctionalGroups(); ii++) { TrackGlobalProcesses.StoreNPPGrid(hh, ii); TrackGlobalProcesses.StoreHANPPGrid(hh, ii); } } EcologyTimer.Start(); // Run cross grid cell ecology RunCrossGridCellEcology(ref Dispersals, initialisation.DispersalOnly, initialisation); EcologyTimer.Stop(); Console.WriteLine("Across grid ecology took: {0}", EcologyTimer.GetElapsedTimeSecs()); // Run the garbage collector. Note that it works in the background so may take a little while // Needs to be done here to ensure cohorts are deleted properly GC.Collect(); // Stop the timer TimeStepTimer.Stop(); OutputTimer.Start(); // Write the global outputs for this time step GlobalOutputs.TimeStepOutputs(EcosystemModelGrid, CurrentTimeStep, CurrentMonth, TimeStepTimer,CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions,_CellList,GlobalDiagnosticVariables, initialisation); OutputTimer.Stop(); Console.WriteLine("Global Outputs took: {0}", OutputTimer.GetElapsedTimeSecs()); OutputTimer.Start(); if (SpecificLocations) { // Loop over grid cells and write (a) time step outputs, and (b) trophic flow data (if process tracking is on) for (int i = 0; i < _CellList.Count; i++) { // Write out the grid cell outputs for this time step CellOutputs[i].TimeStepOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, i, GlobalDiagnosticVariables, TimeStepTimer, NumTimeSteps, CurrentTimeStep, initialisation, CurrentMonth, EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0); // Write out trophic flow data for this time step if(ProcessTrackers[i].TrackProcesses) ProcessTrackers[i].WriteTimeStepTrophicFlows(CurrentTimeStep, EcosystemModelGrid.NumLatCells, EcosystemModelGrid.NumLonCells, initialisation, EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0); } } else { // Write out grid outputs for this time step GridOutputs.TimeStepOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, CurrentTimeStep, initialisation); } OutputTimer.Stop(); Console.WriteLine("Cell/Grid Outputs took: {0}", OutputTimer.GetElapsedTimeSecs()); // Write the results of dispersal to the console Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Number of cohorts that dispersed this time step: {0}\n", Dispersals); Console.ForegroundColor = ConsoleColor.White; Dispersals = 0; if (OutputModelStateTimestep.Contains(hh)) { OutputTimer.Start(); Console.WriteLine("Outputting model state"); //Writing to text based output WriteModelState.OutputCurrentModelState( EcosystemModelGrid, _CellList, hh); //WriteModelState.OutputCurrentModelState(EcosystemModelGrid,CohortFunctionalGroupDefinitions, _CellList, CurrentTimeStep, initialisation.MaxNumberOfCohorts,"ModelState"); OutputTimer.Stop(); // Write the results of dispersal to the console Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Writing model state took: {0}", OutputTimer.GetElapsedTimeSecs()); Console.ForegroundColor = ConsoleColor.White; } } if (TrackGlobalProcesses.TrackProcesses) TrackGlobalProcesses.CloseNPPFile(); // Loop over cells and close process trackers for (int i = 0; i < _CellList.Count; i++) { if (ProcessTrackers[i].TrackProcesses) ProcessTrackers[i].CloseStreams(SpecificLocations); } // Write the final global outputs GlobalOutputs.FinalOutputs(); WriteModelState.CloseStreams(); if (SpecificLocations) { // Loop over grid cells and write the final grid cell outputs for (int i = 0; i < _CellList.Count; i++) { CellOutputs[i].FinalOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, i, GlobalDiagnosticVariables, initialisation, CurrentMonth, EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0); } } else { // Write the final grid outputs GridOutputs.FinalOutputs(); } }
/// <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> /// Run 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="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 eating</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) { PreviousTrophicIndex = gridCellCohorts[actingCohort].TrophicIndex; //Reset this cohort's trohic index ready for calculation across its feeding this timetsstep gridCellCohorts[actingCohort].TrophicIndex = 0.0; // Get the nutrition source (herbivory, carnivory or omnivory) of the acting cohort string NutritionSource = madingleyCohortDefinitions.GetTraitNames("Nutrition source", gridCellCohorts[actingCohort].FunctionalGroupIndex); // Switch to the appropriate eating process(es) given the cohort's nutrition source switch (NutritionSource) { case "herbivore": // Get the assimilation efficiency for herbivory for this cohort from the functional group definitions Implementations["revised herbivory"].AssimilationEfficiency = madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup ("herbivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex); // Get the proportion of time spent eating for this cohort from the functional group definitions Implementations["revised herbivory"].ProportionTimeEating = gridCellCohorts[actingCohort].ProportionTimeActive; // Calculate the potential biomass available from herbivory if (cellEnvironment["Realm"][0] == 2.0) { Implementations["revised herbivory"].GetEatingPotentialMarine (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions); } else { Implementations["revised herbivory"].GetEatingPotentialTerrestrial (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions); } // Run herbivory to apply changes in autotroph biomass from herbivory and add biomass eaten to the delta arrays Implementations["revised herbivory"].RunEating (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, trackProcesses, currentTimestep, specificLocations, outputDetail, initialisation); break; case "carnivore": // Get the assimilation efficiency for predation for this cohort from the functional group definitions Implementations["revised predation"].AssimilationEfficiency = madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup ("carnivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex); Implementations["revised predation"].ProportionTimeEating = gridCellCohorts[actingCohort].ProportionTimeActive; // Calculate the potential biomass available from predation if (cellEnvironment["Realm"][0] == 2.0) { Implementations["revised predation"].GetEatingPotentialMarine (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions); } else { Implementations["revised predation"].GetEatingPotentialTerrestrial (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions); } // Run predation to apply changes in prey biomass from predation and add biomass eaten to the delta arrays Implementations["revised predation"].RunEating (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, trackProcesses, currentTimestep, specificLocations, outputDetail, initialisation); break; case "omnivore": // Get the assimilation efficiency for predation for this cohort from the functional group definitions Implementations["revised predation"].AssimilationEfficiency = madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup ("carnivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex); // Get the assimilation efficiency for herbivory for this cohort from the functional group definitions Implementations["revised herbivory"].AssimilationEfficiency = madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup ("herbivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex); // Get the proportion of time spent eating and assign to both the herbivory and predation implementations double ProportionTimeEating = gridCellCohorts[actingCohort].ProportionTimeActive; Implementations["revised predation"].ProportionTimeEating = ProportionTimeEating; Implementations["revised herbivory"].ProportionTimeEating = ProportionTimeEating; // Calculate the potential biomass available from herbivory if (cellEnvironment["Realm"][0] == 2.0) { Implementations["revised herbivory"].GetEatingPotentialMarine (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions); } else { Implementations["revised herbivory"].GetEatingPotentialTerrestrial (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions); } // Calculate the potential biomass available from predation if (cellEnvironment["Realm"][0] == 2.0) { Implementations["revised predation"].GetEatingPotentialMarine (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions); } else { Implementations["revised predation"].GetEatingPotentialTerrestrial (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, madingleyCohortDefinitions, madingleyStockDefinitions); } // Calculate the total handling time for all expected kills from predation and expected plant matter eaten in herbivory TotalTimeToEatForOmnivores = Implementations["revised herbivory"].TimeUnitsToHandlePotentialFoodItems + Implementations["revised predation"].TimeUnitsToHandlePotentialFoodItems; // Assign this total time to the relevant variables in both herbviory and predation, so that actual amounts eaten are calculated correctly Implementations["revised herbivory"].TimeUnitsToHandlePotentialFoodItems = TotalTimeToEatForOmnivores; Implementations["revised predation"].TimeUnitsToHandlePotentialFoodItems = TotalTimeToEatForOmnivores; // Run predation to update prey cohorts and delta biomasses for the acting cohort Implementations["revised predation"].RunEating (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, trackProcesses, currentTimestep, specificLocations, outputDetail, initialisation); // Run herbivory to update autotroph biomass and delta biomasses for the acting cohort Implementations["revised herbivory"].RunEating (gridCellCohorts, gridCellStocks, actingCohort, cellEnvironment, deltas, madingleyCohortDefinitions, madingleyStockDefinitions, trackProcesses, currentTimestep, specificLocations, outputDetail, initialisation); break; default: // For nutrition source that are not supported, throw an error Debug.Fail("The model currently does not contain an eating model for nutrition source:" + NutritionSource); break; } // Check that the biomasses from predation and herbivory in the deltas is a number Debug.Assert(!double.IsNaN(deltas["biomass"]["predation"]), "BiomassFromEating is NaN"); Debug.Assert(!double.IsNaN(deltas["biomass"]["herbivory"]), "BiomassFromEating is NaN"); double biomassEaten = 0.0; if (madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("carnivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex) > 0) { biomassEaten += (deltas["biomass"]["predation"] / madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("carnivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex)); } if (madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("herbivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex) > 0) { biomassEaten += (deltas["biomass"]["herbivory"] / madingleyCohortDefinitions.GetBiologicalPropertyOneFunctionalGroup("herbivory assimilation", gridCellCohorts[actingCohort].FunctionalGroupIndex)); } if (biomassEaten > 0.0) { gridCellCohorts[actingCohort].TrophicIndex = 1 + (gridCellCohorts[actingCohort].TrophicIndex / (biomassEaten * gridCellCohorts[actingCohort].CohortAbundance)); } else { gridCellCohorts[actingCohort].TrophicIndex = PreviousTrophicIndex; } }
/// <summary> /// Generates the initial outputs for this model run /// </summary> /// <param name="outputFilesSuffix">The suffix to be applied to all outputs from this model run</param> /// <param name="initialisation">The Madingley Model initialisation</param> /// <param name="month">The current month in the model run</param> public void InitialOutputs(string outputFilesSuffix, MadingleyModelInitialisation initialisation, uint month) { // Set up global outputs for all model runs GlobalOutputs.SetupOutputs(NumTimeSteps, EcosystemModelGrid, OutputFilesSuffix); // Create initial global outputs GlobalOutputs.InitialOutputs(EcosystemModelGrid,CohortFunctionalGroupDefinitions,StockFunctionalGroupDefinitions,_CellList, GlobalDiagnosticVariables, initialisation); // Temporary Boolean varExists; if (SpecificLocations) { for (int i = 0; i < _CellList.Count; i++) { // Set up grid cell outputs CellOutputs[i].SetUpOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, NumTimeSteps, OutputFilesSuffix, _CellList, i, EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0); // Create initial grid cell outputs CellOutputs[i].InitialOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, i, GlobalDiagnosticVariables, NumTimeSteps, initialisation, month, EcosystemModelGrid.GetEnviroLayer("Realm", 0, _CellList[i][0], _CellList[i][1], out varExists) == 2.0); } } else { // Set up grid outputs GridOutputs.SetupOutputs(EcosystemModelGrid, OutputFilesSuffix, NumTimeSteps, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions); // Create initial grid outputs GridOutputs.InitialOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, _CellList, initialisation); } }
/// <summary> /// Gets a state variable density for specified functional groups of specified entity types in a specified grid cell /// </summary> /// <param name="variableName">The name of the variable to get: 'biomass' or 'abundance'</param> /// <param name="traitValue">The functional group trait value to get data for</param> /// <param name="functionalGroups">The functional group indices to get the state variable for</param> /// <param name="latCellIndex">The latitudinal index of the cell</param> /// <param name="lonCellIndex">The longitudinal index of the cell</param> /// <param name="stateVariableType">The type of entity to return the state variable for: 'stock' or 'cohort'</param> /// <param name="modelInitialisation">The Madingley Model initialisation</param> /// <returns>The state variable density for specified functional groups of specified entity types in a specified grid cell</returns> public double GetStateVariableDensity(string variableName, string traitValue, int[] functionalGroups, uint latCellIndex, uint lonCellIndex, string stateVariableType, MadingleyModelInitialisation modelInitialisation) { double returnValue = 0.0; switch (stateVariableType.ToLower()) { case "cohort": GridCellCohortHandler TempCohorts = InternalGrid[latCellIndex, lonCellIndex].GridCellCohorts; switch (variableName.ToLower()) { case "biomass": if (traitValue != "Zooplankton (all)") { foreach (int f in functionalGroups) { foreach (var item in TempCohorts[f]) { returnValue += ((item.IndividualBodyMass + item.IndividualReproductivePotentialMass) * item.CohortAbundance); } } } else { foreach (int f in functionalGroups) { foreach (var item in TempCohorts[f]) { if (item.IndividualBodyMass <= modelInitialisation.PlanktonDispersalThreshold) { returnValue += ((item.IndividualBodyMass + item.IndividualReproductivePotentialMass) * item.CohortAbundance); } } } } break; case "abundance": if (traitValue != "Zooplankton (all)") { foreach (int f in functionalGroups) { foreach (var item in TempCohorts[f]) { returnValue += item.CohortAbundance; } } } else { foreach (int f in functionalGroups) { foreach (var item in TempCohorts[f]) { if (item.IndividualBodyMass <= modelInitialisation.PlanktonDispersalThreshold) { returnValue += item.CohortAbundance; } } } } break; default: Debug.Fail("For cohorts, state variable name must be either 'biomass' or 'abundance'"); break; } break; case "stock": GridCellStockHandler TempStocks = InternalGrid[latCellIndex, lonCellIndex].GridCellStocks; switch (variableName.ToLower()) { case "biomass": foreach (int f in functionalGroups) { foreach (var item in TempStocks[f]) { returnValue += item.TotalBiomass; } } break; default: Debug.Fail("For stocks, state variable name must be 'biomass'"); break; } break; default: Debug.Fail("State variable type must be either 'cohort' or 'stock'"); break; } return(returnValue / (InternalGrid[latCellIndex, lonCellIndex].CellEnvironment["Cell Area"][0])); }
/// <summary> /// Run processes for cells in parallel /// </summary> public void RunCellsInParallel(MadingleyModelInitialisation initialisation) { // Create temporary variables to hold extinctions and productions in the parallel loop; int extinctions = 0, productions = 0, combinations = 0; if (initialisation.RunRealm == "") { // Run a parallel loop over rows Parallel.For(0, _CellList.Count, () => new ThreadLockedParallelVariables { Extinctions = 0, Productions = 0, Combinations = 0, NextCohortIDThreadLocked = NextCohortID }, (ii, loop, threadTrackedDiagnostics) => { RunCell(ii, threadTrackedDiagnostics, initialisation.DispersalOnly, initialisation); return threadTrackedDiagnostics; }, (threadTrackedDiagnostics) => { Interlocked.Add(ref extinctions, threadTrackedDiagnostics.Extinctions); Interlocked.Add(ref productions, threadTrackedDiagnostics.Productions); Interlocked.Add(ref combinations, threadTrackedDiagnostics.Combinations); Interlocked.Exchange(ref NextCohortID, threadTrackedDiagnostics.NextCohortIDThreadLocked); } ); } else { if (initialisation.RunRealm == "marine") { // Run a parallel loop over rows Parallel.For(0, _CellList.Count, () => new ThreadLockedParallelVariables { Extinctions = 0, Productions = 0, Combinations = 0, NextCohortIDThreadLocked = NextCohortID }, (ii, loop, threadTrackedDiagnostics) => { if (EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["Realm"][0] == 2.0) RunCell(ii, threadTrackedDiagnostics, initialisation.DispersalOnly, initialisation); return threadTrackedDiagnostics; }, (threadTrackedDiagnostics) => { Interlocked.Add(ref extinctions, threadTrackedDiagnostics.Extinctions); Interlocked.Add(ref productions, threadTrackedDiagnostics.Productions); Interlocked.Add(ref combinations, threadTrackedDiagnostics.Combinations); Interlocked.Exchange(ref NextCohortID, threadTrackedDiagnostics.NextCohortIDThreadLocked); } ); } else if (initialisation.RunRealm == "terrestrial") { // Run a parallel loop over rows Parallel.For(0, _CellList.Count, () => new ThreadLockedParallelVariables { Extinctions = 0, Productions = 0, Combinations = 0, NextCohortIDThreadLocked = NextCohortID }, (ii, loop, threadTrackedDiagnostics) => { if (EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["Realm"][0] == 1.0) RunCell(ii, threadTrackedDiagnostics, initialisation.DispersalOnly, initialisation); return threadTrackedDiagnostics; }, (threadTrackedDiagnostics) => { Interlocked.Add(ref extinctions, threadTrackedDiagnostics.Extinctions); Interlocked.Add(ref productions, threadTrackedDiagnostics.Productions); Interlocked.Add(ref combinations, threadTrackedDiagnostics.Combinations); Interlocked.Exchange(ref NextCohortID, threadTrackedDiagnostics.NextCohortIDThreadLocked); } ); } else { Console.WriteLine("Run single realm needs to be 'marine', 'terrestrial', or blank"); Console.ReadKey(); } } Console.WriteLine("\n"); // Take the results from the thread local variables and apply to the global diagnostic variables GlobalDiagnosticVariables["NumberOfCohortsExtinct"] = extinctions - combinations; GlobalDiagnosticVariables["NumberOfCohortsProduced"] = productions; GlobalDiagnosticVariables["NumberOfCohortsInModel"] = GlobalDiagnosticVariables["NumberOfCohortsInModel"] + productions - extinctions; GlobalDiagnosticVariables["NumberOfCohortsCombined"] = combinations; }
/// <summary> /// Return an array of values for a single state variable over specific cells /// </summary> /// <param name="variableName">Variable name</param> /// <param name="traitValue">The trait values of functional groups to get data for</param> /// <param name="functionalGroups">A vector of functional group indices to consider</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="stateVariableType">A string indicating the type of state variable; 'cohort' or 'stock'</param> /// <param name="initialisation">The Madingley Model initialisation</param> /// <returns>Array of state variable values for each grid cell</returns> public double[,] GetStateVariableGrid(string variableName, string traitValue, int[] functionalGroups, List <uint[]> cellIndices, string stateVariableType, MadingleyModelInitialisation initialisation) { double[,] TempStateVariable = new double[this.NumLatCells, this.NumLonCells]; switch (variableName.ToLower()) { case "biomass": for (int ii = 0; ii < cellIndices.Count; ii++) { // Check whether the state variable concerns cohorts or stocks if (stateVariableType.ToLower() == "cohort") { if (traitValue != "Zooplankton") { // Check to make sure that the cell has at least one cohort if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts != null) { for (int nn = 0; nn < functionalGroups.Length; nn++) { if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts[functionalGroups[nn]] != null) { foreach (Cohort item in InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts[functionalGroups[nn]].ToArray()) { TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]] += ((item.IndividualBodyMass + item.IndividualReproductivePotentialMass) * item.CohortAbundance); } } } } } else { // Check to make sure that the cell has at least one cohort if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts != null) { for (int nn = 0; nn < functionalGroups.Length; nn++) { if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts[functionalGroups[nn]] != null) { foreach (Cohort item in InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts[functionalGroups[nn]].ToArray()) { if (item.IndividualBodyMass <= initialisation.PlanktonDispersalThreshold) { TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]] += ((item.IndividualBodyMass + item.IndividualReproductivePotentialMass) * item.CohortAbundance); } } } } } } } else if (stateVariableType.ToLower() == "stock") { // Check to make sure that the cell has at least one stock if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellStocks != null) { for (int nn = 0; nn < functionalGroups.Length; nn++) { if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellStocks[functionalGroups[nn]] != null) { foreach (Stock item in InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellStocks[functionalGroups[nn]].ToArray()) { TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]] += (item.TotalBiomass); } } } } } else { Debug.Fail("Variable 'state variable type' must be either 'stock' 'or 'cohort'"); } } break; case "abundance": for (int ii = 0; ii < cellIndices.Count; ii++) { // Check whether the state variable concerns cohorts or stocks if (stateVariableType.ToLower() == "cohort") { if (traitValue != "Zooplankton") { // Check to make sure that the cell has at least one cohort if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts != null) { for (int nn = 0; nn < functionalGroups.Length; nn++) { if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts[functionalGroups[nn]] != null) { foreach (Cohort item in InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts[functionalGroups[nn]].ToArray()) { TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]] += item.CohortAbundance; } } } } } else { // Check to make sure that the cell has at least one cohort if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts != null) { for (int nn = 0; nn < functionalGroups.Length; nn++) { if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts[functionalGroups[nn]] != null) { foreach (Cohort item in InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].GridCellCohorts[functionalGroups[nn]].ToArray()) { if (item.IndividualBodyMass <= initialisation.PlanktonDispersalThreshold) { TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]] += item.CohortAbundance; } } } } } } } else { Debug.Fail("Currently abundance cannot be calculated for grid cell stocks"); } } break; default: Debug.Fail("Invalid search string passed for cohort property"); break; } return(TempStateVariable); }
/// <summary> /// Run ecological processes that operate across grid cells /// </summary> public void RunCrossGridCellEcology(ref uint dispersals, bool dispersalOnly, MadingleyModelInitialisation modelInitialisation) { // If we are running specific locations, then we do not run dispersal if (SpecificLocations != true) { if (RunGridCellsInParallel) { // Loop through each grid cell, and run dispersal for each. Note that because cells essentially run independently, we do not need to thread-lock variables // as they do not exchange information until they are all completed (they basically just build up delta arrays of cohorts to move). However, if cells // should start to exchange information for dispersal, or all contribute to a single centralised variable, then thread-locked parallel variables would // have to be used. Parallel.For(0, _CellList.Count, ii => { EcologyCrossGridCell TempMadingleyEcologyCrossGridCell = new EcologyCrossGridCell(); // Initialise cross grid cell ecology TempMadingleyEcologyCrossGridCell.InitializeCrossGridCellEcology(_GlobalModelTimeStepUnit, DrawRandomly, modelInitialisation); //Initialise the delta for dispersal lists for this grid cell EcosystemModelGrid.DeltaFunctionalGroupDispersalArray[_CellList[ii][0], _CellList[ii][1]] = new List<uint>(); EcosystemModelGrid.DeltaCohortNumberDispersalArray[_CellList[ii][0], _CellList[ii][1]] = new List<uint>(); EcosystemModelGrid.DeltaCellToDisperseToArray[_CellList[ii][0], _CellList[ii][1]] = new List<uint[]>(); EcosystemModelGrid.DeltaCellExitDirection[_CellList[ii][0], _CellList[ii][1]] = new List<uint>(); EcosystemModelGrid.DeltaCellEntryDirection[_CellList[ii][0], _CellList[ii][1]] = new List<uint>(); // We have looped through individal cells and calculated ecological processes for each. Now do this for cross grid cell processes TempMadingleyEcologyCrossGridCell.RunCrossGridCellEcology(_CellList[ii], EcosystemModelGrid, dispersalOnly, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, CurrentMonth); }); } else { // Loop through each grid cell, and run dispersal for each. // Note that currently dispersal is not parallelised, although it could be (though care would need to be taken to ensure that necessary variables are thread-locked for (int ii = 0; ii < _CellList.Count; ii++) { //Initialise the delta for dispersal lists for this grid cell EcosystemModelGrid.DeltaFunctionalGroupDispersalArray[_CellList[ii][0], _CellList[ii][1]] = new List<uint>(); EcosystemModelGrid.DeltaCohortNumberDispersalArray[_CellList[ii][0], _CellList[ii][1]] = new List<uint>(); EcosystemModelGrid.DeltaCellToDisperseToArray[_CellList[ii][0], _CellList[ii][1]] = new List<uint[]>(); EcosystemModelGrid.DeltaCellExitDirection[_CellList[ii][0], _CellList[ii][1]] = new List<uint>(); EcosystemModelGrid.DeltaCellEntryDirection[_CellList[ii][0], _CellList[ii][1]] = new List<uint>(); // We have looped through individal cells and calculated ecological processes for each. Now do this for cross grid cell processes MadingleyEcologyCrossGridCell.RunCrossGridCellEcology(_CellList[ii], EcosystemModelGrid, dispersalOnly, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, CurrentMonth); } } // Apply the changes in the delta arrays from dispersal MadingleyEcologyCrossGridCell.UpdateCrossGridCellEcology(EcosystemModelGrid, ref dispersals, TrackCrossCellProcesses, CurrentTimeStep); } }
/// <summary> /// Return an array of log(values + 1) for a state variable for particular functional groups over specific cells. State variable (currently only biomass or abundance) must be >= 0 in all grid cells /// </summary> /// <param name="variableName">The name of the variable</param> /// <param name="traitValue">The functional group trait value to get data for</param> /// <param name="functionalGroups">A vector of functional group indices to consider</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="stateVariableType">A string indicating the type of state variable; 'cohort' or 'stock'</param> /// <param name="initialisation">The Madingley Model intialisation</param> /// <returns>Array of log(state variable values +1 ) for each grid cell</returns> public double[,] GetStateVariableGridLogDensityPerSqKm(string variableName, string traitValue, int[] functionalGroups, List <uint[]> cellIndices, string stateVariableType, MadingleyModelInitialisation initialisation) { double[,] TempStateVariable = new double[this.NumLatCells, this.NumLonCells]; double CellArea; TempStateVariable = this.GetStateVariableGrid(variableName, traitValue, functionalGroups, cellIndices, stateVariableType, initialisation); for (int ii = 0; ii < cellIndices.Count; ii++) { CellArea = GetCellEnvironment(cellIndices[ii][0], cellIndices[ii][1])["Cell Area"][0]; TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]] /= CellArea; TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]] = Math.Log(TempStateVariable[cellIndices[ii][0], cellIndices[ii][1]] + 1); } return(TempStateVariable); }
/// <summary> /// Sets up the model grid within a Madingley 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> public void SetUpModelGrid(MadingleyModelInitialisation initialisation, ScenarioParameterInitialisation scenarioParameters, int scenarioIndex, int simulation) { // If the intialisation file contains a column pointing to another file of specific locations, and if this column is not blank then read the // file indicated if (SpecificLocations) { // Set up the model grid using these locations EcosystemModelGrid = new ModelGrid(BottomLatitude, LeftmostLongitude, TopLatitude, RightmostLongitude, CellSize, CellSize, _CellList, EnviroStack, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, GlobalDiagnosticVariables, initialisation.TrackProcesses, SpecificLocations, RunGridCellsInParallel,GlobalModelTimeStepUnit); } else { _CellList = new List<uint[]>(); //Switched order so we create cell list first then initialise cells using list rather than grid. uint NumLatCells = (uint)((TopLatitude - BottomLatitude) / CellSize); uint NumLonCells = (uint)((RightmostLongitude - LeftmostLongitude) / CellSize); // Loop over all cells in the model for (uint ii = 0; ii < NumLatCells; ii += 1) { for (uint jj = 0; jj < NumLonCells; jj += 1) { // Define a vector to hold the pair of latitude and longitude indices for this grid cell uint[] cellIndices = new uint[2]; // Add the latitude and longitude indices to this vector cellIndices[0] = ii; cellIndices[1] = jj; // Add the vector to the list of all active grid cells _CellList.Add(cellIndices); } } EcologyTimer = new StopWatch(); EcologyTimer.Start(); // Set up a full model grid (i.e. not for specific locations) // Set up the model grid using these locations EcosystemModelGrid = new ModelGrid(BottomLatitude, LeftmostLongitude, TopLatitude, RightmostLongitude, CellSize, CellSize, _CellList, EnviroStack, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, GlobalDiagnosticVariables, initialisation.TrackProcesses, SpecificLocations, RunGridCellsInParallel, GlobalModelTimeStepUnit); List<int> cellsToRemove = new List<int>(); if (initialisation.RunRealm == "terrestrial") { for (int ii = 0; ii < _CellList.Count; ii += 1) { if ((EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["Realm"][0] == 2.0) || (EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["LandSeaMask"][0] == 0.0)) { cellsToRemove.Add(ii); } } } else if (initialisation.RunRealm == "marine") { for (int ii = 0; ii < _CellList.Count; ii += 1) { if (EcosystemModelGrid.GetCellEnvironment(_CellList[ii][0], _CellList[ii][1])["Realm"][0] == 1.0) { cellsToRemove.Add(ii); } } } for (int ii = (cellsToRemove.Count - 1); ii >= 0; ii--) { _CellList.RemoveAt(cellsToRemove[ii]); } EcologyTimer.Stop(); Console.WriteLine("Time to initialise cells: {0}", EcologyTimer.GetElapsedTimeSecs()); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Madingley Model memory usage post grid cell seed: {0}", GC.GetTotalMemory(true) / 1E9, " (G Bytes)\n"); Console.ForegroundColor = ConsoleColor.White; } if (initialisation.InputState) { InputModelState = new InputModelState(initialisation.ModelStatePath[simulation], initialisation.ModelStateFilename[simulation],EcosystemModelGrid, _CellList); } // When the last simulation for the current scenario // if ((scenarioParameters.scenarioSimulationsNumber.Count == 1) && (scenarioIndex == scenarioParameters.scenarioSimulationsNumber[scenarioIndex] - 1)) EnviroStack.Clear(); // Seed stocks and cohorts in the grid cells // If input state from output from a previous simulation if (initialisation.InputState) { // Seed grid cell cohort and stocks EcosystemModelGrid.SeedGridCellStocksAndCohorts(_CellList, InputModelState, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions); //remove cohorts that do not contain any biomass foreach (uint[] CellPair in _CellList) { GridCellCohortHandler workingGridCellCohorts = EcosystemModelGrid.GetGridCellCohorts(CellPair[0], CellPair[1]); for (int kk = 0; kk < CohortFunctionalGroupDefinitions.GetNumberOfFunctionalGroups(); kk++) { // Loop through each cohort in the functional group for (int ll = (workingGridCellCohorts[kk].Count - 1); ll >= 0; ll--) { // If cohort abundance is less than the extinction threshold then add to the list for extinction if (workingGridCellCohorts[kk][ll].CohortAbundance.CompareTo(0) <= 0 || workingGridCellCohorts[kk][ll].IndividualBodyMass.CompareTo(0.0) == 0) { // Remove the extinct cohort from the list of cohorts workingGridCellCohorts[kk].RemoveAt(ll); } } } } } else { EcosystemModelGrid.SeedGridCellStocksAndCohorts(_CellList, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, GlobalDiagnosticVariables, ref NextCohortID, InitialisationFileStrings["OutputDetail"] == "high", DrawRandomly, initialisation.DispersalOnly, InitialisationFileStrings["DispersalOnlyType"], RunGridCellsInParallel); } Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Madingley Model memory usage pre Collect: {0}", Math.Round(GC.GetTotalMemory(true) / 1E9, 2), " (GBytes)"); Console.ForegroundColor = ConsoleColor.White; GC.Collect(); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Madingley Model memory usage post Collect: {0}", Math.Round(GC.GetTotalMemory(true) / 1E9, 5), " (GBytes)\n"); Console.ForegroundColor = ConsoleColor.White; }
/// <summary> /// Constructor for the cell output class /// </summary> /// <param name="outputDetail">The level of detail to include in the ouputs: 'low', 'medium' or 'high'</param> /// <param name="modelInitialisation">Model initialisation object</param> /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param> public OutputCell(string outputDetail, MadingleyModelInitialisation modelInitialisation, int cellIndex) { // Set the output path _OutputPath = modelInitialisation.OutputPath; // Set the initial maximum value for the y-axis of the live display MaximumYValue = 1000000; // Set the local copy of the mass bin handler from the model initialisation _MassBinHandler = modelInitialisation.ModelMassBins; // Get the number of mass bins to be used MassBinNumber = _MassBinHandler.NumMassBins; // Get the specified mass bins MassBins = modelInitialisation.ModelMassBins.GetSpecifiedMassBins(); // Set the output detail level if (outputDetail == "low") ModelOutputDetail = OutputDetailLevel.Low; else if (outputDetail == "medium") ModelOutputDetail = OutputDetailLevel.Medium; else if (outputDetail == "high") ModelOutputDetail = OutputDetailLevel.High; else Debug.Fail("Specified output detail level is not valid, must be 'low', 'medium' or 'high'"); // Get whether to track marine specifics TrackMarineSpecifics = modelInitialisation.TrackMarineSpecifics; // Get whether to track marine specifics OutputMetrics = modelInitialisation.OutputMetrics; //Initialise the EcosystemMetrics class Metrics = new EcosytemMetrics(); // Initialise the data converter DataConverter = new ArraySDSConvert(); // Initialise the SDS object creator SDSCreator = new CreateSDSObject(); // Initialise the grid viewer GridViewer = new ViewGrid(); // Set the local variable designating whether to display live outputs if (modelInitialisation.LiveOutputs) LiveOutputs = true; }
/// <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> /// 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> /// 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> /// Run mortality /// </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 mortality</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 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) { // Variables to hold the mortality rates double MortalityRateBackground; double MortalityRateSenescence; double MortalityRateStarvation; // Variable to hold the total abundance lost to all forms of mortality double MortalityTotal; // Individual body mass including change this time step as a result of other ecological processes double BodyMassIncludingChangeThisTimeStep; // Individual reproductive mass including change this time step as a result of other ecological processes double ReproductiveMassIncludingChangeThisTimeStep; // Calculate the body mass of individuals in this cohort including mass gained through eating this time step, up to but not exceeding adult body mass for this cohort. // Should be fine because these deductions are made in the reproduction implementation, but use Math.Min to double check. BodyMassIncludingChangeThisTimeStep = 0.0; // Loop over all items in the biomass deltas foreach (var Biomass in deltas["biomass"]) { // Add the delta biomass to net biomass BodyMassIncludingChangeThisTimeStep += Biomass.Value; } BodyMassIncludingChangeThisTimeStep = Math.Min(gridCellCohorts[actingCohort].AdultMass, BodyMassIncludingChangeThisTimeStep + gridCellCohorts[actingCohort].IndividualBodyMass); // Temporary variable to hold net reproductive biomass change of individuals in this cohort as a result of other ecological processes ReproductiveMassIncludingChangeThisTimeStep = 0.0; // Loop over all items in the biomass deltas foreach (var Biomass in deltas["reproductivebiomass"]) { // Add the delta biomass to net biomass ReproductiveMassIncludingChangeThisTimeStep += Biomass.Value; } ReproductiveMassIncludingChangeThisTimeStep += gridCellCohorts[actingCohort].IndividualReproductivePotentialMass; // Check to see if the cohort has already been killed by predation etc if ((BodyMassIncludingChangeThisTimeStep).CompareTo(0.0) <= 0) { // If individual body mass is not greater than zero, then all individuals become extinct MortalityTotal = gridCellCohorts[actingCohort].CohortAbundance; } else { // Calculate background mortality rate MortalityRateBackground = Implementations["basic background mortality"].CalculateMortalityRate(gridCellCohorts, actingCohort, BodyMassIncludingChangeThisTimeStep, deltas, currentTimestep); // If the cohort has matured, then calculate senescence mortality rate, otherwise set rate to zero if (gridCellCohorts[actingCohort].MaturityTimeStep != uint.MaxValue) { MortalityRateSenescence = Implementations["basic senescence mortality"].CalculateMortalityRate(gridCellCohorts, actingCohort, BodyMassIncludingChangeThisTimeStep, deltas, currentTimestep); } else { MortalityRateSenescence = 0.0; } // Calculate the starvation mortality rate based on individual body mass and maximum body mass ever // achieved by this cohort MortalityRateStarvation = Implementations["basic starvation mortality"].CalculateMortalityRate(gridCellCohorts, actingCohort, BodyMassIncludingChangeThisTimeStep, deltas, currentTimestep); // Calculate the number of individuals that suffer mortality this time step from all sources of mortality MortalityTotal = (1 - Math.Exp(-MortalityRateBackground - MortalityRateSenescence - MortalityRateStarvation)) * gridCellCohorts[actingCohort].CohortAbundance; } // 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") && (!gridCellCohorts[actingCohort].Merged)) { trackProcesses.RecordMortality((uint)cellEnvironment["LatIndex"][0], (uint)cellEnvironment["LonIndex"][0], gridCellCohorts[actingCohort].BirthTimeStep, currentTimestep, gridCellCohorts[actingCohort].IndividualBodyMass, gridCellCohorts[actingCohort].AdultMass, gridCellCohorts[actingCohort].FunctionalGroupIndex, gridCellCohorts[actingCohort].CohortID[0], MortalityTotal, "sen/bg/starv"); } // Remove individuals that have died from the delta abundance for this cohort deltas["abundance"]["mortality"] = -MortalityTotal; // Add the biomass of individuals that have died to the delta biomass in the organic pool (including reproductive // potential mass, and mass gained through eating, and excluding mass lost through metabolism) deltas["organicpool"]["mortality"] = MortalityTotal * (BodyMassIncludingChangeThisTimeStep + ReproductiveMassIncludingChangeThisTimeStep); }