Skip to content

Commit dc7ea67

Browse files
committed
Merge branch 'main' into webapp
2 parents ba6dff2 + 855ee0e commit dc7ea67

20 files changed

+369
-172
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 = 4;
9-
static constexpr uint8_t DSM_VERSION_PATCH = 0;
9+
static constexpr uint8_t DSM_VERSION_PATCH = 2;
1010

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

src/dsm/headers/AdjacencyMatrix.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ namespace dsm {
7474
/// @brief Get the number of links in the adjacency matrix
7575
/// @return The number of links in the adjacency matrix
7676
size_t size() const;
77+
/// @brief Check if the adjacency matrix is empty
78+
/// @return True if the adjacency matrix is empty, false otherwise
79+
bool empty() const;
7780
/// @brief Get the number of nodes in the adjacency matrix
7881
/// @return The number of nodes in the adjacency matrix
7982
size_t n() const;
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
#pragma once
32

43
#include "../utility/Typedef.hpp"
@@ -7,7 +6,20 @@ namespace dsm {
76

87
class Graph;
98

10-
double streetLength(const Graph* graph, Id node1, Id node2);
11-
double streetTime(const Graph* graph, Id node1, Id node2);
9+
namespace weight_functions {
10+
/// @brief Returns the length of a street given its source and destination nodes
11+
/// @param graph A pointer to the graph
12+
/// @param node1 The source node id
13+
/// @param node2 The destination node id
14+
/// @return The length of the street
15+
double streetLength(const Graph* graph, Id node1, Id node2);
16+
/// @brief Returns the time to cross a street given its source and destination nodes
17+
/// @param graph A pointer to the graph
18+
/// @param node1 The source node id
19+
/// @param node2 The destination node id
20+
/// @return The time to cross the street
21+
/// @details This time also takes into account the number of agents on the street
22+
double streetTime(const Graph* graph, Id node1, Id node2);
23+
} // namespace weight_functions
1224

1325
}; // namespace dsm

src/dsm/headers/Dynamics.hpp

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <exception>
2424
#include <fstream>
2525
#include <filesystem>
26+
#include <functional>
2627
#include <tbb/parallel_for_each.h>
2728

2829
#include "DijkstraWeights.hpp"
@@ -72,6 +73,8 @@ namespace dsm {
7273
private:
7374
std::map<Id, std::unique_ptr<agent_t>> m_agents;
7475
std::unordered_map<Id, std::unique_ptr<Itinerary>> m_itineraries;
76+
std::function<double(const Graph*, Id, Id)> m_weightFunction;
77+
double m_weightTreshold;
7578
bool m_bCacheEnabled;
7679

7780
protected:
@@ -97,7 +100,6 @@ namespace dsm {
97100
}
98101
}
99102

100-
auto const dimension = static_cast<Size>(m_graph.nNodes());
101103
auto const destinationID = pItinerary->destination();
102104
std::vector<double> shortestDistances(m_graph.nNodes());
103105
tbb::parallel_for_each(
@@ -108,7 +110,7 @@ namespace dsm {
108110
if (nodeId == destinationID) {
109111
shortestDistances[nodeId] = -1.;
110112
} else {
111-
auto result = m_graph.shortestPath(nodeId, destinationID);
113+
auto result = m_graph.shortestPath(nodeId, destinationID, m_weightFunction);
112114
if (result.has_value()) {
113115
shortestDistances[nodeId] = result.value().distance();
114116
} else {
@@ -132,17 +134,17 @@ namespace dsm {
132134
auto const& row{m_graph.adjMatrix().getRow(nodeId)};
133135
for (const auto nextNodeId : row) {
134136
if (nextNodeId == destinationID) {
135-
if (std::abs(m_graph.street(nodeId * dimension + nextNodeId)->length() -
136-
minDistance) < 1.) // 1 meter tolerance between shortest paths
137+
if (std::abs(m_weightFunction(&m_graph, nodeId, nextNodeId) - minDistance) <
138+
m_weightTreshold) // 1 meter tolerance between shortest paths
137139
{
138140
path.insert(nodeId, nextNodeId);
139141
} else {
140142
Logger::debug(
141143
std::format("Found a path from {} to {} which differs for more than {} "
142-
"meter(s) from the shortest one.",
144+
"unit(s) from the shortest one.",
143145
nodeId,
144146
destinationID,
145-
1.));
147+
m_weightTreshold));
146148
}
147149
continue;
148150
}
@@ -151,23 +153,23 @@ namespace dsm {
151153
continue;
152154
}
153155
bool const bIsMinDistance{
154-
std::abs(m_graph.street(nodeId * dimension + nextNodeId)->length() +
155-
distance - minDistance) <
156-
1.}; // 1 meter tolerance between shortest paths
156+
std::abs(m_weightFunction(&m_graph, nodeId, nextNodeId) + distance -
157+
minDistance) <
158+
m_weightTreshold}; // 1 meter tolerance between shortest paths
157159
if (bIsMinDistance) {
158160
path.insert(nodeId, nextNodeId);
159161
} else {
160162
Logger::debug(
161163
std::format("Found a path from {} to {} which differs for more than {} "
162-
"meter(s) from the shortest one.",
164+
"unit(s) from the shortest one.",
163165
nodeId,
164166
destinationID,
165-
1.));
167+
m_weightTreshold));
166168
}
167169
}
168170
}
169171

