├── bin └── .gitkeep ├── .gitignore ├── .vscode ├── settings.json ├── tasks.json └── launch.json ├── src ├── Vector.cpp ├── main.cpp ├── Types.cpp ├── IIntegrator.cpp ├── IntegratorRK4.cpp ├── IntegratorADB5.cpp ├── IntegratorRK5.cpp ├── IntegratorADB6.cpp ├── IntegratorRKF4.cpp ├── SDLWnd.cpp ├── BHTree.cpp ├── NBodyWnd.cpp └── ModelNBody.cpp ├── include ├── Constants.h ├── Vector.h ├── IntegratorADB6.h ├── IntegratorADB5.h ├── IntegratorRK4.h ├── IntegratorRK5.h ├── Types.h ├── IModel.h ├── IntegratorRKF4.h ├── NBodyWnd.h ├── IIntegrator.h ├── ModelNBody.h ├── SDLWnd.h └── BHTree.h ├── Build.md ├── README.md ├── CMakeLists.txt └── Makefile /bin/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CMake 2 | CMakeFiles/* 3 | CMakeCache.txt 4 | Makefile 5 | cmake_install.cmake 6 | bin/barnes-hut-simulator 7 | *.tga 8 | build/* 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "stdexcept": "cpp", 4 | "cassert": "cpp", 5 | "iosfwd": "cpp" 6 | } 7 | } -------------------------------------------------------------------------------- /src/Vector.cpp: -------------------------------------------------------------------------------- 1 | #include "Vector.h" 2 | 3 | 4 | Vec2D::Vec2D(double a_x, double a_y) 5 | :x(a_x) 6 | ,y(a_y) 7 | {} 8 | 9 | 10 | Vec3D::Vec3D(double a_x, double a_y, double a_z) 11 | :x(a_x) 12 | ,y(a_y) 13 | ,z(a_z) 14 | {} 15 | -------------------------------------------------------------------------------- /include/Constants.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONSTANTS_H 2 | #define _CONSTANTS_H 3 | 4 | #include 5 | 6 | 7 | class Constants 8 | { 9 | public: 10 | 11 | static constexpr double MassOfSun = 1.988435e30; 12 | static constexpr double ParsecInMeter = 3.08567758129e16; 13 | static constexpr double Gamma = 6.67428e-11; 14 | }; 15 | 16 | #endif // _CONSTANTS_H -------------------------------------------------------------------------------- /include/Vector.h: -------------------------------------------------------------------------------- 1 | #ifndef _VECTOR_H 2 | #define _VECTOR_H 3 | 4 | class Vec2D 5 | { 6 | public: 7 | Vec2D(double _x = 0, double _y = 0); 8 | double x; 9 | double y; 10 | }; 11 | 12 | class Vec3D 13 | { 14 | public: 15 | Vec3D(double _x = 0, double _y = 0, double _z = 0); 16 | double x; 17 | double y; 18 | double z; 19 | }; 20 | 21 | #endif //_VECTOR_H 22 | -------------------------------------------------------------------------------- /Build.md: -------------------------------------------------------------------------------- 1 | # How To Build 2 | 3 | First, install dependencies (assumes Ubuntu): 4 | 5 | ```terminal 6 | sudo apt install libsdl1.2-dev libsdl-ttf2.0-dev libsdl-gfx1.2-dev libglu1-mesa-dev mesa-common-dev freeglut3-dev libgomp1 7 | ``` 8 | 9 | Type the following command under the root directory: 10 | 11 | ```terminal 12 | cmake . 13 | cmake --build . 14 | ./bin/barnes-hut-simulator 15 | ``` 16 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "NBodyWnd.h" 5 | 6 | 7 | int main(int argc, char **argv) 8 | { 9 | try 10 | { 11 | NBodyWnd wndMain(700, "NBody Simulation (Barnes Hut algorithm)"); 12 | 13 | // Define simulation size 14 | wndMain.Init(4000); 15 | wndMain.MainLoop(); 16 | } 17 | catch (std::exception &exc) 18 | { 19 | std::cout << "Fatal error: " << exc.what() << std::endl; 20 | } 21 | catch (...) 22 | { 23 | std::cout << "Fatal error: unexpected exception" << std::endl; 24 | } 25 | 26 | return (EXIT_SUCCESS); 27 | } 28 | -------------------------------------------------------------------------------- /include/IntegratorADB6.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTEGRATOR_ADB6_H 2 | #define _INTEGRATOR_ADB6_H 3 | 4 | #include "IIntegrator.h" 5 | 6 | 7 | /** \brief Implementation of the ADB6 integration scheme. */ 8 | class IntegratorADB6 final : public IIntegrator 9 | { 10 | public: 11 | IntegratorADB6(IModel *pModel, double h); 12 | virtual ~IntegratorADB6(); 13 | virtual void SingleStep() override; 14 | virtual void SetInitialState(double *state) override; 15 | virtual double *GetState() const override; 16 | virtual void Reverse() override; 17 | 18 | private: 19 | double *_state; 20 | double *_f[6]; 21 | double _c[6]; 22 | }; 23 | 24 | #endif // _INTEGRATOR_ADB6_H 25 | -------------------------------------------------------------------------------- /include/IntegratorADB5.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTEGRATOR_ADB5_H 2 | #define _INTEGRATOR_ADB5_H 3 | 4 | #include "IIntegrator.h" 5 | #include "IntegratorRK4.h" 6 | 7 | /** \brief Implementation of the ADB5 integration scheme. */ 8 | class IntegratorADB5 final : public IIntegrator 9 | { 10 | public: 11 | IntegratorADB5(IModel *pModel, double h); 12 | virtual ~IntegratorADB5(); 13 | virtual void SingleStep() override; 14 | virtual void SetInitialState(double *state) override; 15 | virtual double *GetState() const override; 16 | 17 | private: 18 | double *_state; 19 | double *_f[6]; 20 | double _c[6]; 21 | IntegratorRK4 _rk4; 22 | }; 23 | 24 | #endif // _INTEGRATOR_ADB5_H 25 | -------------------------------------------------------------------------------- /include/IntegratorRK4.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTEGRATOR_RK4_H 2 | #define _INTEGRATOR_RK4_H 3 | 4 | #include "IIntegrator.h" 5 | 6 | 7 | /** \brief Implementation of the Runge-Kutta 4th order integration scheme. */ 8 | class IntegratorRK4 final : public IIntegrator 9 | { 10 | public: 11 | IntegratorRK4(IModel *pModel, double h); 12 | virtual ~IntegratorRK4(); 13 | 14 | virtual void SingleStep() override; 15 | virtual void SetInitialState(double *state) override; 16 | virtual double *GetState() const override; 17 | 18 | private: 19 | double *_state; 20 | double *_tmp; 21 | double *_k1; 22 | double *_k2; 23 | double *_k3; 24 | double *_k4; 25 | }; 26 | 27 | #endif // _INTEGRATOR_RK4_H -------------------------------------------------------------------------------- /include/IntegratorRK5.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTEGRATOR_RK5_H 2 | #define _INTEGRATOR_RK5_H 3 | 4 | #include "IIntegrator.h" 5 | 6 | /** \brief Implementation of the simple Euler integration scheme. */ 7 | class IntegratorRK5 final : public IIntegrator 8 | { 9 | public: 10 | IntegratorRK5(IModel *pModel, double h); 11 | virtual ~IntegratorRK5(); 12 | virtual void SingleStep() override; 13 | virtual void SetInitialState(double *state) override; 14 | virtual double *GetState() const override; 15 | 16 | private: 17 | double *_state; 18 | double *_tmp; 19 | double *_k1; 20 | double *_k2; 21 | double *_k3; 22 | double *_k4; 23 | double *_k5; 24 | double *_k6; 25 | }; 26 | 27 | #endif // _INTEGRATOR_RK5_H 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Barnes-Hut-Simulator 2 | 3 | The Barnes-Hut Algorithm describes an effective method for solving n-body problems. It was originally published in 1986 by Josh Barnes and Piet Hut. Instead of directly summing up all forces, it is using a tree based approximation scheme which reduces the computational complexity of the problem from O(N2) to O(N log N). This repository belongs to an article on [beltoforion.de](https://beltoforion.de/en) explaining the Barnes-Hut algorithm. 4 | 5 | English Article: 6 | * [Barnes-Hut galaxy simulator](https://beltoforion.de/en/barnes-hut-galaxy-simulator/) 7 | 8 | German Article: 9 | * [Barnes-Hut Galaxiensimulation](https://beltoforion.de/de/barnes-hut-galaxiensimulation/) 10 | 11 | ![](https://beltoforion.de/en/barnes-hut-galaxy-simulator/images/anim.gif) 12 | -------------------------------------------------------------------------------- /include/Types.h: -------------------------------------------------------------------------------- 1 | #ifndef _TYPES_H 2 | #define _TYPES_H 3 | 4 | #pragma pack(push, 1) 5 | 6 | struct PODState 7 | { 8 | double x; 9 | double y; 10 | double vx; 11 | double vy; 12 | }; 13 | 14 | struct PODAuxState 15 | { 16 | double mass; 17 | }; 18 | 19 | struct PODDeriv 20 | { 21 | double vx; 22 | double vy; 23 | double ax; 24 | double ay; 25 | }; 26 | 27 | #pragma pack(pop) 28 | 29 | struct ParticleData 30 | { 31 | ParticleData(); 32 | ParticleData(PODState *pState, PODAuxState *pAuxState); 33 | ParticleData(const ParticleData &ref); 34 | ParticleData &operator=(const ParticleData &ref); 35 | 36 | void Reset(); 37 | bool IsNull() const; 38 | 39 | PODState *_pState; 40 | PODAuxState *_pAuxState; 41 | }; 42 | 43 | #endif // _TYPES_H 44 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "label": "Build (Debug)", 5 | "type": "shell", 6 | "command": "cmake --build build --config Debug", 7 | "group": "build", 8 | "problemMatcher": "$gcc", 9 | "presentation": { 10 | "reveal": "silent", 11 | "panel": "new" 12 | } 13 | }, 14 | { 15 | "label": "Build (Release)", 16 | "type": "shell", 17 | "command": "cmake --build build --config Release", 18 | "group": "build", 19 | "problemMatcher": "$gcc", 20 | "presentation": { 21 | "reveal": "silent", 22 | "panel": "new" 23 | } 24 | } 25 | ], 26 | "version": "2.0.0" 27 | } -------------------------------------------------------------------------------- /include/IModel.h: -------------------------------------------------------------------------------- 1 | #ifndef _IMODEL_HPP 2 | #define _IMODEL_HPP 3 | 4 | #include 5 | 6 | 7 | /** \brief Interface for the models to be simulated. */ 8 | class IModel 9 | { 10 | public: 11 | 12 | IModel(const std::string &name, unsigned dim=1) 13 | :_dim(dim) 14 | ,_name(name) 15 | {} 16 | 17 | virtual ~IModel() {} 18 | 19 | unsigned GetDim() const noexcept { return _dim; } 20 | void SetDim(unsigned dim) noexcept { _dim = dim; } 21 | 22 | std::string GetName() const noexcept { return _name; } 23 | 24 | virtual void Eval(double *state, double time, double *deriv_in) = 0; 25 | virtual bool IsFinished(double *state) = 0; 26 | virtual double* GetInitialState() = 0; 27 | 28 | private: 29 | unsigned _dim; 30 | std::string _name; 31 | }; 32 | 33 | #endif // _IMODEL_HPP 34 | 35 | -------------------------------------------------------------------------------- /include/IntegratorRKF4.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTEGRATOR_RKF4_H 2 | #define _INTEGRATOR_RKF4_H 3 | 4 | #include "IIntegrator.h" 5 | 6 | /** \brief Implementation of the simple Euler integration scheme. */ 7 | class IntegratorRKF4 final : public IIntegrator 8 | { 9 | public: 10 | IntegratorRKF4(IModel *pModel, double h); 11 | virtual ~IntegratorRKF4(); 12 | virtual void SingleStep() override; 13 | virtual void SetInitialState(double *state) override; 14 | virtual double *GetState() const override; 15 | 16 | void SetMaximumError(double err); 17 | 18 | private: 19 | double *_state; 20 | double *_tmp; 21 | double *_k1; 22 | double *_k2; 23 | double *_k3; 24 | double *_k4; 25 | double *_k5; 26 | double *_k6; 27 | double *_error; 28 | double _maxErr; 29 | }; 30 | 31 | #endif // _INTEGRATOR_RKF4_H 32 | -------------------------------------------------------------------------------- /src/Types.cpp: -------------------------------------------------------------------------------- 1 | #include "Types.h" 2 | 3 | //--- Standard includes ------------------------------------------------------------------ 4 | #include 5 | #include 6 | 7 | 8 | ParticleData::ParticleData() 9 | : _pState(nullptr), _pAuxState(nullptr) 10 | {} 11 | 12 | 13 | ParticleData::ParticleData(PODState *pState, PODAuxState *pAuxState) 14 | : _pState(pState), _pAuxState(pAuxState) 15 | { 16 | assert(_pState); 17 | assert(_pAuxState); 18 | } 19 | 20 | 21 | ParticleData::ParticleData(const ParticleData &ref) 22 | : _pState(ref._pState), _pAuxState(ref._pAuxState) 23 | {} 24 | 25 | 26 | ParticleData &ParticleData::operator=(const ParticleData &ref) 27 | { 28 | if (this != &ref) 29 | { 30 | _pState = ref._pState; 31 | _pAuxState = ref._pAuxState; 32 | } 33 | 34 | return *this; 35 | } 36 | 37 | 38 | void ParticleData::Reset() 39 | { 40 | _pState = nullptr; 41 | _pAuxState = nullptr; 42 | } 43 | 44 | 45 | bool ParticleData::IsNull() const 46 | { 47 | return _pState && _pAuxState; 48 | } 49 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "C++ Launch", 3 | "type": "cppdbg", 4 | "request": "launch", 5 | "program": "${workspaceFolder}/bin/barnes-hut-simulator", 6 | "args": ["arg1", "arg2"], 7 | "environment": [{ "name": "config", "value": "Debug" }], 8 | "cwd": "${workspaceFolder}", 9 | "configurations": [ 10 | 11 | 12 | { 13 | "name": "(gdb) Starten", 14 | "type": "cppdbg", 15 | "request": "launch", 16 | "program": "${workspaceFolder}/bin/barnes-hut-simulator", 17 | "args": [], 18 | "stopAtEntry": false, 19 | "cwd": "${fileDirname}", 20 | "environment": [], 21 | "externalConsole": false, 22 | "MIMode": "gdb", 23 | "setupCommands": [ 24 | { 25 | "description": "Automatische Strukturierung und Einrückung für \"gdb\" aktivieren", 26 | "text": "-enable-pretty-printing", 27 | "ignoreFailures": true 28 | }, 29 | { 30 | "description": "Disassemblierungsvariante auf Intel festlegen", 31 | "text": "-gdb-set disassembly-flavor intel", 32 | "ignoreFailures": true 33 | } 34 | ] 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /include/NBodyWnd.h: -------------------------------------------------------------------------------- 1 | #ifndef _NBODYWND_H 2 | #define _NBODYWND_H 3 | 4 | #include 5 | #include 6 | 7 | #include "SDLWnd.h" 8 | #include "BHTree.h" 9 | #include "ModelNBody.h" 10 | #include "IIntegrator.h" 11 | 12 | 13 | /** \brief Main window of th n-body simulation. */ 14 | class NBodyWnd final : public SDLWindow 15 | { 16 | public: 17 | 18 | NBodyWnd(int sz, std::string caption); 19 | virtual ~NBodyWnd(); 20 | 21 | virtual void Render() override; 22 | virtual void Update() override; 23 | virtual void OnProcessEvents(uint8_t type) override; 24 | 25 | void Init(int num); 26 | 27 | private: 28 | 29 | enum DisplayState : unsigned int 30 | { 31 | dspNONE = 0, 32 | dspAXIS = 1 << 0, 33 | dspBODIES = 1 << 1, 34 | dspSTAT = 1 << 2, 35 | dspTREE = 1 << 3, 36 | dspTREE_COMPLETE = 1 << 4, 37 | dspCENTER_OF_MASS = 1 << 5, 38 | dspPAUSE = 1 << 6, 39 | dspVERBOSE = 1 << 7, 40 | dspHELP = 1 << 8, 41 | dspARROWS = 1 << 9, 42 | dspROI = 1 << 10 43 | }; 44 | 45 | NBodyWnd(const NBodyWnd &orig); 46 | 47 | void DrawBodies(); 48 | void DrawStat(); 49 | void DrawTree(); 50 | void DrawHelp(); 51 | void DrawROI(); 52 | void DrawCenterOfMass(); 53 | void DrawNode(BHTreeNode *pNode, int level); 54 | 55 | ModelNBody *_pModel; 56 | IIntegrator *_pSolver; 57 | 58 | int _camOrient; ///< Index of the camera orientation to use 59 | uint32_t _flags; ///< The display flags 60 | bool _bDumpState = false; 61 | bool _bDumpImage = false; 62 | std::ofstream _outfile; 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/IIntegrator.h: -------------------------------------------------------------------------------- 1 | #ifndef _IINTEGRATOR_H 2 | #define _IINTEGRATOR_H 3 | 4 | #include 5 | 6 | #include "IModel.h" 7 | 8 | 9 | /** \brief Base class for a variety of integration algorithms. */ 10 | class IIntegrator 11 | { 12 | public: 13 | 14 | IIntegrator(IModel *pModel, double h); 15 | virtual ~IIntegrator(); 16 | void SetStepSize(double h); 17 | double GetStepSize() const; 18 | double GetTime() const; 19 | double GetError() const; 20 | IModel* GetModel() const; 21 | void SetModel(IModel *pModel); 22 | 23 | virtual void Reverse(); 24 | virtual void SetInitialState(double *state) = 0; 25 | virtual void SingleStep() = 0; 26 | virtual double* GetState() const = 0; 27 | 28 | const std::string& GetID() const; 29 | 30 | protected: 31 | 32 | void Evaluate(const double *initial, // initial state vector 33 | const double *deriv_in, // derivation k input 34 | double h, // step size 35 | double time, // absolute time 36 | double *deriv_out); // the new derivation at h*deriv_in 37 | 38 | void SetID(const std::string &sID); 39 | 40 | IModel *m_pModel; ///< Pointer to the model implementation 41 | double m_h; ///< The timestep size 42 | double m_time; ///< The absolute time 43 | double m_err; ///< The local error if supported by the integration scheme 44 | std::string m_sID; 45 | 46 | private: 47 | 48 | IIntegrator(const IIntegrator &ref); 49 | IIntegrator& operator=(const IIntegrator &ref); 50 | }; 51 | 52 | #endif // _IINTEGRATOR_H 53 | -------------------------------------------------------------------------------- /src/IIntegrator.cpp: -------------------------------------------------------------------------------- 1 | #include "IIntegrator.h" 2 | 3 | #include 4 | #include 5 | 6 | IIntegrator::IIntegrator(IModel *pModel, double h) 7 | :m_pModel(pModel) 8 | ,m_h(h) 9 | ,m_time(0) 10 | ,m_err(0) 11 | { 12 | if (pModel == nullptr) 13 | throw std::runtime_error("Model pointer may not be NULL"); 14 | 15 | if (h <= 0) 16 | throw std::runtime_error("Step size may not be negative or NULL."); 17 | } 18 | 19 | 20 | IIntegrator::~IIntegrator() 21 | {} 22 | 23 | 24 | double IIntegrator::GetStepSize() const 25 | { 26 | return m_h; 27 | } 28 | 29 | 30 | void IIntegrator::Reverse() 31 | { 32 | m_h *= -1; 33 | } 34 | 35 | 36 | IModel *IIntegrator::GetModel() const 37 | { 38 | return m_pModel; 39 | } 40 | 41 | 42 | void IIntegrator::SetModel(IModel *pModel) 43 | { 44 | m_pModel = pModel; 45 | } 46 | 47 | 48 | /** \brief Set the stepsize of the integrator. */ 49 | void IIntegrator::SetStepSize(double h) 50 | { 51 | m_h = h; 52 | } 53 | 54 | 55 | void IIntegrator::SetID(const std::string &sID) 56 | { 57 | m_sID = sID; 58 | } 59 | 60 | 61 | const std::string &IIntegrator::GetID() const 62 | { 63 | return m_sID; 64 | } 65 | 66 | 67 | /** \brief Returns the absolute time. */ 68 | double IIntegrator::GetTime() const 69 | { 70 | return m_time; 71 | } 72 | 73 | 74 | double IIntegrator::GetError() const 75 | { 76 | return m_err; 77 | } 78 | 79 | 80 | /** \brief Evaluate the model function at a certain point in time. */ 81 | void IIntegrator::Evaluate(const double *initial, // initial state vector 82 | const double *deriv_in, // derivation k input 83 | double h, // the new intermediary timestep is at h*k 84 | double time, // absolute time 85 | double *deriv_out) // the new derivation at h*deriv_in 86 | { 87 | assert(m_pModel); 88 | 89 | // estimate state at timestep i+h 90 | double state[m_pModel->GetDim()]; 91 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 92 | state[i] = initial[i] + h * deriv_in[i]; 93 | 94 | m_pModel->Eval(state, time + h, deriv_out); 95 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(barnes-hut-simulator) 3 | set(CMAKE_CXX_STANDARD 17) 4 | 5 | # Need to install the following libraries in the case of Ubuntu: 6 | # - libsdl1.2-dev 7 | # - libsdl-ttf2.0-dev 8 | # - libsdl-gfx1.2-dev 9 | find_package(SDL REQUIRED) 10 | add_library(SDL INTERFACE IMPORTED) 11 | target_include_directories(SDL INTERFACE ${SDL_INCLUDE_DIR}) 12 | target_link_libraries(SDL INTERFACE ${SDL_LIBRARY}) 13 | 14 | find_package(X11 REQUIRED) 15 | add_library(X11 INTERFACE IMPORTED) 16 | target_include_directories(X11 INTERFACE ${X11_INCLUDE_DIR}) 17 | target_link_libraries(X11 INTERFACE ${X11_LIBRARIES}) 18 | 19 | # Please set "OpenGL_GL_PREFERENCE" to "LEGACY" to use a legacy GL library (libGL.so) 20 | # instead of GLVND libraries (libOpenGL.so, libGSL.so). 21 | # 22 | # Example: 23 | # cmake .. -DOpenGL_GL_PREFERENCE=LEGACY 24 | # 25 | # Need to install the following libraries in the case of Ubuntu: 26 | # - libglu1-mesa-dev 27 | # - mesa-common-dev 28 | # - freeglut3-dev 29 | find_package(OpenGL REQUIRED) 30 | 31 | # Need to install the following libraries in the case of Ubuntu: 32 | # - libgomp1 33 | find_package(OpenMP REQUIRED) 34 | 35 | # Add the include directory 36 | include_directories(include) 37 | 38 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") 39 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -ffast-math -fomit-framepointers") 40 | 41 | # Set the source files 42 | set(SOURCES 43 | src/main.cpp 44 | src/BHTree.cpp 45 | src/IIntegrator.cpp 46 | src/IntegratorADB5.cpp 47 | src/IntegratorADB6.cpp 48 | src/IntegratorRK4.cpp 49 | src/IntegratorRK5.cpp 50 | src/IntegratorRKF4.cpp 51 | src/ModelNBody.cpp 52 | src/NBodyWnd.cpp 53 | src/SDLWnd.cpp 54 | src/Types.cpp 55 | src/Vector.cpp) 56 | 57 | add_executable(${PROJECT_NAME} ${SOURCES}) 58 | set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) 59 | 60 | #target_include_directories(barnes-hut-simulator 61 | # PUBLIC 62 | # ${PROJECT_SOURCE_DIR} 63 | # ) 64 | 65 | target_link_libraries(barnes-hut-simulator 66 | PUBLIC 67 | SDL 68 | X11 69 | OpenGL::GL 70 | OpenGL::GLU 71 | OpenMP::OpenMP_CXX 72 | ) 73 | -------------------------------------------------------------------------------- /src/IntegratorRK4.cpp: -------------------------------------------------------------------------------- 1 | #include "IntegratorRK4.h" 2 | 3 | //--- Standard includes -------------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | IntegratorRK4::IntegratorRK4(IModel *pModel, double h) 10 | :IIntegrator(pModel, h) 11 | ,_state(new double[pModel->GetDim()]) 12 | ,_tmp(new double[pModel->GetDim()]) 13 | ,_k1(new double[pModel->GetDim()]) 14 | ,_k2(new double[pModel->GetDim()]) 15 | ,_k3(new double[pModel->GetDim()]) 16 | ,_k4(new double[pModel->GetDim()]) 17 | { 18 | if (pModel == nullptr) 19 | throw std::runtime_error("Model pointer may not be NULL."); 20 | 21 | std::stringstream ss; 22 | ss << "RK4 (dt=" << m_h << ")"; 23 | SetID(ss.str()); 24 | } 25 | 26 | 27 | IntegratorRK4::~IntegratorRK4() 28 | { 29 | delete[] _state; 30 | delete[] _tmp; 31 | delete[] _k1; 32 | delete[] _k2; 33 | delete[] _k3; 34 | delete[] _k4; 35 | } 36 | 37 | 38 | /** \brief Performs a single integration step. */ 39 | void IntegratorRK4::SingleStep() 40 | { 41 | assert(m_pModel); 42 | 43 | // k1 44 | m_pModel->Eval(_state, m_time, _k1); 45 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 46 | _tmp[i] = _state[i] + m_h * 0.5 * _k1[i]; 47 | 48 | // k2 49 | m_pModel->Eval(_tmp, m_time + m_h * 0.5, _k2); 50 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 51 | _tmp[i] = _state[i] + m_h * 0.5 * _k2[i]; 52 | 53 | // k3 54 | m_pModel->Eval(_tmp, m_time + m_h * 0.5, _k3); 55 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 56 | _tmp[i] = _state[i] + m_h * _k3[i]; 57 | 58 | // k4 59 | m_pModel->Eval(_tmp, m_time + m_h, _k4); 60 | 61 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 62 | _state[i] += m_h / 6 * (_k1[i] + 2 * (_k2[i] + _k3[i]) + _k4[i]); 63 | 64 | m_time += m_h; 65 | } 66 | 67 | 68 | /** \brief Sets the initial state of the simulation. */ 69 | void IntegratorRK4::SetInitialState(double *state) 70 | { 71 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 72 | { 73 | _state[i] = state[i]; 74 | _k1[i] = 0; 75 | _k2[i] = 0; 76 | _k3[i] = 0; 77 | _k4[i] = 0; 78 | } 79 | 80 | m_time = 0; 81 | } 82 | 83 | 84 | double *IntegratorRK4::GetState() const 85 | { 86 | return _state; 87 | } 88 | -------------------------------------------------------------------------------- /include/ModelNBody.h: -------------------------------------------------------------------------------- 1 | #ifndef _MODEL_N_BODY_H 2 | #define _MODEL_N_BODY_H 3 | 4 | #include 5 | 6 | #include "Constants.h" 7 | #include "IModel.h" 8 | #include "Vector.h" 9 | #include "BHTree.h" 10 | #include "Types.h" 11 | 12 | 13 | /** \brief Model class for handling th n-body problem. */ 14 | class ModelNBody final : public IModel 15 | { 16 | public: 17 | 18 | ModelNBody(); 19 | virtual ~ModelNBody(); 20 | 21 | void Init(); 22 | void InitCollision(); 23 | void Init3Body(); 24 | 25 | virtual void Eval(double *state, double time, double *deriv) override; 26 | virtual bool IsFinished(double *state) override; 27 | virtual double* GetInitialState() override; 28 | 29 | double GetSuggestedTimeStep() const; 30 | double GetTheta() const; 31 | BHTreeNode* GetRootNode(); 32 | const PODAuxState* GetAuxState() const; 33 | int GetN() const; 34 | 35 | const Vec3D& GetCamDir() const; 36 | const Vec3D& GetCamPos() const; 37 | Vec3D GetCenterOfMass() const; 38 | 39 | void SetTheta(double theta); 40 | void SetVerbose(bool bVerbose); 41 | void SetROI(double roi); 42 | double GetROI() const; 43 | 44 | private: 45 | 46 | void CalcBHArea(const ParticleData &p); 47 | void BuiltTree(const ParticleData &p); 48 | void GetOrbitalVelocity(const ParticleData &p1, const ParticleData &p2); 49 | void ResetDim(int num, double stepsize); 50 | 51 | PODState *_pInitial; ///< The initial state 52 | PODAuxState *_pAux; ///< Auxilliary state information 53 | 54 | BHTreeNode _root; ///< The root node of the barnes hut tree 55 | Vec2D _min; ///< Upper left corner of the bounding box containing all particles 56 | Vec2D _max; ///< Lower right corner of the bounding box containing all particles 57 | Vec2D _center; ///< The center of the simulation, the barnes hut tree is centered at this point 58 | Vec3D _camDir; ///< Direction of the camera 59 | Vec3D _camPos; ///< Position of the camera 60 | double _roi; 61 | double _timeStep; 62 | 63 | static constexpr double gamma_1 = Constants::Gamma / (Constants::ParsecInMeter * Constants::ParsecInMeter * Constants::ParsecInMeter) * Constants::MassOfSun * (365.25 * 86400) * (365.25 * 86400); 64 | 65 | int _num; 66 | bool _bVerbose; 67 | }; 68 | 69 | #endif 70 | 71 | -------------------------------------------------------------------------------- /include/SDLWnd.h: -------------------------------------------------------------------------------- 1 | #ifndef _SDL_WINDOW_H 2 | #define _SDL_WINDOW_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include // opengl support 9 | #include // Header File For The OpenGL32 Library 10 | #include // Header File For The GLu32 Library 11 | 12 | #include "Vector.h" 13 | 14 | 15 | /** \brief Basic infrastructure for grafical output using SDL/OpenGL */ 16 | class SDLWindow 17 | { 18 | public: 19 | SDLWindow(int width, int height, double axisLen, const std::string &caption); 20 | virtual ~SDLWindow(); 21 | void MainLoop(); 22 | void ExitMainLoop(); 23 | void SetCaption(const std::string &caption); 24 | int GetWidth() const; 25 | int GetHeight() const; 26 | virtual void Render() = 0; 27 | virtual void Update() = 0; 28 | 29 | protected: 30 | virtual void PollEvents(); 31 | virtual void OnProcessEvents(uint8_t type); 32 | 33 | //----------------------------------------- 34 | // Camera setup 35 | //----------------------------------------- 36 | 37 | const Vec3D &GetCamPos() const; 38 | const Vec3D &GetCamOrient() const; 39 | const Vec3D &GetCamLookAt() const; 40 | void SetCameraOrientation(const Vec3D &orientation); 41 | void SetCamera(const Vec3D &pos, const Vec3D &lookAt, const Vec3D &orient); 42 | void AdjustCamera(); 43 | 44 | //----------------------------------------- 45 | // Basic graphics functionality 46 | //----------------------------------------- 47 | 48 | void DrawAxis(const Vec2D &origin); 49 | int GetFPS() const; 50 | void SaveToTGA(const std::string &sName); 51 | void SaveToTGA(int idx = -1); 52 | 53 | //----------------------------------------- 54 | // misc 55 | //----------------------------------------- 56 | 57 | void ScaleAxis(double scale); 58 | double GetFOV() const; 59 | SDL_Surface *Surface(); 60 | SDL_Event _event; 61 | 62 | static void InitFont(); 63 | static void KillFont(); 64 | static void TextOut(const char *fmt, ...); 65 | static void TextOut(int x, int y, const char *fmt, ...); 66 | static Vec3D GetOGLPos(int x, int y); 67 | 68 | static GLuint s_fontBase; 69 | 70 | private: 71 | void InitGL(); 72 | 73 | double _fov; ///< Length of an axis 74 | int _width; ///< Width of the window in pixel 75 | int _height; ///< Height of the window in pixel 76 | int _fps; 77 | int _idxSnapshot; 78 | 79 | Vec3D _camPos; ///< Position of the camera 80 | Vec3D _camLookAt; ///< Point atwhich the camera is aimed 81 | Vec3D _camOrient; ///< orientation of the camera (rotation as it aims at its target) 82 | 83 | SDL_Surface *_pScreen; 84 | 85 | volatile bool _bRunning; 86 | }; 87 | 88 | #endif -------------------------------------------------------------------------------- /include/BHTree.h: -------------------------------------------------------------------------------- 1 | #ifndef BH_TREE_H 2 | #define BH_TREE_H 3 | 4 | //--- Standard includes -------------------------------------------------------- 5 | #include 6 | 7 | //--- Implementation ----------------------------------------------------------- 8 | #include "Vector.h" 9 | #include "Types.h" 10 | 11 | 12 | //------------------------------------------------------------------------------ 13 | struct State 14 | { 15 | Vec2D pos; 16 | Vec2D vel; 17 | Vec2D acc; 18 | double m; 19 | }; 20 | 21 | 22 | 23 | /** \brief Implementation of a single node of the barnes hut tree. */ 24 | class BHTreeNode 25 | { 26 | public: 27 | /** \brief Enumeration for the quadrants. */ 28 | enum EQuadrant 29 | { 30 | NE = 0, 31 | NW, 32 | SW, 33 | SE, 34 | NONE 35 | }; 36 | 37 | /** \brief A structure for holding debug information. */ 38 | struct DebugStat 39 | { 40 | int _nNumCalc; ///< Total number of calculations for estimating the force 41 | }; 42 | 43 | BHTreeNode(const Vec2D &min, 44 | const Vec2D &max, 45 | BHTreeNode *parent = nullptr); 46 | ~BHTreeNode(); 47 | 48 | void Reset(const Vec2D &min, 49 | const Vec2D &max); 50 | 51 | bool IsRoot() const; 52 | bool IsExternal() const; 53 | bool WasTooClose() const; 54 | 55 | void StatReset(); 56 | int StatGetNumCalc() const; 57 | 58 | int GetNumRenegades() const; 59 | int GetNum() const; 60 | const Vec2D &GetCenterOfMass() const; 61 | const Vec2D &GetMin() const; 62 | const Vec2D &GetMax() const; 63 | 64 | double GetTheta() const; 65 | void SetTheta(double theta); 66 | 67 | void Insert(const ParticleData &newParticle, int level); 68 | 69 | EQuadrant GetQuadrant(double x, double y) const; 70 | BHTreeNode *CreateQuadNode(EQuadrant eQuad); 71 | 72 | void ComputeMassDistribution(); 73 | 74 | Vec2D CalcForce(const ParticleData &p) const; 75 | void DumpNode(int quad, int level); 76 | 77 | public: 78 | BHTreeNode *_quadNode[4]; 79 | 80 | private: 81 | Vec2D CalcAcc(const ParticleData &p1, const ParticleData &p2) const; 82 | Vec2D CalcTreeForce(const ParticleData &p) const; 83 | 84 | /** \brief Data for the particle. 85 | 86 | Only valid if this is a leaf node. 87 | */ 88 | ParticleData _particle; 89 | 90 | double _mass; ///< Mass of all particles inside the node 91 | Vec2D _cm; ///< Center of Mass 92 | Vec2D _min; ///< Upper left edge of the node 93 | Vec2D _max; ///< Lower right edge of the node 94 | Vec2D _center; ///< Center of the node 95 | BHTreeNode *_parent; ///< The parent node 96 | int _num; ///< The number of particles in this node 97 | mutable bool _bSubdivided; ///< True if this node is too close to use the approximation for the force calculation 98 | 99 | static double s_theta; 100 | static std::vector s_renegades; 101 | 102 | public: 103 | static double s_gamma; 104 | 105 | private: 106 | static double s_soft; 107 | static DebugStat s_stat; 108 | }; 109 | 110 | #endif // BH_TREE_H 111 | -------------------------------------------------------------------------------- /src/IntegratorADB5.cpp: -------------------------------------------------------------------------------- 1 | #include "IntegratorADB5.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | IntegratorADB5::IntegratorADB5(IModel *pModel, double h) 11 | :IIntegrator(pModel, h) 12 | ,_state() 13 | ,_f() 14 | ,_rk4(pModel, h) 15 | { 16 | if (pModel == nullptr) 17 | throw std::runtime_error("Model pointer may not be NULL."); 18 | 19 | _c[0] = 1901.0 / 720.0; 20 | _c[1] = 1387.0 / 360.0; 21 | _c[2] = 109.0 / 30.0; 22 | _c[3] = 637.0 / 360.0; 23 | _c[4] = 251.0 / 720.0; 24 | 25 | _state = new double[pModel->GetDim()]; 26 | for (unsigned i = 0; i < 6; ++i) 27 | { 28 | _f[i] = new double[pModel->GetDim()]; 29 | std::memset(_f[i], 0, pModel->GetDim() * sizeof(double)); 30 | } 31 | 32 | std::stringstream ss; 33 | ss << "ADB5 (dt=" << m_h << ")"; 34 | SetID(ss.str()); 35 | } 36 | 37 | 38 | IntegratorADB5::~IntegratorADB5() 39 | { 40 | delete[] _state; 41 | 42 | for (unsigned i = 0; i < 6; ++i) 43 | delete[] _f[i]; 44 | } 45 | 46 | 47 | /** \brief Performs a single integration step. */ 48 | void IntegratorADB5::SingleStep() 49 | { 50 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 51 | { 52 | _state[i] += m_h * (_c[0] * _f[4][i] - 53 | _c[1] * _f[3][i] + 54 | _c[2] * _f[2][i] - 55 | _c[3] * _f[1][i] + 56 | _c[4] * _f[0][i]); 57 | 58 | _f[0][i] = _f[1][i]; 59 | _f[1][i] = _f[2][i]; 60 | _f[2][i] = _f[3][i]; 61 | _f[3][i] = _f[4][i]; 62 | } 63 | 64 | m_time += m_h; 65 | m_pModel->Eval(_state, m_time, _f[4]); 66 | } 67 | 68 | 69 | /** \brief Sets the initial state of the simulation. */ 70 | void IntegratorADB5::SetInitialState(double *state) 71 | { 72 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 73 | _state[i] = state[i]; 74 | 75 | m_time = 0; 76 | double k1[m_pModel->GetDim()], 77 | k2[m_pModel->GetDim()], 78 | k3[m_pModel->GetDim()], 79 | k4[m_pModel->GetDim()], 80 | tmp[m_pModel->GetDim()]; 81 | 82 | for (std::size_t n = 0; n < 4; ++n) 83 | { 84 | // k1 85 | m_pModel->Eval(_state, m_time, k1); 86 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 87 | tmp[i] = _state[i] + m_h * 0.5 * k1[i]; 88 | 89 | // k2 90 | m_pModel->Eval(tmp, m_time + m_h * 0.5, k2); 91 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 92 | tmp[i] = _state[i] + m_h * 0.5 * k2[i]; 93 | 94 | // k3 95 | m_pModel->Eval(tmp, m_time + m_h * 0.5, k3); 96 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 97 | tmp[i] = _state[i] + m_h * k3[i]; 98 | 99 | // k4 100 | m_pModel->Eval(tmp, m_time + m_h, k4); 101 | 102 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 103 | { 104 | _state[i] += m_h / 6 * (k1[i] + 2 * (k2[i] + k3[i]) + k4[i]); 105 | _f[n][i] = k1[i]; 106 | } 107 | 108 | m_time += m_h; 109 | } 110 | 111 | m_pModel->Eval(_state, m_time, _f[4]); 112 | } 113 | 114 | 115 | double *IntegratorADB5::GetState() const 116 | { 117 | return _state; 118 | } 119 | -------------------------------------------------------------------------------- /src/IntegratorRK5.cpp: -------------------------------------------------------------------------------- 1 | #include "IntegratorRK5.h" 2 | 3 | //--- Standard includes -------------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | IntegratorRK5::IntegratorRK5(IModel *pModel, double h) 10 | :IIntegrator(pModel, h) 11 | ,_state(new double[pModel->GetDim()]) 12 | ,_tmp(new double[pModel->GetDim()]) 13 | ,_k1(new double[pModel->GetDim()]) 14 | ,_k2(new double[pModel->GetDim()]) 15 | ,_k3(new double[pModel->GetDim()]) 16 | ,_k4(new double[pModel->GetDim()]) 17 | ,_k5(new double[pModel->GetDim()]) 18 | ,_k6(new double[pModel->GetDim()]) 19 | { 20 | if (pModel == nullptr) 21 | throw std::runtime_error("Model pointer may not be NULL."); 22 | 23 | std::stringstream ss; 24 | ss << "RK5 (dt=" << m_h << ")"; 25 | SetID(ss.str()); 26 | } 27 | 28 | 29 | IntegratorRK5::~IntegratorRK5() 30 | { 31 | delete[] _state; 32 | delete[] _tmp; 33 | delete[] _k1; 34 | delete[] _k2; 35 | delete[] _k3; 36 | delete[] _k4; 37 | delete[] _k5; 38 | delete[] _k6; 39 | } 40 | 41 | 42 | /** \brief Performs a single integration step. */ 43 | void IntegratorRK5::SingleStep() 44 | { 45 | assert(m_pModel); 46 | 47 | // k1 48 | m_pModel->Eval(_state, m_time, _k1); 49 | 50 | // k2 51 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 52 | _tmp[i] = _state[i] + 0.25 * m_h * _k1[i]; 53 | 54 | m_pModel->Eval(_tmp, m_time + 0.25 * m_h, _k2); 55 | 56 | // k3 57 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 58 | _tmp[i] = _state[i] + m_h * (3.0 / 32.0 * _k1[i] + 9.0 / 32.0 * _k2[i]); 59 | 60 | m_pModel->Eval(_tmp, m_time + 3.0 / 8.0 * m_h, _k3); 61 | 62 | // k4 63 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 64 | _tmp[i] = _state[i] + m_h * (1932.0 / 2197.0 * _k1[i] - 7200.0 / 2197.0 * _k2[i] + 7296.0 / 2197.0 * _k3[i]); 65 | 66 | m_pModel->Eval(_tmp, m_time + 12.0 / 13.0 * m_h, _k4); 67 | 68 | // k5 69 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 70 | _tmp[i] = _state[i] + m_h * (439.0 / 216.0 * _k1[i] - 8.0 * _k2[i] + 3680.0 / 513.0 * _k3[i] - 845.0 / 4104.0 * _k4[i]); 71 | 72 | m_pModel->Eval(_tmp, m_time + m_h, _k5); 73 | 74 | // K6 75 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 76 | _tmp[i] = _state[i] + m_h * (-8.0 / 27.0 * _k1[i] + 2.0 * _k2[i] - 3544.0 / 2565.0 * _k3[i] + 1859.0 / 4104.0 * _k4[i] - 11.0 / 40.0 * _k5[i]); 77 | 78 | m_pModel->Eval(_tmp, m_time + 0.5 * m_h, _k6); 79 | 80 | // rk5 81 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 82 | _state[i] += m_h * (16.0 / 135.0 * _k1[i] + 83 | 6656.0 / 12825.0 * _k3[i] + 84 | 28561.0 / 56430.0 * _k4[i] - 85 | 9.0 / 50.0 * _k5[i] + 86 | 2.0 / 55.0 * _k6[i]); 87 | 88 | m_time += m_h; 89 | } 90 | 91 | 92 | /** \brief Sets the initial state of the simulation. */ 93 | void IntegratorRK5::SetInitialState(double *state) 94 | { 95 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 96 | { 97 | _state[i] = state[i]; 98 | _tmp[i] = 0; 99 | _k1[i] = 0; 100 | _k2[i] = 0; 101 | _k3[i] = 0; 102 | _k4[i] = 0; 103 | _k5[i] = 0; 104 | _k6[i] = 0; 105 | } 106 | 107 | m_time = 0; 108 | } 109 | 110 | 111 | double *IntegratorRK5::GetState() const 112 | { 113 | return _state; 114 | } 115 | -------------------------------------------------------------------------------- /src/IntegratorADB6.cpp: -------------------------------------------------------------------------------- 1 | #include "IntegratorADB6.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | IntegratorADB6::IntegratorADB6(IModel *model, double h) 11 | :IIntegrator(model, h) 12 | ,_state() 13 | ,_f() 14 | { 15 | if (model == nullptr) 16 | throw std::runtime_error("Model pointer may not be NULL."); 17 | 18 | _c[0] = 4277.0 / 1440.0; 19 | _c[1] = -7923.0 / 1440.0; 20 | _c[2] = 9982.0 / 1440.0; 21 | _c[3] = -7298.0 / 1440.0; 22 | _c[4] = 2877.0 / 1440.0; 23 | _c[5] = -475.0 / 1440.0; 24 | 25 | _state = new double[model->GetDim()]; 26 | for (unsigned i = 0; i < 6; ++i) 27 | { 28 | _f[i] = new double[model->GetDim()]; 29 | std::memset(_f[i], 0, model->GetDim() * sizeof(double)); 30 | } 31 | 32 | std::stringstream ss; 33 | ss << "ADB6 (dt=" << m_h << ")"; 34 | SetID(ss.str()); 35 | } 36 | 37 | 38 | IntegratorADB6::~IntegratorADB6() 39 | { 40 | delete[] _state; 41 | 42 | for (unsigned i = 0; i < 6; ++i) 43 | delete[] _f[i]; 44 | } 45 | 46 | 47 | void IntegratorADB6::Reverse() 48 | { 49 | m_h *= -1; 50 | SetInitialState(GetState()); 51 | } 52 | 53 | 54 | /** \brief Performs a single integration step. */ 55 | void IntegratorADB6::SingleStep() 56 | { 57 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 58 | { 59 | _state[i] += m_h * (_c[0] * _f[5][i] + 60 | _c[1] * _f[4][i] + 61 | _c[2] * _f[3][i] + 62 | _c[3] * _f[2][i] + 63 | _c[4] * _f[1][i] + 64 | _c[5] * _f[0][i]); 65 | 66 | _f[0][i] = _f[1][i]; 67 | _f[1][i] = _f[2][i]; 68 | _f[2][i] = _f[3][i]; 69 | _f[3][i] = _f[4][i]; 70 | _f[4][i] = _f[5][i]; 71 | } 72 | 73 | m_time += m_h; 74 | m_pModel->Eval(_state, m_time, _f[5]); 75 | } 76 | 77 | 78 | /** \brief Sets the initial state of the simulation. */ 79 | void IntegratorADB6::SetInitialState(double *state) 80 | { 81 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 82 | _state[i] = state[i]; 83 | 84 | m_time = 0; 85 | double k1[m_pModel->GetDim()], 86 | k2[m_pModel->GetDim()], 87 | k3[m_pModel->GetDim()], 88 | k4[m_pModel->GetDim()], 89 | tmp[m_pModel->GetDim()]; 90 | 91 | for (std::size_t n = 0; n < 5; ++n) 92 | { 93 | // k1 94 | m_pModel->Eval(_state, m_time, k1); 95 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 96 | tmp[i] = _state[i] + m_h * 0.5 * k1[i]; 97 | 98 | // k2 99 | m_pModel->Eval(tmp, m_time + m_h * 0.5, k2); 100 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 101 | tmp[i] = _state[i] + m_h * 0.5 * k2[i]; 102 | 103 | // k3 104 | m_pModel->Eval(tmp, m_time + m_h * 0.5, k3); 105 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 106 | tmp[i] = _state[i] + m_h * k3[i]; 107 | 108 | // k4 109 | m_pModel->Eval(tmp, m_time + m_h, k4); 110 | 111 | for (std::size_t i = 0; i < m_pModel->GetDim(); ++i) 112 | { 113 | _state[i] += m_h / 6 * (k1[i] + 2 * (k2[i] + k3[i]) + k4[i]); 114 | _f[n][i] = k1[i]; 115 | } 116 | 117 | m_time += m_h; 118 | } 119 | m_pModel->Eval(_state, m_time, _f[5]); 120 | } 121 | 122 | 123 | double *IntegratorADB6::GetState() const 124 | { 125 | return _state; 126 | } 127 | -------------------------------------------------------------------------------- /src/IntegratorRKF4.cpp: -------------------------------------------------------------------------------- 1 | #include "IntegratorRKF4.h" 2 | 3 | //--- Standard includes -------------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | IntegratorRKF4::IntegratorRKF4(IModel *pModel, double h) 12 | :IIntegrator(pModel, h) 13 | ,_state(new double[pModel->GetDim()]) 14 | ,_tmp(new double[pModel->GetDim()]) 15 | ,_k1(new double[pModel->GetDim()]) 16 | ,_k2(new double[pModel->GetDim()]) 17 | ,_k3(new double[pModel->GetDim()]) 18 | ,_k4(new double[pModel->GetDim()]) 19 | ,_k5(new double[pModel->GetDim()]) 20 | ,_k6(new double[pModel->GetDim()]) 21 | ,_error(new double[pModel->GetDim()]) 22 | ,_maxErr(0.005) 23 | { 24 | if (pModel == nullptr) 25 | throw std::runtime_error("Model pointer may not be NULL."); 26 | 27 | std::stringstream ss; 28 | ss << "RKF4 (dt=" << m_h << ")"; 29 | SetID(ss.str()); 30 | } 31 | 32 | 33 | IntegratorRKF4::~IntegratorRKF4() 34 | { 35 | delete[] _state; 36 | delete[] _tmp; 37 | delete[] _k1; 38 | delete[] _k2; 39 | delete[] _k3; 40 | delete[] _k4; 41 | delete[] _k5; 42 | delete[] _k6; 43 | delete[] _error; 44 | } 45 | 46 | 47 | /** \brief Performs a single integration step. */ 48 | void IntegratorRKF4::SingleStep() 49 | { 50 | assert(m_pModel); 51 | 52 | // k1 53 | m_pModel->Eval(_state, m_time, _k1); 54 | 55 | // k2 56 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 57 | _tmp[i] = _state[i] + 0.25 * m_h * _k1[i]; 58 | 59 | m_pModel->Eval(_tmp, m_time + 0.25 * m_h, _k2); 60 | 61 | // k3 62 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 63 | _tmp[i] = _state[i] + m_h * (3.0 / 32.0 * _k1[i] + 9.0 / 32.0 * _k2[i]); 64 | 65 | m_pModel->Eval(_tmp, m_time + 3.0 / 8.0 * m_h, _k3); 66 | 67 | // k4 68 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 69 | _tmp[i] = _state[i] + m_h * (1932.0 / 2197.0 * _k1[i] - 7200.0 / 2197.0 * _k2[i] + 7296.0 / 2197.0 * _k3[i]); 70 | 71 | m_pModel->Eval(_tmp, m_time + 12.0 / 13.0 * m_h, _k4); 72 | 73 | // k5 74 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 75 | _tmp[i] = _state[i] + m_h * (439.0 / 216.0 * _k1[i] - 8.0 * _k2[i] + 3680.0 / 513.0 * _k3[i] - 845.0 / 4104.0 * _k4[i]); 76 | 77 | m_pModel->Eval(_tmp, m_time + m_h, _k5); 78 | 79 | // K6 80 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 81 | _tmp[i] = _state[i] + m_h * (-8.0 / 27.0 * _k1[i] - 2.0 * _k2[i] - 3544.0 / 2565.0 * _k3[i] + 1859.0 / 4104.0 * _k4[i] - 11.0 / 55.0 * _k5[i]); 82 | 83 | m_pModel->Eval(_tmp, m_time + 0.5 * m_h, _k6); 84 | 85 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 86 | _state[i] += m_h * (25.0 / 216.0 * _k1[i] + 87 | 1408.0 / 2565.0 * _k3[i] + 88 | 2197.0 / 4104.0 * _k4[i] - 89 | 1.0 / 5.0 * _k5[i]); 90 | 91 | // Fehler 92 | m_err = 0; 93 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 94 | { 95 | double e = m_h * (1.0 / 360.0 * _k1[i] - 96 | 128.0 / 4275.0 * _k3[i] - 97 | 2197.0 / 75240.0 * _k4[i] + 98 | 1.0 / 50.0 * _k5[i] - 99 | 2.0 / 55.0 * _k6[i]); 100 | m_err += e * e; 101 | } 102 | 103 | m_err = std::sqrt(m_err); 104 | 105 | double h = m_h * std::pow(_maxErr / m_err, 0.25); 106 | if (h > 2.0 * m_h) 107 | { 108 | m_h = h; 109 | } 110 | else if (h < m_h) 111 | { 112 | m_h = 0.75 * h; 113 | } 114 | 115 | m_time += m_h; 116 | } 117 | 118 | 119 | /** \brief Sets the initial state of the simulation. */ 120 | void IntegratorRKF4::SetInitialState(double *state) 121 | { 122 | for (unsigned i = 0; i < m_pModel->GetDim(); ++i) 123 | { 124 | _state[i] = state[i]; 125 | _k1[i] = 0; 126 | _k2[i] = 0; 127 | _k3[i] = 0; 128 | _k4[i] = 0; 129 | _k5[i] = 0; 130 | _k6[i] = 0; 131 | } 132 | 133 | m_time = 0; 134 | } 135 | 136 | 137 | double *IntegratorRKF4::GetState() const 138 | { 139 | return _state; 140 | } 141 | 142 | 143 | void IntegratorRKF4::SetMaximumError(double maxErr) 144 | { 145 | _maxErr = maxErr; 146 | } 147 | -------------------------------------------------------------------------------- /src/SDLWnd.cpp: -------------------------------------------------------------------------------- 1 | #include "SDLWnd.h" 2 | 3 | //--- Standard includes ------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include // Header File For The OpenGL32 Library 13 | #include // Header File For The GLu32 Library 14 | #include // Header file fot the glx libraries. 15 | 16 | // static functions / variables 17 | GLuint SDLWindow::s_fontBase = 0; 18 | 19 | 20 | void SDLWindow::InitFont() 21 | { 22 | Display *dpy; /* Our current X display */ 23 | XFontStruct *fontInfo; /* Our font info */ 24 | 25 | /* Sotrage for 96 characters */ 26 | s_fontBase = glGenLists(96); 27 | 28 | /* Get our current display long enough to get the fonts */ 29 | dpy = XOpenDisplay(nullptr); 30 | 31 | /* Get the font information */ 32 | fontInfo = XLoadQueryFont(dpy, "-adobe-helvetica-medium-r-normal--18-*-*-*-p-*-iso8859-1"); 33 | 34 | /* If the above font didn't exist try one that should */ 35 | if (fontInfo == nullptr) 36 | { 37 | fontInfo = XLoadQueryFont(dpy, "fixed"); 38 | 39 | /* If that font doesn't exist, something is wrong */ 40 | if (fontInfo == nullptr) 41 | throw std::runtime_error("no X font available?"); 42 | } 43 | 44 | /* generate the list */ 45 | glXUseXFont(fontInfo->fid, 32, 96, s_fontBase); 46 | 47 | /* Recover some memory */ 48 | XFreeFont(dpy, fontInfo); 49 | 50 | /* close the display now that we're done with it */ 51 | XCloseDisplay(dpy); 52 | } 53 | 54 | 55 | void SDLWindow::KillFont() 56 | { 57 | glDeleteLists(s_fontBase, 96); 58 | } 59 | 60 | 61 | /* Print our GL text to the screen */ 62 | void SDLWindow::TextOut(const char *fmt, ...) 63 | { 64 | char text[256]; /* Holds our string */ 65 | va_list ap; /* Pointer to our list of elements */ 66 | 67 | /* If there's no text, do nothing */ 68 | if (fmt == nullptr) 69 | return; 70 | 71 | /* Parses The String For Variables */ 72 | va_start(ap, fmt); 73 | 74 | /* Converts Symbols To Actual Numbers */ 75 | vsprintf(text, fmt, ap); 76 | va_end(ap); 77 | 78 | glPushAttrib(GL_LIST_BIT); // Pushes the Display List Bits 79 | glListBase(s_fontBase - 32); // Sets base character to 32 80 | glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws the text 81 | glPopAttrib(); // Pops the Display List Bits 82 | } 83 | 84 | 85 | void SDLWindow::TextOut(int x, int y, const char *fmt, ...) 86 | { 87 | Vec3D p = GetOGLPos(x, y); 88 | glRasterPos2f(p.x, p.y); 89 | 90 | char text[256]; /* Holds our string */ 91 | va_list ap; /* Pointer to our list of elements */ 92 | 93 | /* If there's no text, do nothing */ 94 | if (fmt == nullptr) 95 | return; 96 | 97 | /* Parses The String For Variables */ 98 | va_start(ap, fmt); 99 | 100 | /* Converts Symbols To Actual Numbers */ 101 | vsprintf(text, fmt, ap); 102 | va_end(ap); 103 | 104 | glPushAttrib(GL_LIST_BIT); // Pushes the Display List Bits 105 | glListBase(s_fontBase - 32); // Sets base character to 32 106 | glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws the text 107 | glPopAttrib(); // Pops the Display List Bits 108 | } 109 | 110 | 111 | /** \brief get opengl position from a screen position 112 | 113 | see also: http://nehe.gamedev.net/data/articles/article.asp?article=13 114 | */ 115 | Vec3D SDLWindow::GetOGLPos(int x, int y) 116 | { 117 | GLint viewport[4]; 118 | GLdouble modelview[16]; 119 | GLdouble projection[16]; 120 | GLfloat winX, winY, winZ; 121 | GLdouble posX, posY, posZ; 122 | 123 | glGetDoublev(GL_MODELVIEW_MATRIX, modelview); 124 | glGetDoublev(GL_PROJECTION_MATRIX, projection); 125 | glGetIntegerv(GL_VIEWPORT, viewport); 126 | 127 | winX = (float)x; 128 | winY = (float)viewport[3] - (float)y; 129 | glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); 130 | 131 | gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ); 132 | 133 | return Vec3D(posX, posY, posZ); 134 | } 135 | 136 | 137 | SDLWindow::SDLWindow(int width, int height, double axisLen, const std::string &caption) 138 | :_event() 139 | ,_fov(axisLen) 140 | ,_width(0) 141 | ,_height(0) 142 | ,_fps(0) 143 | ,_idxSnapshot(0) 144 | ,_camPos(0, 0, 2) 145 | ,_camLookAt(0, 0, 0) 146 | ,_camOrient(0, 1, 0) 147 | ,_pScreen(nullptr) 148 | ,_bRunning(true) 149 | { 150 | if (SDL_Init(SDL_INIT_VIDEO) == -1) 151 | throw std::runtime_error(SDL_GetError()); 152 | atexit(SDL_Quit); 153 | 154 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 155 | 156 | _pScreen = SDL_SetVideoMode(width, height, 16, SDL_OPENGL); 157 | if (!_pScreen) 158 | throw std::runtime_error(SDL_GetError()); 159 | 160 | SetCaption(caption); 161 | 162 | _width = width; 163 | _height = height; 164 | 165 | InitGL(); 166 | } 167 | 168 | 169 | SDLWindow::~SDLWindow() 170 | { 171 | KillFont(); 172 | SDL_Quit(); 173 | } 174 | 175 | 176 | void SDLWindow::InitGL() // We call this right after our OpenGL window is created. 177 | { 178 | glShadeModel(GL_SMOOTH); 179 | glClearColor(0.0f, 0.0f, 0.1f, 0.0f); // black background 180 | glViewport(0, 0, GetWidth(), GetHeight()); 181 | 182 | SDLWindow::InitFont(); 183 | } 184 | 185 | 186 | void SDLWindow::SaveToTGA(int idx) 187 | { 188 | if (idx == -1) 189 | _idxSnapshot++; 190 | else 191 | _idxSnapshot = idx; 192 | 193 | std::stringstream ss; 194 | ss << "frame_" << std::setw(5) << std::setfill('0') << _idxSnapshot << ".tga"; 195 | SaveToTGA(ss.str()); 196 | } 197 | 198 | 199 | void SDLWindow::SaveToTGA(const std::string &sName) 200 | { 201 | using std::ios; 202 | 203 | int nSize = GetWidth() * GetHeight() * 3; 204 | 205 | GLubyte pixels[nSize]; 206 | glReadPixels(0, 0, GetWidth(), GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, pixels); 207 | 208 | std::string sFile; 209 | if (sName.length()) 210 | sFile = sName; 211 | else 212 | { 213 | // use default name with time stamp 214 | time_t t = time(nullptr); 215 | struct tm *tmp = localtime(&t); 216 | if (tmp == nullptr) 217 | sFile = "snapshot.tga"; 218 | else 219 | { 220 | char szTime[1024]; 221 | if (strftime(szTime, sizeof(szTime), "snapshot_%Y%m%d_%H%M%S.tga", tmp) == 0) 222 | sFile = "snapshot.tga"; 223 | else 224 | sFile = szTime; 225 | } 226 | } 227 | 228 | std::fstream file(sFile.c_str(), ios::out | ios::binary | ios::trunc); 229 | char TGAheader[12] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 230 | char header[6] = {(char)(GetWidth() % 256), 231 | (char)(GetWidth() / 256), 232 | (char)(GetHeight() % 256), 233 | (char)(GetHeight() / 256), 234 | 24, 235 | 0}; 236 | file.write(TGAheader, sizeof(TGAheader)); 237 | file.write(header, sizeof(header)); 238 | 239 | // convert to BGR format 240 | for (int i = 0; i < nSize; i += 3) 241 | std::swap(pixels[i], pixels[i + 2]); 242 | 243 | file.write(reinterpret_cast(pixels), nSize); 244 | file.close(); 245 | } 246 | 247 | 248 | void SDLWindow::ScaleAxis(double scale) 249 | { 250 | _fov *= scale; 251 | AdjustCamera(); 252 | } 253 | 254 | 255 | const Vec3D &SDLWindow::GetCamPos() const 256 | { 257 | return _camPos; 258 | } 259 | 260 | 261 | const Vec3D &SDLWindow::GetCamOrient() const 262 | { 263 | return _camOrient; 264 | } 265 | 266 | 267 | const Vec3D &SDLWindow::GetCamLookAt() const 268 | { 269 | return _camLookAt; 270 | } 271 | 272 | 273 | void SDLWindow::SetCameraOrientation(const Vec3D &orient) 274 | { 275 | _camOrient = orient; 276 | AdjustCamera(); 277 | } 278 | 279 | 280 | void SDLWindow::SetCamera(const Vec3D &pos, const Vec3D &lookAt, const Vec3D &orient) 281 | { 282 | _camOrient = orient; 283 | _camPos = pos; 284 | _camLookAt = lookAt; 285 | AdjustCamera(); 286 | } 287 | 288 | 289 | void SDLWindow::AdjustCamera() 290 | { 291 | glMatrixMode(GL_PROJECTION); 292 | glLoadIdentity(); 293 | 294 | double l = _fov / 2.0; 295 | glOrtho(-l, l, -l, l, -l, l); 296 | gluLookAt(_camPos.x, _camPos.y, _camPos.z, 297 | _camLookAt.x, _camLookAt.y, _camLookAt.z, 298 | _camOrient.x, _camOrient.y, _camOrient.z); 299 | glMatrixMode(GL_MODELVIEW); 300 | } 301 | 302 | 303 | void SDLWindow::SetCaption(const std::string &caption) 304 | { 305 | SDL_WM_SetCaption(caption.c_str(), NULL); 306 | } 307 | 308 | 309 | double SDLWindow::GetFOV() const 310 | { 311 | return _fov; 312 | } 313 | 314 | 315 | int SDLWindow::GetFPS() const 316 | { 317 | return _fps; 318 | } 319 | 320 | 321 | void SDLWindow::DrawAxis(const Vec2D &origin) 322 | { 323 | glColor3f(0.3, 0.3, 0.3); 324 | 325 | double s = std::pow(10, (int)(log10(_fov / 2))), 326 | l = _fov / 100, 327 | p = 0; 328 | 329 | glPushMatrix(); 330 | glTranslated(origin.x, origin.y, 0); 331 | 332 | for (int i = 0; p < _fov; ++i) 333 | { 334 | p += s; 335 | 336 | if (i % 2 == 0) 337 | { 338 | glRasterPos2f(p - l, -4 * l); 339 | TextOut("%2.0f", p); 340 | } 341 | else 342 | { 343 | glRasterPos2f(p - l, 2 * l); 344 | TextOut("%2.0f", p); 345 | } 346 | 347 | glBegin(GL_LINES); 348 | glVertex3f(p, -l, 0); 349 | glVertex3f(p, l, 0); 350 | 351 | glVertex3f(-p, -l, 0); 352 | glVertex3f(-p, 0, 0); 353 | glVertex3f(-l, p, 0); 354 | glVertex3f(0, p, 0); 355 | glVertex3f(-l, -p, 0); 356 | glVertex3f(0, -p, 0); 357 | glEnd(); 358 | } 359 | 360 | glBegin(GL_LINES); 361 | glVertex3f(-_fov, 0, 0); 362 | glVertex3f(_fov, 0, 0); 363 | glVertex3f(0, -_fov, 0); 364 | glVertex3f(0, _fov, 0); 365 | glEnd(); 366 | 367 | glPopMatrix(); 368 | } 369 | 370 | 371 | void SDLWindow::MainLoop() 372 | { 373 | int ct = 0; 374 | double dt = 0; 375 | time_t t1(time(nullptr)), t2; 376 | 377 | while (_bRunning) 378 | { 379 | ++ct; 380 | 381 | Update(); 382 | Render(); 383 | 384 | PollEvents(); 385 | 386 | t2 = time(nullptr); 387 | dt = difftime(t2, t1); 388 | if (dt > 1) 389 | { 390 | _fps = (double)ct / dt; 391 | ct = 0; 392 | t1 = t2; 393 | } 394 | } 395 | } 396 | 397 | 398 | SDL_Surface *SDLWindow::Surface() 399 | { 400 | return _pScreen; 401 | } 402 | 403 | 404 | int SDLWindow::GetWidth() const 405 | { 406 | return _width; 407 | } 408 | 409 | 410 | int SDLWindow::GetHeight() const 411 | { 412 | return _height; 413 | } 414 | 415 | 416 | void SDLWindow::ExitMainLoop() 417 | { 418 | _bRunning = false; 419 | } 420 | 421 | 422 | void SDLWindow::OnProcessEvents(uint8_t type) 423 | { 424 | } 425 | 426 | 427 | void SDLWindow::PollEvents() 428 | { 429 | while (SDL_PollEvent(&_event)) 430 | { 431 | switch (_event.type) 432 | { 433 | case SDL_QUIT: 434 | ExitMainLoop(); 435 | break; 436 | 437 | default: 438 | OnProcessEvents(_event.type); 439 | break; 440 | } // switch event type 441 | } 442 | } 443 | -------------------------------------------------------------------------------- /src/BHTree.cpp: -------------------------------------------------------------------------------- 1 | #include "BHTree.h" 2 | 3 | //--- Standard includes -------------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | //------------------------------------------------------------------------------ 13 | // static variables 14 | double BHTreeNode::s_theta = 0.9; 15 | std::vector BHTreeNode::s_renegades; 16 | BHTreeNode::DebugStat BHTreeNode::s_stat = {0}; 17 | double BHTreeNode::s_gamma = 0; // gravitational constant is set from the outside 18 | double BHTreeNode::s_soft = 0.1 * 0.1; // approx. 3 light year 19 | 20 | 21 | BHTreeNode::BHTreeNode(const Vec2D &min, 22 | const Vec2D &max, 23 | BHTreeNode *parent) 24 | :_particle() 25 | ,_mass(0) 26 | ,_cm() 27 | ,_min(min) 28 | ,_max(max) 29 | ,_center(min.x + (max.x - min.x) / 2.0, min.y + (max.y - min.y) / 2.0) 30 | ,_parent(parent) 31 | ,_num(0) 32 | ,_bSubdivided(false) 33 | { 34 | _quadNode[0] = _quadNode[1] = _quadNode[2] = _quadNode[3] = nullptr; 35 | } 36 | 37 | 38 | bool BHTreeNode::IsRoot() const 39 | { 40 | return _parent == nullptr; 41 | } 42 | 43 | 44 | bool BHTreeNode::IsExternal() const 45 | { 46 | return _quadNode[0] == nullptr && 47 | _quadNode[1] == nullptr && 48 | _quadNode[2] == nullptr && 49 | _quadNode[3] == nullptr; 50 | } 51 | 52 | 53 | bool BHTreeNode::WasTooClose() const 54 | { 55 | return _bSubdivided; 56 | } 57 | 58 | 59 | const Vec2D &BHTreeNode::GetMin() const 60 | { 61 | return _min; 62 | } 63 | 64 | 65 | const Vec2D &BHTreeNode::GetMax() const 66 | { 67 | return _max; 68 | } 69 | 70 | 71 | const Vec2D &BHTreeNode::GetCenterOfMass() const 72 | { 73 | return _cm; 74 | } 75 | 76 | 77 | double BHTreeNode::GetTheta() const 78 | { 79 | return s_theta; 80 | } 81 | 82 | 83 | void BHTreeNode::SetTheta(double theta) 84 | { 85 | s_theta = theta; 86 | } 87 | 88 | 89 | int BHTreeNode::StatGetNumCalc() const 90 | { 91 | return s_stat._nNumCalc; 92 | } 93 | 94 | 95 | /** \brief Returns the number of particles not assigned to any node. */ 96 | int BHTreeNode::GetNumRenegades() const 97 | { 98 | return s_renegades.size(); 99 | } 100 | 101 | 102 | /** \brief Returns the number of particles inside this node. */ 103 | int BHTreeNode::GetNum() const 104 | { 105 | return _num; 106 | } 107 | 108 | 109 | void BHTreeNode::StatReset() 110 | { 111 | if (!IsRoot()) 112 | throw std::runtime_error("Only the root node may reset statistics data."); 113 | 114 | s_stat._nNumCalc = 0; 115 | 116 | struct ResetSubdivideFlags 117 | { 118 | ResetSubdivideFlags(BHTreeNode *pRoot) 119 | { 120 | ResetFlag(pRoot); 121 | } 122 | 123 | void ResetFlag(BHTreeNode *pNode) 124 | { 125 | pNode->_bSubdivided = false; 126 | for (int i = 0; i < 4; ++i) 127 | { 128 | if (pNode->_quadNode[i]) 129 | ResetFlag(pNode->_quadNode[i]); 130 | } 131 | } 132 | } ResetFlagNow(this); 133 | } 134 | 135 | 136 | void BHTreeNode::Reset(const Vec2D &min, const Vec2D &max) 137 | { 138 | if (!IsRoot()) 139 | throw std::runtime_error("Only the root node may reset the tree."); 140 | 141 | for (int i = 0; i < 4; ++i) 142 | { 143 | delete _quadNode[i]; 144 | _quadNode[i] = nullptr; 145 | } 146 | 147 | _min = min; 148 | _max = max; 149 | _center = Vec2D(min.x + (max.x - min.x) / 2.0, 150 | min.y + (max.y - min.y) / 2.0); 151 | _num = 0; 152 | _mass = 0; 153 | _cm = Vec2D(0, 0); 154 | 155 | s_renegades.clear(); 156 | } 157 | 158 | 159 | BHTreeNode::EQuadrant BHTreeNode::GetQuadrant(double x, double y) const 160 | { 161 | if (x <= _center.x && y <= _center.y) 162 | { 163 | return SW; 164 | } 165 | else if (x <= _center.x && y >= _center.y) 166 | { 167 | return NW; 168 | } 169 | else if (x >= _center.x && y >= _center.y) 170 | { 171 | return NE; 172 | } 173 | else if (x >= _center.x && y <= _center.y) 174 | { 175 | return SE; 176 | } 177 | else if (x > _max.x || y > _max.y || x < _min.x || y < _min.y) 178 | { 179 | std::stringstream ss; 180 | ss << "Can't determine quadrant!\n" 181 | << "particle : " 182 | << "(" << x << ", " << y << ")\n" 183 | << "quadMin : " 184 | << "(" << _min.x << ", " << _min.y << ")\n" 185 | << "quadMax : " 186 | << "(" << _max.x << ", " << _max.y << ")\n" 187 | << "quadCenter: " 188 | << "(" << _center.x << ", " << _center.y << ")\n"; 189 | throw std::runtime_error(ss.str().c_str()); 190 | } 191 | else 192 | { 193 | throw std::runtime_error("Can't determine quadrant!"); 194 | } 195 | } 196 | 197 | 198 | BHTreeNode *BHTreeNode::CreateQuadNode(EQuadrant eQuad) 199 | { 200 | switch (eQuad) 201 | { 202 | case SW: 203 | return new BHTreeNode(_min, _center, this); 204 | case NW: 205 | return new BHTreeNode(Vec2D(_min.x, _center.y), 206 | Vec2D(_center.x, _max.y), 207 | this); 208 | case NE: 209 | return new BHTreeNode(_center, _max, this); 210 | case SE: 211 | return new BHTreeNode(Vec2D(_center.x, _min.y), 212 | Vec2D(_max.x, _center.y), 213 | this); 214 | default: 215 | { 216 | std::stringstream ss; 217 | ss << "Can't determine quadrant!\n"; 218 | /* 219 | << "particle : " << "(" << x << ", " << y << ")\n" 220 | << "quadMin : " << "(" << _min.x << ", " << _min.y << ")\n" 221 | << "quadMax : " << "(" << _max.x << ", " << _max.y << ")\n" 222 | << "quadCenter: " << "(" << _center.x << ", " << _center.y << ")\n"; 223 | */ 224 | throw std::runtime_error(ss.str().c_str()); 225 | } 226 | } 227 | } 228 | 229 | 230 | void BHTreeNode::ComputeMassDistribution() 231 | { 232 | 233 | if (_num == 1) 234 | { 235 | PODState *ps = _particle._pState; 236 | PODAuxState *pa = _particle._pAuxState; 237 | assert(ps); 238 | assert(pa); 239 | 240 | _mass = pa->mass; 241 | _cm = Vec2D(ps->x, ps->y); 242 | } 243 | else 244 | { 245 | _mass = 0; 246 | _cm = Vec2D(0, 0); 247 | 248 | for (int i = 0; i < 4; ++i) 249 | { 250 | if (_quadNode[i]) 251 | { 252 | _quadNode[i]->ComputeMassDistribution(); 253 | _mass += _quadNode[i]->_mass; 254 | _cm.x += _quadNode[i]->_cm.x * _quadNode[i]->_mass; 255 | _cm.y += _quadNode[i]->_cm.y * _quadNode[i]->_mass; 256 | } 257 | } 258 | 259 | _cm.x /= _mass; 260 | _cm.y /= _mass; 261 | } 262 | } 263 | 264 | 265 | /** \brief Calculate the accelleration caused by gravitaion of p2 on p1. */ 266 | Vec2D BHTreeNode::CalcAcc(const ParticleData &p1, const ParticleData &p2) const 267 | { 268 | Vec2D acc; 269 | 270 | if (&p1 == &p2) 271 | return acc; 272 | 273 | // assign references to the variables in a readable form 274 | const double &x1(p1._pState->x), 275 | &y1(p1._pState->y); 276 | const double &x2(p2._pState->x), 277 | &y2(p2._pState->y), 278 | &m2(p2._pAuxState->mass); 279 | 280 | double r = sqrt((x1 - x2) * (x1 - x2) + 281 | (y1 - y2) * (y1 - y2) + s_soft); 282 | if (r > 0) 283 | { 284 | double k = s_gamma * m2 / (r * r * r); 285 | 286 | acc.x += k * (x2 - x1); 287 | acc.y += k * (y2 - y1); 288 | } // if distance is greater zero 289 | else 290 | { 291 | // two particles on the same spot is physical nonsense! 292 | // nevertheless it may happen. I just need to make sure 293 | // there is no singularity... 294 | acc.x = acc.y = 0; 295 | } 296 | 297 | return acc; 298 | } 299 | 300 | 301 | Vec2D BHTreeNode::CalcForce(const ParticleData &p1) const 302 | { 303 | // calculate the force from the barnes hut tree to the particle p1 304 | Vec2D acc = CalcTreeForce(p1); 305 | 306 | // calculate the force from particles not in the barnes hut tree on particle p 307 | if (s_renegades.size()) 308 | { 309 | for (std::size_t i = 0; i < s_renegades.size(); ++i) 310 | { 311 | Vec2D buf = CalcAcc(p1, s_renegades[i]); 312 | acc.x += buf.x; 313 | acc.y += buf.y; 314 | } 315 | } 316 | 317 | return acc; 318 | } 319 | 320 | 321 | /** \brief Compute the force acting from this node and it's child 322 | to a particle p. 323 | */ 324 | Vec2D BHTreeNode::CalcTreeForce(const ParticleData &p1) const 325 | { 326 | Vec2D acc; 327 | 328 | double r(0), k(0), d(0); 329 | if (_num == 1) 330 | { 331 | acc = CalcAcc(p1, _particle); 332 | s_stat._nNumCalc++; 333 | } 334 | else 335 | { 336 | r = sqrt((p1._pState->x - _cm.x) * (p1._pState->x - _cm.x) + 337 | (p1._pState->y - _cm.y) * (p1._pState->y - _cm.y)); 338 | d = _max.x - _min.x; 339 | if (d / r <= s_theta) 340 | { 341 | _bSubdivided = false; 342 | k = s_gamma * _mass / (r * r * r); 343 | acc.x = k * (_cm.x - p1._pState->x); 344 | acc.y = k * (_cm.y - p1._pState->y); 345 | 346 | // keep track of the number of calculations 347 | s_stat._nNumCalc++; 348 | } 349 | else 350 | { 351 | 352 | _bSubdivided = true; 353 | Vec2D buf; 354 | for (int q = 0; q < 4; ++q) 355 | { 356 | if (_quadNode[q]) 357 | { 358 | // const PODState &state = *(p1._pState); 359 | buf = _quadNode[q]->CalcTreeForce(p1); 360 | acc.x += buf.x; 361 | acc.y += buf.y; 362 | } // if node exists 363 | } // for all child nodes 364 | } 365 | } 366 | 367 | return acc; 368 | } 369 | 370 | 371 | void BHTreeNode::DumpNode(int quad, int level) 372 | { 373 | std::string space; 374 | for (int i = 0; i < level; ++i) 375 | space += " "; 376 | 377 | std::cout << space << "Quadrant " << quad << ": "; 378 | std::cout << space << "(num=" << _num << "; "; 379 | std::cout << space << "mass=" << _mass << ";"; 380 | std::cout << space << "cx=" << _cm.x << ";"; 381 | std::cout << space << "cy=" << _cm.y << ")\n"; 382 | 383 | for (int i = 0; i < 4; ++i) 384 | { 385 | if (_quadNode[i]) 386 | { 387 | _quadNode[i]->DumpNode(i, level + 1); 388 | } 389 | } 390 | } 391 | 392 | 393 | void BHTreeNode::Insert(const ParticleData &newParticle, int level) 394 | { 395 | const PODState &p1 = *(newParticle._pState); 396 | if ((p1.x < _min.x || p1.x > _max.x) || (p1.y < _min.y || p1.y > _max.y)) 397 | { 398 | std::stringstream ss; 399 | ss << "Particle position (" << p1.x << ", " << p1.y << ") " 400 | << "is outside tree node (" 401 | << "min.x=" << _min.x << ", " 402 | << "max.x=" << _max.x << ", " 403 | << "min.y=" << _min.y << ", " 404 | << "max.y=" << _max.y << ")"; 405 | throw std::runtime_error(ss.str()); 406 | } 407 | 408 | if (_num > 1) 409 | { 410 | EQuadrant eQuad = GetQuadrant(p1.x, p1.y); 411 | if (!_quadNode[eQuad]) 412 | _quadNode[eQuad] = CreateQuadNode(eQuad); 413 | 414 | _quadNode[eQuad]->Insert(newParticle, level + 1); 415 | } 416 | else if (_num == 1) 417 | { 418 | assert(IsExternal() || IsRoot()); 419 | 420 | const PODState &p2 = *(_particle._pState); 421 | 422 | // This is physically impossible: There are 423 | // two bodies at the exact same coordinates. In these 424 | // cases do not add the second body and place 425 | // it in the renegade vector. 426 | if ((p1.x == p2.x) && (p1.y == p2.y)) 427 | { 428 | s_renegades.push_back(newParticle); 429 | } 430 | else 431 | { 432 | // There is already a particle 433 | // subdivide the node and relocate that particle 434 | EQuadrant eQuad = GetQuadrant(p2.x, p2.y); 435 | if (_quadNode[eQuad] == nullptr) 436 | _quadNode[eQuad] = CreateQuadNode(eQuad); 437 | _quadNode[eQuad]->Insert(_particle, level + 1); 438 | _particle.Reset(); 439 | 440 | eQuad = GetQuadrant(p1.x, p1.y); 441 | if (!_quadNode[eQuad]) 442 | _quadNode[eQuad] = CreateQuadNode(eQuad); 443 | _quadNode[eQuad]->Insert(newParticle, level + 1); 444 | } 445 | } 446 | else if (_num == 0) 447 | { 448 | _particle = newParticle; 449 | } 450 | 451 | _num++; 452 | } 453 | 454 | 455 | BHTreeNode::~BHTreeNode() 456 | { 457 | for (int i = 0; i < 4; ++i) 458 | delete _quadNode[i]; 459 | } 460 | -------------------------------------------------------------------------------- /src/NBodyWnd.cpp: -------------------------------------------------------------------------------- 1 | #include "NBodyWnd.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "IntegratorRK4.h" 10 | #include "IntegratorRK5.h" 11 | #include "IntegratorADB6.h" 12 | 13 | 14 | NBodyWnd::NBodyWnd(int sz, std::string caption) 15 | :SDLWindow(sz, sz, 30.0, caption) 16 | ,_pModel(nullptr) 17 | ,_pSolver(nullptr) 18 | ,_camOrient(0) 19 | ,_flags(dspBODIES | /*dspTREE |*/ dspAXIS | dspSTAT | dspVERBOSE) 20 | {} 21 | 22 | NBodyWnd::~NBodyWnd() 23 | { 24 | delete _pModel; 25 | delete _pSolver; 26 | } 27 | 28 | void NBodyWnd::Init(int num) 29 | { 30 | // Create the n-body model class 31 | delete _pModel; 32 | _pModel = new ModelNBody(); 33 | 34 | // assign model to the solver and set the integration step width 35 | delete _pSolver; 36 | 37 | // _pSolver = new IntegratorADB4(_pModel, 5); 38 | // _pSolver = new IntegratorRK5(_pModel, _pModel->GetSuggestedTimeStep()); 39 | _pSolver = new IntegratorADB6(_pModel, _pModel->GetSuggestedTimeStep()); 40 | _pSolver->SetInitialState(_pModel->GetInitialState()); 41 | 42 | if (_bDumpState) 43 | { 44 | std::string sName = std::string("traces_barnes_hut_") + _pSolver->GetID() + ".dat"; 45 | _outfile.open(sName.c_str()); 46 | } 47 | 48 | // OpenGL initialization 49 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 50 | 51 | SetCameraOrientation(Vec3D(0, 1, 0)); 52 | 53 | glMatrixMode(GL_MODELVIEW); 54 | glLoadIdentity(); 55 | } 56 | 57 | void NBodyWnd::Update() 58 | { 59 | static int ct = 0; 60 | 61 | if (_flags & dspPAUSE) 62 | return; 63 | 64 | _pSolver->SingleStep(); 65 | ++ct; 66 | 67 | if (_bDumpState && ct % 1000000 == 0) 68 | { 69 | int num = _pModel->GetDim() / 4; 70 | PODState *state = reinterpret_cast(_pSolver->GetState()); 71 | _outfile << _pSolver->GetTime() << ", "; 72 | for (int i = 0; i < num; ++i) 73 | { 74 | _outfile << state[i].x << ", " 75 | << state[i].y << ", "; 76 | } 77 | _outfile << std::endl; 78 | } 79 | 80 | if (_bDumpImage && ct % 2000 == 0) 81 | { 82 | SaveToTGA(); 83 | } 84 | } 85 | 86 | void NBodyWnd::Render() 87 | { 88 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 89 | 90 | Vec3D orient; 91 | switch (_camOrient) 92 | { 93 | case 0: 94 | orient.x = 0; 95 | orient.y = 1; 96 | orient.z = 0; 97 | break; 98 | 99 | case 1: 100 | orient = _pModel->GetCamDir(); 101 | break; 102 | } 103 | SetCameraOrientation(orient); 104 | 105 | if (_flags & dspAXIS) 106 | { 107 | // Draw axis at position of the first particle 108 | const Vec3D &cm = _pModel->GetCenterOfMass(); 109 | DrawAxis(Vec2D(cm.x, cm.y)); 110 | } 111 | 112 | if (_flags & dspTREE) 113 | DrawTree(); 114 | 115 | if (_flags & dspBODIES) 116 | DrawBodies(); 117 | 118 | if (_flags & dspROI) 119 | DrawROI(); 120 | 121 | if (_flags & dspSTAT) 122 | DrawStat(); 123 | 124 | if (_flags & dspHELP) 125 | DrawHelp(); 126 | 127 | SDL_GL_SwapBuffers(); 128 | } 129 | 130 | void NBodyWnd::DrawBodies() 131 | { 132 | assert(_pSolver); 133 | 134 | PODState *state = reinterpret_cast(_pSolver->GetState()); 135 | // const PODAuxState *state_aux = _pModel->GetAuxState(); 136 | 137 | glColor3f(1, 1, 1); 138 | glPointSize(2); // state_aux[i].mass/10); 139 | glBegin(GL_POINTS); 140 | 141 | for (int i = 0; i < _pModel->GetN(); ++i) 142 | { 143 | glVertex3f(state[i].x, state[i].y, 0.0f); 144 | } 145 | 146 | glEnd(); 147 | } 148 | 149 | void NBodyWnd::DrawStat() 150 | { 151 | double x0 = 10, y0 = 20, dy = 20; 152 | int line = 0; 153 | 154 | // acquire pointer to the root node of the barnes hut tree from the model 155 | BHTreeNode *pRoot = _pModel->GetRootNode(); 156 | 157 | const Vec3D &camPos = GetCamPos(), 158 | &camLookAt = GetCamLookAt(); 159 | glColor3f(1, 1, 1); 160 | TextOut(x0, y0 + dy * line++, "Number of bodies (outside tree): %d (%d)", pRoot->GetNum(), pRoot->GetNumRenegades()); 161 | TextOut(x0, y0 + dy * line++, "Theta: %2.1f", pRoot->GetTheta()); 162 | TextOut(x0, y0 + dy * line++, "FPS: %d", GetFPS()); 163 | TextOut(x0, y0 + dy * line++, "Time: %2.1f y", _pSolver->GetTime()); 164 | TextOut(x0, y0 + dy * line++, "Camera: %2.2f, %2.2f, %2.2f", camPos.x, camPos.y, camPos.z); 165 | TextOut(x0, y0 + dy * line++, "LookAt: %2.2f, %2.2f, %2.2f", camLookAt.x, camLookAt.y, camLookAt.z); 166 | TextOut(x0, y0 + dy * line++, "Field of view: %2.2f pc", GetFOV()); 167 | TextOut(x0, y0 + dy * line++, "Calculations: %d", pRoot->StatGetNumCalc()); 168 | TextOut(x0, y0 + dy * line++, "Solver: %s", _pSolver->GetID().c_str()); 169 | } 170 | 171 | void NBodyWnd::DrawHelp() 172 | { 173 | double x0 = 10, y0 = 20, dy = 20; 174 | int line = 0; 175 | Vec3D p; 176 | 177 | glColor3f(1, 1, 1); 178 | TextOut(x0, y0 + dy * line++, "Keyboard commands"); 179 | TextOut(x0, y0 + dy * line++, "a - display axis"); 180 | TextOut(x0, y0 + dy * line++, "t - display Barnes Hut tree"); 181 | TextOut(x0, y0 + dy * line++, "s - display statistic data"); 182 | TextOut(x0, y0 + dy * line++, "c - display center of mass"); 183 | TextOut(x0, y0 + dy * line++, "b - display particles"); 184 | TextOut(x0, y0 + dy * line++, "h - display help text"); 185 | TextOut(x0, y0 + dy * line++, "0..1 - Set camera orientation"); 186 | TextOut(x0, y0 + dy * line++, "pause - halt simulation"); 187 | } 188 | 189 | void NBodyWnd::DrawROI() 190 | { 191 | const Vec3D &cm = _pModel->GetCenterOfMass(); 192 | 193 | double l = GetFOV() / 20; 194 | glColor3f(1, 0, 0); 195 | 196 | glPushMatrix(); 197 | glTranslatef(cm.x, cm.y, cm.z); 198 | // cross at the center of mass 199 | glBegin(GL_LINES); 200 | glVertex3f(-l, 0, 0); 201 | glVertex3f(l, 0, 0); 202 | glVertex3f(0, -l, 0); 203 | glVertex3f(0, l, 0); 204 | glEnd(); 205 | 206 | // region of interest 207 | l = _pModel->GetROI() / 2.0; 208 | glBegin(GL_LINE_STRIP); 209 | glVertex3f(-l, l, 0); 210 | glVertex3f(l, l, 0); 211 | glVertex3f(l, -l, 0); 212 | glVertex3f(-l, -l, 0); 213 | glVertex3f(-l, l, 0); 214 | glEnd(); 215 | 216 | glPopMatrix(); 217 | } 218 | 219 | void NBodyWnd::DrawTree() 220 | { 221 | struct DrawTree 222 | { 223 | enum EWhat 224 | { 225 | COMPLETE, ///< Display all nodes 226 | APPROX, ///< Display only the nodes as they where used for the force calculation 227 | }; 228 | 229 | DrawTree(BHTreeNode *pRoot, EWhat what, int flags, int sz) 230 | : displayFlags(flags) 231 | { 232 | DrawNode(pRoot, 0, what, sz); 233 | } 234 | 235 | void DrawNode(BHTreeNode *pNode, int level, EWhat what, int sz) 236 | { 237 | assert(pNode); 238 | 239 | double col = 1 - level * 0.2; 240 | switch (what) 241 | { 242 | case COMPLETE: 243 | glColor3f(col, 1, col); 244 | break; 245 | case APPROX: 246 | glColor3f(0, 1, 0); 247 | break; 248 | } 249 | 250 | // Draw node rectangle 251 | if (what == COMPLETE || 252 | (what == APPROX && !pNode->WasTooClose())) 253 | { 254 | const Vec2D &min = pNode->GetMin(), 255 | &max = pNode->GetMax(); 256 | glBegin(GL_LINE_STRIP); 257 | glVertex3f(min.x, min.y, 0); 258 | glVertex3f(max.x, min.y, 0); 259 | glVertex3f(max.x, max.y, 0); 260 | glVertex3f(min.x, max.y, 0); 261 | glVertex3f(min.x, min.y, 0); 262 | glEnd(); 263 | 264 | // Draw a cross at the center of mass is the corresponding flag is set 265 | if (displayFlags & dspCENTER_OF_MASS && !pNode->IsExternal()) 266 | { 267 | double len = (double)sz / 50 * std::max(1 - level * 0.2, 0.1); 268 | glPointSize(4); 269 | glColor3f(col, 1, col); 270 | 271 | const Vec2D cm = pNode->GetCenterOfMass(); 272 | glBegin(GL_LINES); 273 | glVertex3f(cm.x - len, cm.y, 0); 274 | glVertex3f(cm.x + len, cm.y, 0); 275 | glEnd(); 276 | glBegin(GL_LINES); 277 | glVertex3f(cm.x, cm.y - len, 0); 278 | glVertex3f(cm.x, cm.y + len, 0); 279 | glEnd(); 280 | } 281 | } 282 | 283 | // If the node was not subdivided in the force calculation 284 | // dont draw its subnodes either 285 | if (what != COMPLETE && !pNode->WasTooClose()) 286 | return; 287 | 288 | for (int i = 0; i < 4; ++i) 289 | { 290 | if (pNode->_quadNode[i]) 291 | DrawNode(pNode->_quadNode[i], level + 1, what, sz); 292 | } 293 | } // DrawTree::DrawNode 294 | 295 | int displayFlags; 296 | }; // struct DrawTree 297 | 298 | BHTreeNode *pRoot = _pModel->GetRootNode(); 299 | if ((_flags & dspTREE) && (_flags & dspTREE_COMPLETE)) 300 | DrawTree DrawComplete(pRoot, DrawTree::COMPLETE, _flags, GetFOV()); 301 | else if ((_flags & dspTREE) && !(_flags & dspTREE_COMPLETE)) 302 | DrawTree DrawFar(pRoot, DrawTree::APPROX, _flags, GetFOV()); 303 | } 304 | 305 | void NBodyWnd::DrawNode(BHTreeNode *pNode, int level) 306 | { 307 | assert(pNode); 308 | double len = 0.01 * std::max(1 - level * 0.2, 0.1); 309 | 310 | double col = 1 - level * 0.2; 311 | 312 | if (pNode->WasTooClose()) 313 | glColor3f(1, col, col); 314 | else 315 | glColor3f(col, 1, col); 316 | 317 | const Vec2D &min = pNode->GetMin(), 318 | &max = pNode->GetMax(); 319 | glBegin(GL_LINE_STRIP); 320 | glVertex3f(min.x, min.y, 0); 321 | glVertex3f(max.x, min.y, 0); 322 | glVertex3f(max.x, max.y, 0); 323 | glVertex3f(min.x, max.y, 0); 324 | glVertex3f(min.x, min.y, 0); 325 | glEnd(); 326 | 327 | if (_flags & dspCENTER_OF_MASS && !pNode->IsExternal()) 328 | { 329 | Vec2D cm = pNode->GetCenterOfMass(); 330 | 331 | glPointSize(4); 332 | glColor3f(col, 1, col); 333 | glBegin(GL_LINES); 334 | glVertex3f(cm.x - len, cm.y, 0); 335 | glVertex3f(cm.x + len, cm.y, 0); 336 | glVertex3f(cm.x, cm.y - len, 0); 337 | glVertex3f(cm.x, cm.y + len, 0); 338 | glEnd(); 339 | } 340 | 341 | if (!pNode->WasTooClose()) 342 | return; 343 | 344 | for (int i = 0; i < 4; ++i) 345 | { 346 | if (pNode->_quadNode[i]) 347 | { 348 | DrawNode(pNode->_quadNode[i], level + 1); 349 | } 350 | } 351 | } 352 | 353 | void NBodyWnd::OnProcessEvents(uint8_t type) 354 | { 355 | switch (type) 356 | { 357 | /* commented: does not work 358 | case SDL_MOUSEBUTTONDOWN: 359 | { 360 | // Place a tracer particle at the mouse coordinates 361 | if (!_pSolver) 362 | break; 363 | 364 | PODState *state = reinterpret_cast(_pSolver->GetState()); 365 | Vec3D p = GetOGLPos(_event.button.x, 366 | _event.button.y); 367 | state[0].x = p.x; 368 | state[0].y = p.y; 369 | SetCamera(p, p, Vec3D(0, 1, 0)); 370 | 371 | // the solver may need to rest its temporary arrays. I can't just 372 | // overwrite part of its data because ADB schemes will go mad 373 | // if i change a particles position. without restarting the engine 374 | _pSolver->SetInitialState(reinterpret_cast(state)); 375 | _pSolver->SingleStep(); 376 | } 377 | break; 378 | */ 379 | case SDL_KEYDOWN: 380 | switch (_event.key.keysym.sym) 381 | { 382 | case SDLK_1: 383 | _camOrient = 0; 384 | break; 385 | 386 | case SDLK_2: 387 | _camOrient = 1; 388 | break; 389 | 390 | case SDLK_a: 391 | std::cout << "Display: Toggling axis " << ((_flags & dspAXIS) ? "off" : "on") << "\n"; 392 | _flags ^= dspAXIS; 393 | break; 394 | 395 | case SDLK_b: 396 | std::cout << "Display: Toggling bodies " << ((_flags & dspBODIES) ? "off" : "on") << "\n"; 397 | _flags ^= dspBODIES; 398 | break; 399 | 400 | case SDLK_t: 401 | { 402 | if (!(_flags & dspTREE)) 403 | { 404 | _flags ^= dspTREE; 405 | std::cout << "Display: Tree cells used in force calculation\n"; 406 | } 407 | else if ((_flags & dspTREE) && !(_flags & dspTREE_COMPLETE)) 408 | { 409 | _flags ^= dspTREE_COMPLETE; 410 | std::cout << "Display: Complete tree\n"; 411 | } 412 | else if ((_flags & dspTREE) && (_flags & dspTREE_COMPLETE)) 413 | { 414 | _flags &= ~(dspTREE | dspTREE_COMPLETE); 415 | std::cout << "Display: No tree\n"; 416 | } 417 | } 418 | break; 419 | 420 | case SDLK_c: 421 | std::cout << "Display: Center of mass " << ((_flags & dspCENTER_OF_MASS) ? "off" : "on") << "\n"; 422 | _flags ^= dspCENTER_OF_MASS; 423 | break; 424 | 425 | case SDLK_h: 426 | std::cout << "Display: Help text" << ((_flags & dspHELP) ? "off" : "on") << "\n"; 427 | _flags ^= dspHELP; 428 | _flags &= ~dspSTAT; 429 | break; 430 | 431 | case SDLK_PAUSE: 432 | std::cout << "Simulation: pause " << ((_flags & dspPAUSE) ? "off" : "on") << "\n"; 433 | _flags ^= dspPAUSE; 434 | break; 435 | 436 | case SDLK_v: 437 | std::cout << "Simulation: verbose mode " << ((_flags & dspVERBOSE) ? "off" : "on") << "\n"; 438 | _flags ^= dspVERBOSE; 439 | if (_pModel) 440 | _pModel->SetVerbose(_flags & dspVERBOSE); 441 | break; 442 | 443 | case SDLK_s: 444 | std::cout << "Display: statistics " << ((_flags & dspSTAT) ? "off" : "on") << "\n"; 445 | _flags ^= dspSTAT; 446 | break; 447 | 448 | case SDLK_f: 449 | std::cout << "Display: force indicator " << ((_flags & dspARROWS) ? "off" : "on") << "\n"; 450 | _flags ^= dspARROWS; 451 | break; 452 | 453 | case SDLK_r: 454 | std::cout << "Display: region of interest " << ((_flags & dspROI) ? "off" : "on") << "\n"; 455 | _flags ^= dspROI; 456 | break; 457 | 458 | case SDLK_p: 459 | SaveToTGA(); 460 | break; 461 | 462 | case SDLK_y: 463 | _pModel->SetTheta(_pModel->GetTheta() + 0.1); 464 | break; 465 | 466 | case SDLK_x: 467 | _pModel->SetTheta(std::max(_pModel->GetTheta() - 0.1, 0.1)); 468 | break; 469 | 470 | case SDLK_KP_PLUS: 471 | ScaleAxis(0.9); 472 | SetCameraOrientation(Vec3D(0, 1, 0)); 473 | break; 474 | 475 | case SDLK_KP_MINUS: 476 | ScaleAxis(1.1); 477 | SetCameraOrientation(Vec3D(0, 1, 0)); 478 | break; 479 | 480 | default: 481 | break; 482 | } 483 | 484 | break; 485 | } 486 | } 487 | -------------------------------------------------------------------------------- /src/ModelNBody.cpp: -------------------------------------------------------------------------------- 1 | #include "ModelNBody.h" 2 | 3 | //--- Standard includes -------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | 13 | ModelNBody::ModelNBody() 14 | :IModel("N-Body simulation (2D)") 15 | ,_pInitial(nullptr) 16 | ,_pAux(nullptr) 17 | ,_root(BHTreeNode(Vec2D(), Vec2D())) 18 | ,_min() 19 | ,_max() 20 | ,_center() 21 | ,_camDir() 22 | ,_camPos() 23 | ,_roi(1) 24 | ,_timeStep(1) 25 | ,_num(0) 26 | ,_bVerbose(false) 27 | { 28 | BHTreeNode::s_gamma = gamma_1; 29 | 30 | // Init(); 31 | InitCollision(); 32 | // Init3Body(); 33 | } 34 | 35 | 36 | ModelNBody::~ModelNBody() 37 | { 38 | delete _pInitial; 39 | delete _pAux; 40 | } 41 | 42 | 43 | void ModelNBody::SetROI(double roi) 44 | { 45 | _roi = roi; 46 | } 47 | 48 | 49 | double ModelNBody::GetSuggestedTimeStep() const 50 | { 51 | return _timeStep; 52 | } 53 | 54 | 55 | double ModelNBody::GetROI() const 56 | { 57 | return _roi; 58 | } 59 | 60 | 61 | Vec3D ModelNBody::GetCenterOfMass() const 62 | { 63 | const Vec2D &cm2d = _root.GetCenterOfMass(); 64 | return Vec3D(cm2d.x, cm2d.y, 0); 65 | } 66 | 67 | 68 | const Vec3D &ModelNBody::GetCamDir() const 69 | { 70 | return _camDir; 71 | } 72 | 73 | 74 | const Vec3D &ModelNBody::GetCamPos() const 75 | { 76 | return _camPos; 77 | } 78 | 79 | 80 | double *ModelNBody::GetInitialState() 81 | { 82 | return reinterpret_cast(_pInitial); 83 | } 84 | 85 | 86 | void ModelNBody::GetOrbitalVelocity(const ParticleData &p1, const ParticleData &p2) 87 | { 88 | double x1 = p1._pState->x, 89 | y1 = p1._pState->x, 90 | m1 = p1._pAuxState->mass; 91 | double x2 = p2._pState->x, 92 | y2 = p2._pState->y; 93 | 94 | // Calculate distance from the planet with index idx_main 95 | double r[2], dist; 96 | r[0] = x1 - x2; 97 | r[1] = y1 - y2; 98 | 99 | // distance in parsec 100 | dist = sqrt(r[0] * r[0] + r[1] * r[1]); 101 | 102 | // Based on the distance from the sun calculate the velocity needed to maintain a circular orbit 103 | double v = sqrt(gamma_1 * m1 / dist); 104 | 105 | // Calculate a suitable vector perpendicular to r for the velocity of the tracer 106 | double &vx = p2._pState->vx, 107 | &vy = p2._pState->vy; 108 | vx = (r[1] / dist) * v; 109 | vy = (-r[0] / dist) * v; 110 | } 111 | 112 | 113 | void ModelNBody::ResetDim(int num, double stepsize) 114 | { 115 | _num = num; 116 | SetDim(_num * 4); 117 | 118 | delete _pInitial; 119 | _pInitial = new PODState[num]; 120 | 121 | delete _pAux; 122 | _pAux = new PODAuxState[num]; 123 | 124 | _timeStep = stepsize; 125 | 126 | // reset bounding box and center 127 | _max.x = _max.y = std::numeric_limits::min(); 128 | _min.x = _min.y = std::numeric_limits::max(); 129 | _center = Vec2D(0, 0); // for storing the center of mass 130 | } 131 | 132 | 133 | void ModelNBody::Init() 134 | { 135 | // Reset model size 136 | ResetDim(5000, 100000); 137 | 138 | double mass = 0; // for storing the total mass 139 | 140 | // initialize particles 141 | int ct = 0; 142 | ParticleData blackHole, macho[10]; 143 | 144 | for (int k = 0; k < 40; ++k) 145 | { 146 | for (int l = 0; l < 100; ++l) 147 | { 148 | if (ct >= _num) 149 | goto hell; 150 | 151 | PODState &st = _pInitial[ct]; 152 | PODAuxState &st_aux = _pAux[ct]; 153 | 154 | if (ct == 0) 155 | { 156 | blackHole._pState = &st; 157 | blackHole._pAuxState = &st_aux; 158 | 159 | // particle zero is special its the trace particle that is not part 160 | // of the simulation and can be positioned with the mouse 161 | st.x = st.y = 0; 162 | st.vx = st.vy = 0; 163 | st_aux.mass = 1000000; // 431000; // 4.31 Millionen Sonnenmassen 164 | } 165 | else if (ct == 1) 166 | { 167 | // macho im galaktischen halo, der hoffentlich ein paar spiralarme erzeugt 168 | macho[0]._pState = &st; 169 | macho[0]._pAuxState = &st_aux; 170 | 171 | // particle zero is special its the trace particle that is not part 172 | // of the simulation and can be positioned with the mouse 173 | st_aux.mass = blackHole._pAuxState->mass / 10.0; 174 | st.x = 5000; 175 | st.y = 5000; 176 | 177 | GetOrbitalVelocity(blackHole, ParticleData(&st, &st_aux)); 178 | } 179 | else if (ct == 2) 180 | { 181 | // macho im galaktischen halo, der hoffentlich ein paar spiralarme erzeugt 182 | macho[1]._pState = &st; 183 | macho[1]._pAuxState = &st_aux; 184 | 185 | // particle zero is special its the trace particle that is not part 186 | // of the simulation and can be positioned with the mouse 187 | st_aux.mass = blackHole._pAuxState->mass / 10.0; 188 | st.x = -5000; 189 | st.y = -5000; 190 | 191 | GetOrbitalVelocity(blackHole, ParticleData(&st, &st_aux)); 192 | } 193 | else 194 | { 195 | st_aux.mass = 0.76 + 100 * ((double)rand() / RAND_MAX); 196 | double rad = 1200 + k * 100; 197 | st.x = rad * sin(2 * M_PI * l / 100.0); 198 | st.y = rad * cos(2 * M_PI * l / 100.0); 199 | GetOrbitalVelocity(blackHole, ParticleData(&st, &st_aux)); 200 | } 201 | 202 | // determine the size of the area including all particles 203 | _max.x = std::max(_max.x, st.x); 204 | _max.y = std::max(_max.y, st.y); 205 | _min.x = std::min(_min.x, st.x); 206 | _min.y = std::min(_min.y, st.y); 207 | 208 | _center.x += st.x * st_aux.mass; 209 | _center.y += st.x * st_aux.mass; 210 | mass += st_aux.mass; 211 | ++ct; 212 | } 213 | } 214 | 215 | hell: 216 | 217 | // compute the center of mass 218 | _center.x /= mass; 219 | _center.y /= mass; 220 | 221 | // The Barnes Hut algorithm needs square shaped quadrants. 222 | // calculate the height of the square including all particles (and a bit more space) 223 | _roi = 1.5 * std::max(_max.x - _min.x, 224 | _max.y - _min.y); 225 | 226 | // compute the center of the region including all particles 227 | _min.x = _center.x - _roi; 228 | _max.x = _center.x + _roi; 229 | _min.y = _center.y - _roi; 230 | _max.y = _center.y + _roi; 231 | 232 | std::cout << "Initial particle distribution area\n"; 233 | std::cout << "----------------------------------\n"; 234 | std::cout << "Particle spread:\n"; 235 | std::cout << " xmin = " << _min.x << ", ymin=" << _min.y << "\n"; 236 | std::cout << " xmax = " << _max.y << ", ymax=" << _max.y << "\n"; 237 | std::cout << "Bounding box:\n"; 238 | std::cout << " center = " << _center.x << ", cy =" << _center.y << "\n"; 239 | std::cout << " roi = " << _roi << "\n"; 240 | } 241 | 242 | 243 | void ModelNBody::InitCollision() 244 | { 245 | // Reset model size 246 | ResetDim(5000, 100); 247 | 248 | // initialize particles 249 | ParticleData blackHole; 250 | ParticleData blackHole2; 251 | 252 | for (int i = 0; i < _num; ++i) 253 | { 254 | PODState &st = _pInitial[i]; 255 | PODAuxState &st_aux = _pAux[i]; 256 | 257 | if (i == 0) 258 | { 259 | // particle zero is special its the trace particle that is not part 260 | // of the simulation and can be positioned with the mouse 261 | blackHole._pState = &st; 262 | blackHole._pAuxState = &st_aux; 263 | 264 | st.x = st.y = 0; 265 | st.vx = st.vy = 0; 266 | st_aux.mass = 1000000; // 431000; // 4.31 Millionen Sonnenmassen 267 | } 268 | else if (i < 4000) 269 | { 270 | const double rad = 10; 271 | double r = 0.1 + .8 * (rad * ((double)rand() / RAND_MAX)); 272 | double a = 2.0 * M_PI * ((double)rand() / RAND_MAX); 273 | st_aux.mass = 0.03 + 20 * ((double)rand() / RAND_MAX); 274 | st.x = r * sin(a); 275 | st.y = r * cos(a); 276 | 277 | GetOrbitalVelocity(blackHole, ParticleData(&st, &st_aux)); 278 | } 279 | else if (i == 4000) 280 | { 281 | blackHole2._pState = &st; 282 | blackHole2._pAuxState = &st_aux; 283 | 284 | st.x = st.y = 10; 285 | st_aux.mass = 100000; 286 | GetOrbitalVelocity(blackHole, blackHole2); 287 | blackHole2._pState->vx *= 0.9; 288 | blackHole2._pState->vy *= 0.9; 289 | } 290 | else 291 | { 292 | const double rad = 3; 293 | double r = 0.1 + .8 * (rad * ((double)rand() / RAND_MAX)); 294 | double a = 2.0 * M_PI * ((double)rand() / RAND_MAX); 295 | st_aux.mass = 0.03 + 20 * ((double)rand() / RAND_MAX); 296 | st.x = blackHole2._pState->x + r * sin(a); 297 | st.y = blackHole2._pState->y + r * cos(a); 298 | 299 | GetOrbitalVelocity(blackHole2, ParticleData(&st, &st_aux)); 300 | st.vx += blackHole2._pState->vx; 301 | st.vy += blackHole2._pState->vy; 302 | } 303 | 304 | // determine the size of the area including all particles 305 | _max.x = std::max(_max.x, st.x); 306 | _max.y = std::max(_max.y, st.y); 307 | _min.x = std::min(_min.x, st.x); 308 | _min.y = std::min(_min.y, st.y); 309 | } 310 | 311 | // The Barnes Hut algorithm needs square shaped quadrants. 312 | // calculate the height of the square including all particles (and a bit more space) 313 | double l = 1.05 * std::max(_max.x - _min.x, 314 | _max.y - _min.y); 315 | 316 | _roi = l * 1.5; 317 | 318 | // compute the center of the region including all particles 319 | Vec2D c(_min.x + (_max.x - _min.x) / 2.0, 320 | _min.y + (_max.y - _min.y) / 2.0); 321 | _min.x = c.x - l / 2.0; 322 | _max.x = c.x + l / 2.0; 323 | _min.y = c.y - l / 2.0; 324 | _max.y = c.y + l / 2.0; 325 | 326 | std::cout << "Initial particle distribution area\n"; 327 | std::cout << "----------------------------------\n"; 328 | std::cout << "Particle spread:\n"; 329 | std::cout << " xmin=" << _min.x << ", ymin=" << _min.y << "\n"; 330 | std::cout << " xmax=" << _max.y << ", ymax=" << _max.y << "\n"; 331 | std::cout << "Bounding box:\n"; 332 | std::cout << " cx =" << c.x << ", cy =" << c.y << "\n"; 333 | std::cout << " l =" << l << "\n"; 334 | } 335 | 336 | 337 | void ModelNBody::Init3Body() 338 | { 339 | // Reset model size 340 | ResetDim(3, .5); 341 | _root.SetTheta(0.9); 342 | PODState *st(nullptr); 343 | PODAuxState *st_aux(nullptr); 344 | 345 | // initialize particles 346 | st = &_pInitial[0]; 347 | st_aux = &_pAux[0]; 348 | st->x = 1; 349 | st->y = 3; 350 | st->vx = st->vy = 0; 351 | st_aux->mass = 3; 352 | 353 | st = &_pInitial[1]; 354 | st_aux = &_pAux[1]; 355 | st->x = -2; 356 | st->y = -1; 357 | st->vx = st->vy = 0; 358 | st_aux->mass = 4; 359 | 360 | st = &_pInitial[2]; 361 | st_aux = &_pAux[2]; 362 | st->x = 1; 363 | st->y = -1; 364 | st->vx = st->vy = 0; 365 | st_aux->mass = 5; 366 | 367 | // determine the size of the area including all particles 368 | for (int i = 0; i < _num; ++i) 369 | { 370 | PODState &st = _pInitial[i]; 371 | _max.x = std::max(_max.x, st.x); 372 | _max.y = std::max(_max.y, st.y); 373 | _min.x = std::min(_min.x, st.x); 374 | _min.y = std::min(_min.y, st.y); 375 | } 376 | 377 | // The Barnes Hut algorithm needs square shaped quadrants. 378 | // calculate the height of the square including all particles (and a bit more space) 379 | double l = 1.05 * std::max(_max.x - _min.x, 380 | _max.y - _min.y); 381 | 382 | _roi = l * 1.5; 383 | 384 | // compute the center of the region including all particles 385 | Vec2D c(_min.x + (_max.x - _min.x) / 2.0, 386 | _min.y + (_max.y - _min.y) / 2.0); 387 | _min.x = c.x - l / 2.0; 388 | _max.x = c.x + l / 2.0; 389 | _min.y = c.y - l / 2.0; 390 | _max.y = c.y + l / 2.0; 391 | 392 | std::cout << "Initial particle distribution area\n"; 393 | std::cout << "----------------------------------\n"; 394 | std::cout << "Particle spread:\n"; 395 | std::cout << " xmin=" << _min.x << ", ymin=" << _min.y << "\n"; 396 | std::cout << " xmax=" << _max.y << ", ymax=" << _max.y << "\n"; 397 | std::cout << "Bounding box:\n"; 398 | std::cout << " cx =" << c.x << ", cy =" << c.y << "\n"; 399 | std::cout << " l =" << l << "\n"; 400 | } 401 | 402 | 403 | void ModelNBody::CalcBHArea(const ParticleData &data) 404 | { 405 | /* 406 | // reset bounding box 407 | _max.x = _max.y = std::numeric_limits::min(); 408 | _min.x = _min.y = std::numeric_limits::max(); 409 | 410 | for (int i=0; i<_num; ++i) 411 | { 412 | PODState &s = data._pState[i]; 413 | 414 | // determine the size of the area including all particles 415 | _max.x = std::max(_max.x, s.x); 416 | _max.y = std::max(_max.y, s.y); 417 | _min.x = std::min(_min.x, s.x); 418 | _min.y = std::min(_min.y, s.y); 419 | } 420 | 421 | // The Barnes Hut algorithm needs square shaped quadrants. 422 | // calculate the height of the square including all particles (and a bit more space) 423 | double l = 1.05 * std::max(_max.x - _min.x, 424 | _max.y - _min.y); 425 | 426 | // compute the center of the region including all particles 427 | Vec2D c(_min.x + (_max.x - _min.x)/2.0, 428 | _min.y + (_max.y - _min.y)/2.0); 429 | _min.x = c.x - l/2.0; 430 | _max.x = c.x + l/2.0; 431 | _min.y = c.y - l/2.0; 432 | _max.y = c.y + l/2.0; 433 | */ 434 | } 435 | 436 | 437 | /** \brief Build the barnes hut tree by adding all particles that are inside 438 | the region of interest. 439 | */ 440 | void ModelNBody::BuiltTree(const ParticleData &all) 441 | { 442 | // Reset the quadtree, make sure only particles inside the roi 443 | // are handled. The renegade ones may live long and prosper 444 | // outside my simulation 445 | _root.Reset(Vec2D(_center.x - _roi, _center.y - _roi), 446 | Vec2D(_center.x + _roi, _center.y + _roi)); 447 | 448 | // build the quadtree 449 | int ct = 0; 450 | for (int i = 0; i < _num; ++i) 451 | { 452 | try 453 | { 454 | // extract data for a single particle 455 | ParticleData p(&(all._pState[i]), 456 | &(all._pAuxState[i])); 457 | 458 | // insert the particle, but only if its inside the roi 459 | _root.Insert(p, 0); 460 | ++ct; 461 | } 462 | catch (std::exception &exc) 463 | { 464 | /* 465 | std::cout << exc.what() << "\n"; 466 | std::cout << "Particle " << i << " (" << st->x << ", " << st->y << ") is outside the roi (skipped).\n"; 467 | std::cout << " roi size = " << m_roi << "\n"; 468 | std::cout << " roi center = (" << m_center.x << ", " << m_center.y << ")\n"; 469 | */ 470 | } 471 | } 472 | 473 | // std::cout << ct << " particles added sucessfully\n"; 474 | 475 | // compute masses and center of mass on all scales of the tree 476 | _root.ComputeMassDistribution(); 477 | if (_bVerbose) 478 | { 479 | std::cout << "Tree Dump\n"; 480 | std::cout << "---------\n"; 481 | _root.DumpNode(-1, 0); 482 | std::cout << "\n\n"; 483 | } 484 | 485 | // update the center of mass 486 | _center = _root.GetCenterOfMass(); 487 | } 488 | 489 | 490 | const PODAuxState *ModelNBody::GetAuxState() const 491 | { 492 | return _pAux; 493 | } 494 | 495 | 496 | BHTreeNode *ModelNBody::GetRootNode() 497 | { 498 | return &_root; 499 | } 500 | 501 | 502 | int ModelNBody::GetN() const 503 | { 504 | return _num; 505 | } 506 | 507 | 508 | double ModelNBody::GetTheta() const 509 | { 510 | return _root.GetTheta(); 511 | } 512 | 513 | 514 | void ModelNBody::SetVerbose(bool bVerbose) 515 | { 516 | _bVerbose = bVerbose; 517 | } 518 | 519 | 520 | void ModelNBody::SetTheta(double theta) 521 | { 522 | _root.SetTheta(theta); 523 | } 524 | 525 | 526 | void ModelNBody::Eval(double *a_state, double a_time, double *a_deriv) 527 | { 528 | // wrap the complete particle data together for easier treatment 529 | // in the following algorithms 530 | PODState *pState = reinterpret_cast(a_state); 531 | PODDeriv *pDeriv = reinterpret_cast(a_deriv); 532 | ParticleData all(pState, _pAux); 533 | 534 | CalcBHArea(all); 535 | BuiltTree(all); 536 | 537 | #pragma omp parallel for 538 | for (int i = 1; i < _num; ++i) 539 | { 540 | ParticleData p(&pState[i], &_pAux[i]); 541 | Vec2D acc = _root.CalcForce(p); 542 | pDeriv[i].ax = acc.x; 543 | pDeriv[i].ay = acc.y; 544 | pDeriv[i].vx = pState[i].vx; 545 | pDeriv[i].vy = pState[i].vy; 546 | } 547 | 548 | // Particle 0 is calculated last, because the statistics 549 | // data relate to this particle. They would be overwritten 550 | // otherwise 551 | _root.StatReset(); 552 | ParticleData p(&pState[0], &_pAux[0]); 553 | Vec2D acc = _root.CalcForce(p); 554 | pDeriv[0].ax = acc.x; 555 | pDeriv[0].ay = acc.y; 556 | pDeriv[0].vx = pState[0].vx; 557 | pDeriv[0].vy = pState[0].vy; 558 | 559 | // Save vectors for camera orientations 560 | // m_camDir.x = pState[0].x - pState[4000].x; 561 | // m_camDir.y = pState[0].y - pState[4000].y; 562 | _camPos.x = _root.GetCenterOfMass().x; 563 | _camPos.y = _root.GetCenterOfMass().y; 564 | } 565 | 566 | 567 | bool ModelNBody::IsFinished(double *state) 568 | { 569 | return false; 570 | } 571 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.22 3 | 4 | # Default target executed when no arguments are given to make. 5 | default_target: all 6 | .PHONY : default_target 7 | 8 | # Allow only one "make -f Makefile2" at a time, but pass parallelism. 9 | .NOTPARALLEL: 10 | 11 | #============================================================================= 12 | # Special targets provided by cmake. 13 | 14 | # Disable implicit rules so canonical targets will work. 15 | .SUFFIXES: 16 | 17 | # Disable VCS-based implicit rules. 18 | % : %,v 19 | 20 | # Disable VCS-based implicit rules. 21 | % : RCS/% 22 | 23 | # Disable VCS-based implicit rules. 24 | % : RCS/%,v 25 | 26 | # Disable VCS-based implicit rules. 27 | % : SCCS/s.% 28 | 29 | # Disable VCS-based implicit rules. 30 | % : s.% 31 | 32 | .SUFFIXES: .hpux_make_needs_suffix_list 33 | 34 | # Command-line flag to silence nested $(MAKE). 35 | $(VERBOSE)MAKESILENT = -s 36 | 37 | #Suppress display of executed commands. 38 | $(VERBOSE).SILENT: 39 | 40 | # A target that is always out of date. 41 | cmake_force: 42 | .PHONY : cmake_force 43 | 44 | #============================================================================= 45 | # Set environment variables for the build. 46 | 47 | # The shell in which to execute make rules. 48 | SHELL = /bin/sh 49 | 50 | # The CMake executable. 51 | CMAKE_COMMAND = /usr/bin/cmake 52 | 53 | # The command to remove a file. 54 | RM = /usr/bin/cmake -E rm -f 55 | 56 | # Escaping for special characters. 57 | EQUALS = = 58 | 59 | # The top-level source directory on which CMake was run. 60 | CMAKE_SOURCE_DIR = /home/user/Dokumente/GitHub/Barnes-Hut-Simulator 61 | 62 | # The top-level build directory on which CMake was run. 63 | CMAKE_BINARY_DIR = /home/user/Dokumente/GitHub/Barnes-Hut-Simulator 64 | 65 | #============================================================================= 66 | # Targets provided globally by CMake. 67 | 68 | # Special rule for the target edit_cache 69 | edit_cache: 70 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." 71 | /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. 72 | .PHONY : edit_cache 73 | 74 | # Special rule for the target edit_cache 75 | edit_cache/fast: edit_cache 76 | .PHONY : edit_cache/fast 77 | 78 | # Special rule for the target rebuild_cache 79 | rebuild_cache: 80 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." 81 | /usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) 82 | .PHONY : rebuild_cache 83 | 84 | # Special rule for the target rebuild_cache 85 | rebuild_cache/fast: rebuild_cache 86 | .PHONY : rebuild_cache/fast 87 | 88 | # The main all target 89 | all: cmake_check_build_system 90 | $(CMAKE_COMMAND) -E cmake_progress_start /home/user/Dokumente/GitHub/Barnes-Hut-Simulator/CMakeFiles /home/user/Dokumente/GitHub/Barnes-Hut-Simulator//CMakeFiles/progress.marks 91 | $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all 92 | $(CMAKE_COMMAND) -E cmake_progress_start /home/user/Dokumente/GitHub/Barnes-Hut-Simulator/CMakeFiles 0 93 | .PHONY : all 94 | 95 | # The main clean target 96 | clean: 97 | $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean 98 | .PHONY : clean 99 | 100 | # The main clean target 101 | clean/fast: clean 102 | .PHONY : clean/fast 103 | 104 | # Prepare targets for installation. 105 | preinstall: all 106 | $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall 107 | .PHONY : preinstall 108 | 109 | # Prepare targets for installation. 110 | preinstall/fast: 111 | $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall 112 | .PHONY : preinstall/fast 113 | 114 | # clear depends 115 | depend: 116 | $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 117 | .PHONY : depend 118 | 119 | #============================================================================= 120 | # Target rules for targets named barnes-hut-simulator 121 | 122 | # Build rule for target. 123 | barnes-hut-simulator: cmake_check_build_system 124 | $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 barnes-hut-simulator 125 | .PHONY : barnes-hut-simulator 126 | 127 | # fast build rule for target. 128 | barnes-hut-simulator/fast: 129 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/build 130 | .PHONY : barnes-hut-simulator/fast 131 | 132 | src/BHTree.o: src/BHTree.cpp.o 133 | .PHONY : src/BHTree.o 134 | 135 | # target to build an object file 136 | src/BHTree.cpp.o: 137 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/BHTree.cpp.o 138 | .PHONY : src/BHTree.cpp.o 139 | 140 | src/BHTree.i: src/BHTree.cpp.i 141 | .PHONY : src/BHTree.i 142 | 143 | # target to preprocess a source file 144 | src/BHTree.cpp.i: 145 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/BHTree.cpp.i 146 | .PHONY : src/BHTree.cpp.i 147 | 148 | src/BHTree.s: src/BHTree.cpp.s 149 | .PHONY : src/BHTree.s 150 | 151 | # target to generate assembly for a file 152 | src/BHTree.cpp.s: 153 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/BHTree.cpp.s 154 | .PHONY : src/BHTree.cpp.s 155 | 156 | src/IIntegrator.o: src/IIntegrator.cpp.o 157 | .PHONY : src/IIntegrator.o 158 | 159 | # target to build an object file 160 | src/IIntegrator.cpp.o: 161 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IIntegrator.cpp.o 162 | .PHONY : src/IIntegrator.cpp.o 163 | 164 | src/IIntegrator.i: src/IIntegrator.cpp.i 165 | .PHONY : src/IIntegrator.i 166 | 167 | # target to preprocess a source file 168 | src/IIntegrator.cpp.i: 169 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IIntegrator.cpp.i 170 | .PHONY : src/IIntegrator.cpp.i 171 | 172 | src/IIntegrator.s: src/IIntegrator.cpp.s 173 | .PHONY : src/IIntegrator.s 174 | 175 | # target to generate assembly for a file 176 | src/IIntegrator.cpp.s: 177 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IIntegrator.cpp.s 178 | .PHONY : src/IIntegrator.cpp.s 179 | 180 | src/IModel.o: src/IModel.cpp.o 181 | .PHONY : src/IModel.o 182 | 183 | # target to build an object file 184 | src/IModel.cpp.o: 185 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IModel.cpp.o 186 | .PHONY : src/IModel.cpp.o 187 | 188 | src/IModel.i: src/IModel.cpp.i 189 | .PHONY : src/IModel.i 190 | 191 | # target to preprocess a source file 192 | src/IModel.cpp.i: 193 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IModel.cpp.i 194 | .PHONY : src/IModel.cpp.i 195 | 196 | src/IModel.s: src/IModel.cpp.s 197 | .PHONY : src/IModel.s 198 | 199 | # target to generate assembly for a file 200 | src/IModel.cpp.s: 201 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IModel.cpp.s 202 | .PHONY : src/IModel.cpp.s 203 | 204 | src/IntegratorADB4.o: src/IntegratorADB4.cpp.o 205 | .PHONY : src/IntegratorADB4.o 206 | 207 | # target to build an object file 208 | src/IntegratorADB4.cpp.o: 209 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB4.cpp.o 210 | .PHONY : src/IntegratorADB4.cpp.o 211 | 212 | src/IntegratorADB4.i: src/IntegratorADB4.cpp.i 213 | .PHONY : src/IntegratorADB4.i 214 | 215 | # target to preprocess a source file 216 | src/IntegratorADB4.cpp.i: 217 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB4.cpp.i 218 | .PHONY : src/IntegratorADB4.cpp.i 219 | 220 | src/IntegratorADB4.s: src/IntegratorADB4.cpp.s 221 | .PHONY : src/IntegratorADB4.s 222 | 223 | # target to generate assembly for a file 224 | src/IntegratorADB4.cpp.s: 225 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB4.cpp.s 226 | .PHONY : src/IntegratorADB4.cpp.s 227 | 228 | src/IntegratorADB5.o: src/IntegratorADB5.cpp.o 229 | .PHONY : src/IntegratorADB5.o 230 | 231 | # target to build an object file 232 | src/IntegratorADB5.cpp.o: 233 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB5.cpp.o 234 | .PHONY : src/IntegratorADB5.cpp.o 235 | 236 | src/IntegratorADB5.i: src/IntegratorADB5.cpp.i 237 | .PHONY : src/IntegratorADB5.i 238 | 239 | # target to preprocess a source file 240 | src/IntegratorADB5.cpp.i: 241 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB5.cpp.i 242 | .PHONY : src/IntegratorADB5.cpp.i 243 | 244 | src/IntegratorADB5.s: src/IntegratorADB5.cpp.s 245 | .PHONY : src/IntegratorADB5.s 246 | 247 | # target to generate assembly for a file 248 | src/IntegratorADB5.cpp.s: 249 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB5.cpp.s 250 | .PHONY : src/IntegratorADB5.cpp.s 251 | 252 | src/IntegratorADB6.o: src/IntegratorADB6.cpp.o 253 | .PHONY : src/IntegratorADB6.o 254 | 255 | # target to build an object file 256 | src/IntegratorADB6.cpp.o: 257 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB6.cpp.o 258 | .PHONY : src/IntegratorADB6.cpp.o 259 | 260 | src/IntegratorADB6.i: src/IntegratorADB6.cpp.i 261 | .PHONY : src/IntegratorADB6.i 262 | 263 | # target to preprocess a source file 264 | src/IntegratorADB6.cpp.i: 265 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB6.cpp.i 266 | .PHONY : src/IntegratorADB6.cpp.i 267 | 268 | src/IntegratorADB6.s: src/IntegratorADB6.cpp.s 269 | .PHONY : src/IntegratorADB6.s 270 | 271 | # target to generate assembly for a file 272 | src/IntegratorADB6.cpp.s: 273 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorADB6.cpp.s 274 | .PHONY : src/IntegratorADB6.cpp.s 275 | 276 | src/IntegratorRK4.o: src/IntegratorRK4.cpp.o 277 | .PHONY : src/IntegratorRK4.o 278 | 279 | # target to build an object file 280 | src/IntegratorRK4.cpp.o: 281 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRK4.cpp.o 282 | .PHONY : src/IntegratorRK4.cpp.o 283 | 284 | src/IntegratorRK4.i: src/IntegratorRK4.cpp.i 285 | .PHONY : src/IntegratorRK4.i 286 | 287 | # target to preprocess a source file 288 | src/IntegratorRK4.cpp.i: 289 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRK4.cpp.i 290 | .PHONY : src/IntegratorRK4.cpp.i 291 | 292 | src/IntegratorRK4.s: src/IntegratorRK4.cpp.s 293 | .PHONY : src/IntegratorRK4.s 294 | 295 | # target to generate assembly for a file 296 | src/IntegratorRK4.cpp.s: 297 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRK4.cpp.s 298 | .PHONY : src/IntegratorRK4.cpp.s 299 | 300 | src/IntegratorRK5.o: src/IntegratorRK5.cpp.o 301 | .PHONY : src/IntegratorRK5.o 302 | 303 | # target to build an object file 304 | src/IntegratorRK5.cpp.o: 305 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRK5.cpp.o 306 | .PHONY : src/IntegratorRK5.cpp.o 307 | 308 | src/IntegratorRK5.i: src/IntegratorRK5.cpp.i 309 | .PHONY : src/IntegratorRK5.i 310 | 311 | # target to preprocess a source file 312 | src/IntegratorRK5.cpp.i: 313 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRK5.cpp.i 314 | .PHONY : src/IntegratorRK5.cpp.i 315 | 316 | src/IntegratorRK5.s: src/IntegratorRK5.cpp.s 317 | .PHONY : src/IntegratorRK5.s 318 | 319 | # target to generate assembly for a file 320 | src/IntegratorRK5.cpp.s: 321 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRK5.cpp.s 322 | .PHONY : src/IntegratorRK5.cpp.s 323 | 324 | src/IntegratorRKF4.o: src/IntegratorRKF4.cpp.o 325 | .PHONY : src/IntegratorRKF4.o 326 | 327 | # target to build an object file 328 | src/IntegratorRKF4.cpp.o: 329 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRKF4.cpp.o 330 | .PHONY : src/IntegratorRKF4.cpp.o 331 | 332 | src/IntegratorRKF4.i: src/IntegratorRKF4.cpp.i 333 | .PHONY : src/IntegratorRKF4.i 334 | 335 | # target to preprocess a source file 336 | src/IntegratorRKF4.cpp.i: 337 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRKF4.cpp.i 338 | .PHONY : src/IntegratorRKF4.cpp.i 339 | 340 | src/IntegratorRKF4.s: src/IntegratorRKF4.cpp.s 341 | .PHONY : src/IntegratorRKF4.s 342 | 343 | # target to generate assembly for a file 344 | src/IntegratorRKF4.cpp.s: 345 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/IntegratorRKF4.cpp.s 346 | .PHONY : src/IntegratorRKF4.cpp.s 347 | 348 | src/ModelNBody.o: src/ModelNBody.cpp.o 349 | .PHONY : src/ModelNBody.o 350 | 351 | # target to build an object file 352 | src/ModelNBody.cpp.o: 353 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/ModelNBody.cpp.o 354 | .PHONY : src/ModelNBody.cpp.o 355 | 356 | src/ModelNBody.i: src/ModelNBody.cpp.i 357 | .PHONY : src/ModelNBody.i 358 | 359 | # target to preprocess a source file 360 | src/ModelNBody.cpp.i: 361 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/ModelNBody.cpp.i 362 | .PHONY : src/ModelNBody.cpp.i 363 | 364 | src/ModelNBody.s: src/ModelNBody.cpp.s 365 | .PHONY : src/ModelNBody.s 366 | 367 | # target to generate assembly for a file 368 | src/ModelNBody.cpp.s: 369 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/ModelNBody.cpp.s 370 | .PHONY : src/ModelNBody.cpp.s 371 | 372 | src/NBodyWnd.o: src/NBodyWnd.cpp.o 373 | .PHONY : src/NBodyWnd.o 374 | 375 | # target to build an object file 376 | src/NBodyWnd.cpp.o: 377 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/NBodyWnd.cpp.o 378 | .PHONY : src/NBodyWnd.cpp.o 379 | 380 | src/NBodyWnd.i: src/NBodyWnd.cpp.i 381 | .PHONY : src/NBodyWnd.i 382 | 383 | # target to preprocess a source file 384 | src/NBodyWnd.cpp.i: 385 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/NBodyWnd.cpp.i 386 | .PHONY : src/NBodyWnd.cpp.i 387 | 388 | src/NBodyWnd.s: src/NBodyWnd.cpp.s 389 | .PHONY : src/NBodyWnd.s 390 | 391 | # target to generate assembly for a file 392 | src/NBodyWnd.cpp.s: 393 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/NBodyWnd.cpp.s 394 | .PHONY : src/NBodyWnd.cpp.s 395 | 396 | src/SDLWnd.o: src/SDLWnd.cpp.o 397 | .PHONY : src/SDLWnd.o 398 | 399 | # target to build an object file 400 | src/SDLWnd.cpp.o: 401 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/SDLWnd.cpp.o 402 | .PHONY : src/SDLWnd.cpp.o 403 | 404 | src/SDLWnd.i: src/SDLWnd.cpp.i 405 | .PHONY : src/SDLWnd.i 406 | 407 | # target to preprocess a source file 408 | src/SDLWnd.cpp.i: 409 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/SDLWnd.cpp.i 410 | .PHONY : src/SDLWnd.cpp.i 411 | 412 | src/SDLWnd.s: src/SDLWnd.cpp.s 413 | .PHONY : src/SDLWnd.s 414 | 415 | # target to generate assembly for a file 416 | src/SDLWnd.cpp.s: 417 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/SDLWnd.cpp.s 418 | .PHONY : src/SDLWnd.cpp.s 419 | 420 | src/Types.o: src/Types.cpp.o 421 | .PHONY : src/Types.o 422 | 423 | # target to build an object file 424 | src/Types.cpp.o: 425 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/Types.cpp.o 426 | .PHONY : src/Types.cpp.o 427 | 428 | src/Types.i: src/Types.cpp.i 429 | .PHONY : src/Types.i 430 | 431 | # target to preprocess a source file 432 | src/Types.cpp.i: 433 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/Types.cpp.i 434 | .PHONY : src/Types.cpp.i 435 | 436 | src/Types.s: src/Types.cpp.s 437 | .PHONY : src/Types.s 438 | 439 | # target to generate assembly for a file 440 | src/Types.cpp.s: 441 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/Types.cpp.s 442 | .PHONY : src/Types.cpp.s 443 | 444 | src/Vector.o: src/Vector.cpp.o 445 | .PHONY : src/Vector.o 446 | 447 | # target to build an object file 448 | src/Vector.cpp.o: 449 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/Vector.cpp.o 450 | .PHONY : src/Vector.cpp.o 451 | 452 | src/Vector.i: src/Vector.cpp.i 453 | .PHONY : src/Vector.i 454 | 455 | # target to preprocess a source file 456 | src/Vector.cpp.i: 457 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/Vector.cpp.i 458 | .PHONY : src/Vector.cpp.i 459 | 460 | src/Vector.s: src/Vector.cpp.s 461 | .PHONY : src/Vector.s 462 | 463 | # target to generate assembly for a file 464 | src/Vector.cpp.s: 465 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/Vector.cpp.s 466 | .PHONY : src/Vector.cpp.s 467 | 468 | src/main.o: src/main.cpp.o 469 | .PHONY : src/main.o 470 | 471 | # target to build an object file 472 | src/main.cpp.o: 473 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/main.cpp.o 474 | .PHONY : src/main.cpp.o 475 | 476 | src/main.i: src/main.cpp.i 477 | .PHONY : src/main.i 478 | 479 | # target to preprocess a source file 480 | src/main.cpp.i: 481 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/main.cpp.i 482 | .PHONY : src/main.cpp.i 483 | 484 | src/main.s: src/main.cpp.s 485 | .PHONY : src/main.s 486 | 487 | # target to generate assembly for a file 488 | src/main.cpp.s: 489 | $(MAKE) $(MAKESILENT) -f CMakeFiles/barnes-hut-simulator.dir/build.make CMakeFiles/barnes-hut-simulator.dir/src/main.cpp.s 490 | .PHONY : src/main.cpp.s 491 | 492 | # Help Target 493 | help: 494 | @echo "The following are some of the valid targets for this Makefile:" 495 | @echo "... all (the default if no target is provided)" 496 | @echo "... clean" 497 | @echo "... depend" 498 | @echo "... edit_cache" 499 | @echo "... rebuild_cache" 500 | @echo "... barnes-hut-simulator" 501 | @echo "... src/BHTree.o" 502 | @echo "... src/BHTree.i" 503 | @echo "... src/BHTree.s" 504 | @echo "... src/IIntegrator.o" 505 | @echo "... src/IIntegrator.i" 506 | @echo "... src/IIntegrator.s" 507 | @echo "... src/IModel.o" 508 | @echo "... src/IModel.i" 509 | @echo "... src/IModel.s" 510 | @echo "... src/IntegratorADB4.o" 511 | @echo "... src/IntegratorADB4.i" 512 | @echo "... src/IntegratorADB4.s" 513 | @echo "... src/IntegratorADB5.o" 514 | @echo "... src/IntegratorADB5.i" 515 | @echo "... src/IntegratorADB5.s" 516 | @echo "... src/IntegratorADB6.o" 517 | @echo "... src/IntegratorADB6.i" 518 | @echo "... src/IntegratorADB6.s" 519 | @echo "... src/IntegratorRK4.o" 520 | @echo "... src/IntegratorRK4.i" 521 | @echo "... src/IntegratorRK4.s" 522 | @echo "... src/IntegratorRK5.o" 523 | @echo "... src/IntegratorRK5.i" 524 | @echo "... src/IntegratorRK5.s" 525 | @echo "... src/IntegratorRKF4.o" 526 | @echo "... src/IntegratorRKF4.i" 527 | @echo "... src/IntegratorRKF4.s" 528 | @echo "... src/ModelNBody.o" 529 | @echo "... src/ModelNBody.i" 530 | @echo "... src/ModelNBody.s" 531 | @echo "... src/NBodyWnd.o" 532 | @echo "... src/NBodyWnd.i" 533 | @echo "... src/NBodyWnd.s" 534 | @echo "... src/SDLWnd.o" 535 | @echo "... src/SDLWnd.i" 536 | @echo "... src/SDLWnd.s" 537 | @echo "... src/Types.o" 538 | @echo "... src/Types.i" 539 | @echo "... src/Types.s" 540 | @echo "... src/Vector.o" 541 | @echo "... src/Vector.i" 542 | @echo "... src/Vector.s" 543 | @echo "... src/main.o" 544 | @echo "... src/main.i" 545 | @echo "... src/main.s" 546 | .PHONY : help 547 | 548 | 549 | 550 | #============================================================================= 551 | # Special targets to cleanup operation of make. 552 | 553 | # Special rule to run CMake to check the build system integrity. 554 | # No rule that depends on this can have commands that come from listfiles 555 | # because they might be regenerated. 556 | cmake_check_build_system: 557 | $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 558 | .PHONY : cmake_check_build_system 559 | 560 | --------------------------------------------------------------------------------