Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions src/dsm/headers/RoadNetwork.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ namespace dsm {
/// @brief Adjust the nodes' transport capacity
/// @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.
void adjustNodeCapacities();
/// @brief Initialize the traffic lights with random parameters
/// @details Traffic Lights with no parameters set are initialized with random parameters.
/// Street priorities are assigned considering the number of lanes and the speed limit.
/// Traffic Lights with an input degree lower than 3 are converted to standard intersections.
void initTrafficLights();

/// @brief Import the graph's adjacency matrix from a file.
/// If the file is not of a supported format, it will read the file as a matrix with the first two elements being
Expand Down
156 changes: 154 additions & 2 deletions src/dsm/sources/RoadNetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,162 @@
}
}

void RoadNetwork::initTrafficLights() {
for (auto const& [id, pNode] : m_nodes) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
if (!pNode->isTrafficLight()) {
continue;
}
auto& tl = dynamic_cast<TrafficLight&>(*pNode);
if (!tl.streetPriorities().empty() || !tl.cycles().empty()) {
continue;

Check warning on line 98 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L98

Added line #L98 was not covered by tests
}
auto const& inNeighbours = m_adjacencyMatrix.getCol(id);
std::map<Id, int, std::greater<int>> capacities;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
std::unordered_map<Id, double> streetAngles;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
std::unordered_map<Id, double> maxSpeeds;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
std::unordered_map<Id, int> nLanes;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
double higherSpeed{0.}, lowerSpeed{std::numeric_limits<double>::max()};

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
int higherNLanes{0}, lowerNLanes{std::numeric_limits<int>::max()};

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
if (inNeighbours.size() < 3) {
Logger::warning(std::format(
"Not enough in neighbours {} for Traffic Light {}", inNeighbours.size(), id));

Check warning on line 109 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L108-L109

Added lines #L108 - L109 were not covered by tests
// Replace with a normal intersection
auto const& coordinates{pNode->coords()};

Check warning on line 111 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L111

Added line #L111 was not covered by tests
if (coordinates.has_value()) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
m_nodes[id] = std::make_unique<Intersection>(id, *coordinates);

Check warning on line 113 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L113

Added line #L113 was not covered by tests
} else {
m_nodes[id] = std::make_unique<Intersection>(id);

Check warning on line 115 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L115

Added line #L115 was not covered by tests
}
continue;
}

Check warning on line 118 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L117-L118

Added lines #L117 - L118 were not covered by tests
for (auto const& inId : inNeighbours) {
auto const streetId{inId * nNodes() + id};
auto const& pStreet{m_edges.at(streetId)};

double const speed{pStreet->maxSpeed()};
int const nLan{pStreet->nLanes()};
auto const cap{pStreet->capacity()};
Logger::debug(std::format("Street {} with capacity {}", streetId, cap));
capacities.emplace(streetId, cap);
streetAngles.emplace(streetId, pStreet->angle());

maxSpeeds.emplace(streetId, speed);
nLanes.emplace(streetId, nLan);

higherSpeed = std::max(higherSpeed, speed);
lowerSpeed = std::min(lowerSpeed, speed);

higherNLanes = std::max(higherNLanes, nLan);
lowerNLanes = std::min(lowerNLanes, nLan);
}
if (higherSpeed != lowerSpeed) {
// Assign streets with higher speed to priority
for (auto const& [sid, speed] : maxSpeeds) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
if (speed == higherSpeed) {
tl.addStreetPriority(sid);

Check warning on line 143 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L143

Added line #L143 was not covered by tests
}
}
// continue;
} else if (higherNLanes != lowerNLanes) {
for (auto const& [sid, nLan] : nLanes) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
if (nLan == higherNLanes) {
tl.addStreetPriority(sid);
}
}
// continue;
}

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.7 rule Note

