Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crop stage tests #44

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
44f7b4e
Add Crop Stage Tests
HamishBrownPFR May 27, 2024
2288669
Fix bugs in Crop uptake patterns
HamishBrownPFR May 27, 2024
474b1df
Add Tt_sow parameter
HamishBrownPFR May 27, 2024
ed9d4d2
update tests after bug fix
HamishBrownPFR May 27, 2024
80d082c
update coeffs and tests
HamishBrownPFR May 28, 2024
d1a3d39
More fine tuning of configs and coeffes. Updating tests
HamishBrownPFR May 28, 2024
dc71bb9
Remove redundant method
HamishBrownPFR May 28, 2024
033de5f
Add enums for input classes. Not all inputs are enforcing these yet
HamishBrownPFR May 29, 2024
9a8e28a
Add class for soil test calcultions
HamishBrownPFR May 29, 2024
849b17a
Add excel test of soil test
HamishBrownPFR May 29, 2024
7d2c7dd
Add method to interface that takes soil test inputs and returns soil …
HamishBrownPFR May 29, 2024
8829af2
Alter config to use enums for soil test variables
HamishBrownPFR May 29, 2024
2ec22a5
Add constants needed for soil test calculations
HamishBrownPFR May 29, 2024
cac2827
All test results have changed because an error in Bulk Density calcul…
HamishBrownPFR May 29, 2024
cbca811
Change soil test inputs from strings to enum for defaults and unit tests
HamishBrownPFR May 29, 2024
eac50c6
Fix spelling error and add two new crop parameters
HamishBrownPFR May 29, 2024
edc77d0
rename input types to avoid potential name clash
HamishBrownPFR May 29, 2024
4916dc4
Fix parsing to enum in constructor
HamishBrownPFR May 29, 2024
df6283b
fix bulk density in unit test
HamishBrownPFR May 29, 2024
0a3872f
Change inputs from enums back to strings
HamishBrownPFR May 29, 2024
328d64c
Update tests. model was not picking up the correct soil depth value …
HamishBrownPFR May 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions SVSModel.Excel/ExcelInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using ExcelDna.Integration;
using System.Linq;
using SVSModel.Models;
using static SVSModel.Configuration.Constants;
using static SVSModel.Configuration.InputCategories;

namespace SVSModel.Excel
{
Expand All @@ -18,10 +20,41 @@ public interface IMyFunctions
object[,] GetDailyCropData(double[] Tt, object[,] Config);

object[,] GetCropCoefficients();

object[,] GetSoilTestResult(object testDate, double testValue, string depthOfSample,
string typeOfTest, string moistureOfTest,
string soilCategory, string soilTexture);
}

