Skip to content

Commit 6032b25

Browse files
authored
Add support for io flags in importOSMNodes function (#256)
* Init io node set in importOSMNodes * Add general addAgentsRandomly function * Bugfix * Logging * Formatting * Update version * Bugfix + logging * ChatGPPT optimization * Add path caching * Improve * To revise * First tryal * Handle oneway * Prova * Update version * Update version * Fix merge * Add debug logs * Info to Debug * Enhance code security * Enhance code security * Bugfix * Remove optional from street dequeue * To remove asap * Log messages * Bugfix * Optimize `addAgentsRandomly` functions * Update version * Fix tests * Bugfix * Label coherence * Update version
1 parent f2c151e commit 6032b25

File tree

12 files changed

+128
-62
lines changed

12 files changed

+128
-62
lines changed

src/dsm/dsm.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
static constexpr uint8_t DSM_VERSION_MAJOR = 2;
88
static constexpr uint8_t DSM_VERSION_MINOR = 3;
9-
static constexpr uint8_t DSM_VERSION_PATCH = 27;
9+
static constexpr uint8_t DSM_VERSION_PATCH = 28;
1010

1111
static auto const DSM_VERSION =
1212
std::format("{}.{}.{}", DSM_VERSION_MAJOR, DSM_VERSION_MINOR, DSM_VERSION_PATCH);

src/dsm/headers/Dynamics.hpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ namespace dsm {
9494
auto path = SparseMatrix<bool>{};
9595
path.load(file);
9696
pItinerary->setPath(std::move(path));
97-
Logger::info(
97+
Logger::debug(
9898
std::format("Loaded cached path for itinerary {}", pItinerary->id()));
9999
return;
100100
}
@@ -169,18 +169,20 @@ namespace dsm {
169169
}
170170
}
171171
}
172-
if (path.size() == 0) {
172+
173+
if (path.empty()) {
173174
Logger::error(
174-
std::format("Path with id {} and destination {} is empty. Please "
175-
"check the adjacency matrix.",
175+
std::format("Path with id {} and destination {} is empty. Please check the "
176+
"adjacency matrix.",
176177
pItinerary->id(),
177178
pItinerary->destination()));
178179
}
180+
179181
pItinerary->setPath(path);
180182
if (m_bCacheEnabled) {
181183
pItinerary->path().cache(
182184
std::format("{}it{}.dsmcache", g_cacheFolder, pItinerary->id()));
183-
Logger::info(
185+
Logger::debug(
184186
std::format("Saved path in cache for itinerary {}", pItinerary->id()));
185187
}
186188
}
@@ -276,6 +278,8 @@ namespace dsm {
276278
/// @param itineraries Generic container of itineraries, represented by an std::span
277279
void addItineraries(std::span<Itinerary> itineraries);
278280

281+
void enableCache();
282+
279283
/// @brief Reset the simulation time
280284
void resetTime();
281285

@@ -372,6 +376,11 @@ namespace dsm {
372376
}
373377
Logger::info(std::format("Cache enabled (default folder is {})", g_cacheFolder));
374378
}
379+
for (const auto& nodeId : this->m_graph.outputNodes()) {
380+
addItinerary(Itinerary{nodeId, nodeId});
381+
m_updatePath(m_itineraries.at(nodeId));
382+
}
383+
// updatePaths();
375384
}
376385

377386
template <typename agent_t>
@@ -419,6 +428,10 @@ namespace dsm {
419428
std::format("Agent with id {} already exists.", agent->id())));
420429
}
421430
m_agents.emplace(agent->id(), std::move(agent));
431+
// Logger::debug(std::format("Added agent with id {} from node {} to node {}",
432+
// m_agents.rbegin()->first,
433+
// m_agents.rbegin()->second->srcNodeId().value_or(-1),
434+
// m_agents.rbegin()->second->itineraryId()));
422435
}
423436

424437
template <typename agent_t>
@@ -464,6 +477,7 @@ namespace dsm {
464477
template <typename agent_t>
465478
void Dynamics<agent_t>::removeAgent(Size agentId) {
466479
m_agents.erase(agentId);
480+
Logger::debug(std::format("Removed agent with id {}", agentId));
467481
}
468482

469483
template <typename agent_t>
@@ -507,6 +521,12 @@ namespace dsm {
507521
});
508522
}
509523

