Added colors/labels for each short range interaction. Added cumulative line for long range exposure
This commit is contained in:
parent
3965123393
commit
c19ccbafe7
6 changed files with 166 additions and 85 deletions
|
|
@ -246,9 +246,15 @@ class FormData:
|
||||||
humidity = 0.5
|
humidity = 0.5
|
||||||
room = models.Room(volume=volume, humidity=humidity)
|
room = models.Room(volume=volume, humidity=humidity)
|
||||||
|
|
||||||
sr_presence=self.short_range_intervals()
|
if self.short_range_option == "short_range_yes":
|
||||||
sr_activities=self.short_range_activities()
|
sr_presence=self.short_range_intervals()
|
||||||
short_range_expirations = tuple(short_range_expiration_distributions[activity] for activity in sr_activities)
|
sr_activities=self.short_range_activities()
|
||||||
|
short_range_expirations = tuple(short_range_expiration_distributions[activity] for activity in sr_activities)
|
||||||
|
dilutions=dilution_factor(activities=sr_activities, distance=np.random.uniform(0.5, 1.5, 250000))
|
||||||
|
else:
|
||||||
|
sr_presence=()
|
||||||
|
short_range_expirations=()
|
||||||
|
dilutions=()
|
||||||
|
|
||||||
# Initializes and returns a model with the attributes defined above
|
# Initializes and returns a model with the attributes defined above
|
||||||
return mc.ExposureModel(
|
return mc.ExposureModel(
|
||||||
|
|
@ -261,7 +267,7 @@ class FormData:
|
||||||
short_range = mc.ShortRangeModel(
|
short_range = mc.ShortRangeModel(
|
||||||
presence=sr_presence,
|
presence=sr_presence,
|
||||||
expirations=short_range_expirations,
|
expirations=short_range_expirations,
|
||||||
dilutions=dilution_factor(activities=sr_activities, distance=np.random.uniform(0.5, 1.5, 250000)),
|
dilutions=dilutions,
|
||||||
),
|
),
|
||||||
exposed=self.exposed_population(),
|
exposed=self.exposed_population(),
|
||||||
)
|
)
|
||||||
|
|
@ -639,15 +645,13 @@ class FormData:
|
||||||
)
|
)
|
||||||
|
|
||||||
def short_range_intervals(self) -> typing.Tuple[typing.Tuple[str, models.SpecificInterval], ...]:
|
def short_range_intervals(self) -> typing.Tuple[typing.Tuple[str, models.SpecificInterval], ...]:
|
||||||
if (self.short_range_interactions):
|
short_range_intervals = []
|
||||||
short_range_intervals = []
|
for interaction in self.short_range_interactions:
|
||||||
for interaction in self.short_range_interactions:
|
start_time = time_string_to_minutes(interaction['start_time'])
|
||||||
start_time = time_string_to_minutes(interaction['start_time'])
|
duration = float(interaction['duration'])
|
||||||
duration = float(interaction['duration'])
|
short_range_intervals.append((interaction['activity'], models.SpecificInterval((start_time/60, (start_time + duration)/60))))
|
||||||
short_range_intervals.append((interaction['activity'], models.SpecificInterval((start_time/60, (start_time + duration)/60))))
|
return tuple(short_range_intervals)
|
||||||
return tuple(short_range_intervals)
|
|
||||||
else:
|
|
||||||
return ()
|
|
||||||
|
|
||||||
def exposed_present_interval(self) -> models.Interval:
|
def exposed_present_interval(self) -> models.Interval:
|
||||||
return self.present_interval(
|
return self.present_interval(
|
||||||
|
|
|
||||||
|
|
@ -127,12 +127,18 @@ def calculate_report_data(model: models.ExposureModel):
|
||||||
np.array(model.deposited_exposure_between_bounds(float(time1), float(time2))).mean()
|
np.array(model.deposited_exposure_between_bounds(float(time1), float(time2))).mean()
|
||||||
for time1, time2 in zip(times[:-1], times[1:])
|
for time1, time2 in zip(times[:-1], times[1:])
|
||||||
])
|
])
|
||||||
|
long_range_cumulative_doses = np.cumsum([
|
||||||
|
np.array(model.long_range_deposited_exposure_between_bounds(float(time1), float(time2))).mean()
|
||||||
|
for time1, time2 in zip(times[:-1], times[1:])
|
||||||
|
])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"times": list(times),
|
"times": list(times),
|
||||||
"short_range_intervals": short_range_intervals,
|
"short_range_intervals": short_range_intervals,
|
||||||
|
"short_range_activities": short_range_activities,
|
||||||
"exposed_presence_intervals": [list(interval) for interval in model.exposed.presence.boundaries()],
|
"exposed_presence_intervals": [list(interval) for interval in model.exposed.presence.boundaries()],
|
||||||
"cumulative_doses": list(cumulative_doses),
|
"cumulative_doses": list(cumulative_doses),
|
||||||
|
"long_range_cumulative_doses": list(long_range_cumulative_doses),
|
||||||
"short_range_concentrations": short_range_concentrations,
|
"short_range_concentrations": short_range_concentrations,
|
||||||
"concentrations": sr_breathing_concentrations,
|
"concentrations": sr_breathing_concentrations,
|
||||||
"highest_const": highest_const,
|
"highest_const": highest_const,
|
||||||
|
|
|
||||||
|
|
@ -405,7 +405,7 @@ function validate_form(form) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the short range interactions list
|
// Generate the short range interactions list
|
||||||
let short_range_interactions = [];
|
var short_range_interactions = [];
|
||||||
$(".form_field_outer_row").each(function (index, element){
|
$(".form_field_outer_row").each(function (index, element){
|
||||||
let obj = {};
|
let obj = {};
|
||||||
obj.activity = $(element).find("[name='short_range_activity']").val();
|
obj.activity = $(element).find("[name='short_range_activity']").val();
|
||||||
|
|
@ -413,6 +413,11 @@ function validate_form(form) {
|
||||||
obj.duration = $(element).find("[name='short_range_duration']").val();
|
obj.duration = $(element).find("[name='short_range_duration']").val();
|
||||||
short_range_interactions.push(JSON.stringify(obj));
|
short_range_interactions.push(JSON.stringify(obj));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sort list by time
|
||||||
|
short_range_interactions.sort(function (a, b) {
|
||||||
|
return JSON.parse(a).start_time.localeCompare(JSON.parse(b).start_time);
|
||||||
|
});
|
||||||
$("input[type=text][name=short_range_interactions]").val('[' + short_range_interactions + ']');
|
$("input[type=text][name=short_range_interactions]").val('[' + short_range_interactions + ']');
|
||||||
if (short_range_interactions.length == 0) {
|
if (short_range_interactions.length == 0) {
|
||||||
$("input[type=radio][id=short_range_no]").prop("checked", true);
|
$("input[type=radio][id=short_range_no]").prop("checked", true);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,22 @@
|
||||||
/* Generate the concentration plot using d3 library. */
|
/* Generate the concentration plot using d3 library. */
|
||||||
function draw_plot(svg_id, times, concentrations, short_range_concentrations, cumulative_doses, exposed_presence_intervals, short_range_intervals) {
|
function draw_plot(svg_id, times, concentrations, short_range_concentrations,
|
||||||
|
cumulative_doses, long_range_cumulative_doses, exposed_presence_intervals,
|
||||||
|
short_range_intervals, short_range_activities) {
|
||||||
|
|
||||||
// Used for controlling the short range interactions
|
// Used for controlling the short range interactions
|
||||||
let button_full_exposure = document.getElementById("button_full_exposure");
|
let button_full_exposure = document.getElementById("button_full_exposure");
|
||||||
let button_long_exposure = document.getElementById("button_long_exposure");
|
let button_long_exposure = document.getElementById("button_long_exposure");
|
||||||
|
let long_range_checkbox = document.getElementById('long_range_cumulative_checkbox')
|
||||||
let show_sr_legend = button_full_exposure || Math.round(Math.max(...concentrations)) == Math.round(Math.max(...short_range_concentrations))
|
let show_sr_legend = button_full_exposure || Math.round(Math.max(...concentrations)) == Math.round(Math.max(...short_range_concentrations))
|
||||||
|
|
||||||
var data_for_graphs = {
|
var data_for_graphs = {
|
||||||
'concentrations': [],
|
'concentrations': [],
|
||||||
'cumulative_doses': [],
|
'cumulative_doses': [],
|
||||||
|
'long_range_cumulative_doses': [],
|
||||||
}
|
}
|
||||||
times.map((time, index) => data_for_graphs.concentrations.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': short_range_concentrations[index]}));
|
times.map((time, index) => data_for_graphs.concentrations.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': short_range_concentrations[index]}));
|
||||||
times.map((time, index) => data_for_graphs.cumulative_doses.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': cumulative_doses[index]}));
|
times.map((time, index) => data_for_graphs.cumulative_doses.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': cumulative_doses[index]}));
|
||||||
|
times.map((time, index) => data_for_graphs.long_range_cumulative_doses.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': long_range_cumulative_doses[index]}));
|
||||||
|
|
||||||
// Add main SVG element
|
// Add main SVG element
|
||||||
var plot_div = document.getElementById(svg_id);
|
var plot_div = document.getElementById(svg_id);
|
||||||
|
|
@ -24,10 +29,10 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
bisecHour = d3.bisector((d) => { return d.hour; }).left,
|
bisecHour = d3.bisector((d) => { return d.hour; }).left,
|
||||||
|
|
||||||
yRange = d3.scaleLinear(),
|
yRange = d3.scaleLinear(),
|
||||||
yCumulativeRange = d3.scaleLinear().domain([0., Math.max(...cumulative_doses)*1.1]),
|
yCumulativeRange = d3.scaleLinear(),
|
||||||
|
|
||||||
yAxis = d3.axisLeft();
|
yAxis = d3.axisLeft(),
|
||||||
yCumulativeAxis = d3.axisRight(yCumulativeRange).ticks(4);
|
yCumulativeAxis = d3.axisRight();
|
||||||
|
|
||||||
// X axis declaration.
|
// X axis declaration.
|
||||||
var xAxisEl = vis.append('svg:g')
|
var xAxisEl = vis.append('svg:g')
|
||||||
|
|
@ -54,7 +59,6 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
// Y cumulative concentration axis declaration.
|
// Y cumulative concentration axis declaration.
|
||||||
var yAxisCumEl = vis.append('svg:g')
|
var yAxisCumEl = vis.append('svg:g')
|
||||||
.attr('class', 'y axis')
|
.attr('class', 'y axis')
|
||||||
.style('font-size', 14)
|
|
||||||
.style("stroke-dasharray", "5 5");
|
.style("stroke-dasharray", "5 5");
|
||||||
|
|
||||||
// Y cumulated concentration axis label.
|
// Y cumulated concentration axis label.
|
||||||
|
|
@ -81,12 +85,17 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
.attr('fill', '#1f77b4')
|
.attr('fill', '#1f77b4')
|
||||||
.attr('fill-opacity', '0.1');
|
.attr('fill-opacity', '0.1');
|
||||||
|
|
||||||
|
sr_unique_activities = [...new Set(short_range_activities)]
|
||||||
if (show_sr_legend) {
|
if (show_sr_legend) {
|
||||||
var legendShortRangeAreaIcon = vis.append('rect')
|
var legendShortRangeAreaIcon = {};
|
||||||
|
sr_unique_activities.forEach((b, index) => {
|
||||||
|
legendShortRangeAreaIcon[index] = vis.append('rect')
|
||||||
.attr('width', 20)
|
.attr('width', 20)
|
||||||
.attr('height', 15)
|
.attr('height', 15);
|
||||||
.attr('fill', '#1f00b4')
|
if (sr_unique_activities[index] == 'Breathing') legendShortRangeAreaIcon[index].attr('fill', 'red').attr('fill-opacity', '0.2');
|
||||||
.attr('fill-opacity', '0.1');
|
else if (sr_unique_activities[index] == 'Speaking') legendShortRangeAreaIcon[index].attr('fill', 'green').attr('fill-opacity', '0.1');
|
||||||
|
else legendShortRangeAreaIcon[index].attr('fill', 'blue').attr('fill-opacity', '0.1');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var legendLineText = vis.append('text')
|
var legendLineText = vis.append('text')
|
||||||
|
|
@ -105,14 +114,17 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
.attr('alignment-baseline', 'central');
|
.attr('alignment-baseline', 'central');
|
||||||
|
|
||||||
if (show_sr_legend) {
|
if (show_sr_legend) {
|
||||||
var legendShortRangeText = vis.append('text')
|
var legendShortRangeText = {};
|
||||||
.text('Short range interaction(s)')
|
sr_unique_activities.forEach((b, index) => {
|
||||||
|
legendShortRangeText[index] = vis.append('text')
|
||||||
|
.text('Short range - ' + sr_unique_activities[index])
|
||||||
.style('font-size', '15px')
|
.style('font-size', '15px')
|
||||||
.attr('alignment-baseline', 'central');
|
.attr('alignment-baseline', 'central');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Legend bounding
|
// Legend bounding
|
||||||
if (show_sr_legend) legendBBox_height = 90;
|
if (show_sr_legend) legendBBox_height = 68 + 20 * sr_unique_activities.length;
|
||||||
else legendBBox_height = 68;
|
else legendBBox_height = 68;
|
||||||
var legendBBox = vis.append('rect')
|
var legendBBox = vis.append('rect')
|
||||||
.attr('width', 255)
|
.attr('width', 255)
|
||||||
|
|
@ -140,12 +152,23 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
|
|
||||||
// Line representing the cumulative concentration.
|
// Line representing the cumulative concentration.
|
||||||
var lineCumulative = d3.line();
|
var lineCumulative = d3.line();
|
||||||
var draw_cumulative_line = vis.append('svg:path')
|
var draw_cumulative_line = draw_area.append('svg:path')
|
||||||
.attr('stroke', '#1f77b4')
|
.attr('stroke', '#1f77b4')
|
||||||
.attr('stroke-width', 2)
|
.attr('stroke-width', 2)
|
||||||
.style("stroke-dasharray", "5 5")
|
.style("stroke-dasharray", "5 5")
|
||||||
.attr('fill', 'none');
|
.attr('fill', 'none');
|
||||||
|
|
||||||
|
// Line representing the long range cumulative concentration.
|
||||||
|
if (show_sr_legend) {
|
||||||
|
var longRangeCumulative = d3.line();
|
||||||
|
var draw_long_range_cumulative_line = draw_area.append('svg:path')
|
||||||
|
.attr('stroke', 'purple')
|
||||||
|
.attr('stroke-width', 2)
|
||||||
|
.style("stroke-dasharray", "5 5")
|
||||||
|
.attr('fill', 'none')
|
||||||
|
.attr('opacity', 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Area representing the presence of exposed person(s).
|
// Area representing the presence of exposed person(s).
|
||||||
var exposedArea = {};
|
var exposedArea = {};
|
||||||
var drawArea = {};
|
var drawArea = {};
|
||||||
|
|
@ -161,10 +184,11 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
var drawShortRangeArea = {};
|
var drawShortRangeArea = {};
|
||||||
short_range_intervals.forEach((b, index) => {
|
short_range_intervals.forEach((b, index) => {
|
||||||
shortRangeArea[index] = d3.area();
|
shortRangeArea[index] = d3.area();
|
||||||
drawShortRangeArea[index] = draw_area.append('svg:path')
|
drawShortRangeArea[index] = draw_area.append('svg:path');
|
||||||
.attr('class', 'draw_short_range_area')
|
|
||||||
.attr('fill', '#1f00b4')
|
if (short_range_activities[index] == 'Breathing') drawShortRangeArea[index].attr('fill', 'red').attr('fill-opacity', '0.2');
|
||||||
.attr('fill-opacity', '0.1');
|
else if (short_range_activities[index] == 'Speaking') drawShortRangeArea[index].attr('fill', 'green').attr('fill-opacity', '0.1');
|
||||||
|
else drawShortRangeArea[index].attr('fill', 'blue').attr('fill-opacity', '0.1');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tooltip.
|
// Tooltip.
|
||||||
|
|
@ -202,10 +226,13 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
.attr('pointer-events', 'all');
|
.attr('pointer-events', 'all');
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_concentration_plot(data) {
|
function update_concentration_plot(concentration_data, cumulative_data) {
|
||||||
yRange.domain([0., Math.max(...data)]);
|
yRange.domain([0., Math.max(...concentration_data)*1.1]);
|
||||||
yAxisEl.transition().duration(1000).call(yAxis);
|
yAxisEl.transition().duration(1000).call(yAxis);
|
||||||
|
|
||||||
|
yCumulativeRange.domain([0., Math.max(...cumulative_data)*1.1]);
|
||||||
|
yAxisCumEl.transition().duration(1000).call(yCumulativeAxis)
|
||||||
|
|
||||||
// Concentration line
|
// Concentration line
|
||||||
lineFunc.defined(d => !isNaN(d.concentration))
|
lineFunc.defined(d => !isNaN(d.concentration))
|
||||||
.x(d => xTimeRange(d.time))
|
.x(d => xTimeRange(d.time))
|
||||||
|
|
@ -215,6 +242,24 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
.duration(1000)
|
.duration(1000)
|
||||||
.attr("d", lineFunc(data_for_graphs.concentrations));
|
.attr("d", lineFunc(data_for_graphs.concentrations));
|
||||||
|
|
||||||
|
// Cumulative line.
|
||||||
|
lineCumulative.defined(d => !isNaN(d.concentration))
|
||||||
|
.x(d => xTimeRange(d.time))
|
||||||
|
.y(d => yCumulativeRange(d.concentration));
|
||||||
|
draw_cumulative_line.transition()
|
||||||
|
.duration(1000)
|
||||||
|
.attr("d", lineCumulative(data_for_graphs.cumulative_doses));
|
||||||
|
|
||||||
|
// Long range cumulative line.
|
||||||
|
if (show_sr_legend) {
|
||||||
|
longRangeCumulative.defined(d => !isNaN(d.concentration))
|
||||||
|
.x(d => xTimeRange(d.time))
|
||||||
|
.y(d => yCumulativeRange(d.concentration));
|
||||||
|
draw_long_range_cumulative_line.transition()
|
||||||
|
.duration(1000)
|
||||||
|
.attr("d", lineCumulative(data_for_graphs.long_range_cumulative_doses));
|
||||||
|
}
|
||||||
|
|
||||||
// Area.
|
// Area.
|
||||||
exposed_presence_intervals.forEach((b, index) => {
|
exposed_presence_intervals.forEach((b, index) => {
|
||||||
exposedArea[index].x(d => xTimeRange(d.time))
|
exposedArea[index].x(d => xTimeRange(d.time))
|
||||||
|
|
@ -327,6 +372,7 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
// Axis.
|
// Axis.
|
||||||
var xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d));
|
var xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d));
|
||||||
yAxis.scale(yRange);
|
yAxis.scale(yRange);
|
||||||
|
yCumulativeAxis.scale(yCumulativeRange);
|
||||||
|
|
||||||
xAxisEl.attr('transform', 'translate(0,' + (graph_height - margins.bottom) + ')')
|
xAxisEl.attr('transform', 'translate(0,' + (graph_height - margins.bottom) + ')')
|
||||||
.call(xAxis);
|
.call(xAxis);
|
||||||
|
|
@ -374,10 +420,12 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
.attr('y', margins.top + 3 * size);
|
.attr('y', margins.top + 3 * size);
|
||||||
|
|
||||||
if (show_sr_legend) {
|
if (show_sr_legend) {
|
||||||
legendShortRangeAreaIcon.attr('x', graph_width + size * 2.5)
|
sr_unique_activities.forEach((b, index) => {
|
||||||
.attr('y', margins.top + 3.6 * size);
|
legendShortRangeAreaIcon[index].attr('x', graph_width + size * 2.5)
|
||||||
legendShortRangeText.attr('x', graph_width + 4 * size)
|
.attr('y', margins.top + 3.6 * size + index * size);
|
||||||
.attr('y', margins.top + 4 * size);
|
legendShortRangeText[index].attr('x', graph_width + 4 * size)
|
||||||
|
.attr('y', margins.top + 4 * size + index * size);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
legendBBox.attr('x', graph_width * 1.07)
|
legendBBox.attr('x', graph_width * 1.07)
|
||||||
|
|
@ -403,10 +451,12 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
.attr('y', graph_height + 2.6 * size);
|
.attr('y', graph_height + 2.6 * size);
|
||||||
|
|
||||||
if (show_sr_legend) {
|
if (show_sr_legend) {
|
||||||
legendShortRangeAreaIcon.attr('x', size * 0.50)
|
sr_unique_activities.forEach((b, index) => {
|
||||||
.attr('y', graph_height * 1.175 + size);
|
legendShortRangeAreaIcon[index].attr('x', size * 0.50)
|
||||||
legendShortRangeText.attr('x', 2 * size)
|
.attr('y', graph_height * 1.175 + size + index * size);
|
||||||
.attr('y', graph_height + 3.65 * size);
|
legendShortRangeText[index].attr('x', 2 * size)
|
||||||
|
.attr('y', graph_height + 3.65 * size + index * size);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
legendBBox.attr('x', 1)
|
legendBBox.attr('x', 1)
|
||||||
|
|
@ -419,23 +469,25 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
.attr('height', graph_height);
|
.attr('height', graph_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cumulative line.
|
|
||||||
lineCumulative.defined(d => !isNaN(d.concentration))
|
|
||||||
.x(d => xTimeRange(d.time))
|
|
||||||
.y(d => yCumulativeRange(d.concentration));
|
|
||||||
draw_cumulative_line.attr("d", lineCumulative(data_for_graphs.cumulative_doses));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (long_range_checkbox) {
|
||||||
|
long_range_checkbox.addEventListener("click", () => {
|
||||||
|
if (long_range_checkbox.checked) draw_long_range_cumulative_line.transition().duration(1000).attr("opacity", 1);
|
||||||
|
else draw_long_range_cumulative_line.transition().duration(1000).attr("opacity", 0);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (button_full_exposure) {
|
if (button_full_exposure) {
|
||||||
button_full_exposure.addEventListener("click", () => {
|
button_full_exposure.addEventListener("click", () => {
|
||||||
update_concentration_plot(short_range_concentrations);
|
update_concentration_plot(short_range_concentrations, cumulative_doses);
|
||||||
button_full_exposure.disabled = true;
|
button_full_exposure.disabled = true;
|
||||||
button_long_exposure.disabled = false;
|
button_long_exposure.disabled = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (button_long_exposure) {
|
if (button_long_exposure) {
|
||||||
button_long_exposure.addEventListener("click", () => {
|
button_long_exposure.addEventListener("click", () => {
|
||||||
update_concentration_plot(concentrations);
|
update_concentration_plot(concentrations, long_range_cumulative_doses);
|
||||||
button_full_exposure.disabled = false;
|
button_full_exposure.disabled = false;
|
||||||
button_long_exposure.disabled = true;
|
button_long_exposure.disabled = true;
|
||||||
});
|
});
|
||||||
|
|
@ -443,13 +495,13 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
||||||
|
|
||||||
// Draw for the first time to initialize.
|
// Draw for the first time to initialize.
|
||||||
redraw();
|
redraw();
|
||||||
update_concentration_plot(short_range_concentrations);
|
update_concentration_plot(short_range_concentrations, cumulative_doses);
|
||||||
|
|
||||||
// Redraw based on the new size whenever the browser window is resized.
|
// Redraw based on the new size whenever the browser window is resized.
|
||||||
window.addEventListener("resize", e => {
|
window.addEventListener("resize", e => {
|
||||||
redraw();
|
redraw();
|
||||||
if (button_full_exposure.disabled) update_concentration_plot(short_range_concentrations);
|
if (button_full_exposure.disabled) update_concentration_plot(short_range_concentrations, cumulative_doses);
|
||||||
else update_concentration_plot(concentrations)
|
else update_concentration_plot(concentrations, long_range_cumulative_doses)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,13 @@
|
||||||
{% endblock report_summary_footnote %}
|
{% endblock report_summary_footnote %}
|
||||||
</div>
|
</div>
|
||||||
<p id="section1">* The results are based on the parameters and assumptions published in the CERN Open Report <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a>.</p>
|
<p id="section1">* The results are based on the parameters and assumptions published in the CERN Open Report <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a>.</p>
|
||||||
{% if (form.short_range_option == "short_range_yes" and concentrations|max|int != short_range_concentrations|max|int ) %}
|
{% if form.short_range_option == "short_range_yes" %}
|
||||||
<button class="btn btn-sm btn-primary" id="button_full_exposure" disabled>Show full exposure</button>
|
{% if concentrations|max|int != short_range_concentrations|max|int %}
|
||||||
<button class="btn btn-sm btn-primary ml-0" id="button_long_exposure">Hide high concentration</button>
|
<button class="btn btn-sm btn-primary" id="button_full_exposure" disabled>Show full exposure</button>
|
||||||
|
<button class="btn btn-sm btn-primary ml-0" id="button_long_exposure">Hide high concentration</button>
|
||||||
|
{% endif %}
|
||||||
|
<input type="checkbox" id="long_range_cumulative_checkbox">
|
||||||
|
<label class="form-check-label" for="long_range_cumulative_checkbox">Show long range cumulative doses</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div id="concentration_plot" style="height: 400px"></div>
|
<div id="concentration_plot" style="height: 400px"></div>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
|
@ -99,9 +103,12 @@
|
||||||
var concentrations = {{ concentrations | JSONify }}
|
var concentrations = {{ concentrations | JSONify }}
|
||||||
var short_range_concentrations = {{ short_range_concentrations | JSONify }}
|
var short_range_concentrations = {{ short_range_concentrations | JSONify }}
|
||||||
var cumulative_doses = {{ cumulative_doses | JSONify }}
|
var cumulative_doses = {{ cumulative_doses | JSONify }}
|
||||||
|
var long_range_cumulative_doses = {{ long_range_cumulative_doses | JSONify }}
|
||||||
var exposed_presence_intervals = {{ exposed_presence_intervals | JSONify }}
|
var exposed_presence_intervals = {{ exposed_presence_intervals | JSONify }}
|
||||||
var short_range_intervals = {{ short_range_intervals | JSONify }}
|
var short_range_intervals = {{ short_range_intervals | JSONify }}
|
||||||
draw_plot("concentration_plot", times, concentrations, short_range_concentrations, cumulative_doses, exposed_presence_intervals, short_range_intervals)
|
var short_range_activities = {{ short_range_activities | JSONify }}
|
||||||
|
draw_plot("concentration_plot", times, concentrations, short_range_concentrations, cumulative_doses,
|
||||||
|
long_range_cumulative_doses, exposed_presence_intervals, short_range_intervals, short_range_activities)
|
||||||
</script>
|
</script>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1212,6 +1212,38 @@ class ExposureModel:
|
||||||
return (self.concentration_model.concentration(time) +
|
return (self.concentration_model.concentration(time) +
|
||||||
self.short_range.short_range_concentration(self.concentration_model, time))
|
self.short_range.short_range_concentration(self.concentration_model, time))
|
||||||
|
|
||||||
|
def long_range_deposited_exposure_between_bounds(self, time1: float, time2: float) -> _VectorisedFloat:
|
||||||
|
deposited_exposure = 0.
|
||||||
|
|
||||||
|
emission_rate_per_aerosol = self.concentration_model.infected.emission_rate_per_aerosol_when_present()
|
||||||
|
aerosols = self.concentration_model.infected.aerosols()
|
||||||
|
f_inf = self.concentration_model.infected.fraction_of_infectious_virus()
|
||||||
|
fdep = self.long_range_fraction_deposited()
|
||||||
|
|
||||||
|
diameter = self.concentration_model.infected.particle.diameter
|
||||||
|
|
||||||
|
if not np.isscalar(diameter) and diameter is not None:
|
||||||
|
# we compute first the mean of all diameter-dependent quantities
|
||||||
|
# to perform properly the Monte-Carlo integration over
|
||||||
|
# particle diameters (doing things in another order would
|
||||||
|
# lead to wrong results).
|
||||||
|
dep_exposure_integrated = np.array(self._long_range_normed_exposure_between_bounds(time1, time2) *
|
||||||
|
aerosols *
|
||||||
|
fdep).mean()
|
||||||
|
else:
|
||||||
|
# in the case of a single diameter or no diameter defined,
|
||||||
|
# one should not take any mean at this stage.
|
||||||
|
dep_exposure_integrated = self._long_range_normed_exposure_between_bounds(time1, time2)*aerosols*fdep
|
||||||
|
|
||||||
|
# then we multiply by the diameter-independent quantity emission_rate_per_aerosol,
|
||||||
|
# and parameters of the vD equation (i.e. BR_k and n_in).
|
||||||
|
deposited_exposure += (dep_exposure_integrated * emission_rate_per_aerosol *
|
||||||
|
self.exposed.activity.inhalation_rate *
|
||||||
|
(1 - self.exposed.mask.inhale_efficiency()))
|
||||||
|
|
||||||
|
# In the end we multiply the final results by the fraction of infectious virus of the vD equation.
|
||||||
|
return deposited_exposure * f_inf
|
||||||
|
|
||||||
def deposited_exposure_between_bounds(self, time1: float, time2: float) -> _VectorisedFloat:
|
def deposited_exposure_between_bounds(self, time1: float, time2: float) -> _VectorisedFloat:
|
||||||
"""
|
"""
|
||||||
The number of virus per m^3 deposited on the respiratory tract
|
The number of virus per m^3 deposited on the respiratory tract
|
||||||
|
|
@ -1257,36 +1289,11 @@ class ExposureModel:
|
||||||
|
|
||||||
# then we multiply by the diameter-independent quantity virus viral load
|
# then we multiply by the diameter-independent quantity virus viral load
|
||||||
deposited_exposure *= self.concentration_model.virus.viral_load_in_sputum
|
deposited_exposure *= self.concentration_model.virus.viral_load_in_sputum
|
||||||
|
# long range concentration
|
||||||
# Long range concentration
|
|
||||||
emission_rate_per_aerosol = self.concentration_model.infected.emission_rate_per_aerosol_when_present()
|
|
||||||
f_inf = self.concentration_model.infected.fraction_of_infectious_virus()
|
f_inf = self.concentration_model.infected.fraction_of_infectious_virus()
|
||||||
aerosols = self.concentration_model.infected.aerosols()
|
deposited_exposure += self.long_range_deposited_exposure_between_bounds(time1, time2)/f_inf
|
||||||
fdep = self.long_range_fraction_deposited()
|
|
||||||
|
|
||||||
diameter = self.concentration_model.infected.particle.diameter
|
return deposited_exposure * f_inf
|
||||||
|
|
||||||
if not np.isscalar(diameter) and diameter is not None:
|
|
||||||
# we compute first the mean of all diameter-dependent quantities
|
|
||||||
# to perform properly the Monte-Carlo integration over
|
|
||||||
# particle diameters (doing things in another order would
|
|
||||||
# lead to wrong results).
|
|
||||||
dep_exposure_integrated = np.array(self._long_range_normed_exposure_between_bounds(time1, time2) *
|
|
||||||
aerosols *
|
|
||||||
fdep).mean()
|
|
||||||
else:
|
|
||||||
# in the case of a single diameter or no diameter defined,
|
|
||||||
# one should not take any mean at this stage.
|
|
||||||
dep_exposure_integrated = self._long_range_normed_exposure_between_bounds(time1, time2)*aerosols*fdep
|
|
||||||
|
|
||||||
# then we multiply by the diameter-independent quantity emission_rate_per_aerosol,
|
|
||||||
# and parameters of the vD equation (i.e. BR_k and n_in).
|
|
||||||
deposited_exposure += (dep_exposure_integrated * emission_rate_per_aerosol *
|
|
||||||
self.exposed.activity.inhalation_rate *
|
|
||||||
(1 - self.exposed.mask.inhale_efficiency()))
|
|
||||||
|
|
||||||
# In the end we multiply the final results by the fraction of infectious virus of the vD equation.
|
|
||||||
return f_inf * deposited_exposure
|
|
||||||
|
|
||||||
def deposited_exposure(self) -> _VectorisedFloat:
|
def deposited_exposure(self) -> _VectorisedFloat:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue