From ee29f12f35f91eca590042409b4d5950e1cee3d7 Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Thu, 9 Mar 2023 16:00:00 +0100 Subject: [PATCH] updated typos and got back the state tests --- app-config/caimira-webservice/app.sh | 2 +- caimira/apps/expert.py | 4 +-- caimira/apps/simulator.py | 26 +++---------------- caimira/models.py | 12 ++++----- caimira/state.py | 4 ++- .../models/test_co2_concentration_model.py | 2 +- caimira/tests/test_state.py | 3 +++ 7 files changed, 19 insertions(+), 34 deletions(-) diff --git a/app-config/caimira-webservice/app.sh b/app-config/caimira-webservice/app.sh index 024c8a28..a0dc01b2 100755 --- a/app-config/caimira-webservice/app.sh +++ b/app-config/caimira-webservice/app.sh @@ -27,7 +27,7 @@ elif [[ "$APP_NAME" == "caimira-voila" ]]; then echo "Starting the voila service" voila caimira/apps/expert/ --port=8080 --no-browser --base_url=/voila-server/ --tornado_settings 'allow_origin=*' elif [[ "$APP_NAME" == "caimira-co2-voila" ]]; then - echo "Starting the voila service" + echo "Starting the CO2 voila service" voila caimira/apps/simulator/ --port=8080 --no-browser --base_url=/co2-voila-server/ --tornado_settings 'allow_origin=*' else echo "No APP_NAME specified" diff --git a/caimira/apps/expert.py b/caimira/apps/expert.py index 9214ad3a..c0a60312 100644 --- a/caimira/apps/expert.py +++ b/caimira/apps/expert.py @@ -214,7 +214,7 @@ class ExposureModelResult(View): self.html_output.value = '
\n'.join(lines) -class ExposureComparissonResult(View): +class ExposureComparisonResult(View): def __init__(self): self.figure = matplotlib.figure.Figure(figsize=(9, 6)) ipympl_canvas(self.figure) @@ -937,7 +937,7 @@ class ExpertApplication(Controller): self._model_scenarios: typing.List[ScenarioType] = [] self._active_scenario = 0 self.multi_model_view = MultiModelView(self) - self.comparison_view = ExposureComparissonResult() + self.comparison_view = ExposureComparisonResult() self.current_scenario_figure = ExposureModelResult() self._results_tab = widgets.Tab(children=( self.current_scenario_figure.widget, diff --git a/caimira/apps/simulator.py b/caimira/apps/simulator.py index 722b59b9..599e2616 100644 --- a/caimira/apps/simulator.py +++ b/caimira/apps/simulator.py @@ -126,7 +126,7 @@ class ExposureModelResult(View): self.figure.canvas.draw() -class ExposureComparissonResult(View): +class ExposureComparisonResult(View): def __init__(self): self.figure = matplotlib.figure.Figure(figsize=(9, 6)) ipympl_canvas(self.figure) @@ -193,7 +193,7 @@ class CO2Application(Controller): self._model_scenarios: typing.List[ScenarioType] = [] self._active_scenario = 0 self.multi_model_view = MultiModelView(self) - self.comparison_view = ExposureComparissonResult() + self.comparison_view = ExposureComparisonResult() self.current_scenario_figure = ExposureModelResult() self._results_tab = widgets.Tab(children=( self.current_scenario_figure.widget, @@ -394,11 +394,10 @@ class ModelWidgets(View): ventilation_widgets = { 'HVACMechanical': self._build_mechanical(node), 'Sliding window': self._build_window(node, emitters_node), - 'HEPAFilter': self._build_HEPA(node._states['HEPAFilter']), 'No ventilation': self._build_no_ventilation(node._states['No ventilation']), } - keys=[("Mechanical", "HVACMechanical"), ("Natural", "Sliding window"), ("No ventilation", "No ventilation"), ("HEPA Filter", "HEPAFilter")] + keys=[("Mechanical", "HVACMechanical"), ("Natural", "Sliding window"), ("No ventilation", "No ventilation")] for name, widget in ventilation_widgets.items(): widget.layout.visible = False @@ -632,20 +631,6 @@ class ModelWidgets(View): return widgets.VBox([mechanival_w, widgets.HBox(list(mechanical_widgets.values()))]) - def _build_HEPA( - self, - node, - ) -> widgets.Widget: - - HEPA_w = widgets.FloatSlider(value=node.q_air_mech, min=10, max=500, step=5) - - def on_value_change(change): - node.q_air_mech=change['new'] - - HEPA_w.observe(on_value_change,names= ['value']) - - return widgets.HBox([widgets.Label('HEPA Filtration (m³/h) '),HEPA_w], layout=widgets.Layout(justify_content='space-between')) - def _build_no_ventilation(self, node): return widgets.HBox([]) @@ -757,10 +742,10 @@ class CAIMIRACO2StateBuilder(CAIMIRAStateBuilder): 'No ventilation': self.build_generic(models.AirChange), 'AirChange': self.build_generic(models.AirChange), 'Hinged window': self.build_generic(models.WindowOpening), - 'HEPAFilter': self.build_generic(models.HEPAFilter), }, state_builder=self, ) + #Initialise the "Sliding window" state s._states['Sliding window'].dcs_update_from( models.SlidingWindow(active=models.PeriodicInterval(period=120, duration=15, start=8-(15/60)), outside_temp=models.PiecewiseConstant((0,24.), (283.15,)), @@ -782,9 +767,6 @@ class CAIMIRACO2StateBuilder(CAIMIRAStateBuilder): s._states['No ventilation'].dcs_update_from( models.AirChange(active=models.PeriodicInterval(period=60, duration=60), air_exch=0.) ) - s._states['HEPAFilter'].dcs_update_from( - models.HEPAFilter(active=models.PeriodicInterval(period=60, duration=60), q_air_mech=500.) - ) return s def models_start_end(models: typing.Sequence[models.CO2ConcentrationModel]) -> typing.Tuple[float, float]: diff --git a/caimira/models.py b/caimira/models.py index 140f3935..5483596b 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -1009,11 +1009,9 @@ class _ConcentrationModelBase: return self.min_background_concentration()/self.normalization_factor() V = self.room.volume RR = self.removal_rate(time) - try: - return (1. / (RR * V) + self.min_background_concentration()/ + + return (1. / (RR * V) + self.min_background_concentration()/ self.normalization_factor()) - except ZeroDivisionError: - return 0 @method_cache def state_change_times(self) -> typing.List[float]: @@ -1212,9 +1210,9 @@ class CO2ConcentrationModel(_ConcentrationModelBase): return self.CO2_emitters def removal_rate(self, time: float) -> _VectorisedFloat: - # 0.25 is a minimal, always present source of ventilation, due - # to the air infiltration from the outside. - return self.ventilation.air_exchange(self.room, time) + 1e-6 + # Setting minimum air exchange rate to 1e-6 to avoid divisions by + # zero when computing the CO2 concentration. + return np.maximum(1e-6,self.ventilation.air_exchange(self.room, time)) def min_background_concentration(self) -> _VectorisedFloat: """ diff --git a/caimira/state.py b/caimira/state.py index 6fecac0d..fae297de 100644 --- a/caimira/state.py +++ b/caimira/state.py @@ -228,6 +228,8 @@ class DataclassInstanceState(DataclassState[Datamodel_T]): def dcs_set_instance_type(self, instance_dataclass: typing.Type[Datamodel_T]): if not dataclasses.is_dataclass(instance_dataclass): raise TypeError("The given class is not a valid dataclass") + if not issubclass(instance_dataclass, self._base): + raise TypeError(f"The dataclass type provided ({instance_dataclass}) must be a subclass of the base ({self._base})") self._instance_type = instance_dataclass # TODO: It is possible to cut observer connections by clearing like this. @@ -321,7 +323,7 @@ class DataclassStateNamed(DataclassState[Datamodel_T]): ): # TODO: This is effectively a container type. We shouldn't use the standard constructor for this. enabled = list(states.keys())[0] - t = states[enabled] + super().__init__(**kwargs) with self._object_setattr(): diff --git a/caimira/tests/models/test_co2_concentration_model.py b/caimira/tests/models/test_co2_concentration_model.py index d1a8a6db..ad4a348c 100644 --- a/caimira/tests/models/test_co2_concentration_model.py +++ b/caimira/tests/models/test_co2_concentration_model.py @@ -8,7 +8,7 @@ from caimira import models def simple_co2_conc_model(): return models.CO2ConcentrationModel( room=models.Room(200, models.PiecewiseConstant((0., 24.), (293,))), - ventilation=models.AirChange(models.PeriodicInterval(period=120, duration=120), 0.25-(1e-6)), + ventilation=models.AirChange(models.PeriodicInterval(period=120, duration=120), 0.25), CO2_emitters=models.Population( number=5, presence=models.SpecificInterval((([0., 4.], ))), diff --git a/caimira/tests/test_state.py b/caimira/tests/test_state.py index 15733db4..f984136d 100644 --- a/caimira/tests/test_state.py +++ b/caimira/tests/test_state.py @@ -190,6 +190,9 @@ def test_DCS_named(): opt1_observer.assert_called_once_with() opt1_observer.reset_mock() + with pytest.raises(TypeError): + s.dcs_update_from(opt2) + s.dcs_select('option 2') opt1_observer.assert_called_once_with() opt1_observer.reset_mock()