Skip to content
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
36390b3
Init io node set in importOSMNodes
Grufoony Jan 30, 2025
c0d7d0e
Add general addAgentsRandomly function
Grufoony Jan 30, 2025
c92c5d6
Bugfix
Grufoony Jan 30, 2025
3ef73b2
Logging
Grufoony Jan 30, 2025
9107a59
Formatting
Grufoony Jan 30, 2025
49d79b0
Merge branch 'main' into io_nodes
Grufoony Jan 30, 2025
28da2e4
Update version
Grufoony Jan 30, 2025
ce51ac3
Bugfix + logging
Grufoony Jan 30, 2025
054471c
ChatGPPT optimization
Grufoony Jan 30, 2025
943d578
Add path caching
Grufoony Jan 31, 2025
6e6fb57
Merge branch 'pathCaching' into io_nodes
Grufoony Jan 31, 2025
1fd0ddb
Improve
Grufoony Jan 31, 2025
76f3d46
Merge branch 'pathCaching' into io_nodes
Grufoony Jan 31, 2025
8262983
To revise
Grufoony Jan 31, 2025
b0dc230
First tryal
Grufoony Jan 31, 2025
d88767b
Handle oneway
Grufoony Jan 31, 2025
ae67561
Prova
Grufoony Jan 31, 2025
12c289c
Merge branch 'main' into io_nodes
Grufoony Jan 31, 2025
c15e7bd
Update version
Grufoony Jan 31, 2025
98b3762
Merge branch 'main' into io_nodes
Grufoony Jan 31, 2025
4ff36b2
Update version
Grufoony Jan 31, 2025
fe2f5c0
Fix merge
Grufoony Jan 31, 2025
7f39bfa
Add debug logs
Grufoony Feb 3, 2025
6242461
Merge branch 'main' into io_nodes
Grufoony Feb 3, 2025
c09776c
Info to Debug
Grufoony Feb 3, 2025
f51bbf7
Enhance code security
Grufoony Feb 3, 2025
422f160
Enhance code security
Grufoony Feb 3, 2025
628b5f3
Bugfix
Grufoony Feb 3, 2025
5263389
Remove optional from street dequeue
Grufoony Feb 3, 2025
657a149
To remove asap
Grufoony Feb 3, 2025
e3c31d4
Merge branch 'main' into io_nodes
Grufoony Feb 3, 2025
731a36c
Log messages
Grufoony Feb 4, 2025
56e9d02
Bugfix
Grufoony Feb 4, 2025
69f8a99
Optimize `addAgentsRandomly` functions
Grufoony Feb 5, 2025
1201949
Merge branch 'main' into io_nodes
Grufoony Feb 5, 2025
daa2cf9
Update version
Grufoony Feb 5, 2025
81ac4f9
Fix tests
Grufoony Feb 5, 2025
87232f5
Merge branch 'main' into io_nodes
Grufoony Feb 12, 2025
912e438
Bugfix
Grufoony Feb 12, 2025
864c252
Merge branch 'main' into io_nodes
Grufoony Feb 14, 2025
53f0de3
Label coherence
Grufoony Feb 14, 2025
6a1443e
Update version
Grufoony Feb 14, 2025
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 src/dsm/headers/Agent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ namespace dsm {
Id id() const { return m_id; }
/// @brief Get the agent's itinerary
/// @return The agent's itinerary
Id itineraryId() const { return m_trip[m_itineraryIdx]; }
Id itineraryId() const { return m_trip.at(m_itineraryIdx); }
/// @brief Get the agent's trip
/// @return The agent's trip
std::vector<Id> const& trip() const { return m_trip; }
Expand Down
42 changes: 34 additions & 8 deletions src/dsm/headers/Dynamics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
auto path = SparseMatrix<bool>{};
path.load(file);
pItinerary->setPath(std::move(path));
Logger::info(
Logger::debug(

Check warning on line 96 in src/dsm/headers/Dynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/Dynamics.hpp#L96

Added line #L96 was not covered by tests
std::format("Loaded cached path for itinerary {}", pItinerary->id()));
return;
}
Expand Down Expand Up @@ -147,24 +147,23 @@
destinationID,
1.));
}
} else if ((nextNodeId != destinationID)) {
Logger::warning(std::format(
"No path found from node {} to node {}", nextNodeId, destinationID));
}
}
}
if (path.size() == 0) {

if (path.empty()) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
Logger::error(
std::format("Path with id {} and destination {} is empty. Please "
"check the adjacency matrix.",
std::format("Path with id {} and destination {} is empty. Please check the "
"adjacency matrix.",
pItinerary->id(),
pItinerary->destination()));
}

pItinerary->setPath(path);
if (m_bCacheEnabled) {
pItinerary->path().cache(
std::format("{}it{}.dsmcache", g_cacheFolder, pItinerary->id()));
Logger::info(
Logger::debug(

Check warning on line 166 in src/dsm/headers/Dynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/Dynamics.hpp#L166

Added line #L166 was not covered by tests
std::format("Saved path in cache for itinerary {}", pItinerary->id()));
}
}
Expand Down Expand Up @@ -249,6 +248,8 @@
/// @param itineraries Generic container of itineraries, represented by an std::span
void addItineraries(std::span<Itinerary> itineraries);

void enableCache();

/// @brief Reset the simulation time
void resetTime();

Expand Down Expand Up @@ -332,20 +333,32 @@
m_generator{std::random_device{}()} {
if (seed.has_value()) {
m_generator.seed(seed.value());
}

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
if (m_bCacheEnabled) {
if (!std::filesystem::exists(g_cacheFolder)) {
std::filesystem::create_directory(g_cacheFolder);
}
Logger::info(std::format("Cache enabled (default folder is {})", g_cacheFolder));
}
for (const auto& nodeId : this->m_graph.outputNodes()) {
addItinerary(Itinerary{nodeId, nodeId});
m_updatePath(m_itineraries.at(nodeId));

Check warning on line 345 in src/dsm/headers/Dynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/Dynamics.hpp#L344-L345

Added lines #L344 - L345 were not covered by tests
}
// updatePaths();
}

template <typename agent_t>
void Dynamics<agent_t>::updatePaths() {
if (m_bCacheEnabled) {
if (!std::filesystem::exists(g_cacheFolder)) {
std::filesystem::create_directory(g_cacheFolder);

Check warning on line 354 in src/dsm/headers/Dynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/Dynamics.hpp#L354

Added line #L354 was not covered by tests
}
}

std::vector<std::thread> threads;
threads.reserve(m_itineraries.size());
std::exception_ptr pThreadException;
Logger::info(std::format("Init computing {} paths", m_itineraries.size()));
for (const auto& [itineraryId, itinerary] : m_itineraries) {
threads.emplace_back(std::thread([this, &itinerary, &pThreadException] {
try {
Expand All @@ -362,6 +375,8 @@
// Throw the exception launched first
if (pThreadException)
std::rethrow_exception(pThreadException);

Logger::info("End computing paths");
}

template <typename agent_t>
Expand Down Expand Up @@ -390,6 +405,10 @@
std::format("Agent with id {} already exists.", agent->id())));
}
m_agents.emplace(agent->id(), std::move(agent));
// Logger::debug(std::format("Added agent with id {} from node {} to node {}",
// m_agents.rbegin()->first,
// m_agents.rbegin()->second->srcNodeId().value_or(-1),
// m_agents.rbegin()->second->itineraryId()));
}

template <typename agent_t>
Expand Down Expand Up @@ -435,6 +454,7 @@
template <typename agent_t>
void Dynamics<agent_t>::removeAgent(Size agentId) {
m_agents.erase(agentId);
Logger::debug(std::format("Removed agent with id {}", agentId));
}

template <typename agent_t>
Expand Down Expand Up @@ -468,6 +488,12 @@
});
}

