Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
temp*

# Examples generated files
examples/sctl/*
examples/scrb/*
examples/sctl*
examples/scrb*
examples/*.csv

# Utils generated folders
Expand Down
2 changes: 1 addition & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
slow_charge_tl:
./slow_charge_tl.out 69 0.3 ./sctl/ 0
./slow_charge_tl.out 69 0.3 ./sctl 0
slow_charge_rb:
./slow_charge_rb.out 69 0.3 ./scrb/
stalingrado:
Expand Down
28 changes: 14 additions & 14 deletions examples/slow_charge_tl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,29 +52,27 @@ int main(int argc, char** argv) {

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]};
std::string BASE_OUT_FOLDER{argv[3]};
const bool OPTIMIZE{std::string(argv[4]) != std::string("0")};

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';
if (OPTIMIZE) {
std::cout << "Traffic light optimization enabled.\n";
}
std::cout << "-------------------------------------------------\n";
BASE_OUT_FOLDER += OPTIMIZE ? "_op/" : "/";

const std::string IN_MATRIX{"./data/matrix.dat"}; // input matrix file
const std::string IN_COORDS{"./data/coordinates.dsm"}; // input coords file
std::string OUT_FOLDER{std::format("{}output_sctl_{}_{}/",
BASE_OUT_FOLDER,
ERROR_PROBABILITY,
std::to_string(SEED))}; // output folder
constexpr auto MAX_TIME{static_cast<unsigned int>(1e6)}; // maximum time of simulation

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';
if (OPTIMIZE) {
OUT_FOLDER += "_op/";
std::cout << "Traffic light optimization ENABLED.\n";
}
const auto MAX_TIME{static_cast<unsigned int>(1e6)}; // maximum time of simulation
std::cout << "-------------------------------------------------\n";

// Clear output folder or create it if it doesn't exist
if (!fs::exists(BASE_OUT_FOLDER)) {
Expand Down Expand Up @@ -228,6 +226,8 @@ int main(int argc, char** argv) {
// dynamics.setForcePriorities(false);
dynamics.setSpeedFluctuationSTD(0.1);
dynamics.setMinSpeedRateo(0.95);
if (OPTIMIZE)
dynamics.setDataUpdatePeriod(30); // Store data every 30 time steps
dynamics.updatePaths();

const auto TM = dynamics.turnMapping();
Expand Down Expand Up @@ -310,7 +310,7 @@ int main(int argc, char** argv) {
}
dynamics.evolve(false);
if (OPTIMIZE && (dynamics.time() % 420 == 0)) {
dynamics.optimizeTrafficLights(std::floor(420. / 60), 0.15);
dynamics.optimizeTrafficLights(std::floor(420. / 60), 0.15, 3. / 10);
}
if (dynamics.time() % 2400 == 0 && nAgents > 0) {
// auto meanDelta = std::accumulate(deltas.begin(), deltas.end(), 0) /
Expand Down
25 changes: 13 additions & 12 deletions examples/stalingrado.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@
#include <thread>
#include <atomic>

using unit = uint32_t;
std::atomic<unsigned int> progress{0};

std::atomic<unit> progress{0};
using Unit = unsigned int;
using Delay = uint8_t;

using Graph = dsm::Graph<unit, unit>;
using Itinerary = dsm::Itinerary<unit>;
using Dynamics = dsm::FirstOrderDynamics<unit, unit, unit>;
using TrafficLight = dsm::TrafficLight<unit, unit, unit>;
using Street = dsm::Street<unit, unit>;
using SpireStreet = dsm::SpireStreet<unit, unit>;
using Graph = dsm::Graph<Unit, Unit>;
using Itinerary = dsm::Itinerary<Unit>;
using Dynamics = dsm::FirstOrderDynamics<Unit, Unit, Delay>;
using Street = dsm::Street<Unit, Unit>;
using SpireStreet = dsm::SpireStreet<Unit, Unit>;
using TrafficLight = dsm::TrafficLight<Unit, Unit, Delay>;

void printLoadingBar(int const i, int const n) {
std::cout << "Loading: " << std::setprecision(2) << std::fixed << (i * 100. / n) << "%"
Expand All @@ -34,15 +35,15 @@ void printLoadingBar(int const i, int const n) {
int main() {
// Import input data
std::ifstream ifs{"./data/stalingrado_input.txt"};
unit timeUnit{0};
Unit timeUnit{0};
ifs >> timeUnit;
std::vector<unit> vehiclesToInsert{};
std::vector<Unit> vehiclesToInsert{};
while (!ifs.eof()) {
unit vehicleId{0};
Unit vehicleId{0};
ifs >> vehicleId;
vehiclesToInsert.push_back(vehicleId);
}
const auto MAX_TIME{static_cast<unit>(timeUnit * vehiclesToInsert.size())};
const auto MAX_TIME{static_cast<Unit>(timeUnit * vehiclesToInsert.size())};

// Create the graph
TrafficLight tl1{1}, tl2{2}, tl3{3}, tl4{4};
Expand Down
124 changes: 109 additions & 15 deletions src/dsm/headers/Dynamics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@ namespace dsm {
std::vector<unsigned int> m_travelTimes;
std::unordered_map<Id, Id> m_agentNextStreetId;
bool m_forcePriorities;
std::optional<Delay> m_dataUpdatePeriod;
std::unordered_map<Id, std::array<unsigned long long, 4>> m_turnCounts;
std::unordered_map<Id, std::array<long, 4>> m_turnMapping;
std::unordered_map<Id, unsigned long long> m_streetTails;

/// @brief Get the next street id
/// @param agentId The id of the agent
Expand Down Expand Up @@ -147,6 +149,12 @@ namespace dsm {
/// @param forcePriorities The flag
/// @details If true, if an agent cannot move to the next street, the whole node is skipped
void setForcePriorities(bool forcePriorities) { m_forcePriorities = forcePriorities; }
/// @brief Set the data update period.
/// @param dataUpdatePeriod Delay, The period
/// @details Some data, i.e. the street queue lengths, are stored only after a fixed amount of time which is represented by this variable.
void setDataUpdatePeriod(Delay dataUpdatePeriod) {
m_dataUpdatePeriod = dataUpdatePeriod;
}

/// @brief Update the paths of the itineraries based on the actual travel times
virtual void updatePaths();
Expand All @@ -163,9 +171,12 @@ namespace dsm {
/// @brief Optimize the traffic lights by changing the green and red times
/// @param percentage double, The percentage of the TOTAL cycle time to add or subtract to the green time
/// @param threshold double, The percentage of the mean capacity of the streets used as threshold for the delta between the two tails.
/// @param densityTolerance double, The algorithm will consider all streets with density up to densityTolerance*meanDensity
/// @details The function cycles over the traffic lights and, if the difference between the two tails is greater than
/// the threshold multiplied by the mean capacity of the streets, it changes the green and red times of the traffic light, keeping the total cycle time constant.
void optimizeTrafficLights(double percentage, double threshold = 0.);
void optimizeTrafficLights(double percentage,
double threshold = 0.,
double densityTolerance = 0.);

/// @brief Get the graph
/// @return const Graph<Id, Size>&, The graph
Expand Down Expand Up @@ -325,6 +336,7 @@ namespace dsm {
m_maxFlowPercentage{1.},
m_forcePriorities{false} {
for (const auto& [streetId, street] : m_graph.streetSet()) {
m_streetTails.emplace(streetId, 0);
m_turnCounts.emplace(streetId, std::array<unsigned long long, 4>{0, 0, 0, 0});
// fill turn mapping as [streetId, [left street Id, straight street Id, right street Id, U self street Id]]
m_turnMapping.emplace(streetId, std::array<long, 4>{-1, -1, -1, -1});
Expand Down Expand Up @@ -414,6 +426,12 @@ namespace dsm {
if (m_agents[agentId]->delay() > 0) {
continue;
}
if (m_dataUpdatePeriod.has_value()) {
if (m_time % m_dataUpdatePeriod.value() == 0) {
//m_streetTails[streetId] += street->queue().size();
m_streetTails[streetId] += street->waitingAgents().size();
}
}
m_agents[agentId]->setSpeed(0.);
const auto& destinationNode{this->m_graph.nodeSet()[street->nodePair().second]};
if (destinationNode->isFull()) {
Expand Down Expand Up @@ -705,7 +723,21 @@ namespace dsm {
requires(std::unsigned_integral<Id> && std::unsigned_integral<Size> &&
is_numeric_v<Delay>)
void Dynamics<Id, Size, Delay>::optimizeTrafficLights(double percentage,
double threshold) {
double threshold,
double densityTolerance) {
if (threshold < 0 || threshold > 1) {
throw std::invalid_argument(
buildLog(std::format("The threshold parameter is a percentage and must be "
"bounded between 0-1. Inserted value: {}",
threshold)));
}
if (densityTolerance < 0 || densityTolerance > 1) {
throw std::invalid_argument(buildLog(
std::format("The densityTolerance parameter is a percentage and must be "
"bounded between 0-1. Inserted value: {}",
densityTolerance)));
}
const auto meanDensityGlob = streetMeanDensity().mean; // Measurement<double>
for (const auto& [nodeId, node] : m_graph.nodeSet()) {
if (!node->isTrafficLight()) {
continue;
Expand All @@ -716,16 +748,15 @@ namespace dsm {
}
auto [greenTime, redTime] = tl.delay().value();
const auto cycleTime = greenTime + redTime;
// const Delay delta = cycleTime * percentage;
const auto& streetPriorities = tl.streetPriorities();
Size greenSum{0}, greenQueue{0};
Size redSum{0}, redQueue{0};
for (const auto& [streetId, _] : m_graph.adjMatrix().getCol(nodeId, true)) {
if (streetPriorities.contains(streetId)) {
greenSum += m_graph.streetSet()[streetId]->nAgents();
greenSum += m_streetTails[streetId];
greenQueue += m_graph.streetSet()[streetId]->queue().size();
} else {
redSum += m_graph.streetSet()[streetId]->nAgents();
redSum += m_streetTails[streetId];
redQueue += m_graph.streetSet()[streetId]->queue().size();
}
}
Expand All @@ -739,18 +770,81 @@ namespace dsm {
tl.setDelay(std::floor(cycleTime / 2));
continue;
}
if ((greenSum > redSum) && !(greenTime > redTime) && (greenQueue > redQueue)) {
if (redTime > delta) {
greenTime += delta;
redTime -= delta;
tl.setDelay(std::make_pair(greenTime, redTime));
// If the difference is not less than the threshold
// - 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
// - If the previous check fails, do nothing
double meanDensity_streets{0.};
{
// Store the ids of outgoing streets
const auto& row{m_graph.adjMatrix().getRow(nodeId, true)};
for (const auto& [streetId, _] : row) {
meanDensity_streets += m_graph.streetSet()[streetId]->density();
}
} else if (!(redTime > greenTime) && (greenTime > delta) &&
(redQueue > greenQueue)) {
greenTime -= delta;
redTime += delta;
tl.setDelay(std::make_pair(greenTime, redTime));
// Take the mean density of the outgoing streets
meanDensity_streets /= row.size();
}
//std::cout << '\t' << " -> Mean network density: " << std::setprecision(7) << meanDensityGlob << '\n';
//std::cout << '\t' << " -> Mean density of 4 outgoing streets: " << std::setprecision(7) << meanDensity_streets << '\n';
const auto ratio = meanDensityGlob / meanDensity_streets;
// densityTolerance represents the max border we want to consider
const auto dyn_thresh = std::tanh(ratio) * densityTolerance;
//std::cout << '\t' << " -> Parametro ratio: " << std::setprecision(7) << ratio << '\n';
//std::cout << '\t' << " -> Parametro dyn_thresh: " << std::setprecision(7) << dyn_thresh << '\n';
if (meanDensityGlob * (1. + dyn_thresh) > meanDensity_streets) {
//std::cout << '\t' << " -> I'm on the cluster's border" << '\n';
if (meanDensityGlob > meanDensity_streets) {
//std::cout << '\t' << " -> LESS than max density" << '\n';
if (!(redTime > greenTime) && (redSum > greenSum) && (greenTime > delta)) {
greenTime -= delta;
redTime += delta;
tl.setDelay(std::make_pair(greenTime, redTime));
} else if (!(greenTime > redTime) && (greenSum > redSum) && (redTime > delta)) {
greenTime += delta;
redTime -= delta;
tl.setDelay(std::make_pair(greenTime, redTime));
} else {
//std::cout << '\t' << " -> NOT entered into previous ifs" << '\n';
tl.setDelay(std::make_pair(greenTime, redTime));
}
//std::cout << '\t' << " -> greenTime: " << static_cast<unsigned int>(greenTime) << '\n';
//std::cout << '\t' << " -> redTime: " << static_cast<unsigned int>(redTime) << '\n';
//std::cout << '\t' << " -> modTime: " << tl.modTime() << '\n';
} else {
//std::cout << '\t' << " -> GREATER than max density" << '\n';
if (!(redTime > greenTime) && (redSum > greenSum) &&
(greenTime > ratio * delta)) {
greenTime -= dyn_thresh * delta; //
redTime += delta;
tl.setDelay(std::make_pair(greenTime, redTime));
} else if (!(greenTime > redTime) && (greenSum > redSum) &&
(redTime > ratio * delta)) {
greenTime += delta;
redTime -= dyn_thresh * delta; //
tl.setDelay(std::make_pair(greenTime, redTime));
} else if (!(redTime > greenTime) && (redSum < greenSum) && (redTime > delta)) {
greenTime += dyn_thresh * delta; //
redTime -= delta;
tl.setDelay(std::make_pair(greenTime, redTime));
} else if (!(redTime < greenTime) && (redSum > greenSum) &&
(greenTime > delta)) {
greenTime -= delta;
redTime += dyn_thresh * delta; //
tl.setDelay(std::make_pair(greenTime, redTime));
} else {
//std::cout << '\t' << " -> NON sono entrato negli if precedenti" << '\n';
tl.setDelay(std::make_pair(greenTime, redTime));
}
//std::cout << '\t' << " -> greenTime: " << static_cast<unsigned int>(greenTime) << '\n';
//std::cout << '\t' << " -> redTime: " << static_cast<unsigned int>(redTime) << '\n';
//std::cout << '\t' << " -> modTime: " << tl.modTime() << '\n';
}
} else {
//std::cout << '\t' << " -> I'm INTO the cluster" << '\n';
//std::cout << '\t' << " -> modTime: " << tl.modTime() << '\n';
}
}
for (auto& [id, element] : m_streetTails) {
element = 0;
}
}

Expand Down
26 changes: 26 additions & 0 deletions src/dsm/headers/Node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ namespace dsm {
std::optional<std::pair<Delay, Delay>> m_delay;
Delay m_counter;
Delay m_phase;
/// @brief Variabile che mi dice come sono in rapporto tra di loro il tempo di verde e il tempo di rosso
/// @details Valori possibili: 0, 1, 2 (fino a che non verrà modificata)
/// - se 0: |redTime - greenTime| < 10 && redTime > 5 && greenTime > 5
/// - se 1: |redtime - greenTime| \geq 10 && |redTime - greenTime| < 40 && redTime > 5 && greenTime > 5
/// - se 2: |redTime - greenTime| \geq 40 || redTime < 5 || greenTime < 5
int m_modTime{7};

public:
TrafficLight() = delete;
Expand Down Expand Up @@ -272,6 +278,9 @@ namespace dsm {
/// @return std::optional<Delay> The node's delay
std::optional<std::pair<Delay, Delay>> delay() const { return m_delay; }
Delay counter() const { return m_counter; }
/// @brief Get the node's modTime
/// @return int. The node's modTime
int modTime() const { return m_modTime; }
/// @brief Returns true if the traffic light is green
/// @return bool True if the traffic light is green
bool isGreen() const;
Expand Down Expand Up @@ -304,6 +313,11 @@ namespace dsm {
}
}
m_delay = std::make_pair(delay, delay);
if (delay < 5) {
m_modTime = 2;
} else {
m_modTime = 0;
}
}
template <typename Id, typename Size, typename Delay>
requires(std::unsigned_integral<Id> && std::unsigned_integral<Size> &&
Expand All @@ -319,6 +333,18 @@ namespace dsm {
}
}
m_delay = std::move(delay);
if (delay.first < 5 || delay.second < 5) {
m_modTime = 2;
} else if (std::abs(delay.first - delay.second) < 10) {
m_modTime = 0;
} else if ((std::abs(delay.first - delay.second) > 10 ||
std::abs(delay.first - delay.second) == 10) &&
(std::abs(delay.first - delay.second) < 40 ||
std::abs(delay.first - delay.second) == 40)) {
m_modTime = 1;
} else if (std::abs(delay.first - delay.second) > 40) {
m_modTime = 2;
}
}
template <typename Id, typename Size, typename Delay>
requires(std::unsigned_integral<Id> && std::unsigned_integral<Size> &&
Expand Down
1 change: 0 additions & 1 deletion utils/plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,6 @@ def adjust_dataframe(_df):

df_std = pd.concat(df_array)
df_std = df_std.groupby(df_std.index).std()
df_std.to_csv("aaaaaaaaaaaaaaaaaaa.csv")
# df_std = df_std.interpolate(method='linear', limit_direction='both')
df_std = df_std.abs()

Expand Down