Skip to content

Commit b19139e

Browse files
committed
Merge branch 'main' into implementNewAdjacency
2 parents 3e16890 + 6032b25 commit b19139e

File tree

11 files changed

+116
-49
lines changed

11 files changed

+116
-49
lines changed

src/dsm/headers/Dynamics.hpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ namespace dsm {
9191
auto const& file = std::format("{}it{}.adj", g_cacheFolder, pItinerary->id());
9292
if (std::filesystem::exists(file)) {
9393
pItinerary->setPath(AdjacencyMatrix(file));
94-
Logger::info(
94+
Logger::debug(
9595
std::format("Loaded cached path for itinerary {}", pItinerary->id()));
9696
return;
9797
}
@@ -166,18 +166,20 @@ namespace dsm {
166166
}
167167
}
168168
}
169+
169170
if (path.size() == 0) {
170171
Logger::error(
171-
std::format("Path with id {} and destination {} is empty. Please "
172-
"check the adjacency matrix.",
172+
std::format("Path with id {} and destination {} is empty. Please check the "
173+
"adjacency matrix.",
173174
pItinerary->id(),
174175
pItinerary->destination()));
175176
}
177+
176178
pItinerary->setPath(path);
177179
if (m_bCacheEnabled) {
178180
pItinerary->path()->save(
179181
std::format("{}it{}.adj", g_cacheFolder, pItinerary->id()));
180-
Logger::info(
182+
Logger::debug(
181183
std::format("Saved path in cache for itinerary {}", pItinerary->id()));
182184
}
183185
}
@@ -355,6 +357,10 @@ namespace dsm {
355357
}
356358
Logger::info(std::format("Cache enabled (default folder is {})", g_cacheFolder));
357359
}
360+
for (const auto& nodeId : this->m_graph.outputNodes()) {
361+
addItinerary(nodeId, nodeId);
362+
}
363+
updatePaths();
358364
}
359365

360366
template <typename agent_t>
@@ -402,6 +408,10 @@ namespace dsm {
402408
std::format("Agent with id {} already exists.", agent->id())));
403409
}
404410
m_agents.emplace(agent->id(), std::move(agent));
411+
// Logger::debug(std::format("Added agent with id {} from node {} to node {}",
412+
// m_agents.rbegin()->first,
413+
// m_agents.rbegin()->second->srcNodeId().value_or(-1),
414+
// m_agents.rbegin()->second->itineraryId()));
405415
}
406416

