Skip to content

Commit

Permalink
Merge pull request #44 from HamishBrownPFR/CropStageTests
Browse files Browse the repository at this point in the history
Crop stage tests
  • Loading branch information
HamishBrownPFR authored May 29, 2024
2 parents f11404b + 328d64c commit de5c983
Show file tree
Hide file tree
Showing 276 changed files with 93,585 additions and 87,763 deletions.
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

0 comments on commit de5c983

Please sign in to comment.