/// <summary>Does the re allocation.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> /// <param name="arbitrator">The arbitrator.</param> virtual public void DoReAllocation(IArbitration[] Organs, BiomassArbitrationType BAT, IArbitrationMethod arbitrator) { double BiomassReallocated = 0; if (BAT.TotalReallocationSupply > 0.00000000001) { arbitrator.DoAllocation(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>Relatives the allocation.</summary> /// <param name="Organs">The organs.</param> /// <param name="N">The N bat.</param> /// <param name="dm">The DM BAT.</param> public void DoRetranslocation(IArbitration[] Organs, BiomassArbitrationType N, BiomassArbitrationType dm) { double NotAllocated = N.TotalRetranslocationSupply; //var rootIndex = 1; var leafIndex = 2; var rachisIndex = 3; var stemIndex = 4; var grainIndex = 0; var stemDemand = N.StructuralDemand[stemIndex]; var rachisDemand = N.StructuralDemand[rachisIndex]; var leafDemand = N.StructuralDemand[leafIndex]; var forStem = AllocateStructuralFromLeaf(Organs[leafIndex] as SorghumLeaf, leafIndex, stemIndex, N); var forRachis = AllocateStructuralFromLeaf(Organs[leafIndex] as SorghumLeaf, leafIndex, rachisIndex, N); var forLeaffromStem = AllocateStructuralFromStem(stemIndex, leafIndex, N, dm, Organs[stemIndex] as GenericOrgan); var forLeaf = AllocateStructuralFromLeaf(Organs[leafIndex] as SorghumLeaf, leafIndex, leafIndex, N); double fromRachis = AllocateStructuralFromRachis(rachisIndex, grainIndex, N, dm, Organs[rachisIndex] as GenericOrgan); double fromStem = AllocateStructuralFromStem(stemIndex, grainIndex, N, dm, Organs[stemIndex] as GenericOrgan); double fromLeaf = AllocateStructuralFromLeaf(Organs[leafIndex] as SorghumLeaf, leafIndex, grainIndex, N); }
/// <summary>Relatives the allocation.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> public void DoRetranslocation(IArbitration[] Organs, BiomassArbitrationType BAT) { double NotAllocated = BAT.TotalRetranslocationSupply; //var rootIndex = 1; var leafIndex = 2; var rachisIndex = 3; var stemIndex = 4; var grainIndex = 0; var stemDemand = BAT.StructuralDemand[stemIndex]; var rachisDemand = BAT.StructuralDemand[rachisIndex]; var leafDemand = BAT.StructuralDemand[leafIndex]; var forStem = AllocateStructuralFromLeaf(Organs[leafIndex] as SorghumLeaf, leafIndex, stemIndex, BAT); var forRachis = AllocateStructuralFromLeaf(Organs[leafIndex] as SorghumLeaf, leafIndex, rachisIndex, BAT); var forLeaffromStem = AllocateStructuralFromOrgan(stemIndex, leafIndex, BAT); var forLeaf = AllocateStructuralFromLeaf(Organs[leafIndex] as SorghumLeaf, leafIndex, leafIndex, BAT); AllocateStructuralFromOrgan(rachisIndex, grainIndex, BAT); AllocateStructuralFromOrgan(stemIndex, grainIndex, BAT); AllocateStructuralFromLeaf(Organs[leafIndex] as SorghumLeaf, leafIndex, grainIndex, BAT); }
private void AllocateMetabolic(int i, double allocation, BiomassArbitrationType BAT) { double MetabolicRequirement = Math.Max(0.0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]); if (MathUtilities.IsPositive(allocation)) { //double MetabolicAllocation = Math.Max(0.0, NotAllocated * MathUtilities.Divide(BAT.MetabolicDemand[i], nTotalDemand, 0)); //double Allocation = Math.Max(0.0, allocatation * MathUtilities.Divide(organDemand, nTotalDemand, 0)); double MetabolicAllocation = Math.Min(MetabolicRequirement, allocation); //to stop it from givig it too much metabolic - push the flowover from metabolic into storage BAT.MetabolicAllocation[i] += MetabolicAllocation; //do storage if there is any leftover double storageAllocation = allocation - MetabolicAllocation; BAT.StorageAllocation[i] += storageAllocation; if (storageAllocation > BAT.StorageDemand[i]) { BAT.StorageDemand[i] += storageAllocation; } } }
virtual protected void OnPlantSowing(object sender, SowPlant2Type data) { List <IArbitration> organsToArbitrate = new List <IArbitration>(); List <IHasWaterDemand> Waterdemands = new List <IHasWaterDemand>(); foreach (Model Can in Apsim.FindAll(Plant, typeof(IHasWaterDemand))) { Waterdemands.Add(Can as IHasWaterDemand); } foreach (IOrgan organ in Plant.Organs) { if (organ is IArbitration) { organsToArbitrate.Add(organ as IArbitration); } } Organs = organsToArbitrate; WaterDemands = Waterdemands; DM = new BiomassArbitrationType("DM", Organs); N = new BiomassArbitrationType("N", Organs); }
private void AllocateStorage(int i, ref double TotalAllocated, ref double NotAllocated, BiomassArbitrationType BAT) { double StorageRequirement = Math.Max(0.0, BAT.StorageDemand[i] - BAT.StorageAllocation[i]); //N needed to take organ up to maximum N concentration, Structural, Metabolic and Luxury N demands if (StorageRequirement > 0.0) { double StorageAllocation = Math.Min(NotAllocated * MathUtilities.Divide(BAT.StorageDemand[i], BAT.TotalStorageDemand, 0), StorageRequirement); BAT.StorageAllocation[i] += Math.Max(0, StorageAllocation); NotAllocated -= StorageAllocation; TotalAllocated += StorageAllocation; } }
private void AllocateStructural(int i, ref double TotalAllocated, ref double NotAllocated, BiomassArbitrationType BAT) { 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 if ((StructuralRequirement) > 0.0) { double StructuralAllocation = Math.Min(StructuralRequirement, NotAllocated); BAT.StructuralAllocation[i] += StructuralAllocation; NotAllocated -= (StructuralAllocation); TotalAllocated += (StructuralAllocation); } }
/// <summary>Clears this instance.</summary> public void Clear() { DM = new BiomassArbitrationType(); N = new BiomassArbitrationType(); }
/// <summary>Functions called at DoAllocations.</summary> public void DoAllocations(IArbitration[] Organs, BiomassArbitrationType DM) { allocationMethods.ForEach(pm => pm.Allocate(Organs, DM)); }
/// <summary>Does the fixation.</summary> /// <param name="Organs">The organs.</param> /// <param name="BAT">The bat.</param> /// <param name="arbitrator">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> override public void AllocateFixation(IArbitration[] Organs, BiomassArbitrationType BAT, IArbitrationMethod arbitrator) { double BiomassFixed = 0; if (BAT.TotalFixationSupply > 0.00000000001) { arbitrator.DoAllocation(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 StorageDM allocation to cover the cost double UnallocatedRespirationCost = DM.TotalRespiration - DM.SinkLimitation; if (MathUtilities.IsGreaterThan(DM.TotalStorageAllocation, 0)) { double Costmet = 0; for (int i = 0; i < Organs.Length; i++) { double proportion = DM.StorageAllocation[i] / DM.TotalStorageAllocation; double Clawback = Math.Min(UnallocatedRespirationCost * proportion, DM.StorageAllocation[i]); DM.StorageAllocation[i] -= Clawback; Costmet += Clawback; } UnallocatedRespirationCost -= Costmet; } if (UnallocatedRespirationCost == 0) { } //All cost accounted for else {//Remobilise more Non-structural DM to cover the cost if (DM.TotalRetranslocationSupply > 0) { double Costmet = 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; Costmet += DMRetranslocated; } UnallocatedRespirationCost -= Costmet; } 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>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> public void DoAllocation(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT) { double NotAllocated = TotalSupply; // / 0.1; //g/m^2 //allocate structural first - will be a different order to biomass so need to hard code the order until an interface is created //roots //stem //rachis //leaf //then allocate metabolic relative to demand var grainIndex = 0; var rootIndex = 1; var leafIndex = 2; var rachisIndex = 3; var stemIndex = 4; var grainDemand = BAT.StructuralDemand[grainIndex] + BAT.MetabolicDemand[grainIndex]; var rootDemand = BAT.StructuralDemand[rootIndex] + BAT.MetabolicDemand[rootIndex]; var stemDemand = BAT.StructuralDemand[stemIndex] + BAT.MetabolicDemand[stemIndex]; var rachisDemand = BAT.StructuralDemand[rachisIndex] + BAT.MetabolicDemand[rachisIndex]; var leafMetabolicDemand = BAT.MetabolicDemand[leafIndex]; var leafStructuralDemand = BAT.StructuralDemand[leafIndex]; //calc leaf demand separately - old sorghum doesn't quite fit var leaf = Organs[leafIndex] as SorghumLeaf; var leafAdjustment = leaf.calculateClassicDemandDelta(); var totalPlantNDemand = BAT.TotalPlantDemand + leafAdjustment - grainDemand; // to replicate calcNDemand in old sorghum if (totalPlantNDemand > 0.0) { BAT.SupplyDemandRatioN = Math.Min((BAT.TotalUptakeSupply) / totalPlantNDemand, 1.0); } double rootAllocation = BAT.SupplyDemandRatioN * BAT.StructuralDemand[rootIndex]; BAT.StructuralAllocation[rootIndex] += rootAllocation; NotAllocated -= (rootAllocation); TotalAllocated += (rootAllocation); AllocateStructural(stemIndex, ref TotalAllocated, ref NotAllocated, BAT); AllocateStructural(rachisIndex, ref TotalAllocated, ref NotAllocated, BAT); AllocateStructural(leafIndex, ref TotalAllocated, ref NotAllocated, BAT); var nDemand = totalPlantNDemand - rootDemand; var leafAlloc = CalcPoportionalAllocation(NotAllocated, BAT.MetabolicDemand[leafIndex], nDemand); AllocateMetabolic(leafIndex, leafAlloc, BAT); var rachisAlloc = NotAllocated * MathUtilities.Divide(BAT.StructuralDemand[rachisIndex] + BAT.MetabolicDemand[rachisIndex], nDemand, 0.0); AllocateMetabolic(rachisIndex, rachisAlloc, BAT); var stemAlloc = NotAllocated * MathUtilities.Divide(BAT.StructuralDemand[stemIndex] + BAT.MetabolicDemand[stemIndex], nDemand, 0.0); AllocateMetabolic(stemIndex, stemAlloc, BAT); if (!MathUtilities.FloatsAreEqual(leafAlloc + rachisAlloc + stemAlloc, NotAllocated)) { //this is to check that nDemand is equal to old sorghum N demand calc throw new Exception("Proportional allocation of Metabolic N doesn't balance"); } TotalAllocated += NotAllocated; }
/// <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> public void DoAllocation(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 StorageRequirement = Math.Max(0, BAT.StorageDemand[i] - BAT.StorageAllocation[i]); if ((StructuralRequirement + MetabolicRequirement + StorageRequirement) > 0.0) { double StructuralAllocation = Math.Min(StructuralRequirement, TotalSupply * MathUtilities.Divide(BAT.StructuralDemand[i], BAT.TotalPlantDemand, 0)); double MetabolicAllocation = Math.Min(MetabolicRequirement, TotalSupply * MathUtilities.Divide(BAT.MetabolicDemand[i], BAT.TotalPlantDemand, 0)); double StorageAllocation = Math.Min(StorageRequirement, TotalSupply * MathUtilities.Divide(BAT.StorageDemand[i], BAT.TotalPlantDemand, 0)); BAT.StructuralAllocation[i] += StructuralAllocation; BAT.MetabolicAllocation[i] += MetabolicAllocation; BAT.StorageAllocation[i] += StorageAllocation; NotAllocated -= (StructuralAllocation + MetabolicAllocation + StorageAllocation); TotalAllocated += (StructuralAllocation + MetabolicAllocation + StorageAllocation); } } }
/// <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> public void DoAllocation(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 StorageRequirement = Math.Max(0.0, BAT.StorageDemand[i] - BAT.StorageAllocation[i]); //N needed to take organ up to maximum N concentration, Structural, Metabolic and Luxury N demands if (StorageRequirement > 0.0) { double StorageAllocation = Math.Min(FirstPassNotallocated * MathUtilities.Divide(BAT.StorageDemand[i], BAT.TotalStorageDemand, 0), StorageRequirement); BAT.StorageAllocation[i] += Math.Max(0, StorageAllocation); NotAllocated -= StorageAllocation; TotalAllocated += StorageAllocation; } } }
/// <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> public void DoAllocation(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT) { double NotAllocated = TotalSupply; // Save Totals for use inside the for loops below double totalStructuralDemand = BAT.TotalStructuralDemand; double totalMetabolicDemand = BAT.TotalMetabolicDemand; double totalStorageDemand = BAT.TotalStorageDemand; ////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 = totalStructuralDemand / (totalStructuralDemand + totalMetabolicDemand); double StructuralAllocation = Math.Min(StructuralRequirement, TotalSupply * StructuralFraction * MathUtilities.Divide(BAT.StructuralDemand[i], totalStructuralDemand, 0)); double MetabolicAllocation = Math.Min(MetabolicRequirement, TotalSupply * (1 - StructuralFraction) * MathUtilities.Divide(BAT.MetabolicDemand[i], totalMetabolicDemand, 0)); 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 StorageRequirement = Math.Max(0.0, BAT.StorageDemand[i] - BAT.StorageAllocation[i]); //N needed to take organ up to maximum N concentration, Structural, Metabolic and Luxury N demands if (StorageRequirement > 0.0) { double StorageAllocation = Math.Min(FirstPassNotAllocated * MathUtilities.Divide(BAT.StorageDemand[i], totalStorageDemand, 0), StorageRequirement); BAT.StorageAllocation[i] += Math.Max(0, StorageAllocation); NotAllocated -= StorageAllocation; TotalAllocated += StorageAllocation; } } //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>Clears this instance.</summary> private void Clear() { string[] organNames = new string[0]; DM = new BiomassArbitrationType("DM", Organs); N = new BiomassArbitrationType("N", Organs); }
/// <summary>Relatives the allocation.</summary> /// <param name="leaf">The organs.</param> /// <param name="iSupply">The organs.</param> /// <param name="iSink">The organs.</param> /// <param name="BAT">The organs.</param> public double AllocateStructuralFromLeaf(SorghumLeaf leaf, int iSupply, int iSink, BiomassArbitrationType BAT) { //leaf called double StructuralRequirement = Math.Max(0.0, BAT.StructuralDemand[iSink] - BAT.StructuralAllocation[iSink]); if ((StructuralRequirement) > 0.0) { double currentRetranslocatedN = leaf.DltRetranslocatedN; //-ve number double providedN = leaf.provideNRetranslocation(BAT, StructuralRequirement); BAT.StructuralAllocation[iSink] += providedN; double afterRetranslocatedN = leaf.DltRetranslocatedN; //Leaf keeps track of retranslocation - the return value can include DltLAI which is not techncally retraslocated //Let leaf handle the updating BAT.Retranslocation[iSupply] += Math.Abs(afterRetranslocatedN - currentRetranslocatedN); return(providedN); } return(0.0); }
/// <summary>Relatives the allocation.</summary> /// <param name="iSupply">The organs.</param> /// <param name="iSink">The organs.</param> /// <param name="n">The organs.</param> /// <param name="dm">The dm BAT.</param> /// <param name="source">The organ which N will be taken from.</param> public double AllocateStructuralFromRachis(int iSupply, int iSink, BiomassArbitrationType n, BiomassArbitrationType dm, GenericOrgan source) { double StructuralRequirement = Math.Max(0.0, n.StructuralDemand[iSink] - n.StructuralAllocation[iSink]); if (MathUtilities.IsPositive(StructuralRequirement)) { //only allocate as much structural as demanded - cyclical process so allow for any amounts already allocated to Retranslocation double StructuralAllocation = Math.Min(StructuralRequirement, n.RetranslocationSupply[iSupply] - n.Retranslocation[iSupply]); double dmGreen = source.Live.Wt; double dltDmGreen = dm.StructuralAllocation[iSupply] + dm.MetabolicAllocation[iSupply]; double dltNGreen = n.StructuralAllocation[iSupply] + n.MetabolicAllocation[iSupply]; double nConc = MathUtilities.Divide(source.Live.N, dmGreen + dltDmGreen, 0); // dh - no point multiplying both numbers by 100 as we do in old apsim. if (nConc < source.MinNconc) { return(0); } n.StructuralAllocation[iSink] += StructuralAllocation; n.Retranslocation[iSupply] += StructuralAllocation; return(StructuralAllocation); } return(0.0); }
/// <summary>Clears this instance.</summary> virtual protected void Clear() { DM = new BiomassArbitrationType("DM", Organs); N = new BiomassArbitrationType("N", Organs); }
/// <summary>Relatives the allocation.</summary> /// <param name="iSupply">The organs.</param> /// <param name="iSink">The organs.</param> /// <param name="n">The organs.</param> /// <param name="dm">The dm BAT.</param> /// <param name="source">The organ which N will be taken from.</param> public double AllocateStructuralFromStem(int iSupply, int iSink, BiomassArbitrationType n, BiomassArbitrationType dm, GenericOrgan source) { double StructuralRequirement = Math.Max(0.0, n.StructuralDemand[iSink] - n.StructuralAllocation[iSink]); if (MathUtilities.IsPositive(StructuralRequirement)) { //only allocate as much structural as demanded - cyclical process so allow for any amounts already allocated to Retranslocation double nAvailable = Math.Min(StructuralRequirement, n.RetranslocationSupply[iSupply] - n.Retranslocation[iSupply]); double nProvided = 0; double dmGreen = source.Live.Wt; double dltDmGreen = dm.StructuralAllocation[iSupply] + dm.MetabolicAllocation[iSupply]; double dltNGreen = n.StructuralAllocation[iSupply] + n.MetabolicAllocation[iSupply] + n.StorageAllocation[iSupply]; if (dltNGreen > StructuralRequirement) { n.StructuralAllocation[iSink] += StructuralRequirement; n.Retranslocation[iSupply] += StructuralRequirement; return(StructuralRequirement); } else { StructuralRequirement -= dltNGreen; nProvided = dltNGreen; } // dh - no point multiplying both numbers by 100 as we do in old apsim. double nConc = MathUtilities.Divide(source.Live.N, dmGreen + dltDmGreen, 0); if (nConc < source.CritNconc) { return(0); } double availableN = n.RetranslocationSupply[iSupply] - n.Retranslocation[iSupply]; // cannot take below structural N double structN = (dmGreen + dltDmGreen) * source.CritNconc; nAvailable = Math.Min(nAvailable, source.Live.N - structN); nAvailable = Math.Max(nAvailable, 0); nProvided += Math.Min(StructuralRequirement, nAvailable); n.StructuralAllocation[iSink] += nProvided; n.Retranslocation[iSupply] += nProvided; return(nProvided); } return(0.0); }
/// <summary>Functions called at DoActualPartitioning.</summary> public void DoActualPartitioning(IArbitration[] Organs, BiomassArbitrationType DM) { actualPartitioningMethods.ForEach(pm => pm.Calculate(Organs, DM, ArbitrationMethod)); }
/// <summary>Relatives the allocation.</summary> /// <param name="leaf">The organs.</param> /// <param name="iSupply">The organs.</param> /// <param name="iSink">The organs.</param> /// <param name="BAT">The organs.</param> public double AllocateStructuralFromLeaf(SorghumLeaf leaf, int iSupply, int iSink, BiomassArbitrationType BAT) { double StructuralRequirement = Math.Max(0.0, BAT.StructuralDemand[iSink] - BAT.StructuralAllocation[iSink]); if (MathUtilities.IsPositive(StructuralRequirement)) { bool forLeaf = iSupply == iSink; double providedN = leaf.provideNRetranslocation(BAT, StructuralRequirement, forLeaf); BAT.StructuralAllocation[iSink] += providedN; // Leaf's dltRetranslocatedN is negative (as in old apsim). BAT.Retranslocation[iSupply] = Math.Abs(leaf.DltRetranslocatedN); return(providedN); } return(0.0); }
/// <summary>Functions called at DoUptakes.</summary> public void DoUptakes(IArbitration[] Organs, BiomassArbitrationType DM) { AllocateUptakesMethod.Calculate(Organs, DM, ArbitrationMethod); }
/// <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> public void DoAllocation(IArbitration[] Organs, double TotalSupply, ref double TotalAllocated, BiomassArbitrationType BAT) { double NotAllocated = TotalSupply; // / 0.1; //g/m^2 NSupply = TotalSupply; // reporting variable //allocate structural first - will be a different order to biomass so need to hard code the order until an interface is created //roots //stem //rachis //leaf //then allocate metabolic relative to demand var grainIndex = 0; var rootIndex = 1; var leafIndex = 2; var rachisIndex = 3; var stemIndex = 4; var grainDemand = BAT.StructuralDemand[grainIndex] + BAT.MetabolicDemand[grainIndex]; var rootDemand = BAT.StructuralDemand[rootIndex] + BAT.MetabolicDemand[rootIndex]; //var stemDemand = BAT.StructuralDemand[stemIndex] + BAT.MetabolicDemand[stemIndex]; //var rachisDemand = BAT.StructuralDemand[rachisIndex] + BAT.MetabolicDemand[rachisIndex]; //var leafMetabolicDemand = BAT.MetabolicDemand[leafIndex]; //var leafStructuralDemand = BAT.StructuralDemand[leafIndex]; //calc leaf demand separately - old sorghum doesn't quite fit var leaf = Organs[leafIndex] as SorghumLeaf; var leafAdjustment = leaf.calculateClassicDemandDelta(); //var totalPlantNDemand = BAT.TotalPlantDemand + leafAdjustment - grainDemand; // to replicate calcNDemand in old sorghum // dh - Old apsim calls organ->calcNDemand() to get demands. This is equivalent to metabolic NDemand in new apsim. // Root and grain had no separation of structural/metabolic N in old apsim. New apsim is similar, except it's all in // structural demand, so we need to remember to take that into account as well. double totalDemand = BAT.TotalMetabolicDemand + BAT.StructuralDemand[rootIndex] + BAT.StructuralDemand[grainIndex]; double plantNDemand = Math.Max(0, totalDemand - grainDemand); // to replicate calcNDemand in old sorghum if (MathUtilities.IsPositive(plantNDemand)) { BAT.SupplyDemandRatioN = MathUtilities.Divide(BAT.TotalUptakeSupply, plantNDemand, 0); BAT.SupplyDemandRatioN = Math.Min(BAT.SupplyDemandRatioN, 1); // BAT.SupplyDemandRatioN = Math.Max(BAT.SupplyDemandRatioN, 0); // ? } // todo - what if root demand exceeds supply? double rootAllocation = BAT.SupplyDemandRatioN * BAT.StructuralDemand[rootIndex]; rootAllocation = Math.Min(rootAllocation, NotAllocated); BAT.StructuralAllocation[rootIndex] += rootAllocation; NotAllocated -= (rootAllocation); TotalAllocated += (rootAllocation); AllocateStructural(stemIndex, ref TotalAllocated, ref NotAllocated, BAT); AllocateStructural(rachisIndex, ref TotalAllocated, ref NotAllocated, BAT); AllocateStructural(leafIndex, ref TotalAllocated, ref NotAllocated, BAT); // Structural allocation is subtracted from metabolic demand in old apsim. BAT.MetabolicDemand[leafIndex] = Math.Max(0, BAT.MetabolicDemand[leafIndex] - BAT.StructuralAllocation[leafIndex]); BAT.MetabolicDemand[rachisIndex] = Math.Max(0, BAT.MetabolicDemand[rachisIndex] - BAT.StructuralAllocation[rachisIndex]); BAT.MetabolicDemand[stemIndex] = Math.Max(0, BAT.MetabolicDemand[stemIndex] - BAT.StructuralAllocation[stemIndex]); double leafDemand = BAT.MetabolicDemand[leafIndex]; double rachisDemand = BAT.MetabolicDemand[rachisIndex]; double stemDemand = BAT.MetabolicDemand[stemIndex]; double totalMetabolicDemand = leafDemand + rachisDemand + stemDemand; double leafProportion = MathUtilities.Bound(MathUtilities.Divide(leafDemand, totalMetabolicDemand, 0), 0, 1); double rachisProportion = MathUtilities.Bound(MathUtilities.Divide(rachisDemand, totalMetabolicDemand, 0), 0, 1); double stemProportion = MathUtilities.Bound(MathUtilities.Divide(stemDemand, totalMetabolicDemand, 0), 0, 1); double leafAlloc = NotAllocated * leafProportion; leafAlloc = Math.Min(leafAlloc, leafDemand); double rachisAlloc = NotAllocated * rachisProportion; rachisAlloc = Math.Min(rachisAlloc, rachisDemand); double stemAlloc = NotAllocated - leafAlloc - rachisAlloc; AllocateMetabolic(leafIndex, leafAlloc, BAT); AllocateMetabolic(rachisIndex, rachisAlloc, BAT); AllocateMetabolic(stemIndex, stemAlloc, BAT); if (!MathUtilities.FloatsAreEqual(leafAlloc + rachisAlloc + stemAlloc, NotAllocated, 0.0001)) { //this is to check that nDemand is equal to old sorghum N demand calc throw new Exception("Proportional allocation of Metabolic N doesn't balance"); } TotalAllocated += NotAllocated; }
/// <summary>Clears this instance.</summary> virtual protected void Clear() { string[] organNames = new string[0]; DM = new BiomassArbitrationType("DM", Organs); N = new BiomassArbitrationType("N", Organs); }
/// <summary>Relatives the allocation.</summary> /// <param name="Organs">The organs.</param> /// <param name="TypeSupply">The biomass supply for the current supply type.</param> /// <param name="TotalAllocated">The total allocated.</param> /// <param name="BAT">The bat.</param> public void DoAllocation(IArbitration[] Organs, double TypeSupply, ref double TotalAllocated, BiomassArbitrationType BAT) { BiomassPoolType[] PriorityScalledDemands = new BiomassPoolType[Organs.Length]; double TotalPlantPriorityScalledDemand = 0; for (int i = 0; i < Organs.Length; i++) { PriorityScalledDemands[i] = new BiomassPoolType(); PriorityScalledDemands[i].Structural = BAT.StructuralDemand[i] * BAT.QStructural[i]; PriorityScalledDemands[i].Metabolic = BAT.MetabolicDemand[i] * BAT.QMetabolic[i]; PriorityScalledDemands[i].Storage = BAT.StorageDemand[i] * BAT.QStorage[i]; TotalPlantPriorityScalledDemand += PriorityScalledDemands[i].Total; } double NotAllocated = TypeSupply; ////First time round allocate with priority factors applied so higher priority sinks get more allocation for (int i = 0; i < Organs.Length; i++) { double StructuralRequirement = Math.Max(0, BAT.StructuralDemand[i] - BAT.StructuralAllocation[i]); double MetabolicRequirement = Math.Max(0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]); double StorageRequirement = Math.Max(0, BAT.StorageDemand[i] - BAT.StorageAllocation[i]); if ((StructuralRequirement + MetabolicRequirement + StorageRequirement) > 0.0) { double StructuralAllocation = Math.Min(StructuralRequirement, TypeSupply * MathUtilities.Divide(PriorityScalledDemands[i].Structural, TotalPlantPriorityScalledDemand, 0)); double MetabolicAllocation = Math.Min(MetabolicRequirement, TypeSupply * MathUtilities.Divide(PriorityScalledDemands[i].Metabolic, TotalPlantPriorityScalledDemand, 0)); double StorageAllocation = Math.Min(StorageRequirement, TypeSupply * MathUtilities.Divide(PriorityScalledDemands[i].Storage, TotalPlantPriorityScalledDemand, 0)); BAT.StructuralAllocation[i] += StructuralAllocation; BAT.MetabolicAllocation[i] += MetabolicAllocation; BAT.StorageAllocation[i] += StorageAllocation; NotAllocated -= (StructuralAllocation + MetabolicAllocation + StorageAllocation); TotalAllocated += (StructuralAllocation + MetabolicAllocation + StorageAllocation); } } double FirstPassNotallocated = NotAllocated; double RemainingDemand = BAT.TotalPlantDemand - BAT.TotalPlantAllocation; // Second time round if there is still biomass to allocate do it based on relative demands so lower priority organs have the change to be allocated full demand for (int i = 0; i < Organs.Length; i++) { double StructuralRequirement = Math.Max(0, BAT.StructuralDemand[i] - BAT.StructuralAllocation[i]); double MetabolicRequirement = Math.Max(0, BAT.MetabolicDemand[i] - BAT.MetabolicAllocation[i]); double StorageRequirement = Math.Max(0, BAT.StorageDemand[i] - BAT.StorageAllocation[i]); if ((StructuralRequirement + MetabolicRequirement + StorageRequirement) > 0.0) { double StructuralAllocation = Math.Min(StructuralRequirement, FirstPassNotallocated * MathUtilities.Divide(StructuralRequirement, RemainingDemand, 0)); double MetabolicAllocation = Math.Min(MetabolicRequirement, FirstPassNotallocated * MathUtilities.Divide(MetabolicRequirement, RemainingDemand, 0)); double StorageAllocation = Math.Min(StorageRequirement, FirstPassNotallocated * MathUtilities.Divide(StorageRequirement, RemainingDemand, 0)); BAT.StructuralAllocation[i] += StructuralAllocation; BAT.MetabolicAllocation[i] += MetabolicAllocation; BAT.StorageAllocation[i] += StorageAllocation; NotAllocated -= (StructuralAllocation + MetabolicAllocation + StorageAllocation); TotalAllocated += (StructuralAllocation + MetabolicAllocation + StorageAllocation); } } }