524+
template <typename agent_t>
525+
void Dynamics<agent_t>::enableCache() {
526+
m_bCacheEnabled = true;
527+
Logger::info(std::format("Cache enabled (default folder is {})", g_cacheFolder));
528+
}
529+
510530
template <typename agent_t>
511531
void Dynamics<agent_t>::resetTime() {
512532
m_time = 0;

src/dsm/headers/Graph.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ namespace dsm {
5050
std::unordered_map<Id, std::unique_ptr<Node>> m_nodes;
5151
std::unordered_map<Id, std::unique_ptr<Street>> m_streets;
5252
std::unordered_map<std::string, Id> m_nodeMapping;
53+
std::vector<Id> m_inputNodes;
54+
std::vector<Id> m_outputNodes;
5355
SparseMatrix<bool> m_adjacency;
5456
unsigned long long m_maxAgentCapacity;
5557

@@ -80,6 +82,8 @@ namespace dsm {
8082
});
8183
m_nodeMapping = other.m_nodeMapping;
8284
m_adjacency = other.m_adjacency;
85+
m_inputNodes = other.m_inputNodes;
86+
m_outputNodes = other.m_outputNodes;
8387
}
8488

8589
Graph& operator=(const Graph& other) {
@@ -94,6 +98,8 @@ namespace dsm {
9498
});
9599
m_nodeMapping = other.m_nodeMapping;
96100
m_adjacency = other.m_adjacency;
101+
m_inputNodes = other.m_inputNodes;
102+
m_outputNodes = other.m_outputNodes;
97103