407417
template <typename agent_t>
@@ -447,6 +457,7 @@ namespace dsm {
447457
template <typename agent_t>
448458
void Dynamics<agent_t>::removeAgent(Size agentId) {
449459
m_agents.erase(agentId);
460+
Logger::debug(std::format("Removed agent with id {}", agentId));
450461
}
451462

452463
template <typename agent_t>

src/dsm/headers/Graph.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ namespace dsm {
5151
std::unordered_map<Id, std::unique_ptr<Street>> m_streets;
5252
std::unordered_map<std::string, Id> m_nodeMapping;
5353
AdjacencyMatrix m_adjacencyMatrix;
54+
std::vector<Id> m_inputNodes;
55+
std::vector<Id> m_outputNodes;
5456
unsigned long long m_maxAgentCapacity;
5557

5658
/// @brief Reassign the street ids using the max node id
@@ -80,6 +82,8 @@ namespace dsm {
8082
});
8183
m_nodeMapping = other.m_nodeMapping;
8284
m_adjacencyMatrix = other.m_adjacencyMatrix;
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_adjacencyMatrix = other.m_adjacencyMatrix;
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: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ namespace dsm {
127127
const TContainer& dst_weights,
128128
const size_t minNodeDistance = 0);
129129

130+
void addAgentsRandomly(Size nAgents, const size_t minNodeDistance = 0);
131+
130132
/// @brief Evolve the simulation
131133
/// @details Evolve the simulation by moving the agents and updating the travel times.
132134
/// 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
// while loop to avoid U turns in non-roundabout junctions
@@ -315,9 +320,7 @@ namespace dsm {
315320
}
316321
}
317322
if (bArrived) {
318-
if (pStreet->dequeue(queueIndex) == std::nullopt) {
319-
continue;
320-
}
323+
pStreet->dequeue(queueIndex);
321324
m_travelDTs.push_back({pAgent->distance(), static_cast<double>(pAgent->time())});
322325
if (reinsert_agents) {
323326
// reset Agent's values
@@ -332,8 +335,9 @@ namespace dsm {
332335
if (nextStreet->isFull()) {
333336
continue;
334337
}
335-
if (pStreet->dequeue(queueIndex) == std::nullopt) {
336-
continue;
338+
pStreet->dequeue(queueIndex);
339+
if (destinationNode->id() != nextStreet->source()) {
340+
Logger::error(std::format("Agent {} is going to the wrong street", agentId));
337341
}
338342
assert(destinationNode->id() == nextStreet->source());
339343
if (destinationNode->isIntersection()) {
@@ -490,7 +494,7 @@ namespace dsm {
490494
} else if (!agent->streetId().has_value() && !agent->nextStreetId().has_value()) {
491495
Id srcNodeId = agent->srcNodeId().has_value() ? agent->srcNodeId().value()
492496
: nodeDist(this->m_generator);
493-
const auto& srcNode{this->m_graph.nodeSet()[srcNodeId]};
497+
const auto& srcNode{this->m_graph.node(srcNodeId)};
494498
if (srcNode->isFull()) {
495499
continue;
496500
}
@@ -592,7 +596,16 @@ namespace dsm {
592596
const TContainer& src_weights,
593597
const TContainer& dst_weights,
594598
const size_t minNodeDistance) {
595-
if (src_weights.size() == 1 && dst_weights.size() == 1 &&
599+
auto const& nSources{src_weights.size()};
600+
auto const& nDestinations{dst_weights.size()};
601+
Logger::debug(
602+
std::format("Init addAgentsRandomly for {} agents from {} nodes to {} nodes with "
603+
"minNodeDistance {}",
604+
nAgents,
605+
nSources,
606+
dst_weights.size(),
607+
minNodeDistance));
608+
if (nSources == 1 && nDestinations == 1 &&
596609
src_weights.begin()->first == dst_weights.begin()->first) {
597610
throw std::invalid_argument(Logger::buildExceptionMessage(
598611
std::format("The only source node {} is also the only destination node.",
@@ -626,9 +639,10 @@ namespace dsm {
626639
if (!this->agents().empty()) {
627640
agentId = this->agents().rbegin()->first + 1;
628641
}
642+
Logger::debug(std::format("Adding {} agents at time {}.", nAgents, this->time()));
629643
while (nAgents > 0) {
630644
Id srcId{0}, dstId{0};
631-
if (dst_weights.size() == 1) {
645+
if (nDestinations == 1) {
632646
dstId = dst_weights.begin()->first;
633647
srcId = dstId;
634648
}
@@ -644,19 +658,24 @@ namespace dsm {
644658
}
645659
}
646660
}
647-
if (src_weights.size() > 1) {
661+
if (nSources > 1) {
648662
dstId = srcId;
649663
}
650664
while (dstId == srcId) {
651665
dRand = dstUniformDist(this->m_generator);
652666
sum = 0.;
653667
for (const auto& [id, weight] : dst_weights) {
654668
// if the node is at a minimum distance from the destination, skip it
655-
auto result{this->m_graph.shortestPath(srcId, id)};
656-
if (result.has_value() && result.value().path().size() < minNodeDistance &&
657-
dst_weights.size() > 1) {
669+
if (this->itineraries().at(id)->path()->getRow(srcId).empty()) {
658670
continue;
659671
}
672+
if (nDestinations > 1 && minNodeDistance > 0) {
673+
// NOTE: Result must have a value in this case, so we can use value() as sort-of assertion
674+
if (this->m_graph.shortestPath(srcId, id).value().path().size() <
675+
minNodeDistance) {
676+
continue;
677+
}
678+
}
660679
dstId = id;
661680
sum += weight;
662681
if (dRand < sum) {
@@ -679,6 +698,20 @@ namespace dsm {
679698
}
680699
}
681700

701+
template <typename delay_t>
702+
requires(is_numeric_v<delay_t>)
703+
void RoadDynamics<delay_t>::addAgentsRandomly(Size nAgents,
704+
const size_t minNodeDistance) {
705+
std::unordered_map<Id, double> src_weights, dst_weights;
706+
for (auto const& id : this->m_graph.inputNodes()) {
707+
src_weights[id] = 1.;
708+
}
709+
for (auto const& id : this->m_graph.outputNodes()) {
710+
dst_weights[id] = 1.;
711+
}
712+
addAgentsRandomly(nAgents, src_weights, dst_weights, minNodeDistance);
713+
}
714+
682715
template <typename delay_t>
683716
requires(is_numeric_v<delay_t>)
684717
void RoadDynamics<delay_t>::evolve(bool reinsert_agents) {
@@ -743,9 +776,9 @@ namespace dsm {
743776
auto const streetId = sourceId * N + nodeId;
744777
auto const& pStreet{this->m_graph.street(streetId)};
745778
if (streetPriorities.contains(streetId)) {
746-
inputGreenSum += m_streetTails[streetId] / pStreet->nLanes();
779+
inputGreenSum += m_streetTails.at(streetId) / pStreet->nLanes();
747780
} else {
748-
inputRedSum += m_streetTails[streetId] / pStreet->nLanes();
781+
inputRedSum += m_streetTails.at(streetId) / pStreet->nLanes();
749782
}
750783
}
751784
inputGreenSum /= meanGreenFraction;
@@ -783,13 +816,13 @@ namespace dsm {
783816
// - Check that the incoming streets have a density less than the mean one (eventually + tolerance): I want to avoid being into the cluster, better to be out or on the border
784817
// - If the previous check fails, do nothing
785818
double outputGreenSum{0.}, outputRedSum{0.};
786-
for (const auto& targetId : this->m_graph.adjMatrix().getRow(nodeId)) {
819+
for (auto const& targetId : this->m_graph.adjMatrix().getRow(nodeId)) {
787820
auto const streetId = nodeId * N + targetId;
788821
auto const& pStreet{this->m_graph.street(streetId)};
789822
if (streetPriorities.contains(streetId)) {
790-
outputGreenSum += m_streetTails[streetId] / pStreet->nLanes();
823+
outputGreenSum += m_streetTails.at(streetId) / pStreet->nLanes();
791824
} else {
792-
outputRedSum += m_streetTails[streetId] / pStreet->nLanes();
825+
outputRedSum += m_streetTails.at(streetId) / pStreet->nLanes();
793826
}
794827
}
795828
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};

src/dsm/sources/Graph.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
#include "../headers/Graph.hpp"
33

4+
#include <algorithm>
5+
46
namespace dsm {
57
Graph::Graph()
68
: m_adjacencyMatrix{AdjacencyMatrix()},
@@ -332,13 +334,24 @@ namespace dsm {
332334
} else {
333335
addNode<Intersection>(nodeIndex,
334336
std::make_pair(std::stod(lat), std::stod(lon)));
337+
if ((highway.find("in_out") != std::string::npos) ||
338+
(highway.find("outgoing_only") != std::string::npos)) {
339+
Logger::debug(std::format("Setting node {} as an output node", nodeIndex));
340+
m_outputNodes.push_back(nodeIndex);
341+
}
342+
if ((highway.find("in_out") != std::string::npos) ||
343+
(highway.find("ingoing_only") != std::string::npos)) {
344+
Logger::debug(std::format("Setting node {} as an input node", nodeIndex));
345+
m_inputNodes.push_back(nodeIndex);
346+
}
335347
}
336348
m_nodeMapping.emplace(std::make_pair(id, nodeIndex));
337349
++nodeIndex;
338350
}
339351
} else {
340352
Logger::error(std::format("File extension ({}) not supported", fileExt));
341353
}
354+
Logger::info(std::format("Successfully imported {} nodes", nNodes()));
342355
}
343356

344357
void Graph::importOSMEdges(const std::string& fileName) {
@@ -418,6 +431,7 @@ namespace dsm {
418431
throw std::invalid_argument(
419432
Logger::buildExceptionMessage("File extension not supported"));
420433
}
434+
Logger::info(std::format("Successfully imported {} edges", nEdges()));
421435
}
422436

423437
void Graph::exportMatrix(std::string path, bool isAdj) {

0 commit comments

Comments
 (0)