/// <summary> /// General soil arbitration method (water or nutrients) based upon Runge-Kutta method /// </summary> /// <param name="arbitrationType">Water or Nitrogen</param> private void DoArbitration(Estimate.CalcType arbitrationType) { SoilState InitialSoilState = new SoilState(this.Parent); InitialSoilState.Initialise(); Estimate UptakeEstimate1 = new Estimate(this.Parent, arbitrationType, InitialSoilState); Estimate UptakeEstimate2 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate1 * 0.5); Estimate UptakeEstimate3 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate2 * 0.5); Estimate UptakeEstimate4 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate3); List<CropUptakes> UptakesFinal = new List<CropUptakes>(); foreach (CropUptakes U in UptakeEstimate1.Values) { CropUptakes CWU = new CropUptakes(); CWU.Crop = U.Crop; foreach (ZoneWaterAndN ZW1 in U.Zones) { ZoneWaterAndN NewZ = UptakeEstimate1.UptakeZone(CWU.Crop, ZW1.Name) * (1.0 / 6.0) + UptakeEstimate2.UptakeZone(CWU.Crop, ZW1.Name) * (1.0 / 3.0) + UptakeEstimate3.UptakeZone(CWU.Crop, ZW1.Name) * (1.0 / 3.0) + UptakeEstimate4.UptakeZone(CWU.Crop, ZW1.Name) * (1.0 / 6.0); CWU.Zones.Add(NewZ); } UptakesFinal.Add(CWU); } foreach (CropUptakes Uptake in UptakesFinal) { if (arbitrationType == Estimate.CalcType.Water) Uptake.Crop.SetSWUptake(Uptake.Zones); else Uptake.Crop.SetNUptake(Uptake.Zones); } }
/// <summary>Initializes a new instance of the <see cref="Estimate"/> class.</summary> /// <param name="parent">The parent model</param> /// <param name="Type">The type of estimate</param> /// <param name="soilstate">The state of the soil</param> /// <param name="uptakeModels">A list of models that do uptake.</param> public Estimate(IModel parent, CalcType Type, SoilState soilstate, List<IModel> uptakeModels) { Values = new List<CropUptakes>(); Parent = parent; foreach (IUptake crop in uptakeModels) { List<ZoneWaterAndN> uptake; if (Type == CalcType.Water) uptake = crop.GetSWUptakes(soilstate); else uptake = crop.GetNUptakes(soilstate); if (uptake != null) { CropUptakes Uptake = new CropUptakes(); Uptake.Crop = crop; Uptake.Zones = uptake; Values.Add(Uptake); } } }
/// <summary>Implements the operator -.</summary> /// <param name="state">The soil state.</param> /// <param name="estimate">The estimate to subtract from the soil state.</param> /// <returns>The result of the operator.</returns> public static SoilState operator -(SoilState state, Estimate estimate) { SoilState NewState = new SoilState(state.Parent); foreach (ZoneWaterAndN Z in state.Zones) { ZoneWaterAndN NewZ = new ZoneWaterAndN(); NewZ.Name = Z.Name; NewZ.Water = Z.Water; NewZ.NO3N = Z.NO3N; NewZ.NH4N = Z.NH4N; NewState.Zones.Add(NewZ); } foreach (CropUptakes C in estimate.Values) foreach (ZoneWaterAndN Z in C.Zones) foreach (ZoneWaterAndN NewZ in NewState.Zones) if (Z.Name == NewZ.Name) { NewZ.Water = MathUtilities.Subtract(NewZ.Water, Z.Water); NewZ.NO3N = MathUtilities.Subtract(NewZ.NO3N, Z.NO3N); NewZ.NH4N = MathUtilities.Subtract(NewZ.NH4N, Z.NH4N); } return NewState; }
/// <summary> /// Calculate the potential sw uptake for today. Should return null if crop is not in the ground. /// </summary> public List<Soils.Arbitrator.ZoneWaterAndN> GetNUptakes(SoilState soilstate) { if (Plant.IsAlive) { foreach (ZoneWaterAndN zone in soilstate.Zones) { ZoneWaterAndN UptakeDemands = new ZoneWaterAndN(); if (Plant.Phenology != null) { if (Plant.Phenology.Emerged == true) { DoPotentialNutrientUptake(ref N, zone); //Work out how much N the uptaking organs (roots) would take up in the absence of competition //Pack results into uptake structure UptakeDemands.NO3N = PotentialNO3NUptake; UptakeDemands.NH4N = PotentialNH4NUptake; } else //Uptakes are zero { UptakeDemands.NO3N = new double[zone.NO3N.Length]; for (int i = 0; i < UptakeDemands.NO3N.Length; i++) { UptakeDemands.NO3N[i] = 0; } UptakeDemands.NH4N = new double[zone.NH4N.Length]; for (int i = 0; i < UptakeDemands.NH4N.Length; i++) { UptakeDemands.NH4N[i] = 0; } } } else { DoPotentialNutrientUptake(ref N, zone); //Work out how much N the uptaking organs (roots) would take up in the absence of competition //Pack results into uptake structure UptakeDemands.NO3N = PotentialNO3NUptake; UptakeDemands.NH4N = PotentialNH4NUptake; } UptakeDemands.Name = zone.Name; UptakeDemands.Water = new double[UptakeDemands.NO3N.Length]; List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>(); zones.Add(UptakeDemands); return zones; } } return null; }
/// <summary>Placeholder for SoilArbitrator</summary> /// <param name="soilstate">Soil state</param> /// <returns></returns> public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate) { if (IsAlive) { List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>(); ZoneWaterAndN Uptake = new ZoneWaterAndN(); ZoneWaterAndN MyZone = new ZoneWaterAndN(); foreach (ZoneWaterAndN Z in soilstate.Zones) if (Z.Name == this.Parent.Name) MyZone = Z; double[] SW = MyZone.Water; OnPrepare(null, null); //DEAN!!! Uptake.Name = this.Parent.Name; Uptake.Water = Root.CalculateWaterUptake(TopsSWDemand, SW); Uptake.NO3N = new double[SW.Length]; Uptake.NH4N = new double[SW.Length]; Uptakes.Add(Uptake); return Uptakes; } else return null; }
/// <summary>Placeholder for SoilArbitrator</summary> /// <param name="soilstate">soil state</param> /// <returns></returns> public List<ZoneWaterAndN> GetNUptakes(SoilState soilstate) { if (IsAlive) { List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>(); ZoneWaterAndN Uptake = new ZoneWaterAndN(); ZoneWaterAndN MyZone = new ZoneWaterAndN(); foreach (ZoneWaterAndN Z in soilstate.Zones) if (Z.Name == this.Parent.Name) MyZone = Z; double[] NO3N = MyZone.NO3N; double[] NH4N = MyZone.NH4N; double[] NO3NUp = new double[NO3N.Length]; double[] NH4NUp = new double[NH4N.Length]; Root.CalculateNUptake(NO3N, NH4N, ref NO3NUp, ref NH4NUp); Uptake.NO3N = NO3NUp; Uptake.NH4N = NH4NUp; Uptake.Water = new double[NO3N.Length]; Uptake.Name = this.Parent.Name; Uptakes.Add(Uptake); return Uptakes; } else return null; }
/// <summary>Gets the potential plant water uptake for each layer (mm).</summary> /// <remarks>The model can only handle one root zone at present.</remarks> /// <param name="soilstate">Soil state (current water content)</param> /// <returns>Potential water uptake (mm)</returns> public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate) { if (IsAlive) { // Get the zone this plant is in ZoneWaterAndN myZone = new ZoneWaterAndN(); Zone parentZone = Apsim.Parent(this, typeof (Zone)) as Zone; foreach (ZoneWaterAndN zone in soilstate.Zones) if (zone.Name == parentZone.Name) myZone = zone; // Get the amount of water available for this plant EvaluateSoilWaterAvailable(myZone); // Get the amount of water potentially taken up by this plant EvaluateSoilWaterUptake(); // Pack potential uptake data for this plant ZoneWaterAndN myUptakeDemand = new ZoneWaterAndN(); myUptakeDemand.Name = myZone.Name; myUptakeDemand.Water = mySoilWaterUptake; myUptakeDemand.NO3N = new double[nLayers]; myUptakeDemand.NH4N = new double[nLayers]; List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>(); zones.Add(myUptakeDemand); return zones; } else return null; }
/// <summary>Gets the potential plant N uptake for each layer (mm).</summary> /// <remarks>The model can only handle one root zone at present.</remarks> /// <param name="soilstate">Soil state (current N contents)</param> /// <returns>Potential N uptake (kg/ha)</returns> public List<ZoneWaterAndN> GetNUptakes(SoilState soilstate) { if (IsAlive) { // Get the zone this plant is in 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; // Get the N amount available in the soil EvaluateSoilNitrogenAvailable(myZone); // Get the N amount fixed through symbiosis EvaluateNitrogenFixation(); // Evaluate the use of N remobilised and get N amount demanded from soil EvaluateSoilNitrogenDemand(); // Get N amount take up from the soil EvaluateSoilNitrogenUptake(); //Pack results into uptake structure ZoneWaterAndN myUptakeDemand = new ZoneWaterAndN(); myUptakeDemand.Name = myZone.Name; myUptakeDemand.NH4N = mySoilNH4Uptake; myUptakeDemand.NO3N = mySoilNO3Uptake; myUptakeDemand.Water = new double[nLayers]; List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>(); zones.Add(myUptakeDemand); return zones; } else return null; }
/// <summary> /// Calculate the potential sw uptake for today /// </summary> public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate) { if (Plant.IsAlive) { double Supply = 0; double Demand = 0; double[] supply = null; foreach (IArbitration o in Organs) { double[] organSupply = o.WaterSupply(soilstate.Zones); if (organSupply != null) { supply = organSupply; Supply += MathUtilities.Sum(organSupply); } Demand += o.WaterDemand; } double FractionUsed = 0; if (Supply > 0) FractionUsed = Math.Min(1.0, Demand / Supply); ZoneWaterAndN uptake = new ZoneWaterAndN(); uptake.Name = soilstate.Zones[0].Name; uptake.Water = MathUtilities.Multiply_Value(supply, FractionUsed); uptake.NO3N = new double[uptake.Water.Length]; uptake.NH4N = new double[uptake.Water.Length]; List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>(); zones.Add(uptake); return zones; } else return null; }
/// <summary>Placeholder for SoilArbitrator</summary> /// <param name="soilstate">soil state</param> /// <returns></returns> public List<ZoneWaterAndN> GetNUptakes(SoilState soilstate) { ZoneWaterAndN MyZone = new ZoneWaterAndN(); foreach (ZoneWaterAndN Z in soilstate.Zones) if (Z.Name == this.Parent.Name) MyZone = Z; double[] PotNO3Uptake = new double[Soil.NO3N.Length]; double[] PotNH4Uptake = new double[Soil.NH4N.Length]; NO3Uptake = new double[Soil.NO3N.Length]; NH4Uptake = new double[Soil.NH4N.Length]; SoilCrop soilCrop = Soil.Crop(this.Name) as SoilCrop; for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++) { PotNO3Uptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * soilCrop.KL[j] * MyZone.NO3N[j]); PotNH4Uptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * soilCrop.KL[j] * MyZone.NH4N[j]); } double TotPotNUptake = MathUtilities.Sum(PotNO3Uptake) + MathUtilities.Sum(PotNH4Uptake); for (int j = 0; j < Soil.NO3N.Length; j++) { NO3Uptake[j] = PotNO3Uptake[j] * Math.Min(1.0, NDemand / TotPotNUptake); NH4Uptake[j] = PotNH4Uptake[j] * Math.Min(1.0, NDemand / TotPotNUptake); } List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>(); ZoneWaterAndN Uptake = new ZoneWaterAndN(); Uptake.Name = this.Parent.Name; Uptake.NO3N = NO3Uptake; Uptake.NH4N = NH4Uptake; Uptake.Water = new double[NO3Uptake.Length]; Uptakes.Add(Uptake); return Uptakes; }
/// <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>Calculates how much N the roots will take up in the absence of competition</summary> /// <param name="soilstate">The state of the soil.</param> public void DoNUptakeDemandCalculations(SoilState soilstate) { DoPotentialNutrientUptake(Organs, ref N, soilstate); //Work out how much N the uptaking organs (roots) would take up in the absence of competition }
/// <summary> /// Calculate the potential sw uptake for today /// </summary> public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate) { if (Plant.IsAlive) { // 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; double Supply = 0; double Demand = 0; double[] supply = null; foreach (IArbitration o in Organs) { double[] organSupply = o.WaterSupply(soilstate.Zones); if (organSupply != null) { supply = organSupply; Supply += MathUtilities.Sum(organSupply); } Demand += o.WaterDemand; } double FractionUsed = 0; if (Supply > 0) FractionUsed = Math.Min(1.0, Demand / Supply); // Just send uptake from my zone ZoneWaterAndN uptake = new ZoneWaterAndN(); uptake.Name = MyZone.Name; uptake.Water = MathUtilities.Multiply_Value(supply, FractionUsed); uptake.NO3N = new double[uptake.Water.Length]; uptake.NH4N = new double[uptake.Water.Length]; List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>(); zones.Add(uptake); return zones; } else return null; }
/// <summary> /// Calculate the potential sw uptake for today. Should return null if crop is not in the ground. /// </summary> public List<Soils.Arbitrator.ZoneWaterAndN> GetNUptakes(SoilState soilstate) { if (Plant.IsAlive) { // 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; ZoneWaterAndN UptakeDemands = new ZoneWaterAndN(); if (Plant.Phenology != null) { if (Plant.Phenology.Emerged == true) { DoNUptakeDemandCalculations(soilstate); //Pack results into uptake structure UptakeDemands.NO3N = PotentialNO3NUptake; UptakeDemands.NH4N = PotentialNH4NUptake; } else //Uptakes are zero { UptakeDemands.NO3N = new double[MyZone.NO3N.Length]; for (int i = 0; i < UptakeDemands.NO3N.Length; i++) { UptakeDemands.NO3N[i] = 0; } UptakeDemands.NH4N = new double[MyZone.NH4N.Length]; for (int i = 0; i < UptakeDemands.NH4N.Length; i++) { UptakeDemands.NH4N[i] = 0; } } } else { DoNUptakeDemandCalculations(soilstate); //Pack results into uptake structure UptakeDemands.NO3N = PotentialNO3NUptake; UptakeDemands.NH4N = PotentialNH4NUptake; } UptakeDemands.Name = MyZone.Name; UptakeDemands.Water = new double[UptakeDemands.NO3N.Length]; List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>(); zones.Add(UptakeDemands); return zones; } else return null; }
/// <summary> /// Calculate the potential sw uptake for today /// </summary> public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate) { if (Plant.IsAlive) { // Get all water supplies. double waterSupply = 0; List<double[]> supplies = new List<double[]>(); List<string> zoneNames = new List<string>(); foreach (ZoneWaterAndN zone in soilstate.Zones) { foreach (IArbitration o in Organs) { double[] organSupply = o.WaterSupply(zone); if (organSupply != null) { supplies.Add(organSupply); zoneNames.Add(zone.Name); waterSupply += MathUtilities.Sum(organSupply); } } } // Calculate total water demand. double waterDemand = 0; foreach (IArbitration o in Organs) waterDemand += o.WaterDemand; // Calculate demand / supply ratio. double fractionUsed = 0; if (waterSupply > 0) fractionUsed = Math.Min(1.0, waterDemand / waterSupply); // Apply demand supply ratio to each zone and create a ZoneWaterAndN structure // to return to caller. List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>(); for (int i = 0; i < supplies.Count; i++) { // Just send uptake from my zone ZoneWaterAndN uptake = new ZoneWaterAndN(); uptake.Name = zoneNames[i]; uptake.Water = MathUtilities.Multiply_Value(supplies[i], fractionUsed); uptake.NO3N = new double[uptake.Water.Length]; uptake.NH4N = new double[uptake.Water.Length]; zones.Add(uptake); } return zones; } else return null; }
/// <summary>Calculate the potential sw uptake for today</summary> /// <param name="soilstate"></param> /// <returns>list of uptakes</returns> /// <exception cref="ApsimXException">Could not find root zone in Zone + this.Parent.Name + for SimpleTree</exception> public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate) { ZoneWaterAndN MyZone = new ZoneWaterAndN(); foreach (ZoneWaterAndN Z in soilstate.Zones) if (Z.Name == this.Parent.Name) MyZone = Z; double[] PotSWUptake = new double[Soil.LL15.Length]; SWUptake = new double[Soil.LL15.Length]; SoilCrop soilCrop = Soil.Crop(this.Name) as SoilCrop; for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++) PotSWUptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * soilCrop.KL[j] * (MyZone.Water[j] - Soil.SoilWater.LL15mm[j])); double TotPotSWUptake = MathUtilities.Sum(PotSWUptake); for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++) SWUptake[j] = PotSWUptake[j] * Math.Min(1.0, PotentialEP / TotPotSWUptake); List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>(); ZoneWaterAndN Uptake = new ZoneWaterAndN(); Uptake.Name = this.Parent.Name; Uptake.Water = SWUptake; Uptake.NO3N = new double[SWUptake.Length]; Uptake.NH4N = new double[SWUptake.Length]; Uptakes.Add(Uptake); return Uptakes; }
/// <summary>Placeholder for SoilArbitrator</summary> /// <param name="soilstate">some info</param> /// <returns>soil info</returns> public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate) { throw new NotImplementedException(); }
/// <summary> /// Calculate the potential sw uptake for today. Should return null if crop is not in the ground. /// </summary> public List<Soils.Arbitrator.ZoneWaterAndN> GetNUptakes(SoilState soilstate) { if (Plant.IsAlive) { ZoneWaterAndN UptakeDemands = new ZoneWaterAndN(); if (Plant.Phenology != null) { if (Plant.Phenology.Emerged == true) { DoNUptakeDemandCalculations(soilstate); //Pack results into uptake structure UptakeDemands.NO3N = PotentialNO3NUptake; UptakeDemands.NH4N = PotentialNH4NUptake; } else //Uptakes are zero { UptakeDemands.NO3N = new double[soilstate.Zones[0].NO3N.Length]; for (int i = 0; i < UptakeDemands.NO3N.Length; i++) { UptakeDemands.NO3N[i] = 0; } UptakeDemands.NH4N = new double[soilstate.Zones[0].NH4N.Length]; for (int i = 0; i < UptakeDemands.NH4N.Length; i++) { UptakeDemands.NH4N[i] = 0; } } } else //Uptakes are zero { UptakeDemands.NO3N = new double[soilstate.Zones[0].NO3N.Length]; for (int i = 0; i < UptakeDemands.NO3N.Length; i++) { UptakeDemands.NO3N[i] = 0; } UptakeDemands.NH4N = new double[soilstate.Zones[0].NH4N.Length]; for (int i = 0; i < UptakeDemands.NH4N.Length; i++) { UptakeDemands.NH4N[i] = 0; } } UptakeDemands.Name = soilstate.Zones[0].Name; UptakeDemands.Water = new double[UptakeDemands.NO3N.Length]; List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>(); zones.Add(UptakeDemands); return zones; } else return null; }