def update_orb_elem(host_star, planets, converter=None, kepler_worker=None): if kepler_worker == None: if converter == None: tot_sys = Particles(particles=(host_star, planets)) converter = nbody_system.nbody_to_si(tot_sys.mass.sum(), 2 * host_star.radius) kep_p = Kepler(unit_converter=converter, redirection='none') kep_p.initialize_code() else: kep_p = kepler_worker for planet in planets: total_mass = host_star.mass + planet.mass kep_pos = host_star.position - planet.position kep_vel = host_star.velocity - planet.velocity kep_p.initialize_from_dyn(total_mass, kep_pos[0], kep_pos[1], kep_pos[2], kep_vel[0], kep_vel[1], kep_vel[2]) planet.semimajor_axis, planet.eccentricity = kep_p.get_elements() planet.period = kep_p.get_period() planet.true_anomaly, planet.mean_anomaly = kep_p.get_angles() if kepler_worker == None: kep_p.stop()
def get_heirarchical_systems_from_set(bodies, kepler_workers=None, converter=None, RelativePosition=False): # Initialize Kepler if kepler_workers == None: if converter == None: converter = nbody_system.nbody_to_si( bodies.mass.sum(), 2 * np.max(bodies.radius.number) | bodies.radius.unit) kep_p = Kepler(unit_converter=converter, redirection='none') kep_p.initialize_code() kep_s = Kepler(unit_converter=converter, redirection='none') kep_s.initialize_code() else: kep_p = kepler_workers[0] kep_s = kepler_workers[1] # Seperate Out Planets and Stars from Bodies stars, planets = util.get_stars(bodies), util.get_planets(bodies) num_stars, num_planets = len(stars), len(planets) # Initialize the Dictionary that Contains all Planetary Systems systems = {} # Initialize the List Used to Check Star IDs Against Already Classified Binaries binary_ids = [] # Find Nearest Neighbors of the Set closest_neighbours = stars.nearest_neighbour() # Start Looping Through Stars to Find Bound Planets for index, star in enumerate(stars): # If the star is already in Binary_IDs, just go to the next star. if star.id in binary_ids: continue # If not, Set the System ID and Set-up Data Structure. system_id = star.id current_system = systems.setdefault(system_id, Particles()) current_system.add_particle(star) noStellarHierarchy = False # If there is only one stars, there is obviously no stellar heirarchy in # the encounter that is occuring. if len(stars) == 1: noStellarHierarchy = True if not noStellarHierarchy: # Check to see if the Nearest Neighbor is Mutual star_neighbour_id = closest_neighbours[index].id neighbour_neighbour_id = closest_neighbours[ stars.id == star_neighbour_id].id[0] for other_star in (stars - star): # Check to see if the two stars are bound. kep_s.initialize_from_dyn( star.mass + other_star.mass, star.x - other_star.x, star.y - other_star.y, star.z - other_star.z, star.vx - other_star.vx, star.vy - other_star.vy, star.vz - other_star.vz) a_s, e_s = kep_s.get_elements() print(star.id, other_star.id, e_s) # If they ARE NOT bound ... if e_s >= 1.0: noStellarHierarchy = True # If they ARE bound ... else: # If the star is the star's neighbour's neighbour and visa-versa, then proceed. print(star.id, other_star.id, star_neighbour_id, neighbour_neighbour_id) if star.id == neighbour_neighbour_id and other_star.id == star_neighbour_id: noStellarHierarchy = False print("Binary composed of Star", star.id, "and Star", other_star.id, "has been detected!") current_system.add_particle(other_star) binary_ids.append(star.id) binary_ids.append(other_star.id) else: print( "!!! Alert: Bound Stars are not closest neighbours ..." ) print("!!! Current Star:", star.id, "| Other Star:", other_star.id) print("!!! CS's Neighbour:", star_neighbour_id, \ "| CS's Neighbour's Neighbour:", neighbour_neighbour_id) checked_planet_ids = [] for KeyID in systems.keys(): current_system = systems[KeyID] sys_stars = util.get_stars(current_system) noStellarHierarchy = False # If there is only one stars, there is obviously no stellar heirarchy in # the encounter that is occuring. if len(sys_stars) == 1: noStellarHierarchy = True for planet in planets: if planet.id in checked_planet_ids: continue star = sys_stars[sys_stars.id == KeyID][0] total_mass = star.mass + planet.mass kep_pos = star.position - planet.position kep_vel = star.velocity - planet.velocity kep_p.initialize_from_dyn(total_mass, kep_pos[0], kep_pos[1], kep_pos[2], kep_vel[0], kep_vel[1], kep_vel[2]) a_p, e_p = kep_p.get_elements() P_p = kep_p.get_period() Ta_p, Ma_p = kep_p.get_angles() host_star_id = star.id if e_p < 1.0: # Check to See if The Planetary System is tied to a Stellar Binary # Note: Things get complicated if it is ... if noStellarHierarchy: # Get Additional Information on Orbit planet.semimajor_axis = a_p planet.eccentricity = e_p planet.period = P_p planet.true_anomaly = Ta_p planet.mean_anomaly = Ma_p planet.host_star = star.id # Add the Planet to the System Set current_system.add_particle(planet) else: # Handling for Planetary Systems in Stellar Heirarchical Structures # Note: We check to see which other star in the current systems # have a better boundness with the planet and choose that # as the new host star. for other_star in sys_stars - star: total_mass = other_star.mass + planet.mass kep_pos = other_star.position - planet.position kep_vel = other_star.velocity - planet.velocity kep_p.initialize_from_dyn(total_mass, kep_pos[0], kep_pos[1], kep_pos[2], kep_vel[0], kep_vel[1], kep_vel[2]) a_p2, e_p2 = kep_p.get_elements() # Check to see if the planet is more bound to 'star' or # 'other_star'. If its more bound to 'other_star', # set the attributes to the more bound object. This will # replace *_p with the better values with each loop. if e_p2 < e_p: a_p = a_p2 e_p = e_p2 P_p = kep_p.get_period() Ta_p, Ma_p = kep_p.get_angles() host_star_id = other_star.id planet.semimajor_axis = a_p planet.eccentricity = e_p planet.period = P_p planet.true_anomaly = Ta_p planet.mean_anomaly = Ma_p planet.host_star = host_star_id # Add the Planet to the System Set current_system.add_particle(planet) checked_planet_ids.append(planet.id) elif not noStellarHierarchy: # Handling for Planetary Systems in Stellar Heirarchical Structures # Note: We check to see which other star in the current systems # have a better boundness with the planet and choose that # as the new host star. for other_star in sys_stars - star: total_mass = other_star.mass + planet.mass kep_pos = other_star.position - planet.position kep_vel = other_star.velocity - planet.velocity kep_p.initialize_from_dyn(total_mass, kep_pos[0], kep_pos[1], kep_pos[2], kep_vel[0], kep_vel[1], kep_vel[2]) a_p2, e_p2 = kep_p.get_elements() # Check to see if the planet is more bound to 'star' or # 'other_star'. If its more bound to 'other_star', # set the attributes to the more bound object. This will # replace *_p with the better values with each loop. if e_p2 < e_p: a_p = a_p2 e_p = e_p2 P_p = kep_p.get_period() Ta_p, Ma_p = kep_p.get_angles() host_star_id = other_star.id planet.semimajor_axis = a_p planet.eccentricity = e_p planet.period = P_p planet.true_anomaly = Ta_p planet.mean_anomaly = Ma_p planet.host_star = host_star_id # Add the Planet to the System Set current_system.add_particle(planet) else: print( "!!! Alert: Planet is not bound nor is it bound to any other star." ) if kepler_workers == None: kep_p.stop() kep_s.stop() return systems
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_planetary_systems_from_set(bodies, converter=None, RelativePosition=False): # Initialize Kepler if converter == None: converter = nbody_system.nbody_to_si( bodies.mass.sum(), 2 * np.max(bodies.radius.number) | bodies.radius.unit) kep_p = Kepler(unit_converter=converter, redirection='none') kep_p.initialize_code() kep_s = Kepler(unit_converter=converter, redirection='none') kep_s.initialize_code() # Seperate Out Planets and Stars from Bodies stars, planets = util.get_stars(bodies), util.get_planets(bodies) num_stars, num_planets = len(stars), len(planets) # Initialize the Dictionary that Contains all Planetary Systems systems = {} # Start Looping Through Stars to Find Bound Planets for star in stars: system_id = star.id #star.semimajor_axis, star.eccentricity, star.period, star.true_anomaly, star.mean_anomaly, star.kep_energy, star.angular_momentum = \ # None, None, None, None, None, None, None current_system = systems.setdefault(system_id, Particles()) current_system.add_particle(star) for planet in planets: total_mass = star.mass + planet.mass kep_pos = star.position - planet.position kep_vel = star.velocity - planet.velocity kep_p.initialize_from_dyn(total_mass, kep_pos[0], kep_pos[1], kep_pos[2], kep_vel[0], kep_vel[1], kep_vel[2]) a_p, e_p = kep_p.get_elements() if e_p < 1.0: # Check to See if The Stellar System is a Binary # Note: Things get complicated if it is ... noStellarHeirarchy = False for other_star in (stars - star): kep_s.initialize_from_dyn( star.mass + other_star.mass, star.x - other_star.x, star.y - other_star.y, star.z - other_star.z, star.vx - other_star.vx, star.vy - other_star.vy, star.vz - other_star.vz) a_s, e_s = kep_s.get_elements() r_apo = kep_s.get_apastron() HillR = util.calc_HillRadius(a_s, e_s, other_star.mass, star.mass) if e_s >= 1.0 or HillR < r_apo: noStellarHeirarchy = True else: noStellarHeirarchy = False if noStellarHeirarchy: # Get Additional Information on Orbit planet.semimajor_axis = a_p planet.eccentricity = e_p planet.period = kep_p.get_period() planet.true_anomaly, planet.mean_anomaly = kep_p.get_angles( ) #planet.kep_energy, planet.angular_momentum = kep_p.get_integrals() # Add the Planet to the System Set current_system.add_particle(planet) else: # Handling for Planetary Systems in Stellar Heirarchical Structures # Note: This is empty for now, maybe consider doing it by the heaviest bound stellar object as the primary. pass else: continue kep_p.stop() kep_s.stop() return systems
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)