private void OnSimulationCommencing(object sender, EventArgs e) { bool ParentOrganIdentified = false; IModel ParentClass = this.Parent; while (!ParentOrganIdentified) { if (ParentClass is IArbitration) { parentOrgan = ParentClass as IArbitration; ParentOrganIdentified = true; if (ParentClass is IPlant) { throw new Exception(Name + "cannot find parent organ to get Structural and Storage N status"); } } ParentClass = ParentClass.Parent; } }
/// <summary>Does the retranslocation.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> /// <param name="Option">The option.</param> public virtual void DoRetranslocation(IArbitration[] Organs, BiomassArbitrationType BAT, ArbitrationType Option) { double BiomassRetranslocated = 0; if (BAT.TotalRetranslocationSupply > 0.00000000001) { // Calculate how much retranslocation N (and associated biomass) each demanding organ is allocated based on relative demands if (Option == ArbitrationType.RelativeAllocation) RelativeAllocation(Organs, BAT.TotalRetranslocationSupply, ref BiomassRetranslocated, BAT); if (Option == ArbitrationType.PriorityAllocation) PriorityAllocation(Organs, BAT.TotalRetranslocationSupply, ref BiomassRetranslocated, BAT); if (Option == ArbitrationType.PriorityThenRelativeAllocation) PrioritythenRelativeAllocation(Organs, BAT.TotalRetranslocationSupply, ref BiomassRetranslocated, BAT); if (Option == ArbitrationType.RelativeAllocationSinglePass) RelativeAllocationSinglePass(Organs, BAT.TotalRetranslocationSupply, ref BiomassRetranslocated, BAT); // Then calculate how much N (and associated biomass) is retranslocated from each supplying organ based on relative retranslocation supply for (int i = 0; i < Organs.Length; i++) { if (BAT.RetranslocationSupply[i] > 0.00000000001) { double RelativeSupply = BAT.RetranslocationSupply[i] / BAT.TotalRetranslocationSupply; BAT.Retranslocation[i] += BiomassRetranslocated * RelativeSupply; } } } }
/// <summary>Does the nutrient set up.</summary> /// <param name="Organs">The organs.</param> /// <param name="N">The bat.</param> public virtual void DoNutrientSetUp(IArbitration[] Organs, ref BiomassArbitrationType N) { //Creat Biomass variable class N = new BiomassArbitrationType(Organs.Length); N.BiomassType = "N"; // GET ALL INITIAL STATE VARIABLES FOR MASS BALANCE CHECKS N.Start = 0; // GET ALL SUPPLIES AND DEMANDS AND CALCULATE TOTALS for (int i = 0; i < Organs.Length; i++) { BiomassSupplyType Supply = Organs[i].NSupply; N.ReallocationSupply[i] = Supply.Reallocation; //N.UptakeSupply[i] = Supply.Uptake; This is done on DoNutrientUptakeCalculations N.FixationSupply[i] = Supply.Fixation; N.RetranslocationSupply[i] = Supply.Retranslocation; N.Start += Organs[i].N; } N.TotalReallocationSupply = MathUtilities.Sum(N.ReallocationSupply); //N.TotalUptakeSupply = MathUtilities.Sum(N.UptakeSupply); This is done on DoNutrientUptakeCalculations N.TotalFixationSupply = MathUtilities.Sum(N.FixationSupply); N.TotalRetranslocationSupply = MathUtilities.Sum(N.RetranslocationSupply); N.TotalPlantSupply = N.TotalReallocationSupply + N.TotalUptakeSupply + N.TotalFixationSupply + N.TotalRetranslocationSupply; for (int i = 0; i < Organs.Length; i++) { BiomassPoolType Demand = Organs[i].NDemand; if (MathUtilities.IsLessThan(Demand.Structural, 0)) throw new Exception(Organs[i].Name + " is returning a negative Structural N demand. Check your parameterisation"); if (MathUtilities.IsLessThan(Demand.NonStructural, 0)) throw new Exception(Organs[i].Name + " is returning a negative NonStructural N demand. Check your parameterisation"); if (MathUtilities.IsLessThan(Demand.Metabolic, 0)) throw new Exception(Organs[i].Name + " is returning a negative Metabolic N demand. Check your parameterisation"); N.StructuralDemand[i] = Organs[i].NDemand.Structural; N.MetabolicDemand[i] = Organs[i].NDemand.Metabolic; N.NonStructuralDemand[i] = Organs[i].NDemand.NonStructural; N.TotalDemand[i] = N.StructuralDemand[i] + N.MetabolicDemand[i] + N.NonStructuralDemand[i]; N.Reallocation[i] = 0; N.Uptake[i] = 0; N.Fixation[i] = 0; N.Retranslocation[i] = 0; N.StructuralAllocation[i] = 0; N.MetabolicAllocation[i] = 0; N.NonStructuralAllocation[i] = 0; } N.TotalStructuralDemand = MathUtilities.Sum(N.StructuralDemand); N.TotalMetabolicDemand = MathUtilities.Sum(N.MetabolicDemand); N.TotalNonStructuralDemand = MathUtilities.Sum(N.NonStructuralDemand); N.TotalPlantDemand = N.TotalStructuralDemand + N.TotalMetabolicDemand + N.TotalNonStructuralDemand; N.TotalStructuralAllocation = 0; N.TotalMetabolicAllocation = 0; N.TotalNonStructuralAllocation = 0; //Set relative N demands of each organ for (int i = 0; i < Organs.Length; i++) { if (N.TotalStructuralDemand > 0) N.RelativeStructuralDemand[i] = N.StructuralDemand[i] / N.TotalStructuralDemand; if (N.TotalMetabolicDemand > 0) N.RelativeMetabolicDemand[i] = N.MetabolicDemand[i] / N.TotalMetabolicDemand; if (N.TotalNonStructuralDemand > 0) N.RelativeNonStructuralDemand[i] = N.NonStructuralDemand[i] / N.TotalNonStructuralDemand; } }
/// <summary>Determines Nutrient limitations to DM allocations</summary> /// <param name="Organs">The organs.</param> public virtual void DoNutrientConstrainedDMAllocation(IArbitration[] Organs) { double PreNStressDMAllocation = DM.Allocated; for (int i = 0; i < Organs.Length; i++) N.TotalAllocation[i] = N.StructuralAllocation[i] + N.MetabolicAllocation[i] + N.NonStructuralAllocation[i]; N.Allocated = MathUtilities.Sum(N.TotalAllocation); //To introduce functionality for other nutrients we need to repeat this for loop for each new nutrient type // Calculate posible growth based on Minimum N requirement of organs for (int i = 0; i < Organs.Length; i++) { if (N.TotalAllocation[i] >= N.TotalDemand[i]) N.ConstrainedGrowth[i] = 100000000; //given high value so where there is no N deficit in organ and N limitation to growth else if (N.TotalAllocation[i] == 0) N.ConstrainedGrowth[i] = 0; else N.ConstrainedGrowth[i] = N.TotalAllocation[i] / Organs[i].MinNconc; } // Reduce DM allocation below potential if insufficient N to reach Min n Conc or if DM was allocated to fixation for (int i = 0; i < Organs.Length; i++) { if ((DM.MetabolicAllocation[i] + DM.StructuralAllocation[i]) != 0) { double MetabolicProportion = DM.MetabolicAllocation[i] / (DM.MetabolicAllocation[i] + DM.StructuralAllocation[i] + DM.NonStructuralAllocation[i]); double StructuralProportion = DM.StructuralAllocation[i] / (DM.MetabolicAllocation[i] + DM.StructuralAllocation[i] + DM.NonStructuralAllocation[i]); double NonStructuralProportion = DM.NonStructuralAllocation[i] / (DM.MetabolicAllocation[i] + DM.StructuralAllocation[i] + DM.NonStructuralAllocation[i]); DM.MetabolicAllocation[i] = Math.Min(DM.MetabolicAllocation[i], N.ConstrainedGrowth[i] * MetabolicProportion); DM.StructuralAllocation[i] = Math.Min(DM.StructuralAllocation[i], N.ConstrainedGrowth[i] * StructuralProportion); //To introduce effects of other nutrients Need to include Plimited and Klimited growth in this min function DM.NonStructuralAllocation[i] = Math.Min(DM.NonStructuralAllocation[i], N.ConstrainedGrowth[i] * NonStructuralProportion); //To introduce effects of other nutrients Need to include Plimited and Klimited growth in this min function //Question. Why do I not restrain non-structural DM allocations. I think this may be wrong and require further thought HEB 15-1-2015 } } //Recalculated DM Allocation totals DM.TotalStructuralAllocation = MathUtilities.Sum(DM.StructuralAllocation); DM.TotalMetabolicAllocation = MathUtilities.Sum(DM.MetabolicAllocation); DM.TotalNonStructuralAllocation = MathUtilities.Sum(DM.NonStructuralAllocation); DM.Allocated = DM.TotalStructuralAllocation + DM.TotalMetabolicAllocation + DM.TotalNonStructuralAllocation; DM.NutrientLimitation = (PreNStressDMAllocation - DM.Allocated); }
/// <summary>Does the fixation.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> /// <param name="Option">The option.</param> /// <exception cref="System.Exception">Crop is trying to Fix excessive amounts of BAT. Check partitioning coefficients are giving realistic nodule size and that FixationRatePotential is realistic</exception> public virtual void DoFixation(IArbitration[] Organs, BiomassArbitrationType BAT, ArbitrationType Option) { double BiomassFixed = 0; if (BAT.TotalFixationSupply > 0.00000000001) { // Calculate how much fixed resource each demanding organ is allocated based on relative demands if (Option == ArbitrationType.RelativeAllocation) RelativeAllocation(Organs, BAT.TotalFixationSupply, ref BiomassFixed, BAT); if (Option == ArbitrationType.PriorityAllocation) PriorityAllocation(Organs, BAT.TotalFixationSupply, ref BiomassFixed, BAT); if (Option == ArbitrationType.PriorityThenRelativeAllocation) PrioritythenRelativeAllocation(Organs, BAT.TotalFixationSupply, ref BiomassFixed, BAT); if (Option == ArbitrationType.RelativeAllocationSinglePass) RelativeAllocationSinglePass(Organs, BAT.TotalFixationSupply, ref BiomassFixed, BAT); //Set the sink limitation variable. BAT.NotAllocated changes after each allocation step so it must be caught here and assigned as sink limitation BAT.SinkLimitation = BAT.NotAllocated; // Then calculate how much resource is fixed from each supplying organ based on relative fixation supply if (BiomassFixed > 0) { for (int i = 0; i < Organs.Length; i++) { if (BAT.FixationSupply[i] > 0.00000000001) { double RelativeSupply = BAT.FixationSupply[i] / BAT.TotalFixationSupply; BAT.Fixation[i] = BiomassFixed * RelativeSupply; double Respiration = BiomassFixed * RelativeSupply * Organs[i].NFixationCost; //Calculalte how much respirtion is associated with fixation DM.Respiration[i] = Respiration; // allocate it to the organ } DM.TotalRespiration = MathUtilities.Sum(DM.Respiration); } } // Work out the amount of biomass (if any) lost due to the cost of N fixation if (DM.TotalRespiration <= DM.SinkLimitation) { } //Cost of N fixation can be met by DM supply that was not allocated else {//claw back todays NonStructuralDM allocation to cover the cost double UnallocatedRespirationCost = DM.TotalRespiration - DM.SinkLimitation; if (DM.TotalNonStructuralAllocation > 0) { for (int i = 0; i < Organs.Length; i++) { double proportion = DM.NonStructuralAllocation[i] / DM.TotalNonStructuralAllocation; double Clawback = Math.Min(UnallocatedRespirationCost * proportion, DM.NonStructuralAllocation[i]); DM.NonStructuralAllocation[i] -= Clawback; UnallocatedRespirationCost -= Clawback; } } if (UnallocatedRespirationCost == 0) { }//All cost accounted for else {//Remobilise more Non-structural DM to cover the cost if (DM.TotalRetranslocationSupply > 0) { for (int i = 0; i < Organs.Length; i++) { double proportion = DM.RetranslocationSupply[i] / DM.TotalRetranslocationSupply; double DMRetranslocated = Math.Min(UnallocatedRespirationCost * proportion, DM.RetranslocationSupply[i]); DM.Retranslocation[i] += DMRetranslocated; UnallocatedRespirationCost -= DMRetranslocated; } } if (UnallocatedRespirationCost == 0) { }//All cost accounted for else {//Start cutting into Structural and Metabolic Allocations if ((DM.TotalStructuralAllocation + DM.TotalMetabolicAllocation) > 0) { double Costmet = 0; for (int i = 0; i < Organs.Length; i++) { if ((DM.StructuralAllocation[i] + DM.MetabolicAllocation[i]) > 0) { double proportion = (DM.StructuralAllocation[i] + DM.MetabolicAllocation[i]) / (DM.TotalStructuralAllocation + DM.TotalMetabolicAllocation); double StructualFraction = DM.StructuralAllocation[i] / (DM.StructuralAllocation[i] + DM.MetabolicAllocation[i]); double StructuralClawback = Math.Min(UnallocatedRespirationCost * proportion * StructualFraction, DM.StructuralAllocation[i]); double MetabolicClawback = Math.Min(UnallocatedRespirationCost * proportion * (1 - StructualFraction), DM.MetabolicAllocation[i]); DM.StructuralAllocation[i] -= StructuralClawback; DM.MetabolicAllocation[i] -= MetabolicClawback; Costmet += (StructuralClawback + MetabolicClawback); } } UnallocatedRespirationCost -= Costmet; } } if (UnallocatedRespirationCost > 0.0000000001) throw new Exception("Crop is trying to Fix excessive amounts of " + BAT.BiomassType +" Check partitioning coefficients are giving realistic nodule size and that FixationRatePotential is realistic"); } } } }
/// <summary>Does the dm setup.</summary> /// <param name="Organs">The organs.</param> public virtual void DoDMSetup(IArbitration[] Organs) { //Creat Drymatter variable class DM = new BiomassArbitrationType(Organs.Length); DM.BiomassType = "DM"; // GET INITIAL STATE VARIABLES FOR MASS BALANCE CHECKS DM.Start = 0; // GET SUPPLIES AND CALCULATE TOTAL for (int i = 0; i < Organs.Length; i++) { BiomassSupplyType Supply = Organs[i].DMSupply; if (MathUtilities.IsLessThan(Supply.Fixation + Supply.Reallocation+Supply.Retranslocation+Supply.Uptake, 0)) throw new Exception(Organs[i].Name + " is returning a negative DM supply. Check your parameterisation"); DM.ReallocationSupply[i] = Supply.Reallocation; DM.UptakeSupply[i] = Supply.Uptake; DM.FixationSupply[i] = Supply.Fixation; DM.RetranslocationSupply[i] = Supply.Retranslocation; DM.Start += Organs[i].Wt; } DM.TotalReallocationSupply = MathUtilities.Sum(DM.ReallocationSupply); DM.TotalUptakeSupply = MathUtilities.Sum(DM.UptakeSupply); DM.TotalFixationSupply = MathUtilities.Sum(DM.FixationSupply); DM.TotalRetranslocationSupply = MathUtilities.Sum(DM.RetranslocationSupply); DM.TotalPlantSupply = DM.TotalReallocationSupply + DM.TotalUptakeSupply + DM.TotalFixationSupply + DM.TotalRetranslocationSupply; // SET OTHER ORGAN VARIABLES AND CALCULATE TOTALS for (int i = 0; i < Organs.Length; i++) { BiomassPoolType Demand = Organs[i].DMDemand; if (MathUtilities.IsLessThan(Demand.Structural, 0)) throw new Exception(Organs[i].Name + " is returning a negative Structural DM demand. Check your parameterisation"); if (MathUtilities.IsLessThan(Demand.NonStructural, 0)) throw new Exception(Organs[i].Name + " is returning a negative NonStructural DM demand. Check your parameterisation"); if (MathUtilities.IsLessThan(Demand.Metabolic, 0)) throw new Exception(Organs[i].Name + " is returning a negative Metabolic DM demand. Check your parameterisation"); DM.StructuralDemand[i] = Demand.Structural; DM.MetabolicDemand[i] = Demand.Metabolic; DM.NonStructuralDemand[i] = Demand.NonStructural; DM.TotalDemand[i] = DM.StructuralDemand[i] + DM.MetabolicDemand[i] + DM.NonStructuralDemand[i]; DM.Reallocation[i] = 0; DM.Uptake[i] = 0; DM.Fixation[i] = 0; DM.Retranslocation[i] = 0; DM.StructuralAllocation[i] = 0; DM.MetabolicAllocation[i] = 0; DM.NonStructuralAllocation[i] = 0; } DM.TotalStructuralDemand = MathUtilities.Sum(DM.StructuralDemand); DM.TotalMetabolicDemand = MathUtilities.Sum(DM.MetabolicDemand); DM.TotalNonStructuralDemand = MathUtilities.Sum(DM.NonStructuralDemand); DM.TotalPlantDemand = DM.TotalStructuralDemand + DM.TotalMetabolicDemand + DM.TotalNonStructuralDemand; DM.TotalStructuralAllocation = 0; DM.TotalMetabolicAllocation = 0; DM.TotalNonStructuralAllocation = 0; DM.Allocated = 0; DM.SinkLimitation = 0; DM.NutrientLimitation = 0; //Set relative DM demands of each organ for (int i = 0; i < Organs.Length; i++) { if (DM.TotalStructuralDemand > 0) DM.RelativeStructuralDemand[i] = DM.StructuralDemand[i] / DM.TotalStructuralDemand; if (DM.TotalMetabolicDemand > 0) DM.RelativeMetabolicDemand[i] = DM.MetabolicDemand[i] / DM.TotalMetabolicDemand; if (DM.TotalNonStructuralDemand > 0) DM.RelativeNonStructuralDemand[i] = DM.NonStructuralDemand[i] / DM.TotalNonStructuralDemand; } }
/// <summary>Partitions biomass between organs based on their relative demand in a single pass so non-structural always gets some if there is a non-structural demand</summary> /// <param name="Organs">The organs.</param> /// <param name="TotalSupply">The total supply.</param> /// <param name="TotalAllocated">The total allocated.</param> /// <param name="BAT">The bat.</param> private void RelativeAllocationSinglePass(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT) { double NotAllocated = TotalSupply; ////allocate to all pools based on their relative demands for (int i = 0; i < Organs.Length; i++) { double StructuralRequirement = Math.Max(0, BAT.StructuralDemand[i] - BAT.StructuralAllocation[i]); //N needed to get to Minimum N conc and satisfy structural and metabolic N demands double MetabolicRequirement = Math.Max(0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]); double NonStructuralRequirement = Math.Max(0, BAT.NonStructuralDemand[i] - BAT.NonStructuralAllocation[i]); if ((StructuralRequirement + MetabolicRequirement + NonStructuralRequirement) > 0.0) { double StructuralFraction = BAT.TotalStructuralDemand / (BAT.TotalStructuralDemand + BAT.TotalMetabolicDemand + BAT.TotalNonStructuralDemand); double MetabolicFraction = BAT.TotalMetabolicDemand / (BAT.TotalStructuralDemand + BAT.TotalMetabolicDemand + BAT.TotalNonStructuralDemand); double NonStructuralFraction = BAT.TotalNonStructuralDemand / (BAT.TotalStructuralDemand + BAT.TotalMetabolicDemand + BAT.TotalNonStructuralDemand); double StructuralAllocation = Math.Min(StructuralRequirement, TotalSupply * StructuralFraction * BAT.RelativeStructuralDemand[i]); double MetabolicAllocation = Math.Min(MetabolicRequirement, TotalSupply * MetabolicFraction * BAT.RelativeMetabolicDemand[i]); double NonStructuralAllocation = Math.Min(NonStructuralRequirement, TotalSupply * NonStructuralFraction * BAT.RelativeNonStructuralDemand[i]); BAT.StructuralAllocation[i] += StructuralAllocation; BAT.MetabolicAllocation[i] += MetabolicAllocation; BAT.NonStructuralAllocation[i] += Math.Max(0, NonStructuralAllocation); NotAllocated -= (StructuralAllocation + MetabolicAllocation + NonStructuralAllocation); TotalAllocated += (StructuralAllocation + MetabolicAllocation + NonStructuralAllocation); } } }
/// <summary>Does the re allocation.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> /// <param name="Option">The option.</param> public virtual void DoReAllocation(IArbitration[] Organs, BiomassArbitrationType BAT, string Option) { double BiomassReallocated = 0; if (BAT.TotalReallocationSupply > 0.00000000001) { //Calculate how much reallocated N (and associated biomass) each demanding organ is allocated based on relative demands if (string.Compare(Option, "RelativeAllocation", true) == 0) RelativeAllocation(Organs, BAT.TotalReallocationSupply, ref BiomassReallocated, BAT); if (string.Compare(Option, "PriorityAllocation", true) == 0) PriorityAllocation(Organs, BAT.TotalReallocationSupply, ref BiomassReallocated, BAT); if (string.Compare(Option, "PrioritythenRelativeAllocation", true) == 0) PrioritythenRelativeAllocation(Organs, BAT.TotalReallocationSupply, ref BiomassReallocated, BAT); //Then calculate how much biomass is realloced from each supplying organ based on relative reallocation supply for (int i = 0; i < Organs.Length; i++) { if (BAT.ReallocationSupply[i] > 0) { double RelativeSupply = BAT.ReallocationSupply[i] / BAT.TotalReallocationSupply; BAT.Reallocation[i] += BiomassReallocated * RelativeSupply; } } BAT.TotalReallocation = MathUtilities.Sum(BAT.Reallocation); } }
/// <summary>Prioritythens the relative allocation.</summary> /// <param name="Organs">The organs.</param> /// <param name="TotalSupply">The total supply.</param> /// <param name="TotalAllocated">The total allocated.</param> /// <param name="BAT">The bat.</param> private void PrioritythenRelativeAllocation(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT) { double NotAllocated = TotalSupply; ////First time round allocate to met priority demands of each organ for (int i = 0; i < Organs.Length; i++) { double StructuralRequirement = Math.Max(0.0, BAT.StructuralDemand[i] - BAT.StructuralAllocation[i]); //N needed to get to Minimum N conc and satisfy structural and metabolic N demands double MetabolicRequirement = Math.Max(0.0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]); if ((StructuralRequirement + MetabolicRequirement) > 0.0) { double StructuralFraction = BAT.StructuralDemand[i] / (BAT.StructuralDemand[i] + BAT.MetabolicDemand[i]); double StructuralAllocation = Math.Min(StructuralRequirement, NotAllocated * StructuralFraction); double MetabolicAllocation = Math.Min(MetabolicRequirement, NotAllocated * (1 - StructuralFraction)); BAT.StructuralAllocation[i] += StructuralAllocation; BAT.MetabolicAllocation[i] += MetabolicAllocation; NotAllocated -= (StructuralAllocation + MetabolicAllocation); TotalAllocated += (StructuralAllocation + MetabolicAllocation); } } // Second time round if there is still N to allocate let organs take N up to their Maximum double FirstPassNotallocated = NotAllocated; for (int i = 0; i < Organs.Length; i++) { double NonStructuralRequirement = Math.Max(0.0, BAT.NonStructuralDemand[i] - BAT.NonStructuralAllocation[i]); //N needed to take organ up to maximum N concentration, Structural, Metabolic and Luxury N demands if (NonStructuralRequirement > 0.0) { double NonStructuralAllocation = Math.Min(FirstPassNotallocated * BAT.RelativeNonStructuralDemand[i], NonStructuralRequirement); BAT.NonStructuralAllocation[i] += Math.Max(0, NonStructuralAllocation); NotAllocated -= NonStructuralAllocation; TotalAllocated += NonStructuralAllocation; } } }
/// <summary>Sends the potential dm allocations.</summary> /// <param name="Organs">The organs.</param> /// <exception cref="System.Exception">Mass Balance Error in Photosynthesis DM Allocation</exception> public virtual void SendPotentialDMAllocations(IArbitration[] Organs) { // Allocate to meet Organs demands DM.TotalStructuralAllocation = MathUtilities.Sum(DM.StructuralAllocation); DM.TotalMetabolicAllocation = MathUtilities.Sum(DM.MetabolicAllocation); DM.TotalNonStructuralAllocation = MathUtilities.Sum(DM.NonStructuralAllocation); DM.Allocated = DM.TotalStructuralAllocation + DM.TotalMetabolicAllocation + DM.TotalNonStructuralAllocation; // Then check it all adds up if (Math.Round(DM.Allocated,8) > Math.Round(DM.TotalPlantSupply,8)) throw new Exception("Potential DM allocation by " + this.Name + " exceeds DM supply. Thats not really possible so something has gone a miss"); if (Math.Round(DM.Allocated,8) > Math.Round(DM.TotalPlantDemand,8)) throw new Exception("Potential DM allocation by " + this.Name + " exceeds DM Demand. Thats not really possible so something has gone a miss"); // Send potential DM allocation to organs to set this variable for calculating N demand for (int i = 0; i < Organs.Length; i++) { Organs[i].DMPotentialAllocation = new BiomassPoolType { Structural = DM.StructuralAllocation[i], //Need to seperate metabolic and structural allocations Metabolic = DM.MetabolicAllocation[i], //This wont do anything currently NonStructural = DM.NonStructuralAllocation[i], //Nor will this do anything }; } }
/// <summary>Sends the nutrient allocations.</summary> /// <param name="Organs">The organs.</param> /// <exception cref="System.Exception"> /// -ve N Allocation /// or /// N Mass balance violated!!!!. Daily Plant N increment is greater than N supply /// or /// N Mass balance violated!!!! Daily Plant N increment is greater than N demand /// or /// DM Mass Balance violated!!!! Daily Plant Wt increment is greater than Photosynthetic DM supply /// or /// DM Mass Balance violated!!!! Daily Plant Wt increment is greater than the sum of structural DM demand, metabolic DM demand and NonStructural DM capacity /// </exception> public virtual void SendNutrientAllocations(IArbitration[] Organs) { // Send N allocations to all Plant Organs for (int i = 0; i < Organs.Length; i++) { if ((N.StructuralAllocation[i] < -0.00000001) || (N.MetabolicAllocation[i] < -0.00000001) || (N.NonStructuralAllocation[i] < -0.00000001)) throw new Exception("-ve N Allocation"); if (N.StructuralAllocation[i] < 0.0) N.StructuralAllocation[i] = 0.0; if (N.MetabolicAllocation[i] < 0.0) N.MetabolicAllocation[i] = 0.0; if (N.NonStructuralAllocation[i] < 0.0) N.NonStructuralAllocation[i] = 0.0; Organs[i].NAllocation = new BiomassAllocationType { Structural = N.StructuralAllocation[i], //This needs to be seperated into components Metabolic = N.MetabolicAllocation[i], NonStructural = N.NonStructuralAllocation[i], Fixation = N.Fixation[i], Reallocation = N.Reallocation[i], Retranslocation = N.Retranslocation[i], Uptake = N.Uptake[i] }; } //Finally Check Mass balance adds up N.End = 0; for (int i = 0; i < Organs.Length; i++) N.End += Organs[i].N; N.BalanceError = (N.End - (N.Start + N.TotalUptakeSupply + N.TotalFixationSupply)); if (N.BalanceError > 0.000000001) throw new Exception("N Mass balance violated!!!!. Daily Plant N increment is greater than N supply"); N.BalanceError = (N.End - (N.Start + N.TotalPlantDemand)); if (N.BalanceError > 0.000000001) throw new Exception("N Mass balance violated!!!! Daily Plant N increment is greater than N demand"); DM.End = 0; for (int i = 0; i < Organs.Length; i++) DM.End += Organs[i].Wt; DM.BalanceError = (DM.End - (DM.Start + DM.TotalFixationSupply)); if (DM.BalanceError > 0.0001) throw new Exception("DM Mass Balance violated!!!! Daily Plant Wt increment is greater than Photosynthetic DM supply"); DM.BalanceError = (DM.End - (DM.Start + DM.TotalStructuralDemand + DM.TotalMetabolicDemand + DM.TotalNonStructuralDemand)); if (DM.BalanceError > 0.0001) throw new Exception("DM Mass Balance violated!!!! Daily Plant Wt increment is greater than the sum of structural DM demand, metabolic DM demand and NonStructural DM capacity"); }
/// <summary>Sends the dm allocations.</summary> /// <param name="Organs">The organs.</param> public virtual void SendDMAllocations(IArbitration[] Organs) { // Send DM allocations to all Plant Organs for (int i = 0; i < Organs.Length; i++) { Organs[i].DMAllocation = new BiomassAllocationType { Respired = DM.Respiration[i], Reallocation = DM.Reallocation[i], Retranslocation = DM.Retranslocation[i], Structural = DM.StructuralAllocation[i], NonStructural = DM.NonStructuralAllocation[i], Metabolic = DM.MetabolicAllocation[i], }; } }
/// <summary>Does the uptake.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> /// <param name="soilstate">The soilstate.</param> public virtual void DoPotentialNutrientUptake(IArbitration[] Organs, ref BiomassArbitrationType BAT, SoilState soilstate) { // Model can only handle one root zone at present ZoneWaterAndN MyZone = new ZoneWaterAndN(); Zone ParentZone = Apsim.Parent(this, typeof(Zone)) as Zone; foreach (ZoneWaterAndN Z in soilstate.Zones) if (Z.Name == ParentZone.Name) MyZone = Z; PotentialNO3NUptake = new double[MyZone.NO3N.Length]; PotentialNH4NUptake = new double[MyZone.NH4N.Length]; //Get Nuptake supply from each organ and set the PotentialUptake parameters that are passed to the soil arbitrator for (int i = 0; i < Organs.Length; i++) { double[] organNO3Supply = Organs[i].NO3NSupply(soilstate.Zones); if (organNO3Supply != null) { PotentialNO3NUptake = MathUtilities.Add(PotentialNO3NUptake, organNO3Supply); //Add uptake supply from each organ to the plants total to tell the Soil arbitrator BAT.UptakeSupply[i] = MathUtilities.Sum(organNO3Supply) * kgha2gsm; //Populate uptakeSupply for each organ for internal allocation routines } double[] organNH4Supply = Organs[i].NH4NSupply(soilstate.Zones); if (organNH4Supply != null) { PotentialNH4NUptake = MathUtilities.Add(PotentialNH4NUptake, organNH4Supply); BAT.UptakeSupply[i] += MathUtilities.Sum(organNH4Supply) * kgha2gsm; } } //Calculate plant level supply totals. BAT.TotalUptakeSupply = MathUtilities.Sum(BAT.UptakeSupply); BAT.TotalPlantSupply = BAT.TotalReallocationSupply + BAT.TotalUptakeSupply + BAT.TotalFixationSupply + BAT.TotalRetranslocationSupply; //If NUsupply is greater than uptake (total demand - reallocatio nsupply) reduce the PotentialUptakes that we pass to the soil arbitrator if (BAT.TotalUptakeSupply > (BAT.TotalPlantDemand - BAT.TotalReallocation)) { double ratio = Math.Min(1.0, (BAT.TotalPlantDemand - BAT.TotalReallocation) / BAT.TotalUptakeSupply); PotentialNO3NUptake = MathUtilities.Multiply_Value(PotentialNO3NUptake, ratio); PotentialNH4NUptake = MathUtilities.Multiply_Value(PotentialNH4NUptake, ratio); } }
/// <summary>Sends the potential dm allocations.</summary> /// <param name="Organs">The organs.</param> /// <exception cref="System.Exception">Mass Balance Error in Photosynthesis DM Allocation</exception> public virtual void SendPotentialDMAllocations(IArbitration[] Organs) { // Allocate to meet Organs demands DM.TotalStructuralAllocation = MathUtilities.Sum(DM.StructuralAllocation); DM.TotalMetabolicAllocation = MathUtilities.Sum(DM.MetabolicAllocation); DM.TotalNonStructuralAllocation = MathUtilities.Sum(DM.NonStructuralAllocation); DM.Allocated = DM.TotalStructuralAllocation + DM.TotalMetabolicAllocation + DM.TotalNonStructuralAllocation; DM.SinkLimitation = Math.Max(0.0, DM.TotalFixationSupply + DM.TotalRetranslocationSupply + DM.TotalReallocationSupply - DM.Allocated); // Then check it all adds up DM.BalanceError = Math.Abs((DM.Allocated + DM.SinkLimitation) - (DM.TotalFixationSupply + DM.TotalRetranslocationSupply + DM.TotalReallocationSupply)); if (DM.BalanceError > 0.0000001 & DM.TotalStructuralDemand > 0) throw new Exception("Mass Balance Error in Photosynthesis DM Allocation"); // Send potential DM allocation to organs to set this variable for calculating N demand for (int i = 0; i < Organs.Length; i++) { Organs[i].DMPotentialAllocation = new BiomassPoolType { Structural = DM.StructuralAllocation[i], //Need to seperate metabolic and structural allocations Metabolic = DM.MetabolicAllocation[i], //This wont do anything currently NonStructural = DM.NonStructuralAllocation[i], //Nor will this do anything }; } }
/// <summary>Does the uptake.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> /// <param name="Option">The option.</param> public virtual void DoUptake(IArbitration[] Organs, BiomassArbitrationType BAT, ArbitrationType Option) { double BiomassTakenUp = 0; if (BAT.TotalUptakeSupply > 0.00000000001) { // Calculate how much uptake N each demanding organ is allocated based on relative demands if (Option == ArbitrationType.RelativeAllocation) RelativeAllocation(Organs, BAT.TotalUptakeSupply, ref BiomassTakenUp, BAT); if (Option == ArbitrationType.PriorityAllocation) PriorityAllocation(Organs, BAT.TotalUptakeSupply, ref BiomassTakenUp, BAT); if (Option == ArbitrationType.PriorityThenRelativeAllocation) PrioritythenRelativeAllocation(Organs, BAT.TotalUptakeSupply, ref BiomassTakenUp, BAT); if (Option == ArbitrationType.RelativeAllocationSinglePass) RelativeAllocationSinglePass(Organs, BAT.TotalUptakeSupply, ref BiomassTakenUp, BAT); // Then calculate how much N is taken up by each supplying organ based on relative uptake supply for (int i = 0; i < Organs.Length; i++) { if (BAT.UptakeSupply[i] > 0.00000000001) { double RelativeSupply = BAT.UptakeSupply[i] / BAT.TotalUptakeSupply; BAT.Uptake[i] += BiomassTakenUp * RelativeSupply; } } } }
/// <summary>Relatives the allocation.</summary> /// <param name="Organs">The organs.</param> /// <param name="TotalSupply">The total supply.</param> /// <param name="TotalAllocated">The total allocated.</param> /// <param name="BAT">The bat.</param> private void RelativeAllocation(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT) { double NotAllocated = TotalSupply; ////allocate to structural and metabolic Biomass first for (int i = 0; i < Organs.Length; i++) { double StructuralRequirement = Math.Max(0, BAT.StructuralDemand[i] - BAT.StructuralAllocation[i]); //N needed to get to Minimum N conc and satisfy structural and metabolic N demands double MetabolicRequirement = Math.Max(0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]); if ((StructuralRequirement + MetabolicRequirement) > 0.0) { double StructuralFraction = BAT.TotalStructuralDemand / (BAT.TotalStructuralDemand + BAT.TotalMetabolicDemand); double StructuralAllocation = Math.Min(StructuralRequirement, TotalSupply * StructuralFraction * BAT.RelativeStructuralDemand[i]); double MetabolicAllocation = Math.Min(MetabolicRequirement, TotalSupply * (1 - StructuralFraction) * BAT.RelativeMetabolicDemand[i]); BAT.StructuralAllocation[i] += StructuralAllocation; BAT.MetabolicAllocation[i] += MetabolicAllocation; NotAllocated -= (StructuralAllocation + MetabolicAllocation); TotalAllocated += (StructuralAllocation + MetabolicAllocation); } } // Second time round if there is still Biomass to allocate let organs take N up to their Maximum double FirstPassNotAllocated = NotAllocated; for (int i = 0; i < Organs.Length; i++) { double NonStructuralRequirement = Math.Max(0.0, BAT.NonStructuralDemand[i] - BAT.NonStructuralAllocation[i]); //N needed to take organ up to maximum N concentration, Structural, Metabolic and Luxury N demands if (NonStructuralRequirement > 0.0) { double NonStructuralAllocation = Math.Min(FirstPassNotAllocated * BAT.RelativeNonStructuralDemand[i], NonStructuralRequirement); BAT.NonStructuralAllocation[i] += Math.Max(0,NonStructuralAllocation); NotAllocated -= NonStructuralAllocation; TotalAllocated += NonStructuralAllocation; } } //Set the amount of biomass not allocated. Note, that this value is overwritten following by each arbitration step so if it is to be used correctly //it must be caught in that step. Currently only using to catch DM not allocated so we can report as sink limitaiton BAT.NotAllocated = NotAllocated; }
/// <summary>Does the nutrient set up.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> public virtual void DoNutrientSetUp(IArbitration[] Organs, ref BiomassArbitrationType BAT) { //Creat Biomass variable class BAT = new BiomassArbitrationType(Organs.Length); // GET ALL INITIAL STATE VARIABLES FOR MASS BALANCE CHECKS BAT.Start = 0; // GET ALL SUPPLIES AND DEMANDS AND CALCULATE TOTALS for (int i = 0; i < Organs.Length; i++) { BiomassSupplyType Supply = Organs[i].NSupply; BAT.ReallocationSupply[i] = Supply.Reallocation; //BAT.UptakeSupply[i] = Supply.Uptake; This is done on DoNutrientUptakeCalculations BAT.FixationSupply[i] = Supply.Fixation; BAT.RetranslocationSupply[i] = Supply.Retranslocation; BAT.Start += Organs[i].TotalN; } BAT.TotalReallocationSupply = MathUtilities.Sum(BAT.ReallocationSupply); //BAT.TotalUptakeSupply = MathUtilities.Sum(BAT.UptakeSupply); This is done on DoNutrientUptakeCalculations BAT.TotalFixationSupply = MathUtilities.Sum(BAT.FixationSupply); BAT.TotalRetranslocationSupply = MathUtilities.Sum(BAT.RetranslocationSupply); BAT.TotalPlantSupply = BAT.TotalReallocationSupply + BAT.TotalUptakeSupply + BAT.TotalFixationSupply + BAT.TotalRetranslocationSupply; for (int i = 0; i < Organs.Length; i++) { BiomassPoolType Demand = Organs[i].NDemand; BAT.StructuralDemand[i] = Organs[i].NDemand.Structural; BAT.MetabolicDemand[i] = Organs[i].NDemand.Metabolic; BAT.NonStructuralDemand[i] = Organs[i].NDemand.NonStructural; BAT.TotalDemand[i] = BAT.StructuralDemand[i] + BAT.MetabolicDemand[i] + BAT.NonStructuralDemand[i]; BAT.Reallocation[i] = 0; BAT.Uptake[i] = 0; BAT.Fixation[i] = 0; BAT.Retranslocation[i] = 0; BAT.StructuralAllocation[i] = 0; BAT.MetabolicAllocation[i] = 0; BAT.NonStructuralAllocation[i] = 0; } BAT.TotalStructuralDemand = MathUtilities.Sum(BAT.StructuralDemand); BAT.TotalMetabolicDemand = MathUtilities.Sum(BAT.MetabolicDemand); BAT.TotalNonStructuralDemand = MathUtilities.Sum(BAT.NonStructuralDemand); BAT.TotalPlantDemand = BAT.TotalStructuralDemand + BAT.TotalMetabolicDemand + BAT.TotalNonStructuralDemand; BAT.TotalStructuralAllocation = 0; BAT.TotalMetabolicAllocation = 0; BAT.TotalNonStructuralAllocation = 0; //Set relative N demands of each organ for (int i = 0; i < Organs.Length; i++) { if (BAT.TotalStructuralDemand > 0) BAT.RelativeStructuralDemand[i] = BAT.StructuralDemand[i] / BAT.TotalStructuralDemand; if (BAT.TotalMetabolicDemand > 0) BAT.RelativeMetabolicDemand[i] = BAT.MetabolicDemand[i] / BAT.TotalMetabolicDemand; if (BAT.TotalNonStructuralDemand > 0) BAT.RelativeNonStructuralDemand[i] = BAT.NonStructuralDemand[i] / BAT.TotalNonStructuralDemand; } }