98104
return *this;
99105
}
@@ -261,6 +267,9 @@ namespace dsm {
261267
/// @return unsigned long long The maximum agent capacity of the graph
262268
unsigned long long maxCapacity() const { return m_maxAgentCapacity; }
263269

270+
std::vector<Id> const& inputNodes() const { return m_inputNodes; }
271+
std::vector<Id> const& outputNodes() const { return m_outputNodes; }
272+
264273
/// @brief Get the shortest path between two nodes using dijkstra algorithm
265274
/// @param source The source node
266275
/// @param destination The destination node
@@ -287,7 +296,7 @@ namespace dsm {
287296
std::constructible_from<node_t, Id, TArgs...>)
288297
node_t& Graph::addNode(Id id, TArgs&&... args) {
289298
addNode(std::make_unique<node_t>(id, std::forward<TArgs>(args)...));
290-
return dynamic_cast<node_t&>(*m_nodes[id]);
299+
return dynamic_cast<node_t&>(*m_nodes.at(id));
291300
}
292301
template <typename T1, typename... Tn>
293302
requires is_node_v<std::remove_reference_t<T1>> &&
@@ -302,7 +311,7 @@ namespace dsm {
302311
std::constructible_from<edge_t, Id, TArgs...>)
303312
edge_t& Graph::addEdge(Id id, TArgs&&... args) {
304313
addStreet(std::make_unique<edge_t>(id, std::forward<TArgs>(args)...));
305-
return dynamic_cast<edge_t&>(*m_streets[id]);
314+
return dynamic_cast<edge_t&>(*m_streets.at(id));
306315
}
307316

308317
template <typename T1>

src/dsm/headers/RoadDynamics.hpp

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ namespace dsm {
128128
const TContainer& dst_weights,
129129
const size_t minNodeDistance = 0);
130130

131+
void addAgentsRandomly(Size nAgents, const size_t minNodeDistance = 0);
132+
131133
/// @brief Evolve the simulation
132134
/// @details Evolve the simulation by moving the agents and updating the travel times.
133135
/// In particular:
@@ -234,7 +236,10 @@ namespace dsm {
234236
}
235237
}
236238
}
237-
assert(possibleMoves.size() > 0);
239+
if (possibleMoves.empty()) {
240+
Logger::error(
241+
std::format("No possible moves from node {} for agent {}", nodeId, agentId));
242+
}
238243
std::uniform_int_distribution<Size> moveDist{
239244
0, static_cast<Size>(possibleMoves.size() - 1)};
240245
uint8_t p{0};
@@ -317,9 +322,7 @@ namespace dsm {
317322
}
318323
}
319324
if (bArrived) {
320-
if (pStreet->dequeue(queueIndex) == std::nullopt) {
321-
continue;
322-
}
325+
pStreet->dequeue(queueIndex);
323326
m_travelDTs.push_back({pAgent->distance(), static_cast<double>(pAgent->time())});
324327
if (reinsert_agents) {
325328
// reset Agent's values
@@ -334,10 +337,10 @@ namespace dsm {
334337
if (nextStreet->isFull()) {
335338
continue;
336339
}
337-
if (pStreet->dequeue(queueIndex) == std::nullopt) {
338-
continue;
340+
pStreet->dequeue(queueIndex);
341+
if (destinationNode->id() != nextStreet->source()) {
342+
Logger::error(std::format("Agent {} is going to the wrong street", agentId));
339343
}
340-
assert(destinationNode->id() == nextStreet->nodePair().first);
341344
if (destinationNode->isIntersection()) {
342345
auto& intersection = dynamic_cast<Intersection&>(*destinationNode);
343346
auto const delta{nextStreet->deltaAngle(pStreet->angle())};
@@ -492,7 +495,7 @@ namespace dsm {
492495
} else if (!agent->streetId().has_value() && !agent->nextStreetId().has_value()) {
493496
Id srcNodeId = agent->srcNodeId().has_value() ? agent->srcNodeId().value()
494497
: nodeDist(this->m_generator);
495-
const auto& srcNode{this->m_graph.nodeSet()[srcNodeId]};
498+
const auto& srcNode{this->m_graph.node(srcNodeId)};
496499
if (srcNode->isFull()) {
497500
continue;
498501
}
@@ -594,7 +597,16 @@ namespace dsm {
594597
const TContainer& src_weights,
595598
const TContainer& dst_weights,
596599
const size_t minNodeDistance) {
597-
if (src_weights.size() == 1 && dst_weights.size() == 1 &&
600+
auto const& nSources{src_weights.size()};
601+
auto const& nDestinations{dst_weights.size()};
602+
Logger::debug(
603+
std::format("Init addAgentsRandomly for {} agents from {} nodes to {} nodes with "
604+
"minNodeDistance {}",
605+
nAgents,
606+
nSources,
607+
dst_weights.size(),
608+
minNodeDistance));
609+
if (nSources == 1 && nDestinations == 1 &&
598610
src_weights.begin()->first == dst_weights.begin()->first) {
599611
throw std::invalid_argument(Logger::buildExceptionMessage(
600612
std::format("The only source node {} is also the only destination node.",
@@ -628,9 +640,10 @@ namespace dsm {
628640
if (!this->agents().empty()) {
629641
agentId = this->agents().rbegin()->first + 1;
630642
}
643+
Logger::debug(std::format("Adding {} agents at time {}.", nAgents, this->time()));
631644
while (nAgents > 0) {
632645
Id srcId{0}, dstId{0};
633-
if (dst_weights.size() == 1) {
646+
if (nDestinations == 1) {
634647
dstId = dst_weights.begin()->first;
635648
srcId = dstId;
636649
}
@@ -646,19 +659,24 @@ namespace dsm {
646659
}
647660
}
648661
}
649-
if (src_weights.size() > 1) {
662+
if (nSources > 1) {
650663
dstId = srcId;
651664
}
652665
while (dstId == srcId) {
653666
dRand = dstUniformDist(this->m_generator);
654667
sum = 0.;
655668
for (const auto& [id, weight] : dst_weights) {
656669
// if the node is at a minimum distance from the destination, skip it
657-
auto result{this->m_graph.shortestPath(srcId, id)};
658-
if (result.has_value() && result.value().path().size() < minNodeDistance &&
659-
dst_weights.size() > 1) {
670+
if (this->itineraries().at(id)->path().getRow(srcId).empty()) {
660671
continue;
661672
}
673+
if (nDestinations > 1 && minNodeDistance > 0) {
674+
// NOTE: Result must have a value in this case, so we can use value() as sort-of assertion
675+
if (this->m_graph.shortestPath(srcId, id).value().path().size() <
676+
minNodeDistance) {
677+
continue;
678+
}
679+
}
662680
dstId = id;
663681
sum += weight;
664682
if (dRand < sum) {
@@ -681,6 +699,20 @@ namespace dsm {
681699
}
682700
}
683701

702+
template <typename delay_t>
703+
requires(is_numeric_v<delay_t>)
704+
void RoadDynamics<delay_t>::addAgentsRandomly(Size nAgents,
705+
const size_t minNodeDistance) {
706+
std::unordered_map<Id, double> src_weights, dst_weights;
707+
for (auto const& id : this->m_graph.inputNodes()) {
708+
src_weights[id] = 1.;
709+
}
710+
for (auto const& id : this->m_graph.outputNodes()) {
711+
dst_weights[id] = 1.;
712+
}
713+
addAgentsRandomly(nAgents, src_weights, dst_weights, minNodeDistance);
714+
}
715+
684716
template <typename delay_t>
685717
requires(is_numeric_v<delay_t>)
686718
void RoadDynamics<delay_t>::evolve(bool reinsert_agents) {
@@ -699,15 +731,6 @@ namespace dsm {
699731
}
700732
}
701733
}
702-
// for (const auto& [streetId, pStreet] : this->m_graph.streetSet()) {
703-
// if (bUpdateData) {
704-
// m_streetTails[streetId] += pStreet->nExitingAgents();
705-
// }
706-
// Logger::info(std::format("Evolving street {}", streetId));
707-
// for (auto i = 0; i < pStreet->transportCapacity(); ++i) {
708-
// this->m_evolveStreet(pStreet, reinsert_agents);
709-
// }
710-
// }
711734
// Move transport capacity agents from each node
712735
for (const auto& [nodeId, pNode] : this->m_graph.nodeSet()) {
713736
for (auto i = 0; i < pNode->transportCapacity(); ++i) {
@@ -747,11 +770,11 @@ namespace dsm {
747770

748771
double inputGreenSum{0.}, inputRedSum{0.};
749772
for (const auto& [streetId, _] : this->m_graph.adjMatrix().getCol(nodeId, true)) {
750-
auto const& pStreet{this->m_graph.streetSet()[streetId]};
773+
auto const& pStreet{this->m_graph.street(streetId)};
751774
if (streetPriorities.contains(streetId)) {
752-
inputGreenSum += m_streetTails[streetId] / pStreet->nLanes();
775+
inputGreenSum += m_streetTails.at(streetId) / pStreet->nLanes();
753776
} else {
754-
inputRedSum += m_streetTails[streetId] / pStreet->nLanes();
777+
inputRedSum += m_streetTails.at(streetId) / pStreet->nLanes();
755778
}
756779
}
757780
inputGreenSum /= meanGreenFraction;
@@ -791,11 +814,11 @@ namespace dsm {
791814
// - If the previous check fails, do nothing
792815
double outputGreenSum{0.}, outputRedSum{0.};
793816
for (const auto& [streetId, _] : this->m_graph.adjMatrix().getRow(nodeId, true)) {
794-
auto const& pStreet{this->m_graph.streetSet()[streetId]};
817+
auto const& pStreet{this->m_graph.street(streetId)};
795818
if (streetPriorities.contains(streetId)) {
796-
outputGreenSum += m_streetTails[streetId] / pStreet->nLanes();
819+
outputGreenSum += m_streetTails.at(streetId) / pStreet->nLanes();
797820
} else {
798-
outputRedSum += m_streetTails[streetId] / pStreet->nLanes();
821+
outputRedSum += m_streetTails.at(streetId) / pStreet->nLanes();
799822
}
800823
}
801824
auto const outputDifference{(outputGreenSum - outputRedSum) / nCycles};

src/dsm/headers/SparseMatrix.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ namespace dsm {
178178
/// @return number of non zero elements
179179
Id size() const { return _matrix.size(); };
180180

181+
bool empty() const { return _matrix.empty(); }
182+
181183
/// @brief get the maximum number of elements in the matrix
182184
/// @return maximum number of elements
183185
Id max_size() const { return _rows * _cols; }

src/dsm/headers/Street.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ namespace dsm {
105105
/// @throw std::runtime_error If the street's queue is full
106106
void enqueue(Id agentId, size_t index);
107107
/// @brief Remove an agent from the street's queue
108-
virtual std::optional<Id> dequeue(size_t index);
108+
/// @return Id The id of the agent removed from the street's queue
109+
virtual Id dequeue(size_t index);
109110
/// @brief Check if the street is a spire
110111
/// @return bool True if the street is a spire, false otherwise
111112
virtual bool isSpire() const { return false; };
@@ -160,8 +161,8 @@ namespace dsm {
160161
/// Notice that this flow is positive iff the input flow is greater than the output flow.
161162
int meanFlow();
162163
/// @brief Remove an agent from the street's queue
163-
/// @return std::optional<Id> The id of the agent removed from the street's queue
164-
std::optional<Id> dequeue(size_t index) final;
164+
/// @return Id The id of the agent removed from the street's queue
165+
Id dequeue(size_t index) final;
165166
/// @brief Check if the street is a spire
166167
/// @return bool True if the street is a spire, false otherwise
167168
bool isSpire() const final { return true; };
@@ -182,7 +183,7 @@ namespace dsm {
182183
int meanFlow();
183184
/// @brief Remove an agent from the street's queue
184185
/// @return std::optional<Id> The id of the agent removed from the street's queue
185-
std::optional<Id> dequeue(size_t index) final;
186+
Id dequeue(size_t index) final;
186187
/// @brief Check if the street is a spire
187188
/// @return bool True if the street is a spire, false otherwise
188189
bool isSpire() const final { return true; };

src/dsm/sources/FirstOrderDynamics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace dsm {
2828

2929
void FirstOrderDynamics::setAgentSpeed(Size agentId) {
3030
const auto& agent{this->agents().at(agentId)};
31-
const auto& street{this->m_graph.streetSet()[agent->streetId().value()]};
31+
const auto& street{this->m_graph.street(agent->streetId().value())};
3232
double speed{street->maxSpeed() * (1. - m_alpha * street->density(true))};
3333
if (m_speedFluctuationSTD > 0.) {
3434
std::normal_distribution<double> speedDist{speed, speed * m_speedFluctuationSTD};

0 commit comments

Comments
 (0)