Skip to content

Commit 3cb6197

Browse files
committed
add unit tests for calculating objective functions
1 parent 3e15f59 commit 3cb6197

5 files changed

Lines changed: 219 additions & 1 deletion

File tree

BlueM.Opt.sln

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SensiPlot_ParameterSampling
3636
EndProject
3737
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BlueM.Opt.Tests", "BlueM.Opt.Tests", "{2846C8D3-E679-4D5C-95B4-4CF3E4BF7122}"
3838
EndProject
39+
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BlueM.Opt.Tests", "BlueM.Opt\Tests\BlueM.Opt.Tests\BlueM.Opt.Tests.vbproj", "{69B4CC2F-9BBB-DE40-7F29-C0F416AF0222}"
40+
EndProject
3941
Global
4042
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4143
Debug|x64 = Debug|x64
@@ -162,6 +164,11 @@ Global
162164
{2BC34399-890A-4C37-85A4-3F8D633835B9}.Debug|x86.Build.0 = Debug|x86
163165
{2BC34399-890A-4C37-85A4-3F8D633835B9}.Release|x64.ActiveCfg = Release|x64
164166
{2BC34399-890A-4C37-85A4-3F8D633835B9}.Release|x86.ActiveCfg = Release|x86
167+
{69B4CC2F-9BBB-DE40-7F29-C0F416AF0222}.Debug|x64.ActiveCfg = Debug|x64
168+
{69B4CC2F-9BBB-DE40-7F29-C0F416AF0222}.Debug|x64.Build.0 = Debug|x64
169+
{69B4CC2F-9BBB-DE40-7F29-C0F416AF0222}.Debug|x86.ActiveCfg = Debug|x64
170+
{69B4CC2F-9BBB-DE40-7F29-C0F416AF0222}.Release|x64.ActiveCfg = Release|x64
171+
{69B4CC2F-9BBB-DE40-7F29-C0F416AF0222}.Release|x86.ActiveCfg = Release|x64
165172
EndGlobalSection
166173
GlobalSection(SolutionProperties) = preSolution
167174
HideSolutionNode = FALSE
@@ -175,6 +182,7 @@ Global
175182
{A9272445-616D-4B4F-ACFF-DE6F5591AF63} = {44D440EE-4641-44A1-B177-2DD0FDD6FB75}
176183
{6FCD5583-4A2A-4298-8A48-D46FAEFC5D7C} = {44D440EE-4641-44A1-B177-2DD0FDD6FB75}
177184
{2BC34399-890A-4C37-85A4-3F8D633835B9} = {2846C8D3-E679-4D5C-95B4-4CF3E4BF7122}
185+
{69B4CC2F-9BBB-DE40-7F29-C0F416AF0222} = {2846C8D3-E679-4D5C-95B4-4CF3E4BF7122}
178186
EndGlobalSection
179187
GlobalSection(ExtensibilityGlobals) = postSolution
180188
SolutionGuid = {4558EFAB-BB97-40C0-BF67-4380356C931B}

