Skip to content

1280 trip addition overhaul #1281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cpp/models/abm/mobility_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ namespace abm
*/
enum class TransportMode : uint32_t
{
Unknown = 0,
Bike,
CarDriver,
CarPassenger,
PublicTransport,
Walking,
Other,
Unknown,
Count //last!!
};

Expand Down
7 changes: 3 additions & 4 deletions cpp/models/abm/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,12 @@ void Model::perform_mobility(TimePoint t, TimeSpan dt)
}

// check if a person makes a trip
bool weekend = t.is_weekend();
size_t num_trips = m_trip_list.num_trips(weekend);
size_t num_trips = m_trip_list.num_trips();

for (; m_trip_list.get_current_index() < num_trips &&
m_trip_list.get_next_trip_time(weekend).seconds() < (t + dt).time_since_midnight().seconds();
m_trip_list.get_next_trip_time().seconds() < (t + dt).time_since_midnight().seconds();
m_trip_list.increase_index()) {
auto& trip = m_trip_list.get_next_trip(weekend);
auto& trip = m_trip_list.get_next_trip();
auto& person = get_person(trip.person_id);
auto personal_rng = PersonalRandomNumberGenerator(person);
// skip the trip if the person is in quarantine or is dead
Expand Down
45 changes: 19 additions & 26 deletions cpp/models/abm/trip_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,43 +26,36 @@ namespace mio
namespace abm
{

TripList::TripList()
: m_trips_weekday({})
, m_trips_weekend({})
, m_current_index(0)
const Trip& TripList::get_next_trip() const
{
return m_trips[m_current_index];
}

const Trip& TripList::get_next_trip(bool weekend) const
TimePoint TripList::get_next_trip_time() const
{
return weekend ? m_trips_weekend[m_current_index] : m_trips_weekday[m_current_index];
return m_trips[m_current_index].trip_time;
}

TimePoint TripList::get_next_trip_time(bool weekend) const
{
return weekend ? m_trips_weekend[m_current_index].time : m_trips_weekday[m_current_index].time;
}

void TripList::use_weekday_trips_on_weekend()
{
m_trips_weekend = m_trips_weekday;
}

void TripList::add_trip(Trip trip, bool weekend)
void TripList::add_trips(std::vector<Trip> trip)
{
//Trips are sorted by time.
//Also include the person id in the comparison so different persons can make trips at the same time.
//The same person can only make one trip at the same time.
if (!weekend) {
insert_sorted_replace(m_trips_weekday, trip, [](auto& trip1, auto& trip2) {
return std::tie(trip1.time, trip1.person_id) < std::tie(trip2.time, trip2.person_id);
});
}
else {
insert_sorted_replace(m_trips_weekend, trip, [](auto& trip1, auto& trip2) {
return std::tie(trip1.time, trip1.person_id) < std::tie(trip2.time, trip2.person_id);

std::sort(trip.begin(), trip.end(), [](auto& trip1, auto& trip2) {
return std::tie(trip1.trip_time, trip1.person_id) < std::tie(trip2.trip_time, trip2.person_id);
});
// Avoid storage duplication by using in-place merge
const size_t original_size = m_trips.size();

// Append the sorted new trips to the end
m_trips.insert(m_trips.end(), std::make_move_iterator(trip.begin()), std::make_move_iterator(trip.end()));

// Use in-place merge to merge the two sorted ranges
std::inplace_merge(
m_trips.begin(), m_trips.begin() + original_size, m_trips.end(), [](const auto& trip1, const auto& trip2) {
return std::tie(trip1.trip_time, trip1.person_id) < std::tie(trip2.trip_time, trip2.person_id);
});
}
}

} // namespace abm
Expand Down
90 changes: 25 additions & 65 deletions cpp/models/abm/trip_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,67 +40,35 @@ namespace abm
* @brief A trip describes a change of Location from one Location to another Location.
*/
struct Trip {
//TODO: Origin is currently not used for the trips. Should we delete it then?
PersonId person_id; /**< Person that makes the trip and corresponds to the index into the structure m_persons from
Model, where all Person%s are saved.*/
TimePoint time; ///< Daytime at which a Person changes the Location.
TimePoint trip_time; ///< Daytime at which a Person changes the Location.
LocationId destination; ///< Location where the Person changes to.
int destination_model_id; ///< Model id of destination Location.
LocationId origin; ///< Location where the Person starts the Trip.
int origin_model_id; ///< Model id of origin Location.
TransportMode trip_mode; ///< Mode of transportation. See TransportMode for all possible modes of transportation.
std::vector<uint32_t> cells; /**< If destination consists of different Cell%s, this gives the index of the
Cell%s the Person changes to.*/
TransportMode
trip_mode; ///< Mode of transportation. 1:Bike, 2:Car (Driver), 3:Car (Co-Driver)), 4:Public Transport, 5:Walking, 6:Other/Unknown
LocationType destination_type; ///< Type of destination Location.

/**
* @brief Construct a new Trip.
* @param[in] id ID of the Person that makes the Trip.
* @param[in] time_new Time at which a Person changes the Location this currently cant be set for s specific day just a timepoint in a day.
* @param[in] time Time at which a Person changes the Location this currently cant be set for s specific day just a timepoint in a day.
* @param[in] destination Location where the Person changes to.
* @param[in] destination_model_id Model the Person changes to.
* @param[in] origin Location where the person starts the Trip.
* @param[in] origin_model_id Model the Person starts the Trip.
* @param[in] input_cells The index of the Cell%s the Person changes to.
*/
Trip(PersonId id, TimePoint time_new, LocationId dest, int dest_model_id, LocationId orig, int orig_model_id,
TransportMode mode_of_transport, LocationType type_of_activity, const std::vector<uint32_t>& input_cells = {})
Trip(PersonId id, const TimePoint time, const LocationId dest, const int dest_model_id = 0,
const TransportMode mode_of_transport = mio::abm::TransportMode::Unknown,
const std::vector<uint32_t>& input_cells = {})
: person_id(id)
, time(mio::abm::TimePoint(time_new.time_since_midnight().seconds()))
, trip_time(mio::abm::TimePoint(time.time_since_midnight().seconds()))
, destination(dest)
, destination_model_id(dest_model_id)
, origin(orig)
, origin_model_id(orig_model_id)
, cells(input_cells)
, trip_mode(mode_of_transport)
, destination_type(type_of_activity)
{
}

Trip(PersonId id, TimePoint time_new, LocationId dest, LocationId orig, TransportMode mode_of_transport,
LocationType type_of_activity, const std::vector<uint32_t>& input_cells = {})
: person_id(id)
, time(mio::abm::TimePoint(time_new.time_since_midnight().seconds()))
, destination(dest)
, destination_model_id(0)
, origin(orig)
, origin_model_id(0)
, cells(input_cells)
, trip_mode(mode_of_transport)
, destination_type(type_of_activity)
{
}

Trip(PersonId id, TimePoint time_new, LocationId dest, LocationId orig, LocationType type_of_activity,
const std::vector<uint32_t>& input_cells = {})
: Trip(id, time_new, dest, orig, mio::abm::TransportMode::Unknown, type_of_activity, input_cells)
{
}

Trip(PersonId id, TimePoint time_new, LocationId dest, LocationType type_of_activity,
const std::vector<uint32_t>& input_cells = {})
: Trip(id, time_new, dest, dest, mio::abm::TransportMode::Unknown, type_of_activity, input_cells)
{
}

Expand All @@ -109,17 +77,18 @@ struct Trip {
*/
bool operator==(const Trip& other) const
{
return (person_id == other.person_id) && (time == other.time) && (destination == other.destination) &&
(origin == other.origin);
return (person_id == other.person_id) && (trip_time == other.trip_time) && (destination == other.destination) &&
(destination_model_id == other.destination_model_id) && (trip_mode == other.trip_mode);
}

auto default_serialize()
{
return Members("Trip")
.add("person_id", person_id)
.add("time", time)
.add("trip_time", trip_time)
.add("destination", destination)
.add("origin", origin);
.add("model_id", destination_model_id)
.add("trip_mode", trip_mode);
}
};

Expand All @@ -132,31 +101,26 @@ class TripList
/**
* @brief Construct empty TripList.
*/
TripList();
TripList() = default;

/**
* @brief Get the next Trip.
* @param weekend Whether the Trip%s during the week or on the weekend are used.
*/
const Trip& get_next_trip(bool weekend) const;
const Trip& get_next_trip() const;

/**
* @brief Get the time at which the next Trip will happen.
* @brief Get the trip_time at which the next Trip will happen.
* @param weekend Whether the Trip%s during the week or on the weekend are used.
*/
TimePoint get_next_trip_time(bool weekend) const;
TimePoint get_next_trip_time() const;

/**
* @brief Add a Trip to the trip list.
* @param[in] trip The Trip to be added.
* @brief Adds Trips to the trip list.
* @param[in] trips The Trips to be added.
* @param[in] weekend If the Trip is made on a weekend day.
*/
void add_trip(Trip trip, bool weekend = false);

/**
* @brief Use the same TripList for weekend and weekday.
*/
void use_weekday_trips_on_weekend();
void add_trips(std::vector<Trip> trip);

/**
* @brief Increment the current index to select the next Trip.
Expand All @@ -178,9 +142,9 @@ class TripList
* @brief Get the length of the TripList.
* @param weekend Whether the Trip%s during the week or on the weekend are used.
*/
size_t num_trips(bool weekend = false) const
size_t num_trips() const
{
return weekend ? m_trips_weekend.size() : m_trips_weekday.size();
return m_trips.size();
}

/**
Expand All @@ -194,16 +158,12 @@ class TripList
/// This method is used by the default serialization feature.
auto default_serialize()
{
return Members("TestingScheme")
.add("trips_weekday", m_trips_weekday)
.add("trips_weekend", m_trips_weekend)
.add("index", m_current_index);
return Members("TestingScheme").add("trips", m_trips).add("index", m_current_index);
}

private:
std::vector<Trip> m_trips_weekday; ///< The list of Trip%s a Person makes on a weekday.
std::vector<Trip> m_trips_weekend; ///< The list of Trip%s a Person makes on a weekend day.
uint32_t m_current_index; ///< The index of the Trip a Person makes next.
std::vector<Trip> m_trips; ///< The list of Trip%s a Person makes on a weekday.
uint32_t m_current_index = 0; ///< The index of the Trip a Person makes next.
};

} // namespace abm
Expand All @@ -213,7 +173,7 @@ template <>
struct DefaultFactory<abm::Trip> {
static abm::Trip create()
{
return abm::Trip{abm::PersonId{}, abm::TimePoint{}, abm::LocationId{}, abm::LocationType{}};
return abm::Trip{abm::PersonId{}, abm::TimePoint{}, abm::LocationId{}};
}
};

Expand Down
4 changes: 4 additions & 0 deletions cpp/models/graph_abm/graph_abm_mobility.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,12 @@ class ABMMobilityEdge
for (int i = int(persons_to_change.size()) - 1; i >= 0; --i) {
auto& person = model_from.get_persons()[persons_to_change[i]];
auto target_type = person.get_location_type();
if (target_type == abm::LocationType::Count) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should this happen? Locations with LocationType::Count should be prohibited.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in the graph abm. Please ask julia but in graph_abmmodel.h
person.set_location(abm::LocationType::Count, trip.destination, std::numeric_limits::max());
is set.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was discussed extensively. While in the current implementation nothing changes, it is worth noticing that the read-in of trips is now changed: Before, trips that change the model only considered the given LocationType and mapped this to an assigned location of the person. Now, the actual ID is required, which is then taken to determine the LocationType and then again being used to map to an assigned location.
This means that the location type of the ID is used, and people might go to another location (not the ID, but the assigned location of the same type).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a discussion we decided to use a LocationType::invalid, that is inserted after LocationType::Count.

target_type = model_to.get_location(person.get_location()).get_type();
}
//check if Person uses this edge
if (person.get_assigned_location_model_id(target_type) == model_to.get_id()) {

auto target_id = person.get_assigned_location(target_type);
//set correct location for person
person.set_location(target_type, target_id, model_to.get_id());
Expand Down
10 changes: 4 additions & 6 deletions cpp/models/graph_abm/graph_abmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,12 @@ class GraphABModel : public abm::Model
}

// check if a person makes a trip
bool weekend = t.is_weekend();
size_t num_trips = Base::m_trip_list.num_trips(weekend);
size_t num_trips = Base::m_trip_list.num_trips();

for (; Base::m_trip_list.get_current_index() < num_trips &&
Base::m_trip_list.get_next_trip_time(weekend).seconds() < (t + dt).time_since_midnight().seconds();
Base::m_trip_list.get_next_trip_time().seconds() < (t + dt).time_since_midnight().seconds();
Base::m_trip_list.increase_index()) {
auto& trip = Base::m_trip_list.get_next_trip(weekend);
auto& trip = Base::m_trip_list.get_next_trip();
auto& person = get_person(trip.person_id);
auto person_index = Base::get_person_index(trip.person_id);
auto personal_rng = PersonalRandomNumberGenerator(person);
Expand Down Expand Up @@ -192,8 +191,7 @@ class GraphABModel : public abm::Model
}
else { //person moves to other world
Base::m_activeness_statuses[person_index] = false;
person.set_location(trip.destination_type, abm::LocationId::invalid_id(),
std::numeric_limits<int>::max());
person.set_location(abm::LocationType::Count, trip.destination, std::numeric_limits<int>::max());
m_person_buffer.push_back(person_index);
m_are_exposure_caches_valid = false;
m_is_local_population_cache_valid = false;
Expand Down
13 changes: 5 additions & 8 deletions cpp/simulations/abm_braunschweig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ void create_model_from_data(mio::abm::Model& model, const std::string& filename,
std::getline(fin, line); // Skip header row

// Add the persons and trips
std::vector<mio::abm::Trip> trips;
while (std::getline(fin, line)) {
row.clear();

Expand All @@ -357,8 +358,6 @@ void create_model_from_data(mio::abm::Model& model, const std::string& filename,
uint32_t target_location_id = std::abs(row[index["loc_id_end"]]);
uint32_t start_location_id = std::abs(row[index["loc_id_start"]]);
uint32_t trip_start = row[index["start_time"]];
uint32_t transport_mode = row[index["travel_mode"]];
uint32_t acticity_end = row[index["activity_end"]];

// Add the trip to the trip list person and location must exist at this point
auto target_location = locations.find(target_location_id)->second;
Expand Down Expand Up @@ -388,12 +387,10 @@ void create_model_from_data(mio::abm::Model& model, const std::string& filename,
// For trips where the start location is not known use Home instead
start_location = model.get_person(pid_itr->second).get_assigned_location(mio::abm::LocationType::Home);
}
model.get_trip_list().add_trip(
mio::abm::Trip(static_cast<uint64_t>(pid_itr->first),
mio::abm::TimePoint(0) + mio::abm::minutes(trip_start), target_location, start_location,
mio::abm::TransportMode(transport_mode), mio::abm::LocationType(acticity_end)));
trips.push_back(
mio::abm::Trip(pid_itr->second, mio::abm::TimePoint(0) + mio::abm::minutes(trip_start), target_location));
}
model.get_trip_list().use_weekday_trips_on_weekend();
model.get_trip_list().add_trips(trips);
}

void set_parameters(mio::abm::Parameters params)
Expand Down Expand Up @@ -915,7 +912,7 @@ void write_log_to_file_trip_data(const T& history)

int start_index = mobility_data_index - 1;
using Type = std::tuple<mio::abm::PersonId, mio::abm::LocationId, mio::abm::TimePoint,
mio::abm::TransportMode, mio::abm::ActivityType, mio::abm::InfectionState>;
mio::abm::TransportMode, mio::abm::ActivityType, mio::abm::InfectionState>;
while (!std::binary_search(std::begin(mobility_data[start_index]), std::end(mobility_data[start_index]),
mobility_data[mobility_data_index][trip_index],
[](const Type& v1, const Type& v2) {
Expand Down
Loading
Loading