added new input "room_capacity" and adapted the calculations of the flow rate (l/s/p) accordingly
This commit is contained in:
parent
ada64d6acc
commit
53b3a52513
4 changed files with 63 additions and 28 deletions
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue