2023-01-09 16:06:22 +00:00
|
|
|
import numpy.testing as npt
|
2024-06-27 14:55:30 +00:00
|
|
|
import numpy as np
|
|
|
|
|
import typing
|
2023-01-09 16:06:22 +00:00
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
from caimira import models
|
|
|
|
|
|
|
|
|
|
|
2024-06-27 14:55:30 +00:00
|
|
|
@pytest.fixture
|
|
|
|
|
def real_sensor_data():
|
|
|
|
|
day_times = [8.0, 8.033333333333333, 8.066666666666666, 8.1, 8.133333333333333, 8.166666666666666, 8.2, 8.233333333333333, 8.266666666666667, 8.3, 8.333333333333334, 8.366666666666667, 8.4, 8.433333333333334, 8.466666666666667, 8.5, 8.533333333333333, 8.566666666666666, 8.6, 8.633333333333333, 8.666666666666666, 8.7, 8.733333333333333, 8.766666666666667, 8.8, 8.833333333333334, 8.866666666666667, 8.9, 8.933333333333334, 8.966666666666667, 9.0, 9.033333333333333, 9.066666666666666, 9.1, 9.133333333333333, 9.166666666666666, 9.2, 9.233333333333333, 9.266666666666667, 9.3, 9.333333333333334, 9.366666666666667, 9.4, 9.433333333333334, 9.466666666666667, 9.5, 9.533333333333333, 9.566666666666666, 9.6, 9.633333333333333, 9.666666666666666, 9.7, 9.733333333333333, 9.766666666666667, 9.8, 9.833333333333334, 9.866666666666667, 9.9, 9.933333333333334, 9.966666666666667, 10.0, 10.033333333333333, 10.066666666666666, 10.1, 10.133333333333333, 10.166666666666666, 10.2, 10.233333333333333, 10.266666666666667, 10.3, 10.333333333333334, 10.366666666666667, 10.4, 10.433333333333334, 10.466666666666667, 10.5, 10.533333333333333, 10.566666666666666, 10.6, 10.633333333333333, 10.666666666666666, 10.7, 10.733333333333333, 10.766666666666667, 10.8, 10.833333333333334, 10.866666666666667, 10.9, 10.933333333333334, 10.966666666666667, 11.0, 11.033333333333333, 11.066666666666666, 11.1, 11.133333333333333, 11.166666666666666, 11.2, 11.233333333333333, 11.266666666666667, 11.3, 11.333333333333334, 11.366666666666667, 11.4, 11.433333333333334, 11.466666666666667, 11.5, 11.533333333333333, 11.566666666666666, 11.6, 11.633333333333333, 11.666666666666666, 11.7, 11.733333333333333, 11.766666666666667, 11.8, 11.833333333333334, 11.866666666666667, 11.9, 11.933333333333334, 11.966666666666667, 12.0, 12.033333333333333, 12.066666666666666, 12.1, 12.133333333333333, 12.166666666666666, 12.2, 12.233333333333333, 12.26666666666667, 12.3, 12.333333333333336, 12.366666666666667, 12.400000000000002, 12.433333333333334, 12.466666666666669, 12.5, 12.533333333333335, 12.566666666666666, 12.600000000000001, 12.633333333333333, 12.666666666666668, 12.7, 12.733333333333334, 12.766666666666666, 12.8, 12.833333333333332, 12.866666666666667, 12.899999999999999, 12.933333333333334, 12.966666666666665, 13.0, 13.033333333333331, 13.066666666666666, 13.099999999999998, 13.133333333333333, 13.166666666666664, 13.2, 13.23333333333333, 13.266666666666667, 13.3, 13.333333333333334, 13.366666666666667, 13.4, 13.433333333333334, 13.466666666666667, 13.5, 13.533333333333333, 13.566666666666666, 13.6, 13.633333333333333, 13.666666666666666, 13.7, 13.733333333333333, 13.76666666666667, 13.8, 13.833333333333336, 13.866666666666667, 13.900000000000002, 13.933333333333334, 13.966666666666669, 14.0, 14.033333333333335, 14.066666666666666, 14.100000000000001, 14.133333333333333, 14.166666666666668, 14.2, 14.233333333333334, 14.266666666666666, 14.3, 14.333333333333332, 14.366666666666667, 14.399999999999999, 14.433333333333334, 14.466666666666665, 14.5, 14.533333333333331, 14.566666666666666, 14.599999999999998, 14.633333333333333, 14.666666666666664, 14.7, 14.73333333333333, 14.766666666666667, 14.8, 14.833333333333334, 14.866666666666667, 14.9, 14.933333333333334, 14.966666666666667, 15.0, 15.033333333333333, 15.066666666666666, 15.1, 15.133333333333333, 15.166666666666666, 15.2, 15.233333333333333, 15.26666666666667, 15.3, 15.333333333333336, 15.366666666666667, 15.400000000000002, 15.433333333333334, 15.466666666666669, 15.5, 15.533333333333335, 15.566666666666666, 15.600000000000001, 15.633333333333333, 15.666666666666668, 15.7, 15.733333333333334, 15.766666666666666, 15.8, 15.833333333333332, 15.866666666666667, 15.899999999999999, 15.933333333333334, 15.966666666666665, 16.0, 16.033333333333335, 16.066666666666666, 16.1, 16.133333333333333, 16.166666666666668, 16.2, 16.233333333333334, 16.266666666666666, 16.3, 16.333333333333332, 16.366666666666667, 16.4, 16.433333333333334, 16.466666666666665, 16.5, 16.533333333333335, 16.566666666666666, 16.6, 16.633333333333333, 16.6666
|
|
|
|
|
day_co2 = [445.189166666667, 443.284166666667, 440.908333333333, 443.430833333333, 442.365833333333, 444.094166666667, 445.151666666667, 445.655833333333, 447.9675, 447.998333333333, 443.95, 442.546666666667, 439.313333333333, 438.225, 441.4325, 441.19, 443.804166666667, 445.173333333333, 446.494166666667, 445.2775, 452.073333333333, 458.844166666667, 470.828333333333, 478.146666666667, 488.3375, 502.125833333333, 522.056666666667, 545.519166666667, 579.880833333333, 616.245, 641.154166666667, 676.288333333333, 701.9375, 720.464166666667, 746.933333333333, 765.83, 779.098333333333, 794.173333333333, 810.624166666667, 825.966666666667, 838.34, 854.355, 876.381666666667, 886.208333333334, 898.408333333333, 921.7175, 942.848333333333, 953.811666666667, 978.955833333333, 990.320833333333, 1002.93083333333, 1017.36083333333, 1029.37916666667, 1041.02833333333, 1051.8825, 1067.22, 1073.53, 1079.73833333333, 1093.73333333333, 1104.81416666667, 1125.7975, 1141.115, 1151.04583333333, 1160.0525, 1176.36666666667, 1193.665, 1180.10416666667, 1015.33416666667, 864.745833333333, 802.680833333333, 774.455, 728.268333333333, 697.325833333333, 676.063333333333, 657.555, 640.564166666667, 606.534166666667, 595.925, 577.7525, 553.605, 530.2125, 524.968333333333, 523.1525, 521.534166666667, 512.944166666667, 505.296666666667, 502.055833333333, 502.463333333333, 505.2475, 507.476666666667, 509.170833333333, 511.3125, 513.78, 520.3925, 529.136666666667, 532.798333333333, 530.110833333333, 523.964166666667, 521.574166666667, 519.051666666667, 510.294166666667, 509.981666666667, 514.349166666667, 518.395833333333, 524.6025, 521.003333333333, 519.448333333333, 523.3125, 527.46, 528.325833333333, 526.355, 527.008333333333, 529.9675, 534.019166666667, 535.615833333333, 533.514166666667, 530.551666666667, 522.348333333333, 524.2425, 532.020833333333, 539.126666666667, 538.835833333333, 526.185833333333, 517.509166666667, 507.993333333333, 493.7025, 485.631666666667, 479.526666666667, 471.584166666667, 472.225833333333, 468.205833333333, 463.099166666667, 461.0375, 458.98, 456.354166666667, 458.615, 459.161666666667, 462.9625, 465.558333333333, 468.448333333333, 475.206666666667, 480.3225, 488.961666666667, 527.991818181818, 579.613333333333, 606.594166666667, 611.2175, 617.0225, 635.926666666667, 651.079166666667, 676.646666666667, 696.63, 714.603333333333, 729.926666666667, 744.6525, 765.995833333333, 788.4925, 812.105833333333, 832.75, 854.715, 883.851666666667, 895.591666666667, 910.026666666667, 924.373333333333, 944.516666666667, 956.769166666667, 971.446666666667, 981.2725, 993.645833333333, 1004.37833333333, 1021.56833333333, 1035.155, 1043.84916666667, 1063.7225, 1070.96083333333, 1065.62416666667, 1065.89333333333, 1073.72333333333, 1086.39333333333, 1093.525, 1120.085, 1189.26, 1202.875, 1218.55583333333, 1238.46416666667, 1250.06, 1263.46, 1265.04333333333, 1270.10166666667, 1281.61, 1294.92416666667, 1304.21833333333, 1315.50583333333, 1338.43416666667, 1351.53083333333, 1353.35916666667, 1364.0425, 1361.66583333333, 1343.3225, 1329.69833333333, 1320.43583333333, 1310.45, 1313.62166666667, 1305.505, 1313.36, 1307.45916666667, 1289.97666666667, 1286.87666666667, 1289.315, 1276.8075, 1268.87083333333, 1266.07083333333, 1264.0475, 1271.76416666667, 1268.46833333333, 1244.53166666667, 1206.35416666667, 1173.62666666667, 1144.95833333333, 1157.15166666667, 1194.38333333333, 1198.275, 1196.0825, 1182.46583333333, 1167.85666666667, 1150.36083333333, 1132.83833333333, 1108.08, 1097.41583333333, 1099.82333333333, 1093.3775, 1086.7575, 1086.875, 1083.80166666667, 1075.48166666667, 1059.92083333333, 1048.40416666667, 1047.35, 1042.55166666667, 1036.11333333333, 1026.88333333333, 1022.6775, 1017.64666666667, 1023.52083333333, 1021.01666666667, 1017.255, 1004.57166666667, 908.28, 906.460833333333, 979.216666666667, 955.8475, 928.884166666667, 915.265833333333, 914.135833333333, 930.121666666666, 923.345833333333, 920.959166666667, 865.924166666667, 860.181666666667, 867.003333333333, 869.708333333333, 871.378333333333, 861.466666666667, 862.92
|
|
|
|
|
return {
|
|
|
|
|
'times': day_times,
|
|
|
|
|
'CO2': day_co2,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-01-09 16:06:22 +00:00
|
|
|
@pytest.fixture
|
2023-11-29 07:54:58 +00:00
|
|
|
def simple_co2_conc_model(data_registry):
|
2023-01-09 16:06:22 +00:00
|
|
|
return models.CO2ConcentrationModel(
|
2023-11-29 07:54:58 +00:00
|
|
|
data_registry=data_registry,
|
2023-01-09 16:06:22 +00:00
|
|
|
room=models.Room(200, models.PiecewiseConstant((0., 24.), (293,))),
|
|
|
|
|
ventilation=models.AirChange(models.PeriodicInterval(period=120, duration=120), 0.25),
|
2023-07-25 11:18:33 +00:00
|
|
|
CO2_emitters=models.SimplePopulation(
|
2023-01-09 16:06:22 +00:00
|
|
|
number=5,
|
|
|
|
|
presence=models.SpecificInterval((([0., 4.], ))),
|
|
|
|
|
activity=models.Activity.types['Seated'],
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
"time, expected_co2_concentration", [
|
|
|
|
|
[0., 440.44],
|
|
|
|
|
[1., 914.2487227],
|
|
|
|
|
[2., 1283.251327],
|
|
|
|
|
[3., 1570.630844],
|
|
|
|
|
[4., 1794.442237],
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
def test_co2_concentration(
|
|
|
|
|
simple_co2_conc_model: models.CO2ConcentrationModel,
|
|
|
|
|
time: float,
|
|
|
|
|
expected_co2_concentration: float,
|
|
|
|
|
):
|
|
|
|
|
npt.assert_almost_equal(simple_co2_conc_model.concentration(time), expected_co2_concentration)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_integrated_concentration(simple_co2_conc_model):
|
|
|
|
|
c1 = simple_co2_conc_model.integrated_concentration(0, 2)
|
|
|
|
|
c2 = simple_co2_conc_model.integrated_concentration(0, 1)
|
|
|
|
|
c3 = simple_co2_conc_model.integrated_concentration(1, 2)
|
|
|
|
|
assert c1 != 0
|
|
|
|
|
npt.assert_almost_equal(c1, c2 + c3)
|
2024-06-27 14:55:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_predictive_model_accuracy(data_registry, real_sensor_data):
|
|
|
|
|
'''
|
|
|
|
|
Specific test corresponding to the template data from a simulation day
|
|
|
|
|
in one office in Geneva. The room volume, number of people and ventilation
|
|
|
|
|
transition times correspond to the real occurencies in the simulation day.
|
|
|
|
|
'''
|
|
|
|
|
fitting_model: models.CO2DataModel = models.CO2DataModel(
|
|
|
|
|
data_registry=data_registry,
|
|
|
|
|
room_volume=59.787,
|
|
|
|
|
number=2,
|
|
|
|
|
presence=models.SpecificInterval(((8.63, 11.95), (12.42, 17.5))),
|
|
|
|
|
ventilation_transition_times=(8.63, 10.17, 12.89, 14.5, 17.5, 22.),
|
|
|
|
|
times=real_sensor_data['times'],
|
|
|
|
|
CO2_concentrations=real_sensor_data['CO2'],
|
|
|
|
|
)
|
|
|
|
|
# Get fitting results
|
|
|
|
|
fitting_results: typing.Dict = fitting_model.CO2_fit_params()
|
|
|
|
|
predictive_CO2: typing.List[float] = fitting_results['predictive_CO2']
|
|
|
|
|
|
|
|
|
|
def root_mean_square_error_percentage(actual, predicted) -> float:
|
|
|
|
|
return np.sqrt(np.mean(((actual - predicted) / actual) ** 2)) * 100
|
|
|
|
|
|
|
|
|
|
# Calculate RMSEP metric
|
|
|
|
|
rmsep = root_mean_square_error_percentage(np.array(real_sensor_data['CO2']), np.array(predictive_CO2))
|
|
|
|
|
acceptable_rmsep = 10 # Threshold of 10% for the accepted error margin
|
|
|
|
|
assert rmsep <= acceptable_rmsep, f"RMSEP {rmsep} exceeds acceptable threshold {acceptable_rmsep}"
|
|
|
|
|
|