Skip to content

Commit

Permalink
Merge pull request #1557 from hut104/SoilNutrient
Browse files Browse the repository at this point in the history
Soil Nutrient model for Mineralisation of C in three pools
  • Loading branch information
hol353 authored Mar 15, 2017
2 parents 3d85ae2 + 44427e3 commit 2f541c4
Show file tree
Hide file tree
Showing 15 changed files with 2,556 additions and 757 deletions.
5 changes: 4 additions & 1 deletion Models/Core/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ public Model()
[XmlElement(typeof(Soils.Sample))]
[XmlElement(typeof(Soils.Nutrient.Nutrient))]
[XmlElement(typeof(Soils.Nutrient.NutrientPool))]
[XmlElement(typeof(Soils.Nutrient.Flow))]
[XmlElement(typeof(Soils.Nutrient.CarbonFlow))]
[XmlElement(typeof(Soils.Nutrient.NFlow))]
[XmlElement(typeof(WaterModel.CNReductionForCover))]
[XmlElement(typeof(WaterModel.CNReductionForTillage))]
[XmlElement(typeof(WaterModel.EvaporationModel))]
Expand Down Expand Up @@ -174,6 +175,7 @@ public Model()
[XmlElement(typeof(Models.PMF.Functions.InPhaseTtFunction))]
[XmlElement(typeof(Models.PMF.Functions.LessThanFunction))]
[XmlElement(typeof(Models.PMF.Functions.LinearInterpolationFunction))]
[XmlElement(typeof(Models.PMF.Functions.BoundFunction))]
[XmlElement(typeof(Models.PMF.Functions.MaximumFunction))]
[XmlElement(typeof(Models.PMF.Functions.MinimumFunction))]
[XmlElement(typeof(Models.PMF.Functions.MultiplyFunction))]
Expand All @@ -186,6 +188,7 @@ public Model()
[XmlElement(typeof(Models.PMF.Functions.PowerFunction))]
[XmlElement(typeof(Models.PMF.Functions.SigmoidFunction))]
[XmlElement(typeof(Models.PMF.Functions.SigmoidFunction2))]
[XmlElement(typeof(Models.PMF.Functions.SoilWaterScale))]
[XmlElement(typeof(Models.PMF.Functions.SoilTemperatureDepthFunction))]
[XmlElement(typeof(Models.PMF.Functions.SoilTemperatureFunction))]
[XmlElement(typeof(Models.PMF.Functions.SoilTemperatureWeightedFunction))]
Expand Down
8 changes: 4 additions & 4 deletions Models/Fertiliser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,22 +148,22 @@ public void Apply(double Amount, Types Type, double Depth = 0.0)

NitrogenChangedType NitrogenChanges = new NitrogenChangedType();
NitrogenChanges.Sender = Apsim.FullPath(this);

NitrogenChanges.DeltaNO3 = new double[Soil.Thickness.Length];
NitrogenChanges.DeltaNH4 = new double[Soil.Thickness.Length];
NitrogenChanges.DeltaUrea = new double[Soil.Thickness.Length];

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;
}
Expand Down
1,265 changes: 634 additions & 631 deletions Models/Models.csproj

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions Models/Plant/Functions/Bound.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Models.Core;

