/* * Copyright (c) 2025 Konrad Gębik * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ #include #include #include #include #include #include #include "Simulation.hpp" #include "Vector.hpp" /* This program runs a simulation of two bodies moving while interacting gravitationally. Initial parameters and other options are to be set in a setup.ini file located in the same directory as the executable. Three output files are created: -the orbit file, containing raw relative position data of the bodies -the energy file, containing relative energy differences wrt the initial energy -the periapsis file, containing angular positions of one of the bodies when their distance reaches a local minimum */ //Progress bar properties unsigned g_progBarUpdateInt = 1000000, g_progBarMaxLength = 50; //Struct for storing program settings not used in the simulation itself. struct Settings { unsigned simLength; //Number of steps to be simulated. unsigned saveInterval; //How many steps to omit when saving orbit and energy data. unsigned orbitLimit; //How many data points to save to the orbit file. }; //Read data from setup file, create Simulation object and save additional settings to info. Simulation setupFromFile(std::string filename, Settings& info) { Vector pos = {1, 0, 0}, vel = {0, 0.5, 0}; double deltaTime = 0.01; double mass1 = 1, mass2 = 0.01, PNorder = 1; std::string buffer; std::ifstream inFile(filename); if (!inFile.good()) { std::cout << "setup.ini not found!"; throw std::ios_base::failure("setup.ini doesn't exist"); } //Reading simulation settings. Converts from SI to natural units (c = G = 1, with time measured in SI seconds) inFile >> buffer >> mass1 >> buffer >> mass2 >> buffer >> deltaTime >> buffer >> PNorder; mass1 /= 1.49828e10*299792458.*299792458.*299792458.; mass2 /= 1.49828e10*299792458.*299792458.*299792458.; inFile >> buffer >> pos.x >> pos.y >> pos.z; pos = pos / 299792458.; inFile >> buffer >> vel.x >> vel.y >> vel.z; vel = vel / 299792458.; //Reading additional settings inFile >> buffer >> info.simLength >> buffer >> info.saveInterval >> buffer >> info.orbitLimit; info.orbitLimit *= info.saveInterval; return Simulation(mass1, mass2, deltaTime, PNorder, pos, vel); } //Run the simulation and save the outputs as specified by info. void twoBody(Simulation &sim, Settings info) { Vector previous = {0, 0, 0}; bool isDecreasing = false; double startEnergy = sim.getEnergy(), energy; unsigned progBarLength = 0; std::ofstream outOrbit("orbit.txt"); std::ofstream outPeriapsis("periapsis.txt"); std::ofstream outEnergy("energy.txt"); auto start = std::chrono::steady_clock::now(); for (std::size_t i = 0; i < info.simLength; i++) { sim.simulate(); //Saving orbit and energy data if (i % info.saveInterval == 0) { energy = sim.getEnergy(); outEnergy << sim.getTime() << ' ' << std::abs((startEnergy - energy)/energy) << ' ' << energy << '\n'; if (i < info.orbitLimit) { outOrbit << sim.getTime() << ' ' << sim.getPosition().x << ' ' << sim.getPosition().y << '\n'; } } //Finding and saving periapsis angles relative to the x axis if (isDecreasing == true && previous.norm() < sim.getPosition().norm()) { outPeriapsis << sim.getTime() << ' ' << std::atan2(sim.getPosition().y, sim.getPosition().x) << '\n'; isDecreasing = false; } else if (isDecreasing == false && previous.norm() > sim.getPosition().norm()) { isDecreasing = true; } //Showing progress bar if (i % g_progBarUpdateInt == 0) { progBarLength = g_progBarMaxLength * i / static_cast(info.simLength); std::cout << '[' + std::string(progBarLength, '#') + std::string(g_progBarMaxLength - progBarLength, ' ') + "] " << i / static_cast(info.simLength) * 100 << "%\r"; std::cout.flush(); } previous = sim.getPosition(); } std::cout << '[' + std::string(g_progBarMaxLength, '#') + "] 100%\n" ; auto end = std::chrono::steady_clock::now(); std::cout << "Simulation took " << std::chrono::duration_cast(end - start).count() << " ms\n"; outOrbit.close(); outPeriapsis.close(); outEnergy.close(); } int main() { std::cout << "SIM START\n"; Settings info; Simulation sim = setupFromFile("setup.ini", info); twoBody(sim, info); }