MISRA 15.7 rule
// Set first two elements of capacities to street priorities
// auto it{capacities.begin()};
// tl.addStreetPriority(it->first);
// ++it;
// if (it != capacities.end()) {
// tl.addStreetPriority(it->first);
// continue;
// }
// Id firstStreetId{streetAngles.begin()->first};
// tl.addStreetPriority(firstStreetId);
// for (auto const& [streetId, angle] : streetAngles) {
// if (streetId == firstStreetId) {
// continue;
// }
// if (angle == streetAngles.begin()->second) {
// tl.addStreetPriority(streetId);
// }
// }
// if (tl.streetPriorities().size() > 1) {
// continue;
// }
if (tl.streetPriorities().empty()) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
Logger::warning(std::format("Failed to auto-init Traffic Light {}", id));
continue;

Check warning on line 178 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L177-L178

Added lines #L177 - L178 were not covered by tests
}

// Assign cycles
std::pair<Delay, Delay> greenTimes;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
{
auto capPriority{0.}, capNoPriority{0.};

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
std::unordered_map<Id, double> normCapacities;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
auto sum{0.};
for (auto const& [streetId, cap] : capacities) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
sum += cap;
}
for (auto const& [streetId, cap] : capacities) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
normCapacities.emplace(streetId, cap / sum);
}
for (auto const& [streetId, normCap] : normCapacities) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
if (tl.streetPriorities().contains(streetId)) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
capPriority += normCap;
} else {
capNoPriority += normCap;
}
}
Logger::debug(
std::format("Capacities for Traffic Light {}: priority {} no priority {}",
id,
capPriority,
capNoPriority));
greenTimes = std::make_pair(static_cast<Delay>(capPriority * tl.cycleTime()),
static_cast<Delay>(capNoPriority * tl.cycleTime()));
}
std::for_each(inNeighbours.begin(), inNeighbours.end(), [&](Id const inId) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 13.1 rule Note

MISRA 13.1 rule
auto const streetId{inId * nNodes() + id};
auto const nLane{nLanes.at(streetId)};
Delay greenTime{greenTimes.first};
Delay phase{0};
if (!tl.streetPriorities().contains(streetId)) {
phase = greenTime;
greenTime = greenTimes.second;
}
Logger::debug(
std::format("Setting cycle for street {} with green time {} and phase {}",
streetId,
greenTime,
phase));
switch (nLane) {
case 3:
tl.setCycle(streetId,
dsm::Direction::RIGHTANDSTRAIGHT,
TrafficLightCycle{static_cast<Delay>(greenTime * 2. / 3), phase});
tl.setCycle(
streetId,
dsm::Direction::LEFT,
TrafficLightCycle{

Check warning on line 230 in src/dsm/sources/RoadNetwork.cpp

View check run for this annotation

Codecov / codecov/patch

src/dsm/sources/RoadNetwork.cpp#L230

Added line #L230 was not covered by tests
static_cast<Delay>(greenTime / 3.),
static_cast<Delay>(phase + static_cast<Delay>(greenTime * 2. / 3))});
break;
default:
tl.setCycle(
streetId, dsm::Direction::ANY, TrafficLightCycle{greenTime, phase});
break;
}
});
}
}

