diff --git a/cpp/models/abm/abm.h b/cpp/models/abm/abm.h index 7f8727845c..91ea067f94 100644 --- a/cpp/models/abm/abm.h +++ b/cpp/models/abm/abm.h @@ -40,5 +40,6 @@ #include "abm/age.h" #include "abm/household.h" #include "abm/lockdown_rules.h" +#include "abm/npi.h" #endif diff --git a/cpp/models/abm/location.cpp b/cpp/models/abm/location.cpp index 6b966ed94e..f83c368702 100644 --- a/cpp/models/abm/location.cpp +++ b/cpp/models/abm/location.cpp @@ -113,6 +113,11 @@ void Location::cache_exposure_rates(TimePoint t, TimeSpan dt) } } +bool Location::may_enter(Person::RandomNumberGenerator& rng, const Person& person, TimePoint t) +{ + return m_NPIs(rng, person, *this, t); +} + void Location::add_person(Person& p, std::vector cells) { std::lock_guard lk(m_mut); diff --git a/cpp/models/abm/location.h b/cpp/models/abm/location.h index cb6eadb63e..57fe38de18 100644 --- a/cpp/models/abm/location.h +++ b/cpp/models/abm/location.h @@ -26,6 +26,7 @@ #include "abm/location_type.h" #include "abm/infection_state.h" #include "abm/vaccine.h" +#include "abm/npi.h" #include "memilio/math/eigen.h" #include "memilio/utils/custom_index_array.h" @@ -168,6 +169,11 @@ class Location void interact(Person::RandomNumberGenerator& rng, Person& person, TimePoint t, TimeSpan dt, const GlobalInfectionParameters& global_params) const; + /** + * @brief Check if a Person is allowed to enter this Location. + */ + bool may_enter(Person::RandomNumberGenerator& rng, const Person& person, TimePoint t); + /** * @brief Add a Person to the population at this Location. * @param[in] person The Person arriving. @@ -351,7 +357,7 @@ class Location } private: - std::mutex m_mut; ///< Mutex to protect the list of persons from concurrent modification. + std::mutex m_mut; ///< Mutex to protect the list of Person%s from concurrent modification. LocationId m_id; ///< Id of the Location including type and index. bool m_capacity_adapted_transmission_risk; /**< If true considers the LocationCapacity for the computation of the transmission risk.*/ @@ -361,6 +367,7 @@ class Location InfectionState::Count)}; ///< A TimeSeries of the #InfectionState%s for each TimePoint at the Location. std::vector m_cells{}; ///< A vector of all Cell%s that the Location is divided in. MaskType m_required_mask; ///< Least secure type of Mask that is needed to enter the Location. + LocationNPIStrategy m_NPIs{AcceptBase{}}; ///< Set of NPIs that affect this location. Can be called. bool m_npi_active; ///< If true requires e.g. Mask%s to enter the Location. GeographicalLocation m_geographical_location; ///< Geographical location (longitude and latitude) of the Location. }; diff --git a/cpp/models/abm/npi.cpp b/cpp/models/abm/npi.cpp new file mode 100644 index 0000000000..a0af3ea89d --- /dev/null +++ b/cpp/models/abm/npi.cpp @@ -0,0 +1,153 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: David Kerkman +* +* Contact: Martin J. Kuehn +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "abm/npi.h" +#include "abm/person.h" +#include "abm/location.h" + +namespace mio +{ +namespace abm +{ + +/** + * Base NPI, but equipped with a stringency which is often useful for all kind of NPIs. + * Alternatively, this can also be implemented in each NPI directly. +*/ +struct AcceptBaseStringency : AcceptBase { + AcceptBaseStringency() = default; + AcceptBaseStringency(double strin) + : stringency(strin) + { + } + double stringency = 1.; +}; + +/** + * @brief NPI to require the usage of masks for entering the Location. +*/ +struct MaskRequired : AcceptBaseStringency { + + MaskRequired(MaskType mt) + : mask_type(mt) + { + } + + MaskRequired(MaskType mt, double strin) + : AcceptBaseStringency(strin) + , mask_type(mt) + { + } + + bool operator()(Person::RandomNumberGenerator& rng, const Person& p, const Location& loc, TimePoint /*t*/) override + { + return p.apply_mask_intervention(rng, loc); + } + + MaskType mask_type; +}; + +/** + * @brief NPI to set the maximum capacity for entering for the Location. Use 0 for a complete shutdown. +*/ +struct CapacityAbsolute : AcceptBaseStringency { + + CapacityAbsolute(uint32_t cap) + : capacity(cap) + { + } + + CapacityAbsolute(uint32_t cap, double strin) + : AcceptBaseStringency(strin) + , capacity(cap) + { + } + + bool operator()(Person::RandomNumberGenerator& /*rng*/, const Person& /*p*/, const Location& loc, + TimePoint /*t*/) override + { + return loc.get_number_persons() < capacity; + } + + uint32_t capacity; +}; + +/** + * @brief NPI to set the relative capacity change for entering the Location. Use 0 for a complete shutdown. +*/ +struct CapacityRelative : AcceptBaseStringency { + + CapacityRelative(double cap_fac) + : capacity_factor(cap_fac) + { + } + + CapacityRelative(double cap_fac, double strin) + : AcceptBaseStringency(strin) + , capacity_factor(cap_fac) + { + } + + bool operator()(Person::RandomNumberGenerator& /*rng*/, const Person& /*p*/, const Location& loc, + TimePoint /*t*/) override + { + return loc.get_number_persons() < capacity_factor * loc.get_capacity().persons; + } + + double capacity_factor; +}; + +/** + * @brief NPI to set the required tests for entering the Location. +*/ +struct TestRequired : AcceptBaseStringency { + + TestRequired(TestingScheme& ts) + : testing_scheme(&ts) + { + } + + TestRequired(TestingScheme& ts, double strin) + : AcceptBaseStringency(strin) + , testing_scheme(&ts) + { + } + + bool operator()(Person::RandomNumberGenerator& rng, const Person& p, const Location& loc, TimePoint t) override + { + return testing_scheme->run_scheme(rng, p, loc, t); + } + + TestingScheme* testing_scheme; +}; + +struct NPISet : AcceptBase { + LocationNPI mask{AcceptBase{}}; + LocationNPI capacity{AcceptBase{}}; + LocationNPI test{AcceptBase{}}; + + bool operator()(Person::RandomNumberGenerator& rng, const Person& p, const Location& loc, TimePoint t) override + { + return mask(rng, p, loc, t) && capacity(rng, p, loc, t) && test(rng, p, loc, t); + } +}; + +} // namespace abm +} // namespace mio diff --git a/cpp/models/abm/npi.h b/cpp/models/abm/npi.h new file mode 100644 index 0000000000..8598e85d6f --- /dev/null +++ b/cpp/models/abm/npi.h @@ -0,0 +1,58 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* & Helmholtz Centre for Infection Research (HZI) +* +* Authors: David Kerkmann +* +* Contact: Martin J. Kuehn +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef EPI_ABM_NPI_H +#define EPI_ABM_NPI_H + +#include +#include "abm/mask_type.h" +#include "abm/time.h" +#include "abm/testing_strategy.h" +#include "memilio/utils/random_number_generator.h" + +namespace mio +{ +namespace abm +{ + +/** + * TODO: Template everything with variable arguments. + * TODO: Probably remove std::function for better efficiency and access to final NPI data members. +*/ +class Location; +class Person; +using LocationNPIStrategy = + std::function; + +/** + * @brief Base NPI to always allow entrance. +*/ +struct AcceptBase { + virtual ~AcceptBase() = default; + virtual bool operator()(Person::RandomNumberGenerator&, const Person&, const Location&, TimePoint) + { + return true; + } +}; + +} // namespace abm +} // namespace mio + +#endif //EPI_ABM_NPI_H