Virus Propagation Calibration
agrignard opened this issue · 8 comments
THIS ISSUE IS AN ATTEMPT TO GIVE THE POSSIBILITY TO PEOPLE/USER TO USE AND CRITIC THE MODEL BY:
1. DOCUMENTING THE MODEL
2. VALIDATING THE PARAMETER
3. DESIGNING A STORY TELLING TO EXPLAIN THE MODEL
Different people might be involved in this issues thread so let's see how the issue workflow works or not. So welcome everyone and here is a short introduction of who is involved in what in this issue/project
@agrignard , @tnguyenh and @ptaillandier are the one implementing, running and debugging the model itself
@rocheben will give us insight on the coherence and consistency of the model itself and the parameters
@LAAP, @nayoub might have some story telling feedback and external question and will help to put in design those lines of code in a graphical way.
People has a list of infection made of 3 values: direct, object and air
list<float> cumulated_viral_load <-[0.0,0.0,0.0];
which is updated at every step according to the following rules:
- DIRECT INFECTION (cumulated_viral_load[0])
ask (ViralPeople at_distance infectionDistance) {
geometry line <- line([myself,self]);
if empty(wall overlapping line) {
float direct_infection_factor_real <- direct_infection_factor * step;
if empty(separator_ag overlapping line) {
direct_infection_factor_real <- direct_infection_factor_real * (1 - diminution_cumulated_viral_load_separator);
}
if myself.has_mask {
direct_infection_factor_real <- direct_infection_factor_real * (1 - diminution_cumulated_viral_load_mask_emission);
}
if self.has_mask{
direct_infection_factor_real <- direct_infection_factor_real * (1 - diminution_cumulated_viral_load_mask_reception);
}
cumulated_viral_load[0] <- cumulated_viral_load[0] + direct_infection_factor_real;
}
}
with the following value
float diminution_cumulated_viral_load_mask_emission <- 0.7; //1.0 masks are totaly efficient to avoid direct transmission
float diminution_cumulated_viral_load_mask_reception <- 0.7; //1.0 masks are totaly efficient to avoid direct transmission
float diminution_cumulated_viral_load_separator <- 0.9;
- OBJECT INFECTION
- INFECTION OF OBJECT
In ViralPeople
if (objects_infection) and (time_since_last_hand_cleaning < hand_cleaning_time_effect){
ViralCell vc <- ViralCell(self.target.location);
if (vc != nil) {
ask (vc){
do add_viral_load(myself.has_mask? mask_indirect_infection_factor*indirect_infection_factor * step:indirect_infection_factor * step);
}
}
}
with
float indirect_infection_factor<-0.003;
and where a ViralCell Grid is defined as following:
grid ViralCell cell_width: 1.0 cell_height:1.0 neighbors: 8 {
float viral_load_by_touching min: 0.0 max: 10.0;
action add_viral_load(float value){
viral_load_by_touching <- viral_load_by_touching+value;
}
//Action to update the viral load (i.e. trigger decreases)
reflex update_viral_load {
viral_load_by_touching <- viral_load_by_touching * (1- basic_viral_decrease_cell) ^ step;
}
}
with
float basic_viral_decrease_cell <- 0.0003;
float mask_indirect_infection_factor<-0.25;
- INFECTION BY OBJECT ((cumulated_viral_load[1]))
reflex infection_by_objects when:not target.not_yet_active and not target.end_of_day and objects_infection and not is_infected and not target.is_outside and not target.using_sanitation {
ViralCell vrc <- ViralCell(location);
if (vrc != nil) {cumulated_viral_load[1] <- cumulated_viral_load[1] + (self.has_mask? mask_indirect_infection_factor* step * vrc.viral_load_by_touching: step * vrc.viral_load_by_touching);}
}
3. AIR INFECTION
- AIR INFECTION (ROOM INFECTION)
People emit Virus
ViralRoom my_room <- first(ViralRoom overlapping location);
if (my_room != nil) {ask my_room{do add_viral_load(myself.has_mask ? mask_air_infection_factor*air_infection_factor * step : air_infection_factor * step);}}
ViralCommonArea my_rca <- first(ViralCommonArea overlapping location);
if (my_rca != nil) {ask my_rca{do add_viral_load(myself.has_mask ? mask_air_infection_factor*air_infection_factor * step : air_infection_factor * step);}}
with
float air_infection_factor <- 0.0005;
float mask_air_infection_factor<-0.25;
Room diffuse the virus
reflex update_viral_load when: air_infection{
if (target.isVentilated) {
viral_load <- viral_load * (1-ventilated_viral_decrease_room)^ step;
} else {
viral_load <- viral_load * (1-basic_viral_decrease_room) ^ step;
}
}
with
float basic_viral_decrease_room <- 0.0001; //decreasement of the viral load of cells per second
float ventilated_viral_decrease_room <- 0.001; //decreasement of the viral load of cells per second
- INFECTION BY AIR ((cumulated_viral_load[2])
reflex infection_by_air {
ViralRoom my_room <- first(ViralRoom overlapping location);
if (my_room != nil) {ask my_room{do add_viral_load(myself.has_mask ? mask_air_infection_factor*air_infection_factor * step : air_infection_factor * step);}}
ViralCommonArea my_rca <- first(ViralCommonArea overlapping location);
if (my_rca != nil) {ask my_rca{do add_viral_load(myself.has_mask ? mask_air_infection_factor*air_infection_factor * step : air_infection_factor * step);}}
}
4. SANITATION
reflex using_sanitation when: not target.not_yet_active and not target.end_of_day and target.using_sanitation {
cumulated_viral_load[1] <- cumulated_viral_load[1] * (1- diminution_cumulated_viral_load_sanitation) ^ step;
time_since_last_hand_cleaning <- 0.0;
}
````
with
float diminution_cumulated_viral_load_sanitation <- 0.1;
Thank you @agrignard , this is a great starting point, I think that @tnguyenh and I can try to translate this into math (formulas)
The storytelling is already in your presentation. We try to reopen the UdeG, then we have build this model with the 3 ways of getting infected (3 values: direct, object and air) and 6 interventions (Masks, social distancing, ventilation, density, time, sanitation) and to learn how the infection risk can be higher if we do not use this 6 interventions, and how can we reduce the infection risk if we implement this 6 intervetions.
Just a comment because there is something that is ambiguous in this code, and that may deceptive to some readers: infection_risks and viral_loads are assumed to be the same thing, while they are two different things in reality. In this model, what is calculated is the cumulative viral_loads to which each agent is exposed (and for rooms and object, it is the viral_load at a given time that is calculated). It is then used as a proxy for infection_risk.
Viral_load is well defined (quantity or concentration of viruses), but infection_risk is not, and may be defined several ways: probability to get the disease at the end of the day, cumulative exposure to virus. In the model, it is the second way that has been chosen (for now). I think that variables should be renamed in order to avoid ambiguity that may prevent a good understanding of the model and slow down further developments...
@tnguyenh thank you for the feedback so infection_risk has been changed by cumulated_viral_load
I uploaded the equations as a .pdf, better than a .png to preserve quality while zooming.
I think this is a nice starting point. However, I think there is something unclear. You have direct infection, infection by air, and infection through object. But what is direct infection ? Through direct contacts ? I think you're duplicating something here... Actually, direct infection is either by air, through object or through direct contact. So, in your study, the viral load should be the core object. You can have viral particles in the air or on the objects, as you did. But you need also to model explicitly the viral particles on people body to consider infection through direct contacts
Hi @rocheben thank you very much for taking time to have a look at this.
Yes I see what you mean, by direct infection we meant people that are in less than the security distance (e.g 2m) but you're right at the end they are contacted by air but just the probability is much more higher because the viral load is.
So maybe we can think about a more elaborated infection by air process that differentiate the less than 2m with the greater than 2 meter
Hi @rocheben. Just to clarify:
the risk for an agent is estimated by the viral load it has been in contact with (via breathing or contact). As such, you're right about the fact the viral load is de facto the core concept, while we want to actually do is to estimate a risk. A natural way for this estimation is to quantify the exposure to the virus, and so estimate the viral load. But we decided not to differentiate the viral load in the lungs from the one on the body for the sake of simplicity, since the viral load is not the true objective. Do you think it is an issue ?
Regarding to the names, I think they are misleading and not technically correct. There are three kind of infection in this model:
- aerosols: the viral load is breathed by the agent (maybe it can just accumulate on his skin, but again this has not been differentiated from breathing). This is what is called 'infection by air'.
- droplets: this is the viral load emitted by people when they breath, talk, snore, etc. We assumed that the viral load does not remain in the air, so it can only infect people within a given radius (2m ?) at the moment it is emitted. This is called 'direct infection'. The remaining viral load is then discarded/dropped on the floor (choose the best option).
- fomites: this is 'infection by objets'. Again, for the sake of simplicity, we have not differentiated the viral load in the lung from the one on the body. The idea is to provide an average viral load that is transmitted to the surface by someone with the disease (and reversely an average viral load transmitted to someone by an infected surface, given its viral load). Do you think it is not consistent enough with the modelling of the other ways of contamination ?
In this model, there is for now no infection through direct contact between two people (shaking hands, etc...) Don't know if it should be part of the model or not. It could be implicitly included in the droplet way of infection (in that case the name 'direct infection' would make more sense).
The model is now validated and calibrated and will be published in the corresponding paper in MABS 2021 in AAMAS