/// <summary> /// Set the n uptake for today /// </summary> public void SetActualNitrogenUptakes(List <ZoneWaterAndN> info) { NO3Uptake = info[0].NO3N; NH4Uptake = info[0].NH4N; NO3.SetKgHa(SoluteSetterType.Plant, MathUtilities.Subtract(NO3.kgha, NO3Uptake)); NH4.SetKgHa(SoluteSetterType.Plant, MathUtilities.Subtract(NH4.kgha, NH4Uptake)); }
/// <summary>Add urine to the soil.</summary> private void AddUrineToSoil() { // find the layer that the fertilizer is to be added to. int layer = soil.LayerIndexOfDepth(DepthUrineIsAdded); var no3Values = NO3.kgha; no3Values[layer] += AmountUrineNReturned; NO3.SetKgHa(SoluteSetterType.Fertiliser, no3Values); }
/// <summary>Apply fertiliser.</summary> /// <param name="Amount">The amount.</param> /// <param name="Type">The type.</param> /// <param name="Depth">The depth.</param> /// <param name="doOutput">If true, output will be written to the summary.</param> public void Apply(double Amount, Types Type, double Depth = 0.0, bool doOutput = true) { if (Amount > 0) { // find the layer that the fertilizer is to be added to. int layer = SoilUtilities.LayerIndexOfDepth(soilPhysical.Thickness, Depth); FertiliserType fertiliserType = Definitions.FirstOrDefault(f => f.Name == Type.ToString()); if (fertiliserType == null) { throw new ApsimXException(this, "Cannot find fertiliser type '" + Type + "'"); } // We find the current amount of N in each form, add to it as needed, // then set the new value. An alternative approach could call AddKgHaDelta // rather than SetKgHa if (fertiliserType.FractionNO3 != 0) { var values = NO3.kgha; values[layer] += Amount * fertiliserType.FractionNO3; NO3.SetKgHa(SoluteSetterType.Fertiliser, values); NitrogenApplied += Amount * fertiliserType.FractionNO3; } if (fertiliserType.FractionNH4 != 0) { var values = NH4.kgha; values[layer] += Amount * fertiliserType.FractionNH4; NH4.SetKgHa(SoluteSetterType.Fertiliser, values); NitrogenApplied += Amount * fertiliserType.FractionNH4; } if (fertiliserType.FractionUrea != 0) { var values = Urea.kgha; values[layer] += Amount * fertiliserType.FractionUrea; Urea.SetKgHa(SoluteSetterType.Fertiliser, values); NitrogenApplied += Amount * fertiliserType.FractionUrea; } if (doOutput) { Summary.WriteMessage(this, string.Format("{0} kg/ha of {1} added at depth {2} layer {3}", Amount, Type, Depth, layer + 1)); } Fertilised?.Invoke(this, new FertiliserApplicationType() { Amount = Amount, Depth = Depth, FertiliserType = Type }); } }
/// <summary>Apply fertiliser.</summary> /// <param name="Amount">The amount.</param> /// <param name="Type">The type.</param> /// <param name="Depth">The depth.</param> /// <param name="doOutput">If true, output will be written to the summary.</param> /// <exception cref="ApsimXException">Cannot find fertiliser type ' + Type + '</exception> public void Apply(double Amount, Types Type, double Depth = 0.0, bool doOutput = true) { if (Amount > 0) { // 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 + "'"); } if (fertiliserType.FractionNO3 != 0) { var values = NO3.kgha; values[layer] += Amount * fertiliserType.FractionNO3; NO3.SetKgHa(SoluteSetterType.Fertiliser, values); NitrogenApplied += Amount * fertiliserType.FractionNO3; } if (fertiliserType.FractionNH4 != 0) { var values = NH4.kgha; values[layer] += Amount * fertiliserType.FractionNH4; NH4.SetKgHa(SoluteSetterType.Fertiliser, values); NitrogenApplied += Amount * fertiliserType.FractionNH4; } if (fertiliserType.FractionUrea != 0) { var values = Urea.kgha; values[layer] += Amount * fertiliserType.FractionUrea; Urea.SetKgHa(SoluteSetterType.Fertiliser, values); NitrogenApplied += Amount * fertiliserType.FractionUrea; } if (doOutput) { Summary.WriteMessage(this, string.Format("{0} kg/ha of {1} added at depth {2} layer {3}", Amount, Type, Depth, layer + 1)); } Fertilised?.Invoke(this, new FertiliserApplicationType() { Amount = Amount, Depth = Depth, FertiliserType = Type }); } }
private void OnDoSoilOrganicMatter(object sender, EventArgs e) { if (sourceSolute == null) { sourceSolute = FindInScope <ISolute>(Parent.Name); destinationSolute = FindInScope <ISolute>(destinationName); } double[] source = sourceSolute.kgha; int numLayers = source.Length; if (Value == null) { Value = new double[source.Length]; } double[] destination = null; if (destinationName != null) { destination = destinationSolute.kgha; } for (int i = 0; i < numLayers; i++) { double phosphorusFlow = 0; if (source[i] > 0) { phosphorusFlow = rate.Value(i) * source[i]; } source[i] -= phosphorusFlow; Value[i] = phosphorusFlow; destination[i] += phosphorusFlow; } sourceSolute.SetKgHa(SoluteSetterType.Soil, source); destinationSolute.SetKgHa(SoluteSetterType.Soil, destination); }
/// <summary>Add urine to the soil.</summary> private void AddUrineToSoil() { if (DoUrineReturn == null) { // We will do the urine return. // find the layer that the fertilizer is to be added to. int layer = SoilUtilities.LayerIndexOfDepth(soilPhysical.Thickness, DepthUrineIsAdded); var ureaValues = Urea.kgha; ureaValues[layer] += AmountUrineNReturned; Urea.SetKgHa(SoluteSetterType.Fertiliser, ureaValues); } else { // Another model (e.g. urine patch) will do the urine return. DoUrineReturn.Invoke(this, new UrineReturnType() { Amount = AmountUrineNReturned, Depth = DepthUrineIsAdded, GrazedDM = GrazedDM }); } }
private void OnDoSoilWaterMovement(object sender, EventArgs e) { // Calculate lateral flow. lateralFlowModel.Calculate(); if (LateralFlow.Length > 0) { Water = MathUtilities.Subtract(Water, LateralFlow); } // Calculate runoff. Runoff = runoffModel.Value(); // Calculate infiltration. Infiltration = PotentialInfiltration - Runoff; Water[0] = Water[0] + Infiltration + Runon; // Allow irrigation to infiltrate. foreach (var irrigation in irrigations) { if (irrigation.Amount > 0) { int irrigationLayer = soil.LayerIndexOfDepth(Convert.ToInt32(irrigation.Depth, CultureInfo.InvariantCulture)); Water[irrigationLayer] += irrigation.Amount; if (irrigationLayer == 0) { Infiltration += irrigation.Amount; } if (no3 != null) { no3.kgha[irrigationLayer] += irrigation.NO3; } if (nh4 != null) { nh4.kgha[irrigationLayer] += irrigation.NH4; } if (cl != null) { cl.kgha[irrigationLayer] += irrigation.CL; } } } // Saturated flow. Flux = saturatedFlow.Values; // Add backed up water to runoff. Water[0] = Water[0] - saturatedFlow.backedUpSurface; // Now reduce the infiltration amount by what backed up. Infiltration = Infiltration - saturatedFlow.backedUpSurface; // Turn the proportion of the infiltration that backed up into runoff. Runoff = Runoff + saturatedFlow.backedUpSurface; // Should go to pond if one exists. // pond = Math.Min(Runoff, max_pond); MoveDown(Water, Flux); double[] no3Values = no3.kgha; double[] ureaValues = urea.kgha; // Calcualte solute movement down with water. double[] no3Down = CalculateSoluteMovementDown(no3Values, Water, Flux, SoluteFluxEfficiency); MoveDown(no3Values, no3Down); double[] ureaDown = CalculateSoluteMovementDown(ureaValues, Water, Flux, SoluteFluxEfficiency); MoveDown(ureaValues, ureaDown); // Calculate evaporation and remove from top layer. double es = evaporationModel.Calculate(); Water[0] = Water[0] - es; // Calculate unsaturated flow of water and apply. Flow = unsaturatedFlow.Values; MoveUp(Water, Flow); // Check for errors in water variables. //CheckForErrors(); // Calculate water table depth. waterTableModel.Calculate(); // Calculate and apply net solute movement. double[] no3Up = CalculateNetSoluteMovement(no3Values, Water, Flow, SoluteFlowEfficiency); MoveUp(no3Values, no3Up); double[] ureaUp = CalculateNetSoluteMovement(ureaValues, Water, Flow, SoluteFlowEfficiency); MoveUp(ureaValues, ureaUp); // Update flow output variables. FlowNO3 = MathUtilities.Subtract(no3Down, no3Up); FlowUrea = MathUtilities.Subtract(ureaDown, ureaUp); // Set solute state variables. no3.SetKgHa(SoluteSetterType.Soil, no3Values); urea.SetKgHa(SoluteSetterType.Soil, ureaValues); // Now that we've finished moving water, calculate volumetric water waterVolumetric = MathUtilities.Divide(Water, soil.Thickness); }
private void OnDoSoilWaterMovement(object sender, EventArgs e) { // Calculate lateral flow. LateralFlow = lateralFlowModel.Values; MathUtilities.Subtract(Water, LateralFlow); // Calculate runoff. Runoff = runoffModel.Value(); // Calculate infiltration. Infiltration = PotentialInfiltration - Runoff; Water[0] = Water[0] + Infiltration; // Allow irrigation to infiltrate. if (!irrigation.WillRunoff) { int irrigationLayer = APSIM.Shared.APSoil.SoilUtilities.FindLayerIndex(properties, Convert.ToInt32(irrigation.Depth, CultureInfo.InvariantCulture)); Water[irrigationLayer] = irrigation.IrrigationApplied; Infiltration += irrigation.IrrigationApplied; // DeanH - haven't implemented solutes in irrigation water yet. // NO3[irrigationLayer] = irrigation.NO3; // NH4[irrigationLayer] = irrigation.NH4; // CL[irrigationLayer] = irrigation.Cl; } // Saturated flow. Flux = saturatedFlow.Values; // Add backed up water to runoff. Water[0] = Water[0] - saturatedFlow.backedUpSurface; // Now reduce the infiltration amount by what backed up. Infiltration = Infiltration - saturatedFlow.backedUpSurface; // Turn the proportion of the infiltration that backed up into runoff. Runoff = Runoff + saturatedFlow.backedUpSurface; // Should go to pond if one exists. // pond = Math.Min(Runoff, max_pond); MoveDown(Water, Flux); double[] NO3Values = soilNitrogen.CalculateNO3(); double[] NH4Values = soilNitrogen.CalculateNH4(); // Calcualte solute movement down with water. double[] NO3Down = CalculateSoluteMovementDown(NO3Values, Water, Flux, SoluteFluxEfficiency); double[] NH4Down = CalculateSoluteMovementDown(NH4Values, Water, Flux, SoluteFluxEfficiency); MoveDown(NO3Values, NO3Down); MoveDown(NH4Values, NH4Down); double es = evaporationModel.Calculate(); Water[0] = Water[0] - es; Flow = unsaturatedFlow.Values; MoveUp(Water, Flow); CheckForErrors(); double waterTableDepth = waterTableModel.Value(); double[] NO3Up = CalculateSoluteMovementUpDown(soilNitrogen.CalculateNO3(), Water, Flow, SoluteFlowEfficiency); double[] NH4Up = CalculateSoluteMovementUpDown(soilNitrogen.CalculateNH4(), Water, Flow, SoluteFlowEfficiency); MoveUp(NO3Values, NO3Up); MoveUp(NH4Values, NH4Up); // Set deltas NO3.SetKgHa(SoluteSetterType.Soil, MathUtilities.Subtract(soilNitrogen.CalculateNO3(), NO3Values)); NH4.SetKgHa(SoluteSetterType.Soil, MathUtilities.Subtract(soilNitrogen.CalculateNH4(), NH4Values)); }
/// <summary>Remove nutrients from soil - uptake.</summary> /// <param name="no3Amount">Amount of no3 to remove.</param> /// <param name="nh4Amount">Amount of nh4 to remove.</param> public void PerformNutrientUptake(double[] no3Amount, double[] nh4Amount) { no3.SetKgHa(SoluteSetterType.Plant, MathUtilities.Subtract(no3.kgha, no3Amount)); nh4.SetKgHa(SoluteSetterType.Plant, MathUtilities.Subtract(nh4.kgha, nh4Amount)); }
private void OnDoSoilOrganicMatter(object sender, EventArgs e) { if (sourceSolute == null) { sourceSolute = FindInScope <ISolute>(Parent.Name); destinationSolute = FindInScope <ISolute>(destinationName); } double[] source = sourceSolute.kgha; int numLayers = source.Length; if (Value == null) { Value = new double[source.Length]; } if (Natm == null) { Natm = new double[source.Length]; } if (N2Oatm == null) { N2Oatm = new double[source.Length]; } double[] destination = null; if (destinationName != null) { destination = destinationSolute.kgha; } for (int i = 0; i < numLayers; i++) { double nitrogenFlow = 0; if (source[i] > 0) { nitrogenFlow = rate.Value(i) * source[i]; } if (nitrogenFlow > 0) { Natm[i] = nitrogenFlow * NLoss.Value(i); // keep value of loss for use in output } else { Natm[i] = 0; } if (Natm[i] > 0) { N2Oatm[i] = Natm[i] * N2OFraction.Value(i); } else { N2Oatm[i] = 0; } double nitrogenFlowToDestination = nitrogenFlow - Natm[i]; if (destination == null && NLoss.Value(i) != 1) { throw new Exception("N loss fraction for N flow must be 1 if no destination is specified."); } source[i] -= nitrogenFlow; Value[i] = nitrogenFlowToDestination; // keep value of flow for use in output if (destination != null) { destination[i] += nitrogenFlowToDestination; } } sourceSolute.SetKgHa(SoluteSetterType.Soil, source); if (destination != null) { destinationSolute.SetKgHa(SoluteSetterType.Soil, destination); } }