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
|
|
@ -245,11 +245,17 @@ class FormData:
|
|||
else:
|
||||
humidity = 0.5
|
||||
room = models.Room(volume=volume, humidity=humidity)
|
||||
|
||||
if self.short_range_option == "short_range_yes":
|
||||
sr_presence=self.short_range_intervals()
|
||||
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=()
|
||||
|
||||
sr_presence=self.short_range_intervals()
|
||||
sr_activities=self.short_range_activities()
|
||||
short_range_expirations = tuple(short_range_expiration_distributions[activity] for activity in sr_activities)
|
||||
|
||||
# Initializes and returns a model with the attributes defined above
|
||||
return mc.ExposureModel(
|
||||
concentration_model=mc.ConcentrationModel(
|
||||
|
|
@ -261,7 +267,7 @@ class FormData:
|
|||
short_range = mc.ShortRangeModel(
|
||||
presence=sr_presence,
|
||||
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(),
|
||||
)
|
||||
|
|
@ -639,15 +645,13 @@ class FormData:
|
|||
)
|
||||
|
||||
def short_range_intervals(self) -> typing.Tuple[typing.Tuple[str, models.SpecificInterval], ...]:
|
||||
if (self.short_range_interactions):
|
||||
short_range_intervals = []
|
||||
for interaction in self.short_range_interactions:
|
||||
start_time = time_string_to_minutes(interaction['start_time'])
|
||||
duration = float(interaction['duration'])
|
||||
short_range_intervals.append((interaction['activity'], models.SpecificInterval((start_time/60, (start_time + duration)/60))))
|
||||
return tuple(short_range_intervals)
|
||||
else:
|
||||
return ()
|
||||
short_range_intervals = []
|
||||
for interaction in self.short_range_interactions:
|
||||
start_time = time_string_to_minutes(interaction['start_time'])
|
||||
duration = float(interaction['duration'])
|
||||
short_range_intervals.append((interaction['activity'], models.SpecificInterval((start_time/60, (start_time + duration)/60))))
|
||||
return tuple(short_range_intervals)
|
||||
|
||||
|
||||
def exposed_present_interval(self) -> models.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()
|
||||
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 {
|
||||
"times": list(times),
|
||||
"short_range_intervals": short_range_intervals,
|
||||
"short_range_activities": short_range_activities,
|
||||
"exposed_presence_intervals": [list(interval) for interval in model.exposed.presence.boundaries()],
|
||||
"cumulative_doses": list(cumulative_doses),
|
||||
"long_range_cumulative_doses": list(long_range_cumulative_doses),
|
||||
"short_range_concentrations": short_range_concentrations,
|
||||
"concentrations": sr_breathing_concentrations,
|
||||
"highest_const": highest_const,
|
||||
|
|
|
|||
|
|
@ -405,7 +405,7 @@ function validate_form(form) {
|
|||
}
|
||||
|
||||
// Generate the short range interactions list
|
||||
let short_range_interactions = [];
|
||||
var short_range_interactions = [];
|
||||
$(".form_field_outer_row").each(function (index, element){
|
||||
let obj = {};
|
||||
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();
|
||||
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 + ']');
|
||||
if (short_range_interactions.length == 0) {
|
||||
$("input[type=radio][id=short_range_no]").prop("checked", true);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
/* 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
|
||||
let button_full_exposure = document.getElementById("button_full_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))
|
||||
|
||||
var data_for_graphs = {
|
||||
'concentrations': [],
|
||||
'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.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
|
||||
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,
|
||||
|
||||
yRange = d3.scaleLinear(),
|
||||
yCumulativeRange = d3.scaleLinear().domain([0., Math.max(...cumulative_doses)*1.1]),
|
||||
yCumulativeRange = d3.scaleLinear(),
|
||||
|
||||
yAxis = d3.axisLeft();
|
||||
yCumulativeAxis = d3.axisRight(yCumulativeRange).ticks(4);
|
||||
yAxis = d3.axisLeft(),
|
||||
yCumulativeAxis = d3.axisRight();
|
||||
|
||||
// X axis declaration.
|
||||
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.
|
||||
var yAxisCumEl = vis.append('svg:g')
|
||||
.attr('class', 'y axis')
|
||||
.style('font-size', 14)
|
||||
.style("stroke-dasharray", "5 5");
|
||||
|
||||
// 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-opacity', '0.1');
|
||||
|
||||
sr_unique_activities = [...new Set(short_range_activities)]
|
||||
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('height', 15)
|
||||
.attr('fill', '#1f00b4')
|
||||
.attr('fill-opacity', '0.1');
|
||||
.attr('height', 15);
|
||||
if (sr_unique_activities[index] == 'Breathing') legendShortRangeAreaIcon[index].attr('fill', 'red').attr('fill-opacity', '0.2');
|
||||
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')
|
||||
|
|
@ -105,14 +114,17 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
|||
.attr('alignment-baseline', 'central');
|
||||
|
||||
if (show_sr_legend) {
|
||||
var legendShortRangeText = vis.append('text')
|
||||
.text('Short range interaction(s)')
|
||||
var legendShortRangeText = {};
|
||||
sr_unique_activities.forEach((b, index) => {
|
||||
legendShortRangeText[index] = vis.append('text')
|
||||
.text('Short range - ' + sr_unique_activities[index])
|
||||
.style('font-size', '15px')
|
||||
.attr('alignment-baseline', 'central');
|
||||
});
|
||||
}
|
||||
|
||||
// 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;
|
||||
var legendBBox = vis.append('rect')
|
||||
.attr('width', 255)
|
||||
|
|
@ -140,12 +152,23 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
|||
|
||||
// Line representing the cumulative concentration.
|
||||
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-width', 2)
|
||||
.style("stroke-dasharray", "5 5")
|
||||
.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).
|
||||
var exposedArea = {};
|
||||
var drawArea = {};
|
||||
|
|
@ -161,10 +184,11 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
|||
var drawShortRangeArea = {};
|
||||
short_range_intervals.forEach((b, index) => {
|
||||
shortRangeArea[index] = d3.area();
|
||||
drawShortRangeArea[index] = draw_area.append('svg:path')
|
||||
.attr('class', 'draw_short_range_area')
|
||||
.attr('fill', '#1f00b4')
|
||||
.attr('fill-opacity', '0.1');
|
||||
drawShortRangeArea[index] = draw_area.append('svg:path');
|
||||
|
||||
if (short_range_activities[index] == 'Breathing') drawShortRangeArea[index].attr('fill', 'red').attr('fill-opacity', '0.2');
|
||||
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.
|
||||
|
|
@ -202,9 +226,12 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
|||
.attr('pointer-events', 'all');
|
||||
}
|
||||
|
||||
function update_concentration_plot(data) {
|
||||
yRange.domain([0., Math.max(...data)]);
|
||||
function update_concentration_plot(concentration_data, cumulative_data) {
|
||||
yRange.domain([0., Math.max(...concentration_data)*1.1]);
|
||||
yAxisEl.transition().duration(1000).call(yAxis);
|
||||
|
||||
yCumulativeRange.domain([0., Math.max(...cumulative_data)*1.1]);
|
||||
yAxisCumEl.transition().duration(1000).call(yCumulativeAxis)
|
||||
|
||||
// Concentration line
|
||||
lineFunc.defined(d => !isNaN(d.concentration))
|
||||
|
|
@ -215,6 +242,24 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
|||
.duration(1000)
|
||||
.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.
|
||||
exposed_presence_intervals.forEach((b, index) => {
|
||||
exposedArea[index].x(d => xTimeRange(d.time))
|
||||
|
|
@ -327,6 +372,7 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
|||
// Axis.
|
||||
var xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d));
|
||||
yAxis.scale(yRange);
|
||||
yCumulativeAxis.scale(yCumulativeRange);
|
||||
|
||||
xAxisEl.attr('transform', 'translate(0,' + (graph_height - margins.bottom) + ')')
|
||||
.call(xAxis);
|
||||
|
|
@ -374,10 +420,12 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
|||
.attr('y', margins.top + 3 * size);
|
||||
|
||||
if (show_sr_legend) {
|
||||
legendShortRangeAreaIcon.attr('x', graph_width + size * 2.5)
|
||||
.attr('y', margins.top + 3.6 * size);
|
||||
legendShortRangeText.attr('x', graph_width + 4 * size)
|
||||
.attr('y', margins.top + 4 * size);
|
||||
sr_unique_activities.forEach((b, index) => {
|
||||
legendShortRangeAreaIcon[index].attr('x', graph_width + size * 2.5)
|
||||
.attr('y', margins.top + 3.6 * size + index * size);
|
||||
legendShortRangeText[index].attr('x', graph_width + 4 * size)
|
||||
.attr('y', margins.top + 4 * size + index * size);
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (show_sr_legend) {
|
||||
legendShortRangeAreaIcon.attr('x', size * 0.50)
|
||||
.attr('y', graph_height * 1.175 + size);
|
||||
legendShortRangeText.attr('x', 2 * size)
|
||||
.attr('y', graph_height + 3.65 * size);
|
||||
sr_unique_activities.forEach((b, index) => {
|
||||
legendShortRangeAreaIcon[index].attr('x', size * 0.50)
|
||||
.attr('y', graph_height * 1.175 + size + index * size);
|
||||
legendShortRangeText[index].attr('x', 2 * size)
|
||||
.attr('y', graph_height + 3.65 * size + index * size);
|
||||
});
|
||||
}
|
||||
|
||||
legendBBox.attr('x', 1)
|
||||
|
|
@ -419,23 +469,25 @@ function draw_plot(svg_id, times, concentrations, short_range_concentrations, cu
|
|||
.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) {
|
||||
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_long_exposure.disabled = false;
|
||||
});
|
||||
}
|
||||
if (button_long_exposure) {
|
||||
button_long_exposure.addEventListener("click", () => {
|
||||
update_concentration_plot(concentrations);
|
||||
update_concentration_plot(concentrations, long_range_cumulative_doses);
|
||||
button_full_exposure.disabled = false;
|
||||
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.
|
||||
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.
|
||||
window.addEventListener("resize", e => {
|
||||
redraw();
|
||||
if (button_full_exposure.disabled) update_concentration_plot(short_range_concentrations);
|
||||
else update_concentration_plot(concentrations)
|
||||
if (button_full_exposure.disabled) update_concentration_plot(short_range_concentrations, cumulative_doses);
|
||||
else update_concentration_plot(concentrations, long_range_cumulative_doses)
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -89,19 +89,26 @@
|
|||
{% endblock report_summary_footnote %}
|
||||
</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>
|
||||
{% if (form.short_range_option == "short_range_yes" and concentrations|max|int != short_range_concentrations|max|int ) %}
|
||||
<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 %}
|
||||
{% if form.short_range_option == "short_range_yes" %}
|
||||
{% if concentrations|max|int != short_range_concentrations|max|int %}
|
||||
<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 %}
|
||||
<div id="concentration_plot" style="height: 400px"></div>
|
||||
<script type="application/javascript">
|
||||
var times = {{ times | JSONify }}
|
||||
var concentrations = {{ concentrations | JSONify }}
|
||||
var short_range_concentrations = {{ short_range_concentrations | 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 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>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1212,6 +1212,38 @@ class ExposureModel:
|
|||
return (self.concentration_model.concentration(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:
|
||||
"""
|
||||
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
|
||||
deposited_exposure *= self.concentration_model.virus.viral_load_in_sputum
|
||||
|
||||
# Long range concentration
|
||||
emission_rate_per_aerosol = self.concentration_model.infected.emission_rate_per_aerosol_when_present()
|
||||
# long range concentration
|
||||
f_inf = self.concentration_model.infected.fraction_of_infectious_virus()
|
||||
aerosols = self.concentration_model.infected.aerosols()
|
||||
fdep = self.long_range_fraction_deposited()
|
||||
deposited_exposure += self.long_range_deposited_exposure_between_bounds(time1, time2)/f_inf
|
||||
|
||||
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 f_inf * deposited_exposure
|
||||
return deposited_exposure * f_inf
|
||||
|
||||
def deposited_exposure(self) -> _VectorisedFloat:
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in a new issue