public static class MyFunctions //: IMyFunctions
{
/// <summary>
/// Takes soil test input values and returns a value in kg N/ha
/// </summary>
/// <param name="testDate">Date of test</param>
/// <param name="testValue">value of test in mgN/g soil</param>
/// <param name="depthOfSample">0-15, 30, 60 or 90cm</param>
/// <param name="typeOfTest">Lab or Quicktest</param>
/// <param name="moistureOfTest">Wet, Moist, dry</param>
/// <param name="categoryOfSoil">Volcanic or sedementary</param>
/// <param name="textureOfSoil">a valid texture class</param>
/// <returns>Soil nitrogen in kg/ha</returns>
public static object[,] GetSoilTestResult(object testDate, double testValue,
string depthOfSample,
string typeOfTest, string moistureOfTest,
string categoryOfSoil, string textureOfSoil)

{
DateTime _testDate = Functions.Date(testDate);
SoilTestConfig test = new SoilTestConfig(_testDate, testValue, depthOfSample,
typeOfTest, moistureOfTest,
categoryOfSoil, textureOfSoil);
object[,] st = new object[1, 2];
st[0, 0] = test.Result.Keys.First();
st[0, 1] = test.Result.Values.First();
return st;
}

/// <summary>
/// Function that takes input data in 2D array format and calculates a N balance for a 3 crops rotation and returns N balance variables in 2D array format
/// </summary>
Expand Down
13 changes: 7 additions & 6 deletions SVSModel.Tests/Configuration/FieldConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using SVSModel.Configuration;
using SVSModel.Models;
using Xunit;
using static SVSModel.Configuration.InputCategories;

namespace SVSModel.Tests.Configuration;

Expand Down Expand Up @@ -43,7 +44,7 @@ public void Test_FieldConfig_Excel_Gets_Values_Correctly()

Assert.Equal(fieldConfig.Rocks, Rocks / 100);
Assert.Equal(fieldConfig.SampleDepthFactor, Constants.SampleDepthFactor[SampleDepth]);
Assert.Equal(fieldConfig.BulkDensity, Constants.ParticleDensity[SoilCategory] * Constants.Porosity[Texture]);
Assert.Equal(fieldConfig.BulkDensity, Constants.BulkDensity(SoilCategory, Texture));
Assert.Equal(fieldConfig.AWC, 3 * Constants.AWCpct[Texture] * (1 - Rocks / 100));
Assert.Equal(fieldConfig.PrePlantRainFactor, Constants.PPRainFactors[PrePlantRain]);
Assert.Equal(fieldConfig.InCropRainFactor, Constants.ICRainFactors[InCropRain]);
Expand All @@ -56,21 +57,21 @@ public void Test_FieldConfig_Both_Constructors_Match()
{
var fieldConfig = new FieldConfig
{
SoilCategory = SoilCategory,
SoilTexture = Texture,
Category = SoilCategory,
Texture = Texture,
PMN = PMN,
Splits = Splits,
_rawRocks = Rocks,
_sampleDepth = SampleDepth,
SampleDepth = SampleDepth,
_prePlantRain = PrePlantRain,
_inCropRain = InCropRain,
_irrigation = Irrigation
};

var fieldConfigExcel = new FieldConfig(ExcelInputDict);

Assert.Equal(fieldConfig.SoilCategory, fieldConfigExcel.SoilCategory);
Assert.Equal(fieldConfig.SoilTexture, fieldConfigExcel.SoilTexture);
Assert.Equal(fieldConfig.Category, fieldConfigExcel.Category);
Assert.Equal(fieldConfig.Texture, fieldConfigExcel.Texture);
Assert.Equal(fieldConfig.Rocks, fieldConfigExcel.Rocks);
Assert.Equal(fieldConfig.SampleDepthFactor, fieldConfigExcel.SampleDepthFactor);
Assert.Equal(fieldConfig.BulkDensity, fieldConfigExcel.BulkDensity);
Expand Down
94 changes: 62 additions & 32 deletions SVSModel/Configuration/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// Copyright (c) 2024 The New Zealand Institute for Plant and Food Research Limited

using System.Collections.Generic;
using System.ComponentModel;
using static SVSModel.Configuration.InputCategories;

namespace SVSModel.Configuration
{
Expand All @@ -14,8 +16,8 @@ public static class Constants
/// <summary>Dictionary containing values for the proportion of maximum DM that occurs at each predefined crop stage</summary>
public static readonly Dictionary<string, double> PropnMaxDM = new()
{
{ "Seed", 0.0066 },
{ "Seedling", 0.015 },
{ "Seed", 0.004 },
{ "Seedling", 0.011 },
{ "Vegetative", 0.5 },
{ "EarlyReproductive", 0.75 },
{ "MidReproductive", 0.86 },
Expand All @@ -27,14 +29,14 @@ public static class Constants
/// <summary>Dictionary containing values for the proportion of thermal time to maturity that has accumulate at each predefined crop stage</summary>
public static readonly Dictionary<string, double> PropnTt = new()
{
{ "Seed", 0 },
{ "Seedling", 0.16 },
{ "Seed", -0.0517 },
{ "Seedling", 0.050 },
{ "Vegetative", 0.5 },
{ "EarlyReproductive", 0.61 },
{ "MidReproductive", 0.69 },
{ "LateReproductive", 0.8 },
{ "Maturity", 1.0 },
{ "Late", 1.27 }
{ "EarlyReproductive", 0.5847 },
{ "MidReproductive", 0.6815 },
{ "LateReproductive", 0.7944 },
{ "Maturity", 0.999 },
{ "Late", 1.2957 }
};

/// <summary>Dictionary containing conversion from specified units to kg/ha which are the units that the model works in </summary>
Expand Down Expand Up @@ -102,38 +104,44 @@ public static class Constants
/// <summary>Sample depth factor to adjust measurments to equivelent of 30cm measure</summary>
public static readonly Dictionary<string, double> SampleDepthFactor = new()
{
{ "0-15cm", 0.75 },
{ "0-30cm", 1 }
{ "Top15cm", 0.75 },
{ "Top30cm", 1 },
{ "Top60cm", 1.25 },
{ "Top90cm", 1.5 }
};

/// <summary>Available water capacity %</summary>
public static readonly Dictionary<string, double> AWCpct = new()
{
{ "Sand", 8 },
{ "Loamy sand", 18 },
{ "Sandy loam", 23 },
{ "Sandy clay loam", 16 },
{ "Loam", 22 },
{ "Silt loam", 22 },
{ "Silty clay loam", 20 },
{ "Clay loam", 18 },
{ "Silty clay", 20 },
{ "Clay", 18 },
{ "Sand", 8 },
{ "LoamySand", 18 },
{ "SandyLoam", 23 },
{ "SandyClay", 20 },
{ "SandyClayLoam", 16 },
{ "Loam", 22 },
{ "Silt", 22 },
{ "SiltLoam", 22 },
{ "SiltyClayLoam", 20 },
{ "ClayLoam", 18 },
{ "SiltyClay", 20 },
{ "Clay", 18 },
};

/// <summary>The porocity (mm3 pores/mm3 soil volume) of different soil texture classes</summary>
public static readonly Dictionary<string, double> Porosity = new()
{
{ "Sand", 0.5 },
{ "Loamy sand", 0.51 },
{ "Sandy loam", 0.52 },
{ "Sandy clay loam", 0.56 },
{ "Loam", 0.54 },
{ "Silt loam", 0.55 },
{ "Silty clay loam", 0.58 },
{ "Clay loam", 0.58 },
{ "Silty clay", 0.61 },
{ "Clay", 0.63 },
{ "Sand", 0.5 },
{ "LoamySand", 0.51 },
{ "SandyLoam", 0.52 },
{ "SandyClay", 0.54 },
{ "SandyClayLoam", 0.56 },
{ "Loam", 0.54 },
{ "Silt", 0.54 },
{ "SiltLoam", 0.55 },
{ "SiltyClayLoam", 0.58 },
{ "ClayLoam", 0.58 },
{ "SiltyClay", 0.61 },
{ "Clay", 0.63 },
};

/// <summary>particle bulk density (g/mm3)</summary>
Expand All @@ -142,5 +150,27 @@ public static class Constants
{ "Sedimentary", 2.65 },
{ "Volcanic", 1.9 },
};

public static double BulkDensity(string soilCategory, string soilTexture)
{
return Constants.ParticleDensity[soilCategory] * (1 - Constants.Porosity[soilTexture]);
}

public static readonly Dictionary<string, Dictionary<string, double>> MoistureFactor = new Dictionary<string, Dictionary<string, double>>()
{
{"Clay", new Dictionary<string, double>() { { "Dry", 1.8}, { "Moist", 1.5},{ "Wet", 1.3} } },
{"ClayLoam", new Dictionary<string, double>() { { "Dry", 1.7}, { "Moist", 1.4},{ "Wet", 1.3} } },
{"Loam", new Dictionary<string, double>() { { "Dry", 2.0}, { "Moist", 1.5},{ "Wet", 1.3} } },
{"LoamySand", new Dictionary<string, double>() { { "Dry", 1.8}, { "Moist", 1.5},{ "Wet", 1.4} } },
{"Sand", new Dictionary<string, double>() { { "Dry", 1.8}, { "Moist", 1.5},{ "Wet", 1.4} } },
{"SandyClay", new Dictionary<string, double>() { { "Dry", 1.8}, { "Moist", 1.4},{ "Wet", 1.3} } },
{"SandyClayLoam", new Dictionary<string, double>() { { "Dry", 1.9}, { "Moist", 1.6},{ "Wet", 1.4} } },
{"SandyLoam", new Dictionary<string, double>() { { "Dry", 2.1}, { "Moist", 1.8},{ "Wet", 1.5} } },
{"Silt", new Dictionary<string, double>() { { "Dry", 1.9}, { "Moist", 1.4},{ "Wet", 1.3} } },
{"SiltLoam", new Dictionary<string, double>() { { "Dry", 1.7}, { "Moist", 1.4},{ "Wet", 1.3} } },
{"SiltyClay", new Dictionary<string, double>() { { "Dry", 1.9}, { "Moist", 1.6},{ "Wet", 1.4} } },
{"SiltyClayLoam", new Dictionary<string, double>() { { "Dry", 1.9}, { "Moist", 1.5},{ "Wet", 1.4} } },
};
}
}
}

