#include #include #include #include #include #include #include "simulator.hpp" #include "body.hpp" #include "units.hpp" using json = nlohmann::json; namespace po = boost::program_options; struct SimulationConfig { std::string config_file; std::string output_file; int steps; int steps_per_save; Decimal step_size; // Changed to Decimal for normalized time bool overwrite_output; double simulation_time; // in seconds (real time) }; // Convert time string to seconds double parse_time(const std::string& time_str) { std::string value_str = time_str; std::string unit; // Extract the unit (last character) if (!time_str.empty()) { unit = time_str.back(); value_str = time_str.substr(0, time_str.length() - 1); } double value = std::stod(value_str); // Convert to seconds based on unit switch (unit[0]) { case 's': return value; // seconds case 'm': return value * 60; // minutes case 'h': return value * 3600; // hours case 'd': return value * 86400; // days default: throw std::runtime_error("Invalid time unit. Use s/m/h/d for seconds/minutes/hours/days"); } } SimulationConfig parse_command_line(int argc, char* argv[]) { SimulationConfig config; double temp_step_size; // Temporary variable for parsing po::options_description desc("Orbital Simulator Options"); desc.add_options() ("help,h", "Show help message") ("config,c", po::value(&config.config_file)->required(), "Path to planet configuration file (JSON)") ("output,o", po::value(&config.output_file)->required(), "Path to output file") ("time,t", po::value()->required(), "Simulation time with unit (e.g., 1h for 1 hour, 30m for 30 minutes, 2d for 2 days)") ("step-size,s", po::value(&temp_step_size)->default_value(1.0), "Simulation step size in seconds") ("steps-per-save,p", po::value(&config.steps_per_save)->default_value(100), "Number of steps between saves") ("overwrite,w", po::bool_switch(&config.overwrite_output), "Overwrite output file if it exists"); po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, desc), vm); if (vm.count("help")) { std::cout << desc << "\n"; exit(0); } po::notify(vm); // Parse simulation time config.simulation_time = parse_time(vm["time"].as()); // Convert step size to Decimal and normalize config.step_size = norm_time(Decimal(temp_step_size)); // Calculate number of steps based on normalized time and step size config.steps = static_cast(norm_time(config.simulation_time) / config.step_size); } catch (const po::error& e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << desc << "\n"; exit(1); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << "\n"; std::cerr << desc << "\n"; exit(1); } return config; } std::vector load_planets(const std::string& config_file) { std::ifstream f(config_file); if (!f.is_open()) { throw std::runtime_error("Could not open config file: " + config_file); } json j; f >> j; std::vector bodies; for (const auto& planet : j["planets"]) { std::string name = planet["name"]; double mass = planet["mass"]; std::vector pos = planet["position"]; std::vector vel = planet["velocity"]; if (pos.size() != 3 || vel.size() != 3) { throw std::runtime_error("Position and velocity must be 3D vectors"); } // Normalize units before creating the body Position position{norm_pos(pos[0]), norm_pos(pos[1]), norm_pos(pos[2])}; Velocity velocity{norm_vel(vel[0]), norm_vel(vel[1]), norm_vel(vel[2])}; Mass normalized_mass = norm_mass(mass); bodies.emplace_back(position, velocity, normalized_mass, name); std::cout << "Loaded " << name << " with mass " << mass << " kg\n"; } return bodies; } int main(int argc, char* argv[]) { try { // Parse command line options auto config = parse_command_line(argc, argv); // Load planets from config file auto bodies = load_planets(config.config_file); // Create and run simulator Simulator simulator( bodies, config.step_size, config.steps_per_save, config.output_file, 0, // current_step config.overwrite_output ); std::cout << "Starting simulation with " << bodies.size() << " bodies\n"; std::cout << "Step size: " << real_time(config.step_size) << " seconds\n"; std::cout << "Simulation time: " << config.simulation_time << " seconds\n"; std::cout << "Total steps: " << config.steps << "\n"; std::cout << "Steps per save: " << config.steps_per_save << "\n"; simulator.run(config.steps); std::cout << "Simulation completed successfully\n"; return 0; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; } }