1.3.49
 
Loading...
Searching...
No Matches
selfTest.cpp
1#include "SolarPosition.h"
2
3#define DOCTEST_CONFIG_IMPLEMENT
4#include <doctest.h>
5#include "doctest_utils.h"
6
7using namespace helios;
8
9TEST_CASE("SolarPosition sun position Boulder") {
10 Context context_s;
11
12 DOCTEST_CHECK_NOTHROW(context_s.setDate(make_Date(1, 1, 2000)));
13 DOCTEST_CHECK_NOTHROW(context_s.setTime(make_Time(10, 30, 0)));
14
15 SolarPosition sp(7, 40.1250f, 105.2369f, &context_s);
16 float theta_s = sp.getSunElevation() * 180.f / M_PI;
17 float phi_s = sp.getSunAzimuth() * 180.f / M_PI;
18
19 DOCTEST_CHECK(std::fabs(theta_s - 29.49f) <= 10.0f);
20 DOCTEST_CHECK(std::fabs(phi_s - 154.18f) <= 5.0f);
21}
22
23TEST_CASE("SolarPosition ambient longwave model") {
24 Context context_s;
25 DOCTEST_CHECK_NOTHROW(context_s.setDate(make_Date(5, 5, 2003)));
26 DOCTEST_CHECK_NOTHROW(context_s.setTime(make_Time(9, 10, 0)));
27
28 SolarPosition sp(6, 36.5289f, 97.4439f, &context_s);
29
30 float temperature = 290.f;
31 float humidity = 0.5f;
32
33 float LW;
34 DOCTEST_CHECK_NOTHROW(LW = sp.getAmbientLongwaveFlux(temperature, humidity));
35
36 DOCTEST_CHECK(doctest::Approx(310.03192f).epsilon(1e-6f) == LW);
37}
38
39TEST_CASE("SolarPosition sunrise and sunset") {
40 Context context_s;
41 DOCTEST_CHECK_NOTHROW(context_s.setDate(make_Date(1, 1, 2023)));
42 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
43
44 Time sunrise;
45 DOCTEST_CHECK_NOTHROW(sunrise = sp.getSunriseTime());
46 Time sunset;
47 DOCTEST_CHECK_NOTHROW(sunset = sp.getSunsetTime());
48
49 DOCTEST_CHECK(!(sunrise.hour == 0 && sunrise.minute == 0));
50 DOCTEST_CHECK(!(sunset.hour == 0 && sunset.minute == 0));
51}
52
53TEST_CASE("SolarPosition sun direction vector") {
54 Context context_s;
55 DOCTEST_CHECK_NOTHROW(context_s.setDate(make_Date(1, 1, 2023)));
56 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
57
58 vec3 dir;
59 DOCTEST_CHECK_NOTHROW(dir = sp.getSunDirectionVector());
60 DOCTEST_CHECK(dir.x != 0.f);
61 DOCTEST_CHECK(dir.y != 0.f);
62 DOCTEST_CHECK(dir.z != 0.f);
63}
64
65TEST_CASE("SolarPosition sun direction spherical") {
66 Context context_s;
67 DOCTEST_CHECK_NOTHROW(context_s.setDate(make_Date(1, 1, 2023)));
68 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
69
71 DOCTEST_CHECK_NOTHROW(dir = sp.getSunDirectionSpherical());
72 DOCTEST_CHECK(dir.elevation > 0.f);
73 DOCTEST_CHECK(dir.azimuth > 0.f);
74}
75
76TEST_CASE("SolarPosition flux and fractions") {
77 Context context_s;
78 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
79
80 float flux;
81 DOCTEST_CHECK_NOTHROW(flux = sp.getSolarFlux(101325.f, 300.f, 0.5f, 0.02f));
82 DOCTEST_CHECK(flux > 0.f);
83
84 float diffuse_fraction;
85 DOCTEST_CHECK_NOTHROW(diffuse_fraction = sp.getDiffuseFraction(101325.f, 300.f, 0.5f, 0.02f));
86 DOCTEST_CHECK(diffuse_fraction >= 0.f);
87 DOCTEST_CHECK(diffuse_fraction <= 1.f);
88
89 float flux_par;
90 DOCTEST_CHECK_NOTHROW(flux_par = sp.getSolarFluxPAR(101325.f, 300.f, 0.5f, 0.02f));
91 DOCTEST_CHECK(flux_par > 0.f);
92
93 float flux_nir;
94 DOCTEST_CHECK_NOTHROW(flux_nir = sp.getSolarFluxNIR(101325.f, 300.f, 0.5f, 0.02f));
95 DOCTEST_CHECK(flux_nir > 0.f);
96}
97
98TEST_CASE("SolarPosition elevation, zenith, azimuth") {
99 Context context_s;
100 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
101
102 float elevation;
103 DOCTEST_CHECK_NOTHROW(elevation = sp.getSunElevation());
104 DOCTEST_CHECK(elevation >= 0.f);
105 DOCTEST_CHECK(elevation <= M_PI / 2.f);
106
107 float zenith;
108 DOCTEST_CHECK_NOTHROW(zenith = sp.getSunZenith());
109 DOCTEST_CHECK(zenith >= 0.f);
110 DOCTEST_CHECK(zenith <= M_PI);
111
112 float azimuth;
113 DOCTEST_CHECK_NOTHROW(azimuth = sp.getSunAzimuth());
114 DOCTEST_CHECK(azimuth >= 0.f);
115 DOCTEST_CHECK(azimuth <= 2.f * M_PI);
116}
117
118TEST_CASE("SolarPosition turbidity calibration") {
119 Context context_s;
120 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
121 std::string label = "test_flux_timeseries";
122
123 if (!context_s.doesTimeseriesVariableExist(label.c_str())) {
124 return; // skip test if data does not exist
125 }
126
127 float turbidity;
128 DOCTEST_CHECK_NOTHROW(turbidity = sp.calibrateTurbidityFromTimeseries(label));
129 DOCTEST_CHECK(turbidity > 0.f);
130}
131
132TEST_CASE("SolarPosition invalid lat/long") {
133 Context context_s;
134
135 capture_cerr cerr_buffer;
136 SolarPosition sp_1(7, -100.f, 105.2369f, &context_s);
137 DOCTEST_CHECK(cerr_buffer.has_output());
138
139 cerr_buffer.clear();
140 SolarPosition sp_2(7, 40.125f, -200.f, &context_s);
141 DOCTEST_CHECK(cerr_buffer.has_output());
142}
143
144TEST_CASE("SolarPosition invalid solar angle") {
145 Context context_s;
146 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
147
148 DOCTEST_CHECK_NOTHROW(sp.setSunDirection(make_SphericalCoord(0.75 * M_PI, M_PI / 2.f)));
149
150 float flux;
151 DOCTEST_CHECK_NOTHROW(flux = sp.getSolarFlux(101325.f, 300.f, 0.5f, 0.02f));
152 DOCTEST_CHECK(flux == 0.f);
153}
154
155
156TEST_CASE("SolarPosition solor position overridden") {
157 Context context_s;
158 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
159
160 DOCTEST_CHECK_NOTHROW(sp.setSunDirection(make_SphericalCoord(M_PI / 4.f, M_PI / 2.f)));
161
162 float elevation;
163 DOCTEST_CHECK_NOTHROW(elevation = sp.getSunElevation());
164 DOCTEST_CHECK(elevation >= 0.f);
165 DOCTEST_CHECK(elevation <= M_PI / 2.f);
166
167 float zenith;
168 DOCTEST_CHECK_NOTHROW(zenith = sp.getSunZenith());
169 DOCTEST_CHECK(zenith >= 0.f);
170 DOCTEST_CHECK(zenith <= M_PI);
171
172 float azimuth;
173 DOCTEST_CHECK_NOTHROW(azimuth = sp.getSunAzimuth());
174 DOCTEST_CHECK(azimuth >= 0.f);
175 DOCTEST_CHECK(azimuth <= 2.f * M_PI);
176
177 vec3 sun_vector;
178 DOCTEST_CHECK_NOTHROW(sun_vector = sp.getSunDirectionVector());
179
180 SphericalCoord sun_spherical;
181 DOCTEST_CHECK_NOTHROW(sun_spherical = sp.getSunDirectionSpherical());
182}
183
184TEST_CASE("SolarPosition cloud calibration") {
185 Context context_s;
186 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
187
188 DOCTEST_CHECK_NOTHROW(context_s.loadTabularTimeseriesData("lib/testdata/cimis.csv", {"CIMIS"}, ","));
189
190 context_s.setDate(make_Date(13, 7, 2023));
191 context_s.setTime(make_Time(12, 0, 0));
192
193 DOCTEST_CHECK_NOTHROW(sp.enableCloudCalibration("net_radiation"));
194
195 float flux;
196 DOCTEST_CHECK_NOTHROW(flux = sp.getSolarFlux(101325.f, 300.f, 0.5f, 0.02f));
197 DOCTEST_CHECK(flux > 0.f);
198
199 float diffuse_fraction;
200 DOCTEST_CHECK_NOTHROW(diffuse_fraction = sp.getDiffuseFraction(101325.f, 300.f, 0.5f, 0.02f));
201 DOCTEST_CHECK(diffuse_fraction >= 0.f);
202 DOCTEST_CHECK(diffuse_fraction <= 1.f);
203
204 float flux_par;
205 DOCTEST_CHECK_NOTHROW(flux_par = sp.getSolarFluxPAR(101325.f, 300.f, 0.5f, 0.02f));
206 DOCTEST_CHECK(flux_par > 0.f);
207
208 float flux_nir;
209 DOCTEST_CHECK_NOTHROW(flux_nir = sp.getSolarFluxNIR(101325.f, 300.f, 0.5f, 0.02f));
210 DOCTEST_CHECK(flux_nir > 0.f);
211
212 DOCTEST_CHECK_NOTHROW(sp.disableCloudCalibration());
213
214 capture_cerr cerr_buffer;
215 DOCTEST_CHECK_THROWS_AS(sp.enableCloudCalibration("non_existent_timeseries"), std::runtime_error);
216}
217
218TEST_CASE("SolarPosition turbidity calculation") {
219 Context context_s;
220 SolarPosition sp(7, 40.125f, 105.2369f, &context_s);
221
222 DOCTEST_CHECK_NOTHROW(context_s.loadTabularTimeseriesData("lib/testdata/cimis.csv", {"CIMIS"}, ","));
223
224 float turbidity;
225 DOCTEST_CHECK_NOTHROW(turbidity = sp.calibrateTurbidityFromTimeseries("net_radiation"));
226 DOCTEST_CHECK(turbidity > 0.f);
227
228 capture_cerr cerr_buffer;
229 DOCTEST_CHECK_THROWS_AS(turbidity = sp.calibrateTurbidityFromTimeseries("non_existent_timeseries"), std::runtime_error);
230}
231
232int SolarPosition::selfTest(int argc, char **argv) {
233 return helios::runDoctestWithValidation(argc, argv);
234}