/// <summary>Does the n balance.</summary> private void DoNBalance() { Soils.NitrogenChangedType NUptakeType = new Soils.NitrogenChangedType(); NUptakeType.Sender = Name; NUptakeType.SenderType = "Plant"; NUptakeType.DeltaNO3 = new double[SoilWat.Thickness.Length]; NUptakeType.DeltaNH4 = new double[SoilWat.Thickness.Length]; double Ndemand = DltDM * 10 * 0.021; NFixation = Math.Max(0.0, Ndemand * .44); for (int j = 0; j < SoilWat.Thickness.Length; j++) { PotNUptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * SoilN.NO3[j]); } double TotPotNUptake = MathUtilities.Sum(PotNUptake); double Fr = Math.Min(1.0, (Ndemand - NFixation) / TotPotNUptake); for (int j = 0; j < SoilWat.Thickness.Length; j++) { NUptake[j] = PotNUptake[j] * Fr; NUptakeType.DeltaNO3[j] = -NUptake[j]; } if (NitrogenChanged != null) { NitrogenChanged.Invoke(NUptakeType); } }
/// <summary>Does the Nitrogen uptake.</summary> /// <param name="NO3NAmount">The NO3NAmount.</param> /// <param name="NH4NAmount">The NH4NAmount.</param> public override void DoNitrogenUptake(double[] NO3NAmount, double[] NH4NAmount) { // Send the delta water back to SoilN that we're going to uptake. NitrogenChangedType NitrogenUptake = new NitrogenChangedType(); NitrogenUptake.DeltaNO3 = MathUtilities.Multiply_Value(NO3NAmount, -1.0); NitrogenUptake.DeltaNH4 = MathUtilities.Multiply_Value(NH4NAmount, -1.0); NitUptake = MathUtilities.Add(NitrogenUptake.DeltaNO3, NitrogenUptake.DeltaNH4); if (NitrogenChanged != null) { NitrogenChanged.Invoke(NitrogenUptake); } }
/// <summary>Send a nitrogen changed event.</summary> /// <param name="NO3">The no3 values.</param> /// <param name="NH4">The nh4 values.</param> private void SendNitrogenChangedEvent(double[] NO3, double[] NH4) { NitrogenChangedType NitrogenDeltas = new NitrogenChangedType(); NitrogenDeltas.Sender = "Soil"; NitrogenDeltas.SenderType = "Soil"; NitrogenDeltas.DeltaNO3 = MathUtilities.Subtract(soilNitrogen.NO3, NO3); NitrogenDeltas.DeltaNH4 = MathUtilities.Subtract(soilNitrogen.NH4, NH4); if (NitrogenChanged != null) { NitrogenChanged.Invoke(NitrogenDeltas); } }
/// <summary> /// Make the changes from solute degradation effective . Uses the SoluteChanged event /// </summary> public override void EffectivateSoluteDegradation() { // First reduce the amount of this solute SoluteChangedType SoluteChanges = new SoluteChangedType(); SoluteChanges.Sender = "SoluteDegradation"; SoluteChanges.SoluteName = Name; SoluteChanges.SoluteUnits = "kg/ha"; SoluteChanges.DeltaSolute = deltaSoluteTransformed; SoluteChanged.Invoke(SoluteChanges); // Now increase the degradation product (assumed also solute) NitrogenChangedType NitrogenChanges = new NitrogenChangedType(); NitrogenChanges.Sender = "SoluteDegradation"; NitrogenChanges.SenderType = "Solute"; NitrogenChanges.DeltaUrea = Array.ConvertAll(deltaSoluteTransformed, i => - i); NitrogenChanged.Invoke(NitrogenChanges); }
/// <summary> /// Update the water and N balance. /// </summary> private void UpdateWaterAndNBalance() { NitrogenChangedType NitrogenUptake = new NitrogenChangedType(); NitrogenUptake.Sender = "Plant"; NitrogenUptake.SenderType = "Plant"; NitrogenUptake.DeltaNO3 = MathUtility.Multiply_Value(dlt_no3gsm, Conversions.gm2kg / Conversions.sm2ha); NitrogenUptake.DeltaNH4 = MathUtility.Multiply_Value(dlt_nh4gsm, Conversions.gm2kg / Conversions.sm2ha); Util.Debug("Root.NitrogenUptake.DeltaNO3=%f", MathUtility.Sum(NitrogenUptake.DeltaNO3)); Util.Debug("Root.NitrogenUptake.DeltaNH4=%f", MathUtility.Sum(NitrogenUptake.DeltaNH4)); NitrogenChanged.Invoke(NitrogenUptake); // Send back delta water and nitrogen back to APSIM. if (!SwimIsPresent) { WaterChangedType WaterUptake = new WaterChangedType(); WaterUptake.DeltaWater = dlt_sw_dep; Util.Debug("Root.WaterUptake=%f", MathUtility.Sum(WaterUptake.DeltaWater)); WaterChanged.Invoke(WaterUptake); } }
/// <summary> /// Set the n uptake for today /// </summary> public void SetNUptake(List <ZoneWaterAndN> info) { NitrogenChangedType NUptakeType = new NitrogenChangedType(); NUptakeType.Sender = Name; NUptakeType.SenderType = "Plant"; NUptakeType.DeltaNO3 = new double[Soil.Thickness.Length]; NUptakeType.DeltaNH4 = new double[Soil.Thickness.Length]; NO3Uptake = info[0].NO3N; NH4Uptake = info[0].NH4N; for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++) { NUptakeType.DeltaNO3[j] = -NO3Uptake[j]; NUptakeType.DeltaNH4[j] = -NH4Uptake[j]; } if (NitrogenChanged != null) { NitrogenChanged.Invoke(NUptakeType); } }
/// <summary>Apply fertiliser.</summary> /// <param name="Amount">The amount.</param> /// <param name="Type">The type.</param> /// <param name="Depth">The depth.</param> /// <exception cref="ApsimXException">Cannot find fertiliser type ' + Type + '</exception> public void Apply(double Amount, Types Type, double Depth = 0.0) { if (Amount > 0 && NitrogenChanged != null) { // find the layer that the fertilizer is to be added to. int layer = GetLayerDepth(Depth, Soil.Thickness); FertiliserType fertiliserType = Definitions.FirstOrDefault(f => f.Name == Type.ToString()); if (fertiliserType == null) { throw new ApsimXException(this, "Cannot find fertiliser type '" + Type + "'"); } NitrogenChangedType NitrogenChanges = new NitrogenChangedType(); NitrogenChanges.Sender = Apsim.FullPath(this); if (fertiliserType.FractionNO3 != 0) { NitrogenChanges.DeltaNO3 = new double[Soil.Thickness.Length]; NitrogenChanges.DeltaNO3[layer] = Amount * fertiliserType.FractionNO3; NitrogenApplied += Amount * fertiliserType.FractionNO3; } if (fertiliserType.FractionNH4 != 0) { NitrogenChanges.DeltaNH4 = new double[Soil.Thickness.Length]; NitrogenChanges.DeltaNH4[layer] = Amount * fertiliserType.FractionNH4; NitrogenApplied += Amount * fertiliserType.FractionNH4; } if (fertiliserType.FractionUrea != 0) { NitrogenChanges.DeltaUrea = new double[Soil.Thickness.Length]; NitrogenChanges.DeltaUrea[layer] = Amount * fertiliserType.FractionUrea; NitrogenApplied += Amount * fertiliserType.FractionUrea; } NitrogenChanged.Invoke(NitrogenChanges); Summary.WriteMessage(this, string.Format("{0} kg/ha of {1} added at depth {2} layer {3}", Amount, Type, Depth, layer + 1)); } }
/// <summary> /// Send the nitrogen uptake arrays back to the plants and send the change in nitrogen back to the soil /// </summary> /// <param name="resourceToArbitrate"></param> private void SetNitrogenUptake(string resourceToArbitrate) { zones = -1; int maxPlants = 0; int maxLayers = 0; foreach (Zone zone in Apsim.FindAll(Simulation, typeof(Zone))) //foreach (Zone zone in Simulation.FindAll(typeof(Zone))) { zones += 1; // Find plants in paddock. List <ICrop2> plants = zone.Plants; maxPlants = Math.Max(plants.Count, maxPlants); // Find soil in paddock. Soil Soil = (Soil)Apsim.Find(zone, typeof(Soil)); maxLayers = Math.Max(Soil.Thickness.Length, maxLayers); double[] dummyArray1 = new double[Soil.Thickness.Length]; // have to create a new array for each plant to avoid the .NET pointer thing - will have to re-think this with when zones come in double[] dummyArray2 = new double[Soil.Thickness.Length]; // have to create a new array for each plant to avoid the .NET pointer thing - will have to re-think this with when zones come in // move this inside the zone loop - needs to get zeroed for each seperate zone NitrogenChangedType NUptakeType = new NitrogenChangedType(); NUptakeType.Sender = Name; NUptakeType.SenderType = "Plant"; NUptakeType.DeltaNO3 = new double[Soil.Thickness.Length]; NUptakeType.DeltaNH4 = new double[Soil.Thickness.Length]; for (int p = 0; p < maxPlants; p++) { for (int l = 0; l < maxLayers; l++) { for (int b = 0; b < bounds; b++) { for (int f = 0; f < forms; f++) { dummyArray1[l] += uptake[p, l, z, b, f]; // add the forms together to give the total nitrogen uptake if (f == 0) { NUptakeType.DeltaNO3[l] += -1.0 * uptake[p, l, z, b, f]; dummyArray2[l] += uptake[p, l, z, b, f]; // nitrate only uptake so can do the proportion before sending to the plant } else { NUptakeType.DeltaNH4[l] += -1.0 * uptake[p, l, z, b, f]; } } } } // set uptakes in each plant plants[p].uptakeNitrogen = dummyArray1; for (int l = 0; l < Soil.Thickness.Length; l++) // don't forget to deal with zones at some point { dummyArray2[l] = MathUtilities.Divide(dummyArray2[l], dummyArray1[l], 0.0); // would be nice to have a utility for this } plants[p].uptakeNitrogenPropNO3 = dummyArray2; } // and finally set the changed soil resources if (NitrogenChanged != null) { NitrogenChanged.Invoke(NUptakeType); } } }