template <typename agent_t>
void Dynamics<agent_t>::enableCache() {
m_bCacheEnabled = true;
Logger::info(std::format("Cache enabled (default folder is {})", g_cacheFolder));
}

template <typename agent_t>
void Dynamics<agent_t>::resetTime() {
m_time = 0;
Expand Down
13 changes: 11 additions & 2 deletions src/dsm/headers/Graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
std::unordered_map<Id, std::unique_ptr<Node>> m_nodes;
std::unordered_map<Id, std::unique_ptr<Street>> m_streets;
std::unordered_map<std::string, Id> m_nodeMapping;
std::vector<Id> m_inputNodes;
std::vector<Id> m_outputNodes;
SparseMatrix<bool> m_adjacency;
unsigned long long m_maxAgentCapacity;

Expand Down Expand Up @@ -80,6 +82,8 @@
});
m_nodeMapping = other.m_nodeMapping;
m_adjacency = other.m_adjacency;
m_inputNodes = other.m_inputNodes;
m_outputNodes = other.m_outputNodes;
}

Graph& operator=(const Graph& other) {
Expand All @@ -94,6 +98,8 @@
});
m_nodeMapping = other.m_nodeMapping;
m_adjacency = other.m_adjacency;
m_inputNodes = other.m_inputNodes;
m_outputNodes = other.m_outputNodes;