BlueM.Opt/Common/ObjectiveFunctions/ObjectiveFunction.vb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ Public MustInherit Class ObjectiveFunction
175175
''' <param name="[Function]">comparison function</param>
176176
''' <returns>function value</returns>
177177
''' <remarks>Konstante und gleiche Zeitschrittweiten vorausgesetzt! (#151)</remarks>
178-
Protected Shared Function compareSeries(ByVal SimSeries As Wave.TimeSeries, ByVal RefSeries As Wave.TimeSeries, ByVal [Function] As String) As Double
178+
Public Shared Function compareSeries(ByVal SimSeries As Wave.TimeSeries, ByVal RefSeries As Wave.TimeSeries, ByVal [Function] As String) As Double
179179

180180
Dim objectiveValue As Double
181181
Dim i As Integer
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="MSTest.Sdk/3.6.4">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net48</TargetFramework>
5+
<LangVersion>latest</LangVersion>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<!--
9+
Displays error on console in addition to the log file. Note that this feature comes with a performance impact.
10+
For more information, visit https://learn.microsoft.com/dotnet/core/testing/unit-testing-platform-integration-dotnet-test#show-failure-per-test
11+
-->
12+
<TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
13+
<Platforms>x64</Platforms>
14+
</PropertyGroup>
15+
16+
<ItemGroup>
17+
<Compile Remove="Test1.vb" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<ProjectReference Include="..\..\..\BlueM.Wave\source\Wave.vbproj" />
22+
<ProjectReference Include="..\..\Common\BlueM.Opt.Common.vbproj" />
23+
</ItemGroup>
24+
25+
</Project>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Imports Microsoft.VisualStudio.TestTools.UnitTesting
2+
3+
<Assembly: Parallelize(Scope:=ExecutionScope.MethodLevel)>
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
'BlueM.Opt
2+
'Copyright (C) BlueM Dev Group
3+
'Website: <https://www.bluemodel.org>
4+
'
5+
'This program is free software: you can redistribute it and/or modify
6+
'it under the terms of the GNU General Public License as published by
7+
'the Free Software Foundation, either version 3 of the License, or
8+
'(at your option) any later version.
9+
'
10+
'This program is distributed in the hope that it will be useful,
11+
'but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
'GNU General Public License for more details.
14+
'
15+
'You should have received a copy of the GNU General Public License
16+
'along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
'
18+
Imports Microsoft.VisualStudio.TestTools.UnitTesting
19+
Imports BlueM.Opt.Common
20+
Imports BlueM.Wave
21+
22+
<TestClass>
23+
Public Class TestObjectiveFunctions
24+
25+
Private Function CreateTimeSeries(values As Double(), Optional title As String = "Test") As TimeSeries
26+
Dim ts As New TimeSeries()
27+
ts.Title = title
28+
ts.Interpretation = TimeSeries.InterpretationEnum.BlockRight
29+
Dim startdate As New DateTime(2020, 1, 1)
30+
For i = 0 To values.Length - 1
31+
ts.AddNode(startdate.AddDays(i), values(i))
32+
Next
33+
Return ts
34+
End Function
35+
36+
<TestMethod>
37+
Public Sub CompareSeries_SSE_ReturnsSumOfSquaredErrors()
38+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
39+
Dim ref As TimeSeries = CreateTimeSeries({2.0, 2.0, 2.0})
40+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "SSE")
41+
Assert.AreEqual(2.0, result, 0.000001)
42+
End Sub
43+
44+
<TestMethod>
45+
Public Sub CompareSeries_MSE_ReturnsMeanSquaredError()
46+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
47+
Dim ref As TimeSeries = CreateTimeSeries({2.0, 2.0, 2.0})
48+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "MSE")
49+
Assert.AreEqual(2.0 / 3.0, result, 0.000001)
50+
End Sub
51+
52+
<TestMethod>
53+
Public Sub CompareSeries_SAE_ReturnsSumOfAbsoluteErrors()
54+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
55+
Dim ref As TimeSeries = CreateTimeSeries({2.0, 2.0, 2.0})
56+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "SAE")
57+
Assert.AreEqual(2.0, result, 0.000001)
58+
End Sub
59+
60+
<TestMethod>
61+
Public Sub CompareSeries_MAE_ReturnsMeanAbsoluteError()
62+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
63+
Dim ref As TimeSeries = CreateTimeSeries({2.0, 2.0, 2.0})
64+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "MAE")
65+
Assert.AreEqual(2.0 / 3.0, result, 0.000001)
66+
End Sub
67+
68+
<TestMethod>
69+
Public Sub CompareSeries_BIAS_ReturnsAbsoluteVolumeError()
70+
Dim sim As TimeSeries = CreateTimeSeries({2.0, 3.0, 4.0})
71+
Dim ref As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
72+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "BIAS")
73+
Assert.AreEqual((9.0 - 6.0) / 6.0 * 100.0, result, 0.000001)
74+
End Sub
75+
76+
<TestMethod>
77+
Public Sub CompareSeries_NLT_ReturnsRelativeNumberOfTimestepsLessThan()
78+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
79+
Dim ref As TimeSeries = CreateTimeSeries({2.0, 2.0, 2.0})
80+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "NLT")
81+
Assert.AreEqual(1.0 / 3.0 * 100, result, 0.000001)
82+
End Sub
83+
84+
<TestMethod>
85+
Public Sub CompareSeries_SLT_ReturnsSumOfTimestepsLessThan()
86+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
87+
Dim ref As TimeSeries = CreateTimeSeries({2.0, 2.0, 2.0})
88+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "SLT")
89+
Assert.AreEqual(1.0, result, 0.000001)
90+
End Sub
91+
92+
<TestMethod>
93+
Public Sub CompareSeries_NGT_ReturnsRelativeNumberOfTimestepsGreaterThan()
94+
Dim sim As TimeSeries = CreateTimeSeries({3.0, 2.0, 1.0})
95+
Dim ref As TimeSeries = CreateTimeSeries({2.0, 2.0, 2.0})
96+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "NGT")
97+
Assert.AreEqual(1.0 / 3.0 * 100, result, 0.000001)
98+
End Sub
99+
100+
<TestMethod>
101+
Public Sub CompareSeries_SGT_ReturnsSumOfTimestepsGreaterThan()
102+
Dim sim As TimeSeries = CreateTimeSeries({3.0, 2.0, 1.0})
103+
Dim ref As TimeSeries = CreateTimeSeries({2.0, 2.0, 2.0})
104+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "SGT")
105+
Assert.AreEqual(1.0, result, 0.000001)
106+
End Sub
107+
108+
<TestMethod>
109+
Public Sub CompareSeries_APFB_ReturnsAnnualPeakFlowBias()
110+
'create timeseries with two years of monthly data
111+
Dim sim As New TimeSeries("sim")
112+
sim.Interpretation = TimeSeries.InterpretationEnum.BlockRight
113+
For i As Integer = 1 To 12
114+
sim.AddNode(New DateTime(2020, i, 1), i)
115+
sim.AddNode(New DateTime(2021, i, 1), i * 2)
116+
Next
117+
Dim ref As New TimeSeries("ref")
118+
ref.Interpretation = TimeSeries.InterpretationEnum.BlockRight
119+
For i As Integer = 1 To 12
120+
ref.AddNode(New DateTime(2020, i, 1), i * 1.1)
121+
ref.AddNode(New DateTime(2021, i, 1), i * 0.9 * 2)
122+
Next
123+
Dim peakSim = {12.0, 24.0}
124+
Dim peakRef = {13.2, 21.6}
125+
Dim expected = Math.Sqrt(Math.Pow((peakSim.Average() / peakRef.Average()) - 1.0, 2))
126+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "APFB")
127+
Assert.AreEqual(expected, result, 0.000001)
128+
End Sub
129+
130+
<TestMethod>
131+
Public Sub CompareSeries_NSE_ReturnsNashSutcliffeEfficiency()
132+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
133+
Dim ref As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
134+
' Identical series, NSE = 1
135+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "NSE")
136+
Assert.AreEqual(1.0, result, 0.000001)
137+
End Sub
138+
139+
<TestMethod>
140+
Public Sub CompareSeries_LNNSE_ReturnsLnNashSutcliffeEfficiency()
141+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
142+
Dim ref As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
143+
' Identical series, lnNSE = 1
144+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "LNNSE")
145+
Assert.AreEqual(1.0, result, 0.000001)
146+
End Sub
147+
148+
<TestMethod>
149+
Public Sub CompareSeries_DET_ReturnsCoefficientOfDetermination()
150+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
151+
Dim ref As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
152+
' Identical series, DET = 1
153+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "DET")
154+
Assert.AreEqual(1.0, result, 0.000001)
155+
End Sub
156+
157+
<TestMethod>
158+
Public Sub CompareSeries_KGE_ReturnsKlingGuptaEfficiency()
159+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
160+
Dim ref As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
161+
' Identical series, KGE = 1
162+
Dim result = ObjectiveFunction.compareSeries(sim, ref, "KGE")
163+
Assert.AreEqual(1.0, result, 0.000001)
164+
End Sub
165+
166+
<TestMethod>
167+
<ExpectedException(GetType(Exception))>
168+
Public Sub CompareSeries_DifferentLength_ThrowsException()
169+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0})
170+
Dim ref As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
171+
ObjectiveFunction.compareSeries(sim, ref, "SSE")
172+
End Sub
173+
174+
<TestMethod>
175+
<ExpectedException(GetType(Exception))>
176+
Public Sub CompareSeries_UnsupportedFunction_ThrowsException()
177+
Dim sim As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
178+
Dim ref As TimeSeries = CreateTimeSeries({1.0, 2.0, 3.0})
179+
ObjectiveFunction.compareSeries(sim, ref, "UNSUPPORTED")
180+
End Sub
181+
182+
End Class

0 commit comments

Comments
 (0)