def compress_binary_components(comp1, comp2, scale): # Compress the two-body system consisting of comp1 and comp2 to # lie within distance scale of one another. pos1 = comp1.position pos2 = comp2.position sep12 = ((pos2-pos1)**2).sum() if sep12 > scale*scale: print '\ncompressing components', int(comp1.id.number), \ 'and', int(comp2.id.number), 'to separation', scale.number sys.stdout.flush() mass1 = comp1.mass mass2 = comp2.mass total_mass = mass1 + mass2 vel1 = comp1.velocity vel2 = comp2.velocity cmpos = (mass1*pos1+mass2*pos2)/total_mass cmvel = (mass1*vel1+mass2*vel2)/total_mass # For now, create and delete a temporary kepler # process to handle the transformation. Obviously # more efficient to define a single kepler at the # start of the calculation and reuse it. kep = Kepler(redirection = "none") kep.initialize_code() mass = comp1.mass + comp2.mass rel_pos = pos2 - pos1 rel_vel = vel2 - vel1 kep.initialize_from_dyn(mass, rel_pos[0], rel_pos[1], rel_pos[2], rel_vel[0], rel_vel[1], rel_vel[2]) M,th = kep.get_angles() a,e = kep.get_elements() if e < 1: peri = a*(1-e) apo = a*(1+e) else: peri = a*(e-1) apo = 2*a # OK - used ony to reset scale limit = peri + 0.01*(apo-peri) if scale < limit: scale = limit if M < 0: # print 'approaching' kep.advance_to_periastron() kep.advance_to_radius(limit) else: # print 'receding' if kep.get_separation() < scale: kep.advance_to_radius(limit) else: kep.return_to_radius(scale) # a,e = kep.get_elements() # r = kep.get_separation() # E,J = kep.get_integrals() # print 'kepler: a,e,r =', a.number, e.number, r.number # print 'E, J =', E, J # Note: if periastron > scale, we are now just past periastron. new_rel_pos = kep.get_separation_vector() new_rel_vel = kep.get_velocity_vector() kep.stop() # Enew = 0 # r2 = 0 # for k in range(3): # Enew += 0.5*(new_rel_vel[k].number)**2 # r2 += (new_rel_pos[k].number)**2 # rnew = math.sqrt(r2) # Enew -= mass.number/r1 # print 'E, Enew, rnew =', E.number, E1, r1 # Problem: the vectors returned by kepler are lists, # not numpy arrays, and it looks as though we can say # comp1.position = pos, but not comp1.position[k] = # xxx, as we'd like... Also, we don't know how to # copy a numpy array with units... TODO newpos1 = pos1 - pos1 # stupid trick to create zero vectors newpos2 = pos2 - pos2 # with the proper form and units... newvel1 = vel1 - vel1 newvel2 = vel2 - vel2 frac2 = mass2/total_mass for k in range(3): dxk = new_rel_pos[k] dvk = new_rel_vel[k] newpos1[k] = cmpos[k] - frac2*dxk newpos2[k] = cmpos[k] + (1-frac2)*dxk newvel1[k] = cmvel[k] - frac2*dvk newvel2[k] = cmvel[k] + (1-frac2)*dvk # Perform the changes to comp1 and comp2, and recursively # transmit them to the (currently absolute) coordinates of # all lower components. offset_particle_tree(comp1, newpos1-pos1, newvel1-vel1) offset_particle_tree(comp2, newpos2-pos2, newvel2-vel2)
def get_orbit_ini(m0, m1, peri, ecc, incl, omega, rel_force=0.01, r_disk=50|units.AU): converter=nbody_system.nbody_to_si(1|units.MSun,1|units.AU) # semi-major axis if ecc!=1.0: semi = peri/(1.0-ecc) else: semi = 1.0e10 | units.AU # relative position and velocity vectors at the pericenter using kepler kepler = Kepler_twobody(converter) kepler.initialize_code() kepler.initialize_from_elements(mass=(m0+m1), semi=semi, ecc=ecc, periastron=peri) # at pericenter # moving particle backwards to radius r where: F_m1(r) = rel_force*F_m0(r_disk) #r_disk = peri r_ini = r_disk*(1.0 + numpy.sqrt(m1/m0)/rel_force) kepler.return_to_radius(radius=r_ini) rl = kepler.get_separation_vector() r = [rl[0].value_in(units.AU), rl[1].value_in(units.AU), rl[2].value_in(units.AU)] | units.AU vl = kepler.get_velocity_vector() v = [vl[0].value_in(units.kms), vl[1].value_in(units.kms), vl[2].value_in(units.kms)] | units.kms period_kepler = kepler.get_period() time_peri = kepler.get_time() kepler.stop() # rotation of the orbital plane by inclination and argument of periapsis a1 = ([1.0, 0.0, 0.0], [0.0, numpy.cos(incl), -numpy.sin(incl)], [0.0, numpy.sin(incl), numpy.cos(incl)]) a2 = ([numpy.cos(omega), -numpy.sin(omega), 0.0], [numpy.sin(omega), numpy.cos(omega), 0.0], [0.0, 0.0, 1.0]) rot = numpy.dot(a1,a2) r_au = numpy.reshape(r.value_in(units.AU), 3, 1) v_kms = numpy.reshape(v.value_in(units.kms), 3, 1) r_rot = numpy.dot(rot, r_au) | units.AU v_rot = numpy.dot(rot, v_kms) | units.kms bodies = Particles(2) bodies[0].mass = m0 bodies[0].radius = 1.0|units.RSun bodies[0].position = (0,0,0) | units.AU bodies[0].velocity = (0,0,0) | units.kms bodies[1].mass = m1 bodies[1].radius = 1.0|units.RSun bodies[1].x = r_rot[0] bodies[1].y = r_rot[1] bodies[1].z = r_rot[2] bodies[1].vx = v_rot[0] bodies[1].vy = v_rot[1] bodies[1].vz = v_rot[2] bodies.age = 0.0 | units.yr bodies.move_to_center() print "\t r_rel_ini = ", r_rot.in_(units.AU) print "\t v_rel_ini = ", v_rot.in_(units.kms) print "\t time since peri = ", time_peri.in_(units.yr) a_orbit, e_orbit, p_orbit = orbital_parameters(r_rot, v_rot, (m0+m1)) print "\t a = ", a_orbit.in_(units.AU), "\t e = ", e_orbit, "\t period = ", p_orbit.in_(units.yr) return bodies, time_peri
def compress_binary_components(comp1, comp2, scale): # Compress the two-body system consisting of comp1 and comp2 to # lie within distance scale of one another. pos1 = comp1.position pos2 = comp2.position sep12 = ((pos2 - pos1)**2).sum() if sep12 > scale * scale: print('\ncompressing components', int(comp1.id.number), \ 'and', int(comp2.id.number), 'to separation', scale.number) sys.stdout.flush() mass1 = comp1.mass mass2 = comp2.mass total_mass = mass1 + mass2 vel1 = comp1.velocity vel2 = comp2.velocity cmpos = (mass1 * pos1 + mass2 * pos2) / total_mass cmvel = (mass1 * vel1 + mass2 * vel2) / total_mass # For now, create and delete a temporary kepler # process to handle the transformation. Obviously # more efficient to define a single kepler at the # start of the calculation and reuse it. kep = Kepler(redirection="none") kep.initialize_code() mass = comp1.mass + comp2.mass rel_pos = pos2 - pos1 rel_vel = vel2 - vel1 kep.initialize_from_dyn(mass, rel_pos[0], rel_pos[1], rel_pos[2], rel_vel[0], rel_vel[1], rel_vel[2]) M, th = kep.get_angles() a, e = kep.get_elements() if e < 1: peri = a * (1 - e) apo = a * (1 + e) else: peri = a * (e - 1) apo = 2 * a # OK - used ony to reset scale limit = peri + 0.01 * (apo - peri) if scale < limit: scale = limit if M < 0: # print 'approaching' kep.advance_to_periastron() kep.advance_to_radius(limit) else: # print 'receding' if kep.get_separation() < scale: kep.advance_to_radius(limit) else: kep.return_to_radius(scale) # a,e = kep.get_elements() # r = kep.get_separation() # E,J = kep.get_integrals() # print 'kepler: a,e,r =', a.number, e.number, r.number # print 'E, J =', E, J # Note: if periastron > scale, we are now just past periastron. new_rel_pos = kep.get_separation_vector() new_rel_vel = kep.get_velocity_vector() kep.stop() # Enew = 0 # r2 = 0 # for k in range(3): # Enew += 0.5*(new_rel_vel[k].number)**2 # r2 += (new_rel_pos[k].number)**2 # rnew = math.sqrt(r2) # Enew -= mass.number/r1 # print 'E, Enew, rnew =', E.number, E1, r1 # Problem: the vectors returned by kepler are lists, # not numpy arrays, and it looks as though we can say # comp1.position = pos, but not comp1.position[k] = # xxx, as we'd like... Also, we don't know how to # copy a numpy array with units... TODO newpos1 = pos1 - pos1 # stupid trick to create zero vectors newpos2 = pos2 - pos2 # with the proper form and units... newvel1 = vel1 - vel1 newvel2 = vel2 - vel2 frac2 = mass2 / total_mass for k in range(3): dxk = new_rel_pos[k] dvk = new_rel_vel[k] newpos1[k] = cmpos[k] - frac2 * dxk newpos2[k] = cmpos[k] + (1 - frac2) * dxk newvel1[k] = cmvel[k] - frac2 * dvk newvel2[k] = cmvel[k] + (1 - frac2) * dvk # Perform the changes to comp1 and comp2, and recursively # transmit them to the (currently absolute) coordinates of # all lower components. offset_particle_tree(comp1, newpos1 - pos1, newvel1 - vel1) offset_particle_tree(comp2, newpos2 - pos2, newvel2 - vel2)
def get_orbit_ini(m0, m1, peri, ecc, incl, omega, rel_force=0.01, r_disk=50 | units.AU): converter = nbody_system.nbody_to_si(1 | units.MSun, 1 | units.AU) # semi-major axis if ecc != 1.0: semi = peri / (1.0 - ecc) else: semi = 1.0e10 | units.AU # relative position and velocity vectors at the pericenter using kepler kepler = Kepler_twobody(converter) kepler.initialize_code() kepler.initialize_from_elements(mass=(m0 + m1), semi=semi, ecc=ecc, periastron=peri) # at pericenter # moving particle backwards to radius r where: F_m1(r) = rel_force*F_m0(r_disk) #r_disk = peri r_ini = r_disk * (1.0 + numpy.sqrt(m1 / m0) / rel_force) kepler.return_to_radius(radius=r_ini) rl = kepler.get_separation_vector() r = [ rl[0].value_in(units.AU), rl[1].value_in(units.AU), rl[2].value_in( units.AU) ] | units.AU vl = kepler.get_velocity_vector() v = [ vl[0].value_in(units.kms), vl[1].value_in(units.kms), vl[2].value_in( units.kms) ] | units.kms period_kepler = kepler.get_period() time_peri = kepler.get_time() kepler.stop() # rotation of the orbital plane by inclination and argument of periapsis a1 = ([1.0, 0.0, 0.0], [0.0, numpy.cos(incl), -numpy.sin(incl)], [0.0, numpy.sin(incl), numpy.cos(incl)]) a2 = ([numpy.cos(omega), -numpy.sin(omega), 0.0], [numpy.sin(omega), numpy.cos(omega), 0.0], [0.0, 0.0, 1.0]) rot = numpy.dot(a1, a2) r_au = numpy.reshape(r.value_in(units.AU), 3, 1) v_kms = numpy.reshape(v.value_in(units.kms), 3, 1) r_rot = numpy.dot(rot, r_au) | units.AU v_rot = numpy.dot(rot, v_kms) | units.kms bodies = Particles(2) bodies[0].mass = m0 bodies[0].radius = 1.0 | units.RSun bodies[0].position = (0, 0, 0) | units.AU bodies[0].velocity = (0, 0, 0) | units.kms bodies[1].mass = m1 bodies[1].radius = 1.0 | units.RSun bodies[1].x = r_rot[0] bodies[1].y = r_rot[1] bodies[1].z = r_rot[2] bodies[1].vx = v_rot[0] bodies[1].vy = v_rot[1] bodies[1].vz = v_rot[2] bodies.age = 0.0 | units.yr bodies.move_to_center() print "\t r_rel_ini = ", r_rot.in_(units.AU) print "\t v_rel_ini = ", v_rot.in_(units.kms) print "\t time since peri = ", time_peri.in_(units.yr) a_orbit, e_orbit, p_orbit = orbital_parameters(r_rot, v_rot, (m0 + m1)) print "\t a = ", a_orbit.in_( units.AU), "\t e = ", e_orbit, "\t period = ", p_orbit.in_(units.yr) return bodies, time_peri