added new input "room_capacity" and adapted the calculations of the flow rate (l/s/p) accordingly

This commit is contained in:
lrdossan 2024-08-20 15:53:23 +01:00
parent ada64d6acc
commit 53b3a52513
4 changed files with 63 additions and 28 deletions

View file

@ -22,6 +22,7 @@ class CO2FormData(FormData):
CO2_data: dict
fitting_ventilation_states: list
fitting_ventilation_type: str
room_capacity: int
#: The default values for undefined fields. Note that the defaults here
#: and the defaults in the html form must not be contradictory.
@ -45,6 +46,7 @@ class CO2FormData(FormData):
'infected_lunch_start': '12:30',
'infected_people': 1,
'infected_start': '08:30',
'room_capacity': 10,
'room_volume': NO_DEFAULT,
'specific_breaks': '{}',
'total_people': NO_DEFAULT,
@ -62,6 +64,14 @@ class CO2FormData(FormData):
# Validate population parameters
self.validate_population_parameters()
# Validate room capacity
if type(self.room_capacity) is not int:
raise TypeError(f'The room capacity should be a valid integer (> 0). Got {type(self.room_capacity)}.')
if self.room_capacity <= 0:
raise TypeError(f'The room capacity should be a valid integer (> 0). Got {self.room_capacity}.')
if self.room_capacity < self.total_people:
raise TypeError(f'The room capacity should be higher than the total people in the room. Got {self.room_capacity}.')
# Validate specific inputs - breaks (exposed and infected)
if self.specific_breaks != {}:
if type(self.specific_breaks) is not dict:
@ -181,6 +191,7 @@ class CO2FormData(FormData):
return models.CO2DataModel(
data_registry=self.data_registry,
room_capacity=self.room_capacity,
room_volume=self.room_volume,
occupancy=models.IntPiecewiseConstant(transition_times=tuple(all_state_changes), values=tuple(total_people)),
ventilation_transition_times=self.ventilation_transition_times(),

View file

@ -19,6 +19,7 @@ const CO2_data_form = [
"infected_lunch_start",
"infected_people",
"infected_start",
"room_capacity",
"room_volume",
"specific_breaks",
"total_people",
@ -137,6 +138,7 @@ function generateJSONStructure(endpoint, jsonData) {
$("#generate_fitting_data").prop("disabled", false);
$("#fitting_ventilation_states").prop("disabled", false);
$("[name=fitting_ventilation_type]").prop("disabled", false);
$("#room_capacity").prop("disabled", false);
plotCO2Data(endpoint);
}
}
@ -152,7 +154,9 @@ function validateFormInputs(obj) {
const $referenceNode = $("#DIVCO2_data_dialog");
for (let i = 0; i < CO2_data_form.length; i++) {
const $requiredElement = $(`[name=${CO2_data_form[i]}]`).first();
if ($requiredElement.attr('name') !== "fitting_ventilation_states" && $requiredElement.val() === "") {
if ($requiredElement.attr('name') !== "fitting_ventilation_states" &&
$requiredElement.attr('name') !== "room_capacity" &&
$requiredElement.val() === "") {
insertErrorFor(
$referenceNode,
`'${$requiredElement.attr('name')}' must be defined.<br />`
@ -236,6 +240,36 @@ function validateCO2Form() {
);
submit = false;
}
// Validate room capacity
const roomCapacity = $fittingToSubmit.find("input[name=room_capacity]");
const roomCapacityVal = roomCapacity.val();
if (roomCapacityVal !== "") {
const roomCapacityNumber = Number(roomCapacityVal);
const totalPeopleNumber = Number($("#total_people").val());
if (!Number.isInteger(roomCapacityNumber) || roomCapacityNumber <= 0) {
insertErrorFor(
$referenceNode,
`'${roomCapacity.attr('name')}' must be a valid integer (> 0).</br>`
);
submit = false;
}
else if (roomCapacityNumber < totalPeopleNumber){
insertErrorFor(
$referenceNode,
`'${roomCapacity.attr('name')}' must be higher than the total people.</br>`
);
submit = false;
}
console.log(roomCapacityNumber)
console.log(totalPeopleNumber)
}
else {
insertErrorFor(
$referenceNode,
`'${roomCapacity.attr('name')}' must be defined.</br>`
);
submit = false;
}
}
return submit;
@ -341,6 +375,11 @@ function submitFittingAlgorithm(url) {
"disabled",
true
);
// Disable room capacity input
$("#room_capacity").prop(
"disabled",
true
);
// Prepare data for submission
const CO2_mapping = formatCO2DataForm(CO2_data_form);

View file

@ -363,6 +363,11 @@
</div>
<input type="text" class="form-control" id="fitting_ventilation_states" name="fitting_ventilation_states" placeholder="e.g. [8.5, 10, 11.5, 17]" form="not-submitted"><br>
</div>
<strong>Room data:</strong>
<div class="form-group row">
<div class="col-sm-5"><label class="col-form-label">Maximum number of occupants:</label></div>
<div class="col-sm-7 align-self-center"><input type="number" id="room_capacity" class="form-control" name="room_capacity" placeholder="Number" min=1 form="not-submitted"></div>
</div>
</div>
<div id="DIVCO2_fitting_result" style="display: none">

View file

@ -1526,11 +1526,13 @@ class ShortRangeModel:
@dataclass(frozen=True)
class CO2DataModel:
'''
The CO2DataModel class models CO2 data based on room volume, ventilation transition times, and people presence.
It uses optimization techniques to fit the model's parameters and estimate the exhalation rate and ventilation
values that best match the measured CO2 concentrations.
The CO2DataModel class models CO2 data based on room volume and capacity,
ventilation transition times, and people presence.
It uses optimization techniques to fit the model's parameters and estimate the
exhalation rate and ventilation values that best match the measured CO2 concentrations.
'''
data_registry: DataRegistry
room_capacity: int
room_volume: float
occupancy: IntPiecewiseConstant
ventilation_transition_times: typing.Tuple[float, ...]
@ -1592,30 +1594,8 @@ class CO2DataModel:
the_predictive_CO2 = self.CO2_concentrations_from_params(the_CO2_concentration_model)
# Ventilation in L/s/person
def max_occupancy_in_interval(start: float, stop: float) -> int:
"""
Given a certain ventilation interval, get the maximum number of
people in that period of time.
"""
max_people: int = 0
for i, (people_start, people_stop) in enumerate(zip(self.occupancy.transition_times[:-1],
self.occupancy.transition_times[1:])):
if people_stop <= start or people_start >= stop:
continue
if self.occupancy.values[i] > max_people: max_people = self.occupancy.values[i]
return max_people
vent_volume_liter_person = []
for i, (vent_start, vent_stop) in enumerate(zip(self.ventilation_transition_times[:-1],
self.ventilation_transition_times[1:])):
max_people = max_occupancy_in_interval(vent_start, vent_stop)
if max_people == 0:
# If in a certain interval there are no occupancy, the flow rate per second/person is 0
vent_volume_liter_person.append(0)
else:
vent_volume_liter_person.append(
ventilation_values[i] / 3600 * self.room_volume / max_people * 1000
) # 1m^3 = 1000L
vent_volume_liter_person = [vent / 3600 * self.room_volume / self.room_capacity * 1000
for vent in ventilation_values] # 1m^3 = 1000L
return {
"exhalation_rate": exhalation_rate,