pure-cpp 1.0.0
A C++ physics simulation benchmark comparing performance with Python implementations
cmd_line_parser.hpp
Go to the documentation of this file.
1#ifndef CMD_LINE_PARSER_HPP
2#define CMD_LINE_PARSER_HPP
3
4/**
5 * \file cmd_line_parser.hpp
6 * \brief Command-line argument parsing and validation.
7 * \author Le Bars, Yoann
8 * \ingroup AppConfiguration
9 *
10 * This file is part of the pure C++ benchmark.
11 *
12 * This program is free software: you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the Free
14 * Software Foundation, either version 3 of the License, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * this program. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26#include <QCoreApplication>
27#include <QDebug>
28#include <QObject>
29#include <QString>
30#include <boost/program_options.hpp>
31#include <config.hpp>
32#include <cstddef>
33#include <iostream>
34#include <memory>
35#include <sstream>
36#include <string>
37
38#include "constants.hpp"
39
40namespace po = boost::program_options;
41
42/// \brief Namespace for command-line parsing logic.
43namespace CmdLine {
44 /// \brief Exit codes for the application.
45 enum class ExitCode : int {
46 Success = 0,
47 CmdLineError = -1,
48 NotEnoughIterations = -2,
49 NotEnoughBodies = -3,
50 NegativeDensity = -4,
51 NegativeTimeStep = -5,
52 NegativeGravity = -6,
53 NegativeEpsilon = -7,
54 OutOfRange = -8,
55 BadAlloc = -9,
56 StdException = -10,
57 UnknownException = -11,
58 };
59
60 /// \brief Log level for the application.
61 enum class LogLevel {
62 Debug,
63 Info,
64 Warning,
65 Critical,
66 Fatal,
67 };
68
69 /**
70 * \brief Overload of `operator<<` for `LogLevel` to enable streaming.
71 *
72 * This is required by `boost::program_options` for displaying default
73 * values in the help message.
74 *
75 * \param os The output stream.
76 * \param level The `LogLevel` enum to stream.
77 * \return The output stream.
78 */
79 inline std::ostream& operator<<(std::ostream& os, const LogLevel& level) {
80 switch (level) {
81 case LogLevel::Debug:
82 return os << "debug";
83 case LogLevel::Info:
84 return os << "info";
85 case LogLevel::Warning:
86 return os << "warning";
87 case LogLevel::Critical:
88 return os << "critical";
89 case LogLevel::Fatal:
90 return os << "fatal";
91 }
92 return os; // Should not be reached
93 }
94
95 /**
96 * \brief Converts a double to a string with a specified precision for
97 * display.
98 *
99 * \param value The double value to convert.
100 * \param precision The number of digits of precision.
101 * \param use_scientific If true, uses scientific notation; otherwise,
102 * uses fixed.
103 *
104 * \return A string representation of the double.
105 */
106 inline std::string toStringWithPrecision(
107 double value, int precision = 1,
108 bool use_scientific = true) { // NOLINT
109 std::ostringstream out;
110 out.precision(precision);
111 if (use_scientific) {
112 out << std::scientific;
113 } else {
114 out << std::fixed;
115 }
116 out << value;
117 return out.str();
118 }
119
120 // Forward declaration for the custom validator.
121 void validateIsPositive(const std::size_t& value,
122 const std::string& option_name,
123 const std::function<QString(const char*)>& tr_func);
124
125 /**
126 * \brief Overload of `operator>>` for Boost.Program_Options to parse
127 * `LogLevel`.
128 *
129 * \param is The input stream.
130 * \param level The `LogLevel` enum to populate.
131 * \return The input stream.
132 */
133 inline std::istream& operator>>(std::istream& is, LogLevel& level) {
134 std::string token;
135 is >> token;
136 if (token == "debug")
137 level = LogLevel::Debug;
138 else if (token == "info")
139 level = LogLevel::Info;
140 else if (token == "warning")
141 level = LogLevel::Warning;
142 else if (token == "critical")
143 level = LogLevel::Critical;
144 else if (token == "fatal")
145 level = LogLevel::Fatal;
146 else
147 is.setstate(std::ios_base::failbit);
148 return is;
149 }
150
151 /**
152 * \brief A struct to hold the definition of a single command-line option.
153 *
154 * This data-driven approach makes adding or modifying arguments much
155 * cleaner than a long chain of `add_options()` calls.
156 */
158 /// \brief The flags for the option (e.g., "help,h").
159 std::string flags;
160 /// \brief The help text for the option.
161 std::string help_text;
162 /**
163 * \brief A function that returns the Boost.Program_Options value
164 * semantic. This allows us to handle different types (int, double,
165 * bool_switch) in a uniform way.
166 */
167 std::function<po::value_semantic*()> value_factory;
168 };
169
170 /**
171 * \brief Holds and parses command-line arguments.
172 *
173 * This struct inherits from QObject to gain access to the `tr()` function
174 * for internationalisation.
175 * \ingroup AppConfiguration
176 */
177 struct CmdLineArgs {
178 public:
179 /// \brief The number of iterations to run the simulation.
180 std::size_t n_iter_;
181
182 /// \brief The number of bodies in the simulation.
183 std::size_t n_bodies_;
184
185 /// \brief The density of the bodies.
186 double dens_;
187
188 /// \brief The time step for each simulation iteration.
189 double dt_;
190
191 /// \brief The universal gravitational constant.
192 double G_;
193
194 /// \brief The numerical precision for floating-point comparisons.
195 double epsilon_;
196
197 /// \brief The seed for the random number generator.
198 unsigned int seed_;
199
200 /// \brief Flag to enable diagnostic output.
202
203 /// \brief File path for logging.
204 std::string debug_file_;
205
206 /// \brief Identifier for syslog logging.
207 std::string debug_syslog_;
208
209 /// \brief Log level filter.
211
212 /// \brief Frequency of energy log output.
213 std::size_t log_freq_;
214
215 /// \brief Coefficient of restitution for collisions.
217
218 /// \brief Coefficient of kinetic (sliding) friction.
219 double friction_;
220
221 /// \brief Coefficient of static friction.
223
224 /// \brief Damping factor for linear velocity.
226
227 /// \brief Damping factor for angular velocity.
229
230 /// \brief Flag to display torque vectors in the UI.
232
233 /// \brief Flag to display angular acceleration vectors in the UI.
235
236 /// \brief Cleanup strategy: "fast" (deferred) or "strict" (sync).
237 std::string cleanup_mode_;
238
239 /**
240 * \brief Creates a SimulationConfig object from the parsed arguments.
241 *
242 * \return A populated SimulationConfig struct.
243 */
244 [[nodiscard]] Configuration::SimulationConfig toSimulationConfig()
245 const {
246 return {
247 .n_iter = n_iter_,
248 .n_bodies = n_bodies_,
249 .dens = dens_,
250 .universal_g = G_,
251 .epsilon = epsilon_,
252 .seed = seed_,
253 .max_dt = dt_,
254 .coeff_restitution = restitution_,
255 .coeff_friction = friction_,
256 .coeff_static_friction = static_friction_,
257 .linear_damping = linear_damping_,
258 .angular_damping = angular_damping_,
259 .diagnostics_enabled = debug_console_,
260 .log_freq = log_freq_,
261 .show_torque_arrow = show_torque_arrow_,
262 .show_alpha_arrow = show_alpha_arrow_,
263 };
264 }
265
266 /**
267 * \brief Validates the parsed command-line arguments.
268 * \throws po::validation_error if any argument is invalid.
269 */
271 // TRANSLATOR CmdLine
272 // TR_CONTEXT main
273 const std::function<QString(const char*)>& tr_func) const {
274 validateIsPositive(n_iter_, "niter", tr_func);
275 validateIsPositive(n_bodies_, "nbodies", tr_func);
276 validateIsPositive(log_freq_, "log-freq", tr_func);
277
278 if (dens_ <= 0.) {
279 throw po::validation_error(
280 po::validation_error::invalid_option_value,
281 //: TRANSLATOR: Error message for a command-line option.
282 tr_func(
283 QT_TRANSLATE_NOOP(
284 "CmdLine::CmdLineArgs",
285 "The value for option 'dens' must be positive."))
286 .toStdString());
287 }
288 if (dt_ <= 0.) {
289 throw po::validation_error(
290 po::validation_error::invalid_option_value,
291 //: TRANSLATOR: Error message for a command-line option.
292 tr_func(QT_TRANSLATE_NOOP(
293 "CmdLine::CmdLineArgs",
294 "The value for option 'dt' must be positive."))
295 .toStdString());
296 }
297 if (G_ <= 0.) {
298 throw po::validation_error(
299 po::validation_error::invalid_option_value,
300 //: TRANSLATOR: Error message for a command-line option.
301 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
302 "The value for option "
303 "'universalg' must be positive."))
304 .toStdString());
305 }
306 if (epsilon_ <= 0.) {
307 throw po::validation_error(
308 po::validation_error::invalid_option_value,
309 //: TRANSLATOR: Error message for a command-line option.
310 tr_func(
311 QT_TRANSLATE_NOOP(
312 "CmdLine::CmdLineArgs",
313 "The value for option 'epsilon' must be positive."))
314 .toStdString());
315 }
316 if (restitution_ < 0.) {
317 throw po::validation_error(
318 po::validation_error::invalid_option_value,
319 //: TRANSLATOR: Error message for a command-line option.
320 tr_func(QT_TRANSLATE_NOOP(
321 "CmdLine::CmdLineArgs",
322 "The value for option 'restitution' must be "
323 "non-negative."))
324 .toStdString());
325 }
326 if (friction_ < 0.) {
327 throw po::validation_error(
328 po::validation_error::invalid_option_value,
329 //: TRANSLATOR: Error message for a command-line option.
330 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
331 "The value for option 'friction' "
332 "must be non-negative."))
333 .toStdString());
334 }
335 if (static_friction_ < 0.) {
336 throw po::validation_error(
337 po::validation_error::invalid_option_value,
338 //: TRANSLATOR: Error message for a command-line option.
339 tr_func(QT_TRANSLATE_NOOP(
340 "CmdLine::CmdLineArgs",
341 "The value for option 'static-friction' must "
342 "be non-negative."))
343 .toStdString());
344 }
345 if (linear_damping_ < 0. || angular_damping_ < 0.) {
346 throw po::validation_error(
347 po::validation_error::invalid_option_value,
348 //: TRANSLATOR: Error message for a command-line option.
349 tr_func(QT_TRANSLATE_NOOP(
350 "CmdLine::CmdLineArgs",
351 "Damping values must be non-negative."))
352 .toStdString());
353 }
354 if (cleanup_mode_ != "fast" && cleanup_mode_ != "strict") {
355 throw po::validation_error(
356 po::validation_error::invalid_option_value,
357 //: TRANSLATOR: Error message for a command-line option.
358 tr_func(QT_TRANSLATE_NOOP(
359 "CmdLine::CmdLineArgs",
360 "The value for option 'cleanup-mode' must be "
361 "'fast' or 'strict'."))
362 .toStdString());
363 }
364 }
365 /**
366 * \brief Parses and validates command-line arguments.
367 *
368 * \param argc The argument count from main().
369 * \param argv The argument vector from main().
370 *
371 * \return A `unique_ptr` to a `CmdLineArgs` struct on success, or
372 * `nullptr` if --help or --version was requested, or if an
373 * error occurred.
374 */
375 static std::unique_ptr<CmdLineArgs> parse(
376 // TRANSLATOR CmdLine
377 // TR_CONTEXT main
378 const QStringList& q_args,
379 const std::function<QString(const char*)>& tr_func) {
380 auto args = std::make_unique<CmdLineArgs>();
381
382 // Convert QStringList to std::vector<std::string> for Boost
383 std::vector<std::string> std_args;
384 std_args.reserve(q_args.size());
385 for (const auto& arg : q_args) {
386 std_args.push_back(arg.toStdString());
387 }
388
389 const std::vector<OptionDefinition> definitions = {
390 {"help,h",
391 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
392 "Display this help message."))
393 .toStdString(),
394 nullptr},
395 {"version,V",
396 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
397 "Display program version."))
398 .toStdString(),
399 nullptr},
400 {"diagnostics,D",
401 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
402 "Enable diagnostic output (alias "
403 "for --debugConsole)."))
404 .toStdString(),
405 [&] { return po::bool_switch(); }},
406 {"debugConsole,c",
407 tr_func(QT_TRANSLATE_NOOP(
408 "CmdLine::CmdLineArgs",
409 "Enable logs through the standard output."))
410 .toStdString(),
411 [&] {
412 return po::bool_switch(&args->debug_console_)
413 ->default_value(false);
414 }},
415 {"debugFile,f",
416 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
417 "Enable logs into a file."))
418 .toStdString(),
419 [&] {
420 return po::value<std::string>(&args->debug_file_)
421 ->default_value("");
422 }},
423 {"debugSyslog,S",
424 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
425 "Enable logs through Syslog."))
426 .toStdString(),
427 [&] {
428 return po::value<std::string>(&args->debug_syslog_)
429 ->default_value("");
430 }},
431 {"cleanup-mode",
432 tr_func(
433 QT_TRANSLATE_NOOP(
434 "CmdLine::CmdLineArgs",
435 "Cleanup strategy: 'fast' (deferred destruction, "
436 "best performance) or 'strict' (synchronous "
437 "destruction, conservative)."))
438 .toStdString(),
439 [&] {
440 return po::value<std::string>(&args->cleanup_mode_)
441 ->default_value("fast");
442 }},
443 {"level,l",
444 tr_func(QT_TRANSLATE_NOOP(
445 "CmdLine::CmdLineArgs",
446 "Log level filter (debug, info, warning, "
447 "critical, fatal)."))
448 .toStdString(),
449 [&] {
450 return po::value<LogLevel>(&args->log_level_)
451 ->default_value(LogLevel::Critical);
452 }},
453 {"niter,i",
454 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
455 "Number of iterations."))
456 .toStdString(),
457 [&] {
458 return po::value<std::size_t>(&args->n_iter_)
459 ->default_value(500);
460 }},
461 {"nbodies,n",
462 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
463 "Number of bodies."))
464 .toStdString(),
465 [&] {
466 return po::value<std::size_t>(&args->n_bodies_)
467 ->default_value(20);
468 }},
469 {"dens,d",
470 tr_func(QT_TRANSLATE_NOOP(
471 "CmdLine::CmdLineArgs",
472 "Object density (proportionality coefficient "
473 "between mass and radius)."))
474 .toStdString(),
475 [&] {
476 return po::value<double>(&args->dens_)
477 ->default_value(0.1,
478 toStringWithPrecision(0.1, 1, false));
479 }},
480 {"dt,t",
481 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
482 "Model time step (in s)."))
483 .toStdString(),
484 [&] {
485 return po::value<double>(&args->dt_)
486 ->default_value(0.5,
487 toStringWithPrecision(0.5, 1, false));
488 }},
489 {"universalg,g",
490 tr_func(
491 QT_TRANSLATE_NOOP(
492 "CmdLine::CmdLineArgs",
493 "Universal gravitational constant (in m³ / kg / s²)."))
494 .toStdString(),
495 [&] {
496 return po::value<double>(&args->G_)->default_value(
497 Model::G, toStringWithPrecision(Model::G, 5));
498 }},
499 {"seed,s",
500 tr_func(QT_TRANSLATE_NOOP(
501 "CmdLine::CmdLineArgs",
502 "Seed for random number generation. If 0, a "
503 "random seed is used."))
504 .toStdString(),
505 [&] {
506 return po::value<unsigned int>(&args->seed_)
507 ->default_value(0);
508 }},
509 {"epsilon,e",
510 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
511 "Computing precision."))
512 .toStdString(),
513 [&] {
514 return po::value<double>(&args->epsilon_)
515 ->default_value(
516 Model::EPSILON,
517 toStringWithPrecision(Model::EPSILON, 0));
518 }},
519 {"log-freq",
520 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
521 "Frequency of energy log output "
522 "(every N iterations)."))
523 .toStdString(),
524 [&] {
525 return po::value<std::size_t>(&args->log_freq_)
526 ->default_value(Model::DEFAULT_LOG_FREQ);
527 }},
528 {"restitution,r",
529 tr_func(QT_TRANSLATE_NOOP(
530 "CmdLine::CmdLineArgs",
531 "Coefficient of restitution for collisions."))
532 .toStdString(),
533 [&] {
534 return po::value<double>(&args->restitution_)
535 ->default_value(
536 Model::COEFF_RESTITUTION,
537 toStringWithPrecision(Model::COEFF_RESTITUTION, 1,
538 false));
539 }},
540 {"friction,F",
541 tr_func(QT_TRANSLATE_NOOP(
542 "CmdLine::CmdLineArgs",
543 "Coefficient of kinetic (sliding) friction."))
544 .toStdString(),
545 [&] {
546 return po::value<double>(&args->friction_)
547 ->default_value(Model::COEFF_FRICTION,
549 Model::COEFF_FRICTION, 1, false));
550 }},
551 {"static-friction,T",
552 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
553 "Coefficient of static friction."))
554 .toStdString(),
555 [&] {
556 return po::value<double>(&args->static_friction_)
557 ->default_value(
558 Model::COEFF_STATIC_FRICTION,
559 toStringWithPrecision(Model::COEFF_STATIC_FRICTION,
560 1, false));
561 }},
562 {"linear-damping,L",
563 tr_func(
564 QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
565 "Damping factor for linear velocity."))
566 .toStdString(),
567 [&] {
568 return po::value<double>(&args->linear_damping_)
569 ->default_value(Model::LINEAR_DAMPING,
571 Model::LINEAR_DAMPING, 3, false));
572 }},
573 {"angular-damping,a",
574 tr_func(
575 QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
576 "Damping factor for angular velocity."))
577 .toStdString(),
578 [&] {
579 return po::value<double>(&args->angular_damping_)
580 ->default_value(Model::ANGULAR_DAMPING,
582 Model::ANGULAR_DAMPING, 3, false));
583 }},
584 {"show-torque-arrow",
585 tr_func(QT_TRANSLATE_NOOP(
586 "CmdLine::CmdLineArgs",
587 "Show torque vectors as arrows in the UI."))
588 .toStdString(),
589 [&] {
590 return po::bool_switch(&args->show_torque_arrow_)
591 ->default_value(false);
592 }},
593 {"show-alpha-arrow",
594 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
595 "Show angular acceleration vectors "
596 "as arrows in the UI."))
597 .toStdString(),
598 [&] {
599 return po::bool_switch(&args->show_alpha_arrow_)
600 ->default_value(false);
601 }},
602 };
603
604 po::options_description desc(
605 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
606 "Supported options"))
607 .toStdString(),
608 100);
609 for (const auto& def : definitions) {
610 if (def.value_factory) {
611 desc.add_options()(def.flags.c_str(), def.value_factory(),
612 def.help_text.c_str());
613 } else {
614 desc.add_options()(def.flags.c_str(),
615 def.help_text.c_str());
616 }
617 }
618
619 po::variables_map vm;
620 try {
621 po::store(po::command_line_parser(std_args).options(desc).run(),
622 vm);
623 po::notify(vm);
624
625 // Handle the --diagnostics alias
626 if (vm.count("diagnostics")) {
627 args->debug_console_ = true;
628 }
629 }
630
631 catch (const po::error& e) {
632 /* Catch validation errors from notifiers and other parsing
633 errors. */
634 qCritical().noquote()
635 << tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
636 "Command line error: %1"))
637 .arg(e.what());
638 std::cout << desc << std::endl;
639 return nullptr;
640 }
641 if (vm.count("help")) {
642 std::stringstream desc_stream;
643 desc_stream << desc;
644 qInfo().noquote()
645 <<
646 //: TRANSLATOR: A short description of the application.
647 tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
648 "A benchmark for C++ using Qt "
649 "framework.")) // NOLINT
650 << "\n\n"
651 //: TRANSLATOR: A label for the command-line usage example.
652 << tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
653 "Command line:"))
654 << "\n\t"
655 << QCoreApplication::applicationFilePath() // NOLINT
656 //: TRANSLATOR: A placeholder for command-line options.
657 << tr_func(QT_TRANSLATE_NOOP("CmdLine::CmdLineArgs",
658 " [Options]"))
659 << "\n\n"
660 << desc_stream.str().c_str();
661 return nullptr;
662 }
663
664 if (vm.count("version")) {
665 qInfo().noquote()
666 << QString("%1 version %2.%3.%4")
667 .arg(QCoreApplication::applicationName())
668 .arg(Configuration::VERSION_MAJOR)
669 .arg(Configuration::VERSION_MINOR)
670 .arg(Configuration::PATCH_VERSION);
671 return nullptr;
672 }
673
674 args->validate(tr_func);
675 return args;
676 }
677 };
678
679 // --- Custom Validators for Boost.Program_Options ---
680 /**
681 * \brief Validates that an unsigned integer option is greater than zero.
682 *
683 * \param value The value of the option to validate.
684 * \param option_name The name of the option, used for the error message.
685 *
686 * \throws po::validation_error if the value is zero.
687 *
688 * This is a custom validator for use with Boost.Program_Options.
689 */
691 // TRANSLATOR CmdLine
692 // TR_CONTEXT main
693 const std::size_t& value, const std::string& option_name,
694 const std::function<QString(const char*)>& tr_func) {
695 if (value == 0) {
696 /* Throw a validation error with a specific, translatable message.
697 This function is defined after CmdLineArgs so it can call
698 CmdLineArgs::tr(). */
699 throw po::validation_error(
700 po::validation_error::invalid_option_value,
701 //: TRANSLATOR: Error message for a command-line option. %1 is
702 //: the option name.
703 tr_func(QT_TRANSLATE_NOOP(
704 "CmdLine::CmdLineArgs",
705 "The value for option '%1' must be positive."))
706 .arg(QString::fromStdString(option_name))
707 .toStdString());
708 }
709 }
710} // namespace CmdLine
711
712#endif // CMD_LINE_PARSER_HPP
Constants for the model.
Namespace for command-line parsing logic.
void validateIsPositive(const std::size_t &value, const std::string &option_name, const std::function< QString(const char *)> &tr_func)
Validates that an unsigned integer option is greater than zero.
std::ostream & operator<<(std::ostream &os, const LogLevel &level)
Overload of operator<< for LogLevel to enable streaming.
ExitCode
Exit codes for the application.
std::istream & operator>>(std::istream &is, LogLevel &level)
Overload of operator>> for Boost.Program_Options to parse LogLevel.
std::string toStringWithPrecision(double value, int precision=1, bool use_scientific=true)
Converts a double to a string with a specified precision for display.
LogLevel
Log level for the application.
Holds and parses command-line arguments.
double static_friction_
Coefficient of static friction.
bool show_torque_arrow_
Flag to display torque vectors in the UI.
double restitution_
Coefficient of restitution for collisions.
double dt_
The time step for each simulation iteration.
bool show_alpha_arrow_
Flag to display angular acceleration vectors in the UI.
std::string cleanup_mode_
Cleanup strategy: "fast" (deferred) or "strict" (sync).
unsigned int seed_
The seed for the random number generator.
std::size_t n_iter_
The number of iterations to run the simulation.
std::size_t log_freq_
Frequency of energy log output.
double angular_damping_
Damping factor for angular velocity.
Configuration::SimulationConfig toSimulationConfig() const
Creates a SimulationConfig object from the parsed arguments.
double friction_
Coefficient of kinetic (sliding) friction.
double linear_damping_
Damping factor for linear velocity.
bool debug_console_
Flag to enable diagnostic output.
std::string debug_syslog_
Identifier for syslog logging.
double epsilon_
The numerical precision for floating-point comparisons.
LogLevel log_level_
Log level filter.
static std::unique_ptr< CmdLineArgs > parse(const QStringList &q_args, const std::function< QString(const char *)> &tr_func)
Parses and validates command-line arguments.
void validate(const std::function< QString(const char *)> &tr_func) const
Validates the parsed command-line arguments.
std::string debug_file_
File path for logging.
double G_
The universal gravitational constant.
std::size_t n_bodies_
The number of bodies in the simulation.
double dens_
The density of the bodies.
A struct to hold the definition of a single command-line option.
std::string flags
The flags for the option (e.g., "help,h").
std::function< po::value_semantic *()> value_factory
A function that returns the Boost.Program_Options value semantic. This allows us to handle different ...
std::string help_text
The help text for the option.