namespace Models.PMF.Functions
{
/// <summary>
/// Bounds the child function between lower and upper bounds
/// </summary>
[Serializable]
[Description("Bounds the child function between lower and upper bounds")]
public class BoundFunction : Model, IFunction
{
/// <summary>The child functions</summary>
private List<IModel> ChildFunctions;

[ChildLinkByName]
IFunction Lower = null;

[ChildLinkByName]
IFunction Upper = null;

/// <summary>Gets the value.</summary>
/// <value>The value.</value>
public double Value(int arrayIndex = -1)
{
if (ChildFunctions == null)
ChildFunctions = Apsim.Children(this, typeof(IFunction));
foreach (IFunction child in ChildFunctions)
if (child != Lower && child != Upper)
return Math.Max(Math.Min(Upper.Value(arrayIndex), child.Value(arrayIndex)),Lower.Value(arrayIndex));
throw new Exception("Cannot find function value to apply in bound");
}
}
}
9 changes: 6 additions & 3 deletions Models/Plant/Functions/ExpressionFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public double Value(int arrayIndex = -1)
Parse(fn, Expression);
parsed = true;
}
FillVariableNames(fn, this);
FillVariableNames(fn, this, arrayIndex);
Evaluate(fn);
if (fn.Results != null && arrayIndex != -1)
return fn.Results[arrayIndex];
Expand Down Expand Up @@ -66,8 +66,9 @@ private static void Parse(ExpressionEvaluator fn, string ExpressionProperty)
/// <summary>Fills the variable names.</summary>
/// <param name="fn">The function.</param>
/// <param name="RelativeTo">The relative to.</param>
/// <param name="arrayIndex">The array index</param>
/// <exception cref="System.Exception">Cannot find variable: + sym.m_name + in function: + RelativeTo.Name</exception>
private static void FillVariableNames(ExpressionEvaluator fn, Model RelativeTo)
private static void FillVariableNames(ExpressionEvaluator fn, Model RelativeTo, int arrayIndex)
{
ArrayList varUnfilled = fn.Variables;
ArrayList varFilled = new ArrayList();
Expand All @@ -88,6 +89,8 @@ private static void FillVariableNames(ExpressionEvaluator fn, Model RelativeTo)
for (int i = 0; i < arr.Length; i++)
symFilled.m_values[i] = Convert.ToDouble(arr.GetValue(i));
}
else if (sometypeofobject is IFunction)
symFilled.m_value = (sometypeofobject as IFunction).Value(arrayIndex);
else
symFilled.m_value = Convert.ToDouble(sometypeofobject);
varFilled.Add(symFilled);
Expand Down Expand Up @@ -130,7 +133,7 @@ public static object Evaluate(string Expression, Model RelativeTo)
{
ExpressionEvaluator fn = new ExpressionEvaluator();
Parse(fn, Expression);
FillVariableNames(fn, RelativeTo);
FillVariableNames(fn, RelativeTo, -1);
Evaluate(fn);
if (fn.Results != null)
return fn.Results;
Expand Down
4 changes: 3 additions & 1 deletion Models/Plant/Functions/LinearInterpolationFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ public double Value(int arrayIndex = -1)
double XValue;
if (v is Array)
XValue = (double)(v as Array).GetValue(arrayIndex);
else if (v is IFunction)
XValue = (v as IFunction).Value(arrayIndex);
else
XValue = (double) v;
XValue = (double)v;
return XYPairs.ValueIndexed(XValue);
}

Expand Down
38 changes: 38 additions & 0 deletions Models/Plant/Functions/SoilWaterScale.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using Models.Core;
using Models.Soils;
using APSIM.Shared.Utilities;

namespace Models.PMF.Functions
{
/// <summary>
/// A simple scale to convert soil water content into a value between 0 and 2
/// </summary>
[Serializable]
public class SoilWaterScale : Model, IFunction
{
[Link]
Soil Soil = null;

/// <summary>Gets the value of the function.</summary>
public double Value(int arrayIndex = -1)
{
// temporary water factor (0-1)
double wfd;
if (Soil.SoilWater.SWmm[arrayIndex] > Soil.SoilWater.DULmm[arrayIndex])
{ // saturated
wfd = Math.Max(1.0, Math.Min(2.0, 1.0 +
MathUtilities.Divide(Soil.SoilWater.SWmm[arrayIndex] - Soil.SoilWater.DULmm[arrayIndex], Soil.SoilWater.SATmm[arrayIndex] - Soil.SoilWater.DULmm[arrayIndex], 0.0)));
}
else
{ // unsaturated
// assumes rate of mineralisation is at optimum rate until soil moisture midway between dul and ll15
wfd = Math.Max(0.0, Math.Min(1.0, MathUtilities.Divide(Soil.SoilWater.SWmm[arrayIndex] - Soil.SoilWater.LL15mm[arrayIndex], Soil.SoilWater.DULmm[arrayIndex] - Soil.SoilWater.LL15mm[arrayIndex], 0.0)));
}

return wfd;
}

}
}
7 changes: 6 additions & 1 deletion Models/Plant/Functions/Variable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ public class VariableReference : Model, IFunction
public double Value(int arrayIndex = -1)
{
object o = Apsim.Get(this, VariableName.Trim());
return Convert.ToDouble(o);
if (o is IFunction)
return (o as IFunction).Value(arrayIndex);
else if (o is Array)
return Convert.ToDouble((o as Array).GetValue(arrayIndex));
else
return Convert.ToDouble(o);
}

/// <summary>Writes documentation for this function by adding to the list of documentation tags.</summary>
Expand Down
8 changes: 6 additions & 2 deletions Models/Resources/Wheat.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1996,13 +1996,17 @@ This phase has a target of 1 and a Tt of 1 so it always lasts for a day. Phase
<Name>PendletonTall</Name>
<Command>[Phenology].Vernalisation.VernSens = 5.0</Command>
<Command>[Phenology].Vernalisation.PhotopSens = 5.0</Command>
<Command>[Grain].GrainsPerGramStem = 15</Command>
<Command>[Grain].GrainsPerGramStem = 20</Command>
<Command>[Grain].MaxGrainSize = 0.045</Command>
<Command>[Phenology].StartGrainFillToEndGrainFill.Target.FixedValue = 600</Command>
</Cultivar>
<Cultivar>
<Name>PendletonDwarf</Name>
<Command>[Phenology].Vernalisation.VernSens = 5.0</Command>
<Command>[Phenology].Vernalisation.PhotopSens = 5.0</Command>
<Command>[Grain].GrainsPerGramStem = 20</Command>
<Command>[Grain].GrainsPerGramStem = 25</Command>
<Command>[Grain].MaxGrainSize = 0.045</Command>
<Command>[Phenology].StartGrainFillToEndGrainFill.Target.FixedValue = 600</Command>
</Cultivar>

