Skip to content
2 changes: 1 addition & 1 deletion cpp/models/abm/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ void Model::compute_exposure_caches(TimePoint t, TimeSpan dt)
assert(m_persons[i].get_location_model_id() == m_id && "Person is not in this model but still active.");
mio::abm::add_exposure_contribution(m_air_exposure_rates_cache[location],
m_contact_exposure_rates_cache[location], person,
get_location(person.get_location()), t, dt);
get_location(person.get_location()), parameters, t, dt);
}
} // implicit taskloop barrier
} // implicit single barrier
Expand Down
21 changes: 13 additions & 8 deletions cpp/models/abm/model_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ void interact(PersonalRandomNumberGenerator& personal_rng, Person& person, const
}

void add_exposure_contribution(AirExposureRates& local_air_exposure, ContactExposureRates& local_contact_exposure,
const Person& person, const Location& location, const TimePoint t, const TimeSpan dt)
const Person& person, const Location& location, const Parameters& params,
const TimePoint t, const TimeSpan dt)
{
if (person.get_location() != location.get_id()) {
mio::log_debug("In add_exposure_contribution: Person {} is not at Location {}", person.get_id().get(),
Expand All @@ -110,16 +111,20 @@ void add_exposure_contribution(AirExposureRates& local_air_exposure, ContactExpo
auto virus = infection.get_virus_variant();
auto age = person.get_age();
// average infectivity over the time step to second order accuracy using midpoint rule
const auto infectivity = infection.get_infectivity(t + dt / 2);
const auto quarantine_factor =
person.is_in_quarantine(t, params) ? (1.0 - params.get<QuarantineEffectiveness>()) : 1.0;

for (CellIndex cell : person.get_cells()) {
auto air_contribution = infectivity * quarantine_factor;
auto contact_contribution = infectivity * quarantine_factor;

if (location.get_infection_parameters().get<UseLocationCapacityForTransmissions>()) {
local_air_exposure[{cell, virus}] +=
infection.get_infectivity(t + dt / 2) *
location.get_cells()[cell.get()].compute_space_per_person_relative();
air_contribution *= location.get_cells()[cell.get()].compute_space_per_person_relative();
}
else {
local_air_exposure[{cell, virus}] += infection.get_infectivity(t + dt / 2);
}
local_contact_exposure[{cell, virus, age}] += infection.get_infectivity(t + dt / 2);

local_air_exposure[{cell, virus}] += air_contribution;
local_contact_exposure[{cell, virus, age}] += contact_contribution;
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion cpp/models/abm/model_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,13 @@ ScalarType daily_transmissions_by_air(const AirExposureRates& rates, const CellI
* @param[in, out] local_contact_exposure Exposure by rates contacts for the local population.
* @param[in] person A person from the local population.
* @param[in] location The person's current location.
* @param[in] params The parameter set of the Model.
* @param[in] t Current Simulation time.
* @param[in] dt Length of the current Simulation time step.
*/
void add_exposure_contribution(AirExposureRates& local_air_exposure, ContactExposureRates& local_contact_exposure,
const Person& person, const Location& location, const TimePoint t, const TimeSpan dt);
const Person& person, const Location& location, const Parameters& params,
const TimePoint t, const TimeSpan dt);

/**
* @brief Let a Person interact with the population at its current Location, possibly getting infected.
Expand Down
28 changes: 24 additions & 4 deletions cpp/models/abm/parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,21 @@ struct QuarantineDuration {
}
};

/**
* @brief Effectiveness of quarantine. 0.0 meaning no effect (percentage reduction of viral shed emission), 1.0 meaning full effect.
*/
struct QuarantineEffectiveness {
using Type = ScalarType;
static auto get_default(AgeGroup /*size*/)
{
return 0.0;
}
static std::string name()
{
return "QuarantineEffectivness";
}
};

/**
* @brief Parameter for the exponential distribution to decide if a Person goes shopping.
*/
Expand Down Expand Up @@ -687,10 +702,10 @@ using ParametersBase =
TimeInfectedCriticalToRecovered, SymptomsPerInfectedNoSymptoms, SeverePerInfectedSymptoms,
CriticalPerInfectedSevere, DeathsPerInfectedSevere, DeathsPerInfectedCritical, ViralLoadDistributions,
InfectivityDistributions, VirusShedFactor, DetectInfection, MaskProtection, AerosolTransmissionRates,
LockdownDate, QuarantineDuration, SocialEventRate, BasicShoppingRate, WorkRatio, SchoolRatio,
GotoWorkTimeMinimum, GotoWorkTimeMaximum, GotoSchoolTimeMinimum, GotoSchoolTimeMaximum,
AgeGroupGotoSchool, AgeGroupGotoWork, InfectionProtectionFactor, SeverityProtectionFactor,
HighViralLoadProtectionFactor, TestData>;
LockdownDate, QuarantineDuration, QuarantineEffectiveness, SocialEventRate, BasicShoppingRate,
WorkRatio, SchoolRatio, GotoWorkTimeMinimum, GotoWorkTimeMaximum, GotoSchoolTimeMinimum,
GotoSchoolTimeMaximum, AgeGroupGotoSchool, AgeGroupGotoWork, InfectionProtectionFactor,
SeverityProtectionFactor, HighViralLoadProtectionFactor, TestData>;

/**
* @brief Maximum number of Person%s an infectious Person can infect at the respective Location.
Expand Down Expand Up @@ -984,6 +999,11 @@ class Parameters : public ParametersBase
return true;
}

if (this->get<QuarantineEffectiveness>() < 0.0 || this->get<QuarantineEffectiveness>() > 1.0) {
log_error("Constraint check: Parameter QuarantineEffectiveness not between {:d,:d}", 0.0, 1.0);
return true;
}

return false;
}

Expand Down
4 changes: 2 additions & 2 deletions cpp/tests/abm_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ void interact_testing(mio::abm::PersonalRandomNumberGenerator& personal_rng, mio
std::for_each(local_contact_exposure.begin(), local_contact_exposure.end(), [](auto& r) {
r = 0.0;
});
// caclculate current exposures
// calculate current exposures
for (const mio::abm::Person& p : local_population) {
add_exposure_contribution(local_air_exposure, local_contact_exposure, p, location, t, dt);
add_exposure_contribution(local_air_exposure, local_contact_exposure, p, location, global_parameters, t, dt);
}
// run interaction
mio::abm::interact(personal_rng, person, location, local_air_exposure, local_contact_exposure, t, dt,
Expand Down
3 changes: 2 additions & 1 deletion cpp/tests/test_abm_location.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ TEST_F(TestLocation, interact)

// Setup location with some chance of exposure
mio::abm::Location location(mio::abm::LocationType::Work, 0, num_age_groups);
location.get_infection_parameters().get<mio::abm::UseLocationCapacityForTransmissions>() = true;
auto infected1 = make_test_person(this->get_rng(), location, age_group_15_to_34,
mio::abm::InfectionState::InfectedNoSymptoms, t, params);
auto infected2 = make_test_person(this->get_rng(), location, age_group_80_plus,
Expand Down Expand Up @@ -185,4 +186,4 @@ TEST_F(TestLocation, adjustContactRates)
auto adjusted_contacts_rate =
loc.get_infection_parameters().get<mio::abm::ContactRates>()[{mio::AgeGroup(0), mio::AgeGroup(0)}];
EXPECT_EQ(adjusted_contacts_rate, 2);
}
}
8 changes: 8 additions & 0 deletions cpp/tests/test_abm_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,8 @@ TEST_F(TestModel, checkParameterConstraints)
params.get<mio::abm::MaskProtection>()[mio::abm::MaskType::Community] = 0.5;
params.get<mio::abm::MaskProtection>()[mio::abm::MaskType::FFP2] = 0.6;
params.get<mio::abm::MaskProtection>()[mio::abm::MaskType::Surgical] = 0.7;
params.get<mio::abm::QuarantineEffectiveness>() = 0.5;
params.get<mio::abm::QuarantineDuration>() = mio::abm::days(14);
params.get<mio::abm::LockdownDate>() = mio::abm::TimePoint(0);
ASSERT_EQ(params.check_constraints(), false);

Expand Down Expand Up @@ -789,6 +791,12 @@ TEST_F(TestModel, checkParameterConstraints)
EXPECT_TRUE(params.check_constraints());
params.get<mio::abm::MaskProtection>()[mio::abm::MaskType::Surgical] = 0.7;

params.get<mio::abm::QuarantineEffectiveness>() = -0.1;
EXPECT_TRUE(params.check_constraints());
params.get<mio::abm::QuarantineEffectiveness>() = 1.5;
EXPECT_TRUE(params.check_constraints());
params.get<mio::abm::QuarantineEffectiveness>() = 0.8;

params.get<mio::abm::LockdownDate>() = mio::abm::TimePoint(-2);
EXPECT_TRUE(params.check_constraints());
mio::set_log_level(mio::LogLevel::warn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ def test_network_fit(self, mock_population, mock_baseline, mock_minimum):
model.network_fit(
path=self.path, model=md,
modeltype='classic', training_parameter=training_parameter, filename="data_secir_groups.pickle")

# check error message
error_message_part1 = "[Errno 2] No such file or directory"
error_message_part2 = self.path
Expand Down