@@ -65,6 +65,7 @@ namespace dsf::mobility {
6565 double m_maxTravelDistance;
6666 std::time_t m_maxTravelTime;
6767 double m_weightTreshold;
68+ std::optional<double > m_timeToleranceFactor;
6869 std::optional<delay_t > m_dataUpdatePeriod;
6970 bool m_bCacheEnabled;
7071 bool m_forcePriorities;
@@ -125,9 +126,16 @@ namespace dsf::mobility {
125126 // / @details The passage probability is the probability of passing through a node
126127 // / It is useful in the case of random agents
127128 void setPassageProbability (double passageProbability);
128-
129+ // / @brief Set the time tolerance factor for killing stagnant agents.
130+ // / An agent will be considered stagnant if it has not moved for timeToleranceFactor * std::ceil(street_length / street_maxSpeed) time units.
131+ // / @param timeToleranceFactor The time tolerance factor
132+ // / @throw std::invalid_argument If the time tolerance factor is not positive
133+ void killStagnantAgents (double timeToleranceFactor = 3 .);
134+ // / @brief Set the weight function
135+ // / @param pathWeight The dsf::PathWeight function to use for the pathfinding
136+ // / @param weightThreshold The weight threshold for updating the paths (default is std::nullopt)
129137 void setWeightFunction (PathWeight const pathWeight,
130- std::optional<double > weigthThreshold = std::nullopt );
138+ std::optional<double > weightThreshold = std::nullopt );
131139 // / @brief Set the force priorities flag
132140 // / @param forcePriorities The flag
133141 // / @details If true, if an agent cannot move to the next street, the whole node is skipped
@@ -376,6 +384,7 @@ namespace dsf::mobility {
376384 m_passageProbability{std::nullopt},
377385 m_maxTravelDistance{std::numeric_limits<double>::max()},
378386 m_maxTravelTime{std::numeric_limits<std::time_t>::max()},
387+ m_timeToleranceFactor{std::nullopt},
379388 m_bCacheEnabled{useCache},
380389 m_forcePriorities{false} {
381390 this->setWeightFunction(weightFunction, weightTreshold);
@@ -652,37 +661,31 @@ namespace dsf::mobility {
652661 pAgentTemp->freeTime());
653662 continue;
654663 }
655- bool overtimed{false};
656- {
664+
665+ if (m_timeToleranceFactor.has_value()) {
657666 auto const timeDiff{this->time_step() - pAgentTemp->freeTime()};
658- // A minute of delay has never hurt anyone, right?
659- auto const timeTolerance{
660- std::max(static_cast<std::time_t>(60),
661- static_cast<std::time_t>(
662- 3 * std::ceil(pStreet->length() / pStreet->maxSpeed())))};
667+ auto const timeTolerance{m_timeToleranceFactor.value() *
668+ std::ceil(pStreet->length() / pStreet->maxSpeed())};
663669 if (timeDiff > timeTolerance) {
664- overtimed = true;
665670 spdlog::warn(
666- "Time {} - {} currently on {} ({} turn - Traffic Light? {}), "
667- "has been still for more than {} seconds ({} seconds)",
671+ "Time-step {} - {} currently on {} ({} turn - Traffic Light? {}), "
672+ "has been still for more than {} seconds ({} seconds). Killing it. ",
668673 this->time_step(),
669674 *pAgentTemp,
670675 *pStreet,
671676 directionToString.at(pStreet->laneMapping().at(queueIndex)),
672677 this->graph().node(pStreet->target())->isTrafficLight(),
673678 timeTolerance,
674679 timeDiff);
680+ // Kill the agent
681+ auto pAgent{pStreet->dequeue(queueIndex)};
682+ continue;
675683 }
676684 }
677685 pAgentTemp->setSpeed(0.);
678686 const auto& destinationNode{this->graph().node(pStreet->target())};
679687 if (destinationNode->isFull()) {
680- if (overtimed) {
681- spdlog::warn("Skipping due to full destination node {}", *destinationNode);
682- } else {
683- spdlog::debug("Skipping due to space at destination node {}",
684- *destinationNode);
685- }
688+ spdlog::debug("Skipping due to full destination node {}", *destinationNode);
686689 continue;
687690 }
688691 if (destinationNode->isTrafficLight()) {
@@ -792,17 +795,9 @@ namespace dsf::mobility {
792795 }
793796 if (!bCanPass) {
794797 spdlog::debug(
795- "Skipping agent emission from street {} -> {} due to right of way. ",
798+ "Skipping agent emission from street {} -> {} due to right of way",
796799 pStreet->source(),
797800 pStreet->target());
798- if (overtimed) {
799- spdlog::warn(
800- "Skipping agent emission from street {} -> {} due to right of way "
801- "and overtimed agent {}",
802- pStreet->source(),
803- pStreet->target(),
804- pAgentTemp->id());
805- }
806801 continue;
807802 }
808803 }
@@ -817,14 +812,6 @@ namespace dsf::mobility {
817812 "probability",
818813 pStreet->source(),
819814 pStreet->target());
820- if (overtimed) {
821- spdlog::warn(
822- "Skipping agent emission from street {} -> {} due to passage "
823- "probability and overtimed agent {}",
824- pStreet->source(),
825- pStreet->target(),
826- pAgentTemp->id());
827- }
828815 continue;
829816 }
830817 }
@@ -865,21 +852,12 @@ namespace dsf::mobility {
865852 }
866853 auto const & nextStreet{this ->graph ().edge (pAgentTemp->nextStreetId ().value ())};
867854 if (nextStreet->isFull ()) {
868- if (overtimed) {
869- spdlog::warn (
870- " Skipping agent emission from street {} -> {} due to full "
871- " next street: {}" ,
872- pStreet->source (),
873- pStreet->target (),
874- *nextStreet);
875- } else {
876- spdlog::debug (
877- " Skipping agent emission from street {} -> {} due to full "
878- " next street: {}" ,
879- pStreet->source (),
880- pStreet->target (),
881- *nextStreet);
882- }
855+ spdlog::debug (
856+ " Skipping agent emission from street {} -> {} due to full "
857+ " next street: {}" ,
858+ pStreet->source (),
859+ pStreet->target (),
860+ *nextStreet);
883861 continue ;
884862 }
885863 auto pAgent{pStreet->dequeue (queueIndex)};
@@ -1042,6 +1020,15 @@ namespace dsf::mobility {
10421020 }
10431021 m_passageProbability = passageProbability;
10441022 }
1023+ template <typename delay_t >
1024+ requires (is_numeric_v<delay_t >)
1025+ void RoadDynamics<delay_t>::killStagnantAgents(double timeToleranceFactor) {
1026+ if (timeToleranceFactor <= 0 .) {
1027+ throw std::invalid_argument (std::format (
1028+ " The time tolerance factor ({}) must be positive" , timeToleranceFactor));
1029+ }
1030+ m_timeToleranceFactor = timeToleranceFactor;
1031+ }
10451032 template <typename delay_t >
10461033 requires (is_numeric_v<delay_t >)
10471034 void RoadDynamics<delay_t>::setWeightFunction(PathWeight const pathWeight,
@@ -1200,6 +1187,15 @@ namespace dsf::mobility {
12001187 requires (is_numeric_v<delay_t >)
12011188 void RoadDynamics<delay_t>::addAgentsUniformly(Size nAgents,
12021189 std::optional<Id> optItineraryId) {
1190+ if (m_timeToleranceFactor.has_value () && !m_agents.empty ()) {
1191+ auto const nStagnantAgents{m_agents.size ()};
1192+ spdlog::warn (
1193+ " Removing {} stagnant agents that were not inserted since the previous call to "
1194+ " addAgentsUniformly()." ,
1195+ nStagnantAgents);
1196+ m_agents.clear ();
1197+ m_nAgents -= nStagnantAgents;
1198+ }
12031199 if (optItineraryId.has_value () && !this ->itineraries ().contains (*optItineraryId)) {
12041200 throw std::invalid_argument (
12051201 std::format (" No itineraries available. Cannot add agents with itinerary id {}" ,
@@ -1256,6 +1252,15 @@ namespace dsf::mobility {
12561252 void RoadDynamics<delay_t>::addAgentsRandomly(Size nAgents,
12571253 const TContainer& src_weights,
12581254 const TContainer& dst_weights) {
1255+ if (m_timeToleranceFactor.has_value () && !m_agents.empty ()) {
1256+ auto const nStagnantAgents{m_agents.size ()};
1257+ spdlog::warn (
1258+ " Removing {} stagnant agents that were not inserted since the previous call to "
1259+ " addAgentsRandomly()." ,
1260+ nStagnantAgents);
1261+ m_agents.clear ();
1262+ m_nAgents -= nStagnantAgents;
1263+ }
12591264 auto const & nSources{src_weights.size ()};
12601265 auto const & nDestinations{dst_weights.size ()};
12611266 spdlog::debug (" Init addAgentsRandomly for {} agents from {} nodes to {} nodes." ,
0 commit comments