// a single Leapfrog step (parameter = step length) void Solvers::Leapfrog(double step) { int n = this->_leapfrog->n(); // number of celestial bodies double halfStep = (step / 2.0); // calculate forces/accelerations based on current postions this->_leapfrog->setForces(); for (int j = 0; j < n; j++) // for each celestial body { CelestialBody* cb = this->_leapfrog->body(j); if (!cb->fixed) // a fixed celestial body will never move { // Leapfrog algorithm, step 1 *(cb->velocity) += halfStep * cb->acc(); // Leapfrog algorithm, step 2 *(cb->position) += step * *(cb->velocity); } } // calculate the forces using the new positions this->_leapfrog->setForces(); for (int j = 0; j < n; j++) // for each celestial body { CelestialBody* cb = this->_leapfrog->body(j); if (!cb->fixed) // a fixed celestial body will never move { // Leapfrog algorithm, step 3 *(cb->velocity) += halfStep * cb->acc(); } } }
// a single Euler-Cromer step (parameter = step length) void Solvers::Euler(double step) { int n = this->_euler->n(); // number of celestial bodies // calculate forces/accelerations based on current postions this->_euler->setForces(); for (int j = 0; j < n; j++) // for each celestial body { CelestialBody* cb = this->_euler->body(j); if (!cb->fixed) // a fixed celestial body will never move { // acc -> velocity (Euler-Cromer, for testing only) *(cb->velocity) += step * cb->acc(); // velocity -> position (Euler-Cromer, for testing only) *(cb->position) += step * *(cb->velocity); } } }
// a single Runge-Kutta step (parameter = step length) void Solvers::RK4(double step) { int n = this->_rk4->n(); // matrices for Runge-Kutta values: mat k1_v(this->_rk4->dim(), n); // k1, velocity mat k1_p(this->_rk4->dim(), n); // k1, position mat k2_v(this->_rk4->dim(), n); // k2, velocity (etc.) mat k2_p(this->_rk4->dim(), n); mat k3_v(this->_rk4->dim(), n); mat k3_p(this->_rk4->dim(), n); mat k4_v(this->_rk4->dim(), n); mat k4_p(this->_rk4->dim(), n); // initial position and velocity for each celestial body mat orig_v(this->_rk4->dim(), n); mat orig_p(this->_rk4->dim(), n); #pragma region k1 // calculate forces/accelerations based on current postions this->_rk4->setForces(); for (int j = 0; j < n; j++) // for each celestial body { CelestialBody* cb = this->_rk4->body(j); if (!cb->fixed) // a fixed celestial body will never move { // store initial position and velocity orig_v.col(j) = *(cb->velocity); orig_p.col(j) = *(cb->position); // save values k1_v.col(j) = step * cb->acc(); k1_p.col(j) = step * *(cb->velocity); // advance to mid-point after k1 *(cb->velocity) = orig_v.col(j) + 0.5 * k1_v.col(j); *(cb->position) = orig_p.col(j) + 0.5 * k1_p.col(j); } } #pragma endregion #pragma region k2 // calculate forces/accelerations based on current postions this->_rk4->setForces(); for (int j = 0; j < n; j++) // for each celestial body { CelestialBody* cb = this->_rk4->body(j); if (!cb->fixed) // a fixed celestial body will never move { // save values k2_v.col(j) = step * cb->acc(); k2_p.col(j) = step * *(cb->velocity); // switch to new mid-point using k2 instead *(cb->velocity) = orig_v.col(j) + 0.5 * k2_v.col(j); *(cb->position) = orig_p.col(j) + 0.5 * k2_p.col(j); } } #pragma endregion #pragma region k3 // calculate forces/accelerations based on current postions this->_rk4->setForces(); for (int j = 0; j < n; j++) // for each celestial body { CelestialBody* cb = this->_rk4->body(j); if (!cb->fixed) // a fixed celestial body will never move { // save values k3_v.col(j) = step * cb->acc(); k3_p.col(j) = step * *(cb->velocity); // switch to end-point *(cb->velocity) = orig_v.col(j) + k3_v.col(j); *(cb->position) = orig_p.col(j) + k3_p.col(j); } } #pragma endregion #pragma region k4 // calculate forces/accelerations based on current postions this->_rk4->setForces(); for (int j = 0; j < n; j++) // for each celestial body { CelestialBody* cb = this->_rk4->body(j); if (!cb->fixed) // a fixed celestial body will never move { // save values k4_v.col(j) = step * cb->acc(); k4_p.col(j) = step * *(cb->velocity); // finally, update position and velocity *(cb->velocity) = orig_v.col(j) + (1.0 / 6.0)*(k1_v.col(j) + 2.0 * k2_v.col(j) + 2.0 * k3_v.col(j) + k4_v.col(j)); *(cb->position) = orig_p.col(j) + (1.0 / 6.0)*(k1_p.col(j) + 2.0 * k2_p.col(j) + 2.0 * k3_p.col(j) + k4_p.col(j)); } } #pragma endregion }