return *this;
}
Expand Down Expand Up @@ -261,6 +267,9 @@
/// @return unsigned long long The maximum agent capacity of the graph
unsigned long long maxCapacity() const { return m_maxAgentCapacity; }

std::vector<Id> const& inputNodes() const { return m_inputNodes; }
std::vector<Id> const& outputNodes() const { return m_outputNodes; }

/// @brief Get the shortest path between two nodes using dijkstra algorithm
/// @param source The source node
/// @param destination The destination node
Expand All @@ -287,7 +296,7 @@
std::constructible_from<node_t, Id, TArgs...>)
node_t& Graph::addNode(Id id, TArgs&&... args) {
addNode(std::make_unique<node_t>(id, std::forward<TArgs>(args)...));
return dynamic_cast<node_t&>(*m_nodes[id]);
return dynamic_cast<node_t&>(*m_nodes.at(id));

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
}
template <typename T1, typename... Tn>
requires is_node_v<std::remove_reference_t<T1>> &&
Expand All @@ -302,7 +311,7 @@
std::constructible_from<edge_t, Id, TArgs...>)
edge_t& Graph::addEdge(Id id, TArgs&&... args) {
addStreet(std::make_unique<edge_t>(id, std::forward<TArgs>(args)...));
return dynamic_cast<edge_t&>(*m_streets[id]);
return dynamic_cast<edge_t&>(*m_streets.at(id));

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
}

template <typename T1>
Expand Down
61 changes: 43 additions & 18 deletions src/dsm/headers/RoadDynamics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
const TContainer& dst_weights,
const size_t minNodeDistance = 0);

void addAgentsRandomly(Size nAgents, const size_t minNodeDistance = 0);

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 17.8 rule Note

MISRA 17.8 rule