void RoadNetwork::buildAdj() {
// find max values in streets node pairs
m_maxAgentCapacity = 0;
for (const auto& [streetId, pStreet] : m_edges) {
for (auto const& [streetId, pStreet] : m_edges) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
m_maxAgentCapacity += pStreet->capacity();
if (pStreet->geometry().empty()) {
std::vector<std::pair<double, double>> coords;
Expand Down Expand Up @@ -319,7 +471,7 @@
std::getline(iss, highway, ';');
if (highway.find("traffic_signals") != std::string::npos) {
addNode<TrafficLight>(
nodeIndex, 60, std::make_pair(std::stod(lat), std::stod(lon)));
nodeIndex, 120, std::make_pair(std::stod(lat), std::stod(lon)));
} else if (highway.find("roundabout") != std::string::npos) {
addNode<Roundabout>(nodeIndex, std::make_pair(std::stod(lat), std::stod(lon)));
} else {
Expand Down
4 changes: 1 addition & 3 deletions test/Test_dynamics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,12 +604,10 @@ TEST_CASE("FirstOrderDynamics") {
RoadNetwork graph2;
graph2.addNode<TrafficLight>(1, 4);
graph2.addStreets(s1, s2, s3, s4);
graph2.buildAdj();
auto& tl = graph2.node<TrafficLight>(1);
tl.setCycle(1, dsm::Direction::RIGHT, {2, 0});
tl.setCycle(7, dsm::Direction::RIGHT, {2, 0});
tl.setCycle(16, dsm::Direction::RIGHT, {2, 2});
tl.setCycle(9, dsm::Direction::RIGHT, {2, 2});
graph2.buildAdj();
FirstOrderDynamics dynamics{
graph2, false, 69, 0., dsm::weight_functions::streetLength, 1.};
dynamics.addItinerary(2, 2);
Expand Down
46 changes: 46 additions & 0 deletions test/Test_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,52 @@
CHECK_FALSE(graph.street(1, 0));
}
SUBCASE("make trafficlight") {
GIVEN("A graph with a traffic light with no parameters") {
Street s1{1, std::make_pair(0, 1), 30., 15., 3};

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note test

MISRA 12.3 rule
Street s2{11, std::make_pair(2, 1), 30., 15., 3};

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note test

MISRA 12.3 rule
Street s3{16, std::make_pair(3, 1), 30., 15., 1};

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note test

MISRA 12.3 rule
Street s4{21, std::make_pair(4, 1), 30., 15., 2};

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note test

MISRA 12.3 rule
RoadNetwork graph2;
graph2.addNode<dsm::TrafficLight>(1, 120);
graph2.addStreets(s1, s2, s3, s4);
for (auto const& pair : graph2.edges()) {
pair.second->setCapacity(2 * pair.second->nLanes());
}
graph2.buildAdj();
WHEN("We auto-init Traffic Lights") {
graph2.initTrafficLights();
THEN("Parameters are correctly set") {
auto& tl{graph2.node<dsm::TrafficLight>(1)};
CHECK_EQ(tl.cycleTime(), 120);
auto const& cycles{tl.cycles()};
CHECK_EQ(cycles.size(), 4);
CHECK_EQ(cycles.at(1)[0].greenTime(), 53);
CHECK_EQ(cycles.at(1)[1].greenTime(), 53);
CHECK_EQ(cycles.at(1)[2].greenTime(), 26);
CHECK_EQ(cycles.at(1)[0].phase(), 0);
CHECK_EQ(cycles.at(1)[1].phase(), 0);
CHECK_EQ(cycles.at(1)[2].phase(), 53);
CHECK_EQ(cycles.at(11)[0].greenTime(), 53);
CHECK_EQ(cycles.at(11)[1].greenTime(), 53);
CHECK_EQ(cycles.at(11)[2].greenTime(), 26);
CHECK_EQ(cycles.at(11)[0].phase(), 0);
CHECK_EQ(cycles.at(11)[1].phase(), 0);
CHECK_EQ(cycles.at(11)[2].phase(), 53);
CHECK_EQ(cycles.at(16)[0].greenTime(), 40);
CHECK_EQ(cycles.at(16)[1].greenTime(), 40);
CHECK_EQ(cycles.at(16)[2].greenTime(), 40);
CHECK_EQ(cycles.at(16)[0].phase(), 80);
CHECK_EQ(cycles.at(16)[1].phase(), 80);
CHECK_EQ(cycles.at(16)[2].phase(), 80);
CHECK_EQ(cycles.at(21)[0].greenTime(), 40);
CHECK_EQ(cycles.at(21)[1].greenTime(), 40);
CHECK_EQ(cycles.at(21)[2].greenTime(), 40);
CHECK_EQ(cycles.at(21)[0].phase(), 80);
CHECK_EQ(cycles.at(21)[1].phase(), 80);
CHECK_EQ(cycles.at(21)[2].phase(), 80);
}
}
}
GIVEN("A graph object with two nodes and one street") {
RoadNetwork graph{};
graph.addStreet(Street{1, std::make_pair(0, 1)});
Expand Down
Loading