def get_component_binary_elements(comp1, comp2): kep = Kepler(redirection = "none") kep.initialize_code() mass = comp1.mass + comp2.mass pos = comp2.position - comp1.position vel = comp2.velocity - comp1.velocity kep.initialize_from_dyn(mass, pos[0], pos[1], pos[2], vel[0], vel[1], vel[2]) a,e = kep.get_elements() r = kep.get_separation() E,J = kep.get_integrals() # per unit reduced mass, note kep.stop() return mass,a,e,r,E
def get_component_binary_elements(comp1, comp2): kep = Kepler(redirection="none") kep.initialize_code() mass = comp1.mass + comp2.mass pos = comp2.position - comp1.position vel = comp2.velocity - comp1.velocity kep.initialize_from_dyn(mass, pos[0], pos[1], pos[2], vel[0], vel[1], vel[2]) a, e = kep.get_elements() r = kep.get_separation() E, J = kep.get_integrals() # per unit reduced mass, note kep.stop() return mass, a, e, r, E
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 CutOrAdvance(enc_bodies, primary_sysID, converter=None): bodies = enc_bodies.copy() if converter==None: converter = nbody_system.nbody_to_si(bodies.mass.sum(), 2 * np.max(bodies.radius.number) | bodies.radius.unit) systems = stellar_systems.get_heirarchical_systems_from_set(bodies, converter=converter, RelativePosition=False) # Deal with Possible Key Issues with Encounters with 3+ Star Particles Being Run More than Other Systems ... if int(primary_sysID) not in systems.keys(): print "...: Error: Previously run binary system has been found! Not running this system ..." print primary_sysID print systems.keys() print "---------------------------------" return None # As this function is pulling from Multiples, there should never be more or less than 2 "Root" Particles ... if len(systems) != 2: print "...: Error: Encounter has more roots than expected! Total Root Particles:", len(systems) print bodies print "---------------------------------" return None # Assign the Primary System to #1 and Perturbing System to #2 sys_1 = systems[int(primary_sysID)] secondary_sysID = [key for key in systems.keys() if key!=int(primary_sysID)][0] sys_2 = systems[secondary_sysID] print 'All System Keys:', systems.keys() print 'Primary System Key:', primary_sysID print 'System 1 IDs:', sys_1.id print 'System 2 IDs:', sys_2.id # Calculate Useful Quantities mass_ratio = sys_2.mass.sum()/sys_1.mass.sum() total_mass = sys_1.mass.sum() + sys_2.mass.sum() rel_pos = sys_1.center_of_mass() - sys_2.center_of_mass() rel_vel = sys_1.center_of_mass_velocity() - sys_2.center_of_mass_velocity() # Initialize Kepler Worker kep = Kepler(unit_converter = converter, redirection = 'none') kep.initialize_code() kep.initialize_from_dyn(total_mass, rel_pos[0], rel_pos[1], rel_pos[2], rel_vel[0], rel_vel[1], rel_vel[2]) # Check to See if the Periastron is within the Ignore Distance for 10^3 Perturbation p = kep.get_periastron() ignore_distance = mass_ratio**(1./3.) * 600 | units.AU if p > ignore_distance: print "Encounter Ignored due to Periastron of", p.in_(units.AU), "and an IgnoreDistance of",ignore_distance kep.stop() print "---------------------------------" return None # Move the Particles to be Relative to their Respective Center of Mass cm_sys_1, cm_sys_2 = sys_1.center_of_mass(), sys_2.center_of_mass() cmv_sys_1, cmv_sys_2 = sys_1.center_of_mass_velocity(), sys_2.center_of_mass_velocity() for particle in sys_1: particle.position -= cm_sys_1 particle.velocity -= cmv_sys_1 for particle in sys_2: particle.position -= cm_sys_2 particle.velocity -= cmv_sys_2 # Check to See if the Planets are Closer than the Ignore Distance # Note: This shouldn't happen in the main code, but this prevents overshooting the periastron in debug mode. if kep.get_separation() > ignore_distance: kep.advance_to_radius(ignore_distance) # Advance the Center of Masses to the Desired Distance in Reduced Mass Coordinates x, y, z = kep.get_separation_vector() rel_pos_f = rel_pos.copy() rel_pos_f[0], rel_pos_f[1], rel_pos_f[2] = x, y, z vx, vy, vz = kep.get_velocity_vector() rel_vel_f = rel_vel.copy() rel_vel_f[0], rel_vel_f[1], rel_vel_f[2] = vx, vy, vz # Transform to Absolute Coordinates from Kepler Reduced Mass Coordinates cm_pos_1, cm_pos_2 = sys_2.mass.sum() * rel_pos_f / total_mass, -sys_1.mass.sum() * rel_pos_f / total_mass cm_vel_1, cm_vel_2 = sys_2.mass.sum() * rel_vel_f / total_mass, -sys_1.mass.sum() * rel_vel_f / total_mass # Move the Particles to the New Postions of their Respective Center of Mass for particle in sys_1: particle.position += cm_pos_1 particle.velocity += cm_vel_1 for particle in sys_2: particle.position += cm_pos_2 particle.velocity += cm_vel_2 # Stop Kepler and Return the Systems as a Particle Set kep.stop() # Collect the Collective Particle Set to be Returned Back final_set = Particles() final_set.add_particles(sys_1) final_set.add_particles(sys_2) print "---------------------------------" return final_set
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)