4 changes: 4 additions & 0 deletions SVSModel/Configuration/CropParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public double TypicalYield_kgPerHa
public double RootN { get; private set; }
public double StoverN { get; private set; }
public double ProductN { get; private set; }
public double TtSowtoEmerge { get; private set; }
public double Tbase { get; private set; }

public CropParams(Dictionary<string, object> c)
{
Expand All @@ -60,6 +62,8 @@ public CropParams(Dictionary<string, object> c)
RootN = Functions.Num(c["Root [N]"]);
StoverN = Functions.Num(c["Stover [N]"]);
ProductN = Functions.Num(c["Product [N]"]);
TtSowtoEmerge = Functions.Num(c["TtEmerg"]);
Tbase = Functions.Num(c["Tbase"].ToString());
}
}
}
24 changes: 13 additions & 11 deletions SVSModel/Configuration/FieldConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// Author: Hamish Brown.
// Copyright (c) 2024 The New Zealand Institute for Plant and Food Research Limited

using System;
using System.Collections.Generic;
using static SVSModel.Configuration.InputCategories;

namespace SVSModel.Configuration
{
Expand All @@ -14,21 +16,21 @@ public class FieldConfig
{
// Inputs
public string WeatherStation { get; init; }
public string SoilCategory { get; init; }
public string SoilTexture { get; init; }
public string Category { get; init; }
public string Texture { get; init; }
public double PMN { get; init; }
public int Splits { get; init; }
public double _rawRocks { internal get; init; }
public string _sampleDepth { internal get; init; }
public string SampleDepth { internal get; init; }
public string _prePlantRain { internal get; init; }
public string _inCropRain { internal get; init; }
public string _irrigation { internal get; init; }

// Calculated fields
public double Rocks => _rawRocks / 100;
public double SampleDepthFactor => Constants.SampleDepthFactor[_sampleDepth];
public double BulkDensity => Constants.ParticleDensity[SoilCategory] * Constants.Porosity[SoilTexture];
public double AWC => 3 * Constants.AWCpct[SoilTexture] * (1 - Rocks);
public double SampleDepthFactor => Constants.SampleDepthFactor[SampleDepth];
public double BulkDensity => Constants.BulkDensity(Category, Texture);
public double AWC => 3 * Constants.AWCpct[Texture] * (1 - Rocks);
public double PrePlantRainFactor => Constants.PPRainFactors[_prePlantRain];
public double InCropRainFactor => Constants.ICRainFactors[_inCropRain];
public double IrrigationTrigger => Constants.IrrigationTriggers[_irrigation];
Expand All @@ -46,13 +48,13 @@ public FieldConfig(Dictionary<string, object> c)
{
// Only raw input values should be set in here
WeatherStation = c["WeatherStation"].ToString();
SoilCategory = c["SoilCategory"].ToString();
SoilTexture = c["Texture"].ToString();
Category = c["SoilCategory"].ToString();
Texture = c["Texture"].ToString();
PMN = Functions.Num(c["PMN"]);
Splits = int.Parse(c["Splits"].ToString());

_rawRocks = Functions.Num(c["Rocks"]);
_sampleDepth = c["SampleDepth"].ToString();
SampleDepth = c["SampleDepth"].ToString();
_prePlantRain = c["PrePlantRain"].ToString();
_inCropRain = c["InCropRain"].ToString();
_irrigation = c["Irrigation"].ToString();
Expand Down
9 changes: 7 additions & 2 deletions SVSModel/Configuration/Functions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,12 @@ public static DateTime[] DateSeries(DateTime start, DateTime end)
/// </summary>
/// <param name="Tt">array of daily average temperatures</param>
/// <returns>Array of accumulated thermal time</returns>
public static Dictionary<DateTime, double> AccumulateTt(DateTime[] dates, Dictionary<DateTime, double> Tt)
public static Dictionary<DateTime, double> AccumulateTt(DateTime[] dates, Dictionary<DateTime, double> Tt, double Tbase)
{
Dictionary<DateTime, double> tt = new Dictionary<DateTime, double>();
foreach (DateTime d in dates)
{
double todayTt = Math.Max(0,Tt[d] - 5);
double todayTt = Math.Max(0,Tt[d] - Tbase);
if (d == dates[0]) // if today is the first day the below will throw
{
tt.Add(d, todayTt);
Expand Down Expand Up @@ -294,5 +294,10 @@ public static double sumOverDates(DateTime start, DateTime end, Dictionary<DateT
}
return ret;
}

public static double sigmoid(double dX, double Xo, double b)
{
return 1 / (1 + Math.Exp(-(dX - Xo) / b));
}
}
}
Loading
Loading