/// <summary> /// Record dispersal events in the dispersal tracker /// </summary> /// <param name="inboundCohorts">The cohorts arriving in a cell in the current time step</param> /// <param name="outboundCohorts">The cohorts leaving a cell in the current time step</param> /// <param name="outboundCohortWeights">The body masses of cohorts leaving the cell in the current time step</param> /// <param name="timestep">The current model time step</param> /// <param name="madingleyModelGrid">The model grid</param> public void RecordDispersalForACell(uint[, ,] inboundCohorts, uint[, ,] outboundCohorts, List<double>[,] outboundCohortWeights, uint timestep, ModelGrid madingleyModelGrid) { var count = inboundCohorts.GetLength(0) * inboundCohorts.GetLength(1); var copy = new Madingley.Common.GridCellDispersal[count]; for (var kk = 0; kk < count; kk++) { var ii = (int)kk / inboundCohorts.GetLength(1); var jj = kk % inboundCohorts.GetLength(1); var denter = new Tuple<Madingley.Common.CohortsEnterDirection, int>[] { Tuple.Create(Madingley.Common.CohortsEnterDirection.North, (int)inboundCohorts[ii, jj, 0]), Tuple.Create(Madingley.Common.CohortsEnterDirection.NorthEast, (int)inboundCohorts[ii, jj, 1]), Tuple.Create(Madingley.Common.CohortsEnterDirection.East, (int)inboundCohorts[ii, jj, 2]), Tuple.Create(Madingley.Common.CohortsEnterDirection.SouthEast, (int)inboundCohorts[ii, jj, 3]), Tuple.Create(Madingley.Common.CohortsEnterDirection.South, (int)inboundCohorts[ii, jj, 4]), Tuple.Create(Madingley.Common.CohortsEnterDirection.SouthWest, (int)inboundCohorts[ii, jj, 5]), Tuple.Create(Madingley.Common.CohortsEnterDirection.West, (int)inboundCohorts[ii, jj, 6]), Tuple.Create(Madingley.Common.CohortsEnterDirection.NorthWest, (int)inboundCohorts[ii, jj, 7]), }; var enter = denter.ToDictionary(l => l.Item1, l => l.Item2); var dexit = new Tuple<Madingley.Common.CohortsExitDirection, int>[] { Tuple.Create(Madingley.Common.CohortsExitDirection.North, (int)outboundCohorts[ii, jj, 0]), Tuple.Create(Madingley.Common.CohortsExitDirection.NorthEast, (int)outboundCohorts[ii, jj, 1]), Tuple.Create(Madingley.Common.CohortsExitDirection.East, (int)outboundCohorts[ii, jj, 2]), Tuple.Create(Madingley.Common.CohortsExitDirection.SouthEast, (int)outboundCohorts[ii, jj, 3]), Tuple.Create(Madingley.Common.CohortsExitDirection.South, (int)outboundCohorts[ii, jj, 4]), Tuple.Create(Madingley.Common.CohortsExitDirection.SouthWest, (int)outboundCohorts[ii, jj, 5]), Tuple.Create(Madingley.Common.CohortsExitDirection.West, (int)outboundCohorts[ii, jj, 6]), Tuple.Create(Madingley.Common.CohortsExitDirection.NorthWest, (int)outboundCohorts[ii, jj, 7]), }; var exit = dexit.ToDictionary(l => l.Item1, l => l.Item2); var weights = outboundCohortWeights[ii, jj].ToArray(); var cell = madingleyModelGrid.GetGridCell((uint)ii, (uint)jj); var ccell = Converters.ConvertCellData(cell); copy[kk] = new Madingley.Common.GridCellDispersal(enter, exit, weights, ccell); } this.GridCellDispersals = copy; }
/// <summary> /// Run responsive dispersal /// </summary> /// <param name="cellIndices">The longitudinal and latitudinal indices of the current grid cell</param> /// <param name="gridForDispersal">The model grid to run dispersal for</param> /// <param name="cohortToDisperse">The cohort for which to apply the dispersal process</param> /// <param name="actingCohortFunctionalGroup">The functional group index of the acting cohort</param> /// <param name="actingCohortNumber">The position of the acting cohort within the functional group in the array of grid cell cohorts</param> /// <param name="currentMonth">The current model month</param> public void RunDispersal(uint[] cellIndices, ModelGrid gridForDispersal, Cohort cohortToDisperse, int actingCohortFunctionalGroup, int actingCohortNumber, uint currentMonth) { // Starvation driven dispersal takes precedence over density driven dispersal (i.e. a cohort can't do both). Also, the delta // arrays only allow each cohort to perform one type of dispersal each time step bool CohortDispersed = false; // Check for starvation-driven dispersal CohortDispersed = CheckStarvationDispersal(gridForDispersal, cellIndices[0], cellIndices[1], cohortToDisperse, actingCohortFunctionalGroup, actingCohortNumber); if (!CohortDispersed) { // Check for density driven dispersal CheckDensityDrivenDispersal(gridForDispersal, cellIndices[0], cellIndices[1], cohortToDisperse, actingCohortFunctionalGroup, actingCohortNumber); } }
/// <summary> /// Run dispersal /// </summary> public void RunCrossGridCellEcologicalProcess(uint[] cellIndex, ModelGrid gridForDispersal, bool dispersalOnly, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, uint currentMonth) { // Create a temporary handler for grid cell cohorts GridCellCohortHandler WorkingGridCellCohorts; // Get the lat and lon indices uint ii = cellIndex[0]; uint jj = cellIndex[1]; // A boolean to check that the environmental layer exists bool varExists; // Check to see if the cell is marine double CellRealm = gridForDispersal.GetEnviroLayer("Realm", 0, ii, jj, out varExists); // Go through all of the cohorts in turn and see if they disperse WorkingGridCellCohorts = gridForDispersal.GetGridCellCohorts(ii, jj); // Loop through cohorts, and perform dispersal according to cohort type and status for (int kk = 0; kk < WorkingGridCellCohorts.Count; kk++) { // Work through the list of cohorts for (int ll = 0; ll < WorkingGridCellCohorts[kk].Count; ll++) { // Check to see if the cell is marine and the cohort type is planktonic if (CellRealm == 2.0 && ((madingleyCohortDefinitions.GetTraitNames("Mobility", WorkingGridCellCohorts[kk][ll].FunctionalGroupIndex) == "planktonic") || (WorkingGridCellCohorts[kk][ll].IndividualBodyMass <= PlanktonThreshold))) { // Run advective dispersal Implementations["basic advective dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth); } // Otherwise, if mature do responsive dispersal else if (WorkingGridCellCohorts[kk][ll].MaturityTimeStep < uint.MaxValue) { // Run diffusive dispersal Implementations["basic responsive dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth); } // If the cohort is immature, run diffusive dispersal else { Implementations["basic diffusive dispersal"].RunDispersal(cellIndex, gridForDispersal, WorkingGridCellCohorts[kk][ll], kk, ll, currentMonth); } } } }
/// <summary> /// Initializes the ecosystem model /// </summary> /// <param name="mmi">An instance of the model initialisation class</param> public static void Load(Tuple<Madingley.Common.Environment, SortedList<string, EnviroData>> mmi, bool readData) { var e = mmi.Item1; if (e.SpecificLocations == false) { var CellList = new List<Tuple<int, int>>(); var NumLatCells = (uint)((e.TopLatitude - e.BottomLatitude) / e.CellSize); var NumLonCells = (uint)((e.RightmostLongitude - e.LeftmostLongitude) / e.CellSize); // Loop over all cells in the model for (int latitudeIndex = 0; latitudeIndex < NumLatCells; latitudeIndex++) { for (int longitudeIndex = 0; longitudeIndex < NumLonCells; longitudeIndex++) { // Add the vector to the list of all active grid cells CellList.Add(Tuple.Create(latitudeIndex, longitudeIndex)); } } e.FocusCells = CellList; } if (readData) { var cellList = e.FocusCells.Select(a => new UInt32[] { (uint)a.Item1, (uint)a.Item2 }).ToList(); var EcosystemModelGrid = new ModelGrid((float)e.BottomLatitude, (float)e.LeftmostLongitude, (float)e.TopLatitude, (float)e.RightmostLongitude, (float)e.CellSize, (float)e.CellSize, cellList, mmi.Item2, e.SpecificLocations); Func<Tuple<int, int>, IDictionary<string, double[]>> convertCellEnvironment = cell => { var env = EcosystemModelGrid.GetCellEnvironment((uint)cell.Item1, (uint)cell.Item2); return env.ToDictionary(kv => kv.Key, kv => kv.Value.ToArray()); }; e.CellEnvironment = e.FocusCells.Select(convertCellEnvironment).ToList(); } }
/// <summary> /// Calculates the mean trophic level of all individual organisms in a grid cell /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The list of cell indices in the current model simulation</param> /// <param name="cellIndex">The index of the current cell in the list of cells to run</param> /// <returns>The mean trophic level of individuals in the grid cell</returns> public double CalculateMeanTrophicLevelCell(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double BiomassWeightedTI = 0.0; double TotalBiomass = 0.0; double CohortBiomass = 0.0; foreach (var CohortList in CellCohorts) { foreach (Cohort c in CohortList) { CohortBiomass = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; BiomassWeightedTI += CohortBiomass * c.TrophicIndex; TotalBiomass += CohortBiomass; } } return(BiomassWeightedTI / TotalBiomass); }
/// <summary> /// Return the distribution of biomasses among trophic level bins /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The list of cell indices to be run in the current model simulation</param> /// <param name="cellIndex">The index of the current cell in the list of cells to be run</param> /// <returns>The distribution of biomasses among trophic level bins</returns> public double[] CalculateTrophicDistribution(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double[] TrophicIndexBinMasses = new double[NumberTrophicBins]; int BinIndex; foreach (var CohortList in CellCohorts) { foreach (Cohort c in CohortList) { BinIndex = _TrophicIndexBinValues.ToList().IndexOf(_TrophicIndexBinValues.Last(x => x < c.TrophicIndex)); TrophicIndexBinMasses[BinIndex] += (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; } } return(TrophicIndexBinMasses); }
/// <summary> /// Run diffusive dispersal /// </summary> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="gridForDispersal">The model grid to run dispersal for</param> /// <param name="cohortToDisperse">The cohort for which to run the dispersal process for</param> /// <param name="actingCohortFunctionalGroup">The functional group index of the acting cohort</param> /// <param name="actingCohortNumber">The position of the cohort within the functional group in the array of grid cell cohorts</param> /// <param name="currentMonth">The current model month</param> public void RunDispersal(uint[] cellIndices, ModelGrid gridForDispersal, Cohort cohortToDisperse, int actingCohortFunctionalGroup, int actingCohortNumber, uint currentMonth) { // Calculate dispersal speed for the cohort double DispersalSpeed = CalculateDispersalSpeed(cohortToDisperse.IndividualBodyMass); // A double to indicate whether or not the cohort has dispersed, and if it has dispersed, where to double CohortDispersed = 0; // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step uint ExitDirection = new uint(); uint EntryDirection = new uint(); ExitDirection = 9999; // Get the probability of dispersal double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, cellIndices[0], cellIndices[1], DispersalSpeed); // Check to see if it does disperse CohortDispersed = CheckForDispersal(DispersalArray[0]); // If it does, check to see where it will end up if (CohortDispersed > 0) { // Check to see if the direction is actually dispersable uint[] DestinationCell = CellToDisperseTo(gridForDispersal, cellIndices[0], cellIndices[1], DispersalArray, CohortDispersed, DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection); if (DestinationCell[0] < 999999) { // Update the delta array of cohorts gridForDispersal.DeltaFunctionalGroupDispersalArray[cellIndices[0], cellIndices[1]].Add((uint)actingCohortFunctionalGroup); gridForDispersal.DeltaCohortNumberDispersalArray[cellIndices[0], cellIndices[1]].Add((uint)actingCohortNumber); // Update the delta array of cells to disperse to gridForDispersal.DeltaCellToDisperseToArray[cellIndices[0], cellIndices[1]].Add(DestinationCell); // Update the delta array of exit and entry directions gridForDispersal.DeltaCellExitDirection[cellIndices[0], cellIndices[1]].Add(ExitDirection); gridForDispersal.DeltaCellEntryDirection[cellIndices[0], cellIndices[1]].Add(EntryDirection); } } }
/// <summary> /// Calculates the geometric community weighted mean body mass /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The list of indices of cells to be run in the current model simulation</param> /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param> /// <returns>geometric community weighted mean body mass</returns> public double CalculateGeometricCommunityMeanBodyMass(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double CumulativeAbundance = 0.0; double CumulativeLogBiomass = 0.0; //Retrieve the biomass foreach (var CohortList in CellCohorts) { foreach (Cohort c in CohortList) { CumulativeLogBiomass += Math.Log(c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; CumulativeAbundance += c.CohortAbundance; } } double CWGMBM = Math.Exp(CumulativeLogBiomass / CumulativeAbundance); return(CWGMBM); }
/// <summary> /// Initializes the ecosystem model /// </summary> /// <param name="mmi">An instance of the model initialisation class</param> public static void Load(Tuple <Madingley.Common.Environment, SortedList <string, EnviroData> > mmi) { var e = mmi.Item1; if (e.SpecificLocations == false) { var CellList = new List <Tuple <int, int> >(); var NumLatCells = (uint)((e.TopLatitude - e.BottomLatitude) / e.CellSize); var NumLonCells = (uint)((e.RightmostLongitude - e.LeftmostLongitude) / e.CellSize); // Loop over all cells in the model for (int latitudeIndex = 0; latitudeIndex < NumLatCells; latitudeIndex++) { for (int longitudeIndex = 0; longitudeIndex < NumLonCells; longitudeIndex++) { // Add the vector to the list of all active grid cells CellList.Add(Tuple.Create(latitudeIndex, longitudeIndex)); } } e.FocusCells = CellList; } var cellList = e.FocusCells.Select(a => new UInt32[] { (uint)a.Item1, (uint)a.Item2 }).ToList(); var EcosystemModelGrid = new ModelGrid((float)e.BottomLatitude, (float)e.LeftmostLongitude, (float)e.TopLatitude, (float)e.RightmostLongitude, (float)e.CellSize, (float)e.CellSize, cellList, mmi.Item2, e.SpecificLocations); Func <Tuple <int, int>, IDictionary <string, double[]> > convertCellEnvironment = cell => { var env = EcosystemModelGrid.GetCellEnvironment((uint)cell.Item1, (uint)cell.Item2); return(env.ToDictionary(kv => kv.Key, kv => kv.Value.ToArray())); }; e.CellEnvironment = e.FocusCells.Select(convertCellEnvironment).ToList(); }
/// <summary> /// Calculates the probability of diffusive dispersal given average individual dispersal speed /// </summary> /// <param name="madingleyGrid">The model grid</param> /// <param name="latIndex">The latitude index of the grid cell to check for dispersal</param> /// <param name="lonIndex">The longitude index of the grid cell to check for dispersal</param> /// <param name="dispersalSpeed">The average speed at which individuals in this cohort move around their environment, in km per month</param> /// <returns>A six element array. /// The first element is the probability of dispersal. /// The second element is the probability of dispersing in the u (longitudinal) direction /// The third element is the probability of dispersing in the v (latitudinal) direction /// The fourth element is the probability of dispersing in the diagonal direction /// The fifth element is the u velocity modified by the random diffusion component /// The sixth element is the v velocity modified by the random diffusion component /// Note that the second, third, and fourth elements are always positive; thus, they do not indicate 'direction' in terms of dispersal.</returns> private double[] CalculateDispersalProbability(ModelGrid madingleyGrid, uint latIndex, uint lonIndex, double dispersalSpeed) { // Check that the u speed and v speed are not greater than the cell length. If they are, then rescale them; this limits the max velocity // so that cohorts cannot be advected more than one grid cell per time step double LatCellLength = madingleyGrid.CellHeightsKm[latIndex]; double LonCellLength = madingleyGrid.CellWidthsKm[latIndex]; // Pick a direction at random double RandomDirection = RandomNumberGenerator.GetUniform() * 2 * Math.PI; // Calculate the u and v components given the dispersal speed double uSpeed = dispersalSpeed * Math.Cos(RandomDirection); double vSpeed = dispersalSpeed * Math.Sin(RandomDirection); // Calculate the area of the grid cell that is now outside in the diagonal direction double AreaOutsideBoth = Math.Abs(uSpeed * vSpeed); // Calculate the area of the grid cell that is now outside in the u direction (not including the diagonal) double AreaOutsideU = Math.Abs(uSpeed * LatCellLength) - AreaOutsideBoth; // Calculate the proportion of the grid cell that is outside in the v direction (not including the diagonal double AreaOutsideV = Math.Abs(vSpeed * LonCellLength) - AreaOutsideBoth; // Get the cell area, in kilometres squared double CellArea = madingleyGrid.GetCellEnvironment(latIndex, lonIndex)["Cell Area"][0]; // Convert areas to a probability double DispersalProbability = (AreaOutsideU + AreaOutsideV + AreaOutsideBoth) / CellArea; // Check that the whole cell hasn't moved out. This could happen if dispersal speed was high enough if (DispersalProbability >= 1) { Debug.Fail("Dispersal probability in diffusion should always be <= 1"); } double[] NewArray = { DispersalProbability, AreaOutsideU / CellArea, AreaOutsideV / CellArea, AreaOutsideBoth / CellArea, uSpeed, vSpeed }; return(NewArray); }
/// <summary> /// Generates the file outputs for the current time step /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="currentTimeStep">The current model time step</param> private void TimeStepFileOutputs(ModelGrid ecosystemModelGrid, uint currentTimeStep) { Console.WriteLine("Writing global ouputs to file...\n"); // Write out the basic diagnostic variables DataConverter.ValueToSDS1D(OrganicPoolOut, "Organic matter pool", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutput, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(RespiratoryPoolOut, "Respiratory CO2 pool", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutput, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalNumberOfCohorts, "Number of cohorts in model", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutput, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalNumberOfStocks, "Number of stocks in model", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutput, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(NumberOfCohortsExtinct, "Number of cohorts extinct", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutput, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(NumberOfCohortsProduced, "Number of cohorts produced", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutput, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(NumberOfCohortsCombined, "Number of cohorts combined", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutput, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalLivingBiomass, "Total living biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutput, (int)currentTimeStep + 1); }
/// <summary> /// Calculates the abundances and biomasses within mass bins for all functional groups in the cohort indices array /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="cellIndex">The number of the current cell in the list of indices of active cells</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> private void CalculateMassBinOutputs(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex, Boolean marineCell) { string[] Keys; if (marineCell) { // Get the cohort trait combinations to consider Keys = CohortTraitIndicesMarine.Keys.ToArray(); } else { // Get the cohort trait combinations to consider Keys = CohortTraitIndices.Keys.ToArray(); } // Loop over trait combinations foreach (var TraitValue in Keys) { // Declare vectors to hold abundance and biomass in mass bins for this trait combination double[] WorkingAbundanceInMassBins = new double[MassBinNumber]; double[] WorkingBiomassInMassBins = new double[MassBinNumber]; // Declare arrays to hold abundance and biomass in juvenile vs. adult mass bins for this trait combination double[,] WorkingAbundanceJuvenileAdultMassBins = new double[MassBinNumber, MassBinNumber]; double[,] WorkingBiomassJuvenileAdultMassBins = new double[MassBinNumber, MassBinNumber]; // Create a temporary local copy of the cohorts in this grid cell GridCellCohortHandler TempCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0],cellIndices[cellIndex][1]); if (marineCell) { // Loop over functional groups foreach (int FunctionalGroupIndex in CohortTraitIndicesMarine[TraitValue]) { // Loop over all cohorts in this functional group for (int cohort = 0; cohort < TempCohorts[FunctionalGroupIndex].Count; cohort++) { // Find the appropriate mass bin for the cohort int mb = 0; do { mb++; } while (mb < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass > MassBins[mb]); // Add the cohort's abundance to the approriate mass bin. Note that we have to differentiate here for non-obligate zooplankton, because they are only added in if they are // below the zooplankton mass threshold (or an obligate zooplankton) if (String.Equals(TraitValue, "Zooplankton (all)")) { if (TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass < PlanktonSizeThreshold || CohortTraitIndicesMarine["Obligate zooplankton"].Contains(FunctionalGroupIndex)) { WorkingAbundanceInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance; // Add the cohort's biomass to the approriate mass bin WorkingBiomassInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass; // Find the mass bin appropriate for this cohort's juvenile mass int j = 0; do { j++; } while (j < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].JuvenileMass > MassBins[j]); // Find the mass bin appropriate for this cohort's adult mass int a = 0; do { a++; } while (a < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].AdultMass > MassBins[a]); // Add the cohort's abundance to this adult vs juvenile mass bins WorkingAbundanceJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance; // Add the cohort's biomass to this adult vs juvenile mass bins WorkingBiomassJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass; } } else { WorkingAbundanceInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance; // Add the cohort's biomass to the approriate mass bin WorkingBiomassInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass; // Find the mass bin appropriate for this cohort's juvenile mass int j = 0; do { j++; } while (j < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].JuvenileMass > MassBins[j]); // Find the mass bin appropriate for this cohort's adult mass int a = 0; do { a++; } while (a < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].AdultMass > MassBins[a]); // Add the cohort's abundance to this adult vs juvenile mass bins WorkingAbundanceJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance; // Add the cohort's biomass to this adult vs juvenile mass bins WorkingBiomassJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass; } } } //Copy the working vectors and arrays to the sortedlist for the current key value AbundancesInMassBins[TraitValue] = WorkingAbundanceInMassBins; BiomassesInMassBins[TraitValue] = WorkingBiomassInMassBins; AbundancesInJuvenileAdultMassBins[TraitValue] = WorkingAbundanceJuvenileAdultMassBins; BiomassesInJuvenileAdultMassBins[TraitValue] = WorkingBiomassJuvenileAdultMassBins; } else { // Loop over functional groups foreach (int FunctionalGroupIndex in CohortTraitIndices[TraitValue]) { // Loop over all cohorts in this functional group for (int cohort = 0; cohort < TempCohorts[FunctionalGroupIndex].Count; cohort++) { // Find the appropriate mass bin for the cohort int mb = 0; do { mb++; } while (mb < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass > MassBins[mb]); // Add the cohort's abundance to the approriate mass bin WorkingAbundanceInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance; // Add the cohort's biomass to the approriate mass bin WorkingBiomassInMassBins[mb - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass; // Find the mass bin appropriate for this cohort's juvenile mass int j = 0; do { j++; } while (j < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].JuvenileMass > MassBins[j]); // Find the mass bin appropriate for this cohort's adult mass int a = 0; do { a++; } while (a < (MassBins.Length - 1) && TempCohorts[FunctionalGroupIndex][cohort].AdultMass > MassBins[a]); // Add the cohort's abundance to this adult vs juvenile mass bins WorkingAbundanceJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance; // Add the cohort's biomass to this adult vs juvenile mass bins WorkingBiomassJuvenileAdultMassBins[a - 1, j - 1] += TempCohorts[FunctionalGroupIndex][cohort].CohortAbundance * TempCohorts[FunctionalGroupIndex][cohort].IndividualBodyMass; } } //Copy the working vectors and arrays to the sortedlist for the current key value AbundancesInMassBins[TraitValue] = WorkingAbundanceInMassBins; BiomassesInMassBins[TraitValue] = WorkingBiomassInMassBins; AbundancesInJuvenileAdultMassBins[TraitValue] = WorkingAbundanceJuvenileAdultMassBins; BiomassesInJuvenileAdultMassBins[TraitValue] = WorkingBiomassJuvenileAdultMassBins; } } // Loop over trait combinations and log abundances and body masses foreach (var TraitValue in Keys) { for (int i = 0; i < MassBins.Length; i++) { AbundancesInMassBins[TraitValue][i] = (AbundancesInMassBins[TraitValue][i] > 0) ? Math.Log(AbundancesInMassBins[TraitValue][i]) : ecosystemModelGrid.GlobalMissingValue; BiomassesInMassBins[TraitValue][i] = (BiomassesInMassBins[TraitValue][i] > 0) ? Math.Log(BiomassesInMassBins[TraitValue][i]) : ecosystemModelGrid.GlobalMissingValue; for (int j = 0; j < MassBins.Length; j++) { AbundancesInJuvenileAdultMassBins[TraitValue][i, j] = (AbundancesInJuvenileAdultMassBins[TraitValue][i, j] > 0) ? Math.Log(AbundancesInJuvenileAdultMassBins[TraitValue][i, j]) : ecosystemModelGrid.GlobalMissingValue; BiomassesInJuvenileAdultMassBins[TraitValue][i, j] = (BiomassesInJuvenileAdultMassBins[TraitValue][i, j] > 0) ? Math.Log(BiomassesInJuvenileAdultMassBins[TraitValue][i, j]) : ecosystemModelGrid.GlobalMissingValue; } } } }
/// <summary> /// Calculate outputs associated with high-level outputs /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="cellIndex">The number of the current cell in the list of active cells</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> private void CalculateHighLevelOutputs(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex, Boolean marineCell) { // Calcalate the outputs arranged by mass bin CalculateMassBinOutputs(ecosystemModelGrid, cellIndices, cellIndex, marineCell); // Declare vectors to hold properties of tracked cohorts TrackedCohortIndividualMasses = new double[TrackedCohorts.Count]; TrackedCohortAbundances = new double[TrackedCohorts.Count]; // Get a temporary local copy of the cohorts in the grid cell GridCellCohortHandler TempCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); // Loop over functional groups in the grid cell cohorts for (int j = 0; j < TempCohorts.Count; j++) { // Loop over cohorts within this functional group for (int k = 0; k < TempCohorts[j].Count; k++) { // Loop over all cohort IDs foreach (uint CohortID in TempCohorts[j][k].CohortID) { // Check whether the cohort ID corresponds to a tracked cohort if (TrackedCohorts.Contains(CohortID)) { // Get the position of the cohort in the list of tracked cohorts int position = TrackedCohorts.FindIndex( delegate(uint i) { return i == CohortID; }); // Add the body mass and abundance of the tracked cohort to the appropriate position in the output vector TrackedCohortIndividualMasses[position] = TempCohorts[j][k].IndividualBodyMass; TrackedCohortAbundances[position] = TempCohorts[j][k].CohortAbundance; } } } } }
/// <summary> /// Set up all outputs (live, console and file) prior to the model run /// </summary> /// <param name="ecosystemModelGrid">The model grid that output data will be derived from</param> /// <param name="cohortFunctionalGroupDefinitions">The definitions for cohort functional groups</param> /// <param name="stockFunctionalGroupDefinitions">The definitions for stock functional groups</param> /// <param name="numTimeSteps">The number of time steps in the model run</param> /// <param name="outputFilesSuffix">The suffix to be applied to all output files from the current model run</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="cellIndex">The number of the current grid cell in the list of indices of active cells</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> public void SetUpOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions, uint numTimeSteps, string outputFilesSuffix, List<uint[]> cellIndices, int cellIndex, Boolean marineCell) { Console.WriteLine("Setting up grid cell outputs...\n"); // Set the suffix for all output files _OutputSuffix = outputFilesSuffix + "_Cell" + cellIndex; // Create vector to hold the values of the time dimension TimeSteps = new float[numTimeSteps + 1]; // Set the first value to be -1 (this will hold initial outputs) TimeSteps[0] = 0; // Fill other values from 0 (this will hold outputs during the model run) for (int i = 1; i < numTimeSteps + 1; i++) { TimeSteps[i] = i; } // Initialise the trait based outputs InitialiseTraitBasedOutputs(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, marineCell); // Setup low-level outputs SetUpLowLevelOutputs(numTimeSteps, ecosystemModelGrid); if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High)) { // Setup medium-level outputs SetupMediumLevelOutputs(ecosystemModelGrid, marineCell); if (ModelOutputDetail == OutputDetailLevel.High) { // Setup high-level outputs SetUpHighLevelOutputs(ecosystemModelGrid, cellIndices,cellIndex, cohortFunctionalGroupDefinitions, marineCell); } } }
/// <summary> /// Write to the output file values of the output variables at the end of the model run /// </summary> /// <param name="EcosystemModelGrid">The model grid to get data from</param> /// <param name="CohortFunctionalGroupDefinitions">Definitions of the cohort functional groups in the model</param> /// <param name="StockFunctionalGroupDefinitions">Definitions of the stock functional groups in the model</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="cellNumber">The number of the current cell in the list of indices of active cells</param> /// <param name="GlobalDiagnosticVariables">List of global diagnostic variables</param> /// <param name="initialisation">The Madingley Model initialisation</param> /// <param name="month">The current month in the model run</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> public void FinalOutputs(ModelGrid EcosystemModelGrid, FunctionalGroupDefinitions CohortFunctionalGroupDefinitions, FunctionalGroupDefinitions StockFunctionalGroupDefinitions, List<uint[]> cellIndices, int cellNumber, SortedList<string, double> GlobalDiagnosticVariables, MadingleyModelInitialisation initialisation, uint month, Boolean marineCell) { // Calculate output variables CalculateOutputs(EcosystemModelGrid, CohortFunctionalGroupDefinitions, StockFunctionalGroupDefinitions, cellIndices,cellNumber, GlobalDiagnosticVariables, initialisation, month, marineCell); // Dispose of the dataset objects BasicOutputMemory.Clone("msds:nc?file="+ _OutputPath + "BasicOutputs" + _OutputSuffix + ".nc&openMode=create"); BasicOutputMemory.Dispose(); if (LiveOutputs) { DataSetToViewLive.Dispose(); } if (ModelOutputDetail == OutputDetailLevel.High) { // Dispose of the dataset objects for high detail level outputs MassBinsOutputMemory.Clone("msds:nc?file="+ _OutputPath + "MassBinsOutputs" + _OutputSuffix + ".nc&openMode=create"); MassBinsOutputMemory.Dispose(); TrackedCohortsOutputMemory.Clone("msds:nc?file="+ _OutputPath + "TrackedCohortsOutputs" + _OutputSuffix + ".nc&openMode=create"); TrackedCohortsOutputMemory.Dispose(); } Metrics.CloseRserve(); }
/// <summary> /// Generate file outputs for the current time step /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="currentTimeStep">The current time step</param> /// <param name="MarineCell">Whether the current cell is a marine cell</param> /// <param name="cellIndices">The list of all cells to run the model for</param> /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param> private void TimeStepFileOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, uint currentTimeStep, Boolean MarineCell, List<uint[]> cellIndices, int cellIndex) { Console.WriteLine("Writing grid cell ouputs to file...\n"); //Write the low level outputs first DataConverter.ValueToSDS1D(TotalLivingBiomassDensity, "Total Biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalHeterotrophAbundanceDensity, "Heterotroph Abundance density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalHeterotrophBiomassDensity, "Heterotroph Biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); // File outputs for medium and high detail levels if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High)) { if (MarineCell) { // Loop over all cohort trait value combinations and output abundances, densities and biomasses foreach (string TraitValue in CohortTraitIndicesMarine.Keys) { DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); } // Loop over all stock trait value combinations and output biomasses foreach (string TraitValue in StockTraitIndicesMarine.Keys) { DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); } } else { // Loop over all cohort trait value combinations and output abudnances, densities and biomasses foreach (string TraitValue in CohortTraitIndices.Keys) { DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); } // Loop over all stock trait value combinations and output biomasses foreach (string TraitValue in StockTraitIndices.Keys) { DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); } } // If ouputting ecosystem metrics has been specified then add these metrics to the output if (OutputMetrics) { DataConverter.ValueToSDS1D(Metrics.CalculateMeanTrophicLevelCell(ecosystemModelGrid, cellIndices, cellIndex), "Mean Trophic Level", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid,cohortFunctionalGroupDefinitions, cellIndices, cellIndex,"trophic index"), "Trophic Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "biomass"), "Biomass Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); double[] FunctionalDiversity = Metrics.CalculateFunctionalDiversity(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex); DataConverter.ValueToSDS1D(FunctionalDiversity[0], "Functional Richness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(FunctionalDiversity[1], "Rao Functional Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[0], "Biomass Richness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[1], "Min Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[2], "Max Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[0], "Trophic Richness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[1], "Min Trophic Index", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[2], "Max Trophic Index", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateArithmeticCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, cellIndex), "Arithmetic Mean Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(Metrics.CalculateGeometricCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, cellIndex), "Geometric Mean Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); } if (TrackMarineSpecifics && MarineCell) { DataConverter.ValueToSDS1D(TotalIncomingNPP, "Incoming NPP", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, (int)currentTimeStep + 1); } if (currentTimeStep % 600 == 0 && currentTimeStep > 0) { BasicOutputMemory.Clone("msds:nc?file=" + _OutputPath + "BasicOutputs" + _OutputSuffix + ".nc&openMode=create"); Console.WriteLine("Cloning grid cell ouputs to file...\n"); } // File outputs for high detail level if (ModelOutputDetail == OutputDetailLevel.High) { if (OutputMetrics) { DataConverter.VectorToSDS2D(Metrics.CalculateTrophicDistribution(ecosystemModelGrid,cellIndices,cellIndex), "Trophic Index Distribution", new string[2] { "Time step", "Trophic Index Bins" }, TimeSteps, Metrics.TrophicIndexBinValues, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, (int)currentTimeStep + 1); } // Loop over trait combinations in the mass bin outputs foreach (var TraitValue in AbundancesInMassBins.Keys) { // Write out abundances in each of the mass bins to the relevant two-dimensional output variables DataConverter.VectorToSDS2D(AbundancesInMassBins[TraitValue], "Log " + TraitValue + " abundance in mass bins", new string[2] { "Time step", "Mass bin" }, TimeSteps, MassBins, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, (int)currentTimeStep + 1); DataConverter.VectorToSDS2D(BiomassesInMassBins[TraitValue], "Log " + TraitValue + " biomass in mass bins", new string[2] { "Time step", "Mass bin" }, TimeSteps, MassBins, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, (int)currentTimeStep + 1); // Write out abundances in combinations of juvenile and adult mass bins to the relevant three-dimensional output variable DataConverter.Array2DToSDS3D(AbundancesInJuvenileAdultMassBins[TraitValue], "Log " + TraitValue + " abundance in juvenile vs adult bins", new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory); // Write out biomasses in combinations of juvenile and adult mass bins to the relevant three-dimensional output variable DataConverter.Array2DToSDS3D(BiomassesInJuvenileAdultMassBins[TraitValue], "Log " + TraitValue + " biomass in juvenile vs adult bins", new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory); } // Loop over tracked cohorts for (int i = 0; i < TrackedCohorts.Count; i++) { // Add the individual body mass and abundance of the tracked cohort to the output dataset string[] TrackedCohortDimensions = new string[] { "Time step", "Cohort ID" }; DataConverter.ValueToSDS2D(TrackedCohortIndividualMasses[i], "Individual body mass", TrackedCohortDimensions, ecosystemModelGrid.GlobalMissingValue, TrackedCohortsOutputMemory, (int)currentTimeStep + 1, i); DataConverter.ValueToSDS2D(TrackedCohortAbundances[i], "Number of individuals", TrackedCohortDimensions, ecosystemModelGrid.GlobalMissingValue, TrackedCohortsOutputMemory, (int)currentTimeStep + 1, i); } if (currentTimeStep % 600 ==0 && currentTimeStep > 0) { MassBinsOutputMemory.Clone("msds:nc?file=" + _OutputPath + "MassBinsOutputs" + _OutputSuffix + ".nc&openMode=create"); TrackedCohortsOutputMemory.Clone("msds:nc?file=" + _OutputPath + "TrackedCohortsOutputs" + _OutputSuffix + ".nc&openMode=create"); } } } }
/// <summary> /// Run advective dispersal /// </summary> /// <param name="cellIndex">The longitudinal and latitudinal indices of the focal grid cell</param> /// <param name="gridForDispersal">The model grid to run dispersal for</param> /// <param name="cohortToDisperse">The cohort to run dispersal for</param> /// <param name="actingCohortFunctionalGroup">The functional group index of the acting cohort</param> /// <param name="actingCohortNumber">The position of the acting cohort wihtin the functional group in the array of grid cell cohorts</param> /// <param name="currentMonth">The current model month</param> public void RunDispersal(uint[] cellIndex, ModelGrid gridForDispersal, Cohort cohortToDisperse, int actingCohortFunctionalGroup, int actingCohortNumber, uint currentMonth) { // An array to hold the dispersal information double[] DispersalArray = new double[6]; // A double to indicate whether or not the cohort has dispersed, and if it has dispersed, where to double CohortDispersed = 0; // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step uint ExitDirection = new uint(); uint EntryDirection = new uint(); ExitDirection = 9999; // An array to hold the present cohort location for the intermediate steps that occur before the final dispersal this time step uint[] PresentLocation = { cellIndex[0], cellIndex[1] }; // Get the u speed and the v speed from the cell data double uAdvectiveSpeed = gridForDispersal.GetEnviroLayer("uVel", currentMonth, PresentLocation[0], PresentLocation[1], out varExists); Debug.Assert(uAdvectiveSpeed != -9999); double vAdvectiveSpeed = gridForDispersal.GetEnviroLayer("vVel", currentMonth, PresentLocation[0], PresentLocation[1], out varExists); Debug.Assert(vAdvectiveSpeed != -9999); uAdvectiveSpeed = RescaleDispersalSpeed(uAdvectiveSpeed); vAdvectiveSpeed = RescaleDispersalSpeed(vAdvectiveSpeed); // Loop through a number of times proportional to the rescaled dispersal for (int mm = 0; mm < _AdvectionTimeStepsPerModelTimeStep; mm++) { // Get the probability of dispersal DispersalArray = CalculateDispersalProbability(gridForDispersal, PresentLocation[0], PresentLocation[1], currentMonth, uAdvectiveSpeed, vAdvectiveSpeed); // Check to see if it does disperse CohortDispersed = CheckForDispersal(DispersalArray[0]); // If it does, check to see where it will end up if (CohortDispersed > 0) { // Check to see if the direction is actually dispersable uint[] DestinationCell = CellToDisperseTo(gridForDispersal, PresentLocation[0], PresentLocation[1], DispersalArray, CohortDispersed, DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection); // If it is, go ahead and update the cohort location if (DestinationCell[0] < 999999) { PresentLocation = DestinationCell; // Get the u speed and the v speed from the cell data uAdvectiveSpeed = gridForDispersal.GetEnviroLayer("uVel", currentMonth, PresentLocation[0], PresentLocation[1], out varExists); vAdvectiveSpeed = gridForDispersal.GetEnviroLayer("vVel", currentMonth, PresentLocation[0], PresentLocation[1], out varExists); uAdvectiveSpeed = RescaleDispersalSpeed(uAdvectiveSpeed); vAdvectiveSpeed = RescaleDispersalSpeed(vAdvectiveSpeed); } } } // Update the dipersal deltas for this cohort, if necessary if ((cellIndex[0] != PresentLocation[0]) || (cellIndex[1] != PresentLocation[1])) { // Update the delta array of cohorts gridForDispersal.DeltaFunctionalGroupDispersalArray[cellIndex[0], cellIndex[1]].Add((uint)actingCohortFunctionalGroup); gridForDispersal.DeltaCohortNumberDispersalArray[cellIndex[0], cellIndex[1]].Add((uint)actingCohortNumber); // Update the delta array of cells to disperse to gridForDispersal.DeltaCellToDisperseToArray[cellIndex[0], cellIndex[1]].Add(PresentLocation); // Update the delta array of exit and entry directions gridForDispersal.DeltaCellExitDirection[cellIndex[0], cellIndex[1]].Add(ExitDirection); gridForDispersal.DeltaCellEntryDirection[cellIndex[0], cellIndex[1]].Add(EntryDirection); } }
public double[] CalculateFunctionalRichness(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions, List <uint[]> cellIndices, int cellIndex, string trait) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double MinCurrentTraitValue = double.MaxValue; double MaxCurrentTraitValue = double.MinValue; double MinModelTraitValue = 0.0; double MaxModelTraitValue = 0.0; switch (trait.ToLower()) { case "biomass": foreach (var CohortList in CellCohorts) { foreach (var cohort in CohortList) { if (cohort.IndividualBodyMass < MinCurrentTraitValue) { MinCurrentTraitValue = cohort.IndividualBodyMass; } if (cohort.IndividualBodyMass > MaxCurrentTraitValue) { MaxCurrentTraitValue = cohort.IndividualBodyMass; } } } //Define upper and lower limits for body mass MinModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min(); MaxModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max(); break; case "trophic index": foreach (var CohortList in CellCohorts) { foreach (var cohort in CohortList) { if (cohort.TrophicIndex < MinCurrentTraitValue) { MinCurrentTraitValue = cohort.TrophicIndex; } if (cohort.TrophicIndex > MaxCurrentTraitValue) { MaxCurrentTraitValue = cohort.TrophicIndex; } } } //Define upper and lower limits for body mass MinModelTraitValue = MinTI; MaxModelTraitValue = MaxTI; break; default: Debug.Fail("Trait not recognised in calculation of ecosystem metrics: " + trait); break; } Debug.Assert((MaxModelTraitValue - MinModelTraitValue) > 0.0, "Division by zero or negative model trait values in calculation of functional richness"); double[] NewArray = { (MaxCurrentTraitValue - MinCurrentTraitValue) / (MaxModelTraitValue - MinModelTraitValue), MinCurrentTraitValue, MaxCurrentTraitValue }; return(NewArray); }
// Determine to which cell the cohort disperses /// <summary> /// Determines the cell to which a cohort disperses /// </summary> /// <param name="madingleyGrid">The ecosystem model grid</param> /// <param name="latIndex">The latitudinal index of the cell being run</param> /// <param name="lonIndex">The longitudinal index of the cell being run</param> /// <param name="dispersalArray"></param> /// <param name="RandomValue"></param> /// <param name="uSpeedIncDiffusion"></param> /// <param name="vSpeedIncDiffusion"></param> /// <param name="exitDirection"></param> /// <param name="entryDirection"></param> /// <returns></returns> protected uint[] CellToDisperseTo(ModelGrid madingleyGrid, uint latIndex, uint lonIndex, double[] dispersalArray, double RandomValue, double uSpeedIncDiffusion, double vSpeedIncDiffusion, ref uint exitDirection, ref uint entryDirection) { uint[] DestinationCell; // Check to see in which axis the cohort disperses // Note that the values in the dispersal array are the proportional area moved outside the grid cell in each direction; we simply compare the random draw to this // to determine the direction in which the cohort moves probabilistically // Longitudinally if (RandomValue <= dispersalArray[1]) { // Work out whether dispersal is to the cell to the E or the W if (uSpeedIncDiffusion > 0) { DestinationCell = madingleyGrid.CheckDispersalEast(latIndex, lonIndex); // Record entry and exit directions. Exit direction is only recorded the first time it happens during a (model) timestep, not each advection time step. if (exitDirection == 9999) { exitDirection = 2; } entryDirection = 6; } else { DestinationCell = madingleyGrid.CheckDispersalWest(latIndex, lonIndex); // Record entry and exit directions. Exit direction is only recorded the first time it happens during a (model) timestep, not each advection time step. if (exitDirection == 9999) { exitDirection = 6; } entryDirection = 2; } } else { // Latitudinally if (RandomValue <= (dispersalArray[1] + dispersalArray[2])) { // Work out whether dispersal is to the cell to the N or the S if (vSpeedIncDiffusion > 0) { DestinationCell = madingleyGrid.CheckDispersalNorth(latIndex, lonIndex); // Record entry and exit directions. Exit direction is only recorded the first time it happens during a (model) timestep, not each advection time step. if (exitDirection == 9999) { exitDirection = 0; } entryDirection = 4; } else { DestinationCell = madingleyGrid.CheckDispersalSouth(latIndex, lonIndex); // Record entry and exit directions. Exit direction is only recorded the first time it happens during a (model) timestep, not each advection time step. if (exitDirection == 9999) { exitDirection = 4; } entryDirection = 0; } } else { // Diagonally. Note that DispersalArray[0] is equal to dispersalArray[1] + dispersalArray[2] + dispersalArray[3], but it // is both faster to compare and also avoids any rounding errors. if (RandomValue <= (dispersalArray[0])) { // Work out to which cell dispersal occurs if (uSpeedIncDiffusion > 0) { if (vSpeedIncDiffusion > 0) { DestinationCell = madingleyGrid.CheckDispersalNorthEast(latIndex, lonIndex); // Record entry and exit directions. Exit direction is only recorded the first time it happens during a (model) timestep, not each advection time step. if (exitDirection == 9999) { exitDirection = 1; } entryDirection = 5; } else { DestinationCell = madingleyGrid.CheckDispersalSouthEast(latIndex, lonIndex); // Record entry and exit directions. Exit direction is only recorded the first time it happens during a (model) timestep, not each advection time step. if (exitDirection == 9999) { exitDirection = 5; } entryDirection = 1; } } else { if (vSpeedIncDiffusion > 0) { DestinationCell = madingleyGrid.CheckDispersalNorthWest(latIndex, lonIndex); // Record entry and exit directions. Exit direction is only recorded the first time it happens during a (model) timestep, not each advection time step. if (exitDirection == 9999) { exitDirection = 7; } entryDirection = 3; } else { DestinationCell = madingleyGrid.CheckDispersalSouthWest(latIndex, lonIndex); // Record entry and exit directions. Exit direction is only recorded the first time it happens during a (model) timestep, not each advection time step. if (exitDirection == 9999) { exitDirection = 3; } entryDirection = 7; } } } else { // This should never happen. Means that the random number indicates dispersal by being lower than the probability, but // that in the comparison abive, it is higher than the probability. Debug.Fail("Error when determining which cell to disperse to"); Console.WriteLine("Error when determining which cell to disperse to"); Console.ReadKey(); DestinationCell = new uint[2] { 9999999, 9999999 }; } } } return(DestinationCell); }
public void TimeStepOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions, List <uint[]> cellIndices, uint currentTimeStep, MadingleyModelInitialisation initialisation) { // Calculate the output variables for this time step CalculateOutputs(ecosystemModelGrid, cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, cellIndices, initialisation, currentTimeStep); // Write the total biomass of cohorts to the live display if (LiveOutputs) { DataConverter.Array2DToSDS2D(LogBiomassDensityGridCohorts, "Log(Biomass density, g/km^2)", ecosystemModelGrid.Lats, ecosystemModelGrid.Lons, 0, DataSetToViewLive); } Console.WriteLine("Writing grid ouputs to file...\n"); // Add the grid of total biomass in cells to the file dataset DataConverter.Array2DToSDS3D(LogBiomassDensityGridCohorts, "Biomass density", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, 0, GridOutput); // Add the grid of total abudance in cells to the file dataset DataConverter.Array2DToSDS3D(LogAbundanceDensityGridCohorts, "Abundance density", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, 0, GridOutput); // Temporary outputs to check plant model DataConverter.Array2DToSDS3D(Realm, "Realm", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, GridOutput); DataConverter.Array2DToSDS3D(FrostDays, "Fraction year frost", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, GridOutput); DataConverter.Array2DToSDS3D(FracEvergreen, "Fraction evergreen", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, GridOutput); DataConverter.Array2DToSDS3D(HANPP, "HANPP", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, GridOutput); DataConverter.Array2DToSDS3D(Temperature, "Temperature", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, GridOutput); if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High)) { foreach (var TraitValue in BiomassDensityGrid.Keys) { // Add the biomass grids for individual trait combinations to the file dataset DataConverter.Array2DToSDS3D(BiomassDensityGrid[TraitValue], TraitValue + "biomass density", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, GridOutput); } foreach (var Key in AbundanceDensityGrid.Keys) { DataConverter.Array2DToSDS3D(AbundanceDensityGrid[Key], Key + "abundance density", new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, GridOutput); } } // Output ecosystem metrics if (OutputMetrics) { foreach (string Key in MetricsGrid.Keys) { DataConverter.Array2DToSDS3D(MetricsGrid[Key], Key, new string[] { "Latitude", "Longitude", "Time step" }, (int)currentTimeStep + 1, ecosystemModelGrid.GlobalMissingValue, GridOutput); } } }
private bool CheckStarvationDispersal(ModelGrid gridForDispersal, uint latIndex, uint lonIndex, Cohort cohortToDisperse, int functionalGroup, int cohortNumber) { // A boolean to check whether a cohort has dispersed bool CohortHasDispersed = false; // Check for starvation driven dispersal // What is the present body mass of the cohort? // Note that at present we are just tracking starvation for adults double IndividualBodyMass = cohortToDisperse.IndividualBodyMass; double AdultMass = cohortToDisperse.AdultMass; // Temporary variables to keep track of directions in which cohorts enter/exit cells during the multiple advection steps per time step uint ExitDirection = new uint(); uint EntryDirection = new uint(); ExitDirection = 9999; // Assume a linear relationship between probability of dispersal and body mass loss, up to _StarvationDispersalBodyMassThreshold // at which point the cohort will try to disperse every time step if (IndividualBodyMass < AdultMass) { double ProportionalPresentMass = IndividualBodyMass / AdultMass; // If the body mass loss is greater than the starvation dispersal body mass threshold, then the cohort tries to disperse if (ProportionalPresentMass < _StarvationDispersalBodyMassThreshold) { // Cohort tries to disperse double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, latIndex, lonIndex, CalculateDispersalSpeed(AdultMass)); double CohortDispersed = CheckForDispersal(DispersalArray[0]); if (CohortDispersed > 0) { uint[] DestinationCell = CellToDisperseTo(gridForDispersal, latIndex, lonIndex, DispersalArray, DispersalArray[0], DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection); // Update the delta array of cells to disperse to, if the cohort moves if (DestinationCell[0] < 999999) { // Update the delta array of cohorts gridForDispersal.DeltaFunctionalGroupDispersalArray[latIndex, lonIndex].Add((uint)functionalGroup); gridForDispersal.DeltaCohortNumberDispersalArray[latIndex, lonIndex].Add((uint)cohortNumber); // Update the delta array of cells to disperse to gridForDispersal.DeltaCellToDisperseToArray[latIndex, lonIndex].Add(DestinationCell); // Update the delta array of exit and entry directions gridForDispersal.DeltaCellExitDirection[latIndex, lonIndex].Add(ExitDirection); gridForDispersal.DeltaCellEntryDirection[latIndex, lonIndex].Add(EntryDirection); } } // Note that regardless of whether or not it succeeds, if a cohort tries to disperse, it is counted as having dispersed for // the purposes of not then allowing it to disperse based on its density. CohortHasDispersed = true; } // Otherwise, the cohort has a chance of trying to disperse proportional to its mass loss else { // Cohort tries to disperse with a particular probability // Draw a random number if (((1.0 - ProportionalPresentMass) / (1.0 - _StarvationDispersalBodyMassThreshold)) > RandomNumberGenerator.GetUniform()) { // Cohort tries to disperse double[] DispersalArray = CalculateDispersalProbability(gridForDispersal, latIndex, lonIndex, CalculateDispersalSpeed(AdultMass)); double CohortDispersed = CheckForDispersal(DispersalArray[0]); if (CohortDispersed > 0) { uint[] DestinationCell = CellToDisperseTo(gridForDispersal, latIndex, lonIndex, DispersalArray, DispersalArray[0], DispersalArray[4], DispersalArray[5], ref ExitDirection, ref EntryDirection); // Update the delta array of cells to disperse to, if the cohort moves if (DestinationCell[0] < 999999) { // Update the delta array of cohorts gridForDispersal.DeltaFunctionalGroupDispersalArray[latIndex, lonIndex].Add((uint)functionalGroup); gridForDispersal.DeltaCohortNumberDispersalArray[latIndex, lonIndex].Add((uint)cohortNumber); // Update the delta array of cells to disperse to gridForDispersal.DeltaCellToDisperseToArray[latIndex, lonIndex].Add(DestinationCell); // Update the delta array of exit and entry directions gridForDispersal.DeltaCellExitDirection[latIndex, lonIndex].Add(ExitDirection); gridForDispersal.DeltaCellEntryDirection[latIndex, lonIndex].Add(EntryDirection); } } CohortHasDispersed = true; } } } return(CohortHasDispersed); }
public InputModelState(string outputPath, string filename, ModelGrid ecosystemModelGrid, List <uint[]> cellList) { //Set the input state flag to be true _InputState = true; // Construct the string required to access the file using Scientific Dataset string _ReadFileString = "msds:nc?file=input/ModelStates/" + filename + ".nc&openMode=readOnly"; // Open the data file using Scientific Dataset DataSet StateDataSet = DataSet.Open(_ReadFileString); float[] Latitude = StateDataSet.GetData <float[]>("Latitude"); float[] Longitude = StateDataSet.GetData <float[]>("Longitude"); float[] CohortFunctionalGroup = StateDataSet.GetData <float[]>("Cohort Functional Group"); float[] Cohort = StateDataSet.GetData <float[]>("Cohort"); float[] StockFunctionalGroup = StateDataSet.GetData <float[]>("Stock Functional Group"); float[] Stock = StateDataSet.GetData <float[]>("Stock"); // Check that the longitudes and latitudes in the input state match the cell environment for (int la = 0; la < Latitude.Length; la++) { Debug.Assert(ecosystemModelGrid.GetCellEnvironment((uint)la, 0)["Latitude"][0] == Latitude[la], "Error: input-state grid doesn't match current model grid"); } for (int lo = 0; lo < Longitude.Length; lo++) { Debug.Assert(ecosystemModelGrid.GetCellEnvironment(0, (uint)lo)["Longitude"][0] == Longitude[lo], "Error: input-state grid doesn't match current model grid"); } List <double[, , ]> CohortJuvenileMass = new List <double[, , ]>(); List <double[, , ]> CohortAdultMass = new List <double[, , ]>(); List <double[, , ]> CohortIndividualBodyMass = new List <double[, , ]>(); List <double[, , ]> CohortCohortAbundance = new List <double[, , ]>(); List <double[, , ]> CohortLogOptimalPreyBodySizeRatio = new List <double[, , ]>(); List <double[, , ]> CohortBirthTimeStep = new List <double[, , ]>(); List <double[, , ]> CohortProportionTimeActive = new List <double[, , ]>(); List <double[, , ]> CohortTrophicIndex = new List <double[, , ]>(); double[,,,] tempData = new double[Latitude.Length, Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]; tempData = StateDataSet.GetData <double[, , , ]>("CohortJuvenileMass"); for (int la = 0; la < Latitude.Length; la++) { CohortJuvenileMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { for (int c = 0; c < Cohort.Length; c++) { CohortJuvenileMass[(int)cell[0]][cell[1], fg, c] = tempData[ cell[0], cell[1], fg, c]; } } } tempData = StateDataSet.GetData <double[, , , ]>("CohortAdultMass"); for (int la = 0; la < Latitude.Length; la++) { CohortAdultMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { for (int c = 0; c < Cohort.Length; c++) { CohortAdultMass[(int)cell[0]][cell[1], fg, c] = tempData[ cell[0], cell[1], fg, c]; } } } tempData = StateDataSet.GetData <double[, , , ]>("CohortIndividualBodyMass"); for (int la = 0; la < Latitude.Length; la++) { CohortIndividualBodyMass.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { for (int c = 0; c < Cohort.Length; c++) { CohortIndividualBodyMass[(int)cell[0]][cell[1], fg, c] = tempData[ cell[0], cell[1], fg, c]; } } } tempData = StateDataSet.GetData <double[, , , ]>("CohortCohortAbundance"); for (int la = 0; la < Latitude.Length; la++) { CohortCohortAbundance.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { for (int c = 0; c < Cohort.Length; c++) { CohortCohortAbundance[(int)cell[0]][cell[1], fg, c] = tempData[ cell[0], cell[1], fg, c]; } } } tempData = StateDataSet.GetData <double[, , , ]>("CohortLogOptimalPreyBodySizeRatio"); for (int la = 0; la < Latitude.Length; la++) { CohortLogOptimalPreyBodySizeRatio.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { for (int c = 0; c < Cohort.Length; c++) { CohortLogOptimalPreyBodySizeRatio[(int)cell[0]][cell[1], fg, c] = tempData[ cell[0], cell[1], fg, c]; } } } tempData = StateDataSet.GetData <double[, , , ]>("CohortBirthTimeStep"); for (int la = 0; la < Latitude.Length; la++) { CohortBirthTimeStep.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { for (int c = 0; c < Cohort.Length; c++) { CohortBirthTimeStep[(int)cell[0]][cell[1], fg, c] = tempData[ cell[0], cell[1], fg, c]; } } } tempData = StateDataSet.GetData <double[, , , ]>("CohortProportionTimeActive"); for (int la = 0; la < Latitude.Length; la++) { CohortProportionTimeActive.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { for (int c = 0; c < Cohort.Length; c++) { CohortProportionTimeActive[(int)cell[0]][cell[1], fg, c] = tempData[ cell[0], cell[1], fg, c]; } } } tempData = StateDataSet.GetData <double[, , , ]>("CohortTrophicIndex"); for (int la = 0; la < Latitude.Length; la++) { CohortTrophicIndex.Add(new double[Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { for (int c = 0; c < Cohort.Length; c++) { CohortTrophicIndex[(int)cell[0]][cell[1], fg, c] = tempData[ cell[0], cell[1], fg, c]; } } } _GridCellCohorts = new GridCellCohortHandler[Latitude.Length, Longitude.Length]; long temp = 0; for (int cell = 0; cell < cellList.Count; cell++) { _GridCellCohorts[cellList[cell][0], cellList[cell][1]] = new GridCellCohortHandler(CohortFunctionalGroup.Length); for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { _GridCellCohorts[cellList[cell][0], cellList[cell][1]][fg] = new List <Cohort>(); for (int c = 0; c < Cohort.Length; c++) { if (CohortCohortAbundance[(int)cellList[cell][0]][cellList[cell][1], fg, c] > 0.0) { Cohort TempCohort = new Cohort( (byte)fg, CohortJuvenileMass[(int)cellList[cell][0]][cellList[cell][1], fg, c], CohortAdultMass[(int)cellList[cell][0]][cellList[cell][1], fg, c], CohortIndividualBodyMass[(int)cellList[cell][0]][cellList[cell][1], fg, c], CohortCohortAbundance[(int)cellList[cell][0]][cellList[cell][1], fg, c], Math.Exp(CohortLogOptimalPreyBodySizeRatio[(int)cellList[cell][0]][cellList[cell][1], fg, c]), Convert.ToUInt16(CohortBirthTimeStep[(int)cellList[cell][0]][cellList[cell][1], fg, c]), CohortProportionTimeActive[(int)cellList[cell][0]][cellList[cell][1], fg, c], ref temp, CohortTrophicIndex[(int)cellList[cell][0]][cellList[cell][1], fg, c], false); _GridCellCohorts[cellList[cell][0], cellList[cell][1]][fg].Add(TempCohort); } } } } CohortJuvenileMass.RemoveRange(0, CohortJuvenileMass.Count); CohortAdultMass.RemoveRange(0, CohortAdultMass.Count); CohortIndividualBodyMass.RemoveRange(0, CohortIndividualBodyMass.Count); CohortCohortAbundance.RemoveRange(0, CohortCohortAbundance.Count); CohortLogOptimalPreyBodySizeRatio.RemoveRange(0, CohortLogOptimalPreyBodySizeRatio.Count); CohortBirthTimeStep.RemoveRange(0, CohortBirthTimeStep.Count); CohortProportionTimeActive.RemoveRange(0, CohortProportionTimeActive.Count); CohortTrophicIndex.RemoveRange(0, CohortTrophicIndex.Count); List <double[, , ]> StockIndividualBodyMass = new List <double[, , ]>(); List <double[, , ]> StockTotalBiomass = new List <double[, , ]>(); double[,,,] tempData2 = new double[Latitude.Length, Longitude.Length, StockFunctionalGroup.Length, Stock.Length]; tempData2 = StateDataSet.GetData <double[, , , ]>("StockIndividualBodyMass"); for (int la = 0; la < Latitude.Length; la++) { StockIndividualBodyMass.Add(new double[Longitude.Length, StockFunctionalGroup.Length, Stock.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < StockFunctionalGroup.Length; fg++) { for (int c = 0; c < Stock.Length; c++) { StockIndividualBodyMass[(int)cell[0]][cell[1], fg, c] = tempData2[ cell[0], cell[1], fg, c]; } } } tempData2 = StateDataSet.GetData <double[, , , ]>("StockTotalBiomass"); for (int la = 0; la < Latitude.Length; la++) { StockTotalBiomass.Add(new double[Longitude.Length, StockFunctionalGroup.Length, Stock.Length]); } foreach (uint[] cell in cellList) { for (int fg = 0; fg < StockFunctionalGroup.Length; fg++) { for (int c = 0; c < Stock.Length; c++) { StockTotalBiomass[(int)cell[0]][cell[1], fg, c] = tempData2[ cell[0], cell[1], fg, c]; } } } _GridCellStocks = new GridCellStockHandler[Latitude.Length, Longitude.Length]; for (int cell = 0; cell < cellList.Count; cell++) { _GridCellStocks[cellList[cell][0], cellList[cell][1]] = new GridCellStockHandler(StockFunctionalGroup.Length); for (int fg = 0; fg < StockFunctionalGroup.Length; fg++) { _GridCellStocks[cellList[cell][0], cellList[cell][1]][fg] = new List <Stock>(); for (int c = 0; c < Stock.Length; c++) { if (StockTotalBiomass[(int)cellList[cell][0]][cellList[cell][1], fg, c] > 0.0) { Stock TempStock = new Stock( (byte)fg, StockIndividualBodyMass[(int)cellList[cell][0]][cellList[cell][1], fg, c], StockTotalBiomass[(int)cellList[cell][0]][cellList[cell][1], fg, c]); _GridCellStocks[cellList[cell][0], cellList[cell][1]][fg].Add(TempStock); } } } } }
/// <summary> /// Extract an array of values from a state variable in a model grid and add to a two-dimensional variable in an SDS object /// </summary> /// <param name="ecosystemModelGrid">The model grid to extract data from</param> /// <param name="cellIndices">List of indices of active cells in the model grid</param> /// <param name="gridVariableName">The name of the state variable in the model grid</param> /// <param name="traitValue">The trait value of the functional groups to get data for</param> /// <param name="variableType">The type of the state variable: 'stock' or 'cohort'</param> /// <param name="outputVariableName">The name of the variable to write to</param> /// <param name="SDSObject">The SDS object to write to</param> /// <param name="functionalGroupHandler">The functional group handler corresponding to cohorts or stocks</param> /// <param name="initialisation">The Madingley Model initialisation</param> public void Array2DToSDS2D(ModelGrid ecosystemModelGrid, List <uint[]> cellIndices, string gridVariableName, string traitValue, string variableType, string outputVariableName, DataSet SDSObject, FunctionalGroupDefinitions functionalGroupHandler, MadingleyModelInitialisation initialisation) { // Get the missing value from the model grid double MissingValue = ecosystemModelGrid.GlobalMissingValue; // create an array to hold the data to output double[,] dataToConvert = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; // generate arrays to hold latitudes and longitudes float[] lats = new float[ecosystemModelGrid.NumLatCells]; float[] lons = new float[ecosystemModelGrid.NumLonCells]; // Populate arrays of latitudes and longitudes, converting from bottom left cell references as used in the model grid // to cell centre references as required by SDS for (uint ii = 0; ii < ecosystemModelGrid.NumLatCells; ii++) { lats[ii] = ecosystemModelGrid.Lats[ii] + (ecosystemModelGrid.LatCellSize / 2); } for (uint jj = 0; jj < ecosystemModelGrid.NumLonCells; jj++) { lons[jj] = ecosystemModelGrid.Lons[jj] + (ecosystemModelGrid.LonCellSize / 2); } // Get the required data from the model grid dataToConvert = ecosystemModelGrid.GetStateVariableGrid(gridVariableName, traitValue, functionalGroupHandler.AllFunctionalGroupsIndex, cellIndices, variableType, initialisation); // If not already contained in the SDS, add the dimension information (geographic coordinates) if (SDSObject.Variables.Contains("Latitude")) { } else { SDSObject.AddVariable <float>("Latitude", lats, "Lat"); } if (SDSObject.Variables.Contains("Longitude")) { } else { SDSObject.AddVariable <float>("Longitude", lons, "Lon"); } // If the SDS object already contains the output variable, then add the data. Otherwise, define the variable and then add the data if (SDSObject.Variables.Contains(outputVariableName)) { SDSObject.PutData <double[, ]>(outputVariableName, dataToConvert); // Commit the changes SDSObject.Commit(); } else { // Set up the dimensions and add the gridded data string[] dimensions = { "Lat", "Lon" }; var DataGrid = SDSObject.AddVariable <double>(outputVariableName, dataToConvert, dimensions); // Add appropriate metadata (including missing values) DataGrid.Metadata["DisplayName"] = outputVariableName; DataGrid.Metadata["MissingValue"] = (double)MissingValue; // Commit changes to update data set SDSObject.Commit(); } }
/// <summary> /// Generates the initial file outputs /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="MarineCell">Whether the current cell is a marine cell</param> /// <param name="cellIndices">The list of all cells to run the model for</param> /// <param name="cellIndex">The index of the current cell in the list of all cells to run the model for</param> private void InitialFileOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, Boolean MarineCell, List<uint[]> cellIndices, int cellIndex) { Console.WriteLine("Writing initial grid cell outputs to memory..."); //Write the low level outputs first DataConverter.ValueToSDS1D(TotalLivingBiomassDensity, "Total Biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(TotalHeterotrophAbundanceDensity, "Heterotroph Abundance density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(TotalHeterotrophBiomassDensity, "Heterotroph Biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); // File outputs for medium and high detail levels if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High)) { if (MarineCell) { foreach (string TraitValue in CohortTraitIndicesMarine.Keys) { // Write densities, biomasses and abundances in different functional groups to the relevant one-dimensional output variables DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); } foreach (string TraitValue in StockTraitIndicesMarine.Keys) { DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); } } else { foreach (string TraitValue in CohortTraitIndices.Keys) { // Write densities, biomasses and abundances in different functional groups to the relevant one-dimensional output variables DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); } foreach (string TraitValue in StockTraitIndices.Keys) { DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass density", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); } } if (OutputMetrics) { DataConverter.ValueToSDS1D(Metrics.CalculateMeanTrophicLevelCell(ecosystemModelGrid,cellIndices,cellIndex), "Mean Trophic Level", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid, cohortFunctionalGroupDefinitions,cellIndices, cellIndex,"trophic index"), "Trophic Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "biomass"), "Biomass Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); double[] FunctionalDiversity = Metrics.CalculateFunctionalDiversity(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex); DataConverter.ValueToSDS1D(FunctionalDiversity[0], "Functional Richness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(FunctionalDiversity[1], "Rao Functional Evenness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[0], "Biomass Richness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[1], "Min Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Biomass")[2], "Max Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[0], "Trophic Richness", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[1], "Min Trophic Index", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, cellIndex, "Trophic index")[2], "Max Trophic Index", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateArithmeticCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, cellIndex), "Arithmetic Mean Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); DataConverter.ValueToSDS1D(Metrics.CalculateGeometricCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, cellIndex), "Geometric Mean Bodymass", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); } if (MarineCell && TrackMarineSpecifics) { DataConverter.ValueToSDS1D(TotalIncomingNPP, "Incoming NPP", "Time step", ecosystemModelGrid.GlobalMissingValue, BasicOutputMemory, 0); } // File outputs for high detail level if (ModelOutputDetail == OutputDetailLevel.High) { if (OutputMetrics) { DataConverter.VectorToSDS2D(Metrics.CalculateTrophicDistribution(ecosystemModelGrid,cellIndices,cellIndex), "Trophic Index Distribution", new string[2] { "Time step", "Trophic Index Bins" }, TimeSteps, Metrics.TrophicIndexBinValues, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, 0); } foreach (var TraitValue in AbundancesInMassBins.Keys) { DataConverter.VectorToSDS2D(AbundancesInMassBins[TraitValue], "Log " + TraitValue + " abundance in mass bins", new string[2] { "Time step", "Mass bin" }, TimeSteps, MassBins, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, 0); DataConverter.VectorToSDS2D(BiomassesInMassBins[TraitValue], "Log " + TraitValue + " biomass in mass bins", new string[2] { "Time step", "Mass bin" }, TimeSteps, MassBins, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory, 0); // Write out abundances in combinations of juvenile and adult mass bins to the relevant three-dimensional output variables DataConverter.Array2DToSDS3D(AbundancesInJuvenileAdultMassBins[TraitValue], "Log " + TraitValue + " abundance in juvenile vs adult bins", new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory); DataConverter.Array2DToSDS3D(BiomassesInJuvenileAdultMassBins[TraitValue], "Log " + TraitValue + " biomass in juvenile vs adult bins", new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, MassBinsOutputMemory); } // Write outputs for tracking individual cohorts // Loop over tracked cohorts for (int i = 0; i < TrackedCohorts.Count; i++) { // Add the individual body mass of the tracked cohort to the output dataset string[] TrackedCohortDimensions = new string[] { "Time step", "Cohort ID" }; DataConverter.ValueToSDS2D(TrackedCohortIndividualMasses[i], "Individual body mass", TrackedCohortDimensions, ecosystemModelGrid.GlobalMissingValue, TrackedCohortsOutputMemory, 0, i); DataConverter.ValueToSDS2D(TrackedCohortAbundances[i], "Number of individuals", TrackedCohortDimensions, ecosystemModelGrid.GlobalMissingValue, TrackedCohortsOutputMemory, 0, i); } } } }
/// <summary> /// Record dispersal events in the dispersal tracker /// </summary> /// <param name="inboundCohorts">The cohorts arriving in a cell in the current time step</param> /// <param name="outboundCohorts">The cohorts leaving a cell in the current time step</param> /// <param name="outboundCohortWeights">The body masses of cohorts leaving the cell in the current time step</param> /// <param name="timestep">The current model time step</param> /// <param name="madingleyModelGrid">The model grid</param> public void RecordDispersalForACell(uint[, ,] inboundCohorts, uint[, ,] outboundCohorts, List <double>[,] outboundCohortWeights, uint timestep, ModelGrid madingleyModelGrid) { _TrackDispersal.RecordDispersal(inboundCohorts, outboundCohorts, outboundCohortWeights, timestep, madingleyModelGrid); }
private void CalculateOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions, List <uint[]> cellIndices, MadingleyModelInitialisation initialisation, uint currentTimestep) { // Get grids of the total biomass densities of all stocks and all cohorts in each grid cell LogBiomassDensityGridCohorts = ecosystemModelGrid.GetStateVariableGridLogDensityPerSqKm("Biomass", "NA", cohortFunctionalGroupDefinitions. AllFunctionalGroupsIndex, cellIndices, "cohort", initialisation); LogBiomassDensityGridStocks = ecosystemModelGrid.GetStateVariableGridLogDensityPerSqKm("Biomass", "NA", stockFunctionalGroupDefinitions. AllFunctionalGroupsIndex, cellIndices, "stock", initialisation); // Get grids of total abundance densities of all stocks and all cohorts in each grid cell LogAbundanceDensityGridCohorts = ecosystemModelGrid.GetStateVariableGridLogDensityPerSqKm("Abundance", "NA", cohortFunctionalGroupDefinitions. AllFunctionalGroupsIndex, cellIndices, "cohort", initialisation); // Loop over grid cells and add stock and cohort biomass density to get the total of all biomass densities for (int ii = 0; ii < ecosystemModelGrid.NumLatCells; ii++) { for (int jj = 0; jj < ecosystemModelGrid.NumLonCells; jj++) { LogBiomassDensityGrid[ii, jj] = Math.Log(Math.Exp(LogBiomassDensityGridCohorts[ii, jj]) + Math.Exp(LogBiomassDensityGridStocks[ii, jj])); } } string[] Keys = CohortTraitIndices.Keys.ToArray(); foreach (string Key in Keys) { BiomassDensityGrid[Key] = ecosystemModelGrid.GetStateVariableGridLogDensityPerSqKm("Biomass", "NA", CohortTraitIndices[Key], cellIndices, "cohort", initialisation); AbundanceDensityGrid[Key] = ecosystemModelGrid.GetStateVariableGridLogDensityPerSqKm("Abundance", "NA", CohortTraitIndices[Key], cellIndices, "cohort", initialisation); } Keys = StockTraitIndices.Keys.ToArray(); foreach (string Key in Keys) { BiomassDensityGrid[Key] = ecosystemModelGrid.GetStateVariableGridLogDensityPerSqKm("Biomass", "NA", StockTraitIndices[Key], cellIndices, "stock", initialisation); } // Temporary outputs to check plant model Realm = ecosystemModelGrid.GetEnviroGrid("Realm", 0); FrostDays = ecosystemModelGrid.GetEnviroGrid("Fraction Year Frost", 0); Temperature = ecosystemModelGrid.GetEnviroGrid("Temperature", Utils.GetCurrentMonth(currentTimestep, initialisation.GlobalModelTimeStepUnit)); for (int i = 0; i < ecosystemModelGrid.NumLatCells; i++) { for (int j = 0; j < ecosystemModelGrid.NumLonCells; j++) { FracEvergreen[i, j] = BiomassDensityGrid["evergreen"][i, j] / BiomassDensityGrid["autotroph"][i, j]; } } HANPP = ecosystemModelGrid.GetEnviroGrid("HANPP", 0); if (OutputMetrics) { //Calculate the values for the ecosystem metrics for each of the grid cells for (int i = 0; i < cellIndices.Count; i++) { uint latIndex = cellIndices[i][0]; uint lonIndex = cellIndices[i][1]; MetricsGrid["Mean Trophic Level"][latIndex, lonIndex] = Metrics.CalculateMeanTrophicLevelCell(ecosystemModelGrid, cellIndices, i); MetricsGrid["Trophic Evenness"][latIndex, lonIndex] = Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i, "trophic index"); MetricsGrid["Biomass Evenness"][latIndex, lonIndex] = Metrics.CalculateFunctionalEvennessRao(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i, "biomass"); double[] FunctionalDiversity = Metrics.CalculateFunctionalDiversity(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i); // Functional Richness not currently calculated //MetricsGrid["Functional Richness"][latIndex, lonIndex] = FunctionalDiversity[0]; MetricsGrid["Rao Functional Evenness"][latIndex, lonIndex] = FunctionalDiversity[1]; MetricsGrid["Biomass Richness"][latIndex, lonIndex] = Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i, "Biomass")[0]; MetricsGrid["Min Bodymass"][latIndex, lonIndex] = Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i, "Biomass")[1]; MetricsGrid["Max Bodymass"][latIndex, lonIndex] = Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i, "Biomass")[2]; MetricsGrid["Trophic Richness"][latIndex, lonIndex] = Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i, "Trophic Index")[0]; MetricsGrid["Min Trophic Index"][latIndex, lonIndex] = Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i, "Trophic Index")[1]; MetricsGrid["Max Trophic Index"][latIndex, lonIndex] = Metrics.CalculateFunctionalRichness(ecosystemModelGrid, cohortFunctionalGroupDefinitions, cellIndices, i, "Trophic Index")[2]; MetricsGrid["Arithmetic Mean Bodymass"][latIndex, lonIndex] = Metrics.CalculateArithmeticCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, i); MetricsGrid["Geometric Mean Bodymass"][latIndex, lonIndex] = Metrics.CalculateGeometricCommunityMeanBodyMass(ecosystemModelGrid, cellIndices, i); } } }
public void InitialOutputs(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions, List <uint[]> cellIndices, MadingleyModelInitialisation initialisation) { Console.WriteLine("Writing initial grid outputs..."); // Calculate the output variables CalculateOutputs(ecosystemModelGrid, cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, cellIndices, initialisation, 0); // Write the total biomass of cohorts to the live display if (LiveOutputs) { DataConverter.Array2DToSDS2D(LogBiomassDensityGridCohorts, "Log(Biomass density, g/km^2)", ecosystemModelGrid.Lats, ecosystemModelGrid.Lons, ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive); } // Add the grid of total biomass in cells to the file dataset DataConverter.Array2DToSDS3D(LogBiomassDensityGridCohorts, "Biomass density", new string[] { "Latitude", "Longitude", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, GridOutput); DataConverter.Array2DToSDS3D(LogAbundanceDensityGridCohorts, "Abundance density", new string[] { "Latitude", "Longitude", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, GridOutput); // Temporary outputs to check plant model DataConverter.Array2DToSDS3D(Realm, "Realm", new string[] { "Latitude", "Longitude", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, GridOutput); DataConverter.Array2DToSDS3D(HANPP, "HANPP", new string[] { "Latitude", "Longitude", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, GridOutput); DataConverter.Array2DToSDS3D(Temperature, "Temperature", new string[] { "Latitude", "Longitude", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, GridOutput); // File outputs for medium and high detail levels if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High)) { // Add the biomass grids for individual trait combinations to the file dataset foreach (var Key in BiomassDensityGrid.Keys) { DataConverter.Array2DToSDS3D(BiomassDensityGrid[Key], Key + "biomass density", new string[] { "Latitude", "Longitude", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, GridOutput); } // Add the abundance density grid foreach (var Key in AbundanceDensityGrid.Keys) { DataConverter.Array2DToSDS3D(AbundanceDensityGrid[Key], Key + "abundance density", new string[] { "Latitude", "Longitude", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, GridOutput); } // Output ecosystem metrics if (OutputMetrics) { foreach (string Key in MetricsGrid.Keys) { DataConverter.Array2DToSDS3D(MetricsGrid[Key], Key, new string[] { "Latitude", "Longitude", "Time step" }, 0, ecosystemModelGrid.GlobalMissingValue, GridOutput); } } } }
/// <summary> /// Calculates functional diversity of cohorts in a grid cell as functional richness and functional diveregence (using the Rao Index) /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cohortDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="cellIndices">The list of cell indices in the current model simulation</param> /// <param name="cellIndex">The index of the current cell within the list of cells to run</param> /// <returns>A pair of values representing the functional richness and functional divergence (functional richness currently disabled!)</returns> public double[] CalculateFunctionalDiversity(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions, List <uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); //Variable to hold the functional richness value for the current cohorts double FunctionalRichness; //Variable to hold the functional divergence value for the current cohorts double RaoFunctionalDivergence = 0.0; double[,] Distances = new double[CellCohorts.GetNumberOfCohorts(), CellCohorts.GetNumberOfCohorts()]; List <string> AllTraitNames = cohortDefinitions.GetAllTraitNames().ToList(); AllTraitNames.Remove("realm"); AllTraitNames.Remove("heterotroph/autotroph"); AllTraitNames.Remove("diet"); string[] TraitNames = AllTraitNames.ToArray(); //Define upper and lower limits for body mass double MinMass = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min(); double MaxMass = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max(); //Define upp and lower limits for trophic index double MaxTI = 40.0; double MinTI = 1.0; // Construct an array of functional trait values for each cohort // Rows are specific cohorts // Columns are the functional traits (these include different types: // quantative: current mass, trophic index // nominal: diet, reproductive strategy, mobility, metabolism Tuple <double[], string[]>[] CohortFunctionalTraits = new Tuple <double[], string[]> [CellCohorts.GetNumberOfCohorts()]; double[] IndividualBodyMasses = new double[CellCohorts.GetNumberOfCohorts()]; double[] TrophicIndex = new double[CellCohorts.GetNumberOfCohorts()]; string[][] CohortNominalTraitValues = new string[TraitNames.Length][]; for (int i = 0; i < TraitNames.Length; i++) { CohortNominalTraitValues[i] = new string[CellCohorts.GetNumberOfCohorts()]; } // Construct a vector of cohort biomass (in case we want to weight by them) double[] CohortTotalBiomasses = new double[CellCohorts.GetNumberOfCohorts()]; string[] TraitValues = new string[TraitNames.Length]; double[] QuantitativeTraitValues = new double[2]; int CohortNumberCounter = 0; for (int fg = 0; fg < CellCohorts.Count; fg++) { foreach (Cohort c in CellCohorts[fg]) { TraitValues = cohortDefinitions.GetTraitValues(TraitNames, fg); for (int ii = 0; ii < TraitValues.Length; ii++) { CohortNominalTraitValues[ii][CohortNumberCounter] = TraitValues[ii]; } IndividualBodyMasses[CohortNumberCounter] = c.IndividualBodyMass; TrophicIndex[CohortNumberCounter] = c.TrophicIndex; QuantitativeTraitValues[0] = c.IndividualBodyMass; QuantitativeTraitValues[1] = c.TrophicIndex; CohortFunctionalTraits[CohortNumberCounter] = new Tuple <double[], string[]>(QuantitativeTraitValues, TraitValues); CohortTotalBiomasses[CohortNumberCounter] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; CohortNumberCounter++; } } List <double[, ]> DistanceList = new List <double[, ]>(); DistanceList.Add(CalculateDistanceMatrix(IndividualBodyMasses, MaxMass, MinMass)); DistanceList.Add(CalculateDistanceMatrix(TrophicIndex, MaxTI, MinTI)); foreach (string[] t in CohortNominalTraitValues) { DistanceList.Add(CalculateDistanceMatrix(t)); } Distances = CalculateAggregateDistance(DistanceList); RaoFunctionalDivergence = RaoEntropy(Distances, CohortTotalBiomasses); return(new double[] { 0.0, RaoFunctionalDivergence }); }
/// <summary> /// Apply all updates from the ecological processes to the properties of the acting cohort and to the environment /// </summary> public void UpdateAllCrossGridCellEcology(ModelGrid madingleyModelGrid, ref uint dispersalCounter, CrossCellProcessTracker trackCrossCellProcesses, uint currentTimeStep) { // Create an array to hold the number of cohorts dispersing in each direction from each grid cell uint[, ,] InboundCohorts = new uint[madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(0), madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(1), 8]; // Create an array to hold the number of cohorts dispersing in each direction to each grid cell uint[, ,] OutboundCohorts = new uint[madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(0), madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(1), 8]; // Create an list array to hold the weights of cohorts dispersing from grid cell. Dimensions are: num grid cells lon, num grid cells lat, num cohorts dispersing List <double>[,] OutboundCohortWeights = new List <double> [madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(0), madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(1)]; for (uint ii = 0; ii < madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(0); ii++) { for (uint jj = 0; jj < madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(1); jj++) { OutboundCohortWeights[ii, jj] = new List <double>(); } } // Loop through the delta array that holds the grid cells of the cohorts that are flagged as needing to be moved for (uint ii = 0; ii < madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(0); ii++) { for (uint jj = 0; jj < madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(1); jj++) { // No cohorts to move if there are none in the delta dispersal array if (madingleyModelGrid.DeltaFunctionalGroupDispersalArray[ii, jj].Count == 0) { } // Otherwise, loop through the cohorts and change the pointers/references to them one-by-one else { for (int kk = 0; kk < madingleyModelGrid.DeltaFunctionalGroupDispersalArray[ii, jj].Count; kk++) { // Find out which grid cell it is going to uint[] CellToDisperseTo = madingleyModelGrid.DeltaCellToDisperseToArray[ii, jj].ElementAt(kk); // Functional group is identified by the first array uint CohortToDisperseFG = madingleyModelGrid.DeltaFunctionalGroupDispersalArray[ii, jj].ElementAt(kk); // Cohort number is identified by the second array uint CohortToDisperseNum = madingleyModelGrid.DeltaCohortNumberDispersalArray[ii, jj].ElementAt(kk); // If track processes is on, add this to the list of inbound and outbound cohorts if (trackCrossCellProcesses.TrackCrossCellProcesses) { WriteOutCrossGridCell(madingleyModelGrid, CellToDisperseTo, InboundCohorts, OutboundCohorts, OutboundCohortWeights, ii, jj, CohortToDisperseFG, CohortToDisperseNum, madingleyModelGrid.DeltaCellExitDirection[ii, jj].ElementAt(kk), madingleyModelGrid.DeltaCellEntryDirection[ii, jj].ElementAt(kk)); } // Simmply add it to the existing cohorts in that FG in the grid cell to disperse to madingleyModelGrid.AddNewCohortToGridCell(CellToDisperseTo[0], CellToDisperseTo[1], (int)CohortToDisperseFG, madingleyModelGrid.GetGridCellIndividualCohort(ii, jj, (int)CohortToDisperseFG, (int)CohortToDisperseNum)); // Update the dispersal counter dispersalCounter++; // So now there is a pointer in the grid cell to which it is going. We have to delete the pointers in the original cell and in the // delta array, but we need to do this without messing with the list structure; i.e. wait until all cohorts have been moved } } } } // Reset the delta arrays and remove the pointers to the cohorts in the original list for (uint ii = 0; ii < madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(0); ii++) { for (uint jj = 0; jj < madingleyModelGrid.DeltaFunctionalGroupDispersalArray.GetLength(1); jj++) { // No cohorts to move if there are none in the delta dispersal array if (madingleyModelGrid.DeltaFunctionalGroupDispersalArray[ii, jj].Count == 0) { } // Otherwise, loop through the cohorts and change the pointers/references to them one-by-one else { // Delete the cohorts from the original grid cell. Note that this needs to be done carefully to ensure that the correct ones // are deleted (lists shift about when an internal element is deleted. madingleyModelGrid.DeleteGridCellIndividualCohorts(ii, jj, madingleyModelGrid.DeltaFunctionalGroupDispersalArray[ii, jj], madingleyModelGrid.DeltaCohortNumberDispersalArray[ii, jj]); // Reset the lists in the delta dispersal arrays madingleyModelGrid.DeltaFunctionalGroupDispersalArray[ii, jj] = new List <uint>(); madingleyModelGrid.DeltaCohortNumberDispersalArray[ii, jj] = new List <uint>(); // Reset the list in the grid cells to disperse to array madingleyModelGrid.DeltaCellToDisperseToArray[ii, jj] = new List <uint[]>(); // Reset the lists in the delta dispersal arrays madingleyModelGrid.DeltaCellExitDirection[ii, jj] = new List <uint>(); madingleyModelGrid.DeltaCellEntryDirection[ii, jj] = new List <uint>(); } } } if (trackCrossCellProcesses.TrackCrossCellProcesses) { // If we are tracking dispersal, then write out how many cohorts have moved to a file trackCrossCellProcesses.RecordDispersalForACell(InboundCohorts, OutboundCohorts, OutboundCohortWeights, currentTimeStep, madingleyModelGrid); } }
/// <summary> /// Sets up the outputs associated with medium and high levels of output detail /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> private void SetupMediumLevelOutputs(ModelGrid ecosystemModelGrid, Boolean marineCell) { string[] TimeDimension = { "Time step" }; if (OutputMetrics) { DataConverter.AddVariable(BasicOutputMemory, "Mean Trophic Level", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Trophic Evenness", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Biomass Evenness", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Functional Richness", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Rao Functional Evenness", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Biomass Richness", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Trophic Richness", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Max Bodymass", "g", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Min Bodymass", "g", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Max Trophic Index", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Min Trophic Index", "dimensionless", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Geometric Mean Bodymass", "g", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Arithmetic Mean Bodymass", "g", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); } if (marineCell) { foreach (string TraitValue in CohortTraitIndicesMarine.Keys) { DataConverter.AddVariable(BasicOutputMemory, TraitValue + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, TraitValue + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); } foreach (string TraitValue in StockTraitIndicesMarine.Keys) { DataConverter.AddVariable(BasicOutputMemory, TraitValue + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); } if (TrackMarineSpecifics) { // Add a variable to keep track of the NPP incoming from the VGPM model DataConverter.AddVariable(BasicOutputMemory, "Incoming NPP", "gC / m^2 / day", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); } } else { foreach (string TraitValue in CohortTraitIndices.Keys) { DataConverter.AddVariable(BasicOutputMemory, TraitValue + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, TraitValue + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); } foreach (string TraitValue in StockTraitIndices.Keys) { DataConverter.AddVariable(BasicOutputMemory, TraitValue + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); } } }
public void OutputCurrentModelState(ModelGrid currentModelGrid, FunctionalGroupDefinitions functionalGroupHandler, List <uint[]> cellIndices, uint currentTimestep, int maximumNumberOfCohorts, string filename) { float[] Latitude = currentModelGrid.Lats; float[] Longitude = currentModelGrid.Lons; float[] CohortFunctionalGroup = new float[functionalGroupHandler.GetNumberOfFunctionalGroups()]; for (int fg = 0; fg < CohortFunctionalGroup.Length; fg++) { CohortFunctionalGroup[fg] = fg; } int CellCohortNumber = 0; GridCellCohortHandler CellCohorts; for (int cellIndex = 0; cellIndex < cellIndices.Count; cellIndex++) { CellCohorts = currentModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); for (int i = 0; i < CellCohorts.Count; i++) { if (CellCohorts[i].Count > CellCohortNumber) { CellCohortNumber = CellCohorts[i].Count; } } } int MaxNumberCohorts = Math.Max(CellCohortNumber, maximumNumberOfCohorts); float[] Cohort = new float[MaxNumberCohorts]; for (int c = 0; c < Cohort.Length; c++) { Cohort[c] = c; } //Define an array for stock functional group - there are only three currently float[] StockFunctionalGroup = new float[] { 1, 2, 3 }; //Define an array for index of stocks - there is only one currently float[] Stock = new float[] { 1 }; string Filename = filename + "_" + currentTimestep.ToString() + Simulation.ToString(); StateOutput = SDSCreator.CreateSDS("netCDF", Filename, _OutputPath); //Define the cohort properties for output string[] CohortProperties = new string[] { "JuvenileMass", "AdultMass", "IndividualBodyMass", "IndividualReproductivePotentialMass", "CohortAbundance", "BirthTimeStep", "MaturityTimeStep", "LogOptimalPreyBodySizeRatio", "MaximumAchievedBodyMass", "Merged", "TrophicIndex", "ProportionTimeActive" }; //define the dimensions for cohort outputs string[] dims = new string[] { "Latitude", "Longitude", "Cohort Functional Group", "Cohort" }; // Add the variables for each cohort property // Then calculate the state for this property and put the data to this variable foreach (string v in CohortProperties) { DataConverter.AddVariable(StateOutput, "Cohort" + v, 4, dims, currentModelGrid.GlobalMissingValue, Latitude, Longitude, CohortFunctionalGroup, Cohort); StateOutput.PutData <double[, , , ]>("Cohort" + v, CalculateCurrentCohortState(currentModelGrid, v, Latitude.Length, Longitude.Length, CohortFunctionalGroup.Length, Cohort.Length, cellIndices)); StateOutput.Commit(); } //Define the stock properties for output string[] StockProperties = new string[] { "IndividualBodyMass", "TotalBiomass" }; //define the dimensions for cohort outputs dims = new string[] { "Latitude", "Longitude", "Stock Functional Group", "Stock" }; // Add the variables for each stock property // Then calculate the state for this property and put the data to this variable foreach (string v in StockProperties) { DataConverter.AddVariable(StateOutput, "Stock" + v, 4, dims, currentModelGrid.GlobalMissingValue, Latitude, Longitude, StockFunctionalGroup, Stock); StateOutput.PutData <double[, , , ]>("Stock" + v, CalculateCurrentStockState(currentModelGrid, v, Latitude.Length, Longitude.Length, StockFunctionalGroup.Length, Stock.Length, cellIndices)); StateOutput.Commit(); } //Close this data set StateOutput.Dispose(); }
/// <summary> /// Generate the live outputs for the current time step /// </summary> /// <param name="numTimeSteps">The number of time steps in the model run</param> /// <param name="currentTimeStep">The current time step</param> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> private void TimeStepLiveOutputs(uint numTimeSteps, uint currentTimeStep, ModelGrid ecosystemModelGrid, Boolean marineCell) { // Output to the live graph view according to the specified level of detail if (ModelOutputDetail == OutputDetailLevel.Low) { // Rescale the y-axis if necessary if (TotalLivingBiomass > MaximumYValue) { MaximumYValue = TotalLivingBiomass * 1.1; DataSetToViewLive.Metadata["VisualHints"] = "\"Total living biomass\"[Time step]; Style:Polyline; Visible: 0,1," + numTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#D95F02; Thickness:3; Title:\"Total Biomass" + "\""; } // Write out total living biomass DataConverter.ValueToSDS1D(TotalLivingBiomass, "Total living biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, (int)currentTimeStep + 1); } else { //Find the max value in the TotalBiomassDensities double MaxVal = 0.0; foreach (var KVPair in TotalBiomassDensitiesOut) { if (KVPair.Value > MaxVal) MaxVal = KVPair.Value; } // Rescale the y-axis if necessary if (MaxVal > MaximumYValue) { MaximumYValue = MaxVal * 1.1; DataSetToViewLive.Metadata["VisualHints"] = "\"autotroph biomass\"[Time step]; Style:Polyline; Visible: 0,1," + numTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#FF008040;Thickness:3;;\"carnivore biomass\"[Time step] ; Style:Polyline; Visible: 0,1," + numTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#FFFF0000;Thickness:3;;\"herbivore biomass\"[Time step] ; Style:Polyline; Visible: 0,1," + numTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#FF00FF00;Thickness:3;;\"omnivore biomass\"[Time step] ; Style:Polyline; Visible: 0,1," + numTimeSteps.ToString() + "," + MaximumYValue.ToString() + "; LogScale:Y; Stroke:#FF0000FF;Thickness:3; Title:\"Biomass Densities"; } if (marineCell) { foreach (string TraitValue in CohortTraitIndicesMarine.Keys) { // Output the total carnivore, herbivore and omnivore abundances DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, (int)currentTimeStep + 1); } foreach (string TraitValue in StockTraitIndicesMarine.Keys) { // Add in the initial values of stock biomass density DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, (int)currentTimeStep + 1); } } else { foreach (string TraitValue in CohortTraitIndices.Keys) { // Output the total carnivore, herbivore and omnivore abundances DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, (int)currentTimeStep + 1); DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, (int)currentTimeStep + 1); } foreach (string TraitValue in StockTraitIndices.Keys) { // Add in the initial values of stock biomass density DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, (int)currentTimeStep + 1); } } } }
private double[, , ,] CalculateCurrentCohortState(ModelGrid currentModelState, string variableName, int numLats, int numLons, int numFG, int numCohorts, List <uint[]> cellList) { //Calculate the cohort state double[, , ,] State = new double[numLats, numLons, numFG, numCohorts]; GridCellCohortHandler CellCohorts; for (int cellIndex = 0; cellIndex < cellList.Count; cellIndex++) { CellCohorts = currentModelState.GetGridCellCohorts(cellList[cellIndex][0], cellList[cellIndex][1]); for (int functionalGroupIndex = 0; functionalGroupIndex < CellCohorts.Count; functionalGroupIndex++) { for (int cohortIndex = 0; cohortIndex < CellCohorts[functionalGroupIndex].Count; cohortIndex++) { switch (variableName) { case "JuvenileMass": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].JuvenileMass; break; case "AdultMass": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].AdultMass; break; case "IndividualBodyMass": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].IndividualBodyMass; break; case "CohortAbundance": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].CohortAbundance; break; case "BirthTimeStep": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = (double)CellCohorts[functionalGroupIndex][cohortIndex].BirthTimeStep; break; case "MaturityTimeStep": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = (double)CellCohorts[functionalGroupIndex][cohortIndex].MaturityTimeStep; break; case "LogOptimalPreyBodySizeRatio": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].LogOptimalPreyBodySizeRatio; break; case "MaximumAchievedBodyMass": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].MaximumAchievedBodyMass; break; case "Merged": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = Convert.ToDouble(CellCohorts[functionalGroupIndex][cohortIndex].Merged); break; case "TrophicIndex": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].TrophicIndex; break; case "ProportionTimeActive": State[cellList[cellIndex][0], cellList[cellIndex][1], functionalGroupIndex, cohortIndex] = CellCohorts[functionalGroupIndex][cohortIndex].ProportionTimeActive; break; } } } } return(State); }
/// <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> /// Calculates the probability of advective dispersal given the grid cell /// </summary> /// <param name="madingleyGrid">The model grid</param> /// <param name="latIndex">The latitude index of the grid cell to check for dispersal</param> /// <param name="lonIndex">The longitude index of the grid cell to check for dispersal</param> /// <param name="currentMonth">The current model month</param> /// <returns>A six element array. /// The first element is the probability of dispersal. /// The second element is the probability of dispersing in the u (longitudinal) direction /// The third element is the probability of dispersing in the v (latitudinal) direction /// The fourth element is the probability of dispersing in the diagonal direction /// The fifth element is the distance travelled in the u direction (u velocity modified by the random diffusion component) /// The sixth element is the distance travelled in the v direction (v velocity modified by the random diffusion component) /// Note that the second, third, and fourth elements are always positive; thus, they do not indicate 'direction' in terms of dispersal.</returns> private double[] CalculateDispersalProbability(ModelGrid madingleyGrid, uint latIndex, uint lonIndex, uint currentMonth, double rescaleduSpeed, double rescaledvSpeed) { // Distance travelled in u (longitudinal) direction double uDistanceTravelled; // Distance travelled in v (latitudinal) direction double vDistanceTravelled; // U and V components of the diffusive velocity double[] DiffusiveUandVComponents = new double[2]; // Length in km of a cell boundary latitudinally double LatCellLength; // Length in km of a cell boundary longitudinally double LonCellLength; // Area of the grid cell that is outside in the diagonal direction after dispersal, in kilometres squared double AreaOutsideBoth; // Area of the grid cell that is outside in the u (longitudinal) direction after dispersal, in kilometres squared double AreaOutsideU; // Area of the grid cell that is outside in the v (latitudinal) direction after dispersal, in kilometres squared double AreaOutsideV; // Cell area, in kilometres squared double CellArea; // Probability of dispersal double DispersalProbability; // Calculate the diffusive movement speed, with a direction chosen at random DiffusiveUandVComponents = CalculateDiffusion(); // Calculate the distance travelled in this dispersal (not global) time step. both advective and diffusive speeds need to have been converted to km / advective model time step uDistanceTravelled = rescaleduSpeed + DiffusiveUandVComponents[0]; vDistanceTravelled = rescaledvSpeed + DiffusiveUandVComponents[1]; // Check that the u distance travelled and v distance travelled are not greater than the cell length LatCellLength = madingleyGrid.CellHeightsKm[latIndex]; LonCellLength = madingleyGrid.CellWidthsKm[latIndex]; if (Math.Abs(uDistanceTravelled) >= LonCellLength) { Debug.Fail("u velocity greater than cell width"); } if (Math.Abs(vDistanceTravelled) >= LatCellLength) { Debug.Fail("v velocity greater than cell width"); } // We assume that the whole grid cell moves at the given velocity and calculate the area that is then outside the original grid cell location. // This then becomes the probability of dispersal // Calculate the area of the grid cell that is now outside in the diagonal direction. AreaOutsideBoth = Math.Abs(uDistanceTravelled * vDistanceTravelled); // Calculate the area of the grid cell that is now outside in the u (longitudinal) direction (not including the diagonal) AreaOutsideU = Math.Abs(uDistanceTravelled * LatCellLength) - AreaOutsideBoth; // Calculate the proportion of the grid cell that is outside in the v (latitudinal) direction (not including the diagonal) AreaOutsideV = Math.Abs(vDistanceTravelled * LonCellLength) - AreaOutsideBoth; // Get the cell area, in kilometres squared CellArea = madingleyGrid.GetCellEnvironment(latIndex, lonIndex)["Cell Area"][0]; // Convert areas to a probability DispersalProbability = (AreaOutsideU + AreaOutsideV + AreaOutsideBoth) / CellArea; // Check that the whole cell hasn't moved out. Could this happen for the fastest currents in a month? Definitely, // if current speeds were not constrained if (DispersalProbability >= 1) { Debug.Fail("Dispersal probability in advection should always be <= 1"); } double[] NewArray = { DispersalProbability, AreaOutsideU / CellArea, AreaOutsideV / CellArea, AreaOutsideBoth / CellArea, uDistanceTravelled, vDistanceTravelled }; return(NewArray); }
/// <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 trophic evenness using the Rao Index /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The list of indices of cells to be run in the current simulation</param> /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param> /// <returns>Trophic evenness</returns> public double CalculateFunctionalEvennessRao(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions, List<uint[]> cellIndices, int cellIndex, string trait) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double[] EvennessValues = new double[2]; double[,] Distances = new double[CellCohorts.GetNumberOfCohorts(), CellCohorts.GetNumberOfCohorts()]; double[] FunctionalTrait = new double[CellCohorts.GetNumberOfCohorts()]; double MaxModelTraitValue=0; double MinModelTraitValue=0; // Construct a vector of cohort biomass (in case we want to weight by them) double[] CohortTotalBiomasses = new double[CellCohorts.GetNumberOfCohorts()]; int CohortNumberCounter = 0; switch (trait.ToLower()) { case "biomass": for (int fg = 0; fg < CellCohorts.Count; fg++) { foreach (Cohort c in CellCohorts[fg]) { FunctionalTrait[CohortNumberCounter] = c.IndividualBodyMass; CohortTotalBiomasses[CohortNumberCounter] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; CohortNumberCounter++; } } //Define upper and lower limits for body mass MinModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min(); MaxModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max(); break; case "trophic index": for (int fg = 0; fg < CellCohorts.Count; fg++) { foreach (Cohort c in CellCohorts[fg]) { FunctionalTrait[CohortNumberCounter] = c.IndividualBodyMass; CohortTotalBiomasses[CohortNumberCounter] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; CohortNumberCounter++; } } MinModelTraitValue = MinTI; MaxModelTraitValue = MaxTI; break; } Distances = CalculateDistanceMatrix(FunctionalTrait, MaxModelTraitValue, MinModelTraitValue); return RaoEntropy(Distances, CohortTotalBiomasses); }
/// <summary> /// 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> /// Calculates the geometric community weighted mean body mass /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The list of indices of cells to be run in the current model simulation</param> /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param> /// <returns>geometric community weighted mean body mass</returns> public double CalculateGeometricCommunityMeanBodyMass(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double CumulativeAbundance = 0.0; double CumulativeLogBiomass = 0.0; //Retrieve the biomass foreach (var CohortList in CellCohorts) { foreach (Cohort c in CohortList) { CumulativeLogBiomass += Math.Log(c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; CumulativeAbundance += c.CohortAbundance; } } double CWGMBM = Math.Exp(CumulativeLogBiomass / CumulativeAbundance); return (CWGMBM); }
/// <summary> /// 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> /// Return the distribution of biomasses among trophic level bins /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The list of cell indices to be run in the current model simulation</param> /// <param name="cellIndex">The index of the current cell in the list of cells to be run</param> /// <returns>The distribution of biomasses among trophic level bins</returns> public double[] CalculateTrophicDistribution(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double[] TrophicIndexBinMasses = new double[NumberTrophicBins]; int BinIndex; foreach (var CohortList in CellCohorts) { foreach (Cohort c in CohortList) { BinIndex = _TrophicIndexBinValues.ToList().IndexOf(_TrophicIndexBinValues.Last(x => x < c.TrophicIndex)); TrophicIndexBinMasses[BinIndex] += (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; } } return TrophicIndexBinMasses; }
/// <summary> /// 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> /// Record dispersal events in the dispersal tracker /// </summary> /// <param name="inboundCohorts">The cohorts arriving in a cell in the current time step</param> /// <param name="outboundCohorts">The cohorts leaving a cell in the current time step</param> /// <param name="outboundCohortWeights">The body masses of cohorts leaving the cell in the current time step</param> /// <param name="timestep">The current model time step</param> /// <param name="madingleyModelGrid">The model grid</param> public void RecordDispersalForACell(uint[, ,] inboundCohorts, uint[, ,] outboundCohorts, List <double>[,] outboundCohortWeights, uint timestep, ModelGrid madingleyModelGrid) { var count = inboundCohorts.GetLength(0) * inboundCohorts.GetLength(1); var copy = new Madingley.Common.GridCellDispersal[count]; for (var kk = 0; kk < count; kk++) { var ii = (int)kk / inboundCohorts.GetLength(1); var jj = kk % inboundCohorts.GetLength(1); var denter = new Tuple <Madingley.Common.CohortsEnterDirection, int>[] { Tuple.Create(Madingley.Common.CohortsEnterDirection.North, (int)inboundCohorts[ii, jj, 0]), Tuple.Create(Madingley.Common.CohortsEnterDirection.NorthEast, (int)inboundCohorts[ii, jj, 1]), Tuple.Create(Madingley.Common.CohortsEnterDirection.East, (int)inboundCohorts[ii, jj, 2]), Tuple.Create(Madingley.Common.CohortsEnterDirection.SouthEast, (int)inboundCohorts[ii, jj, 3]), Tuple.Create(Madingley.Common.CohortsEnterDirection.South, (int)inboundCohorts[ii, jj, 4]), Tuple.Create(Madingley.Common.CohortsEnterDirection.SouthWest, (int)inboundCohorts[ii, jj, 5]), Tuple.Create(Madingley.Common.CohortsEnterDirection.West, (int)inboundCohorts[ii, jj, 6]), Tuple.Create(Madingley.Common.CohortsEnterDirection.NorthWest, (int)inboundCohorts[ii, jj, 7]), }; var enter = denter.ToDictionary(l => l.Item1, l => l.Item2); var dexit = new Tuple <Madingley.Common.CohortsExitDirection, int>[] { Tuple.Create(Madingley.Common.CohortsExitDirection.North, (int)outboundCohorts[ii, jj, 0]), Tuple.Create(Madingley.Common.CohortsExitDirection.NorthEast, (int)outboundCohorts[ii, jj, 1]), Tuple.Create(Madingley.Common.CohortsExitDirection.East, (int)outboundCohorts[ii, jj, 2]), Tuple.Create(Madingley.Common.CohortsExitDirection.SouthEast, (int)outboundCohorts[ii, jj, 3]), Tuple.Create(Madingley.Common.CohortsExitDirection.South, (int)outboundCohorts[ii, jj, 4]), Tuple.Create(Madingley.Common.CohortsExitDirection.SouthWest, (int)outboundCohorts[ii, jj, 5]), Tuple.Create(Madingley.Common.CohortsExitDirection.West, (int)outboundCohorts[ii, jj, 6]), Tuple.Create(Madingley.Common.CohortsExitDirection.NorthWest, (int)outboundCohorts[ii, jj, 7]), }; var exit = dexit.ToDictionary(l => l.Item1, l => l.Item2); var weights = outboundCohortWeights[ii, jj].ToArray(); var cell = madingleyModelGrid.GetGridCell((uint)ii, (uint)jj); var ccell = Converters.ConvertCellData(cell); copy[kk] = new Madingley.Common.GridCellDispersal(enter, exit, weights, ccell); } this.GridCellDispersals = copy; }
public void SetupOutputs(ModelGrid ecosystemModelGrid, string outputFilesSuffix, uint numTimeSteps, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions) { // Create an SDS object to hold grid outputs GridOutput = SDSCreator.CreateSDS("netCDF", "GridOutputs" + outputFilesSuffix, _OutputPath); // Initilalise trait-based outputs InitialiseTraitBasedOutputs(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions); // Create vector to hold the values of the time dimension TimeSteps = new float[numTimeSteps + 1]; // Set the first value to be 0 (this will hold initial outputs) TimeSteps[0] = 0; // Fill other values from 0 (this will hold outputs during the model run) for (int i = 1; i < numTimeSteps + 1; i++) { TimeSteps[i] = i; } // Declare vectors for geographical dimension data float[] outLats = new float[ecosystemModelGrid.NumLatCells]; float[] outLons = new float[ecosystemModelGrid.NumLonCells]; // Populate the dimension variable vectors with cell centre latitude and longitudes for (int i = 0; i < ecosystemModelGrid.NumLatCells; i++) { outLats[i] = ecosystemModelGrid.Lats[i] + (ecosystemModelGrid.LatCellSize / 2); } for (int jj = 0; jj < ecosystemModelGrid.NumLonCells; jj++) { outLons[jj] = ecosystemModelGrid.Lons[jj] + (ecosystemModelGrid.LonCellSize / 2); } //GridOutputArray = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells, numTimeSteps]; // Add output variables that are dimensioned geographically and temporally to grid output file string[] GeographicalDimensions = { "Latitude", "Longitude", "Time step" }; DataConverter.AddVariable(GridOutput, "Biomass density", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Abundance density", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); // Initialise the arrays that will be used for the grid-based outputs LogBiomassDensityGridCohorts = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; LogBiomassDensityGridStocks = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; LogBiomassDensityGrid = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; LogAbundanceDensityGridCohorts = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; FrostDays = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; FracEvergreen = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; Realm = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; HANPP = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; Temperature = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; // Temporary outputs for checking plant model DataConverter.AddVariable(GridOutput, "Fraction year frost", 3, GeographicalDimensions, ecosystemModelGrid.GlobalMissingValue, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Fraction evergreen", 3, GeographicalDimensions, ecosystemModelGrid.GlobalMissingValue, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Realm", 3, GeographicalDimensions, ecosystemModelGrid.GlobalMissingValue, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "HANPP", 3, GeographicalDimensions, ecosystemModelGrid.GlobalMissingValue, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Temperature", 3, GeographicalDimensions, ecosystemModelGrid.GlobalMissingValue, outLats, outLons, TimeSteps); // Set up outputs for medium or high output levels if ((ModelOutputDetail == OutputDetailLevel.Medium) || (ModelOutputDetail == OutputDetailLevel.High)) { double[,] temp = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; foreach (string TraitValue in CohortTraitIndices.Keys) { BiomassDensityGrid.Add(TraitValue, temp); DataConverter.AddVariable(GridOutput, TraitValue + "biomass density", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); AbundanceDensityGrid.Add(TraitValue, temp); DataConverter.AddVariable(GridOutput, TraitValue + "abundance density", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); } foreach (string TraitValue in StockTraitIndices.Keys) { BiomassDensityGrid.Add(TraitValue, temp); DataConverter.AddVariable(GridOutput, TraitValue + "biomass density", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); } if (OutputMetrics) { double[,] MTL = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Mean Trophic Level", MTL); double[,] TE = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Trophic Evenness", TE); double[,] BE = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Biomass Evenness", BE); double[,] FR = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Functional Richness", FR); double[,] RFE = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Rao Functional Evenness", RFE); double[,] BR = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Biomass Richness", BR); double[,] TR = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Trophic Richness", TR); double[,] Bmax = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Max Bodymass", Bmax); double[,] Bmin = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Min Bodymass", Bmin); double[,] TImax = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Max Trophic Index", TImax); double[,] TImin = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Min Trophic Index", TImin); double[,] ArithMean = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Arithmetic Mean Bodymass", ArithMean); double[,] GeomMean = new double[ecosystemModelGrid.NumLatCells, ecosystemModelGrid.NumLonCells]; MetricsGrid.Add("Geometric Mean Bodymass", GeomMean); DataConverter.AddVariable(GridOutput, "Mean Trophic Level", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Trophic Evenness", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Biomass Evenness", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Functional Richness", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Rao Functional Evenness", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Biomass Richness", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Trophic Richness", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Max Bodymass", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Min Bodymass", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Max Trophic Index", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Min Trophic Index", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Arithmetic Mean Bodymass", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); DataConverter.AddVariable(GridOutput, "Geometric Mean Bodymass", 3, GeographicalDimensions, 0, outLats, outLons, TimeSteps); } } }
/// <summary> /// Sets up the outputs associated with the high level of output detail /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The indices of active cells in the model grid</param> /// <param name="cellNumber">The index of the current cell in the list of active cells</param> /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> private void SetUpHighLevelOutputs(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellNumber, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, Boolean marineCell) { // Create an SDS object for outputs by mass bin // MassBinsOutput = SDSCreator.CreateSDS("netCDF", "MassBins" + _OutputSuffix, _OutputPath); MassBinsOutputMemory = SDSCreator.CreateSDSInMemory(true); // Add relevant output variables to the mass bin output file string[] MassBinDimensions = { "Time step", "Mass bin" }; string[] DoubleMassBinDimensions = new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" }; if (OutputMetrics) { DataConverter.AddVariable(MassBinsOutputMemory, "Trophic Index Distribution", 2, new string[] {"Time step","Trophic Index Bins"}, ecosystemModelGrid.GlobalMissingValue, TimeSteps, Metrics.TrophicIndexBinValues); } if (marineCell) { foreach (string TraitValue in CohortTraitIndicesMarine.Keys) { DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); } } else { foreach (string TraitValue in CohortTraitIndices.Keys) { DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValue + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); } } // Create an SDS object in memory for tracked cohorts outputs // TrackedCohortsOutput = SDSCreator.CreateSDS("netCDF", "TrackedCohorts" + _OutputSuffix, _OutputPath); TrackedCohortsOutputMemory = SDSCreator.CreateSDSInMemory(true); // Initialise list to hold tracked cohorts TrackedCohorts = new List<uint>(); // Identify cohorts to track GridCellCohortHandler TempCohorts = null; bool FoundCohorts = false; // Get a local copy of the cohorts in the grid cell TempCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellNumber][0], cellIndices[cellNumber][1]); // Loop over functional groups and check whether any cohorts exist in this grid cell foreach (var CohortList in TempCohorts) { if (CohortList.Count > 0) { FoundCohorts = true; break; } } // If there are some cohorts in the grid cell, then setup the tracked cohorts if (FoundCohorts) { // Initialise stream writer to hold details of tracked cohorts StreamWriter sw = new StreamWriter(_OutputPath + "TrackedCohortProperties" + _OutputSuffix + ".txt"); sw.WriteLine("Output ID\tCohort ID\tFunctional group index\tNutrition source\tDiet\tRealm\tMobility\tJuvenile mass\tAdult mass"); // Counter for tracked cohorts int TrackedCohortCounter = 0; for (int i = 0; i < TempCohorts.Count; i++) { if (TempCohorts[i].Count > 0) { for (int j = 0; j < TempCohorts[i].Count; j++) { // Write out properties of the selected cohort sw.WriteLine(Convert.ToString(TrackedCohortCounter) + '\t' + Convert.ToString(TempCohorts[i][j].CohortID[0]) + '\t' + i + '\t' + cohortFunctionalGroupDefinitions.GetTraitNames("Nutrition source", i) + '\t' + cohortFunctionalGroupDefinitions. GetTraitNames("Diet", i) + '\t' + cohortFunctionalGroupDefinitions.GetTraitNames("Realm", i) + '\t' + cohortFunctionalGroupDefinitions.GetTraitNames("Mobility", i) + '\t' + TempCohorts[i][j].JuvenileMass + '\t' + TempCohorts[i][j].AdultMass); // Add the ID of the cohort to the list of tracked cohorts TrackedCohorts.Add(TempCohorts[i][j].CohortID[0]); // Increment the counter of tracked cohorts TrackedCohortCounter++; } } } // Generate an array of floating points to index the tracked cohorts in the output file float[] OutTrackedCohortIDs = new float[TrackedCohortCounter]; for (int i = 0; i < TrackedCohortCounter; i++) { OutTrackedCohortIDs[i] = i; } // Set up outputs for tracked cohorts string[] TrackedCohortsDimensions = { "Time step", "Cohort ID" }; // Add output variables for the tracked cohorts output DataConverter.AddVariable(TrackedCohortsOutputMemory, "Individual body mass", 2, TrackedCohortsDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, OutTrackedCohortIDs); DataConverter.AddVariable(TrackedCohortsOutputMemory, "Number of individuals", 2, TrackedCohortsDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, OutTrackedCohortIDs); // Dispose of the streamwriter sw.Dispose(); } // Get a list of all possible combinations of trait values as a jagged array string[][] TraitValueSearch; if (marineCell) TraitValueSearch = CalculateAllCombinations(CohortTraitValuesMarine[CohortTraits[0]], CohortTraitValuesMarine[CohortTraits[1]]); else TraitValueSearch = CalculateAllCombinations(CohortTraitValues[CohortTraits[0]], CohortTraitValues[CohortTraits[1]]); // Add the functional group indices of these trait combinations to the list of indices of the trait values to consider, // keyed with a concatenated version of the trait values string TraitValueJoin = ""; string[] TimeDimension = { "Time step" }; for (int i = 0; i < TraitValueSearch.Count(); i++) { TraitValueJoin = ""; foreach (string TraitValue in TraitValueSearch[i]) { TraitValueJoin += TraitValue + " "; } if (marineCell) { // Only add indices of marine functional groups int[] TempIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(CohortTraits, TraitValueSearch[i], true); Boolean[] TempIndices2 = new Boolean[TempIndices.GetLength(0)]; for (int ii = 0; ii < TempIndices.GetLength(0); ii++) { if (cohortFunctionalGroupDefinitions.GetTraitNames("Realm", TempIndices[ii]).Equals("Marine", StringComparison.OrdinalIgnoreCase)) { TempIndices2[ii] = true; } } // Extract only the indices which are marine int[] TempIndices3 = Enumerable.Range(0, TempIndices2.Length).Where(zz => TempIndices2[zz]).ToArray(); if (TempIndices3.Length > 0) { // Extract the values at these indices for (int ii = 0; ii < TempIndices3.Length; ii++) { TempIndices3[ii] = TempIndices[TempIndices3[ii]]; } // Add in the indices for this functional group and this realm CohortTraitIndices.Add(TraitValueJoin, TempIndices3); DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); TotalBiomassDensitiesOut.Add(TraitValueJoin, 0.0); TotalDensitiesOut.Add(TraitValueJoin, 0.0); } } else { // Only add indices of terrestrial functional groups int[] TempIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(CohortTraits, TraitValueSearch[i], true); Boolean[] TempIndices2 = new Boolean[TempIndices.GetLength(0)]; for (int ii = 0; ii < TempIndices.GetLength(0); ii++) { if (cohortFunctionalGroupDefinitions.GetTraitNames("Realm", TempIndices[ii]).Equals("Terrestrial", StringComparison.OrdinalIgnoreCase)) { TempIndices2[ii] = true; } } // Extract only the indices which are terrestrial int[] TempIndices3 = Enumerable.Range(0, TempIndices2.Length).Where(zz => TempIndices2[zz]).ToArray(); if (TempIndices3.Length > 0) { // Extract the values at these indices for (int ii = 0; ii < TempIndices3.Length; ii++) { TempIndices3[ii] = TempIndices[TempIndices3[ii]]; } // Add in the indices for this functional group and this realm CohortTraitIndices.Add(TraitValueJoin, TempIndices3); DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, TraitValueJoin + " biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in mass bins", 2, MassBinDimensions, ecosystemModelGrid.GlobalMissingValue, TimeSteps, MassBins); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " abundance in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); DataConverter.AddVariable(MassBinsOutputMemory, "Log " + TraitValueJoin + " biomass in juvenile vs adult bins", 3, DoubleMassBinDimensions, ecosystemModelGrid.GlobalMissingValue, MassBins, MassBins, TimeSteps); TotalBiomassDensitiesOut.Add(TraitValueJoin, 0.0); TotalDensitiesOut.Add(TraitValueJoin, 0.0); } } } }
/// <summary> /// Record dispersal events in the dispersal tracker /// </summary> /// <param name="inboundCohorts">The cohorts arriving in a grid cell in the current time step</param> /// <param name="outboundCohorts">The cohorts leaving a ce ll in the current time step</param> /// <param name="outboundCohortWeights">The body masses of cohorts leaving the cell in the current time step</param> /// <param name="currentTimeStep">The current model time step</param> /// <param name="madingleyModelGrid">The model grid</param> public void RecordDispersal(uint[, ,] inboundCohorts, uint[, ,] outboundCohorts, List <double>[,] outboundCohortWeights, uint currentTimeStep, ModelGrid madingleyModelGrid) { // Loop through cells in the grid and write out the necessary data for (uint ii = 0; ii < outboundCohorts.GetLength(0); ii++) { for (uint jj = 0; jj < outboundCohorts.GetLength(1); jj++) { double MeanOutboundCohortWeight = new double(); // Calculate the mean weight of outbound cohorts (ignoring abundance) if (outboundCohortWeights[ii, jj].Count == 0) { MeanOutboundCohortWeight = 0.0; } else { MeanOutboundCohortWeight = outboundCohortWeights[ii, jj].Average(); } // Calculate the mean weight of all cohorts (ignoring abundance) List <double> TempList = new List <double>(); GridCellCohortHandler Temp1 = madingleyModelGrid.GetGridCellCohorts(ii, jj); // Loop through functional groups for (int kk = 0; kk < Temp1.Count; kk++) { // Loop through cohorts for (int hh = 0; hh < Temp1[kk].Count; hh++) { // Add the cohort weight to the list TempList.Add(Temp1[kk][hh].IndividualBodyMass); } } // Calculate the mean weight double MeanCohortWeight = new double(); if (TempList.Count == 0) { MeanCohortWeight = 0.0; } else { MeanCohortWeight = TempList.Average(); } string newline = Convert.ToString(currentTimeStep) + '\t' + Convert.ToString(ii) + '\t' + Convert.ToString(jj) + '\t' + Convert.ToString(madingleyModelGrid.GetCellLatitude(ii)) + '\t' + Convert.ToString(madingleyModelGrid.GetCellLongitude(jj)) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 0]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 1]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 2]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 3]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 4]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 5]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 6]) + '\t' + Convert.ToString(outboundCohorts[ii, jj, 7]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 0]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 1]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 2]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 3]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 4]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 5]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 6]) + '\t' + Convert.ToString(inboundCohorts[ii, jj, 7]) + '\t' + Convert.ToString(String.Format("{0:.000000}", MeanOutboundCohortWeight) + '\t' + Convert.ToString(String.Format("{0:.000000}", MeanCohortWeight))); SyncedDispersalWriter.WriteLine(newline); } } }
/// <summary> /// Sets up the outputs associated with all levels of output detail /// </summary> /// <param name="numTimeSteps">The number of time steps in the model run</param> /// <param name="ecosystemModelGrid">The model grid</param> private void SetUpLowLevelOutputs(uint numTimeSteps, ModelGrid ecosystemModelGrid) { // Create an SDS object to hold total abundance and biomass data // BasicOutput = SDSCreator.CreateSDS("netCDF", "BasicOutputs" + _OutputSuffix, _OutputPath); BasicOutputMemory = SDSCreator.CreateSDSInMemory(true); string[] TimeDimension = { "Time step" }; DataConverter.AddVariable(BasicOutputMemory, "Total Biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Heterotroph Abundance density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); DataConverter.AddVariable(BasicOutputMemory, "Heterotroph Biomass density", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); }
/// <summary> /// Calculates functional diversity of cohorts in a grid cell as functional richness and functional diveregence (using the Rao Index) /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cohortDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="cellIndices">The list of cell indices in the current model simulation</param> /// <param name="cellIndex">The index of the current cell within the list of cells to run</param> /// <returns>A pair of values representing the functional richness and functional divergence (functional richness currently disabled!)</returns> public double[] CalculateFunctionalDiversity(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions, List<uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); //Variable to hold the functional richness value for the current cohorts double FunctionalRichness; //Variable to hold the functional divergence value for the current cohorts double RaoFunctionalDivergence = 0.0; double[,] Distances= new double[CellCohorts.GetNumberOfCohorts(), CellCohorts.GetNumberOfCohorts()]; List<string> AllTraitNames = cohortDefinitions.GetAllTraitNames().ToList(); AllTraitNames.Remove("realm"); AllTraitNames.Remove("heterotroph/autotroph"); AllTraitNames.Remove("diet"); string[] TraitNames = AllTraitNames.ToArray(); //Define upper and lower limits for body mass double MinMass = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min(); double MaxMass = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max(); //Define upp and lower limits for trophic index double MaxTI = 40.0; double MinTI = 1.0; // Construct an array of functional trait values for each cohort // Rows are specific cohorts // Columns are the functional traits (these include different types: // quantative: current mass, trophic index // nominal: diet, reproductive strategy, mobility, metabolism Tuple<double[], string[]>[] CohortFunctionalTraits = new Tuple<double[], string[]>[CellCohorts.GetNumberOfCohorts()]; double[] IndividualBodyMasses = new double[CellCohorts.GetNumberOfCohorts()]; double[] TrophicIndex = new double[CellCohorts.GetNumberOfCohorts()]; string[][] CohortNominalTraitValues= new string[TraitNames.Length][]; for (int i = 0; i < TraitNames.Length; i++) { CohortNominalTraitValues[i] = new string[CellCohorts.GetNumberOfCohorts()]; } // Construct a vector of cohort biomass (in case we want to weight by them) double[] CohortTotalBiomasses = new double[CellCohorts.GetNumberOfCohorts()]; string[] TraitValues = new string[TraitNames.Length]; double[] QuantitativeTraitValues= new double[2]; int CohortNumberCounter = 0; for (int fg = 0; fg < CellCohorts.Count; fg++) { foreach (Cohort c in CellCohorts[fg]) { TraitValues = cohortDefinitions.GetTraitValues(TraitNames, fg); for (int ii = 0; ii < TraitValues.Length; ii++) { CohortNominalTraitValues[ii][CohortNumberCounter] = TraitValues[ii]; } IndividualBodyMasses[CohortNumberCounter] = c.IndividualBodyMass; TrophicIndex[CohortNumberCounter] = c.TrophicIndex; QuantitativeTraitValues[0] = c.IndividualBodyMass; QuantitativeTraitValues[1] = c.TrophicIndex; CohortFunctionalTraits[CohortNumberCounter] = new Tuple<double[], string[]>(QuantitativeTraitValues, TraitValues); CohortTotalBiomasses[CohortNumberCounter] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; CohortNumberCounter++; } } List<double[,]> DistanceList = new List<double[,]>(); DistanceList.Add(CalculateDistanceMatrix(IndividualBodyMasses, MaxMass, MinMass)); DistanceList.Add(CalculateDistanceMatrix(TrophicIndex, MaxTI, MinTI)); foreach (string[] t in CohortNominalTraitValues) { DistanceList.Add(CalculateDistanceMatrix(t)); } Distances = CalculateAggregateDistance(DistanceList); RaoFunctionalDivergence = RaoEntropy(Distances, CohortTotalBiomasses); return new double[] {0.0,RaoFunctionalDivergence}; }
public void OutputCurrentModelState(ModelGrid currentModelGrid, List <uint[]> cellIndices, uint currentTimestep) { GridCellCohortHandler TempCohorts; GridCellStockHandler TempStocks; string context; string organism; context = Convert.ToString(currentTimestep) + "\t"; using (var StateWriter = File.AppendText(this.FileName)) { foreach (uint[] cell in cellIndices) { context = Convert.ToString(currentTimestep) + "\t" + Convert.ToString(currentModelGrid.GetCellLatitude(cell[0])) + "\t" + Convert.ToString(currentModelGrid.GetCellLongitude(cell[1])) + "\t"; TempStocks = currentModelGrid.GetGridCellStocks(cell[0], cell[1]); TempCohorts = currentModelGrid.GetGridCellCohorts(cell[0], cell[1]); foreach (List <Stock> ListS in TempStocks) { foreach (Stock S in ListS) { organism = "-999\tS" + Convert.ToString(S.FunctionalGroupIndex) + "\t" + "-999\t-999\t" + Convert.ToString(S.IndividualBodyMass) + "\t" + Convert.ToString(S.TotalBiomass / S.IndividualBodyMass) + "\t" + "-999\t-999\t-999\t-999\t-999\t-999"; StateWriter.WriteLine(context + organism); } } foreach (List <Cohort> ListC in TempCohorts) { foreach (Cohort C in ListC) { #if true var cohortIds = C.CohortID.Select(id => Convert.ToString(id)); organism = String.Join(";", cohortIds) + "\t" + #else organism = Convert.ToString(C.CohortID) + "\t" + #endif Convert.ToString(C.FunctionalGroupIndex) + "\t" + Convert.ToString(C.JuvenileMass) + "\t" + Convert.ToString(C.AdultMass) + "\t" + Convert.ToString(C.IndividualBodyMass) + "\t" + Convert.ToString(C.CohortAbundance) + "\t" + Convert.ToString(C.BirthTimeStep) + "\t" + Convert.ToString(C.MaturityTimeStep) + "\t" + Convert.ToString(C.LogOptimalPreyBodySizeRatio) + "\t" + Convert.ToString(C.MaximumAchievedBodyMass) + "\t" + Convert.ToString(C.TrophicIndex) + "\t" + Convert.ToString(C.ProportionTimeActive); StateWriter.WriteLine(context + organism); } } } } }
public double[] CalculateFunctionalRichness(ModelGrid ecosystemModelGrid, FunctionalGroupDefinitions cohortDefinitions, List<uint[]> cellIndices, int cellIndex, string trait) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double MinCurrentTraitValue = double.MaxValue; double MaxCurrentTraitValue = double.MinValue; double MinModelTraitValue = 0.0; double MaxModelTraitValue = 0.0; switch (trait.ToLower()) { case "biomass": foreach (var CohortList in CellCohorts) { foreach (var cohort in CohortList) { if (cohort.IndividualBodyMass < MinCurrentTraitValue) MinCurrentTraitValue = cohort.IndividualBodyMass; if (cohort.IndividualBodyMass > MaxCurrentTraitValue) MaxCurrentTraitValue = cohort.IndividualBodyMass; } } //Define upper and lower limits for body mass MinModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("minimum mass").Min(); MaxModelTraitValue = cohortDefinitions.GetBiologicalPropertyAllFunctionalGroups("maximum mass").Max(); break; case "trophic index": foreach (var CohortList in CellCohorts) { foreach (var cohort in CohortList) { if (cohort.TrophicIndex < MinCurrentTraitValue) MinCurrentTraitValue = cohort.TrophicIndex; if (cohort.TrophicIndex > MaxCurrentTraitValue) MaxCurrentTraitValue = cohort.TrophicIndex; } } //Define upper and lower limits for body mass MinModelTraitValue = MinTI; MaxModelTraitValue = MaxTI; break; default: Debug.Fail("Trait not recognised in calculation of ecosystem metrics: " + trait); break; } Debug.Assert((MaxModelTraitValue - MinModelTraitValue) > 0.0, "Division by zero or negative model trait values in calculation of functional richness"); double[] NewArray = {(MaxCurrentTraitValue-MinCurrentTraitValue)/(MaxModelTraitValue-MinModelTraitValue),MinCurrentTraitValue,MaxCurrentTraitValue}; return NewArray; }
/// <summary> /// Set up the file, screen and live outputs prior to the model run /// </summary> /// <param name="EcosystemModelGrid">The model grid that output data will be derived from</param> /// <param name="CohortFunctionalGroupDefinitions">The definitions for cohort functional groups</param> /// <param name="StockFunctionalGroupDefinitions">The definitions for stock functional groups</param> /// <param name="NumTimeSteps">The number of time steps in the model run</param> public void SetUpOutputs(ModelGrid EcosystemModelGrid, FunctionalGroupDefinitions CohortFunctionalGroupDefinitions, FunctionalGroupDefinitions StockFunctionalGroupDefinitions, uint NumTimeSteps, string FileOutputs) { // Get the functional group indices of herbivore, carnivore and omnivore cohorts, and autotroph stocks string[] Trait = { "Nutrition source" }; string[] Trait2 = { "Heterotroph/Autotroph" }; string[] TraitValue1 = { "Herbivory" }; string[] TraitValue2 = { "Carnivory" }; string[] TraitValue3 = { "Omnivory" }; string[] TraitValue4 = { "Autotroph" }; HerbivoreIndices = CohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue1, false); CarnivoreIndices = CohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue2, false); OmnivoreIndices = CohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue3, false); AutotrophIndices = StockFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait2, TraitValue4, false); // Set up vectors to hold dimension data for the output variables float[] outLats = new float[EcosystemModelGrid.NumLatCells]; float[] outLons = new float[EcosystemModelGrid.NumLonCells]; float[] IdentityMassBins; // Populate the dimension variable vectors with cell centre latitude and longitudes for (int ii = 0; ii < EcosystemModelGrid.NumLatCells; ii++) { outLats[ii] = EcosystemModelGrid.Lats[ii] + (EcosystemModelGrid.LatCellSize / 2); } for (int jj = 0; jj < EcosystemModelGrid.NumLonCells; jj++) { outLons[jj] = EcosystemModelGrid.Lons[jj] + (EcosystemModelGrid.LonCellSize / 2); } // Create vector to hold the values of the time dimension OutTimes = new float[NumTimeSteps + 1]; // Set the first value to be -1 (this will hold initial outputs) OutTimes[0] = -1; // Fill other values from 0 (this will hold outputs during the model run) for (int ii = 1; ii < NumTimeSteps + 1; ii++) { OutTimes[ii] = ii + 1; } // Set up a vector to hold (log) individual body mass bins OutMassBins = new float[MassBinNumber]; IdentityMassBins = new float[MassBinNumber]; // Get the (log) minimum and maximum possible (log) masses across all functional groups combined, start with default values of // Infinity and -Infinity float MaximumMass = -1 / 0F; float MinimumMass = 1 / 0F; foreach (int FunctionalGroupIndex in CohortFunctionalGroupDefinitions.AllFunctionalGroupsIndex) { MinimumMass = (float)Math.Min(MinimumMass, Math.Log(CohortFunctionalGroupDefinitions.GetBiologicalPropertyOneFunctionalGroup("minimum mass", FunctionalGroupIndex))); MaximumMass = (float)Math.Max(MaximumMass, Math.Log(CohortFunctionalGroupDefinitions.GetBiologicalPropertyOneFunctionalGroup("maximum mass", FunctionalGroupIndex))); } // Get the interval required to span the range between the minimum and maximum values in 100 steps float MassInterval = (MaximumMass - MinimumMass) / MassBinNumber; // Fill the vector of output mass bins with (log) body masses spread evenly between the minimum and maximum values for (int ii = 0; ii < MassBinNumber; ii++) { OutMassBins[ii] = MinimumMass + ii * MassInterval; IdentityMassBins[ii] = Convert.ToSingle(Math.Exp(Convert.ToDouble(OutMassBins[ii]))); } // Create file for model outputs DataSetForFileOutput = CreateSDSObject.CreateSDS("netCDF", FileOutputs); // Add three-dimensional variables to output file, dimensioned by latitude, longtiude and time string[] dimensions3D = { "Latitude", "Longitude", "Time step" }; ArraySDSConvert.AddVariable(DataSetForFileOutput, "Biomass density", 3, dimensions3D, 0, outLats, outLons, OutTimes); dimensions3D = new string[] { "Adult Mass bin", "Juvenile Mass bin", "Time step" }; ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Carnivore abundance in juvenile vs adult bins", 3, dimensions3D,Math.Log(0), OutMassBins, OutMassBins, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Herbivore abundance in juvenile vs adult bins", 3, dimensions3D, Math.Log(0), OutMassBins, OutMassBins, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Carnivore biomass in juvenile vs adult bins", 3, dimensions3D, Math.Log(0), OutMassBins, OutMassBins, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Herbivore biomass in juvenile vs adult bins", 3, dimensions3D, Math.Log(0), OutMassBins, OutMassBins, OutTimes); // Add two-dimensional variables to output file, dimensioned by mass bins and time string[] dimensions2D = { "Time step", "Mass bin" }; ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Carnivore abundance in mass bins", 2, dimensions2D, Math.Log(0), OutTimes, OutMassBins); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Herbivore abundance in mass bins", 2, dimensions2D, Math.Log(0), OutTimes, OutMassBins); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Carnivore biomass in mass bins", 2, dimensions2D, Math.Log(0), OutTimes, OutMassBins); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Log Herbivore biomass in mass bins", 2, dimensions2D, Math.Log(0), OutTimes, OutMassBins); // Add one-dimensional variables to the output file, dimensioned by time string[] dimensions1D = { "Time step" }; ArraySDSConvert.AddVariable(DataSetForFileOutput, "Herbivore density", "Individuals / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Herbivore abundance", "Individuals", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Herbivore biomass", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Carnivore density", "Individuals / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Carnivore abundance", "Individuals", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Carnivore biomass", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Omnivore density", "Individuals / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Omnivore abundance", "Individuals", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Omnivore biomass", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Autotroph biomass", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Organic matter pool", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Respiratory CO2 pool", "Kg / km^2", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of cohorts extinct", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of cohorts produced", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of cohorts combined", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of cohorts in model", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); ArraySDSConvert.AddVariable(DataSetForFileOutput, "Number of stocks in model", "", 1, dimensions1D, EcosystemModelGrid.GlobalMissingValue, OutTimes); // Add one-dimensional variables to the output file, dimensioned by mass bin index // To enable outputs to be visualised against mass instead of index // Initialise the arrays that will be used for the grid-based outputs LogBiomassDensityGridCohorts = new double[EcosystemModelGrid.NumLatCells, EcosystemModelGrid.NumLonCells]; LogBiomassDensityGridStocks = new double[EcosystemModelGrid.NumLatCells, EcosystemModelGrid.NumLonCells]; LogBiomassDensityGrid = new double[EcosystemModelGrid.NumLatCells, EcosystemModelGrid.NumLonCells]; }
/// <summary> /// Calculates the mean trophic level of all individual organisms in a grid cell /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The list of cell indices in the current model simulation</param> /// <param name="cellIndex">The index of the current cell in the list of cells to run</param> /// <returns>The mean trophic level of individuals in the grid cell</returns> public double CalculateMeanTrophicLevelCell(ModelGrid ecosystemModelGrid,List<uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); double BiomassWeightedTI = 0.0; double TotalBiomass = 0.0; double CohortBiomass = 0.0; foreach (var CohortList in CellCohorts) { foreach (Cohort c in CohortList) { CohortBiomass = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; BiomassWeightedTI += CohortBiomass * c.TrophicIndex; TotalBiomass += CohortBiomass; } } return BiomassWeightedTI/TotalBiomass; }
/// <summary> /// Calculates the 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="_LatCellIndices">A vector of the latitudinal indices of live cells in the model grid</param> /// <param name="_LonCellIndices">A vector of the longitudinal indices of live cells in the model grid</param> /// <param name="GlobalDiagnosticVariables">The sorted list of global diagnostic variables in the model</param> public void CalculateOutputs(ModelGrid EcosystemModelGrid, FunctionalGroupDefinitions CohortFunctionalGroupDefinitions, FunctionalGroupDefinitions StockFunctionalGroupDefinitions, uint[] _LatCellIndices, uint[] _LonCellIndices, SortedList<string, double> GlobalDiagnosticVariables) { # region Get biomasses and abundances from model grid
/// <summary> /// Calculates trophic evenness using the FRO Index of Mouillot et al. /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="cellIndices">The list of indices of cells to be run in the current model simulation</param> /// <param name="cellIndex">The index of the current cell within the list of cells to be run</param> /// <returns>Trophic evenness</returns> /// <remarks>From Mouillot et al (2005) Functional regularity: a neglected aspect of functional diversity, Oecologia</remarks> public double CalculateTrophicEvennessFRO(ModelGrid ecosystemModelGrid, List<uint[]> cellIndices, int cellIndex) { //Get the cohorts for the specified cell GridCellCohortHandler CellCohorts = ecosystemModelGrid.GetGridCellCohorts(cellIndices[cellIndex][0], cellIndices[cellIndex][1]); List<double[]> TrophicIndexBiomassDistribution = new List<double[]>(); double[] TIBiomass; double[] EW; foreach (var CohortList in CellCohorts) { foreach (Cohort c in CohortList) { TIBiomass = new double[2]; TIBiomass[0] = c.TrophicIndex; TIBiomass[1] = (c.IndividualBodyMass + c.IndividualReproductivePotentialMass) * c.CohortAbundance; TrophicIndexBiomassDistribution.Add(TIBiomass); } } TrophicIndexBiomassDistribution = TrophicIndexBiomassDistribution.OrderBy(x => x[0]).ToList(); //Use the Mouillot Evenness index - Functional Regularity Index or FRO //From Mouillot et al (2005) Functional regularity: a neglected aspect of functional diversity, Oecologia EW = new double[TrophicIndexBiomassDistribution.Count]; double TotalEW = 0.0 ; for (int ii = 0; ii < TrophicIndexBiomassDistribution.Count-1; ii++) { EW[ii] = (TrophicIndexBiomassDistribution[ii + 1][0] - TrophicIndexBiomassDistribution[ii][0]) / (TrophicIndexBiomassDistribution[ii + 1][1] + TrophicIndexBiomassDistribution[ii][1]); TotalEW += EW[ii]; } double FRO = 0.0; for (int ii = 0; ii < TrophicIndexBiomassDistribution.Count - 1; ii++) { FRO += Math.Min(EW[ii]/TotalEW,1.0/(TrophicIndexBiomassDistribution.Count-1)); } return FRO; }
/// <summary> /// Generates the intial output to the live dataset view /// </summary> /// <param name="ecosystemModelGrid">The model grid</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> private void InitialLiveOutputs(ModelGrid ecosystemModelGrid, Boolean marineCell) { // Create a string holding the name of the x-axis variable string[] TimeDimension = { "Time step" }; // Add the x-axis to the plots (time step) DataSetToViewLive.AddAxis("Time step", "Month", TimeSteps); // Add the relevant output variables depending on the specified level of detail if (ModelOutputDetail == OutputDetailLevel.Low) { // Add the variable for total living biomass DataConverter.AddVariable(DataSetToViewLive, "Total living biomass", "kg", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); // Add the initial value of total living biomass DataConverter.ValueToSDS1D(TotalLivingBiomass, "Total living biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, 0); } else { if (marineCell) { foreach (string TraitValue in CohortTraitIndicesMarine.Keys) { // Add in the carnivore and herbivore abundance variables DataConverter.AddVariable(DataSetToViewLive, TraitValue + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); // Add in the initial values of carnivore and herbivore abundance DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, 0); // Add in the carnivore and herbivore biomass variables DataConverter.AddVariable(DataSetToViewLive, TraitValue + " biomass", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); // Add in the initial values of carnivore and herbivore abundance DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, 0); } foreach (string TraitValue in StockTraitIndicesMarine.Keys) { // Add in the stock biomass variables DataConverter.AddVariable(DataSetToViewLive, TraitValue + " biomass", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); // Add in the initial value DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, 0); } } else { foreach (string TraitValue in CohortTraitIndices.Keys) { // Add in the carnivore and herbivore abundance variables DataConverter.AddVariable(DataSetToViewLive, TraitValue + " density", "Individuals / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); // Add in the initial values of carnivore and herbivore abundance DataConverter.ValueToSDS1D(TotalDensitiesOut[TraitValue], TraitValue + " density", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, 0); // Add in the carnivore and herbivore biomass variables DataConverter.AddVariable(DataSetToViewLive, TraitValue + " biomass", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); // Add in the initial values of carnivore and herbivore abundance DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, 0); } foreach (string TraitValue in StockTraitIndices.Keys) { // Add in the stock biomass variables DataConverter.AddVariable(DataSetToViewLive, TraitValue + " biomass", "Kg / km^2", 1, TimeDimension, ecosystemModelGrid.GlobalMissingValue, TimeSteps); // Add in the initial value DataConverter.ValueToSDS1D(TotalBiomassDensitiesOut[TraitValue], TraitValue + " biomass", "Time step", ecosystemModelGrid.GlobalMissingValue, DataSetToViewLive, 0); } } } }