//Function to bin cohorts according to the mass bins defined for the catch data /// <summary> /// Bin cohorts according to the mass bins defined for the catch data /// Constructs a list of functional group and cohort indices falling within each mass bin /// as well as the total biomass available to be fished in each /// </summary> /// <param name="c">The grid cell cohorts</param> /// <param name="fishCatch">Fisheries catch data</param> public void BinCohorts(GridCellCohortHandler c, InputCatchData fishCatch, FunctionalGroupDefinitions cohortFGs) { int mb = 0; int[] FishFGs = cohortFGs.GetFunctionalGroupIndex("Endo/Ectotherm", "Ectotherm",false); for (int i = 0; i < BinnedCohorts.Length; i++) { BinnedCohorts[i] = new List<Tuple<int[], double>>(); } foreach (int fg in FishFGs) { for (int i = 0; i < c[fg].Count(); i++) { //Find the mass bin for this cohort mb = fishCatch.MassBins.ToList().FindIndex(a => a >= c[fg,i].AdultMass); if (mb < 0) mb = fishCatch.UnknownMassBinIndex - 1; //Check if the current bodymass is greater than the proportion of the adult mass if (c[fg, i].IndividualBodyMass >= c[fg, i].AdultMass * AdultMassProportionFished) { //Calculate the total biomass of this cohort double CohortBiomass = (c[fg, i].IndividualBodyMass + c[fg, i].IndividualReproductivePotentialMass) * c[fg, i].CohortAbundance; //Add the indices and total biomass to the bins BinnedCohorts[mb].Add(new Tuple<int[], double>(new int[] { fg, i }, CohortBiomass)); BinnedTotalModelBiomass[mb] += CohortBiomass; } } } }
//Function to bin cohorts according to the mass bins defined for the catch data /// <summary> /// Bin cohorts according to the mass bins defined for the catch data /// Constructs a list of functional group and cohort indices falling within each mass bin /// as well as the total biomass available to be fished in each /// </summary> /// <param name="c">The grid cell cohorts</param> /// <param name="fishCatch">Fisheries catch data</param> public void BinCohorts(GridCellCohortHandler c, InputCatchData fishCatch, FunctionalGroupDefinitions cohortFGs) { int mb = 0; int[] FishFGs = cohortFGs.GetFunctionalGroupIndex("Endo/Ectotherm", "Ectotherm", false); for (int i = 0; i < BinnedCohorts.Length; i++) { BinnedCohorts[i] = new List <Tuple <int[], double> >(); } foreach (int fg in FishFGs) { for (int i = 0; i < c[fg].Count(); i++) { //Find the mass bin for this cohort mb = fishCatch.MassBins.ToList().FindIndex(a => a >= c[fg, i].AdultMass); if (mb < 0) { mb = fishCatch.UnknownMassBinIndex - 1; } //Check if the current bodymass is greater than the proportion of the adult mass if (c[fg, i].IndividualBodyMass >= c[fg, i].AdultMass * AdultMassProportionFished) { //Calculate the total biomass of this cohort double CohortBiomass = (c[fg, i].IndividualBodyMass + c[fg, i].IndividualReproductivePotentialMass) * c[fg, i].CohortAbundance; //Add the indices and total biomass to the bins BinnedCohorts[mb].Add(new Tuple <int[], double>(new int[] { fg, i }, CohortBiomass)); BinnedTotalModelBiomass[mb] += CohortBiomass; } } } }
/// <summary> /// Initialises herbivory implementation each time step /// </summary> /// <param name="gridCellCohorts">The cohorts in the current grid cell</param> /// <param name="gridCellStocks">The stocks in the current grid cell</param> /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param> /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param> /// <param name="cellEnvironment">The environment in the current grid cell</param> /// <remarks>This only works if: a) herbivory is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips /// It is critical to run this every time step</remarks> public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, SortedList <string, double[]> cellEnvironment) { // Get the functional group indices of all autotroph stocks _FunctionalGroupIndicesToEat = madingleyStockDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "Autotroph", false); string[] realm = { "Terrestrial", "Marine" }; int realm_index = (int)cellEnvironment["Realm"][0] - 1; string Current_realm = realm[realm_index]; }
/// <summary> /// Initialises predation implementation each time step /// </summary> /// <param name="gridCellCohorts">The cohorts in the current grid cell</param> /// <param name="gridCellStocks">The stocks in the current grid cell</param> /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param> /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param> /// <param name="cellEnvironment">The environment in the current grid cell</param> /// <remarks>This only works if: a) predation is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips /// It is critical to run this every time step</remarks> public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, SortedList <string, double[]> cellEnvironment) { // Get the functional group indices of all heterotroph cohorts (i.e. potential prey) // _FunctionalGroupIndicesToEat = madingleyCohortDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "heterotroph", false); string [] realm = { "Terrestrial", "Marine" }; int realm_index = (int)cellEnvironment["Realm"][0] - 1; string Current_realm = realm[realm_index]; _FunctionalGroupIndicesToEat = madingleyCohortDefinitions.GetFunctionalGroupIndex("realm", Current_realm, false); // Initialise the vector to hold the number of cohorts in each functional group at the start of the time step NumberCohortsPerFunctionalGroupNoNewCohorts = new int[gridCellCohorts.Count]; // Initialise the jagged arrays to hold the potential and actual numbers of prey eaten in each of the grid cell cohorts _AbundancesEaten = new double[gridCellCohorts.Count][]; _PotentialAbundanceEaten = new double[gridCellCohorts.Count][]; // Initialise the vector to identify carnivore cohorts _CarnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; _OmnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; _PlanktonFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; // Loop over rows in the jagged arrays, initialise each vector within the jagged arrays, and calculate the current number of cohorts in // each functional group for (int i = 0; i < gridCellCohorts.Count; i++) { // Calculate the current number of cohorts in this functional group int NumCohortsThisFG = gridCellCohorts[i].Count; NumberCohortsPerFunctionalGroupNoNewCohorts[i] = NumCohortsThisFG; // Initialise the jagged arrays _AbundancesEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]]; _PotentialAbundanceEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]]; } // Loop over functional groups that are potential prey and determine which are carnivores THIS IS COMMENTED OUT AS IT'S NOT USED //foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) // _CarnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "carnivore"; //foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) // _OmnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "omnivore"; //foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) // _PlanktonFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Mobility", FunctionalGroup) == "planktonic"; }
/// <summary> /// Set up the necessary architecture for generating outputs arranged by trait value /// </summary> /// <param name="cohortFunctionalGroupDefinitions">Functional group definitions for cohorts in the model</param> /// <param name="stockFunctionalGroupDefinitions">Functional group definitions for stocks in the model</param> private void InitialiseTraitBasedOutputs(FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions) { // Define the cohort traits that will be used to separate outputs CohortTraits = new string[3] { "Nutrition source", "Endo/Ectotherm", "Reproductive strategy" }; // Declare a sorted dictionary to hold all unique trait values CohortTraitValues = new SortedDictionary <string, string[]>(); // Add all unique trait values to the sorted dictionary foreach (string Trait in CohortTraits) { CohortTraitValues.Add(Trait, cohortFunctionalGroupDefinitions.GetUniqueTraitValues(Trait)); } // Get the list of functional group indices corresponding to each unique trait value foreach (string Trait in CohortTraits) { foreach (string TraitValue in CohortTraitValues[Trait]) { CohortTraitIndices.Add(TraitValue, cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false)); } } // Define the stock traits that will be used to separate outputs StockTraits = new string[2] { "Heterotroph/Autotroph", "Leaf strategy" }; // Re-initialise the sorted dictionary to hold all unique trait values StockTraitValues = new SortedDictionary <string, string[]>(); // Add all unique stock trait values to the sorted dictionary foreach (string Trait in StockTraits) { StockTraitValues.Add(Trait, stockFunctionalGroupDefinitions.GetUniqueTraitValues(Trait)); } // Get the list of functional group indices corresponding to each unique trait value foreach (string Trait in StockTraits) { foreach (string TraitValue in StockTraitValues[Trait]) { StockTraitIndices.Add(TraitValue, stockFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false)); } } }
/// <summary> /// Initialises predation implementation each time step /// </summary> /// <param name="gridCellCohorts">The cohorts in the current grid cell</param> /// <param name="gridCellStocks">The stocks in the current grid cell</param> /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param> /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param> /// <remarks>This only works if: a) predation is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips /// It is critical to run this every time step</remarks> public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions) { // Get the functional group indices of all heterotroph cohorts (i.e. potential prey) _FunctionalGroupIndicesToEat = madingleyCohortDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "heterotroph", false); // Initialise the vector to hold the number of cohorts in each functional group at the start of the time step NumberCohortsPerFunctionalGroupNoNewCohorts = new int[gridCellCohorts.Count]; // Initialise the jagged arrays to hold the potential and actual numbers of prey eaten in each of the grid cell cohorts _AbundancesEaten = new double[gridCellCohorts.Count][]; _PotentialAbundanceEaten = new double[gridCellCohorts.Count][]; // Initialise the vector to identify carnivore cohorts _CarnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; _OmnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; _PlanktonFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; // Loop over rows in the jagged arrays, initialise each vector within the jagged arrays, and calculate the current number of cohorts in // each functional group for (int i = 0; i < gridCellCohorts.Count; i++) { // Calculate the current number of cohorts in this functional group int NumCohortsThisFG = gridCellCohorts[i].Count; NumberCohortsPerFunctionalGroupNoNewCohorts[i] = NumCohortsThisFG; // Initialise the jagged arrays _AbundancesEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]]; _PotentialAbundanceEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]]; } // Loop over functional groups that are potential prey and determine which are carnivores foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) { _CarnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "carnivore"; } foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) { _OmnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "omnivore"; } foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) { _PlanktonFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Mobility", FunctionalGroup) == "planktonic"; } }
/// <summary> /// Seed the stocks and cohorts for all active cells in the model grid /// </summary> /// <param name="cellIndices">A list of the active cells in the model grid</param> /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="stockFunctionalGroupDefinitions">The functional group definitions for stocks in the model</param> /// <param name="globalDiagnostics">A list of global diagnostic variables</param> /// <param name="nextCohortID">The ID number to be assigned to the next produced cohort</param> /// <param name="tracking">Whether process-tracking is enabled</param> /// <param name="DrawRandomly">Whether the model is set to use a random draw</param> /// <param name="dispersalOnly">Whether to run dispersal only (i.e. to turn off all other ecological processes</param> /// <param name="dispersalOnlyType">For dispersal only runs, the type of dispersal to apply</param> public void SeedGridCellStocksAndCohorts(List<uint[]> cellIndices, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions, SortedList<string, double> globalDiagnostics, ref Int64 nextCohortID, Boolean tracking, Boolean DrawRandomly, Boolean dispersalOnly, string dispersalOnlyType, Boolean runCellsInParallel) { Console.WriteLine("Seeding grid cell stocks and cohorts:"); //Work out how many cohorts are to be seeded in each grid cell - split by realm as different set of cohorts initialised by realm int TotalTerrestrialCellCohorts = 0; int TotalMarineCellCohorts = 0; int[] TerrestrialFunctionalGroups = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex("Realm", "Terrestrial", false); if (TerrestrialFunctionalGroups == null) { TotalTerrestrialCellCohorts = 0; } else { foreach (int F in TerrestrialFunctionalGroups) { TotalTerrestrialCellCohorts += (int)cohortFunctionalGroupDefinitions.GetBiologicalPropertyOneFunctionalGroup("Initial number of GridCellCohorts", F); } } int[] MarineFunctionalGroups = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex("Realm", "Marine", false); if (MarineFunctionalGroups == null) { TotalMarineCellCohorts = 0; } else { foreach (int F in MarineFunctionalGroups) { TotalMarineCellCohorts += (int)cohortFunctionalGroupDefinitions.GetBiologicalPropertyOneFunctionalGroup("Initial number of GridCellCohorts", F); } } // Now loop through and determine the starting CohortID number for each cell. This allows the seeding to be done in parallel. Int64[] StartingCohortsID = new Int64[cellIndices.Count]; StartingCohortsID[0] = nextCohortID; for (int kk = 1; kk < cellIndices.Count; kk++) { if (InternalGrid[cellIndices[kk - 1][0], cellIndices[kk - 1][1]].CellEnvironment["Realm"][0] == 1) { // Terrestrial cell StartingCohortsID[kk] = StartingCohortsID[kk - 1] + TotalTerrestrialCellCohorts; } else { // Marine cell StartingCohortsID[kk] = StartingCohortsID[kk - 1] + TotalMarineCellCohorts; } } int Count = 0; if (runCellsInParallel) { Parallel.For(0, cellIndices.Count, (ii, loopState) => { if (dispersalOnly) { if (dispersalOnlyType == "diffusion") { // Diffusive dispersal if ((cellIndices[ii][0] == 90) && (cellIndices[ii][1] == 180)) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } else if ((cellIndices[ii][0] == 95) && (cellIndices[ii][1] == 110)) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } else { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, true); } Console.Write("\rGrid Cell: {0} of {1}", ii++, cellIndices.Count); } else if (dispersalOnlyType == "advection") { // Advective dispersal /* if ((cellIndices[ii][0] == 58) && (cellIndices[ii][1] == 225)) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } else if ((cellIndices[ii][0] == 95) && (cellIndices[ii][1] == 110)) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } else { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, true); } */ if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].CellEnvironment["Realm"][0] == 1.0) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks( cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, true); } else { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks( cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } Console.Write("\rGrid Cell: {0} of {1}", ii++, cellIndices.Count); } else if (dispersalOnlyType == "responsive") { // Responsive dispersal InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, true); } else { Debug.Fail("Dispersal only type not recognized from initialisation file"); } Count++; } else { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks( cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); Count++; } Console.Write("\rGrid Cell: {0} of {1}", Count, cellIndices.Count); } ); } else { for (int ii = 0; ii < cellIndices.Count; ii++) { if (dispersalOnly) { if (dispersalOnlyType == "diffusion") { // Diffusive dispersal if ((cellIndices[ii][0] == 90) && (cellIndices[ii][1] == 180)) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } else if ((cellIndices[ii][0] == 95) && (cellIndices[ii][1] == 110)) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } else { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, true); } Console.Write("\rGrid Cell: {0} of {1}", ii++, cellIndices.Count); } else if (dispersalOnlyType == "advection") { // Advective dispersal /* if ((cellIndices[ii][0] == 58) && (cellIndices[ii][1] == 225)) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } else if ((cellIndices[ii][0] == 95) && (cellIndices[ii][1] == 110)) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } else { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, true); } */ if (InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].CellEnvironment["Realm"][0] == 1.0) { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks( cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, true); } else { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks( cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); } Console.Write("\rGrid Cell: {0} of {1}", ii++, cellIndices.Count); } else if (dispersalOnlyType == "responsive") { // Responsive dispersal InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks(cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, true); } else { Debug.Fail("Dispersal only type not recognized from initialisation file"); } Count++; } else { InternalGrid[cellIndices[ii][0], cellIndices[ii][1]].SeedGridCellCohortsAndStocks( cohortFunctionalGroupDefinitions, stockFunctionalGroupDefinitions, globalDiagnostics, StartingCohortsID[ii], tracking, TotalTerrestrialCellCohorts, TotalMarineCellCohorts, DrawRandomly, false); Count++; } Console.Write("\rGrid Cell: {0} of {1}", Count, cellIndices.Count); } } Console.WriteLine(""); Console.WriteLine(""); if (InternalGrid[cellIndices[cellIndices.Count - 1][0], cellIndices[cellIndices.Count - 1][1]].CellEnvironment["Realm"][0] == 1) nextCohortID = StartingCohortsID[cellIndices.Count - 1] + TotalTerrestrialCellCohorts; else nextCohortID = StartingCohortsID[cellIndices.Count - 1] + TotalMarineCellCohorts; }
/// <summary> /// Initialises predation implementation each time step /// </summary> /// <param name="gridCellCohorts">The cohorts in the current grid cell</param> /// <param name="gridCellStocks">The stocks in the current grid cell</param> /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param> /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param> /// <remarks>This only works if: a) predation is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips /// It is critical to run this every time step</remarks> public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions) { // Get the functional group indices of all heterotroph cohorts (i.e. potential prey) _FunctionalGroupIndicesToEat = madingleyCohortDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "heterotroph", false); // Initialise the vector to hold the number of cohorts in each functional group at the start of the time step NumberCohortsPerFunctionalGroupNoNewCohorts = new int[gridCellCohorts.Count]; // Initialise the jagged arrays to hold the potential and actual numbers of prey eaten in each of the grid cell cohorts _AbundancesEaten = new double[gridCellCohorts.Count][]; _PotentialAbundanceEaten = new double[gridCellCohorts.Count][]; // Initialise the vector to identify carnivore cohorts _CarnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; _OmnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; _PlanktonFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; // Loop over rows in the jagged arrays, initialise each vector within the jagged arrays, and calculate the current number of cohorts in // each functional group for (int i = 0; i < gridCellCohorts.Count; i++) { // Calculate the current number of cohorts in this functional group int NumCohortsThisFG = gridCellCohorts[i].Count; NumberCohortsPerFunctionalGroupNoNewCohorts[i] = NumCohortsThisFG; // Initialise the jagged arrays _AbundancesEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]]; _PotentialAbundanceEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]]; } // Loop over functional groups that are potential prey and determine which are carnivores foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) _CarnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "carnivore"; foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) _OmnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "omnivore"; foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) _PlanktonFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Mobility", FunctionalGroup) == "planktonic"; }
/// <summary> /// Initialises herbivory implementation each time step /// </summary> /// <param name="gridCellCohorts">The cohorts in the current grid cell</param> /// <param name="gridCellStocks">The stocks in the current grid cell</param> /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param> /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param> /// <remarks>This only works if: a) herbivory is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips /// It is critical to run this every time step</remarks> public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions) { // Get the functional group indices of all autotroph stocks _FunctionalGroupIndicesToEat = madingleyStockDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "Autotroph", false); }
/// <summary> /// 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> /// Set up the necessary architecture for generating outputs arranged by trait value /// </summary> /// <param name="cohortFunctionalGroupDefinitions">Functional group definitions for cohorts in the model</param> /// <param name="stockFunctionalGroupDefinitions">Functional group definitions for stocks in the model</param> /// <param name="marineCell">Whether the current cell is a marine cell</param> private void InitialiseTraitBasedOutputs(FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions, Boolean marineCell) { // Define the cohort traits that will be used to separate outputs CohortTraits = new string[2] { "Nutrition source", "Endo/Ectotherm"}; // Declare a sorted dictionary to hold all unique trait values CohortTraitValues = new SortedDictionary<string, string[]>(); // Declare a sorted dictionary to hold all unique trait values for marine systems CohortTraitValuesMarine = new SortedDictionary<string, string[]>(); // Get the list of functional group indices corresponding to each unique trait value if (marineCell) { // Add all unique trait values to the sorted dictionary foreach (string Trait in CohortTraits) { CohortTraitValuesMarine.Add(Trait, cohortFunctionalGroupDefinitions.GetUniqueTraitValues(Trait)); } foreach (string Trait in CohortTraits) { foreach (string TraitValue in CohortTraitValuesMarine[Trait]) { // Only add indices of marine functional groups int[] TempIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false); 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(i => TempIndices2[i]).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 CohortTraitIndicesMarine.Add(TraitValue, TempIndices3); } } } if (TrackMarineSpecifics) { // Add in the specific classes of zooplankton and baleen whales // There are functional groups representing obligate zooplankton string[] TempString = new string[1] { "Obligate zooplankton" }; CohortTraitValuesMarine.Add("Obligate zooplankton", TempString); CohortTraitIndicesMarine.Add("Obligate zooplankton", cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex("Mobility", "planktonic", false)); // Whales have a special dietary index TempString = new string[1] { "Baleen whales" }; CohortTraitValuesMarine.Add("Baleen whales", TempString); CohortTraitIndicesMarine.Add("Baleen whales", cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex("Diet", "allspecial", false)); // But we also want all zooplankton, including larval/juvenile stages of other cohorts int[] ZooplanktonIndices1 = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex("Mobility", "planktonic", false); // Then there are all of the other groups which may have planktonic juveniles. In the ModelGrid.cs class, these cohorts are checked to see // if they have a weight of less than the planktonic dispersal threshold. TempString = new string[3] { "Realm", "Endo/Ectotherm", "Mobility" }; string[] TempString2 = new string[3] { "marine", "ectotherm", "mobile" }; int[] ZooplanktonIndices2 = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(TempString, TempString2, true); CohortTraitIndicesMarine.Add("Zooplankton (all)", ZooplanktonIndices2.Concat(ZooplanktonIndices1).ToArray()); } // Add unique trait values to each of the lists that will contain output data arranged by trait value foreach (string TraitValue in CohortTraitIndicesMarine.Keys) { TotalBiomassDensitiesMarineOut.Add(TraitValue, 0.0); TotalDensitiesMarineOut.Add(TraitValue, 0.0); } } else { // Add all unique trait values to the sorted dictionary foreach (string Trait in CohortTraits) { CohortTraitValues.Add(Trait, cohortFunctionalGroupDefinitions.GetUniqueTraitValues(Trait)); } foreach (string Trait in CohortTraits) { foreach (string TraitValue in CohortTraitValues[Trait]) { // Only add indices of terrestrial functional groups int[] TempIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false); 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(i => TempIndices2[i]).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(TraitValue, TempIndices3); } } } // Add unique trait values to each of the lists that will contain output data arranged by trait value foreach (string TraitValue in CohortTraitIndices.Keys) { TotalBiomassDensitiesOut.Add(TraitValue, 0.0); TotalDensitiesOut.Add(TraitValue, 0.0); } } if (marineCell) { // Define the stock traits that will be used to separate outputs StockTraitsMarine = new string[1] { "Heterotroph/Autotroph"}; // Re-initialise the sorted dictionary to hold all unique trait values StockTraitValuesMarine = new SortedDictionary<string, string[]>(); // Add all unique stock trait values to the sorted dictionary foreach (string Trait in StockTraitsMarine) { StockTraitValuesMarine.Add(Trait, stockFunctionalGroupDefinitions.GetUniqueTraitValues(Trait)); } // Get the list of functional group indices corresponding to each unique marine trait value foreach (string Trait in StockTraitsMarine) { foreach (string TraitValue in StockTraitValuesMarine[Trait]) { StockTraitIndicesMarine.Add(TraitValue, stockFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false)); } } // Add unique trait values to each of the lists that will contain output data arranged by trait value foreach (string TraitValue in StockTraitIndicesMarine.Keys) { TotalBiomassDensitiesOut.Add(TraitValue, 0.0); } } else { // Define the stock traits that will be used to separate outputs StockTraits = new string[2] { "Heterotroph/Autotroph", "Leaf strategy" }; // Re-initialise the sorted dictionary to hold all unique trait values StockTraitValues = new SortedDictionary<string, string[]>(); // Add all unique marine stock trait values to the sorted dictionary foreach (string Trait in StockTraits) { StockTraitValues.Add(Trait, stockFunctionalGroupDefinitions.GetUniqueTraitValues(Trait)); } // Get the list of functional group indices corresponding to each unique trait value foreach (string Trait in StockTraits) { foreach (string TraitValue in StockTraitValues[Trait]) { StockTraitIndices.Add(TraitValue, stockFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false)); } } // Add unique trait values to each of the lists that will contain output data arranged by trait value foreach (string TraitValue in StockTraitIndices.Keys) { TotalBiomassDensitiesOut.Add(TraitValue, 0.0); } } }
/// <summary> /// Seed grid cell with stocks, as specified in the model input files /// </summary> /// <param name="functionalGroups">A reference to the stock functional group handler</param> /// <param name="cellEnvironment">The environment in the grid cell</param> /// <param name="globalDiagnostics">A list of global diagnostic variables for the model grid</param> private void SeedGridCellStocks(ref FunctionalGroupDefinitions functionalGroups, ref SortedList<string, double[]> cellEnvironment, SortedList<string, double> globalDiagnostics) { // Set the seed for the random number generator from the system time RandomNumberGenerator.SetSeedFromSystemTime(); Stock NewStock; // Define local variables int[] FunctionalGroupsToUse; // Get the individual body masses for organisms in each stock functional group double[] IndividualMass = functionalGroups.GetBiologicalPropertyAllFunctionalGroups("individual mass"); // Check which realm the cell is in if (cellEnvironment["Realm"][0] == 1.0 && _CellEnvironment["Precipitation"][0] != _CellEnvironment["Missing Value"][0] && _CellEnvironment["Temperature"][0] != _CellEnvironment["Missing Value"][0]) { // Get the indices of all terrestrial functional groups FunctionalGroupsToUse = functionalGroups.GetFunctionalGroupIndex("realm", "terrestrial", true); } else if (cellEnvironment["Realm"][0] == 2.0 && _CellEnvironment["NPP"][0] != _CellEnvironment["Missing Value"][0]) { // Get the indices of all marine functional groups FunctionalGroupsToUse = functionalGroups.GetFunctionalGroupIndex("realm", "marine", true); } else { // For cells without a realm designation, no functional groups will be used FunctionalGroupsToUse = new int[0]; } // Loop over all functional groups in the model for (int FunctionalGroup = 0; FunctionalGroup < functionalGroups.GetNumberOfFunctionalGroups(); FunctionalGroup++) { // Create a new list to hold the stocks in the grid cell _GridCellStocks[FunctionalGroup] = new List<Stock>(); // If it is a functional group that corresponds to the current realm, then seed the stock if (FunctionalGroupsToUse.Contains(FunctionalGroup)) { if (_CellEnvironment["Realm"][0] == 1.0) { // An instance of the terrestrial carbon model class RevisedTerrestrialPlantModel PlantModel = new RevisedTerrestrialPlantModel(); // Calculate predicted leaf mass at equilibrium for this stock double LeafMass = PlantModel.CalculateEquilibriumLeafMass(_CellEnvironment, functionalGroups.GetTraitNames("leaf strategy", FunctionalGroup) == "deciduous"); // Initialise the new stock with the relevant properties NewStock = new Stock((byte)FunctionalGroup, IndividualMass[FunctionalGroup], LeafMass); // Add the new stock to the list of grid cell stocks _GridCellStocks[FunctionalGroup].Add(NewStock); // Increment the variable tracking the total number of stocks in the model globalDiagnostics["NumberOfStocksInModel"]++; } else if (FunctionalGroupsToUse.Contains(FunctionalGroup)) { // Initialise the new stock with the relevant properties NewStock = new Stock((byte)FunctionalGroup, IndividualMass[FunctionalGroup], 1e12); // Add the new stock to the list of grid cell stocks _GridCellStocks[FunctionalGroup].Add(NewStock); // Increment the variable tracking the total number of stocks in the model globalDiagnostics["NumberOfStocksInModel"]++; } else { } } } }
/// <summary> /// Seed grid cell with cohorts, as specified in the model input files /// </summary> /// <param name="functionalGroups">The functional group definitions for cohorts in the grid cell</param> /// <param name="cellEnvironment">The environment in the grid cell</param> /// <param name="globalDiagnostics">A list of global diagnostic variables</param> /// <param name="nextCohortID">YThe unique ID to assign to the next cohort produced</param> /// <param name="tracking">boolean to indicate if cohorts are to be tracked in this model</param> /// <param name="totalCellTerrestrialCohorts">The total number of cohorts to be seeded in each terrestrial grid cell</param> /// <param name="totalCellMarineCohorts">The total number of cohorts to be seeded in each marine grid cell</param> /// <param name="DrawRandomly">Whether the model is set to use random draws</param> /// <param name="ZeroAbundance">Set this parameter to 'true' if you want to seed the cohorts with zero abundance</param> private void SeedGridCellCohorts(ref FunctionalGroupDefinitions functionalGroups, ref SortedList<string, double[]> cellEnvironment, SortedList<string, double> globalDiagnostics, Int64 nextCohortID, Boolean tracking, double totalCellTerrestrialCohorts, double totalCellMarineCohorts, Boolean DrawRandomly, Boolean ZeroAbundance) { // Set the seed for the random number generator from the system time RandomNumberGenerator.SetSeedFromSystemTime(); // StreamWriter tempsw = new StreamWriter("C://Temp//adult_juvenile_masses.txt"); // tempsw.WriteLine("adult mass\tjuvenilemass"); // Define local variables double CohortJuvenileMass; double CohortAdultMassRatio; double CohortAdultMass; double ExpectedLnAdultMassRatio; int[] FunctionalGroupsToUse; double NumCohortsThisCell; double TotalNewBiomass =0.0; // Get the minimum and maximum possible body masses for organisms in each functional group double[] MassMinima = functionalGroups.GetBiologicalPropertyAllFunctionalGroups("minimum mass"); double[] MassMaxima = functionalGroups.GetBiologicalPropertyAllFunctionalGroups("maximum mass"); string[] NutritionSource = functionalGroups.GetTraitValuesAllFunctionalGroups("nutrition source"); double[] ProportionTimeActive = functionalGroups.GetBiologicalPropertyAllFunctionalGroups("proportion suitable time active"); //Variable for altering the juvenile to adult mass ratio for marine cells when handling certain functional groups eg baleen whales double Scaling = 0.0; Int64 CohortIDIncrementer = nextCohortID; // Check which realm the cell is in if (cellEnvironment["Realm"][0] == 1.0) { // Get the indices of all terrestrial functional groups FunctionalGroupsToUse = functionalGroups.GetFunctionalGroupIndex("realm", "terrestrial", true); NumCohortsThisCell = totalCellTerrestrialCohorts; } else { // Get the indices of all marine functional groups FunctionalGroupsToUse = functionalGroups.GetFunctionalGroupIndex("realm", "marine", true); NumCohortsThisCell = totalCellMarineCohorts; } Debug.Assert(cellEnvironment["Realm"][0] > 0.0, "Missing realm for grid cell"); if (NumCohortsThisCell > 0) { // Loop over all functional groups in the model for (int FunctionalGroup = 0; FunctionalGroup < functionalGroups.GetNumberOfFunctionalGroups(); FunctionalGroup++) { // Create a new list to hold the cohorts in the grid cell _GridCellCohorts[FunctionalGroup] = new List<Cohort>(); // If it is a functional group that corresponds to the current realm, then seed cohorts if (FunctionalGroupsToUse.Contains(FunctionalGroup)) { // Loop over the initial number of cohorts double NumberOfCohortsInThisFunctionalGroup = 1.0; if (!ZeroAbundance) { NumberOfCohortsInThisFunctionalGroup = functionalGroups.GetBiologicalPropertyOneFunctionalGroup("initial number of gridcellcohorts", FunctionalGroup); } for (int jj = 0; jj < NumberOfCohortsInThisFunctionalGroup; jj++) { // Check whether the model is set to randomly draw the body masses of new cohorts if (DrawRandomly) { // Draw adult mass from a log-normal distribution with mean -6.9 and standard deviation 10.0, // within the bounds of the minimum and maximum body masses for the functional group CohortAdultMass = Math.Pow(10, (RandomNumberGenerator.GetUniform() * (Math.Log10(MassMaxima[FunctionalGroup]) - Math.Log10(50 * MassMinima[FunctionalGroup])) + Math.Log10(50 * MassMinima[FunctionalGroup]))); // Terrestrial and marine organisms have different optimal prey/predator body mass ratios if (cellEnvironment["Realm"][0] == 1.0) // Optimal prey body size 10% OptimalPreyBodySizeRatio = Math.Max(0.01, RandomNumberGenerator.GetNormal(0.1, 0.02)); else { if (functionalGroups.GetTraitNames("Diet", FunctionalGroup) == "allspecial") { // Note that for this group // it is actually (despite the name) not an optimal prey body size ratio, but an actual body size. // This is because it is invariant as the predator (filter-feeding baleen whale) grows. // See also the predation classes. OptimalPreyBodySizeRatio = Math.Max(0.00001, RandomNumberGenerator.GetNormal(0.0001, 0.1)); } else { // Optimal prey body size or marine organisms is 10% OptimalPreyBodySizeRatio = Math.Max(0.01, RandomNumberGenerator.GetNormal(0.1, 0.02)); } } // Draw from a log-normal distribution with mean 10.0 and standard deviation 5.0, then add one to obtain // the ratio of adult to juvenile body mass, and then calculate juvenile mass based on this ratio and within the // bounds of the minimum and maximum body masses for this functional group if (cellEnvironment["Realm"][0] == 1.0) { do { ExpectedLnAdultMassRatio = 2.24 + 0.13 * Math.Log(CohortAdultMass); CohortAdultMassRatio = 1.0 + RandomNumberGenerator.GetLogNormal(ExpectedLnAdultMassRatio, 0.5); CohortJuvenileMass = CohortAdultMass * 1.0 / CohortAdultMassRatio; } while (CohortAdultMass <= CohortJuvenileMass || CohortJuvenileMass < MassMinima[FunctionalGroup]); } // In the marine realm, have a greater difference between the adult and juvenile body masses, on average else { uint Counter = 0; Scaling = 0.2; // Use the scaling to deal with baleen whales not having such a great difference do { ExpectedLnAdultMassRatio = 2.5 + Scaling * Math.Log(CohortAdultMass); CohortAdultMassRatio = 1.0 + 10 * RandomNumberGenerator.GetLogNormal(ExpectedLnAdultMassRatio, 0.5); CohortJuvenileMass = CohortAdultMass * 1.0 / CohortAdultMassRatio; Counter++; if (Counter > 10) { Scaling -= 0.01; Counter = 0; } } while (CohortAdultMass <= CohortJuvenileMass || CohortJuvenileMass < MassMinima[FunctionalGroup]); } } else { // Use the same seed for the random number generator every time RandomNumberGenerator.SetSeed((uint)(jj + 1), (uint)((jj + 1) * 3)); // Draw adult mass from a log-normal distribution with mean -6.9 and standard deviation 10.0, // within the bounds of the minimum and maximum body masses for the functional group CohortAdultMass = Math.Pow(10, (RandomNumberGenerator.GetUniform() * (Math.Log10(MassMaxima[FunctionalGroup]) - Math.Log10(50 * MassMinima[FunctionalGroup])) + Math.Log10(50 * MassMinima[FunctionalGroup]))); OptimalPreyBodySizeRatio = Math.Max(0.01, RandomNumberGenerator.GetNormal(0.1, 0.02)); // Draw from a log-normal distribution with mean 10.0 and standard deviation 5.0, then add one to obtain // the ratio of adult to juvenile body mass, and then calculate juvenile mass based on this ratio and within the // bounds of the minimum and maximum body masses for this functional group if (cellEnvironment["Realm"][0] == 1.0) { do { ExpectedLnAdultMassRatio = 2.24 + 0.13 * Math.Log(CohortAdultMass); CohortAdultMassRatio = 1.0 + RandomNumberGenerator.GetLogNormal(ExpectedLnAdultMassRatio, 0.5); CohortJuvenileMass = CohortAdultMass * 1.0 / CohortAdultMassRatio; } while (CohortAdultMass <= CohortJuvenileMass || CohortJuvenileMass < MassMinima[FunctionalGroup]); } // In the marine realm, have a greater difference between the adult and juvenile body masses, on average else { do { ExpectedLnAdultMassRatio = 2.24 + 0.13 * Math.Log(CohortAdultMass); CohortAdultMassRatio = 1.0 + 10 * RandomNumberGenerator.GetLogNormal(ExpectedLnAdultMassRatio, 0.5); CohortJuvenileMass = CohortAdultMass * 1.0 / CohortAdultMassRatio; } while (CohortAdultMass <= CohortJuvenileMass || CohortJuvenileMass < MassMinima[FunctionalGroup]); } } // An instance of Cohort to hold the new cohort Cohort NewCohort; //double NewBiomass = Math.Pow(0.2, (Math.Log10(CohortAdultMass))) * (1.0E9 * _CellEnvironment["Cell Area"][0]) / NumCohortsThisCell; // 3000*(0.6^log(mass)) gives individual cohort biomass density in g ha-1 // * 100 to give g km-2 // * cell area to give g grid cell //*3300/NumCohortsThisCell scales total initial biomass in the cell to some approximately reasonable mass double NewBiomass = (3300 / NumCohortsThisCell) * 100 * 3000 * Math.Pow(0.6, (Math.Log10(CohortJuvenileMass))) * (_CellEnvironment["Cell Area"][0]); TotalNewBiomass += NewBiomass; double NewAbund = 0.0; if (!ZeroAbundance) { NewAbund = NewBiomass / CohortJuvenileMass; } /* // TEMPORARILY MARINE ONLY if (cellEnvironment["Realm"][0] == 1) { NewAbund = 0.0; } */ double TrophicIndex; switch (NutritionSource[FunctionalGroup]) { case "herbivore": TrophicIndex = 2; break; case "omnivore": TrophicIndex = 2.5; break; case "carnivore": TrophicIndex = 3; break; default: Debug.Fail("Unexpected nutrition source trait value when assigning trophic index"); TrophicIndex = 0.0; break; } // Initialise the new cohort with the relevant properties NewCohort = new Cohort((byte)FunctionalGroup, CohortJuvenileMass, CohortAdultMass, CohortJuvenileMass, NewAbund, OptimalPreyBodySizeRatio, (ushort)0, ProportionTimeActive[FunctionalGroup], ref CohortIDIncrementer,TrophicIndex, tracking); // Add the new cohort to the list of grid cell cohorts _GridCellCohorts[FunctionalGroup].Add(NewCohort); // TEMPORARY /* // Check whether the model is set to randomly draw the body masses of new cohorts if ((Longitude % 4 == 0) && (Latitude % 4 == 0)) { if (DrawRandomly) { CohortAdultMass = 100000; CohortJuvenileMass = 100000; } else { CohortAdultMass = 100000; CohortJuvenileMass = 100000; } // An instance of Cohort to hold the new cohort Cohort NewCohort; double NewBiomass = (1.0E7 * _CellEnvironment["Cell Area"][0]) / NumCohortsThisCell; double NewAbund = 0.0; NewAbund = 3000; // Initialise the new cohort with the relevant properties NewCohort = new Cohort((byte)FunctionalGroup, CohortJuvenileMass, CohortAdultMass, CohortJuvenileMass, NewAbund, (ushort)0, ref nextCohortID, tracking); // Add the new cohort to the list of grid cell cohorts _GridCellCohorts[FunctionalGroup].Add(NewCohort); } */ // Incrememt the variable tracking the total number of cohorts in the model globalDiagnostics["NumberOfCohortsInModel"]++; } } } } else { // Loop over all functional groups in the model for (int FunctionalGroup = 0; FunctionalGroup < functionalGroups.GetNumberOfFunctionalGroups(); FunctionalGroup++) { // Create a new list to hold the cohorts in the grid cell _GridCellCohorts[FunctionalGroup] = new List<Cohort>(); } } // tempsw.Dispose(); }
/// <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> /// Initialises herbivory implementation each time step /// </summary> /// <param name="gridCellCohorts">The cohorts in the current grid cell</param> /// <param name="gridCellStocks">The stocks in the current grid cell</param> /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param> /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param> /// <param name="cellEnvironment">The environment in the current grid cell</param> /// <remarks>This only works if: a) herbivory is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips /// It is critical to run this every time step</remarks> public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, SortedList<string, double[]> cellEnvironment) { // Get the functional group indices of all autotroph stocks _FunctionalGroupIndicesToEat = madingleyStockDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "Autotroph", false); string[] realm = { "Terrestrial", "Marine" }; int realm_index = (int)cellEnvironment["Realm"][0] - 1; string Current_realm = realm[realm_index]; }
/// <summary> /// Seed the stocks and cohorts from output from a previous simulation /// </summary> /// <param name="cellIndices">A list of the active cells in the model grid</param> /// <param name="cohortFunctionalGroupDefinitions">The functional group definitions for cohorts in the model</param> /// <param name="stockFunctionalGroupDefinitions">The functional group definitions for stocks in the model</param> /// <param name="globalDiagnostics">A list of global diagnostic variables</param> /// <param name="nextCohortID">The ID number to be assigned to the next produced cohort</param> /// <param name="tracking">Whether process-tracking is enabled</param> /// <param name="DrawRandomly">Whether the model is set to use a random draw</param> /// <param name="dispersalOnly">Whether to run dispersal only (i.e. to turn off all other ecological processes</param> /// <param name="processTrackers">An instance of the ecological process tracker</param> public void SeedGridCellStocksAndCohorts(List<uint[]> cellIndices, InputModelState inputModelState, FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions) { int ii = 1; Console.WriteLine("Seeding grid cell stocks and cohorts:"); //Check to see if the correct number of functional groups exist in the definitions file and in the input state if (cohortFunctionalGroupDefinitions.GetNumberOfFunctionalGroups() != inputModelState.GridCellCohorts[ cellIndices[0][0],cellIndices[0][1]].Count) { Console.WriteLine("Mismatch in the number of functional groups defined in CohortFunctionalGroupDefinitions.csv set-up file and the Model State being read in"); Environment.Exit(0); } int[] TerrestrialStockFunctionalIndices = stockFunctionalGroupDefinitions.GetFunctionalGroupIndex("Realm", "Terrestrial", false); int[] MarineStockFunctionalIndices = stockFunctionalGroupDefinitions.GetFunctionalGroupIndex("Realm", "Marine", false); int[] TerrestrialCohortFunctionalIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex("Realm", "Terrestrial", false); int[] MarineCohortFunctionalIndices = cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex("Realm", "Marine", false); foreach (uint[] cellIndexPair in cellIndices) { for (int i = 0; i < inputModelState.GridCellCohorts[cellIndexPair[0], cellIndexPair[1]].Count; i++) { InternalGrid[cellIndexPair[0], cellIndexPair[1]].GridCellCohorts[i] = new List<Cohort>(); } //Check which cohorts should be initialised for each cell if (InternalGrid[cellIndexPair[0], cellIndexPair[1]].CellEnvironment["Realm"][0] == 1) { //This is a terrestrial cell so only add the terrestrial stocks foreach (int fg in TerrestrialCohortFunctionalIndices) { //Cohort[] tempGridCellCohorts = (Cohort[])inputModelState.GridCellCohorts[cellIndexPair[0], cellIndexPair[1]][fg].ToArray().Clone(); //Cohort[] tempGridCellCohorts = (Cohort[])Array.ConvertAll(inputModelState.GridCellCohorts[cellIndexPair[0], cellIndexPair[1]][fg].ToArray(), // element => (Cohort)element.Clone()); Cohort[] tempGridCellCohorts = inputModelState.GridCellCohorts[cellIndexPair[0], cellIndexPair[1]][fg].ToArray().Select(cohort => new Cohort(cohort)).ToArray(); InternalGrid[cellIndexPair[0], cellIndexPair[1]].GridCellCohorts[fg] = tempGridCellCohorts.ToList(); } } else { // this is a marine cell so only add the marine stocks foreach (int fg in MarineCohortFunctionalIndices) { //Cohort[] tempGridCellCohorts = (Cohort[])inputModelState.GridCellCohorts[cellIndexPair[0], cellIndexPair[1]][fg].ToArray().Clone(); //Cohort[] tempGridCellCohorts = (Cohort[])Array.ConvertAll(inputModelState.GridCellCohorts[cellIndexPair[0], cellIndexPair[1]][fg].ToArray(), // element => (Cohort)element.Clone()); Cohort[] tempGridCellCohorts = inputModelState.GridCellCohorts[cellIndexPair[0], cellIndexPair[1]][fg].ToArray().Select(cohort => new Cohort(cohort)).ToArray(); InternalGrid[cellIndexPair[0], cellIndexPair[1]].GridCellCohorts[fg] = tempGridCellCohorts.ToList(); } } for (int i = 0; i < inputModelState.GridCellStocks[cellIndexPair[0], cellIndexPair[1]].Count; i++) { InternalGrid[cellIndexPair[0], cellIndexPair[1]].GridCellStocks[i] = new List<Stock>(); } //Check which stocks should be initialised for each cell if (InternalGrid[cellIndexPair[0], cellIndexPair[1]].CellEnvironment["Realm"][0] == 1) { //This is a terrestrial cell so only add the terrestrial stocks foreach (int fg in TerrestrialStockFunctionalIndices) { //Stock[] tempGridCellStocks = (Stock[])inputModelState.GridCellStocks[cellIndexPair[0], cellIndexPair[1]][fg].ToArray().Clone(); //Stock[] tempGridCellStocks = (Stock[])Array.ConvertAll(inputModelState.GridCellStocks[cellIndexPair[0], cellIndexPair[1]][fg].ToArray(), // element => (Stock)element.Clone()); Stock[] tempGridCellStocks = inputModelState.GridCellStocks[cellIndexPair[0], cellIndexPair[1]][fg].ToArray().Select(stock => new Stock(stock)).ToArray(); InternalGrid[cellIndexPair[0], cellIndexPair[1]].GridCellStocks[fg] = tempGridCellStocks.ToList(); } } else { // this is a marine cell so only add the marine stocks foreach (int fg in MarineStockFunctionalIndices) { //Stock[] tempGridCellStocks = (Stock[])inputModelState.GridCellStocks[cellIndexPair[0], cellIndexPair[1]][fg].ToArray().Clone(); //Stock[] tempGridCellStocks = (Stock[])Array.ConvertAll(inputModelState.GridCellStocks[cellIndexPair[0], cellIndexPair[1]][fg].ToArray(), // element => (Stock)element.Clone()); Stock[] tempGridCellStocks = inputModelState.GridCellStocks[cellIndexPair[0], cellIndexPair[1]][fg].ToArray().Select(stock => new Stock(stock)).ToArray(); InternalGrid[cellIndexPair[0], cellIndexPair[1]].GridCellStocks[fg] = tempGridCellStocks.ToList(); } } Console.Write("\rGrid Cell: {0} of {1}", ii++, cellIndices.Count); } Console.WriteLine(""); Console.WriteLine(""); }
/// <summary> /// Initialises predation implementation each time step /// </summary> /// <param name="gridCellCohorts">The cohorts in the current grid cell</param> /// <param name="gridCellStocks">The stocks in the current grid cell</param> /// <param name="madingleyCohortDefinitions">The definitions for cohorts in the model</param> /// <param name="madingleyStockDefinitions">The definitions for stocks in the model</param> /// <param name="cellEnvironment">The environment in the current grid cell</param> /// <remarks>This only works if: a) predation is initialised in every grid cell; and b) if parallelisation is done by latitudinal strips /// It is critical to run this every time step</remarks> public void InitializeEatingPerTimeStep(GridCellCohortHandler gridCellCohorts, GridCellStockHandler gridCellStocks, FunctionalGroupDefinitions madingleyCohortDefinitions, FunctionalGroupDefinitions madingleyStockDefinitions, SortedList<string, double[]> cellEnvironment) { // Get the functional group indices of all heterotroph cohorts (i.e. potential prey) // _FunctionalGroupIndicesToEat = madingleyCohortDefinitions.GetFunctionalGroupIndex("Heterotroph/Autotroph", "heterotroph", false); string [] realm = { "Terrestrial", "Marine" }; int realm_index = (int)cellEnvironment["Realm"][0] - 1; string Current_realm = realm[realm_index]; _FunctionalGroupIndicesToEat = madingleyCohortDefinitions.GetFunctionalGroupIndex("realm", Current_realm, false); // Initialise the vector to hold the number of cohorts in each functional group at the start of the time step NumberCohortsPerFunctionalGroupNoNewCohorts = new int[gridCellCohorts.Count]; // Initialise the jagged arrays to hold the potential and actual numbers of prey eaten in each of the grid cell cohorts _AbundancesEaten = new double[gridCellCohorts.Count][]; _PotentialAbundanceEaten = new double[gridCellCohorts.Count][]; // Initialise the vector to identify carnivore cohorts _CarnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; _OmnivoreFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; _PlanktonFunctionalGroups = new Boolean[_FunctionalGroupIndicesToEat.Length]; // Loop over rows in the jagged arrays, initialise each vector within the jagged arrays, and calculate the current number of cohorts in // each functional group for (int i = 0; i < gridCellCohorts.Count; i++) { // Calculate the current number of cohorts in this functional group int NumCohortsThisFG = gridCellCohorts[i].Count; NumberCohortsPerFunctionalGroupNoNewCohorts[i] = NumCohortsThisFG; // Initialise the jagged arrays _AbundancesEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]]; _PotentialAbundanceEaten[i] = new double[NumberCohortsPerFunctionalGroupNoNewCohorts[i]]; } // Loop over functional groups that are potential prey and determine which are carnivores THIS IS COMMENTED OUT AS IT'S NOT USED //foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) // _CarnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "carnivore"; //foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) // _OmnivoreFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Nutrition source", FunctionalGroup) == "omnivore"; //foreach (int FunctionalGroup in FunctionalGroupIndicesToEat) // _PlanktonFunctionalGroups[FunctionalGroup] = madingleyCohortDefinitions.GetTraitNames("Mobility", FunctionalGroup) == "planktonic"; }
/// <summary> /// Set up the necessary architecture for generating outputs arranged by trait value /// </summary> /// <param name="cohortFunctionalGroupDefinitions">Functional group definitions for cohorts in the model</param> /// <param name="stockFunctionalGroupDefinitions">Functional group definitions for stocks in the model</param> private void InitialiseTraitBasedOutputs(FunctionalGroupDefinitions cohortFunctionalGroupDefinitions, FunctionalGroupDefinitions stockFunctionalGroupDefinitions) { // Define the cohort traits that will be used to separate outputs CohortTraits = new string[3] { "Nutrition source", "Endo/Ectotherm", "Reproductive strategy" }; // Declare a sorted dictionary to hold all unique trait values CohortTraitValues = new SortedDictionary<string, string[]>(); // Add all unique trait values to the sorted dictionary foreach (string Trait in CohortTraits) { CohortTraitValues.Add(Trait, cohortFunctionalGroupDefinitions.GetUniqueTraitValues(Trait)); } // Get the list of functional group indices corresponding to each unique trait value foreach (string Trait in CohortTraits) { foreach (string TraitValue in CohortTraitValues[Trait]) { CohortTraitIndices.Add(TraitValue, cohortFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false)); } } // Define the stock traits that will be used to separate outputs StockTraits = new string[2] { "Heterotroph/Autotroph" ,"Leaf strategy"}; // Re-initialise the sorted dictionary to hold all unique trait values StockTraitValues = new SortedDictionary<string, string[]>(); // Add all unique stock trait values to the sorted dictionary foreach (string Trait in StockTraits) { StockTraitValues.Add(Trait, stockFunctionalGroupDefinitions.GetUniqueTraitValues(Trait)); } // Get the list of functional group indices corresponding to each unique trait value foreach (string Trait in StockTraits) { foreach (string TraitValue in StockTraitValues[Trait]) { StockTraitIndices.Add(TraitValue, stockFunctionalGroupDefinitions.GetFunctionalGroupIndex(Trait, TraitValue, false)); } } }