170-
if (path.size() == 0) {
172+
if (path.empty()) {
171173
Logger::error(
172174
std::format("Path with id {} and destination {} is empty. Please check the "
173175
"adjacency matrix.",
@@ -199,6 +201,19 @@ namespace dsm {
199201
/// @brief Update the paths of the itineraries based on the actual travel times
200202
virtual void updatePaths();
201203

204+
/// @brief Set the weight function for the Dijkstra's algorithm
205+
/// @param weightFunction A std::function returning a double value and taking as arguments a
206+
/// pointer to the graph, an id of a source node and an id of a target node (for the edge)
207+
/// @details The weight function must return the weight of the edge between the source and the
208+
/// target node. One can use the predefined weight functions in the DijkstraWeights.hpp file,
209+
/// like weight_functions::streetLength or weight_functions::streetTime.
210+
void setWeightFunction(std::function<double(const Graph*, Id, Id)> weightFunction);
211+
/// @brief Set the weight treshold for updating the paths
212+
/// @param weightTreshold The weight treshold
213+
/// @details If two paths differs only for a weight smaller than the treshold, the two paths are
214+
/// considered equivalent.
215+
void setWeightTreshold(double weightTreshold) { m_weightTreshold = weightTreshold; }
216+
202217
/// @brief Set the destination nodes
203218
/// @param destinationNodes The destination nodes (as an initializer list)
204219
/// @param updatePaths If true, the paths are updated
@@ -343,7 +358,9 @@ namespace dsm {
343358
Dynamics<agent_t>::Dynamics(Graph& graph,
344359
bool useCache,
345360
std::optional<unsigned int> seed)
346-
: m_bCacheEnabled{useCache},
361+
: m_weightFunction{weight_functions::streetLength},
362+
m_weightTreshold{1.},
363+
m_bCacheEnabled{useCache},
347364
m_graph{std::move(graph)},
348365
m_time{0},
349366
m_previousSpireTime{0},
@@ -371,6 +388,12 @@ namespace dsm {
371388
});
372389
}
373390

391+
template <typename agent_t>
392+
void Dynamics<agent_t>::setWeightFunction(
393+
std::function<double(const Graph*, Id, Id)> weightFunction) {
394+
m_weightFunction = weightFunction;
395+
}
396+
374397
template <typename agent_t>
375398
void Dynamics<agent_t>::setDestinationNodes(std::initializer_list<Id> destinationNodes,
376399
bool updatePaths) {
@@ -546,7 +569,7 @@ namespace dsm {
546569

547570
template <typename agent_t>
548571
Measurement<double> Dynamics<agent_t>::streetMeanDensity(bool normalized) const {
549-
if (m_graph.streetSet().size() == 0) {
572+
if (m_graph.streetSet().empty()) {
550573
return Measurement(0., 0.);
551574
}
552575
std::vector<double> densities;

src/dsm/headers/Edge.hpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
#pragma once
22

33
#include <utility>
4+
#include <vector>
45
#include "../utility/Typedef.hpp"
56

67
namespace dsm {
78
class Edge {
89
protected:
10+
std::vector<std::pair<double, double>> m_geometry;
911
Id m_id;
1012
std::pair<Id, Id> m_nodePair;
1113
int m_capacity;
1214
int m_transportCapacity;
1315
double m_angle;
1416

17+
void m_setAngle(std::pair<double, double> srcNodeCoordinates,
18+
std::pair<double, double> dstNodeCoordinates);
19+
1520
public:
1621
/// @brief Construct a new Edge object
1722
/// @param id The edge's id
@@ -25,12 +30,11 @@ namespace dsm {
2530
std::pair<Id, Id> nodePair,
2631
int capacity = 1,
2732
int transportCapacity = 1,
28-
double angle = 0.0);
33+
std::vector<std::pair<double, double>> geometry = {});
2934

3035
void setCapacity(int capacity);
3136
void setTransportCapacity(int capacity);
32-
void setAngle(std::pair<double, double> srcNodeCoordinates,
33-
std::pair<double, double> dstNodeCoordinates);
37+
void setGeometry(std::vector<std::pair<double, double>> geometry);
3438

3539
/// @brief Get the edge's id
3640
/// @return Id The edge's id
@@ -45,6 +49,8 @@ namespace dsm {
4549
/// @return std::pair<Id, Id> The edge's node pair, where the first element is the source node id and the second
4650
/// element is the target node id. The pair is (u, v) with the edge u -> v.
4751
std::pair<Id, Id> const& nodePair() const;
52+
53+
std::vector<std::pair<double, double>> const& geometry() const;
4854
/// @brief Get the edge's capacity, in number of agents
4955
/// @return int The edge's capacity, in number of agents
5056
int capacity() const;

src/dsm/headers/Graph.hpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ namespace dsm {
4949
private:
5050
std::unordered_map<Id, std::unique_ptr<Node>> m_nodes;
5151
std::unordered_map<Id, std::unique_ptr<Street>> m_streets;
52-
std::unordered_map<std::string, Id> m_nodeMapping;
5352
AdjacencyMatrix m_adjacencyMatrix;
53+
std::unordered_map<std::string, Id> m_nodeMapping;
5454
std::vector<Id> m_inputNodes;
5555
std::vector<Id> m_outputNodes;
5656
unsigned long long m_maxAgentCapacity;
@@ -110,9 +110,8 @@ namespace dsm {
110110
/// @brief Build the graph's adjacency matrix and computes max capacity
111111
/// @details The adjacency matrix is built using the graph's streets and nodes. N.B.: The street ids
112112
/// are reassigned using the max node id, i.e. newStreetId = srcId * n + dstId, where n is the max node id.
113+
/// Moreover, street angles and geometries are set using the nodes' coordinates.
113114
void buildAdj();
114-
/// @brief Build the graph's street angles using the node's coordinates
115-
void buildStreetAngles();
116115
/// @brief Adjust the nodes' transport capacity
117116
/// @details The nodes' capacity is adjusted using the graph's streets transport capacity, which may vary basing on the number of lanes. The node capacity will be set to the sum of the incoming streets' transport capacity.
118117
void adjustNodeCapacities();
@@ -144,14 +143,19 @@ namespace dsm {
144143
/// @throws std::invalid_argument if the file is not found, invalid or the format is not supported
145144
void importOSMEdges(const std::string& fileName);
146145

146+
/// @brief Export the graph's nodes to a csv-like file separated with ';'
147+
/// @param path The path to the file to export the nodes to
148+
/// @details The file format is csv-like, with the first line being the column names: id;lon;lat
149+
void exportNodes(const std::string& fileName);
150+
/// @brief Export the graph's edges to a csv-like file separated with ';'
151+
/// @param path The path to the file to export the edges to
152+
/// @details The file format is csv-like, with the first line being the column names: id;source_id;target_id;name;geometry
153+
void exportEdges(const std::string& fileName);
147154
/// @brief Export the graph's adjacency matrix to a file
148155
/// @param path The path to the file to export the adjacency matrix to (default: ./matrix.dsm)
149156
/// @param isAdj A boolean value indicating if the file contains the adjacency matrix or the distance matrix.
150157
/// @throws std::invalid_argument if the file is not found or invalid
151158
void exportMatrix(std::string path = "./matrix.dsm", bool isAdj = true);
152-
/// @brief Export the nodes' coordinates to a file
153-
/// @param path The path to the file to export the nodes' coordinates to (default: ./nodes.dsm)
154-
void exportCoordinates(std::string const& path = "./coordinates.csv");
155159

156160
/// @brief Add a node to the graph
157161
/// @param node A std::unique_ptr to the node to add
@@ -276,19 +280,19 @@ namespace dsm {
276280
/// @return A DijkstraResult object containing the path and the distance
277281
template <typename Func = std::function<double(const Graph*, Id, Id)>>
278282
requires(std::is_same_v<std::invoke_result_t<Func, const Graph*, Id, Id>, double>)
279-
std::optional<DijkstraResult> shortestPath(const Node& source,
280-
const Node& destination,
281-
Func f = streetLength) const;
283+
std::optional<DijkstraResult> shortestPath(
284+
const Node& source,
285+
const Node& destination,
286+
Func f = weight_functions::streetLength) const;
282287

283288
/// @brief Get the shortest path between two nodes using dijkstra algorithm
284289
/// @param source The source node id
285290
/// @param destination The destination node id
286291
/// @return A DijkstraResult object containing the path and the distance
287292
template <typename Func = std::function<double(const Graph*, Id, Id)>>
288293
requires(std::is_same_v<std::invoke_result_t<Func, const Graph*, Id, Id>, double>)
289-
std::optional<DijkstraResult> shortestPath(Id source,
290-
Id destination,
291-
Func f = streetLength) const;
294+
std::optional<DijkstraResult> shortestPath(
295+
Id source, Id destination, Func f = weight_functions::streetLength) const;
292296
};
293297

294298
template <typename node_t, typename... TArgs>

src/dsm/headers/Road.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ namespace dsm {
3636
double maxSpeed = 13.8888888889,
3737
int nLanes = 1,
3838
std::string name = std::string(),
39+
std::vector<std::pair<double, double>> geometry = {},
3940
std::optional<int> capacity = std::nullopt,
4041
int transportCapacity = 1);
4142
/// @brief Set the mean vehicle length, in meters (default is 5)

0 commit comments

Comments
 (0)