Skip to content

Commit 1bd2a0f

Browse files
GrufoonyCopilot
andauthored
Add auto-naming for main saving functions (#362)
* Add auto-naming for main saving functions * Update src/dsf/mobility/RoadDynamics.hpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix * Bump version --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 30e1446 commit 1bd2a0f

File tree

7 files changed

+203
-91
lines changed

7 files changed

+203
-91
lines changed

examples/slow_charge_rb.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ int main(int argc, char** argv) {
102102

103103
std::cout << "Creating dynamics...\n";
104104

105-
Dynamics dynamics{graph, true, SEED, 0.6};
105+
Dynamics dynamics{graph, false, SEED, 0.6};
106106

107107
{
108108
std::vector<dsf::Id> destinationNodes;
@@ -123,7 +123,6 @@ int main(int argc, char** argv) {
123123

124124
std::cout << "Done." << std::endl;
125125
std::cout << "Running simulation...\n";
126-
127126
#ifdef PRINT_FLOWS
128127
std::ofstream streetFlow(OUT_FOLDER + "flows.csv");
129128
streetFlow << "time";

examples/slow_charge_tl.cpp

Lines changed: 16 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <dsf/dsf.hpp>
22
#include <array>
3+
#include <chrono>
34
#include <cmath>
45
#include <cstdint>
56
#include <fstream>
@@ -45,13 +46,13 @@ void printLoadingBar(int const i, int const n) {
4546
}
4647

4748
int main(int argc, char** argv) {
49+
auto const start = std::chrono::high_resolution_clock::now();
4850
if (argc != 6) {
4951
std::cerr
5052
<< "Usage: " << argv[0]
5153
<< " <SEED> <ERROR_PROBABILITY> <OUT_FOLDER_BASE> <OPTIMIZE> <INIT_NAGENTS>\n";
5254
return 1;
5355
}
54-
spdlog::set_level(spdlog::level::err); // turn off spdlog logging
5556

5657
const int SEED = std::stoi(argv[1]); // seed for random number generator
5758
const double ERROR_PROBABILITY{std::stod(argv[2])};
@@ -60,12 +61,6 @@ int main(int argc, char** argv) {
6061
BASE_OUT_FOLDER += OPTIMIZE ? "_op/" : "/";
6162
auto nAgents{std::stoul(argv[5])};
6263

63-
std::string OUT_FOLDER{std::format("{}output_sctl_{}_{}/",
64-
BASE_OUT_FOLDER,
65-
ERROR_PROBABILITY,
66-
std::to_string(SEED))}; // output folder
67-
constexpr auto MAX_TIME{static_cast<unsigned int>(5e5)}; // maximum time of simulation
68-
6964
std::cout << "-------------------------------------------------\n";
7065
std::cout << "Input parameters:\n";
7166
std::cout << "Seed: " << SEED << '\n';
@@ -76,7 +71,11 @@ int main(int argc, char** argv) {
7671
std::cout << "Traffic light optimization ENABLED.\n";
7772
}
7873
std::cout << "-------------------------------------------------\n";
79-
74+
const std::string OUT_FOLDER{std::format("{}output_sctl_{}_{}/",
75+
BASE_OUT_FOLDER,
76+
ERROR_PROBABILITY,
77+
std::to_string(SEED))}; // output folder
78+
constexpr auto MAX_TIME{static_cast<unsigned int>(5e5)}; // maximum time of simulation
8079
// Clear output folder or create it if it doesn't exist
8180
if (!fs::exists(BASE_OUT_FOLDER)) {
8281
fs::create_directory(BASE_OUT_FOLDER);
@@ -151,81 +150,25 @@ int main(int argc, char** argv) {
151150
for (const auto& pair : graph.edges()) {
152151
graph.makeSpireStreet(pair.first);
153152
}
154-
// create gaussian random number generator
155-
std::random_device rd;
156-
std::mt19937 gen(rd());
157-
gen.seed(64313);
158-
std::normal_distribution d(60., 10.);
159-
std::array<uint8_t, 2> sda{0, 0};
160-
auto random = [&d, &gen]() { return std::round(d(gen)); };
161-
std::cout << "Adjusting node capacities...\n";
162153
graph.adjustNodeCapacities();
163154
std::cout << "Setting traffic light parameters..." << '\n';
164-
for (const auto& [nodeId, pNode] : graph.nodes()) {
165-
if (!pNode->isTrafficLight()) {
166-
continue;
167-
}
168-
auto& tl = dynamic_cast<TrafficLight&>(*pNode);
169-
double value = -1.;
170-
while (value < 0.) {
171-
value = random();
172-
}
173-
const auto& ingoingEdges = pNode->ingoingEdges();
174-
if (ingoingEdges.empty()) {
175-
spdlog::error("Node {} has no ingoing edges.", nodeId);
176-
continue;
177-
}
178-
std::set<dsf::Id> streets;
179-
if (!pNode->geometry().has_value()) {
180-
std::cerr << "Warning: Node " << nodeId << " has no geometry, skipping.\n";
181-
continue;
182-
}
183-
const auto& refLat = (*pNode->geometry()).y();
184-
for (const auto& inEdgeId : ingoingEdges) {
185-
auto const& pEdge{graph.edge(inEdgeId)};
186-
const auto& edgeGeometry = pEdge->geometry();
187-
if (edgeGeometry.empty()) {
188-
std::cerr << "Warning: Edge " << inEdgeId << " has empty geometry, skipping.\n";
189-
continue;
190-
}
191-
const auto& lat = edgeGeometry.front().y();
192-
// std::cout << "Lat: " << lat << " RefLat: " << refLat << '\n';
193-
if (std::abs(lat - refLat) < std::numeric_limits<double>::epsilon()) {
194-
streets.emplace(inEdgeId);
195-
}
196-
}
197-
for (auto const& streetId : streets) {
198-
tl.setCycle(streetId, dsf::Direction::ANY, {static_cast<dsf::Delay>(value), 0});
199-
}
200-
for (const auto& streetId : ingoingEdges) {
201-
if (!streets.contains(streetId)) {
202-
tl.setComplementaryCycle(streetId, *streets.begin());
203-
}
204-
}
205-
++sda[streets.size() - 1];
206-
// std::cout << "Node id: " << nodeId << " has " << streets.size()
207-
// << "streets.\n";
208-
}
209-
std::cout << "Nodes with one street: " << static_cast<int>(sda[0]) << '\n';
210-
std::cout << "Nodes with two streets: " << static_cast<int>(sda[1]) << '\n';
155+
graph.initTrafficLights();
211156
std::cout << "Done." << std::endl;
212157

213158
std::cout << "Creating dynamics...\n";
214159

215-
Dynamics dynamics{graph, true, SEED, 0.6};
216-
std::size_t n{0};
160+
Dynamics dynamics{graph, false, SEED, 0.6};
217161
{
218162
std::vector<dsf::Id> destinationNodes;
219163
for (auto const& [nodeId, pNode] : dynamics.graph().nodes()) {
220164
if (pNode->outgoingEdges().size() < 4) {
221-
destinationNodes.push_back(pNode->id());
222-
++n;
165+
destinationNodes.push_back(nodeId);
223166
}
224167
}
225168
dynamics.setDestinationNodes(destinationNodes);
169+
std::cout << "Number of exits: " << destinationNodes.size() << '\n';
226170
}
227171
dynamics.updatePaths();
228-
std::cout << "Number of exits: " << n << '\n';
229172

230173
dynamics.setErrorProbability(ERROR_PROBABILITY);
231174
// dynamics.setMaxFlowPercentage(0.69);
@@ -429,6 +372,10 @@ int main(int argc, char** argv) {
429372
#ifdef __APPLE__
430373
t.join();
431374
#endif
432-
375+
std::cout << "Total elapsed time: "
376+
<< std::chrono::duration_cast<std::chrono::milliseconds>(
377+
std::chrono::high_resolution_clock::now() - start)
378+
.count()
379+
<< " milliseconds\n";
433380
return 0;
434381
}

src/dsf/base/Dynamics.hpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,34 +69,64 @@ namespace dsf {
6969
class Dynamics {
7070
private:
7171
network_t m_graph;
72+
std::string m_name;
73+
std::time_t m_timeInit, m_timeStep;
7274

7375
protected:
7476
tbb::task_arena m_taskArena;
75-
std::time_t m_timeInit, m_timeStep;
7677
std::mt19937_64 m_generator;
7778

7879
protected:
79-
void m_evolve() { ++m_timeStep; };
80+
inline void m_evolve() { ++m_timeStep; };
81+
82+
/// @brief Get a safe date-time string for filenames (YYYYMMDD_HHMMSS)
83+
/// @return std::string, The safe date-time string
84+
inline auto m_safeDateTime() const {
85+
#ifdef __APPLE__
86+
std::time_t const t = time();
87+
std::ostringstream oss;
88+
oss << std::put_time(std::localtime(&t), "%Y%m%d_%H%M%S");
89+
return oss.str();
90+
#else
91+
return std::format(
92+
"{:%Y%m%d_%H%M%S}",
93+
std::chrono::floor<std::chrono::seconds>(std::chrono::current_zone()->to_local(
94+
std::chrono::system_clock::from_time_t(time()))));
95+
#endif
96+
}
97+
/// @brief Get a safe name string for filenames (spaces replaced by underscores)
98+
/// @return std::string, The safe name string
99+
inline auto m_safeName() const {
100+
std::string safeName = m_name;
101+
std::replace(safeName.begin(), safeName.end(), ' ', '_');
102+
return safeName;
103+
}
80104

81105
public:
82106
/// @brief Construct a new Dynamics object
83107
/// @param graph The graph representing the network
84108
/// @param seed The seed for the random number generator (default is std::nullopt)
85109
Dynamics(network_t& graph, std::optional<unsigned int> seed = std::nullopt);
86110

111+
/// @brief Set the name of the simulation
112+
/// @param name The name of the simulation
113+
inline void setName(const std::string& name) { m_name = name; };
87114
/// @brief Set the initial time as epoch time
88115
/// @param timeEpoch The initial time as epoch time
89-
void setInitTime(std::time_t timeEpoch) { m_timeInit = timeEpoch; };
116+
inline void setInitTime(std::time_t timeEpoch) { m_timeInit = timeEpoch; };
90117

91118
/// @brief Get the graph
92119
/// @return const network_t&, The graph
93-
inline const network_t& graph() const { return m_graph; };
120+
inline const auto& graph() const { return m_graph; };
121+
/// @brief Get the name of the simulation
122+
/// @return const std::string&, The name of the simulation
123+
inline const auto& name() const { return m_name; };
94124
/// @brief Get the current simulation time as epoch time
95125
/// @return std::time_t, The current simulation time as epoch time
96-
inline std::time_t time() const { return m_timeInit + m_timeStep; }
126+
inline auto time() const { return m_timeInit + m_timeStep; }
97127
/// @brief Get the current simulation time-step
98128
/// @return std::time_t, The current simulation time-step
99-
inline std::time_t time_step() const { return m_timeStep; }
129+
inline auto time_step() const { return m_timeStep; }
100130
/// @brief Get the current simulation time as formatted string (YYYY-MM-DD HH:MM:SS)
101131
/// @return std::string, The current simulation time as formatted string
102132
inline auto strDateTime() const {
@@ -117,6 +147,7 @@ namespace dsf {
117147
template <typename network_t>
118148
Dynamics<network_t>::Dynamics(network_t& graph, std::optional<unsigned int> seed)
119149
: m_graph{std::move(graph)},
150+
m_name{"unnamed simulation"},
120151
m_timeInit{0},
121152
m_timeStep{0},
122153
m_generator{std::random_device{}()} {

src/dsf/bindings.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@ PYBIND11_MODULE(dsf_cpp, m) {
270270
dsf::g_docstrings.at("dsf::mobility::FirstOrderDynamics::FirstOrderDynamics")
271271
.c_str())
272272
// Note: Constructors with std::function parameters are not exposed to avoid stub generation issues
273+
.def("setName",
274+
&dsf::mobility::FirstOrderDynamics::setName,
275+
pybind11::arg("name"),
276+
dsf::g_docstrings.at("dsf::Dynamics::setName").c_str())
273277
.def("setInitTime",
274278
&dsf::mobility::FirstOrderDynamics::setInitTime,
275279
pybind11::arg("timeEpoch"),

src/dsf/dsf.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
static constexpr uint8_t DSF_VERSION_MAJOR = 4;
88
static constexpr uint8_t DSF_VERSION_MINOR = 3;
9-
static constexpr uint8_t DSF_VERSION_PATCH = 0;
9+
static constexpr uint8_t DSF_VERSION_PATCH = 1;
1010

1111
static auto const DSF_VERSION =
1212
std::format("{}.{}.{}", DSF_VERSION_MAJOR, DSF_VERSION_MINOR, DSF_VERSION_PATCH);

src/dsf/mobility/RoadDynamics.hpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,9 @@ namespace dsf::mobility {
332332
Measurement<double> meanSpireOutputFlow(bool resetValue = true);
333333

334334
/// @brief Save the street densities in csv format
335-
/// @param filename The name of the file
335+
/// @param filename The name of the file (default is "{datetime}_{simulation_name}_street_densities.csv")
336336
/// @param normalized If true, the densities are normalized in [0, 1]
337-
void saveStreetDensities(const std::string& filename,
337+
void saveStreetDensities(std::string filename = std::string(),
338338
bool normalized = true,
339339
char const separator = ';') const;
340340
/// @brief Save the street input counts in csv format
@@ -357,11 +357,11 @@ namespace dsf::mobility {
357357
/// - distances: the travel distances of the agents
358358
/// - times: the travel times of the agents
359359
/// - speeds: the travel speeds of the agents
360-
/// @param filename The name of the file
360+
/// @param filename The name of the file (default is "{datetime}_{simulation_name}_travel_data.csv")
361361
/// @param reset If true, the travel speeds are cleared after the computation
362-
void saveTravelData(const std::string& filename, bool reset = false);
362+
void saveTravelData(std::string filename = std::string(), bool reset = false);
363363
/// @brief Save the main macroscopic observables in csv format
364-
/// @param filename The name of the file
364+
/// @param filename The name of the file (default is "{datetime}_{simulation_name}_macroscopic_observables.csv")
365365
/// @param separator The separator character (default is ';')
366366
/// @details The file contains the following columns:
367367
/// - time: the time of the simulation
@@ -375,7 +375,7 @@ namespace dsf::mobility {
375375
/// - mean_travelspeed - mean_travelspeed_std (km/h): the mean travel speed of the agents
376376
///
377377
/// NOTE: the mean density is normalized in [0, 1] and reset is true for all observables which have such parameter
378-
void saveMacroscopicObservables(const std::string& filename,
378+
void saveMacroscopicObservables(std::string filename = std::string(),
379379
char const separator = ';');
380380
};
381381
@@ -2160,9 +2160,13 @@ namespace dsf::mobility {
21602160

21612161
template <typename delay_t>
21622162
requires(is_numeric_v<delay_t>)
2163-
void RoadDynamics<delay_t>::saveStreetDensities(const std::string& filename,
2163+
void RoadDynamics<delay_t>::saveStreetDensities(std::string filename,
21642164
bool normalized,
21652165
char const separator) const {
2166+
if (filename.empty()) {
2167+
filename =
2168+
this->m_safeDateTime() + '_' + this->m_safeName() + "_street_densities.csv";
2169+
}
21662170
bool bEmptyFile{false};
21672171
{
21682172
std::ifstream file(filename);
@@ -2276,7 +2280,10 @@ namespace dsf::mobility {
22762280
}
22772281
template <typename delay_t>
22782282
requires(is_numeric_v<delay_t>)
2279-
void RoadDynamics<delay_t>::saveTravelData(const std::string& filename, bool reset) {
2283+
void RoadDynamics<delay_t>::saveTravelData(std::string filename, bool reset) {
2284+
if (filename.empty()) {
2285+
filename = this->m_safeDateTime() + '_' + this->m_safeName() + "_travel_data.csv";
2286+
}
22802287
bool bEmptyFile{false};
22812288
{
22822289
std::ifstream file(filename);
@@ -2331,8 +2338,12 @@ namespace dsf::mobility {
23312338
}
23322339
template <typename delay_t>
23332340
requires(is_numeric_v<delay_t>)
2334-
void RoadDynamics<delay_t>::saveMacroscopicObservables(const std::string& filename,
2341+
void RoadDynamics<delay_t>::saveMacroscopicObservables(std::string filename,
23352342
char const separator) {
2343+
if (filename.empty()) {
2344+
filename = this->m_safeDateTime() + '_' + this->m_safeName() +
2345+
"_macroscopic_observables.csv";
2346+
}
23362347
bool bEmptyFile{false};
23372348
{
23382349
std::ifstream file(filename);
@@ -2343,10 +2354,12 @@ namespace dsf::mobility {
23432354
throw std::runtime_error("Error opening file \"" + filename + "\" for writing.");
23442355
}
23452356
if (bEmptyFile) {
2346-
file << "datetime;time_step;n_ghost_agents;n_agents;mean_speed_kph;std_speed_kph;"
2347-
"mean_density_vpk;std_density_vpk;mean_flow_vph;std_flow_vph;mean_"
2348-
"traveltime_m;std_traveltime_m;mean_traveldistance_km;std_traveldistance_"
2349-
"km;mean_travelspeed_kph;std_travelspeed_kph\n";
2357+
constexpr auto strHeader{
2358+
"datetime;time_step;n_ghost_agents;n_agents;mean_speed_kph;std_speed_kph;"
2359+
"mean_density_vpk;std_density_vpk;mean_flow_vph;std_flow_vph;mean_"
2360+
"traveltime_m;std_traveltime_m;mean_traveldistance_km;std_traveldistance_"
2361+
"km;mean_travelspeed_kph;std_travelspeed_kph\n"};
2362+
file << strHeader;
23502363
}
23512364
double mean_speed{0.}, mean_density{0.}, mean_flow{0.}, mean_travel_distance{0.},
23522365
mean_travel_time{0.}, mean_travel_speed{0.};

0 commit comments

Comments
 (0)