diff --git a/benchmark/Dynamics/BenchDynamics.cpp b/benchmark/Dynamics/BenchDynamics.cpp index 79136a329..3689fad0a 100644 --- a/benchmark/Dynamics/BenchDynamics.cpp +++ b/benchmark/Dynamics/BenchDynamics.cpp @@ -7,7 +7,7 @@ using Graph = dsm::Graph; using Itinerary = dsm::Itinerary; -using Dynamics = dsm::FirstOrderDynamics; +using Dynamics = dsm::FirstOrderDynamics; using Bench = sb::Bench; @@ -28,8 +28,6 @@ int main() { dynamics.addItinerary(it2); dynamics.addItinerary(it3); dynamics.addItinerary(it4); - dynamics.setErrorProbability(0.3); - dynamics.setMinSpeedRateo(0.95); const int n_rep{100}; Bench b1(n_rep); diff --git a/examples/Makefile b/examples/Makefile index c13c5ed59..97c887e3e 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,6 +1,6 @@ slow_charge_tl: - ./slow_charge_tl.out 69 0.3 ./sctl 0 + ./slow_charge_tl.out 69 0.3 ./sctl 0 450 slow_charge_rb: - ./slow_charge_rb.out 69 0.3 ./scrb/ + ./slow_charge_rb.out 69 0.3 ./scrb/ 900 stalingrado: ./stalingrado.out \ No newline at end of file diff --git a/examples/slow_charge_rb.cpp b/examples/slow_charge_rb.cpp index 84ebf2f99..f51b0f0ed 100644 --- a/examples/slow_charge_rb.cpp +++ b/examples/slow_charge_rb.cpp @@ -18,7 +18,6 @@ namespace fs = std::filesystem; std::atomic progress{0}; std::atomic bExitFlag{false}; -uint nAgents{450}; // uncomment these lines to print densities, flows and speeds #define PRINT_DENSITIES @@ -30,7 +29,7 @@ using Unit = unsigned int; using Delay = uint8_t; using Graph = dsm::Graph; -using Dynamics = dsm::FirstOrderDynamics; +using Dynamics = dsm::FirstOrderDynamics; using Street = dsm::Street; using SpireStreet = dsm::SpireStreet; using Roundabout = dsm::Roundabout; @@ -42,21 +41,23 @@ void printLoadingBar(int const i, int const n) { } int main(int argc, char** argv) { - if (argc != 4) { + if (argc != 5) { std::cerr << "Usage: " << argv[0] - << " \n"; + << " \n"; return 1; } const int SEED = std::stoi(argv[1]); // seed for random number generator const double ERROR_PROBABILITY{std::stod(argv[2])}; const std::string BASE_OUT_FOLDER{argv[3]}; + auto nAgents{std::stoul(argv[4])}; std::cout << "-------------------------------------------------\n"; std::cout << "Input parameters:\n"; std::cout << "Seed: " << SEED << '\n'; std::cout << "Error probability: " << ERROR_PROBABILITY << '\n'; std::cout << "Base output folder: " << BASE_OUT_FOLDER << '\n'; + std::cout << "Initial number of agents: " << nAgents << '\n'; std::cout << "-------------------------------------------------\n"; const std::string IN_MATRIX{"./data/matrix.dat"}; // input matrix file @@ -83,12 +84,11 @@ int main(int argc, char** argv) { graph.importCoordinates(IN_COORDS); std::cout << "Setting street parameters..." << '\n'; for (const auto& [streetId, street] : graph.streetSet()) { - street->setLength(2e3); - street->setCapacity(225); street->setTransportCapacity(1); street->setMaxSpeed(13.9); } graph.buildAdj(); + graph.normalizeStreetCapacities(); std::cout << "Number of nodes: " << graph.nNodes() << '\n'; std::cout << "Number of streets: " << graph.nEdges() << '\n'; diff --git a/examples/slow_charge_tl.cpp b/examples/slow_charge_tl.cpp index 09afb4691..8240a5cfe 100644 --- a/examples/slow_charge_tl.cpp +++ b/examples/slow_charge_tl.cpp @@ -18,7 +18,6 @@ namespace fs = std::filesystem; std::atomic progress{0}; std::atomic bExitFlag{false}; -uint nAgents{315}; // 315 for error probability 0.3, 450 for error probability 0.05 // uncomment these lines to print densities, flows and speeds #define PRINT_DENSITIES @@ -31,7 +30,7 @@ using Unit = unsigned int; using Delay = uint8_t; using Graph = dsm::Graph; -using Dynamics = dsm::FirstOrderDynamics; +using Dynamics = dsm::FirstOrderDynamics; using Street = dsm::Street; using SpireStreet = dsm::SpireStreet; using TrafficLight = dsm::TrafficLight; @@ -43,9 +42,10 @@ void printLoadingBar(int const i, int const n) { } int main(int argc, char** argv) { - if (argc != 5) { - std::cerr << "Usage: " << argv[0] - << " \n"; + if (argc != 6) { + std::cerr + << "Usage: " << argv[0] + << " \n"; return 1; } @@ -54,6 +54,7 @@ int main(int argc, char** argv) { std::string BASE_OUT_FOLDER{argv[3]}; const bool OPTIMIZE{std::string(argv[4]) != std::string("0")}; BASE_OUT_FOLDER += OPTIMIZE ? "_op/" : "/"; + auto nAgents{std::stoul(argv[5])}; const std::string IN_MATRIX{"./data/matrix.dat"}; // input matrix file const std::string IN_COORDS{"./data/coordinates.dsm"}; // input coords file @@ -68,6 +69,7 @@ int main(int argc, char** argv) { std::cout << "Seed: " << SEED << '\n'; std::cout << "Error probability: " << ERROR_PROBABILITY << '\n'; std::cout << "Base output folder: " << BASE_OUT_FOLDER << '\n'; + std::cout << "Initial number of agents: " << nAgents << '\n'; if (OPTIMIZE) { std::cout << "Traffic light optimization ENABLED.\n"; } @@ -89,12 +91,11 @@ int main(int argc, char** argv) { graph.importCoordinates(IN_COORDS); std::cout << "Setting street parameters..." << '\n'; for (const auto& [streetId, street] : graph.streetSet()) { - street->setLength(2e3); - street->setCapacity(225); street->setTransportCapacity(1); street->setMaxSpeed(13.9); } graph.buildAdj(); + graph.normalizeStreetCapacities(); const auto dv = graph.adjMatrix().getDegreeVector(); // graph.addStreet(Street(100002, std::make_pair(0, 108))); diff --git a/examples/stalingrado.cpp b/examples/stalingrado.cpp index 49a075691..cd82164e6 100644 --- a/examples/stalingrado.cpp +++ b/examples/stalingrado.cpp @@ -21,7 +21,7 @@ using Delay = uint8_t; using Graph = dsm::Graph; using Itinerary = dsm::Itinerary; -using Dynamics = dsm::FirstOrderDynamics; +using Dynamics = dsm::FirstOrderDynamics; using Street = dsm::Street; using SpireStreet = dsm::SpireStreet; using TrafficLight = dsm::TrafficLight; diff --git a/profiling/main.cpp b/profiling/main.cpp index 268a0b210..ef91cceba 100644 --- a/profiling/main.cpp +++ b/profiling/main.cpp @@ -10,7 +10,7 @@ using unit = uint32_t; using Graph = dsm::Graph; using Itinerary = dsm::Itinerary; -using Dynamics = dsm::FirstOrderDynamics; +using Dynamics = dsm::FirstOrderDynamics; int main() { Graph graph{}; @@ -36,13 +36,12 @@ int main() { std::cout << "Creating dynamics...\n"; - Dynamics dynamics{graph}; + Dynamics dynamics{graph, std::nullopt, 0.95}; dynamics.addItinerary(it1); dynamics.addItinerary(it2); dynamics.addItinerary(it3); dynamics.addItinerary(it4); dynamics.setErrorProbability(0.3); - dynamics.setMinSpeedRateo(0.95); dynamics.updatePaths(); std::cout << "Done.\n" diff --git a/src/dsm/dsm.hpp b/src/dsm/dsm.hpp index 4c71f828c..d3cfb1158 100644 --- a/src/dsm/dsm.hpp +++ b/src/dsm/dsm.hpp @@ -6,7 +6,7 @@ static constexpr uint8_t DSM_VERSION_MAJOR = 2; static constexpr uint8_t DSM_VERSION_MINOR = 2; -static constexpr uint8_t DSM_VERSION_PATCH = 4; +static constexpr uint8_t DSM_VERSION_PATCH = 5; static auto const DSM_VERSION = std::format("{}.{}.{}", DSM_VERSION_MAJOR, DSM_VERSION_MINOR, DSM_VERSION_PATCH); diff --git a/src/dsm/headers/Dynamics.hpp b/src/dsm/headers/Dynamics.hpp index 2506d78c7..4d42b1871 100644 --- a/src/dsm/headers/Dynamics.hpp +++ b/src/dsm/headers/Dynamics.hpp @@ -22,7 +22,6 @@ #include #include -#include "Agent.hpp" #include "DijkstraWeights.hpp" #include "Itinerary.hpp" #include "Graph.hpp" @@ -63,12 +62,11 @@ namespace dsm { /// @brief The Dynamics class represents the dynamics of the network. /// @tparam Id, The type of the graph's id. It must be an unsigned integral type. /// @tparam Size, The type of the graph's capacity. It must be an unsigned integral type. - template - requires(is_numeric_v) + template class Dynamics { protected: std::unordered_map> m_itineraries; - std::map>> m_agents; + std::map> m_agents; Graph m_graph; Time m_time, m_previousSpireTime; std::mt19937_64 m_generator; @@ -151,10 +149,10 @@ namespace dsm { /// @brief Add an agent to the simulation /// @param agent The agent - void addAgent(const Agent& agent); + void addAgent(const agent_t& agent); /// @brief Add an agent to the simulation /// @param agent std::unique_ptr to the agent - void addAgent(std::unique_ptr> agent); + void addAgent(std::unique_ptr agent); /// @brief Add an agent with given source node and itinerary /// @param srcNodeId The id of the source node /// @param itineraryId The id of the itinerary @@ -181,7 +179,7 @@ namespace dsm { void addAgents(T1 agent, Tn... agents); /// @brief Add a set of agents to the simulation /// @param agents Generic container of agents, represented by an std::span - void addAgents(std::span> agents); + void addAgents(std::span agents); /// @brief Add a set of agents to the simulation /// @param nAgents The number of agents to add /// @param uniformly If true, the agents are added uniformly on the streets @@ -240,9 +238,7 @@ namespace dsm { } /// @brief Get the agents /// @return const std::unordered_map>&, The agents - const std::map>>& agents() const { - return m_agents; - } + const std::map>& agents() const { return m_agents; } /// @brief Get the time /// @return Time The time Time time() const { return m_time; } @@ -283,9 +279,8 @@ namespace dsm { Measurement meanTravelTime(bool clearData = false); }; - template - requires(is_numeric_v) - Dynamics::Dynamics(Graph& graph, std::optional seed) + template + Dynamics::Dynamics(Graph& graph, std::optional seed) : m_graph{std::move(graph)}, m_time{0}, m_previousSpireTime{0}, @@ -295,9 +290,8 @@ namespace dsm { } } - template - requires(is_numeric_v) - void Dynamics::updatePaths() { + template + void Dynamics::updatePaths() { std::vector threads; threads.reserve(m_itineraries.size()); std::exception_ptr pThreadException; @@ -319,9 +313,8 @@ namespace dsm { std::rethrow_exception(pThreadException); } - template - requires(is_numeric_v) - void Dynamics::setDestinationNodes(const std::span& destinationNodes, + template + void Dynamics::setDestinationNodes(const std::span& destinationNodes, bool updatePaths) { for (const auto& nodeId : destinationNodes) { if (!m_graph.nodeSet().contains(nodeId)) { @@ -335,9 +328,8 @@ namespace dsm { } } - template - requires(is_numeric_v) - void Dynamics::addAgent(const Agent& agent) { + template + void Dynamics::addAgent(const agent_t& agent) { if (m_agents.size() + 1 > m_graph.maxCapacity()) { throw std::overflow_error(buildLog( std::format("Graph is already holding the max possible number of agents ({})", @@ -347,11 +339,10 @@ namespace dsm { throw std::invalid_argument( buildLog(std::format("Agent with id {} already exists.", agent.id()))); } - m_agents.emplace(agent.id(), std::make_unique>(agent)); + m_agents.emplace(agent.id(), std::make_unique(agent)); } - template - requires(is_numeric_v) - void Dynamics::addAgent(std::unique_ptr> agent) { + template + void Dynamics::addAgent(std::unique_ptr agent) { if (m_agents.size() + 1 > m_graph.maxCapacity()) { throw std::overflow_error(buildLog( std::format("Graph is already holding the max possible number of agents ({})", @@ -363,9 +354,8 @@ namespace dsm { } m_agents.emplace(agent->id(), std::move(agent)); } - template - requires(is_numeric_v) - void Dynamics::addAgent(Id srcNodeId, Id itineraryId) { + template + void Dynamics::addAgent(Id srcNodeId, Id itineraryId) { if (m_agents.size() + 1 > m_graph.maxCapacity()) { throw std::overflow_error(buildLog( std::format("Graph is already holding the max possible number of agents ({})", @@ -383,11 +373,10 @@ namespace dsm { if (!m_agents.empty()) { agentId = m_agents.rbegin()->first + 1; } - this->addAgent(Agent{agentId, itineraryId, srcNodeId}); + this->addAgent(agent_t{agentId, itineraryId, srcNodeId}); } - template - requires(is_numeric_v) - void Dynamics::addAgents(Id itineraryId, + template + void Dynamics::addAgents(Id itineraryId, Size nAgents, std::optional srcNodeId) { if (m_agents.size() + nAgents > m_graph.maxCapacity()) { @@ -405,28 +394,25 @@ namespace dsm { agentId = m_agents.rbegin()->first + 1; } for (Size i{0}; i < nAgents; ++i, ++agentId) { - this->addAgent(Agent{agentId, itineraryId, srcNodeId}); + this->addAgent(agent_t{agentId, itineraryId, srcNodeId}); } } - template - requires(is_numeric_v) + template template requires(is_agent_v && ...) - void Dynamics::addAgents(Tn... agents) {} + void Dynamics::addAgents(Tn... agents) {} - template - requires(is_numeric_v) + template template requires(is_agent_v && (is_agent_v && ...)) - void Dynamics::addAgents(T1 agent, Tn... agents) { + void Dynamics::addAgents(T1 agent, Tn... agents) { addAgent(agent); addAgents(agents...); } - template - requires(is_numeric_v) - void Dynamics::addAgents(std::span> agents) { + template + void Dynamics::addAgents(std::span agents) { if (this->m_agents.size() + agents.size() > this->m_graph.maxCapacity()) { throw std::overflow_error(buildLog( std::format("Graph is already holding the max possible number of agents ({})", @@ -437,9 +423,8 @@ namespace dsm { }); } - template - requires(is_numeric_v) - void Dynamics::addAgentsUniformly(Size nAgents, + template + void Dynamics::addAgentsUniformly(Size nAgents, std::optional itineraryId) { if (m_agents.size() + nAgents > m_graph.maxCapacity()) { throw std::overflow_error(buildLog( @@ -477,7 +462,7 @@ namespace dsm { streetId = streetIt->first; } while (m_graph.streetSet()[streetId]->isFull()); const auto& street{m_graph.streetSet()[streetId]}; - Agent agent{agentId, itineraryId.value(), street->nodePair().first}; + agent_t agent{agentId, itineraryId.value(), street->nodePair().first}; agent.setStreetId(streetId); this->addAgent(agent); this->setAgentSpeed(agentId); @@ -488,12 +473,11 @@ namespace dsm { } } - template - requires(is_numeric_v) + template template requires(std::is_same_v> || std::is_same_v>) - void Dynamics::addAgentsRandomly(Size nAgents, + void Dynamics::addAgentsRandomly(Size nAgents, const TContainer& src_weights, const TContainer& dst_weights) { if (src_weights.size() == 1 && dst_weights.size() == 1 && @@ -572,58 +556,50 @@ namespace dsm { } } - template - requires(is_numeric_v) - void Dynamics::removeAgent(Size agentId) { + template + void Dynamics::removeAgent(Size agentId) { m_agents.erase(agentId); } - template - requires(is_numeric_v) + template + template requires(std::is_convertible_v && (std::is_convertible_v && ...)) - void Dynamics::removeAgents(T1 id, Tn... ids) { + void Dynamics::removeAgents(T1 id, Tn... ids) { removeAgent(id); removeAgents(ids...); } - template - requires(is_numeric_v) - void Dynamics::addItinerary(const Itinerary& itinerary) { + template + void Dynamics::addItinerary(const Itinerary& itinerary) { m_itineraries.emplace(itinerary.id(), std::make_unique(itinerary)); } - template - requires(is_numeric_v) - void Dynamics::addItinerary(std::unique_ptr itinerary) { + template + void Dynamics::addItinerary(std::unique_ptr itinerary) { m_itineraries.emplace(itinerary->id(), std::move(itinerary)); } - template - requires(is_numeric_v) + template template requires(is_itinerary_v && ...) - void Dynamics::addItineraries(Tn... itineraries) { + void Dynamics::addItineraries(Tn... itineraries) { (this->addItinerary(itineraries), ...); } - - template - requires(is_numeric_v) - void Dynamics::addItineraries(std::span itineraries) { + template + void Dynamics::addItineraries(std::span itineraries) { std::ranges::for_each(itineraries, [this](const auto& itinerary) -> void { m_itineraries.insert(std::make_unique(itinerary)); }); } - template - requires(is_numeric_v) - void Dynamics::resetTime() { + template + void Dynamics::resetTime() { m_time = 0; } - template - requires(is_numeric_v) - Measurement Dynamics::agentMeanSpeed() const { + template + Measurement Dynamics::agentMeanSpeed() const { std::vector speeds; if (!m_agents.empty()) { speeds.reserve(m_agents.size()); @@ -634,9 +610,8 @@ namespace dsm { return Measurement(speeds); } - template - requires(is_numeric_v) - Measurement Dynamics::streetMeanDensity(bool normalized) const { + template + Measurement Dynamics::streetMeanDensity(bool normalized) const { if (m_graph.streetSet().size() == 0) { return Measurement(0., 0.); } @@ -648,9 +623,8 @@ namespace dsm { return Measurement(densities); } - template - requires(is_numeric_v) - Measurement Dynamics::streetMeanFlow() const { + template + Measurement Dynamics::streetMeanFlow() const { std::vector flows; flows.reserve(m_graph.streetSet().size()); for (const auto& [streetId, street] : m_graph.streetSet()) { @@ -659,9 +633,8 @@ namespace dsm { return Measurement(flows); } - template - requires(is_numeric_v) - Measurement Dynamics::streetMeanFlow(double threshold, + template + Measurement Dynamics::streetMeanFlow(double threshold, bool above) const { std::vector flows; flows.reserve(m_graph.streetSet().size()); @@ -675,9 +648,8 @@ namespace dsm { return Measurement(flows); } - template - requires(is_numeric_v) - Measurement Dynamics::meanSpireInputFlow(bool resetValue) { + template + Measurement Dynamics::meanSpireInputFlow(bool resetValue) { auto deltaTime{m_time - m_previousSpireTime}; if (deltaTime == 0) { return Measurement(0., 0.); @@ -694,9 +666,8 @@ namespace dsm { return Measurement(flows); } - template - requires(is_numeric_v) - Measurement Dynamics::meanSpireOutputFlow(bool resetValue) { + template + Measurement Dynamics::meanSpireOutputFlow(bool resetValue) { auto deltaTime{m_time - m_previousSpireTime}; if (deltaTime == 0) { return Measurement(0., 0.); diff --git a/src/dsm/headers/FirstOrderDynamics.cpp b/src/dsm/headers/FirstOrderDynamics.cpp new file mode 100644 index 000000000..e43096433 --- /dev/null +++ b/src/dsm/headers/FirstOrderDynamics.cpp @@ -0,0 +1,126 @@ +#include "FirstOrderDynamics.hpp" + +namespace dsm { + FirstOrderDynamics::FirstOrderDynamics(Graph& graph, + std::optional seed, + double alpha) + : RoadDynamics(graph, seed), m_alpha{0.}, m_speedFluctuationSTD{0.} { + if (alpha < 0. || alpha > 1.) { + throw std::invalid_argument(buildLog(std::format( + "The minimum speed rateo must be between 0 and 1, but it is {}", alpha))); + } else { + m_alpha = alpha; + } + double globMaxTimePenalty{0.}; + for (const auto& [streetId, street] : this->m_graph.streetSet()) { + globMaxTimePenalty = + std::max(globMaxTimePenalty, + std::ceil(street->length() / ((1. - m_alpha) * street->maxSpeed()))); + } + if (globMaxTimePenalty > static_cast(std::numeric_limits::max())) { + throw std::overflow_error( + buildLog(std::format("The maximum time penalty ({}) is greater than the " + "maximum value of delay_t ({})", + globMaxTimePenalty, + std::numeric_limits::max()))); + } + } + + void FirstOrderDynamics::setAgentSpeed(Size agentId) { + const auto& agent{this->m_agents[agentId]}; + const auto& street{this->m_graph.streetSet()[agent->streetId().value()]}; + double speed{street->maxSpeed() * (1. - m_alpha * street->density(true))}; + if (m_speedFluctuationSTD > 0.) { + std::normal_distribution speedDist{speed, speed * m_speedFluctuationSTD}; + speed = speedDist(this->m_generator); + } + speed < 0. ? agent->setSpeed(street->maxSpeed() * (1. - m_alpha)) + : agent->setSpeed(speed); + } + + void FirstOrderDynamics::setSpeedFluctuationSTD(double speedFluctuationSTD) { + if (speedFluctuationSTD < 0.) { + throw std::invalid_argument( + buildLog("The speed fluctuation standard deviation must be positive.")); + } + m_speedFluctuationSTD = speedFluctuationSTD; + } + + double FirstOrderDynamics::streetMeanSpeed(Id streetId) const { + const auto& street{this->m_graph.streetSet().at(streetId)}; + if (street->nAgents() == 0) { + return street->maxSpeed(); + } + double meanSpeed{0.}; + Size n{0}; + if (street->nExitingAgents() == 0) { + n = static_cast(street->waitingAgents().size()); + double alpha{m_alpha / street->capacity()}; + meanSpeed = street->maxSpeed() * n * (1. - 0.5 * alpha * (n - 1.)); + } else { + for (const auto& agentId : street->waitingAgents()) { + meanSpeed += this->m_agents.at(agentId)->speed(); + ++n; + } + for (auto const& queue : street->exitQueues()) { + for (const auto& agentId : queue) { + meanSpeed += this->m_agents.at(agentId)->speed(); + ++n; + } + } + } + const auto& node = this->m_graph.nodeSet().at(street->nodePair().second); + if (node->isIntersection()) { + auto& intersection = dynamic_cast(*node); + for (const auto& [angle, agentId] : intersection.agents()) { + const auto& agent{this->m_agents.at(agentId)}; + if (agent->streetId().has_value() && agent->streetId().value() == streetId) { + meanSpeed += agent->speed(); + ++n; + } + } + } else if (node->isRoundabout()) { + auto& roundabout = dynamic_cast(*node); + for (const auto& agentId : roundabout.agents()) { + const auto& agent{this->m_agents.at(agentId)}; + if (agent->streetId().has_value() && agent->streetId().value() == streetId) { + meanSpeed += agent->speed(); + ++n; + } + } + } + return meanSpeed / n; + } + + Measurement FirstOrderDynamics::streetMeanSpeed() const { + if (this->m_agents.size() == 0) { + return Measurement(0., 0.); + } + std::vector speeds; + speeds.reserve(this->m_graph.streetSet().size()); + for (const auto& [streetId, street] : this->m_graph.streetSet()) { + speeds.push_back(this->streetMeanSpeed(streetId)); + } + return Measurement(speeds); + } + Measurement FirstOrderDynamics::streetMeanSpeed(double threshold, + bool above) const { + if (this->m_agents.size() == 0) { + return Measurement(0., 0.); + } + std::vector speeds; + speeds.reserve(this->m_graph.streetSet().size()); + for (const auto& [streetId, street] : this->m_graph.streetSet()) { + if (above) { + if (street->density(true) > threshold) { + speeds.push_back(this->streetMeanSpeed(streetId)); + } + } else { + if (street->density(true) < threshold) { + speeds.push_back(this->streetMeanSpeed(streetId)); + } + } + } + return Measurement(speeds); + } +} // namespace dsm \ No newline at end of file diff --git a/src/dsm/headers/FirstOrderDynamics.hpp b/src/dsm/headers/FirstOrderDynamics.hpp index 4b201d0b7..27fe7c134 100644 --- a/src/dsm/headers/FirstOrderDynamics.hpp +++ b/src/dsm/headers/FirstOrderDynamics.hpp @@ -3,18 +3,16 @@ #include "RoadDynamics.hpp" namespace dsm { - template - requires(std::unsigned_integral) - class FirstOrderDynamics : public RoadDynamics { + class FirstOrderDynamics : public RoadDynamics { double m_alpha; double m_speedFluctuationSTD; public: /// @brief Construct a new First Order Dynamics object /// @param graph, The graph representing the network - FirstOrderDynamics(Graph& graph, - std::optional seed = std::nullopt, - double minSpeedRateo = 0.); + explicit FirstOrderDynamics(Graph& graph, + std::optional seed = std::nullopt, + double alpha = 0.); /// @brief Set the speed of an agent /// @param agentId The id of the agent /// @throw std::invalid_argument, If the agent is not found @@ -39,144 +37,4 @@ namespace dsm { /// @return Measurement The mean speed of the agents and the standard deviation Measurement streetMeanSpeed(double threshold, bool above) const override; }; - - template - requires(std::unsigned_integral) - FirstOrderDynamics::FirstOrderDynamics(Graph& graph, - std::optional seed, - double minSpeedRateo) - : RoadDynamics(graph, seed), - m_alpha{0.}, - m_speedFluctuationSTD{0.} { - if (minSpeedRateo < 0. || minSpeedRateo > 1.) { - throw std::invalid_argument(buildLog( - std::format("The minimum speed rateo must be between 0 and 1, but it is {}", - minSpeedRateo))); - } else { - m_alpha = minSpeedRateo; - } - double globMaxTimePenalty{0.}; - for (const auto& [streetId, street] : this->m_graph.streetSet()) { - globMaxTimePenalty = - std::max(globMaxTimePenalty, - std::ceil(street->length() / - ((1. - m_alpha) * street->maxSpeed()))); - } - if (globMaxTimePenalty > static_cast(std::numeric_limits::max())) { - throw std::overflow_error( - buildLog(std::format("The maximum time penalty ({}) is greater than the " - "maximum value of delay_t ({})", - globMaxTimePenalty, - std::numeric_limits::max()))); - } - } - - template - requires(std::unsigned_integral) - void FirstOrderDynamics::setAgentSpeed(Size agentId) { - const auto& agent{this->m_agents[agentId]}; - const auto& street{this->m_graph.streetSet()[agent->streetId().value()]}; - double speed{street->maxSpeed() * - (1. - m_alpha * street->density(true))}; - if (m_speedFluctuationSTD > 0.) { - std::normal_distribution speedDist{speed, speed * m_speedFluctuationSTD}; - speed = speedDist(this->m_generator); - } - speed < 0. ? agent->setSpeed(street->maxSpeed() * (1. - m_alpha)) - : agent->setSpeed(speed); - } - - template - requires(std::unsigned_integral) - void FirstOrderDynamics::setSpeedFluctuationSTD(double speedFluctuationSTD) { - if (speedFluctuationSTD < 0.) { - throw std::invalid_argument( - buildLog("The speed fluctuation standard deviation must be positive.")); - } - m_speedFluctuationSTD = speedFluctuationSTD; - } - - template - requires(std::unsigned_integral) - double FirstOrderDynamics::streetMeanSpeed(Id streetId) const { - const auto& street{this->m_graph.streetSet().at(streetId)}; - if (street->nAgents() == 0) { - return street->maxSpeed(); - } - double meanSpeed{0.}; - Size n{0}; - if (street->nExitingAgents() == 0) { - n = static_cast(street->waitingAgents().size()); - double alpha{m_alpha / street->capacity()}; - meanSpeed = street->maxSpeed() * n * (1. - 0.5 * alpha * (n - 1.)); - } else { - for (const auto& agentId : street->waitingAgents()) { - meanSpeed += this->m_agents.at(agentId)->speed(); - ++n; - } - for (auto const& queue : street->exitQueues()) { - for (const auto& agentId : queue) { - meanSpeed += this->m_agents.at(agentId)->speed(); - ++n; - } - } - } - const auto& node = this->m_graph.nodeSet().at(street->nodePair().second); - if (node->isIntersection()) { - auto& intersection = dynamic_cast(*node); - for (const auto& [angle, agentId] : intersection.agents()) { - const auto& agent{this->m_agents.at(agentId)}; - if (agent->streetId().has_value() && agent->streetId().value() == streetId) { - meanSpeed += agent->speed(); - ++n; - } - } - } else if (node->isRoundabout()) { - auto& roundabout = dynamic_cast(*node); - for (const auto& agentId : roundabout.agents()) { - const auto& agent{this->m_agents.at(agentId)}; - if (agent->streetId().has_value() && agent->streetId().value() == streetId) { - meanSpeed += agent->speed(); - ++n; - } - } - } - return meanSpeed / n; - } - - template - requires(std::unsigned_integral) - Measurement FirstOrderDynamics::streetMeanSpeed() const { - if (this->m_agents.size() == 0) { - return Measurement(0., 0.); - } - std::vector speeds; - speeds.reserve(this->m_graph.streetSet().size()); - for (const auto& [streetId, street] : this->m_graph.streetSet()) { - speeds.push_back(this->streetMeanSpeed(streetId)); - } - return Measurement(speeds); - } - template - requires(std::unsigned_integral) - Measurement FirstOrderDynamics::streetMeanSpeed(double threshold, - bool above) const { - if (this->m_agents.size() == 0) { - return Measurement(0., 0.); - } - std::vector speeds; - speeds.reserve(this->m_graph.streetSet().size()); - for (const auto& [streetId, street] : this->m_graph.streetSet()) { - if (above) { - if (street->density(true) > threshold) { - speeds.push_back(this->streetMeanSpeed(streetId)); - } - } else { - if (street->density(true) < threshold) { - speeds.push_back(this->streetMeanSpeed(streetId)); - } - } - } - return Measurement(speeds); - } } // namespace dsm \ No newline at end of file diff --git a/src/dsm/headers/RoadDynamics.hpp b/src/dsm/headers/RoadDynamics.hpp index 619c6788b..fef7414f8 100644 --- a/src/dsm/headers/RoadDynamics.hpp +++ b/src/dsm/headers/RoadDynamics.hpp @@ -39,7 +39,7 @@ namespace dsm { /// @tparam Size, The type of the graph's capacity. It must be an unsigned integral type. template requires(is_numeric_v) - class RoadDynamics : public Dynamics { + class RoadDynamics : public Dynamics> { protected: Time m_previousOptimizationTime; double m_errorProbability; @@ -82,10 +82,7 @@ namespace dsm { /// @brief Construct a new RoadDynamics object /// @param graph The graph representing the network /// @param seed The seed for the random number generator - /// @param minSpeedRateo The minimum speed rateo - RoadDynamics(Graph& graph, - std::optional seed, - double minSpeedRateo = 0.); + RoadDynamics(Graph& graph, std::optional seed); /// @brief Set the error probability /// @param errorProbability The error probability @@ -150,10 +147,8 @@ namespace dsm { template requires(is_numeric_v) - RoadDynamics::RoadDynamics(Graph& graph, - std::optional seed, - double minSpeedRateo) - : Dynamics(graph, seed), + RoadDynamics::RoadDynamics(Graph& graph, std::optional seed) + : Dynamics>(graph, seed), m_previousOptimizationTime{0}, m_errorProbability{0.}, m_maxFlowPercentage{1.}, diff --git a/test/Test_dynamics.cpp b/test/Test_dynamics.cpp index 9a88940b2..b81e69bf9 100644 --- a/test/Test_dynamics.cpp +++ b/test/Test_dynamics.cpp @@ -7,7 +7,7 @@ #include "doctest.h" -using Dynamics = dsm::FirstOrderDynamics; +using Dynamics = dsm::FirstOrderDynamics; using Graph = dsm::Graph; using SparseMatrix = dsm::SparseMatrix; using Street = dsm::Street; diff --git a/utils/plotter.py b/utils/plotter.py index 4c55147df..160eaf418 100644 --- a/utils/plotter.py +++ b/utils/plotter.py @@ -49,6 +49,7 @@ """ import os +import sys from argparse import ArgumentParser import pandas as pd import seaborn as sns @@ -57,7 +58,7 @@ import networkx as nx from tqdm import tqdm -PRESENTATION = True +PRESENTATION = False class RealTimePeakDetection: @@ -267,17 +268,21 @@ def adjust_dataframe(_df): df_den_array.append(temp) # make an unique dataframe as mean of all the dataframes + DF = None if len(df_array) > 0: DF = pd.concat(df_array) DF = DF.groupby(DF.index).mean() else: - DF = None + print("No data found") + sys.exit() + DF_DEN = None if len(df_den_array) > 0: DF_DEN = pd.concat(df_den_array) DF_DEN = DF_DEN.groupby(DF_DEN.index).mean() else: - DF_DEN = None + print("No density data found") + sys.exit() ############################################ # Load densities