diff --git a/MANIFEST.in b/MANIFEST.in index b2097ce97..5bc904f93 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,5 @@ include README.md include LICENSE -include requirements.txt include CMakeLists.txt include Doxyfile recursive-include src * diff --git a/benchmark/Bench_Dynamics.cpp b/benchmark/Bench_Dynamics.cpp index d9b9d0291..1c7db66e3 100644 --- a/benchmark/Bench_Dynamics.cpp +++ b/benchmark/Bench_Dynamics.cpp @@ -8,13 +8,13 @@ static const auto DATA_FOLDER = std::filesystem::path(__FILE__).parent_path().parent_path() / "test/data"; static void BM_FirstOrderDynamics_Empty_Evolve(benchmark::State& state) { - dsf::mobility::RoadNetwork network; - network.importEdges((DATA_FOLDER / "forlì_edges.csv").string()); - network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string()); - dsf::mobility::FirstOrderDynamics dynamics(network); - for (auto _ : state) { - dynamics.evolve(); - } + dsf::mobility::RoadNetwork network; + network.importEdges((DATA_FOLDER / "forlì_edges.csv").string()); + network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string()); + dsf::mobility::FirstOrderDynamics dynamics(network); + for (auto _ : state) { + dynamics.evolve(); + } } BENCHMARK(BM_FirstOrderDynamics_Empty_Evolve); diff --git a/benchmark/Bench_Network.cpp b/benchmark/Bench_Network.cpp index aeb9447e9..0b6cadd2b 100644 --- a/benchmark/Bench_Network.cpp +++ b/benchmark/Bench_Network.cpp @@ -36,26 +36,26 @@ static void BM_RoadNetwork_GeoJSONImport(benchmark::State& state) { } } static void BM_RoadNetwork_NodesLooping(benchmark::State& state) { - dsf::mobility::RoadNetwork network; - network.importEdges((DATA_FOLDER / "forlì_edges.csv").string()); - network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string()); - for (auto _ : state) { - for (auto const& [id, node] : network.nodes()) { - benchmark::DoNotOptimize(id); - benchmark::DoNotOptimize(node); - } + dsf::mobility::RoadNetwork network; + network.importEdges((DATA_FOLDER / "forlì_edges.csv").string()); + network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string()); + for (auto _ : state) { + for (auto const& [id, node] : network.nodes()) { + benchmark::DoNotOptimize(id); + benchmark::DoNotOptimize(node); } + } } static void BM_RoadNetwork_EdgesLooping(benchmark::State& state) { - dsf::mobility::RoadNetwork network; - network.importEdges((DATA_FOLDER / "forlì_edges.csv").string()); - network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string()); - for (auto _ : state) { - for (auto const& [id, edge] : network.edges()) { - benchmark::DoNotOptimize(id); - benchmark::DoNotOptimize(edge); - } + dsf::mobility::RoadNetwork network; + network.importEdges((DATA_FOLDER / "forlì_edges.csv").string()); + network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string()); + for (auto _ : state) { + for (auto const& [id, edge] : network.edges()) { + benchmark::DoNotOptimize(id); + benchmark::DoNotOptimize(edge); } + } } static void BM_RoadNetwork_ShortestPath(benchmark::State& state) { dsf::mobility::RoadNetwork network; @@ -63,7 +63,8 @@ static void BM_RoadNetwork_ShortestPath(benchmark::State& state) { network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string()); auto itNode = network.nodes().cbegin(); for (auto _ : state) { - auto paths = network.allPathsTo(itNode->first, [](auto const& pEdge) { return pEdge->length(); }); + auto paths = network.allPathsTo(itNode->first, + [](auto const& pEdge) { return pEdge->length(); }); ++itNode; } } diff --git a/benchmark/Bench_Street.cpp b/benchmark/Bench_Street.cpp index a79960339..e90a23042 100644 --- a/benchmark/Bench_Street.cpp +++ b/benchmark/Bench_Street.cpp @@ -5,15 +5,8 @@ static void BM_Street_Construction(benchmark::State& state) { for (auto _ : state) { - dsf::mobility::Street street(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - std::nullopt, - 1.0); + dsf::mobility::Street street( + 0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, std::nullopt, 1.0); benchmark::DoNotOptimize(street); } } @@ -36,15 +29,7 @@ static void BM_Street_AddAgent(benchmark::State& state) { } static void BM_Street_Enqueue(benchmark::State& state) { - dsf::mobility::Street street(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; for (int i = 0; i < 50; ++i) { auto agent = std::make_unique(spawnTime++, 1, 0); @@ -60,15 +45,7 @@ static void BM_Street_Enqueue(benchmark::State& state) { } static void BM_Street_Dequeue(benchmark::State& state) { - dsf::mobility::Street street(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; for (int i = 0; i < 50; ++i) { auto agent = std::make_unique(spawnTime++, 1, 0); @@ -85,20 +62,13 @@ static void BM_Street_Dequeue(benchmark::State& state) { } static void BM_Street_nAgents(benchmark::State& state) { - dsf::mobility::Street street(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; for (int i = 0; i < 50; ++i) { auto agent = std::make_unique(spawnTime++, 1, 0); street.addAgent(std::move(agent)); - if (i % 2 == 0) street.enqueue(0); + if (i % 2 == 0) + street.enqueue(0); } for (auto _ : state) { int n = street.nAgents(); @@ -107,20 +77,13 @@ static void BM_Street_nAgents(benchmark::State& state) { } static void BM_Street_Density(benchmark::State& state) { - dsf::mobility::Street street(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; for (int i = 0; i < 50; ++i) { auto agent = std::make_unique(spawnTime++, 1, 0); street.addAgent(std::move(agent)); - if (i % 2 == 0) street.enqueue(0); + if (i % 2 == 0) + street.enqueue(0); } for (auto _ : state) { double d = street.density(false); @@ -129,15 +92,7 @@ static void BM_Street_Density(benchmark::State& state) { } static void BM_Street_nMovingAgents(benchmark::State& state) { - dsf::mobility::Street street(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; for (int i = 0; i < 50; ++i) { auto agent = std::make_unique(spawnTime++, 1, 0); @@ -150,15 +105,7 @@ static void BM_Street_nMovingAgents(benchmark::State& state) { } static void BM_Street_nExitingAgents(benchmark::State& state) { - dsf::mobility::Street street(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; for (int i = 0; i < 50; ++i) { auto agent = std::make_unique(spawnTime++, 1, 0); @@ -172,34 +119,18 @@ static void BM_Street_nExitingAgents(benchmark::State& state) { } static void BM_Street_SetLaneMapping(benchmark::State& state) { - dsf::mobility::Street street(0, - {0, 1}, - 100.0, - 13.8888888889, - 3, - "test", - {}, - std::nullopt, - 1.0); + dsf::mobility::Street street( + 0, {0, 1}, 100.0, 13.8888888889, 3, "test", {}, std::nullopt, 1.0); std::vector laneMapping = { - dsf::Direction::RIGHTANDSTRAIGHT, - dsf::Direction::STRAIGHT, - dsf::Direction::LEFT}; + dsf::Direction::RIGHTANDSTRAIGHT, dsf::Direction::STRAIGHT, dsf::Direction::LEFT}; for (auto _ : state) { street.setLaneMapping(laneMapping); } } static void BM_StochasticStreet_SetFlowRate(benchmark::State& state) { - dsf::mobility::Street baseStreet(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - std::nullopt, - 1.0); + dsf::mobility::Street baseStreet( + 0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, std::nullopt, 1.0); dsf::mobility::StochasticStreet street(std::move(baseStreet), 0.5); for (auto _ : state) { street.setFlowRate(0.8); @@ -207,15 +138,8 @@ static void BM_StochasticStreet_SetFlowRate(benchmark::State& state) { } static void BM_StochasticStreet_FlowRate(benchmark::State& state) { - dsf::mobility::Street baseStreet(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - std::nullopt, - 1.0); + dsf::mobility::Street baseStreet( + 0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, std::nullopt, 1.0); dsf::mobility::StochasticStreet street(std::move(baseStreet), 0.5); for (auto _ : state) { double fr = street.flowRate(); @@ -223,17 +147,9 @@ static void BM_StochasticStreet_FlowRate(benchmark::State& state) { } } -static void BM_SpireStreet_AddAgent(benchmark::State& state) { - dsf::mobility::Street baseStreet(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); - dsf::mobility::SpireStreet street(std::move(baseStreet)); +static void BM_CoilStreet_AddAgent(benchmark::State& state) { + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); + street.enableCounter(); std::time_t spawnTime = 0; for (auto _ : state) { auto agent = std::make_unique(spawnTime++, 1, 0); @@ -241,17 +157,9 @@ static void BM_SpireStreet_AddAgent(benchmark::State& state) { } } -static void BM_SpireStreet_MeanFlow(benchmark::State& state) { - dsf::mobility::Street baseStreet(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); - dsf::mobility::SpireStreet street(std::move(baseStreet)); +static void BM_CoilStreet_MeanFlow(benchmark::State& state) { + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); + street.enableCounter(); std::time_t spawnTime = 0; for (int i = 0; i < 50; ++i) { auto agent = std::make_unique(spawnTime++, 1, 0); @@ -262,22 +170,14 @@ static void BM_SpireStreet_MeanFlow(benchmark::State& state) { } } for (auto _ : state) { - int flow = street.meanFlow(); + auto flow = street.counts(); benchmark::DoNotOptimize(flow); } } -static void BM_SpireStreet_Dequeue(benchmark::State& state) { - dsf::mobility::Street baseStreet(0, - {0, 1}, - 100.0, - 13.8888888889, - 2, - "test", - {}, - 100, - 1.0); - dsf::mobility::SpireStreet street(std::move(baseStreet)); +static void BM_CoilStreet_Dequeue(benchmark::State& state) { + dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); + street.enableCounter(); std::time_t spawnTime = 0; for (int i = 0; i < 50; ++i) { auto agent = std::make_unique(spawnTime++, 1, 0); @@ -304,8 +204,8 @@ BENCHMARK(BM_Street_nExitingAgents); 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(); diff --git a/examples/slow_charge_rb.cpp b/examples/slow_charge_rb.cpp index 5a7b14b32..15a394348 100644 --- a/examples/slow_charge_rb.cpp +++ b/examples/slow_charge_rb.cpp @@ -28,13 +28,11 @@ std::atomic bExitFlag{false}; // uncomment these lines to print densities, flows and speeds #define PRINT_DENSITIES // #define PRINT_FLOWS -#define PRINT_OUT_SPIRES // #define PRINT_SPEEDS using RoadNetwork = dsf::mobility::RoadNetwork; using Dynamics = dsf::mobility::FirstOrderDynamics; using Street = dsf::mobility::Street; -using SpireStreet = dsf::mobility::SpireStreet; using Roundabout = dsf::mobility::Roundabout; void printLoadingBar(int const i, int const n) { @@ -93,9 +91,9 @@ int main(int argc, char** argv) { for (std::size_t i{0}; i < graph.nNodes(); ++i) { graph.makeRoundabout(i); } - std::cout << "Making every street a spire...\n"; + std::cout << "Add a coil on every street...\n"; for (const auto& [streetId, pStreet] : graph.edges()) { - graph.makeSpireStreet(streetId); + graph.addCoil(streetId); } graph.adjustNodeCapacities(); std::cout << "Done." << std::endl; @@ -139,18 +137,6 @@ int main(int argc, char** argv) { } streetSpeed << '\n'; #endif -#ifdef PRINT_OUT_SPIRES - std::ofstream outSpires(OUT_FOLDER + "out_spires.csv"); - std::ofstream inSpires(OUT_FOLDER + "in_spires.csv"); - outSpires << "time"; - inSpires << "time"; - for (const auto& [streetId, pStreet] : dynamics.graph().edges()) { - outSpires << ';' << streetId; - inSpires << ';' << streetId; - } - outSpires << '\n'; - inSpires << '\n'; -#endif int deltaAgents{std::numeric_limits::max()}; int previousAgents{0}; @@ -190,17 +176,7 @@ int main(int argc, char** argv) { } if (dynamics.time_step() % 300 == 0) { -#ifdef PRINT_OUT_SPIRES - outSpires << dynamics.time_step(); - inSpires << dynamics.time_step(); - for (const auto& [streetId, pStreet] : dynamics.graph().edges()) { - auto& spire = dynamic_cast(*pStreet); - outSpires << ';' << spire.outputCounts(false); - inSpires << ';' << spire.inputCounts(false); - } - outSpires << std::endl; - inSpires << std::endl; -#endif + dynamics.saveCoilCounts(std::format("{}coil_counts.csv", OUT_FOLDER)); printLoadingBar(dynamics.time_step(), MAX_TIME); dynamics.saveMacroscopicObservables(std::format("{}data.csv", OUT_FOLDER)); } @@ -240,9 +216,6 @@ int main(int argc, char** argv) { #endif #ifdef PRINT_SPEEDS streetSpeed.close(); -#endif -#ifdef PRINT_OUT_SPIRES - outSpires.close(); #endif // std::cout << std::endl; // std::map turnNames{ diff --git a/examples/slow_charge_tl.cpp b/examples/slow_charge_tl.cpp index ab9db4b47..ab06b37c4 100644 --- a/examples/slow_charge_tl.cpp +++ b/examples/slow_charge_tl.cpp @@ -29,14 +29,12 @@ std::atomic bExitFlag{false}; // uncomment these lines to print densities, flows and speeds #define PRINT_DENSITIES // #define PRINT_FLOWS -#define PRINT_OUT_SPIRES // #define PRINT_SPEEDS // #define PRINT_TP using RoadNetwork = dsf::mobility::RoadNetwork; using Dynamics = dsf::mobility::FirstOrderDynamics; using Street = dsf::mobility::Street; -using SpireStreet = dsf::mobility::SpireStreet; using TrafficLight = dsf::mobility::TrafficLight; void printLoadingBar(int const i, int const n) { @@ -146,9 +144,9 @@ int main(int argc, char** argv) { graph.makeTrafficLight(nodeId, 120); } } - std::cout << "Making every street a spire...\n"; + std::cout << "Add a coil on every street...\n"; for (const auto& pair : graph.edges()) { - graph.makeSpireStreet(pair.first); + graph.addCoil(pair.first); } graph.adjustNodeCapacities(); std::cout << "Setting traffic light parameters..." << '\n'; @@ -197,18 +195,6 @@ int main(int argc, char** argv) { } streetSpeed << '\n'; #endif -#ifdef PRINT_OUT_SPIRES - std::ofstream outSpires(OUT_FOLDER + "out_spires.csv"); - std::ofstream inSpires(OUT_FOLDER + "in_spires.csv"); - outSpires << "time"; - inSpires << "time"; - for (const auto& pair : dynamics.graph().edges()) { - outSpires << ';' << pair.first; - inSpires << ';' << pair.first; - } - outSpires << '\n'; - inSpires << '\n'; -#endif #ifdef PRINT_TP std::ofstream outTP(OUT_FOLDER + "turn_probabilities.csv"); outTP << "time"; @@ -270,17 +256,7 @@ int main(int argc, char** argv) { if (dynamics.time_step() % 300 == 0) { // printLoadingBar(dynamics.time_step(), MAX_TIME); // deltaAgents = std::labs(dynamics.agents().size() - previousAgents); -#ifdef PRINT_OUT_SPIRES - outSpires << dynamics.time_step(); - inSpires << dynamics.time_step(); - for (const auto& pair : dynamics.graph().edges()) { - auto& spire = dynamic_cast(*pair.second); - outSpires << ';' << spire.outputCounts(false); - inSpires << ';' << spire.inputCounts(false); - } - outSpires << std::endl; - inSpires << std::endl; -#endif + dynamics.saveCoilCounts(std::format("{}coil_counts.csv", OUT_FOLDER)); dynamics.saveMacroscopicObservables(std::format("{}data.csv", OUT_FOLDER)); // deltas.push_back(deltaAgents); // previousAgents = dynamics.agents().size(); @@ -352,10 +328,6 @@ int main(int argc, char** argv) { #endif #ifdef PRINT_SPEEDS streetSpeed.close(); -#endif -#ifdef PRINT_OUT_SPIRES - outSpires.close(); - inSpires.close(); #endif // std::cout << std::endl; // std::map turnNames{ diff --git a/examples/stalingrado.cpp b/examples/stalingrado.cpp index f5418d4c6..e5d505805 100644 --- a/examples/stalingrado.cpp +++ b/examples/stalingrado.cpp @@ -73,8 +73,8 @@ int main() { graph.addStreets(s01, s12, s23, s34); graph.adjustNodeCapacities(); - graph.makeSpireStreet(19); - auto& spire = graph.edge(19); + graph.addCoil(19); + auto const& coil = graph.edge(19); // Create the dynamics FirstOrderDynamics dynamics{graph, false, 69, 0.6}; @@ -100,7 +100,8 @@ int main() { ++it; } if (progress % 300 == 0) { - ofs << progress << ';' << spire.outputCounts(true) << std::endl; + ofs << progress << ';' << coil->counts() << std::endl; + coil->resetCounter(); } dynamics.addAgents(*it, 4, 0); } diff --git a/src/dsf/bindings.cpp b/src/dsf/bindings.cpp index bebcbd587..4bd69777a 100644 --- a/src/dsf/bindings.cpp +++ b/src/dsf/bindings.cpp @@ -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_(mobility, "Itinerary") .def(pybind11::init(), @@ -469,16 +467,6 @@ 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, @@ -486,20 +474,12 @@ PYBIND11_MODULE(dsf_cpp, m) { pybind11::arg("normalized") = true, pybind11::arg("separator") = ';', dsf::g_docstrings.at("dsf::mobility::RoadDynamics::saveStreetDensities").c_str()) - .def("saveInputStreetCounts", - &dsf::mobility::FirstOrderDynamics::saveInputStreetCounts, + .def("saveCoilCounts", + &dsf::mobility::FirstOrderDynamics::saveCoilCounts, 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, - pybind11::arg("filename"), - pybind11::arg("reset") = false, - pybind11::arg("separator") = ';', - dsf::g_docstrings.at("dsf::mobility::RoadDynamics::saveOutputStreetCounts") - .c_str()) + dsf::g_docstrings.at("dsf::mobility::RoadDynamics::saveCoilCounts").c_str()) .def("saveTravelData", &dsf::mobility::FirstOrderDynamics::saveTravelData, pybind11::arg("filename"), diff --git a/src/dsf/dsf.hpp b/src/dsf/dsf.hpp index b4961843d..8989a53ce 100644 --- a/src/dsf/dsf.hpp +++ b/src/dsf/dsf.hpp @@ -5,8 +5,8 @@ #include static constexpr uint8_t DSF_VERSION_MAJOR = 4; -static constexpr uint8_t DSF_VERSION_MINOR = 3; -static constexpr uint8_t DSF_VERSION_PATCH = 1; +static constexpr uint8_t DSF_VERSION_MINOR = 4; +static constexpr uint8_t DSF_VERSION_PATCH = 0; static auto const DSF_VERSION = std::format("{}.{}.{}", DSF_VERSION_MAJOR, DSF_VERSION_MINOR, DSF_VERSION_PATCH); diff --git a/src/dsf/mobility/RoadDynamics.hpp b/src/dsf/mobility/RoadDynamics.hpp index 90ac099b0..2fd9c779f 100644 --- a/src/dsf/mobility/RoadDynamics.hpp +++ b/src/dsf/mobility/RoadDynamics.hpp @@ -56,7 +56,7 @@ namespace dsf::mobility { tbb::concurrent_unordered_map> m_queuesAtTrafficLights; tbb::concurrent_vector> m_travelDTs; - std::time_t m_previousOptimizationTime, m_previousSpireTime; + std::time_t m_previousOptimizationTime; private: std::function const&)> m_weightFunction; @@ -320,16 +320,6 @@ namespace dsf::mobility { /// @param above If true, the function returns the mean flow of the streets with a density above the threshold, otherwise below /// @return Measurement The mean flow of the streets and the standard deviation Measurement 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 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 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 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 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") @@ -340,17 +330,10 @@ namespace dsf::mobility { /// @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 - /// @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 @@ -389,7 +372,6 @@ namespace dsf::mobility { : Dynamics(graph, seed), m_nAgents{0}, m_previousOptimizationTime{0}, - m_previousSpireTime{0}, m_errorProbability{std::nullopt}, m_passageProbability{std::nullopt}, m_maxTravelDistance{std::numeric_limits::max()}, @@ -2120,44 +2102,6 @@ namespace dsf::mobility { return Measurement(flows); } - template - requires(is_numeric_v) - Measurement RoadDynamics::meanSpireInputFlow(bool resetValue) { - auto deltaTime{this->time_step() - m_previousSpireTime}; - if (deltaTime == 0) { - return Measurement(0., 0.); - } - m_previousSpireTime = this->time_step(); - std::vector flows; - flows.reserve(this->graph().nEdges()); - for (const auto& [streetId, pStreet] : this->graph().edges()) { - if (pStreet->isSpire()) { - auto& spire = dynamic_cast(*pStreet); - flows.push_back(static_cast(spire.inputCounts(resetValue)) / deltaTime); - } - } - return Measurement(flows); - } - - template - requires(is_numeric_v) - Measurement RoadDynamics::meanSpireOutputFlow(bool resetValue) { - auto deltaTime{this->time_step() - m_previousSpireTime}; - if (deltaTime == 0) { - return Measurement(0., 0.); - } - m_previousSpireTime = this->time_step(); - std::vector flows; - flows.reserve(this->graph().nEdges()); - for (auto const& [streetId, pStreet] : this->graph().edges()) { - if (pStreet->isSpire()) { - auto& spire = dynamic_cast(*pStreet); - flows.push_back(static_cast(spire.outputCounts(resetValue)) / deltaTime); - } - } - return Measurement(flows); - } - template requires(is_numeric_v) void RoadDynamics::saveStreetDensities(std::string filename, @@ -2194,9 +2138,9 @@ namespace dsf::mobility { } template requires(is_numeric_v) - void RoadDynamics::saveInputStreetCounts(const std::string& filename, - bool reset, - char const separator) { + void RoadDynamics::saveCoilCounts(const std::string& filename, + bool reset, + char const separator) { bool bEmptyFile{false}; { std::ifstream file(filename); @@ -2209,70 +2153,19 @@ namespace dsf::mobility { 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(*pStreet).code(); - } else { - file << separator << dynamic_cast(*pStreet).code(); + if (pStreet->hasCoil()) { + 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(*pStreet).inputCounts(reset); - } else { - value = dynamic_cast(*pStreet).inputCounts(reset); - } - } - file << separator << value; - } - file << std::endl; - file.close(); - } - template - requires(is_numeric_v) - void RoadDynamics::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(*pStreet).code(); - } else { - file << separator << dynamic_cast(*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(*pStreet).outputCounts(reset); - } else { - value = dynamic_cast(*pStreet).outputCounts(reset); + if (pStreet->hasCoil()) { + file << separator << pStreet->counts(); + if (reset) { + pStreet->resetCounter(); } - file << separator << value; } } file << std::endl; diff --git a/src/dsf/mobility/RoadNetwork.cpp b/src/dsf/mobility/RoadNetwork.cpp index c7332a56a..18edfb1c3 100644 --- a/src/dsf/mobility/RoadNetwork.cpp +++ b/src/dsf/mobility/RoadNetwork.cpp @@ -90,14 +90,7 @@ namespace dsf::mobility { [](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(std::stoul(strCoilCode))}; - makeSpireStreet(streetId); - auto& coil = edge(streetId); - coil.setCode(coilCode); - } catch (...) { - spdlog::warn("Invalid coil code for {}", *edge(streetId)); - } + addCoil(streetId, strCoilCode); } } if (bHasCustomWeight) { @@ -255,16 +248,17 @@ namespace dsf::mobility { name, geometry)); // Check if there is coilcode property - if (!edge_properties["coilcode"].is_null() && - edge_properties["coilcode"].is_uint64()) { - makeSpireStreet(edge_id); - auto& coil = edge(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)); + if (!edge_properties["coilcode"].is_null()) { + if (edge_properties["coilcode"].is_string()) { + std::string strCoilCode{edge_properties["coilcode"].get_string().value()}; + addCoil(edge_id, strCoilCode); + } else if (edge_properties["coilcode"].is_number()) { + std::string strCoilCode = + std::to_string(edge_properties["coilcode"].get_uint64()); + addCoil(edge_id, strCoilCode); + } else { + spdlog::warn("Invalid coilcode for edge {}, adding default", edge_id); + addCoil(edge_id); } } } else { @@ -294,7 +288,7 @@ namespace dsf::mobility { 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(); }); } @@ -824,14 +818,8 @@ namespace dsf::mobility { pStreet = std::unique_ptr( new StochasticStreet(std::move(*pStreet), flowRate)); } - void RoadNetwork::makeSpireStreet(Id streetId) { - auto& pStreet = edge(streetId); - if (pStreet->isStochastic()) { - pStreet = std::unique_ptr(new StochasticSpireStreet( - std::move(*pStreet), dynamic_cast(*pStreet).flowRate())); - return; - } - pStreet = std::unique_ptr(new SpireStreet(std::move(*pStreet))); + void RoadNetwork::addCoil(Id streetId, std::string const& name) { + edge(streetId)->enableCounter(name); } void RoadNetwork::addStreet(Street&& street) { diff --git a/src/dsf/mobility/RoadNetwork.hpp b/src/dsf/mobility/RoadNetwork.hpp index 4962de15d..d7d10f625 100644 --- a/src/dsf/mobility/RoadNetwork.hpp +++ b/src/dsf/mobility/RoadNetwork.hpp @@ -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 diff --git a/src/dsf/mobility/Sensors.cpp b/src/dsf/mobility/Sensors.cpp deleted file mode 100644 index a48bdd323..000000000 --- a/src/dsf/mobility/Sensors.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "Sensors.hpp" - -namespace dsf::mobility { - void Counter::setCode(Id const code) { m_code = code; } - void Counter::increaseInputCounter() { m_counters.first++; } - void Counter::increaseOutputCounter() { m_counters.second++; } - - Id Counter::code() const { return m_code; } - int Counter::inputCounts(bool reset) { - if (reset) { - int count{0}; - std::swap(count, m_counters.first); - return count; - } - return m_counters.first; - } - int Counter::outputCounts(bool reset) { - if (reset) { - int count{0}; - std::swap(count, m_counters.second); - return count; - } - return m_counters.second; - } -} // namespace dsf::mobility \ No newline at end of file diff --git a/src/dsf/mobility/Sensors.hpp b/src/dsf/mobility/Sensors.hpp index 7eda09491..30aeaaa1e 100644 --- a/src/dsf/mobility/Sensors.hpp +++ b/src/dsf/mobility/Sensors.hpp @@ -2,7 +2,7 @@ /// @brief Defines some sensor classes. /// /// @details This file contains the definition of some sensor classes. -/// The Counter class contains two counters to count input and output. +/// The Counter class is used to count events. #pragma once @@ -11,24 +11,25 @@ #include "../utility/Typedef.hpp" namespace dsf::mobility { - /// @brief The Counter class contains two counters to count input and output. + /// @brief The Counter class is used to count events. class Counter { protected: - Id m_code; - std::pair m_counters = {0, 0}; // First = in, Second = out + std::string m_name{"N/A"}; + std::size_t m_counter{0}; + public: - void setCode(Id const code); - /// @brief Increase the input counter by one - void increaseInputCounter(); - /// @brief Increase the output counter by one - void increaseOutputCounter(); + inline void setName(std::string const& name) { m_name = name; } + inline Counter& operator++() { + ++m_counter; + return *this; + } + inline void reset() { m_counter = 0; } - Id code() const; - /// @brief Get the number of input counts registered - /// @param reset If true, the counter is reset to 0. Default is true - int inputCounts(bool reset = true); - /// @brief Get the number of output counts registered - /// @param reset If true, the counter is reset to 0. Default is true - int outputCounts(bool reset = true); + /// @brief Get the name of the counter + /// @return The name of the counter + inline auto const& name() const noexcept { return m_name; } + /// @brief Get the value of the counter + /// @return The value of the counter + inline auto value() const noexcept { return m_counter; } }; } // namespace dsf::mobility \ No newline at end of file diff --git a/src/dsf/mobility/Street.cpp b/src/dsf/mobility/Street.cpp index c39cf0ea4..5f5dd1d83 100644 --- a/src/dsf/mobility/Street.cpp +++ b/src/dsf/mobility/Street.cpp @@ -79,6 +79,24 @@ namespace dsf::mobility { assert(index < m_exitQueues.size()); m_exitQueues[index] = std::move(queue); } + void Street::enableCounter(std::string name) { + if (m_counter.has_value()) { + throw std::runtime_error( + std::format("{} already has a counter named {}", *this, m_counter->name())); + } + if (name.empty()) { + name = std::format("Coil_{}", m_id); + } + m_counter.emplace(); + m_counter->setName(name); + } + void Street::resetCounter() { + if (!hasCoil()) { + throw std::runtime_error( + std::format("Cannot reset counter for {} which does not have a coil.", *this)); + } + m_counter->reset(); + } void Street::addAgent(std::unique_ptr pAgent) { assert(!isFull()); @@ -91,6 +109,9 @@ namespace dsf::mobility { m_exitQueues[queueId].push( std::move(const_cast&>(m_movingAgents.top()))); m_movingAgents.pop(); + if (m_counter.has_value()) { + ++(*m_counter); + } } std::unique_ptr Street::dequeue(size_t index) { assert(!m_exitQueues[index].empty()); @@ -180,28 +201,5 @@ namespace dsf::mobility { } m_flowRate = flowRate; } - double StochasticStreet::flowRate() const { return m_flowRate; } - - void SpireStreet::addAgent(std::unique_ptr pAgent) { - Street::addAgent(std::move(pAgent)); - increaseInputCounter(); - } - - int SpireStreet::meanFlow() { return inputCounts() - outputCounts(); } - std::unique_ptr SpireStreet::dequeue(size_t index) { - increaseOutputCounter(); - return Street::dequeue(index); - } - void StochasticSpireStreet::addAgent(std::unique_ptr pAgent) { - Street::addAgent(std::move(pAgent)); - increaseInputCounter(); - } - - int StochasticSpireStreet::meanFlow() { return inputCounts() - outputCounts(); } - - std::unique_ptr StochasticSpireStreet::dequeue(size_t index) { - increaseOutputCounter(); - return Street::dequeue(index); - } }; // namespace dsf::mobility diff --git a/src/dsf/mobility/Street.hpp b/src/dsf/mobility/Street.hpp index 462272e7f..0aeda272d 100644 --- a/src/dsf/mobility/Street.hpp +++ b/src/dsf/mobility/Street.hpp @@ -48,6 +48,7 @@ namespace dsf::mobility { AgentComparator> m_movingAgents; std::vector m_laneMapping; + std::optional m_counter; public: /// @brief Construct a new Street object @@ -82,6 +83,12 @@ namespace dsf::mobility { /// @param meanVehicleLength The mean vehicle length /// @throw std::invalid_argument If the mean vehicle length is negative static void setMeanVehicleLength(double meanVehicleLength); + /// @brief Enable a coil (dsf::Counter sensor) on the street + /// @param name The name of the counter (default is "Coil_") + void enableCounter(std::string name = std::string()); + /// @brief Reset the counter of the street + /// @throw std::runtime_error If the street does not have a coil + void resetCounter(); /// @brief Get the street's queue /// @return dsf::queue, The street's queue @@ -103,10 +110,22 @@ namespace dsf::mobility { /// @brief Check if the street is full /// @return bool, True if the street is full, false otherwise inline bool isFull() const final { return this->nAgents() == this->m_capacity; } - - dsf::priority_queue, - std::vector>, - AgentComparator>& + /// @brief Get the name of the counter + /// @return std::string The name of the counter + inline auto counterName() const { + return hasCoil() ? m_counter->name() : std::string("N/A"); + } + /// @brief Get the counts of the counter + /// @return std::size_t The counts of the counter + inline auto counts() const { + return hasCoil() ? m_counter->value() : static_cast(0); + } + /// @brief Get the street's moving agents priority queue + /// @return dsf::priority_queue, std::vector>, + /// AgentComparator>& The street's moving agents priority queue + inline dsf::priority_queue, + std::vector>, + AgentComparator>& movingAgents() { return m_movingAgents; } @@ -119,9 +138,11 @@ namespace dsf::mobility { /// @return double The number of agents on all queues for a given direction double nExitingAgents(Direction direction = Direction::ANY, bool normalizeOnNLanes = false) const final; - + /// @brief Get the street's lane mapping + /// @return std::vector The street's lane mapping inline std::vector const& laneMapping() const { return m_laneMapping; } - + /// @brief Add an agent to the street + /// @param pAgent The agent to add to the street virtual void addAgent(std::unique_ptr pAgent); /// @brief Add an agent to the street's queue /// @param agentId The id of the agent to add to the street's queue @@ -130,9 +151,11 @@ namespace dsf::mobility { /// @brief Remove an agent from the street's queue /// @return Id The id of the agent removed from the street's queue virtual std::unique_ptr 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; }; + /// @brief Check if the street has a coil (dsf::Counter sensor) on it + /// @return bool True if the street has a coil, false otherwise + constexpr bool hasCoil() const { return m_counter.has_value(); }; + /// @brief Check if the street is stochastic + /// @return bool True if the street is stochastic, false otherwise virtual bool isStochastic() const { return false; }; }; @@ -158,63 +181,17 @@ namespace dsf::mobility { double flowRate = 1., std::optional capacity = std::nullopt, double transportCapacity = 1.); - + /// @brief Set the flow rate of the street, i.e. the probability that an agent can exit the street + /// @param flowRate The flow rate to set void setFlowRate(double const flowRate); - double flowRate() const; - + /// @brief Get the flow rate of the street + /// @return double The flow rate of the street + inline auto flowRate() const { return m_flowRate; } + /// @brief Check if the street is stochastic + /// @return bool True if the street is stochastic, false otherwise constexpr bool isStochastic() const final { return true; }; }; - /// @brief The SpireStreet class represents a street which is able to count agent flows in both input and output. - /// @tparam Id The type of the street's id - /// @tparam Size The type of the street's capacity - class SpireStreet : public Street, public Counter { - public: - using Street::Street; - SpireStreet(Street&& street) : Street(std::move(street)) {} - SpireStreet(SpireStreet&&) = default; - SpireStreet(SpireStreet const&) = delete; - ~SpireStreet() = default; - - /// @brief Add an agent to the street's queue - /// @param agentId The id of the agent to add to the street's queue - /// @throw std::runtime_error If the street's queue is full - void addAgent(std::unique_ptr pAgent) final; - - /// @brief Get the mean flow of the street - /// @return int The flow of the street, i.e. the difference between input and output flows - /// @details Once the flow is retrieved, bothh the input and output flows are reset to 0. - /// 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 Id The id of the agent removed from the street's queue - std::unique_ptr dequeue(size_t index) final; - /// @brief Check if the street is a spire - /// @return bool True if the street is a spire, false otherwise - constexpr bool isSpire() const final { return true; }; - }; - - class StochasticSpireStreet : public StochasticStreet, public Counter { - public: - using StochasticStreet::StochasticStreet; - /// @brief Add an agent to the street's queue - /// @param agentId The id of the agent to add to the street's queue - /// @throw std::runtime_error If the street's queue is full - void addAgent(std::unique_ptr pAgent) final; - - /// @brief Get the mean flow of the street - /// @return int The flow of the street, i.e. the difference between input and output flows - /// @details Once the flow is retrieved, bothh the input and output flows are reset to 0. - /// 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 The id of the agent removed from the street's queue - std::unique_ptr dequeue(size_t index) final; - /// @brief Check if the street is a spire - /// @return bool True if the street is a spire, false otherwise - constexpr bool isSpire() const final { return true; }; - }; - }; // namespace dsf::mobility // Specialization of std::formatter for dsf::Street diff --git a/test/mobility/Test_dynamics.cpp b/test/mobility/Test_dynamics.cpp index 63c5ebfb5..1705fadef 100644 --- a/test/mobility/Test_dynamics.cpp +++ b/test/mobility/Test_dynamics.cpp @@ -86,10 +86,10 @@ TEST_CASE("FirstOrderDynamics") { CHECK(dynamics.graph().node(0)->isRoundabout()); } } - WHEN("We transform a street into a spire and create the dynamics") { - defaultNetwork.makeSpireStreet(8); + WHEN("We put a coil on the street and create the dynamics") { + defaultNetwork.addCoil(8); FirstOrderDynamics dynamics{defaultNetwork, false, 69}; - THEN("The street is a spire") { CHECK(dynamics.graph().edge(8)->isSpire()); } + THEN("The street has a coil") { CHECK(dynamics.graph().edge(8)->hasCoil()); } } } } @@ -1044,80 +1044,6 @@ TEST_CASE("FirstOrderDynamics") { } } } - SUBCASE("meanSpireFlow") { - GIVEN("A network with a spireStreet and a normal street") { - RoadNetwork graph2; - graph2.addNode(0); - graph2.addNode(1); - graph2.addNode(2); - graph2.addEdge(0, std::make_pair(0, 1), 10., 5.); - graph2.addEdge(1, std::make_pair(1, 2), 10., 10.); - FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; - dynamics.addItinerary(std::unique_ptr(new Itinerary(2, 2))); - dynamics.updatePaths(); - dynamics.addAgent(2, 0); - dynamics.initTurnCounts(); - WHEN("We evolve the dynamics") { - dynamics.evolve(false); - dynamics.evolve(false); - auto meanSpireFlow = dynamics.meanSpireInputFlow(); - THEN("The mean flow of the spire street is the same as the agent flow") { - CHECK_EQ(meanSpireFlow.mean, 0.5); - CHECK_EQ(meanSpireFlow.std, 0); - } - dynamics.evolve(false); - dynamics.evolve(false); - meanSpireFlow = dynamics.meanSpireOutputFlow(); - THEN("The mean flow of the spire street is the same as the agent flow") { - CHECK_EQ(meanSpireFlow.mean, 0.5); - CHECK_EQ(meanSpireFlow.std, 0); - } - THEN("Also the turn counts are correct") { - auto const normTurnCounts = dynamics.normalizedTurnCounts(); - CHECK_EQ(normTurnCounts.at(0).at(1), 1.); - auto const& turnCounts = dynamics.turnCounts(); - CHECK_EQ(turnCounts.at(0).at(1), 1); - dynamics.resetTurnCounts(); - for (auto const& [k1, map] : turnCounts) { - for (auto const& [k2, value] : map) { - CHECK_EQ(value, 0); - } - } - } - } - spdlog::set_level(spdlog::level::info); - } - } - SUBCASE("meanSpireFlow") { - GIVEN("A network with a spireStreet and a normal street") { - RoadNetwork graph2; - graph2.addNode(0); - graph2.addNode(1); - graph2.addNode(2); - graph2.addEdge(0, std::make_pair(0, 1), 10., 5.); - graph2.addEdge(1, std::make_pair(1, 2), 10., 10.); - FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; - dynamics.addItinerary(2, 2); - dynamics.updatePaths(); - dynamics.addAgent(2, 0); - WHEN("We evolve the dynamics") { - dynamics.evolve(false); - dynamics.evolve(false); - auto meanSpireFlow = dynamics.meanSpireInputFlow(); - THEN("The mean flow of the spire street is the same as the agent flow") { - CHECK_EQ(meanSpireFlow.mean, 0.5); - CHECK_EQ(meanSpireFlow.std, 0); - } - dynamics.evolve(false); - dynamics.evolve(false); - meanSpireFlow = dynamics.meanSpireOutputFlow(); - THEN("The mean flow of the spire street is the same as the agent flow") { - CHECK_EQ(meanSpireFlow.mean, 0.5); - CHECK_EQ(meanSpireFlow.std, 0); - } - } - } - } SUBCASE("Save functions with default filenames") { GIVEN("A dynamics object with some streets and agents") { Street s1{0, std::make_pair(0, 1), 30., 15.}; diff --git a/test/mobility/Test_graph.cpp b/test/mobility/Test_graph.cpp index ae5db52b2..302c8a451 100644 --- a/test/mobility/Test_graph.cpp +++ b/test/mobility/Test_graph.cpp @@ -268,13 +268,13 @@ TEST_CASE("RoadNetwork") { } } } - SUBCASE("make spire street") { + SUBCASE("add coil on a street") { GIVEN("A graph object with two nodes and one street") { RoadNetwork graph{}; graph.addEdge(Street{0, std::make_pair(0, 1)}); - WHEN("We make the street a spire street") { - graph.makeSpireStreet(0); - THEN("The street is a spire street") { CHECK(graph.edge(0)->isSpire()); } + WHEN("We add a coil to the street") { + graph.addCoil(0); + THEN("The street has a coil") { CHECK(graph.edge(0)->hasCoil()); } } } } diff --git a/test/mobility/Test_street.cpp b/test/mobility/Test_street.cpp index 7e5fdc5af..d3a0d24d8 100644 --- a/test/mobility/Test_street.cpp +++ b/test/mobility/Test_street.cpp @@ -16,7 +16,6 @@ using Agent = dsf::mobility::Agent; using Intersection = dsf::mobility::Intersection; using Street = dsf::mobility::Street; using Road = dsf::mobility::Road; -using SpireStreet = dsf::mobility::SpireStreet; TEST_CASE("Street") { Road::setMeanVehicleLength(1.); @@ -182,86 +181,19 @@ TEST_CASE("Street") { } } -TEST_CASE("SpireStreet") { - SUBCASE("Input flow") { - GIVEN("A spire street") { - SpireStreet street{1, std::make_pair(0, 1), 3.5}; - WHEN("An agent is enqueued") { +TEST_CASE("Street with a coil") { + SUBCASE("Counts") { + GIVEN("A street with a counter") { + Street street{1, std::make_pair(0, 1), 3.5}; + street.enableCounter(); + CHECK_EQ(street.counterName(), "Coil_1"); + WHEN("An agent is added") { street.addAgent(std::make_unique(0, 1)); - THEN("The input flow is one") { CHECK_EQ(street.inputCounts(), 1); } + THEN("The input flow is zero") { CHECK_EQ(street.counts(), 0); } street.enqueue(0); - THEN("The density is updated") { - CHECK_EQ(doctest::Approx(street.density()), 0.285714); - } - THEN("Output flow is zero") { CHECK_EQ(street.outputCounts(), 0); } - THEN("Mean flow is one") { CHECK_EQ(street.meanFlow(), 1); } - } - WHEN("Three agents are enqueued") { - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - THEN("The density is updated") { - CHECK_EQ(doctest::Approx(street.density()), 0.857143); - } - THEN("Input flow is three") { CHECK_EQ(street.inputCounts(), 3); } - THEN("Output flow is zero") { CHECK_EQ(street.outputCounts(), 0); } - THEN("Mean flow is three") { CHECK_EQ(street.meanFlow(), 3); } - } - WHEN("An agent is dequeued") { - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.dequeue(0); - THEN("The density is updated") { CHECK_EQ(doctest::Approx(street.density()), 0); } - THEN("Input flow is one") { CHECK_EQ(street.inputCounts(), 1); } - THEN("Output flow is one") { CHECK_EQ(street.outputCounts(), 1); } - THEN("Mean flow is zero") { CHECK_EQ(street.meanFlow(), 0); } - } - WHEN("Three agents are dequeued") { - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.dequeue(0); - street.dequeue(0); - street.dequeue(0); - THEN("The density is updated") { CHECK_EQ(doctest::Approx(street.density()), 0); } - THEN("Input flow is three") { CHECK_EQ(street.inputCounts(), 3); } - THEN("Output flow is three") { CHECK_EQ(street.outputCounts(), 3); } - THEN("Mean flow is zero") { CHECK_EQ(street.meanFlow(), 0); } - } - WHEN("Input is greater than output") { - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.dequeue(0); - street.dequeue(0); - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - THEN("The density is updated") { - CHECK_EQ(doctest::Approx(street.density()), 0.285714); - } - THEN("Mean flow is one") { CHECK_EQ(street.meanFlow(), 1); } - } - WHEN("Output is greater than input") { - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.meanFlow(); - street.addAgent(std::make_unique(0, 1)); - street.enqueue(0); - street.dequeue(0); - street.dequeue(0); - THEN("The density is updated") { - CHECK_EQ(doctest::Approx(street.density()), 0.285714); - } - THEN("Mean flow is minus one") { CHECK_EQ(street.meanFlow(), -1); } + THEN("The input flow is one once enqueued") { CHECK_EQ(street.counts(), 1); } + street.resetCounter(); + THEN("The counts are 0 after reset") { CHECK_EQ(street.counts(), 0); } } } }