/// @brief Evolve the simulation
/// @details Evolve the simulation by moving the agents and updating the travel times.
/// In particular:
Expand Down Expand Up @@ -235,7 +237,10 @@
}
}
}
assert(possibleMoves.size() > 0);
if (possibleMoves.empty()) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
Logger::error(

Check warning on line 241 in src/dsm/headers/RoadDynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/RoadDynamics.hpp#L241

Added line #L241 was not covered by tests
std::format("No possible moves from node {} for agent {}", nodeId, agentId));
}
std::uniform_int_distribution<Size> moveDist{
0, static_cast<Size>(possibleMoves.size() - 1)};
uint8_t p{0};
Expand Down Expand Up @@ -319,9 +324,7 @@
}
}
if (bArrived) {
if (pStreet->dequeue(queueIndex) == std::nullopt) {
continue;
}
pStreet->dequeue(queueIndex);
m_travelDTs.push_back({pAgent->distance(), static_cast<double>(pAgent->time())});
if (reinsert_agents) {
// reset Agent's values
Expand All @@ -331,14 +334,14 @@
}
continue;
}
auto const& nextStreet{this->m_graph.streetSet()[m_agentNextStreetId[agentId]]};
auto const& nextStreet{this->m_graph.street(m_agentNextStreetId.at(agentId))};
if (nextStreet->isFull()) {
continue;
}
if (pStreet->dequeue(queueIndex) == std::nullopt) {
continue;
pStreet->dequeue(queueIndex);
if (destinationNode->id() != nextStreet->u()) {
Logger::error(std::format("Agent {} is going to the wrong street", agentId));

Check warning on line 343 in src/dsm/headers/RoadDynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/RoadDynamics.hpp#L343

Added line #L343 was not covered by tests
}
assert(destinationNode->id() == nextStreet->nodePair().first);
if (destinationNode->isIntersection()) {
auto& intersection = dynamic_cast<Intersection&>(*destinationNode);
auto const delta{nextStreet->deltaAngle(pStreet->angle())};
Expand All @@ -360,7 +363,7 @@
return false;
}
for (auto const [angle, agentId] : intersection.agents()) {
auto const& nextStreet{this->m_graph.streetSet()[m_agentNextStreetId[agentId]]};
auto const& nextStreet{this->m_graph.street(m_agentNextStreetId.at(agentId))};
if (nextStreet->isFull()) {
if (m_forcePriorities) {
return false;
Expand All @@ -383,7 +386,7 @@
return false;
}
auto const agentId{roundabout.agents().front()};
auto const& nextStreet{this->m_graph.streetSet()[m_agentNextStreetId[agentId]]};
auto const& nextStreet{this->m_graph.street(m_agentNextStreetId.at(agentId))};
if (!(nextStreet->isFull())) {
if (this->agents().at(agentId)->streetId().has_value()) {
const auto streetId = this->agents().at(agentId)->streetId().value();
Expand Down Expand Up @@ -494,7 +497,7 @@
!m_agentNextStreetId.contains(agentId)) {
Id srcNodeId = agent->srcNodeId().has_value() ? agent->srcNodeId().value()
: nodeDist(this->m_generator);
const auto& srcNode{this->m_graph.nodeSet()[srcNodeId]};
const auto& srcNode{this->m_graph.node(srcNodeId)};
if (srcNode->isFull()) {
continue;
}
Expand Down Expand Up @@ -596,6 +599,13 @@
const TContainer& src_weights,
const TContainer& dst_weights,
const size_t minNodeDistance) {
Logger::debug(
std::format("Init addAgentsRandomly for {} agents from {} nodes to {} nodes with "
"minNodeDistance {}",
nAgents,
src_weights.size(),
dst_weights.size(),
minNodeDistance));
if (src_weights.size() == 1 && dst_weights.size() == 1 &&
src_weights.begin()->first == dst_weights.begin()->first) {
throw std::invalid_argument(Logger::buildExceptionMessage(
Expand Down Expand Up @@ -630,6 +640,7 @@
if (!this->agents().empty()) {
agentId = this->agents().rbegin()->first + 1;
}
Logger::debug(std::format("Adding {} agents at time {}.", nAgents, this->time()));

Check notice

Code scanning / Cppcheck (reported by Codacy)

time is Y2038-unsafe Note

time is Y2038-unsafe
while (nAgents > 0) {
Id srcId{0}, dstId{0};
if (dst_weights.size() == 1) {
Expand Down Expand Up @@ -683,6 +694,20 @@
}
}

template <typename delay_t>
requires(is_numeric_v<delay_t>)
void RoadDynamics<delay_t>::addAgentsRandomly(Size nAgents,
const size_t minNodeDistance) {
std::unordered_map<Id, double> src_weights, dst_weights;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
for (auto const& id : this->m_graph.inputNodes()) {
src_weights[id] = 1.;
}
for (auto const& id : this->m_graph.outputNodes()) {
dst_weights[id] = 1.;
}
addAgentsRandomly(nAgents, src_weights, dst_weights, minNodeDistance);
}

template <typename delay_t>
requires(is_numeric_v<delay_t>)
void RoadDynamics<delay_t>::evolve(bool reinsert_agents) {
Expand All @@ -691,7 +716,7 @@
m_dataUpdatePeriod.has_value() && this->m_time % m_dataUpdatePeriod.value() == 0;
for (const auto& [streetId, pStreet] : this->m_graph.streetSet()) {
if (bUpdateData) {
m_streetTails[streetId] += pStreet->nExitingAgents();
m_streetTails.at(streetId) += pStreet->nExitingAgents();
}
for (auto i = 0; i < pStreet->transportCapacity(); ++i) {
this->m_evolveStreet(pStreet, reinsert_agents);
Expand Down Expand Up @@ -736,11 +761,11 @@

double inputGreenSum{0.}, inputRedSum{0.};
for (const auto& [streetId, _] : this->m_graph.adjMatrix().getCol(nodeId, true)) {
auto const& pStreet{this->m_graph.streetSet()[streetId]};
auto const& pStreet{this->m_graph.street(streetId)};
if (streetPriorities.contains(streetId)) {
inputGreenSum += m_streetTails[streetId] / pStreet->nLanes();
inputGreenSum += m_streetTails.at(streetId) / pStreet->nLanes();
} else {
inputRedSum += m_streetTails[streetId] / pStreet->nLanes();
inputRedSum += m_streetTails.at(streetId) / pStreet->nLanes();
}
}
inputGreenSum /= meanGreenFraction;
Expand Down Expand Up @@ -780,11 +805,11 @@
// - If the previous check fails, do nothing
double outputGreenSum{0.}, outputRedSum{0.};
for (const auto& [streetId, _] : this->m_graph.adjMatrix().getRow(nodeId, true)) {
auto const& pStreet{this->m_graph.streetSet()[streetId]};
auto const& pStreet{this->m_graph.street(streetId)};

Check warning on line 808 in src/dsm/headers/RoadDynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/RoadDynamics.hpp#L808

Added line #L808 was not covered by tests
if (streetPriorities.contains(streetId)) {
outputGreenSum += m_streetTails[streetId] / pStreet->nLanes();
outputGreenSum += m_streetTails.at(streetId) / pStreet->nLanes();

Check warning on line 810 in src/dsm/headers/RoadDynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/RoadDynamics.hpp#L810

Added line #L810 was not covered by tests
} else {
outputRedSum += m_streetTails[streetId] / pStreet->nLanes();
outputRedSum += m_streetTails.at(streetId) / pStreet->nLanes();

Check warning on line 812 in src/dsm/headers/RoadDynamics.hpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/headers/RoadDynamics.hpp#L812

Added line #L812 was not covered by tests
}
}
auto const outputDifference{(outputGreenSum - outputRedSum) / nCycles};
Expand Down
2 changes: 2 additions & 0 deletions src/dsm/headers/SparseMatrix.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ namespace dsm {
/// @return number of non zero elements
Id size() const { return _matrix.size(); };

bool empty() const { return _matrix.empty(); }

/// @brief get the maximum number of elements in the matrix
/// @return maximum number of elements
Id max_size() const { return _rows * _cols; }
Expand Down
9 changes: 5 additions & 4 deletions src/dsm/headers/Street.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ namespace dsm {
/// @throw std::runtime_error If the street's queue is full
void enqueue(Id agentId, size_t index);
/// @brief Remove an agent from the street's queue
virtual std::optional<Id> dequeue(size_t index);
/// @return Id The id of the agent removed from the street's queue
virtual Id dequeue(size_t index);
/// @brief Check if the street is a spire
/// @return bool True if the street is a spire, false otherwise
virtual bool isSpire() const { return false; };
Expand Down Expand Up @@ -160,8 +161,8 @@ namespace dsm {
/// Notice that this flow is positive iff the input flow is greater than the output flow.
int meanFlow();
/// @brief Remove an agent from the street's queue
/// @return std::optional<Id> The id of the agent removed from the street's queue
std::optional<Id> dequeue(size_t index) final;
/// @return Id The id of the agent removed from the street's queue
Id dequeue(size_t index) final;
/// @brief Check if the street is a spire
/// @return bool True if the street is a spire, false otherwise
bool isSpire() const final { return true; };
Expand All @@ -182,7 +183,7 @@ namespace dsm {
int meanFlow();
/// @brief Remove an agent from the street's queue
/// @return std::optional<Id> The id of the agent removed from the street's queue
std::optional<Id> dequeue(size_t index) final;
Id dequeue(size_t index) final;
/// @brief Check if the street is a spire
/// @return bool True if the street is a spire, false otherwise
bool isSpire() const final { return true; };
Expand Down
2 changes: 1 addition & 1 deletion src/dsm/sources/FirstOrderDynamics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace dsm {

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