Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
24 changes: 12 additions & 12 deletions benchmark/Bench_Street.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@
}
}

static void BM_SpireStreet_AddAgent(benchmark::State& state) {
dsf::mobility::Street baseStreet(0,
static void BM_CoilStreet_AddAgent(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Street street(0,
{0, 1},
100.0,
13.8888888889,
Expand All @@ -233,16 +233,16 @@
{},
100,
1.0);
dsf::mobility::SpireStreet street(std::move(baseStreet));
street.enableCounter();
std::time_t spawnTime = 0;
for (auto _ : state) {
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
street.addAgent(std::move(agent));
}
}

static void BM_SpireStreet_MeanFlow(benchmark::State& state) {
dsf::mobility::Street baseStreet(0,
static void BM_CoilStreet_MeanFlow(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Street street(0,
{0, 1},
100.0,
13.8888888889,
Expand All @@ -251,7 +251,7 @@
{},
100,
1.0);
dsf::mobility::SpireStreet street(std::move(baseStreet));
street.enableCounter();
std::time_t spawnTime = 0;
for (int i = 0; i < 50; ++i) {
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
Expand All @@ -267,8 +267,8 @@
}
}

static void BM_SpireStreet_Dequeue(benchmark::State& state) {
dsf::mobility::Street baseStreet(0,
static void BM_CoilStreet_Dequeue(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Street street(0,
{0, 1},
100.0,
13.8888888889,
Expand All @@ -277,7 +277,7 @@
{},
100,
1.0);
dsf::mobility::SpireStreet street(std::move(baseStreet));
street.enableCounter();
std::time_t spawnTime = 0;
for (int i = 0; i < 50; ++i) {
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
Expand All @@ -304,8 +304,8 @@
BENCHMARK(BM_Street_SetLaneMapping);
BENCHMARK(BM_StochasticStreet_SetFlowRate);
BENCHMARK(BM_StochasticStreet_FlowRate);
BENCHMARK(BM_SpireStreet_AddAgent);
BENCHMARK(BM_SpireStreet_MeanFlow);
BENCHMARK(BM_SpireStreet_Dequeue);
BENCHMARK(BM_CoilStreet_AddAgent);
BENCHMARK(BM_CoilStreet_MeanFlow);
BENCHMARK(BM_CoilStreet_Dequeue);

BENCHMARK_MAIN();
35 changes: 8 additions & 27 deletions src/dsf/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,11 @@ PYBIND11_MODULE(dsf_cpp, m) {
pybind11::arg("cycleTime"),
pybind11::arg("counter"),
dsf::g_docstrings.at("dsf::mobility::RoadNetwork::makeTrafficLight").c_str())
.def(
"makeSpireStreet",
[](dsf::mobility::RoadNetwork& self, dsf::Id id) -> void {
self.makeSpireStreet(id);
},
pybind11::arg("id"),
dsf::g_docstrings.at("dsf::mobility::RoadNetwork::makeSpireStreet").c_str());
.def("addCoil",
&dsf::mobility::RoadNetwork::addCoil,
pybind11::arg("streetId"),
pybind11::arg("name") = std::string(),
dsf::g_docstrings.at("dsf::mobility::RoadNetwork::addCoil").c_str());

pybind11::class_<dsf::mobility::Itinerary>(mobility, "Itinerary")
.def(pybind11::init<dsf::Id, dsf::Id>(),
Expand Down Expand Up @@ -469,36 +467,19 @@ PYBIND11_MODULE(dsf_cpp, m) {
},
dsf::g_docstrings.at("dsf::mobility::RoadDynamics::normalizedTurnCounts")
.c_str())
.def(
"meanSpireInputFlow",
&dsf::mobility::FirstOrderDynamics::meanSpireInputFlow,
pybind11::arg("resetValue") = true,
dsf::g_docstrings.at("dsf::mobility::RoadDynamics::meanSpireInputFlow").c_str())
.def(
"meanSpireOutputFlow",
&dsf::mobility::FirstOrderDynamics::meanSpireOutputFlow,
pybind11::arg("resetValue") = true,
dsf::g_docstrings.at("dsf::mobility::RoadDynamics::meanSpireOutputFlow").c_str())
.def(
"saveStreetDensities",
&dsf::mobility::FirstOrderDynamics::saveStreetDensities,
pybind11::arg("filename"),
pybind11::arg("normalized") = true,
pybind11::arg("separator") = ';',
dsf::g_docstrings.at("dsf::mobility::RoadDynamics::saveStreetDensities").c_str())
.def("saveInputStreetCounts",
&dsf::mobility::FirstOrderDynamics::saveInputStreetCounts,
pybind11::arg("filename"),
pybind11::arg("reset") = false,
pybind11::arg("separator") = ';',
dsf::g_docstrings.at("dsf::mobility::RoadDynamics::saveInputStreetCounts")
.c_str())
.def("saveOutputStreetCounts",
&dsf::mobility::FirstOrderDynamics::saveOutputStreetCounts,
.def("saveCoilCounts",
&dsf::mobility::FirstOrderDynamics::saveCoilCounts,
pybind11::arg("filename"),
pybind11::arg("reset") = false,
pybind11::arg("separator") = ';',
dsf::g_docstrings.at("dsf::mobility::RoadDynamics::saveOutputStreetCounts")
dsf::g_docstrings.at("dsf::mobility::RoadDynamics::saveCoilCounts")
.c_str())
.def("saveTravelData",
&dsf::mobility::FirstOrderDynamics::saveTravelData,
Expand Down
133 changes: 12 additions & 121 deletions src/dsf/mobility/RoadDynamics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
tbb::concurrent_unordered_map<Id, std::unordered_map<Direction, double>>
m_queuesAtTrafficLights;
tbb::concurrent_vector<std::pair<double, double>> m_travelDTs;
std::time_t m_previousOptimizationTime, m_previousSpireTime;
std::time_t m_previousOptimizationTime;

private:
std::function<double(std::unique_ptr<Street> const&)> m_weightFunction;
Expand Down Expand Up @@ -320,16 +320,6 @@
/// @param above If true, the function returns the mean flow of the streets with a density above the threshold, otherwise below
/// @return Measurement<double> The mean flow of the streets and the standard deviation
Measurement<double> streetMeanFlow(double threshold, bool above) const;
/// @brief Get the mean spire input flow of the streets in \f$s^{-1}\f$
/// @param resetValue If true, the spire input/output flows are cleared after the computation
/// @return Measurement<double> The mean spire input flow of the streets and the standard deviation
/// @details The spire input flow is computed as the sum of counts over the product of the number of spires and the time delta
Measurement<double> meanSpireInputFlow(bool resetValue = true);
/// @brief Get the mean spire output flow of the streets in \f$s^{-1}\f$
/// @param resetValue If true, the spire output/input flows are cleared after the computation
/// @return Measurement<double> The mean spire output flow of the streets and the standard deviation
/// @details The spire output flow is computed as the sum of counts over the product of the number of spires and the time delta
Measurement<double> meanSpireOutputFlow(bool resetValue = true);

/// @brief Save the street densities in csv format
/// @param filename The name of the file (default is "{datetime}_{simulation_name}_street_densities.csv")
Expand All @@ -340,17 +330,10 @@
/// @brief Save the street input counts in csv format
/// @param filename The name of the file
/// @param reset If true, the input counts are cleared after the computation
Comment on lines 330 to 332
Copy link

Copilot AI Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation inconsistency: The documentation says "Save the street input counts" but the method name is saveCoilCounts. Consider updating the documentation to match the method name, e.g., "Save the coil counts from streets with coils".

Suggested change
/// @brief Save the street input counts in csv format
/// @param filename The name of the file
/// @param reset If true, the input counts are cleared after the computation
/// @brief Save the coil counts from streets with coils in csv format
/// @param filename The name of the file
/// @param reset If true, the coil counts are cleared after the computation

Copilot uses AI. Check for mistakes.
/// @details NOTE: counts are printed only if the street is a spire
void saveInputStreetCounts(const std::string& filename,
bool reset = false,
char const separator = ';');
/// @brief Save the street output counts in csv format
/// @param filename The name of the file
/// @param reset If true, the output counts are cleared after the computation
/// @details NOTE: counts are printed only if the street is a spire
void saveOutputStreetCounts(const std::string& filename,
bool reset = false,
char const separator = ';');
/// @details NOTE: counts are saved only if the street has a coil on it
void saveCoilCounts(const std::string& filename,
bool reset = false,
char const separator = ';');
/// @brief Save the travel data of the agents in csv format.
/// @details The file contains the following columns:
/// - time: the time of the simulation
Expand All @@ -359,7 +342,7 @@
/// - speeds: the travel speeds of the agents
/// @param filename The name of the file (default is "{datetime}_{simulation_name}_travel_data.csv")
/// @param reset If true, the travel speeds are cleared after the computation
void saveTravelData(std::string filename = std::string(), bool reset = false);

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 17.8 rule Note

MISRA 17.8 rule
/// @brief Save the main macroscopic observables in csv format
/// @param filename The name of the file (default is "{datetime}_{simulation_name}_macroscopic_observables.csv")
/// @param separator The separator character (default is ';')
Expand Down Expand Up @@ -389,12 +372,11 @@
: Dynamics<RoadNetwork>(graph, seed),
m_nAgents{0},
m_previousOptimizationTime{0},
m_previousSpireTime{0},
m_errorProbability{std::nullopt},
m_passageProbability{std::nullopt},
m_maxTravelDistance{std::numeric_limits<double>::max()},
m_maxTravelTime{std::numeric_limits<std::time_t>::max()},
m_bCacheEnabled{useCache},

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 17.8 rule Note

MISRA 17.8 rule
m_forcePriorities{false} {
this->setWeightFunction(weightFunction, weightTreshold);
if (m_bCacheEnabled) {
Expand Down Expand Up @@ -2120,44 +2102,6 @@
return Measurement<double>(flows);
}

template <typename delay_t>
requires(is_numeric_v<delay_t>)
Measurement<double> RoadDynamics<delay_t>::meanSpireInputFlow(bool resetValue) {
auto deltaTime{this->time_step() - m_previousSpireTime};
if (deltaTime == 0) {
return Measurement(0., 0.);
}
m_previousSpireTime = this->time_step();
std::vector<double> flows;
flows.reserve(this->graph().nEdges());
for (const auto& [streetId, pStreet] : this->graph().edges()) {
if (pStreet->isSpire()) {
auto& spire = dynamic_cast<SpireStreet&>(*pStreet);
flows.push_back(static_cast<double>(spire.inputCounts(resetValue)) / deltaTime);
}
}
return Measurement<double>(flows);
}

template <typename delay_t>
requires(is_numeric_v<delay_t>)
Measurement<double> RoadDynamics<delay_t>::meanSpireOutputFlow(bool resetValue) {
auto deltaTime{this->time_step() - m_previousSpireTime};
if (deltaTime == 0) {
return Measurement(0., 0.);
}
m_previousSpireTime = this->time_step();
std::vector<double> flows;
flows.reserve(this->graph().nEdges());
for (auto const& [streetId, pStreet] : this->graph().edges()) {
if (pStreet->isSpire()) {
auto& spire = dynamic_cast<SpireStreet&>(*pStreet);
flows.push_back(static_cast<double>(spire.outputCounts(resetValue)) / deltaTime);
}
}
return Measurement<double>(flows);
}

template <typename delay_t>
requires(is_numeric_v<delay_t>)
void RoadDynamics<delay_t>::saveStreetDensities(std::string filename,
Expand Down Expand Up @@ -2194,9 +2138,9 @@
}
template <typename delay_t>
requires(is_numeric_v<delay_t>)
void RoadDynamics<delay_t>::saveInputStreetCounts(const std::string& filename,
bool reset,
char const separator) {
void RoadDynamics<delay_t>::saveCoilCounts(const std::string& filename,
bool reset,
char const separator) {
bool bEmptyFile{false};
{
std::ifstream file(filename);
Expand All @@ -2209,70 +2153,17 @@
if (bEmptyFile) {
file << "datetime" << separator << "time_step";
for (auto const& [streetId, pStreet] : this->graph().edges()) {
if (!pStreet->isSpire()) {
continue;
}
if (pStreet->isStochastic()) {
file << separator << dynamic_cast<StochasticSpireStreet&>(*pStreet).code();
} else {
file << separator << dynamic_cast<SpireStreet&>(*pStreet).code();
if (pStreet->hasCoil()) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
file << separator << pStreet->counterName();
}
}
file << std::endl;
}
file << this->strDateTime() << separator << this->time_step();
for (auto const& [streetId, pStreet] : this->graph().edges()) {
int value{0};
if (pStreet->isSpire()) {
if (pStreet->isStochastic()) {
value = dynamic_cast<StochasticSpireStreet&>(*pStreet).inputCounts(reset);
} else {
value = dynamic_cast<SpireStreet&>(*pStreet).inputCounts(reset);
}
}
file << separator << value;
}
file << std::endl;
file.close();
}
template <typename delay_t>
requires(is_numeric_v<delay_t>)
void RoadDynamics<delay_t>::saveOutputStreetCounts(const std::string& filename,
bool reset,
char const separator) {
bool bEmptyFile{false};
{
std::ifstream file(filename);
bEmptyFile = file.peek() == std::ifstream::traits_type::eof();
}
std::ofstream file(filename, std::ios::app);
if (!file.is_open()) {
throw std::runtime_error("Error opening file \"" + filename + "\" for writing.");
}
if (bEmptyFile) {
file << "datetime" << separator << "time_step";
for (auto const& [streetId, pStreet] : this->graph().edges()) {
if (!pStreet->isSpire()) {
continue;
}
if (pStreet->isStochastic()) {
file << separator << dynamic_cast<StochasticSpireStreet&>(*pStreet).code();
} else {
file << separator << dynamic_cast<SpireStreet&>(*pStreet).code();
}
}
file << std::endl;
}
file << this->strDateTime() << separator << this->time_step();
for (auto const& [streetId, pStreet] : this->graph().edges()) {
int value{0};
if (pStreet->isSpire()) {
if (pStreet->isStochastic()) {
value = dynamic_cast<StochasticSpireStreet&>(*pStreet).outputCounts(reset);
} else {
value = dynamic_cast<SpireStreet&>(*pStreet).outputCounts(reset);
}
file << separator << value;
if (pStreet->hasCoil()) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
file << separator << pStreet->counts();
}
}
file << std::endl;
Expand Down
34 changes: 7 additions & 27 deletions src/dsf/mobility/RoadNetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,7 @@
[](unsigned char c) { return std::tolower(c); });
// Do not warn if the coilcode contains null or nan
if (!strCoilCode.empty() && strCoilCode != "null" && strCoilCode != "nan") {
try {
auto const coilCode{static_cast<Id>(std::stoul(strCoilCode))};
makeSpireStreet(streetId);
auto& coil = edge<SpireStreet>(streetId);
coil.setCode(coilCode);
} catch (...) {
spdlog::warn("Invalid coil code for {}", *edge(streetId));
}
addCoil(streetId, strCoilCode);
}
}
if (bHasCustomWeight) {
Expand Down Expand Up @@ -256,16 +249,9 @@
geometry));
// Check if there is coilcode property
if (!edge_properties["coilcode"].is_null() &&
edge_properties["coilcode"].is_uint64()) {
makeSpireStreet(edge_id);
auto& coil = edge<SpireStreet>(edge_id);
try {
coil.setCode(edge_properties["coilcode"].get_uint64());
} catch (...) {
spdlog::warn("Invalid coil code ({}) for {}",
edge_properties["coilcode"].get_string().value(),
*edge(edge_id));
}
edge_properties["coilcode"].is_string()) {
std::string strCoilCode{edge_properties["coilcode"].get_string().value()};
addCoil(edge_id, strCoilCode);
}
} else {
addStreet(Street(edge_id * 10,
Expand Down Expand Up @@ -294,7 +280,7 @@

Size RoadNetwork::nCoils() const {
return std::count_if(m_edges.cbegin(), m_edges.cend(), [](auto const& pair) {
return pair.second->isSpire();
return pair.second->hasCoil();

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
});
}

Expand Down Expand Up @@ -824,14 +810,8 @@
pStreet = std::unique_ptr<StochasticStreet>(
new StochasticStreet(std::move(*pStreet), flowRate));
}
void RoadNetwork::makeSpireStreet(Id streetId) {
auto& pStreet = edge(streetId);
if (pStreet->isStochastic()) {
pStreet = std::unique_ptr<StochasticSpireStreet>(new StochasticSpireStreet(
std::move(*pStreet), dynamic_cast<StochasticStreet&>(*pStreet).flowRate()));
return;
}
pStreet = std::unique_ptr<SpireStreet>(new SpireStreet(std::move(*pStreet)));
void RoadNetwork::addCoil(Id streetId, std::string const& name) {
edge(streetId)->enableCounter(name);
}

void RoadNetwork::addStreet(Street&& street) {
Expand Down
7 changes: 4 additions & 3 deletions src/dsf/mobility/RoadNetwork.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,11 @@ namespace dsf::mobility {
Roundabout& makeRoundabout(Id nodeId);

void makeStochasticStreet(Id streetId, double const flowRate);
/// @brief Convert an existing street into a spire street
/// @param streetId The id of the street to convert to a spire street
/// @brief Add a coil (dsf::Counter sensor) on the street with streetId
/// @param streetId The id of the street to add the coil to
/// @param name The coil name
/// @throws std::invalid_argument if the street does not exist
void makeSpireStreet(Id streetId);
void addCoil(Id streetId, std::string const& name = std::string());
/// @brief Convert an existing node into a station
/// @param nodeId The id of the node to convert to a station
/// @param managementTime The station's management time
Expand Down
Loading
Loading