3#define DOCTEST_CONFIG_IMPLEMENT
5#include "doctest_utils.h"
11DOCTEST_TEST_CASE(
"EnergyBalanceModel Equilibrium Test") {
13 std::vector<uint> UUIDs;
18 context_test.
setPrimitiveData(UUIDs,
"radiation_flux_LW",
float(2.f * 5.67e-8 * pow(Tref, 4)));
22 energymodeltest.disableMessages();
23 energymodeltest.addRadiationBand(
"LW");
24 DOCTEST_CHECK_NOTHROW(energymodeltest.run());
26 for (
int p = 0; p < UUIDs.size(); p++) {
28 DOCTEST_CHECK_NOTHROW(context_test.
getPrimitiveData(UUIDs.at(p),
"temperature", T));
29 DOCTEST_CHECK(T == doctest::Approx(Tref).epsilon(err_tol));
33DOCTEST_TEST_CASE(
"EnergyBalanceModel Energy Budget Closure") {
35 std::vector<uint> UUIDs_2;
40 context_2.
setPrimitiveData(UUIDs_2,
"radiation_flux_LW",
float(2.f * 5.67e-8 * pow(T, 4)));
45 energymodel_2.disableMessages();
46 energymodel_2.addRadiationBand(
"LW");
47 energymodel_2.addRadiationBand(
"SW");
48 DOCTEST_CHECK_NOTHROW(energymodel_2.run());
50 for (
int p = 0; p < UUIDs_2.size(); p++) {
51 float sensible_flux, latent_flux,
R, temperature;
54 DOCTEST_CHECK_NOTHROW(context_2.
getPrimitiveData(UUIDs_2.at(p),
"sensible_flux", sensible_flux));
55 DOCTEST_CHECK_NOTHROW(context_2.
getPrimitiveData(UUIDs_2.at(p),
"latent_flux", latent_flux));
56 DOCTEST_CHECK_NOTHROW(context_2.
getPrimitiveData(UUIDs_2.at(p),
"radiation_flux_LW",
R));
58 DOCTEST_CHECK_NOTHROW(context_2.
getPrimitiveData(UUIDs_2.at(p),
"radiation_flux_SW",
R));
60 DOCTEST_CHECK_NOTHROW(context_2.
getPrimitiveData(UUIDs_2.at(p),
"temperature", temperature));
62 float Rout = 2.f * 5.67e-8 * pow(temperature, 4);
63 float resid = Rin - Rout - sensible_flux - latent_flux;
64 DOCTEST_CHECK(resid == doctest::Approx(0.0f).epsilon(err_tol));
68DOCTEST_TEST_CASE(
"EnergyBalanceModel Temperature Solution Check 1") {
73 context_3.
setPrimitiveData(UUID_3,
"radiation_flux_LW",
float(5.67e-8 * pow(T, 4)));
84 energymodel_3.disableMessages();
85 energymodel_3.addRadiationBand(
"LW");
86 energymodel_3.addRadiationBand(
"SW");
87 DOCTEST_CHECK_NOTHROW(energymodel_3.run());
89 float sensible_flux, latent_flux, temperature;
90 float sensible_flux_exact = 48.7017;
91 float latent_flux_exact = 21.6094;
92 float temperature_exact = 329.307;
94 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"sensible_flux", sensible_flux));
95 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"latent_flux", latent_flux));
96 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"temperature", temperature));
98 DOCTEST_CHECK(sensible_flux == doctest::Approx(sensible_flux_exact).epsilon(err_tol));
99 DOCTEST_CHECK(latent_flux == doctest::Approx(latent_flux_exact).epsilon(err_tol));
100 DOCTEST_CHECK(temperature == doctest::Approx(temperature_exact).epsilon(err_tol));
103DOCTEST_TEST_CASE(
"EnergyBalanceModel Temperature Solution Check 2 - Object Length") {
108 context_3.
setPrimitiveData(UUID_3,
"radiation_flux_LW",
float(5.67e-8 * pow(T, 4)));
119 energymodel_3.disableMessages();
120 energymodel_3.addRadiationBand(
"LW");
121 energymodel_3.addRadiationBand(
"SW");
125 DOCTEST_CHECK_NOTHROW(energymodel_3.run());
127 float sensible_flux, latent_flux, temperature;
128 float sensible_flux_exact = 89.2024;
129 float latent_flux_exact = 20.0723;
130 float temperature_exact = 324.386;
132 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"sensible_flux", sensible_flux));
133 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"latent_flux", latent_flux));
134 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"temperature", temperature));
136 DOCTEST_CHECK(sensible_flux == doctest::Approx(sensible_flux_exact).epsilon(err_tol));
137 DOCTEST_CHECK(latent_flux == doctest::Approx(latent_flux_exact).epsilon(err_tol));
138 DOCTEST_CHECK(temperature == doctest::Approx(temperature_exact).epsilon(err_tol));
141DOCTEST_TEST_CASE(
"EnergyBalanceModel Temperature Solution Check 3 - Manual Boundary Layer Conductance") {
146 context_3.
setPrimitiveData(UUID_3,
"radiation_flux_LW",
float(5.67e-8 * pow(T, 4)));
157 energymodel_3.disableMessages();
158 energymodel_3.addRadiationBand(
"LW");
159 energymodel_3.addRadiationBand(
"SW");
162 context_3.
setPrimitiveData(UUID_3,
"boundarylayer_conductance",
float(0.134f));
163 DOCTEST_CHECK_NOTHROW(energymodel_3.run());
165 float sensible_flux, latent_flux, temperature;
166 float sensible_flux_exact = 61.5411f;
167 float latent_flux_exact = 21.6718f;
168 float temperature_exact = 327.701f;
170 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"sensible_flux", sensible_flux));
171 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"latent_flux", latent_flux));
172 DOCTEST_CHECK_NOTHROW(context_3.
getPrimitiveData(UUID_3,
"temperature", temperature));
174 DOCTEST_CHECK(sensible_flux == doctest::Approx(sensible_flux_exact).epsilon(err_tol));
175 DOCTEST_CHECK(latent_flux == doctest::Approx(latent_flux_exact).epsilon(err_tol));
176 DOCTEST_CHECK(temperature == doctest::Approx(temperature_exact).epsilon(err_tol));
179DOCTEST_TEST_CASE(
"EnergyBalanceModel Optional Primitive Data Output Check") {
184 energymodel_4.disableMessages();
185 energymodel_4.addRadiationBand(
"LW");
186 DOCTEST_CHECK_NOTHROW(energymodel_4.optionalOutputPrimitiveData(
"boundarylayer_conductance_out"));
187 DOCTEST_CHECK_NOTHROW(energymodel_4.optionalOutputPrimitiveData(
"vapor_pressure_deficit"));
190 DOCTEST_CHECK_NOTHROW(energymodel_4.run());
196DOCTEST_TEST_CASE(
"EnergyBalanceModel Dynamic Model Check") {
198 float dt_5 = 1.f, T_5 = 3600, To_5 = 300.f, cp_5 = 2000;
199 float Rlow = 50.f, Rhigh = 500.f;
209 energybalance_5.disableMessages();
210 energybalance_5.addRadiationBand(
"SW");
211 DOCTEST_CHECK_NOTHROW(energybalance_5.optionalOutputPrimitiveData(
"boundarylayer_conductance_out"));
213 std::vector<float> temperature_dyn;
214 int N = round(T_5 / dt_5);
215 for (
int t = 0; t < N; t++) {
219 DOCTEST_CHECK_NOTHROW(energybalance_5.run(dt_5));
222 DOCTEST_CHECK_NOTHROW(context_5.
getPrimitiveData(UUID_5,
"temperature", temp));
223 temperature_dyn.push_back(temp);
227 DOCTEST_CHECK_NOTHROW(context_5.
getPrimitiveData(UUID_5,
"boundarylayer_conductance_out", gH_5));
228 float tau_5 = cp_5 / gH_5 / 29.25f;
231 DOCTEST_CHECK_NOTHROW(energybalance_5.run());
233 DOCTEST_CHECK_NOTHROW(context_5.
getPrimitiveData(UUID_5,
"temperature", Tlow));
236 DOCTEST_CHECK_NOTHROW(energybalance_5.run());
238 DOCTEST_CHECK_NOTHROW(context_5.
getPrimitiveData(UUID_5,
"temperature", Thigh));
241 for (
int t = round(0.5f * N); t < N; t++) {
242 float time = dt_5 * (t - round(0.5f * N));
243 float temperature_ref = Tlow + (Thigh - Tlow) * (1.f - exp(-time / tau_5));
244 err += pow(temperature_ref - temperature_dyn.at(t), 2);
247 err = sqrt(err /
float(N));
248 DOCTEST_CHECK(err == doctest::Approx(0.0f).epsilon(0.2f));
251DOCTEST_TEST_CASE(
"EnergyBalanceModel Enable/Disable Messages") {
255 DOCTEST_CHECK_NOTHROW(testModel.enableMessages());
256 DOCTEST_CHECK_NOTHROW(testModel.disableMessages());
259DOCTEST_TEST_CASE(
"EnergyBalanceModel Radiation Band Management") {
263 DOCTEST_CHECK_NOTHROW(testModel.addRadiationBand(
"LW"));
264 DOCTEST_CHECK_NOTHROW(testModel.addRadiationBand(
"LW"));
265 DOCTEST_CHECK_NOTHROW(testModel.addRadiationBand(
"SW"));
268DOCTEST_TEST_CASE(
"EnergyBalanceModel Optional Output Primitive Data") {
272 DOCTEST_CHECK_NOTHROW(testModel.optionalOutputPrimitiveData(
"boundarylayer_conductance_out"));
275 DOCTEST_CHECK_NOTHROW(testModel.optionalOutputPrimitiveData(
"invalid_label"));
279DOCTEST_TEST_CASE(
"EnergyBalanceModel Print Default Value Report") {
283 std::stringstream buffer;
284 std::streambuf *old = std::cout.rdbuf(buffer.rdbuf());
286 DOCTEST_CHECK_NOTHROW(testModel.printDefaultValueReport());
288 std::cout.rdbuf(old);
290 std::string output = buffer.str();
291 std::vector<std::string> required_keywords = {
"surface temperature",
"air pressure",
"air temperature",
"air humidity",
"boundary-layer conductance",
"moisture conductance",
"surface humidity",
"two-sided flag",
"evaporating faces"};
293 for (
const auto &keyword: required_keywords) {
294 DOCTEST_CHECK(output.find(keyword) != std::string::npos);
298DOCTEST_TEST_CASE(
"EnergyBalanceModel Print Default Value Report with UUIDs") {
301 std::vector<uint> testUUIDs;
304 std::stringstream buffer;
305 std::streambuf *old = std::cout.rdbuf(buffer.rdbuf());
307 DOCTEST_CHECK_NOTHROW(testModel.printDefaultValueReport(testUUIDs));
309 std::cout.rdbuf(old);
311 std::string output = buffer.str();
312 std::vector<std::string> required_keywords = {
"surface temperature",
"air pressure",
"air temperature",
"air humidity",
"boundary-layer conductance",
"moisture conductance",
"surface humidity",
"two-sided flag",
"evaporating faces"};
314 for (
const auto &keyword: required_keywords) {
315 DOCTEST_CHECK(output.find(keyword) != std::string::npos);
319DOCTEST_TEST_CASE(
"EnergyBalanceModel Additional Dynamic Model Check") {
321 float dt = 1.f, Tfinal = 3600, To = 300.f, cp = 2000;
322 float Rlow = 50.f, Rhigh = 500.f;
332 energybalance_dyn.disableMessages();
333 energybalance_dyn.addRadiationBand(
"SW");
335 std::vector<float> temperature_dyn;
336 int N = round(Tfinal / dt);
337 for (
int t = 0; t < N; t++) {
341 DOCTEST_CHECK_NOTHROW(energybalance_dyn.run(dt));
344 DOCTEST_CHECK_NOTHROW(context_dyn.
getPrimitiveData(UUID_dyn,
"temperature", temp));
345 temperature_dyn.push_back(temp);
348 DOCTEST_CHECK(!temperature_dyn.empty());
352 return helios::runDoctestWithValidation(argc, argv);