/* * Calculate Kepler position and velocity for given timestep _dt_ * for particle no. _pos_. * _xp_ and _vp_ will be updated. */ void step_kepler_1(struct particle parts[], int pcount, int pos, double dt, double *out_a, double *out_a_, double *out_a_2, double *out_a_3, double *curr_a, double *curr_e) { _enter_function(_UL_KEPLER, _UL_KEPLER_STEP_KEPLER_1); int i; struct particle *p0 = parts, *p1 = parts + pos; double r_[3], v_[3], j_[3], ecc_[3], a_[3], b_[3], _1_r2, afact, v_r_, v_v_, r_a_, v_a_, r_a__; double ecc, a, r, v, b, omega, e, mean, cosp, sinp; double m_c=p0->m, _cosp_ecc, e2, _1_ecc, _cosp_1, de_dt;//+p1->m; // get relative position / motion for(i = 0; i < 3; i++) { r_[i] = p1->xp[i] - p0->xp[i]; v_[i] = p1->vp[i] - p0->vp[i]; } // calculate ellipse constants get_constants(r_, v_, m_c, j_, ecc_, &a, &omega); //printf("# [%d]:\t%e\t%e\t%e\n", pos, v_abs(ecc_), a, omega); ecc = v_abs(ecc_); // b_ = a * sqrt(|1-e²|) * (j_ x e_) / |j_ x e_| vec_prod(j_, ecc_, b_); b = a * sqrt(fabs(1-ecc*ecc)) / v_abs(b_); for(i = 0; i < 3; i++) { a_[i] = a*ecc_[i]/ecc; // semi major vector b_[i] *= b; // semi minor vector } if(curr_a != NULL) *curr_a = a; if(curr_e != NULL) *curr_e = ecc; if(ecc < 1) // elliptical orbit { if(!p1->is_elliptical) { fprintf(get_file(FILE_WARNING), "#### [t=%1.12e] Particle #%d captured onto elliptical orbit with e=%e ####\n", t_total(p1->t), pos, ecc); p1->is_elliptical = 1; } // calculate eccentric anomaly e at t+dt e = (a - v_abs(r_)) / (ecc * a); if(e >= 1.0) e = .0; else if(e <= -1.0) e = M_PI; else e = acos(e); if(scal_prod(r_, b_) < 0) e = 2*M_PI - e; mean = (e - ecc*sin(e)) + dt * omega; while(mean >= 2. * M_PI) mean -= 2. * M_PI; e = solve_kepler(mean, ecc); cosp = cos(e); sinp = sin(e); _cosp_ecc = cosp - ecc; de_dt = omega / (1. - ecc * cosp); if(ecc > .99) { e2 = (e > 2. * M_PI - 1e-3) ? e - 2. * M_PI : e; if(e2 < 1e-3) { e2 *= e2; _1_ecc = scal_prod(j_, j_)/(p0->m*a*(1+ecc)); _cosp_1 = - .5 * e2 * (1 - e2 / 12. * (1 - e2 / 30.)); _cosp_ecc = _1_ecc + _cosp_1; de_dt = omega / (_1_ecc - ecc * _cosp_1); } } for(i = 0; i < DIMENSIONS; i++) { r_[i] = a_[i] * _cosp_ecc + b_[i] * sinp ; // new location v_[i] = (-a_[i] * sinp + b_[i] * cosp) * de_dt; // direction of v only } } else // hyperbolic orbit // parabolic? { if(p1->is_elliptical) { fprintf(get_file(FILE_WARNING), "#### [t=%1.12e+%1.12e] Particle #%d thrown onto hyperbolic orbit with e=%e (E=%e, a=%e) ####\n", t_total(p1->t), convert_time(dt, 0), pos, ecc, p1->energy, convert_length(a, 0)); p1->is_elliptical = 0; } if(ecc == 1) fprintf(get_file(FILE_WARNING), "# # # %e\tParabolic orbit of m%d treated as hyperbolic: e=%e\t(x=%e)\n", t_total(p1->t), pos, ecc, convert_length(v_abs(p1->xp), 0)); // calculate eccentric anomaly e at t+dt e = (a + v_abs(r_)) / (ecc * a); if(e < 1.0) e = .0; else if(scal_prod(r_, v_) < 0) e = -acosh(e); else e = acosh(e); e = kepler(ecc, ecc * sinh(e) - e + dt * omega); cosp = cosh(e); sinp = sinh(e); de_dt = omega / (ecc * cosp - 1.); for(i = 0; i < DIMENSIONS; i++) { r_[i] = a_[i] * (ecc - cosp) + b_[i] * sinp; // new location v_[i] = (-a_[i] * sinp + b_[i] * cosp) * de_dt; // direction of v only } } // get |v_| from j_ = r_ x v_ v = v_abs(v_); r = v_abs(r_); v = v_abs(j_) / (r * v * sin(acos(scal_prod(r_, v_)/ (r * v)))); for(i = 0; i < DIMENSIONS; i++) { //v_[i] *= v; // total motion relative to fix central mass p1->xp[i] = p0->xp[i] + r_[i]; p1->vp[i] = p0->vp[i] + v_[i]; } if(out_a != NULL) { _1_r2 = 1. / scal_prod(r_, r_); afact = - m_c * _1_r2 * sqrt(_1_r2); //printf("4 %e %e %e\n", *(out_a), *(out_a+1), *(out_a+2)); for(i = 0; i < DIMENSIONS; i++) out_a[i] = afact * r_[i]; if(out_a_ != NULL) { v_r_ = scal_prod(v_, r_); for(i = 0; i < DIMENSIONS; i++) out_a_[i] = afact * (v_[i] - 3 * _1_r2 * v_r_ * r_[i]); if(out_a_2 != NULL) { v_v_ = scal_prod(v_, v_); r_a_ = scal_prod(r_, out_a); for(i = 0; i < DIMENSIONS; i++) out_a_2[i] = afact * (out_a[i] - 3. * _1_r2 * (v_r_ * (2. * v_[i] - 5. * v_r_ * r_[i] * _1_r2) + (v_v_ + r_a_) * r_[i])); if(out_a_3 != NULL) { v_a_ = scal_prod(v_, out_a); r_a__ = scal_prod(r_, out_a_); for(i = 0; i < DIMENSIONS; i++) out_a_3[i] = afact * (out_a_[i] - 3. * _1_r2 * (3. * v_r_ * out_a[i] + 3. * (v_v_ + r_a_) * (v_[i] - 5. * v_r_ * _1_r2 * r_[i]) + (3. * v_a_ + r_a__) * r_[i] + v_r_ * v_r_ * _1_r2 * (-15. * v_[i] + 35. * v_r_ * _1_r2 * r_[i]))); } } } } _exit_function(); }
double advance_orbit_set_up(BEMRI * b, double chi, double r_current, double dt1) { double t_current, t_new, psi_h_target, theta_h_target, psi_b_advanced, Mb, t_elapsed, new_true; //find current hole eccentric anomaly psi_h = acos( (eh + cos(theta_h)) / (1+eh*cos(theta_h)) ); //find current time in the orbit (since last periapse) t_current = Ph/(2*PI) * (psi_h - eh*sin(psi_h)); //now find target (new) values psi_h_target = 2*PI - acos( (1 - chi/ah) / eh); //hole eccentric anomaly value to skip to theta_h_target = fix_angle( 2*atan2(sqrt(1+eh)*sin(psi_h_target/2.0) , sqrt(1-eh)*cos(psi_h_target/2)) ); //hole true anomaly value to skip to t_new = Ph/(2*PI) * (psi_h_target - eh*sin(psi_h_target)); //new time value from Kepler's equation //then the elapsed time is given by: t_elapsed = t_new - t_current; //printf("\nt_elapsed = %.5e",t_elapsed); //_+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //force t_elapsed to equal an integer multiple of dt1 t_elapsed = floor(t_elapsed/dt1) * dt1; //now t_elapsed is good t_new = t_elapsed + t_current; //now we're recalculating the hole orbit anomalies //printf("\nMh = %.15e",2*PI/Ph*t_new); psi_h_target = solve_kepler(2*PI/Ph*t_new,eh); //here is the new target eccentric anomaly theta_h_target = fix_angle( 2*atan2(sqrt(1+eh)*sin(psi_h_target/2.0) , sqrt(1-eh)*cos(psi_h_target/2.0)) ); //new hole true anomaly value to skip to //printf("\npsi_h_target = %.3e\nsolving keplers eqn for t_new = %.3f",psi_h_target, Ph/(2*PI)*kepler(psi_h_target,eh)); //printf("\nt_elapsed / dt1 = %.20f\n",t_elapsed / dt1); //_+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //now the mean anomaly of the BEMRI orbit will have advanced by: Mb = 2*PI/Pb*t_elapsed - 2*PI*floor(t_elapsed/Pb); //note this is not the current mean anomaly of the BEMRI, but how much it has advanced //here is how much the eccentric anomaly of the BEMRI has advanced psi_b_advanced = solve_kepler(Mb,eb); //so the new value of the true anomaly of the BEMRI is given by: (current + advanced) new_true = theta_b + fix_angle((2*atan2(sqrt(1+eb)*sin(psi_b_advanced/2.0),sqrt(1-eb)*cos(psi_b_advanced/2.0))) ); //_+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //printf("\ncurrent hole anomaly is %.3f, target anomaly is %.3f\n",theta_h, theta_h_target); //printf("chi = %.3e\nah = %.3e\neh=%.3e\n",chi,ah,eh); //_+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //before advancing the BH orbit, freeze the BEMRI CM motion so the new CM motion can be added on easily for(int i=0; i < 3; i++) { V1[i] -= V4[i]; //remove CM motion for mass 1 V2[i] -= V4[i]; //remove CM motion for mass 2 R1[i] -= R4[i]; R2[i] -= R4[i]; } //now that we know the new true anomaly of the hole AND the BEMRI, we can advance the two orbits to the new positions advance_orbit(&(b->binary_b),lb,new_true); //now advance the BH orbit advance_orbit(&(b->binary_h),lh,theta_h_target); //and now the BEMRI CM values need to be updated: //BEMRI_CM_update(b); return t_elapsed; }