</Plant15>
Expand Down
19 changes: 14 additions & 5 deletions Models/Soils/Nutrient/Flow.cs → Models/Soils/Nutrient/CFlow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ namespace Models.Soils.Nutrient
using System;

/// <summary>
/// Encapsulates a flow between pools.
/// Encapsulates a carbon flow between pools.
/// </summary>
[Serializable]
[ValidParent(ParentType = typeof(Nutrient))]
[PresenterName("UserInterface.Presenters.PropertyPresenter")]
[ViewName("UserInterface.Views.GridView")]
public class Flow : Model
public class CarbonFlow : Model
{
private NutrientPool source = null;
private NutrientPool destination = null;
Expand All @@ -23,6 +23,9 @@ public class Flow : Model
[Link]
private IFunction CO2Efficiency = null;

[Link]
private Nutrient nutrient = null;

/// <summary>
/// Name of source pool
/// </summary>
Expand Down Expand Up @@ -61,11 +64,17 @@ private void OnDoSoilOrganicMatter(object sender, EventArgs e)
for (int i= 0; i < source.C.Length; i++)
{
double carbonFlow = rate.Value(i) * source.C[i];
double nitrogenFlow = carbonFlow * source.CNRatio;
double nitrogenFlow = carbonFlow / source.CNRatio[i];
double carbonFlowToDestination = carbonFlow * CO2Efficiency.Value(i);
double nitrogenFlowToDestination = carbonFlowToDestination / destination.CNRatio[i];
source.C[i] -= carbonFlow;
destination.C[i] += carbonFlow*CO2Efficiency.Value(i);
source.N[i] -= nitrogenFlow;
destination.N[i] += nitrogenFlow;
destination.C[i] += carbonFlowToDestination;
destination.N[i] += nitrogenFlowToDestination;
if (nitrogenFlowToDestination < nitrogenFlow)
nutrient.NH4[i] += (nitrogenFlow - nitrogenFlowToDestination);
else
throw new NotImplementedException();
}
}

Expand Down
79 changes: 79 additions & 0 deletions Models/Soils/Nutrient/NFlow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

namespace Models.Soils.Nutrient
{
using Core;
using Models.PMF.Functions;
using System;
using System.Reflection;

/// <summary>
/// Encapsulates a nitrogen flow between mineral N pools.
/// </summary>
[Serializable]
[ValidParent(ParentType = typeof(Nutrient))]
[PresenterName("UserInterface.Presenters.PropertyPresenter")]
[ViewName("UserInterface.Views.GridView")]
public class NFlow : Model
{
private PropertyInfo sourceProperty;
private PropertyInfo destinationProperty;

[Link]
private IFunction rate = null;

[Link]
private IFunction NLoss = null;

[Link]
private Nutrient nutrient = null;

/// <summary>
/// Name of source pool
/// </summary>
[Description("Name of source pool")]
public string sourceName { get; set; }

/// <summary>
/// Name of destination pool
/// </summary>
[Description("Name of destination pool")]
public string destinationName { get; set; }

/// <summary>Performs the initial checks and setup</summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
[EventSubscribe("Commencing")]
private void OnSimulationCommencing(object sender, EventArgs e)
{
sourceProperty = nutrient.GetType().GetProperty(sourceName);
destinationProperty = nutrient.GetType().GetProperty(destinationName);
}

/// <summary>
/// Get the information on potential residue decomposition - perform daily calculations as part of this.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
[EventSubscribe("DoSoilOrganicMatter")]
private void OnDoSoilOrganicMatter(object sender, EventArgs e)
{

double[] source = (double[])sourceProperty.GetValue(nutrient);

double[] destination = (double[])destinationProperty.GetValue(nutrient);

for (int i= 0; i < nutrient.NO3.Length; i++)
{
double nitrogenFlow = rate.Value(i) * source[i];
double nitrogenFlowToDestination = nitrogenFlow * (1-NLoss.Value(i));

source[i] -= nitrogenFlow;
destination[i] += nitrogenFlowToDestination;
}
sourceProperty.SetValue(nutrient, source);
destinationProperty.SetValue(nutrient, destination);
}


}
}
Loading

0 comments on commit 2f541c4

Please sign in to comment.