def evolve_quadruple(N_output, end_time, m1, m2, m3, m4, aA, aB, aC, eA, eB, eC, iA, iB, iC, ApA, ApB, ApC, LANA, LANB, LANC): masses = [m1, m2, m3, m4] semimajor_axis = [aA, aB, aC] eccentricity = [eA, eB, eC] inclination = numpy.deg2rad([iA, iB, iC]) argument_of_percienter = numpy.deg2rad([ApA, ApB, ApC]) longitude_of_ascending_node = numpy.deg2rad([LANA, LANB, LANC]) print longitude_of_ascending_node N_bodies = 4 N_binaries = N_bodies-1 particles, binaries = initialize_multiple_system(N_bodies, masses, semimajor_axis, eccentricity, inclination, argument_of_percienter, longitude_of_ascending_node) code = SecularMultiple() code.particles.add_particles(particles) channel_from_particles_to_code = particles.new_channel_to(code.particles) channel_from_code_to_particles = code.particles.new_channel_to(particles) channel_from_particles_to_code.copy() ### set up some arrays for plotting ### print_smas_AU = [[] for x in range(N_binaries)] print_rps_AU = [[] for x in range(N_binaries)] print_parent_is_deg = [[] for x in range(N_binaries)] print_times_Myr = [] time = 0.0|units.yr output_time_step = end_time/float(N_output) while time <= end_time: time += output_time_step code.evolve_model(time) channel_from_code_to_particles.copy() print '='*50 print 't/Myr',time.value_in(units.Myr) print 'e',binaries.eccentricity print 'i/deg', numpy.rad2deg(binaries.inclination) print 'AP/deg', \ numpy.rad2deg(binaries.argument_of_pericenter) print 'LAN/deg', \ numpy.rad2deg(binaries.longitude_of_ascending_node) ### write to output arrays ### print_times_Myr.append(time.value_in(units.Myr)) for index_binary in range(N_binaries): print_smas_AU[index_binary].append( binaries[index_binary].semimajor_axis.value_in(units.AU) ) print_rps_AU[index_binary].append( binaries[index_binary].semimajor_axis.value_in(units.AU)*(1.0 - binaries[index_binary].eccentricity) ) print_parent_is_deg[index_binary].append( numpy.rad2deg(binaries[index_binary].inclination_relative_to_parent) ) ### compute the `canonical' maximum eccentricity/periapsis distance that applies in the quadrupole-order test-particle limit if the `outer' binary is replaced by a point mass ### print inclination[0],inclination[2],longitude_of_ascending_node[0],longitude_of_ascending_node[2] i_AC_init = compute_mutual_inclination(inclination[0],inclination[2],longitude_of_ascending_node[0],longitude_of_ascending_node[2]) i_BC_init = compute_mutual_inclination(inclination[1],inclination[2],longitude_of_ascending_node[1],longitude_of_ascending_node[2]) canonical_rp_min_A_AU = (semimajor_axis[0]*(1.0 - numpy.sqrt( 1.0 - (5.0/3.0)*numpy.cos(i_AC_init)**2 ) )).value_in(units.AU) canonical_rp_min_B_AU = (semimajor_axis[1]*(1.0 - numpy.sqrt( 1.0 - (5.0/3.0)*numpy.cos(i_BC_init)**2 ) )).value_in(units.AU) data = print_times_Myr,print_smas_AU,print_rps_AU,print_parent_is_deg,canonical_rp_min_A_AU,canonical_rp_min_B_AU return data
def test7(self): """ test collision detection in 3-body system """ particles = create_nested_multiple(3,[1.0|units.MSun, 1.2|units.MSun, 0.9|units.MSun], [1.0|units.AU, 100.0|units.AU], [0.1, 0.5], [0.01, 80.0*numpy.pi/180.0], [0.01, 0.01], [0.01, 0.01]) binaries = particles[particles.is_binary] stars = particles - binaries binaries.check_for_physical_collision_or_orbit_crossing = True stars.radius = 0.03 | units.AU code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e-2 | units.Myr tend = 1.0e-1 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() while (t<tend): t+=dt code.evolve_model(t) flag = code.flag channel_from_code.copy() print 'secular_breakdown_has_occurred',binaries.secular_breakdown_has_occurred print 'dynamical_instability_has_occurred',binaries.dynamical_instability_has_occurred print 'physical_collision_or_orbit_crossing_has_occurred',binaries.physical_collision_or_orbit_crossing_has_occurred print 'minimum_periapse_distance_has_occurred',binaries.minimum_periapse_distance_has_occurred print 'RLOF_at_pericentre_has_occurred',binaries.RLOF_at_pericentre_has_occurred if flag == 2: print 'root found' break print 't_end',code.model_time.value_in(units.Myr) t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) if HAS_MATPLOTLIB == True: fig = pyplot.figure() plot = fig.add_subplot(2,1,1) plot.plot(t_print_array.value_in(units.Myr),e_print_array.value_in(units.none)) plot = fig.add_subplot(2,1,2) plot.plot(t_print_array.value_in(units.Myr),a_print_array.value_in(units.AU)*(1.0-e_print_array.value_in(units.none))) plot.axhline(y = stars[0].radius.value_in(units.AU) + stars[1].radius.value_in(units.AU),color='k') pyplot.show()
def test1(self): """ test reference system of Naoz et al. (2009) """ particles = create_nested_multiple(3,[1.0|units.MSun, 1.0|units.MJupiter, 40.0|units.MJupiter], [6.0|units.AU,100.0|units.AU], [0.001,0.6], [0.0001,65.0*numpy.pi/180.0],[45.0*numpy.pi/180.0,0.0001],[0.01,0.01]) binaries = particles[particles.is_binary] binaries.include_pairwise_1PN_terms = False code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() self.assertEquals(0.6, code.particles[particles.is_binary][1].eccentricity) t = 0.0 | units.Myr dt = 1.0e-2 | units.Myr tend = 3.0e0 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() INCL_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() N = 0 while (t<tend): t+=dt N+=1 code.evolve_model(t) print 't/Myr = ',code.model_time.value_in(units.Myr) channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) INCL_print_array.append(binaries[0].inclination_relative_to_parent | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16,10)) plot1 = fig.add_subplot(2,1,1) plot2 = fig.add_subplot(2,1,2,yscale="log") plot1.plot(t_print_array.value_in(units.Myr),(180.0/numpy.pi)*INCL_print_array.value_in(units.none), color='k') plot2.plot(t_print_array.value_in(units.Myr),1.0-e_print_array.value_in(units.none), color='k') fontsize = 15 plot1.set_ylabel("$i$",fontsize=fontsize) plot2.set_ylabel("$1-e$",fontsize=fontsize) plot2.set_xlabel("$t/\mathrm{Myr}$",fontsize=fontsize) pyplot.show()
def test8(self): """ test minimum periapse occurrence """ particles = create_nested_multiple( 3, [1.0 | units.MSun, 1.2 | units.MSun, 0.9 | units.MSun], [1.0 | units.AU, 100.0 | units.AU], [0.1, 0.5], [0.01, 80.0 * numpy.pi / 180.0], [0.01, 0.01], [0.01, 0.01]) binaries = particles[particles.is_binary] stars = particles - binaries binaries.check_for_minimum_periapse_distance = True rp_min = 0.1 | units.AU binaries.check_for_minimum_periapse_distance_value = rp_min code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 5.0e-3 | units.Myr tend = 1.0e-1 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() while (t < tend): t += dt code.evolve_model(t) flag = code.flag channel_from_code.copy() print('secular_breakdown_has_occurred', binaries.secular_breakdown_has_occurred) print('dynamical_instability_has_occurred', binaries.dynamical_instability_has_occurred) print('physical_collision_or_orbit_crossing_has_occurred', binaries.physical_collision_or_orbit_crossing_has_occurred) print('minimum_periapse_distance_has_occurred', binaries.minimum_periapse_distance_has_occurred) print('RLOF_at_pericentre_has_occurred', binaries.RLOF_at_pericentre_has_occurred) if flag == 2: print('root found') break print('t_end', code.model_time.value_in(units.Myr)) t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none)
def test3(self): """ test GW emission in 2-body system + collision detection """ particles = create_nested_multiple( 2, [1.0 | units.MSun, 1.0 | units.MJupiter], [0.1 | units.AU], [0.994], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] stars = particles - binaries stars.radius = 0.0001 | units.AU binaries.check_for_physical_collision_or_orbit_crossing = True binaries.include_pairwise_25PN_terms = True code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() tend = 1.0 | units.Gyr N = 0 t = 0.0 | units.Myr dt = 100.0 | units.Myr while (t < tend): t += dt N += 1 code.evolve_model(t) flag = code.flag if flag == 2: print('root found') break channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) print('e', binaries.eccentricity, 'a/AU', binaries.semimajor_axis.value_in(units.AU), 'rp/AU', (binaries.semimajor_axis * (1.0 - binaries.eccentricity)).value_in(units.AU))
def test2(self): """ test 1PN precession in 2-body system """ particles = create_nested_multiple( 2, [1.0 | units.MSun, 1.0 | units.MJupiter], [1.0 | units.AU], [0.99], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] binaries.include_pairwise_1PN_terms = True code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e-1 | units.Myr tend = 1.0e0 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() N = 0 while (t < tend): t += dt N += 1 code.evolve_model(t) channel_from_code.copy() print('t/Myr', t.value_in(units.Myr), 'omega', binaries[0].argument_of_pericenter | units.none) t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) a = binaries[0].semimajor_axis e = binaries[0].eccentricity M = binaries[0].mass rg = constants.G * M / (constants.c**2) P = 2.0 * numpy.pi * numpy.sqrt(a**3 / (constants.G * M)) t_1PN = (1.0 / 3.0) * P * (1.0 - e**2) * (a / rg)
def test1(self): """ test reference system of Naoz et al. (2009) """ particles = create_nested_multiple( 3, [1.0 | units.MSun, 1.0 | units.MJupiter, 40.0 | units.MJupiter], [6.0 | units.AU, 100.0 | units.AU], [0.001, 0.6], [0.0001, 65.0 * numpy.pi / 180.0], [45.0 * numpy.pi / 180.0, 0.0001], [0.01, 0.01]) binaries = particles[particles.is_binary] binaries.include_pairwise_1PN_terms = False code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() self.assertEqual(0.6, code.particles[particles.is_binary][1].eccentricity) t = 0.0 | units.Myr dt = 1.0e-2 | units.Myr tend = 3.0e0 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() INCL_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() N = 0 while (t < tend): t += dt N += 1 code.evolve_model(t) print('t/Myr = ', code.model_time.value_in(units.Myr)) channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) INCL_print_array.append(binaries[0].inclination_relative_to_parent | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none)
def test5(self): """ test precession due to tidal bulges """ M = 1.0 | units.MJupiter R = 1.0 | units.RJupiter m_per = 1.0 | units.MSun a0 = 30.0 | units.AU e0 = 0.999 P0 = 2.0 * numpy.pi * numpy.sqrt(a0**3 / (constants.G * (M + m_per))) n0 = 2.0 * numpy.pi / P0 particles = create_nested_multiple(2, [m_per, M], [a0], [e0], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] particles[0].radius = 1.0 | units.RSun particles[1].radius = R k_L = 0.41 k_AM = k_L / 2.0 particles[1].tides_method = 0 particles[1].include_tidal_friction_terms = False particles[1].include_tidal_bulges_precession_terms = True particles[1].include_rotation_precession_terms = False particles[1].minimum_eccentricity_for_tidal_precession = 1.0e-5 particles[1].tides_apsidal_motion_constant = k_AM particles[1].tides_gyration_radius = 0.25 code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e1 | units.Myr tend = 1.0e2 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() g_dot_TB = (15.0 / 8.0) * n0 * (8.0 + 12.0 * e0**2 + e0**4) * ( m_per / M) * k_AM * pow(R / a0, 5.0) / pow(1.0 - e0**2, 5.0) t_TB = 2.0 * numpy.pi / g_dot_TB N = 0 while (t < tend): t += dt code.evolve_model(t) print('flag', code.flag, t, binaries[0].semimajor_axis, binaries[0].eccentricity) channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) N += 1
def test6(self): """ test precession due to rotation """ M = 1.0 | units.MJupiter R = 1.5 | units.RJupiter m_per = 1.0 | units.MSun a0 = 30.0 | units.AU e0 = 0.999 P0 = 2.0 * numpy.pi * numpy.sqrt(a0**3 / (constants.G * (M + m_per))) n0 = 2.0 * numpy.pi / P0 aF = a0 * (1.0 - e0**2) nF = numpy.sqrt(constants.G * (M + m_per) / (aF**3)) particles = create_nested_multiple(2, [m_per, M], [a0], [e0], [1.0e-5], [1.0e-5], [1.0e-5]) binaries = particles[particles.is_binary] particles[0].radius = 1.0 | units.RSun particles[1].radius = R particles[1].spin_vec_x = 0.0 | 1.0 / units.day particles[1].spin_vec_y = 0.0 | 1.0 / units.day Omega_PS0 = n0 * (33.0 / 10.0) * pow(a0 / aF, 3.0 / 2.0) particles[1].spin_vec_z = Omega_PS0 k_L = 0.51 k_AM = k_L / 2.0 rg = 0.25 particles[1].tides_method = 1 particles[1].include_tidal_friction_terms = False particles[1].include_tidal_bulges_precession_terms = False particles[1].include_rotation_precession_terms = True particles[1].minimum_eccentricity_for_tidal_precession = 1.0e-5 particles[1].tides_apsidal_motion_constant = k_AM particles[1].tides_gyration_radius = rg code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e1 | units.Myr tend = 1.0e2 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() Omega_vec = [ particles[1].spin_vec_x, particles[1].spin_vec_y, particles[1].spin_vec_z ] Omega = numpy.sqrt(Omega_vec[0]**2 + Omega_vec[1]**2 + Omega_vec[2]**2) print('Omega/n', Omega / n0) g_dot_rot = n0 * (1.0 + m_per / M) * k_AM * pow( R / a0, 5.0) * (Omega / n0)**2 / ((1.0 - e0**2)**2) t_rot = 2.0 * numpy.pi / g_dot_rot print('t_rot/Myr', t_rot.value_in(units.Myr)) N = 0 while (t < tend): t += dt code.evolve_model(t) print('flag', code.flag, t, binaries[0].semimajor_axis, binaries[0].eccentricity) channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) N += 1
def test2(self): """ test 1PN precession in 2-body system """ particles = create_nested_multiple(2,[1.0|units.MSun, 1.0|units.MJupiter], [1.0|units.AU], [0.99], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] binaries.include_pairwise_1PN_terms = True code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e-1 | units.Myr tend = 1.0e0 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() N = 0 while (t<tend): t+=dt N+=1 code.evolve_model(t) channel_from_code.copy() print 't/Myr',t.value_in(units.Myr),'omega',binaries[0].argument_of_pericenter | units.none t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) a = binaries[0].semimajor_axis e = binaries[0].eccentricity M = binaries[0].mass rg = constants.G*M/(constants.c**2) P = 2.0*numpy.pi*numpy.sqrt(a**3/(constants.G*M)) t_1PN = (1.0/3.0)*P*(1.0-e**2)*(a/rg) if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16,10)) plot1 = fig.add_subplot(4,1,1) plot2 = fig.add_subplot(4,1,2,yscale="log") plot3 = fig.add_subplot(4,1,3,yscale="log") plot4 = fig.add_subplot(4,1,4,yscale="log") plot1.plot(t_print_array.value_in(units.Myr),AP_print_array.value_in(units.none), color='r') points = numpy.linspace(0.0,tend.value_in(units.Myr),N) AP = 0.01 +2.0*numpy.pi*points/(t_1PN.value_in(units.Myr)) AP = (AP+numpy.pi)%(2.0*numpy.pi) - numpy.pi ### -pi < AP < pi plot1.plot(points,AP,color='g') plot2.plot(t_print_array.value_in(units.Myr),numpy.fabs( (AP - AP_print_array.value_in(units.none))/AP ), color='r') plot3.plot(t_print_array.value_in(units.Myr),numpy.fabs((a-a_print_array)/a), color='r') plot4.plot(t_print_array.value_in(units.Myr),numpy.fabs((e-e_print_array)/e), color='r') fontsize = 15 plot1.set_ylabel("$\omega$",fontsize=fontsize) plot2.set_ylabel("$|(\omega_p-\omega)/\omega_p|$",fontsize=fontsize) plot3.set_ylabel("$|(a_0-a)/a_0|$",fontsize=fontsize) plot4.set_ylabel("$|(e_0-e)/e_0|$",fontsize=fontsize) pyplot.show()
class CloseEncounters(): def __init__(self, Star_EncounterHistory, KeplerWorkerList = None, \ NBodyWorkerList = None, SecularWorker = None, SEVWorker = None): '''EncounterHistory should be a List of the Format {RotationKey: [Encounter0_FilePath, ...]}''' # Find the Main System's Host Star's ID and Assign it to 'KeySystemID' self.doEncounterPatching = True self.KeySystemID = int(Star_EncounterHistory[list( Star_EncounterHistory)[0]][0].split("/")[-2]) self.ICs = defaultdict(list) self.StartTimes = defaultdict(list) self.desired_endtime = 1.0 | units.Gyr self.max_end_time = 0.1 | units.Myr self.kep = KeplerWorkerList self.NBodyCodes = NBodyWorkerList self.SecularCode = SecularWorker self.SEVCode = SEVWorker self.getOEData = True self.OEData = defaultdict(list) # Create a List of StartingTimes and Encounter Initial Conditions (ICs) for all Orientations for RotationKey in Star_EncounterHistory.keys(): for i, Encounter in enumerate(Star_EncounterHistory[RotationKey]): self.ICs[RotationKey].append( read_set_from_file(Encounter, format="hdf5", version='2.0', close_file=True)) self.StartTimes[RotationKey].append( np.max(np.unique(self.ICs[RotationKey][i].time))) #print(self.KeySystemID) self.FinalStates = defaultdict(list) def SimAllEncounters(self): ''' Call this function to run all Encounters for a System.''' # Start up Kepler Functions if Needed if self.kep == None: self.kep = [] bodies = self.ICs[next(iter(self.ICs))][0] converter = nbody_system.nbody_to_si( bodies.mass.sum(), 2 * np.max(bodies.radius.number) | bodies.radius.unit) self.kep.append( Kepler(unit_converter=converter, redirection='none')) self.kep.append( Kepler(unit_converter=converter, redirection='none')) self.kep[0].initialize_code() self.kep[1].initialize_code() # Start up NBodyCodes if Needed if self.NBodyCodes == None: self.NBodyCodes = [ initialize_GravCode(ph4), initialize_isOverCode() ] # Start up SecularCode if Needed if self.SecularCode == None: self.SecularCode = SecularMultiple() if self.SEVCode == None: self.SEVCode = SSE() # Begin Looping over Rotation Keys ... for RotationKey in self.ICs.keys(): for i in range(len(self.ICs[RotationKey])): try: print(util.timestamp(), "!!! UPDATE: Starting the following encounter", \ "Star", self.KeySystemID, RotationKey, "-", i) # Identify the Current Encounter in the List for This Rotation CurrentEncounter = self.ICs[RotationKey][i] #print(CurrentEncounter[0].position) # Create the Encounter Instance with the Current Encounter Encounter_Inst = self.SingleEncounter(CurrentEncounter) # Simulate the Encounter till the Encounter is Over via N-Body Integrator # -OR- the time to the Next Encounter is Reached if len(self.StartTimes[RotationKey]) == 1 or i + 1 == len( self.StartTimes[RotationKey]): current_max_endtime = self.max_end_time else: current_max_endtime = self.StartTimes[RotationKey][i + 1] EndingState = Encounter_Inst.SimSingleEncounter(current_max_endtime, \ start_time = self.StartTimes[RotationKey][i], \ GCodes = self.NBodyCodes) EndingStateTime = np.max(np.unique(EndingState.time)) #print(Encounter_Inst.particles[0].position) print("The Encounter was over after:", (EndingStateTime - self.StartTimes[RotationKey][i]).value_in( units.Myr)) #print(EndingState.id, EndingState.x) print('----------') #print(Encounter_Inst.particles.id, Encounter_Inst.particles.x) # Strip off Anything Not Associated with the Key System systems_in_current_encounter = stellar_systems.get_heirarchical_systems_from_set( EndingState, kepler_workers=self.kep) # Reassign the EndingState to include the Primary System ONLY EndingState = systems_in_current_encounter[ self.KeySystemID] print("Before Secular:", EndingState.id, EndingState.x) #print(EndingState[0].position) #print(len(self.ICs[RotationKey])-1) # If Encounter Patching is Desired -AND- it isn't the last Encounter if i + 1 < len(self.ICs[RotationKey] ) and self.doEncounterPatching: # Identify the Next Encounter in the List NextEncounter = self.ICs[RotationKey][i + 1] # Simulate System till the Next Encounter's Start Time Encounter_Inst = self.SingleEncounter(EndingState) FinalState, data, newcode = Encounter_Inst.SimSecularSystem(self.StartTimes[RotationKey][i+1], \ start_time = EndingStateTime, \ GCode = self.SecularCode, getOEData=self.getOEData, \ KeySystemID = self.KeySystemID, SCode=self.SEVCode) if newcode != None: self.SecularCode = newcode print("After Secular:", FinalState.id) # Begin Patching of the End State to the Next Encounter self.ICs[RotationKey][i + 1] = self.PatchedEncounter( FinalState, NextEncounter) else: # Simulate System till Desired Global Endtime #print(CurrentEncounter[0].time.value_in(units.Myr)) #print(EndingState[0].time.value_in(units.Myr)) Encounter_Inst = self.SingleEncounter(EndingState) FinalState, data, newcode = Encounter_Inst.SimSecularSystem(self.desired_endtime, \ start_time = EndingStateTime, \ GCode = self.SecularCode, getOEData=self.getOEData, \ KeySystemID = self.KeySystemID, SCode=self.SEVCode) if newcode != None: self.SecularCode = newcode print("After Secular:", FinalState.id) # Append the FinalState of Each Encounter to its Dictionary self.FinalStates[RotationKey].append(FinalState) if self.getOEData and data != None: self.OEData[RotationKey].append(data) except: print("!!!! Alert: Skipping", RotationKey, "-", i, "for Star", self.KeySystemID, "due to unforseen issues!") print("!!!! The Particle Set's IDs are as follows:", self.ICs[RotationKey][i].id) # Stop the NBody Codes if not Provided if self.kep == None: self.kep[0].stop() self.kep[1].stop() # Start up NBodyCodes if Needed if self.NBodyCodes == None: self.NBodyCodes[0].stop() self.NBodyCodes[1].stop() # Start up SecularCode if Needed if self.SecularCode == None: self.SecularCode.stop() return None def PatchedEncounter(self, EndingState, NextEncounter): ''' Call this function to Patch Encounter Endstates to the Next Encounter''' # Determine Time to Next Encounter current_time = max(EndingState.time) final_time = max(NextEncounter.time) # Map the Orbital Elements to the Child2 Particles (LilSis) [MUST BE A TREE SET] enc_patching.map_node_oe_to_lilsis(EndingState) # Seperate Next Encounter Systems to Locate the Primary System systems_at_next_encounter = stellar_systems.get_heirarchical_systems_from_set( NextEncounter) sys_1 = systems_at_next_encounter[self.KeySystemID] # Note: This was changed to handle encounters of which result in one # bound object of multiple subsystems. ~ Joe G. | 8/24/20 BoundObjOnly = False if len(systems_at_next_encounter.keys()) == 1: BoundObjOnly = True else: secondary_sysID = [ key for key in list(systems_at_next_encounter.keys()) if key != int(self.KeySystemID) ][0] sys_2 = systems_at_next_encounter[secondary_sysID] # Get Planet and Star Subsets for the Current and Next Encounter children_at_EndingState = EndingState.select(lambda x: x == False, ["is_binary"]) planets_at_current_encounter = util.get_planets( children_at_EndingState) hoststar_at_current_encounter = util.get_stars( children_at_EndingState).select(lambda x: x == self.KeySystemID, ["id"])[0] planets_at_next_encounter = util.get_planets(sys_1) print("Planets at Next Encount:", planets_at_next_encounter.id) hoststar_at_next_encounter = util.get_stars(sys_1).select( lambda x: x == self.KeySystemID, ["id"])[0] #print(hoststar_at_next_encounter) # Update Current Positions & Velocitys to Relative Coordinates from Orbital Parameters!! # TO-DO: Does not handle Binary Star Systems for planet in planets_at_current_encounter: #print(planet.id, planet.position) nbody_PlanetStarPair = \ new_binary_from_orbital_elements(hoststar_at_current_encounter.mass, planet.mass, planet.semimajor_axis, \ eccentricity = planet.eccentricity, inclination=planet.inclination, \ longitude_of_the_ascending_node=planet.longitude_of_ascending_node, \ argument_of_periapsis=planet.argument_of_pericenter, G=units.constants.G, \ true_anomaly = 360*rp.uniform(0.0,1.0) | units.deg) # random point in the orbit planet.position = nbody_PlanetStarPair[1].position planet.velocity = nbody_PlanetStarPair[1].velocity #print(planet.id, planet.position) for planet in planets_at_current_encounter: print(planet.id, planet.position) # Release a Warning when Odd Planet Number Combinations Occur (Very Unlikely, More of a Safe Guard) if len(planets_at_current_encounter) != len(planets_at_next_encounter): print("!!!! Expected", len(planets_at_next_encounter), "planets but recieved only", len(planets_at_current_encounter)) # Move Planets to Host Star in the Next Encounter for next_planet in planets_at_next_encounter: for current_planet in planets_at_current_encounter: if next_planet.id == current_planet.id: next_planet.position = current_planet.position + hoststar_at_next_encounter.position next_planet.velocity = current_planet.velocity + hoststar_at_next_encounter.velocity break #for planet in planets_at_next_encounter: # print(planet.id, planet.position) #for particle in sys_1: # print(particle.id, particle.position) # Recombine Seperated Systems to Feed into SimSingleEncounter UpdatedNextEncounter = Particles() print("IDs in System 1", sys_1.id) UpdatedNextEncounter.add_particles(sys_1) if not BoundObjOnly: UpdatedNextEncounter.add_particles(sys_2) print("IDs in System 2", sys_2.id) # Return the Updated and Patched Encounter as a Partcile Set for the N-Body Simulation return UpdatedNextEncounter class SingleEncounter(): def __init__(self, EncounterBodies): self.particles = EncounterBodies def SimSecularSystem(self, desired_end_time, **kwargs): start_time = kwargs.get("start_time", 0 | units.Myr) getOEData = kwargs.get("getOEData", False) KeySystemID = kwargs.get("KeySystemID", None) GCode = kwargs.get("GCode", None) SEVCode = kwargs.get("SCode", None) self.particles, data, newcode = enc_patching.run_secularmultiple(self.particles, desired_end_time, \ start_time = start_time, N_output=1, \ GCode=GCode, exportData=getOEData, \ KeySystemID=KeySystemID, SEVCode=SEVCode) return self.particles, data, newcode def SimSingleEncounter(self, max_end_time, **kwargs): delta_time = kwargs.get("delta_time", 100 | units.yr) converter = kwargs.get("converter", None) start_time = kwargs.get("start_time", 0 | units.yr) doStateSaves = kwargs.get("doStateSaves", False) doVerbosSaves = kwargs.get("doEncPatching", False) GCodes = kwargs.get("GCodes", None) GravitatingBodies = self.particles # Set Up the Integrators if GCodes == None: if converter == None: converter = nbody_system.nbody_to_si(GravitatingBodies.mass.sum(), \ 2 * np.max(GravitatingBodies.radius.number) | GravitatingBodies.radius.unit) gravity = initialize_GravCode(ph4, converter=converter) over_grav = initialize_isOverCode(converter=converter) else: gravity = GCodes[0] over_grav = GCodes[1] # Set up SaveState if Requested if doStateSaves: pass # Currently Massive Memory Leak Present # Store Initial Center of Mass Information rCM_i = GravitatingBodies.center_of_mass() vCM_i = GravitatingBodies.center_of_mass_velocity() # Remove Attributes that Cause Issues with SmallN if 'child1' in GravitatingBodies.get_attribute_names_defined_in_store( ): del GravitatingBodies.child1, GravitatingBodies.child2 # Moving the Encounter's Center of Mass to the Origin and Setting it at Rest GravitatingBodies.position -= rCM_i GravitatingBodies.velocity -= vCM_i # Add and Commit the Scattering Particles gravity.particles.add_particles( GravitatingBodies) # adds bodies to gravity calculations gravity.commit_particles() #gravity.begin_time = start_time # Create the Channel to Python Set & Copy it Over channel_from_grav_to_python = gravity.particles.new_channel_to( GravitatingBodies) channel_from_grav_to_python.copy() # Get Free-Fall Time for the Collision s = util.get_stars(GravitatingBodies) t_freefall = s.dynamical_timescale() #print(gravity.begin_time) #print(t_freefall) # Setting Coarse Timesteps list_of_times = np.arange(0.0, start_time.value_in(units.yr)+max_end_time.value_in(units.yr), \ delta_time.value_in(units.yr)) | units.yr stepNumber = 0 # Loop through the List of Coarse Timesteps for current_time in list_of_times: #print(current_time) #print(GravitatingBodies.time) #print(gravity.sync_time) # Evolve the Model to the Desired Current Time gravity.evolve_model(current_time) # Update Python Set in In-Code Set channel_from_grav_to_python.copy() # original channel_from_grav_to_python.copy_attribute( "index_in_code", "id") # Check to See if the Encounter is Over After the Freefall Time and Every 25 Steps After That if current_time > 1.25 * t_freefall and stepNumber % 25 == 0: over = util.check_isOver(gravity.particles, over_grav) print("Is it Over?", over) if over: #print(gravity.particles[0].position) #print(GravitatingBodies[0].position) current_time += 100 | units.yr # Get to a Final State After Several Planet Orbits gravity.evolve_model(current_time) gravity.update_particle_set() gravity.particles.synchronize_to(GravitatingBodies) channel_from_grav_to_python.copy() GravitatingBodies.time = start_time + current_time # Create a Save State break if current_time == list_of_times[-1]: # Create a Save State pass stepNumber += 1 if GCodes == None: # Stop the Gravity Code Once the Encounter Finishes gravity.stop() over_grav.stop() else: # Reset the Gravity Codes Once Encounter Finishes gravity.reset() over_grav.reset() # Return the GravitatingBodies as they are at the End of the Simulation return GravitatingBodies
def test6(self): """ test precession due to rotation """ M = 1.0 | units.MJupiter R = 1.5 | units.RJupiter m_per = 1.0 | units.MSun a0 = 30.0 | units.AU e0 = 0.999 P0 = 2.0 * numpy.pi * numpy.sqrt(a0**3 / (constants.G * (M + m_per))) n0 = 2.0 * numpy.pi / P0 aF = a0 * (1.0 - e0**2) nF = numpy.sqrt(constants.G * (M + m_per) / (aF**3)) particles = create_nested_multiple(2, [m_per, M], [a0], [e0], [1.0e-5], [1.0e-5], [1.0e-5]) binaries = particles[particles.is_binary] particles[0].radius = 1.0 | units.RSun particles[1].radius = R particles[1].spin_vec_x = 0.0 | 1.0 / units.day particles[1].spin_vec_y = 0.0 | 1.0 / units.day Omega_PS0 = n0 * (33.0 / 10.0) * pow(a0 / aF, 3.0 / 2.0) particles[1].spin_vec_z = Omega_PS0 k_L = 0.51 k_AM = k_L / 2.0 rg = 0.25 particles[1].tides_method = 1 particles[1].include_tidal_friction_terms = False particles[1].include_tidal_bulges_precession_terms = False particles[1].include_rotation_precession_terms = True particles[1].minimum_eccentricity_for_tidal_precession = 1.0e-5 particles[1].tides_apsidal_motion_constant = k_AM particles[1].tides_gyration_radius = rg code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e1 | units.Myr tend = 1.0e2 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() Omega_vec = [ particles[1].spin_vec_x, particles[1].spin_vec_y, particles[1].spin_vec_z ] Omega = numpy.sqrt(Omega_vec[0]**2 + Omega_vec[1]**2 + Omega_vec[2]**2) print('Omega/n', Omega / n0) g_dot_rot = n0 * (1.0 + m_per / M) * k_AM * pow( R / a0, 5.0) * (Omega / n0)**2 / ((1.0 - e0**2)**2) t_rot = 2.0 * numpy.pi / g_dot_rot print('t_rot/Myr', t_rot.value_in(units.Myr)) N = 0 while (t < tend): t += dt code.evolve_model(t) print('flag', code.flag, t, binaries[0].semimajor_axis, binaries[0].eccentricity) channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) N += 1 if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16, 10)) plot1 = fig.add_subplot(4, 1, 1) plot2 = fig.add_subplot(4, 1, 2, yscale="log") plot3 = fig.add_subplot(4, 1, 3, yscale="log") plot4 = fig.add_subplot(4, 1, 4, yscale="log") plot1.plot(t_print_array.value_in(units.Myr), AP_print_array.value_in(units.none), color='r') points = numpy.linspace(0.0, tend.value_in(units.Myr), N) AP = 0.01 + 2.0 * numpy.pi * points / (t_rot.value_in(units.Myr)) AP = (AP + numpy.pi) % (2.0 * numpy.pi) - numpy.pi ### -pi < AP < pi plot1.plot(points, AP, color='g') plot2.plot(t_print_array.value_in(units.Myr), numpy.fabs( (AP - AP_print_array.value_in(units.none)) / AP), color='r') plot3.plot(t_print_array.value_in(units.Myr), numpy.fabs((a0 - a_print_array) / a0), color='r') plot4.plot(t_print_array.value_in(units.Myr), numpy.fabs((e0 - e_print_array) / e0), color='r') fontsize = 15 plot1.set_ylabel("$\omega$", fontsize=fontsize) plot2.set_ylabel("$|(\omega_p-\omega)/\omega_p|$", fontsize=fontsize) plot3.set_ylabel("$|(a_0-a)/a_0|$", fontsize=fontsize) plot4.set_ylabel("$|(e_0-e)/e_0|$", fontsize=fontsize) pyplot.show()
def SimAllEncounters(self): ''' Call this function to run all Encounters for a System.''' # Start up Kepler Functions if Needed if self.kep == None: self.kep = [] bodies = self.ICs[next(iter(self.ICs))][0] converter = nbody_system.nbody_to_si( bodies.mass.sum(), 2 * np.max(bodies.radius.number) | bodies.radius.unit) self.kep.append( Kepler(unit_converter=converter, redirection='none')) self.kep.append( Kepler(unit_converter=converter, redirection='none')) self.kep[0].initialize_code() self.kep[1].initialize_code() # Start up NBodyCodes if Needed if self.NBodyCodes == None: self.NBodyCodes = [ initialize_GravCode(ph4), initialize_isOverCode() ] # Start up SecularCode if Needed if self.SecularCode == None: self.SecularCode = SecularMultiple() if self.SEVCode == None: self.SEVCode = SSE() # Begin Looping over Rotation Keys ... for RotationKey in self.ICs.keys(): for i in range(len(self.ICs[RotationKey])): try: print(util.timestamp(), "!!! UPDATE: Starting the following encounter", \ "Star", self.KeySystemID, RotationKey, "-", i) # Identify the Current Encounter in the List for This Rotation CurrentEncounter = self.ICs[RotationKey][i] #print(CurrentEncounter[0].position) # Create the Encounter Instance with the Current Encounter Encounter_Inst = self.SingleEncounter(CurrentEncounter) # Simulate the Encounter till the Encounter is Over via N-Body Integrator # -OR- the time to the Next Encounter is Reached if len(self.StartTimes[RotationKey]) == 1 or i + 1 == len( self.StartTimes[RotationKey]): current_max_endtime = self.max_end_time else: current_max_endtime = self.StartTimes[RotationKey][i + 1] EndingState = Encounter_Inst.SimSingleEncounter(current_max_endtime, \ start_time = self.StartTimes[RotationKey][i], \ GCodes = self.NBodyCodes) EndingStateTime = np.max(np.unique(EndingState.time)) #print(Encounter_Inst.particles[0].position) print("The Encounter was over after:", (EndingStateTime - self.StartTimes[RotationKey][i]).value_in( units.Myr)) #print(EndingState.id, EndingState.x) print('----------') #print(Encounter_Inst.particles.id, Encounter_Inst.particles.x) # Strip off Anything Not Associated with the Key System systems_in_current_encounter = stellar_systems.get_heirarchical_systems_from_set( EndingState, kepler_workers=self.kep) # Reassign the EndingState to include the Primary System ONLY EndingState = systems_in_current_encounter[ self.KeySystemID] print("Before Secular:", EndingState.id, EndingState.x) #print(EndingState[0].position) #print(len(self.ICs[RotationKey])-1) # If Encounter Patching is Desired -AND- it isn't the last Encounter if i + 1 < len(self.ICs[RotationKey] ) and self.doEncounterPatching: # Identify the Next Encounter in the List NextEncounter = self.ICs[RotationKey][i + 1] # Simulate System till the Next Encounter's Start Time Encounter_Inst = self.SingleEncounter(EndingState) FinalState, data, newcode = Encounter_Inst.SimSecularSystem(self.StartTimes[RotationKey][i+1], \ start_time = EndingStateTime, \ GCode = self.SecularCode, getOEData=self.getOEData, \ KeySystemID = self.KeySystemID, SCode=self.SEVCode) if newcode != None: self.SecularCode = newcode print("After Secular:", FinalState.id) # Begin Patching of the End State to the Next Encounter self.ICs[RotationKey][i + 1] = self.PatchedEncounter( FinalState, NextEncounter) else: # Simulate System till Desired Global Endtime #print(CurrentEncounter[0].time.value_in(units.Myr)) #print(EndingState[0].time.value_in(units.Myr)) Encounter_Inst = self.SingleEncounter(EndingState) FinalState, data, newcode = Encounter_Inst.SimSecularSystem(self.desired_endtime, \ start_time = EndingStateTime, \ GCode = self.SecularCode, getOEData=self.getOEData, \ KeySystemID = self.KeySystemID, SCode=self.SEVCode) if newcode != None: self.SecularCode = newcode print("After Secular:", FinalState.id) # Append the FinalState of Each Encounter to its Dictionary self.FinalStates[RotationKey].append(FinalState) if self.getOEData and data != None: self.OEData[RotationKey].append(data) except: print("!!!! Alert: Skipping", RotationKey, "-", i, "for Star", self.KeySystemID, "due to unforseen issues!") print("!!!! The Particle Set's IDs are as follows:", self.ICs[RotationKey][i].id) # Stop the NBody Codes if not Provided if self.kep == None: self.kep[0].stop() self.kep[1].stop() # Start up NBodyCodes if Needed if self.NBodyCodes == None: self.NBodyCodes[0].stop() self.NBodyCodes[1].stop() # Start up SecularCode if Needed if self.SecularCode == None: self.SecularCode.stop() return None
def test3(self): """ test GW emission in 2-body system + collision detection """ particles = create_nested_multiple( 2, [1.0 | units.MSun, 1.0 | units.MJupiter], [0.1 | units.AU], [0.994], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] stars = particles - binaries stars.radius = 0.0001 | units.AU binaries.check_for_physical_collision_or_orbit_crossing = True binaries.include_pairwise_25PN_terms = True code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() tend = 1.0 | units.Gyr N = 0 t = 0.0 | units.Myr dt = 100.0 | units.Myr while (t < tend): t += dt N += 1 code.evolve_model(t) flag = code.flag if flag == 2: print('root found') break channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) print('e', binaries.eccentricity, 'a/AU', binaries.semimajor_axis.value_in(units.AU), 'rp/AU', (binaries.semimajor_axis * (1.0 - binaries.eccentricity)).value_in(units.AU)) if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16, 10)) plot1 = fig.add_subplot(2, 1, 1) plot2 = fig.add_subplot(2, 1, 2, yscale="log") plot1.plot(t_print_array.value_in(units.Myr), e_print_array.value_in(units.none), color='r') plot2.plot(t_print_array.value_in(units.Myr), a_print_array.value_in(units.AU), color='r') fontsize = 15 plot1.set_ylabel("$e$", fontsize=fontsize) plot2.set_ylabel("$a/\mathrm{AU}$", fontsize=fontsize) plot2.set_xlabel("$t/\mathrm{Myr}$", fontsize=fontsize) pyplot.show()
def test1(self): """ test reference system of Naoz et al. (2009) """ particles = create_nested_multiple( 3, [1.0 | units.MSun, 1.0 | units.MJupiter, 40.0 | units.MJupiter], [6.0 | units.AU, 100.0 | units.AU], [0.001, 0.6], [0.0001, 65.0 * numpy.pi / 180.0], [45.0 * numpy.pi / 180.0, 0.0001], [0.01, 0.01]) binaries = particles[particles.is_binary] binaries.include_pairwise_1PN_terms = False code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() self.assertEqual(0.6, code.particles[particles.is_binary][1].eccentricity) t = 0.0 | units.Myr dt = 1.0e-2 | units.Myr tend = 3.0e0 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() INCL_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() N = 0 while (t < tend): t += dt N += 1 code.evolve_model(t) print('t/Myr = ', code.model_time.value_in(units.Myr)) channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) INCL_print_array.append(binaries[0].inclination_relative_to_parent | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16, 10)) plot1 = fig.add_subplot(2, 1, 1) plot2 = fig.add_subplot(2, 1, 2, yscale="log") plot1.plot(t_print_array.value_in(units.Myr), (180.0 / numpy.pi) * INCL_print_array.value_in(units.none), color='k') plot2.plot(t_print_array.value_in(units.Myr), 1.0 - e_print_array.value_in(units.none), color='k') fontsize = 15 plot1.set_ylabel("$i$", fontsize=fontsize) plot2.set_ylabel("$1-e$", fontsize=fontsize) plot2.set_xlabel("$t/\mathrm{Myr}$", fontsize=fontsize) pyplot.show()
def test3(self): """ test GW emission in 2-body system + collision detection """ particles = create_nested_multiple(2,[1.0|units.MSun, 1.0|units.MJupiter], [0.1|units.AU], [0.994], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] stars = particles - binaries stars.radius = 0.0001 | units.AU binaries.check_for_physical_collision_or_orbit_crossing = True binaries.include_pairwise_25PN_terms = True code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() tend = 1.0 | units.Gyr N = 0 t = 0.0 | units.Myr dt = 100.0 | units.Myr while (t<tend): t+=dt N+=1 code.evolve_model(t) flag = code.flag if flag == 2: print 'root found' break channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) print 'e',binaries.eccentricity,'a/AU',binaries.semimajor_axis.value_in(units.AU),'rp/AU',(binaries.semimajor_axis*(1.0-binaries.eccentricity)).value_in(units.AU) if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16,10)) plot1 = fig.add_subplot(2,1,1) plot2 = fig.add_subplot(2,1,2,yscale="log") plot1.plot(t_print_array.value_in(units.Myr),e_print_array.value_in(units.none), color='r') plot2.plot(t_print_array.value_in(units.Myr),a_print_array.value_in(units.AU), color='r') fontsize = 15 plot1.set_ylabel("$e$",fontsize=fontsize) plot2.set_ylabel("$a/\mathrm{AU}$",fontsize=fontsize) plot2.set_xlabel("$t/\mathrm{Myr}$",fontsize=fontsize) pyplot.show()
def test6(self): """ test precession due to rotation """ M = 1.0|units.MJupiter R = 1.5|units.RJupiter m_per = 1.0|units.MSun a0 = 30.0 | units.AU e0 = 0.999 P0 = 2.0*numpy.pi*numpy.sqrt(a0**3/(constants.G*(M+m_per))) n0 = 2.0*numpy.pi/P0 aF = a0*(1.0-e0**2) nF = numpy.sqrt( constants.G*(M+m_per)/(aF**3) ) particles = create_nested_multiple(2, [m_per, M], [a0], [e0], [1.0e-5], [1.0e-5], [1.0e-5]) binaries = particles[particles.is_binary] particles[0].radius = 1.0 | units.RSun particles[1].radius = R particles[1].spin_vec_x = 0.0 | 1.0/units.day particles[1].spin_vec_y = 0.0 | 1.0/units.day Omega_PS0 = n0*(33.0/10.0)*pow(a0/aF,3.0/2.0) particles[1].spin_vec_z = Omega_PS0 k_L = 0.51 k_AM = k_L/2.0 rg = 0.25 particles[1].tides_method = 1 particles[1].include_tidal_friction_terms = False particles[1].include_tidal_bulges_precession_terms = False particles[1].include_rotation_precession_terms = True particles[1].minimum_eccentricity_for_tidal_precession = 1.0e-5 particles[1].tides_apsidal_motion_constant = k_AM particles[1].tides_gyration_radius = rg code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e1 | units.Myr tend = 1.0e2 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() Omega_vec = [particles[1].spin_vec_x,particles[1].spin_vec_y,particles[1].spin_vec_z] Omega = numpy.sqrt(Omega_vec[0]**2 + Omega_vec[1]**2 + Omega_vec[2]**2) print 'Omega/n',Omega/n0 g_dot_rot = n0*(1.0 + m_per/M)*k_AM*pow(R/a0,5.0)*(Omega/n0)**2/((1.0-e0**2)**2) t_rot = 2.0*numpy.pi/g_dot_rot print 't_rot/Myr',t_rot.value_in(units.Myr) N=0 while (t<tend): t+=dt code.evolve_model(t) print 'flag',code.flag,t,binaries[0].semimajor_axis,binaries[0].eccentricity channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) N+=1 if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16,10)) plot1 = fig.add_subplot(4,1,1) plot2 = fig.add_subplot(4,1,2,yscale="log") plot3 = fig.add_subplot(4,1,3,yscale="log") plot4 = fig.add_subplot(4,1,4,yscale="log") plot1.plot(t_print_array.value_in(units.Myr),AP_print_array.value_in(units.none), color='r') points = numpy.linspace(0.0,tend.value_in(units.Myr),N) AP = 0.01 +2.0*numpy.pi*points/(t_rot.value_in(units.Myr)) AP = (AP+numpy.pi)%(2.0*numpy.pi) - numpy.pi ### -pi < AP < pi plot1.plot(points,AP,color='g') plot2.plot(t_print_array.value_in(units.Myr),numpy.fabs( (AP - AP_print_array.value_in(units.none))/AP ), color='r') plot3.plot(t_print_array.value_in(units.Myr),numpy.fabs((a0-a_print_array)/a0), color='r') plot4.plot(t_print_array.value_in(units.Myr),numpy.fabs((e0-e_print_array)/e0), color='r') fontsize = 15 plot1.set_ylabel("$\omega$",fontsize=fontsize) plot2.set_ylabel("$|(\omega_p-\omega)/\omega_p|$",fontsize=fontsize) plot3.set_ylabel("$|(a_0-a)/a_0|$",fontsize=fontsize) plot4.set_ylabel("$|(e_0-e)/e_0|$",fontsize=fontsize) pyplot.show()
def test4(self): """ test tidal friction in 2-body system """ M = 1.0|units.MJupiter R = 40.0|units.RJupiter m_per = 1.0|units.MSun m = m_per mu = m*M/(m+M) a0 = 0.1 | units.AU e0 = 0.3 P0 = 2.0*numpy.pi*numpy.sqrt(a0**3/(constants.G*(M+m_per))) n0 = 2.0*numpy.pi/P0 aF = a0*(1.0-e0**2) nF = numpy.sqrt( constants.G*(M+m_per)/(aF**3) ) particles = create_nested_multiple(2, [m_per, M], [a0], [e0], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] particles[0].radius = 1.0 | units.RSun particles[1].radius = R particles[1].spin_vec_x = 0.0 | 1.0/units.day particles[1].spin_vec_y = 0.0 | 1.0/units.day particles[1].spin_vec_z = 4.0e-2 | 1.0/units.day k_L = 0.38 k_AM = k_L/2.0 rg = 0.25 tau = 0.66 | units.s I = rg*M*R**2 alpha = I/(mu*a0**2) T = R**3/(constants.G*M*tau) t_V = 3.0*(1.0 + 1.0/k_L)*T particles[1].tides_method = 2 particles[1].include_tidal_friction_terms = True particles[1].include_tidal_bulges_precession_terms = False particles[1].include_rotation_precession_terms = False particles[1].minimum_eccentricity_for_tidal_precession = 1.0e-8 particles[1].tides_apsidal_motion_constant = k_AM particles[1].tides_viscous_time_scale = t_V particles[1].tides_gyration_radius = rg tD = M*aF**8/(3.0*k_L*tau*constants.G*m_per*(M+m_per)*R**5) particles[2].check_for_physical_collision_or_orbit_crossing = True code = SecularMultiple(redirection='none') code.particles.add_particles(particles) code.parameters.relative_tolerance = 1.0e-14 channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e-5 | units.Myr tend = 1.0e-4 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() n_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() spin_print_array = quantities.AdaptingVectorQuantity() while (t<tend): t+=dt code.evolve_model(t) print 'flag',code.flag,t,'a/AU',binaries[0].semimajor_axis,'e',binaries[0].eccentricity channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) n_print_array.append(numpy.sqrt(constants.G*(M+m)/(binaries[0].semimajor_axis**3))) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) spin_print_array.append( numpy.sqrt( particles[1].spin_vec_x**2 + particles[1].spin_vec_y**2 + particles[1].spin_vec_z**2) ) binaries = particles[particles.is_binary] bodies = particles - binaries print 'S_x',bodies.spin_vec_x.value_in(1.0/units.day) print 'S_y',bodies.spin_vec_y.value_in(1.0/units.day) print 'S_z',bodies.spin_vec_z.value_in(1.0/units.day) print '='*50 if HAS_MATPLOTLIB == True: fig = pyplot.figure() fontsize=12 N_p = 4 plot1 = fig.add_subplot(N_p,1,1) plot1.plot(t_print_array.value_in(units.Myr),a_print_array.value_in(units.AU), color='r') plot1.set_ylabel("$a/\mathrm{AU}$",fontsize=fontsize) plot2 = fig.add_subplot(N_p,1,2) plot2.plot(t_print_array.value_in(units.Myr),e_print_array.value_in(units.none),color='k') plot2.set_ylabel("$e$",fontsize=fontsize) plot3 = fig.add_subplot(N_p,1,3,yscale="log") plot3.plot(t_print_array.value_in(units.Myr),a_print_array.value_in(units.AU)*(1.0-e_print_array.value_in(units.none)**2),color='k') plot3.axhline(y = a0.value_in(units.AU)*(1.0 - e0**2), color='k') plot3.set_ylabel("$a(1-e^2)/\mathrm{AU}$",fontsize=fontsize) plot4 = fig.add_subplot(N_p,1,4) plot4.plot(t_print_array.value_in(units.Myr),spin_print_array/n_print_array) plot4.set_ylabel("$\Omega/n$",fontsize=fontsize) plot4.set_xlabel("$t/\mathrm{Myr}$",fontsize=fontsize) pyplot.show()
def test0(self): instance = SecularMultiple() print(instance.parameters)
def evolve_quadruple(N_output, end_time, m1, m2, m3, m4, aA, aB, aC, eA, eB, eC, iA, iB, iC, ApA, ApB, ApC, LANA, LANB, LANC): masses = [m1, m2, m3, m4] semimajor_axis = [aA, aB, aC] eccentricity = [eA, eB, eC] inclination = numpy.deg2rad([iA, iB, iC]) argument_of_percienter = numpy.deg2rad([ApA, ApB, ApC]) longitude_of_ascending_node = numpy.deg2rad([LANA, LANB, LANC]) print longitude_of_ascending_node N_bodies = 4 N_binaries = N_bodies - 1 particles, binaries = initialize_multiple_system( N_bodies, masses, semimajor_axis, eccentricity, inclination, argument_of_percienter, longitude_of_ascending_node) code = SecularMultiple() code.particles.add_particles(particles) channel_from_particles_to_code = particles.new_channel_to(code.particles) channel_from_code_to_particles = code.particles.new_channel_to(particles) channel_from_particles_to_code.copy() ### set up some arrays for plotting ### print_smas_AU = [[] for x in range(N_binaries)] print_rps_AU = [[] for x in range(N_binaries)] print_parent_is_deg = [[] for x in range(N_binaries)] print_times_Myr = [] time = 0.0 | units.yr output_time_step = end_time / float(N_output) while time <= end_time: time += output_time_step code.evolve_model(time) channel_from_code_to_particles.copy() print '=' * 50 print 't/Myr', time.value_in(units.Myr) print 'e', binaries.eccentricity print 'i/deg', numpy.rad2deg(binaries.inclination) print 'AP/deg', \ numpy.rad2deg(binaries.argument_of_pericenter) print 'LAN/deg', \ numpy.rad2deg(binaries.longitude_of_ascending_node) ### write to output arrays ### print_times_Myr.append(time.value_in(units.Myr)) for index_binary in range(N_binaries): print_smas_AU[index_binary].append( binaries[index_binary].semimajor_axis.value_in(units.AU)) print_rps_AU[index_binary].append( binaries[index_binary].semimajor_axis.value_in(units.AU) * (1.0 - binaries[index_binary].eccentricity)) print_parent_is_deg[index_binary].append( numpy.rad2deg( binaries[index_binary].inclination_relative_to_parent)) ### compute the `canonical' maximum eccentricity/periapsis distance that applies in the quadrupole-order test-particle limit if the `outer' binary is replaced by a point mass ### print inclination[0], inclination[2], longitude_of_ascending_node[ 0], longitude_of_ascending_node[2] i_AC_init = compute_mutual_inclination(inclination[0], inclination[2], longitude_of_ascending_node[0], longitude_of_ascending_node[2]) i_BC_init = compute_mutual_inclination(inclination[1], inclination[2], longitude_of_ascending_node[1], longitude_of_ascending_node[2]) canonical_rp_min_A_AU = ( semimajor_axis[0] * (1.0 - numpy.sqrt(1.0 - (5.0 / 3.0) * numpy.cos(i_AC_init)**2))).value_in( units.AU) canonical_rp_min_B_AU = ( semimajor_axis[1] * (1.0 - numpy.sqrt(1.0 - (5.0 / 3.0) * numpy.cos(i_BC_init)**2))).value_in( units.AU) data = print_times_Myr, print_smas_AU, print_rps_AU, print_parent_is_deg, canonical_rp_min_A_AU, canonical_rp_min_B_AU return data
def test2(self): """ test 1PN precession in 2-body system """ particles = create_nested_multiple( 2, [1.0 | units.MSun, 1.0 | units.MJupiter], [1.0 | units.AU], [0.99], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] binaries.include_pairwise_1PN_terms = True code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e-1 | units.Myr tend = 1.0e0 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() N = 0 while (t < tend): t += dt N += 1 code.evolve_model(t) channel_from_code.copy() print('t/Myr', t.value_in(units.Myr), 'omega', binaries[0].argument_of_pericenter | units.none) t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) a = binaries[0].semimajor_axis e = binaries[0].eccentricity M = binaries[0].mass rg = constants.G * M / (constants.c**2) P = 2.0 * numpy.pi * numpy.sqrt(a**3 / (constants.G * M)) t_1PN = (1.0 / 3.0) * P * (1.0 - e**2) * (a / rg) if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16, 10)) plot1 = fig.add_subplot(4, 1, 1) plot2 = fig.add_subplot(4, 1, 2, yscale="log") plot3 = fig.add_subplot(4, 1, 3, yscale="log") plot4 = fig.add_subplot(4, 1, 4, yscale="log") plot1.plot(t_print_array.value_in(units.Myr), AP_print_array.value_in(units.none), color='r') points = numpy.linspace(0.0, tend.value_in(units.Myr), N) AP = 0.01 + 2.0 * numpy.pi * points / (t_1PN.value_in(units.Myr)) AP = (AP + numpy.pi) % (2.0 * numpy.pi) - numpy.pi ### -pi < AP < pi plot1.plot(points, AP, color='g') plot2.plot(t_print_array.value_in(units.Myr), numpy.fabs( (AP - AP_print_array.value_in(units.none)) / AP), color='r') plot3.plot(t_print_array.value_in(units.Myr), numpy.fabs((a - a_print_array) / a), color='r') plot4.plot(t_print_array.value_in(units.Myr), numpy.fabs((e - e_print_array) / e), color='r') fontsize = 15 plot1.set_ylabel("$\omega$", fontsize=fontsize) plot2.set_ylabel("$|(\omega_p-\omega)/\omega_p|$", fontsize=fontsize) plot3.set_ylabel("$|(a_0-a)/a_0|$", fontsize=fontsize) plot4.set_ylabel("$|(e_0-e)/e_0|$", fontsize=fontsize) pyplot.show()
def run_secularmultiple(particle_set, end_time, start_time=(0 |units.Myr), \ N_output=100, debug_mode=False, genT4System=False, \ exportData=True, useAMD=True, GCode = None, \ KeySystemID=None, SEVCode=None): '''Does what it says on the tin.''' try: hierarchical_test = [x for x in particle_set if x.is_binary == True] print("The supplied set has", len(hierarchical_test), "node particles and is a tree.") py_particles = particle_set except: print("The supplied set is NOT a tree set! Building tree ...") py_particles = get_full_hierarchical_structure(particle_set, KeySystemID=KeySystemID, SEVCode=SEVCode) hierarchical_test = [x for x in py_particles if x.is_binary == True] print("Tree has been built with", len(hierarchical_test), "node particles.") nodes = py_particles.select(lambda x: x == True, ["is_binary"]) Num_nodes = len(nodes) stellarCollisionOccured = False if GCode == None: code = SecularMultiple() else: code = GCode if exportData: plot_a_AU = defaultdict(list) plot_e = defaultdict(list) plot_peri_AU = defaultdict(list) plot_stellar_inc_deg = defaultdict(list) if useAMD: plot_AMDBeta = defaultdict(list) plot_times_Myr = [] if genT4System: print(nodes.inclination) nodes.inclination = [-18.137, 0.0, 23.570] | units.deg print(nodes.inclination) if debug_mode: print('=' * 50) print('t/kyr', 0.00) print('a/AU', nodes.semimajor_axis) print('p/day', nodes.period) print('e', nodes.eccentricity) print('i/deg', nodes.inclination) print('AP/deg', \ nodes.argument_of_pericenter) print('LAN/deg', \ nodes.longitude_of_ascending_node) #print(py_particles) code.particles.add_particles(py_particles) #code.commit_particles() #print(code.particles.semimajor_axis) code.model_time = start_time #print(py_particles.id, py_particles.semimajor_axis) channel_from_particles_to_code = py_particles.new_channel_to( code.particles) channel_from_code_to_particles = code.particles.new_channel_to( py_particles) #print(py_particles.id, py_particles.semimajor_axis) channel_from_particles_to_code.copy( ) #copy_attributes(['semimajor_axis', 'eccentricity', \ #'longitude_of_ascending_node', 'argument_of_pericenter', 'inclination']) #print('This is After the First Channel Copy:', code.particles.semimajor_axis) time = start_time if useAMD: #print(py_particles.id, py_particles.mass) jovianParent = get_jovian_parent(py_particles) output_time_step = 1000 * jovianParent.period.value_in( units.Myr) | units.Myr PS = initialize_PlanetarySystem_from_HierarchicalSet(py_particles) PS.get_SystemBetaValues() if exportData: for planet in PS.planets: plot_AMDBeta[planet.id].append(planet.AMDBeta) else: output_time_step = end_time / float(N_output) if exportData: plot_times_Myr.append(time.value_in(units.Myr)) for i, node in enumerate(nodes): plot_a_AU[node.child2.id].append( node.semimajor_axis.value_in(units.AU)) plot_e[node.child2.id].append(node.eccentricity) plot_peri_AU[node.child2.id].append( node.semimajor_axis.value_in(units.AU) * (1.0 - node.eccentricity)) plot_stellar_inc_deg[node.child2.id].append( node.inclination.value_in(units.deg)) counter = 0 while time <= end_time: #print('Start of Time Loop') #print(output_time_step) time += output_time_step counter += 1 #print(time) #print(code.model_time) #print(code.particles.semimajor_axis) code.evolve_model(time) #print('Evolved model to:', time.value_in(units.Myr), "Myr") #print(code.particles.semimajor_axis) channel_from_code_to_particles.copy() #channel_from_code_to_particles.copy_attributes(['semimajor_axis', 'eccentricity', \ #'longitude_of_ascending_node', 'argument_of_pericenter', 'inclination']) #print('Hello') py_particles.time = time if exportData: plot_times_Myr.append(time.value_in(units.Myr)) nodes = py_particles.select(lambda x: x == True, ["is_binary"]) for i, node in enumerate(nodes): plot_a_AU[node.child2.id].append( node.semimajor_axis.value_in(units.AU)) plot_e[node.child2.id].append(node.eccentricity) plot_peri_AU[node.child2.id].append( node.semimajor_axis.value_in(units.AU) * (1.0 - node.eccentricity)) plot_stellar_inc_deg[node.child2.id].append( node.inclination.value_in(units.deg)) if time == end_time + output_time_step: map_node_oe_to_lilsis(py_particles) if debug_mode: if time == end_time or time == output_time_step: print('=' * 50) print('t/kyr', time.value_in(units.kyr)) print('a/AU', nodes.semimajor_axis) print('p/day', nodes.period) print('e', nodes.eccentricity) print('i/deg', nodes.inclination) print('AP/deg', \ nodes.argument_of_pericenter) print('LAN/deg', \ nodes.longitude_of_ascending_node) # Check for Planet Destruction from Star #print(py_particles.id, py_particles.semimajor_axis) temp = check_for_stellar_collision(py_particles) #print(temp) # Returns 'None' if No Destruction! if temp != None: code.stop() code = SecularMultiple() code.model_time = time py_particles = Particles() py_particles.add_particles(temp) code.particles.add_particles(py_particles) py_particles.time = time #code.commit_particles() channel_from_particles_to_code = py_particles.new_channel_to( code.particles) channel_from_code_to_particles = code.particles.new_channel_to( py_particles) channel_from_particles_to_code.copy() nodes = py_particles.select(lambda x: x == True, ["is_binary"]) stellarCollisionOccured = True if useAMD: PS = initialize_PlanetarySystem_from_HierarchicalSet( py_particles) #channel_from_code_to_particles.copy_attributes(['semimajor_axis', 'eccentricity', \ #'longitude_of_ascending_node', 'argument_of_pericenter', 'inclination']) #print(code.particles.semimajor_axis) # AMD Checking if useAMD: PS = update_oe_for_PlanetarySystem(PS, py_particles) PS.get_SystemBetaValues() if exportData: for planet in PS.planets: plot_AMDBeta[planet.id].append(planet.AMDBeta) if counter % 100 == 0 and len( PS.planets.select(lambda x: x < 1.0, ["AMDBeta"])) > 1: break if GCode == None: code.stop() else: code = reset_secularmultiples(code) if exportData: if useAMD: data = plot_times_Myr, plot_a_AU, plot_e, plot_peri_AU, plot_stellar_inc_deg, plot_AMDBeta else: data = plot_times_Myr, plot_a_AU, plot_e, plot_peri_AU, plot_stellar_inc_deg else: data = None # Set the Output Code to be the New Code if a Stellar Collision Occured. if stellarCollisionOccured: newcode = code else: newcode = None return py_particles, data, newcode
def test4(self): """ test tidal friction in 2-body system """ M = 1.0 | units.MJupiter R = 40.0 | units.RJupiter m_per = 1.0 | units.MSun m = m_per mu = m * M / (m + M) a0 = 0.1 | units.AU e0 = 0.3 P0 = 2.0 * numpy.pi * numpy.sqrt(a0**3 / (constants.G * (M + m_per))) n0 = 2.0 * numpy.pi / P0 aF = a0 * (1.0 - e0**2) nF = numpy.sqrt(constants.G * (M + m_per) / (aF**3)) particles = create_nested_multiple(2, [m_per, M], [a0], [e0], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] particles[0].radius = 1.0 | units.RSun particles[1].radius = R particles[1].spin_vec_x = 0.0 | 1.0 / units.day particles[1].spin_vec_y = 0.0 | 1.0 / units.day particles[1].spin_vec_z = 4.0e-2 | 1.0 / units.day k_L = 0.38 k_AM = k_L / 2.0 rg = 0.25 tau = 0.66 | units.s I = rg * M * R**2 alpha = I / (mu * a0**2) T = R**3 / (constants.G * M * tau) t_V = 3.0 * (1.0 + 1.0 / k_L) * T particles[1].tides_method = 2 particles[1].include_tidal_friction_terms = True particles[1].include_tidal_bulges_precession_terms = False particles[1].include_rotation_precession_terms = False particles[1].minimum_eccentricity_for_tidal_precession = 1.0e-8 particles[1].tides_apsidal_motion_constant = k_AM particles[1].tides_viscous_time_scale = t_V particles[1].tides_gyration_radius = rg tD = M * aF**8 / (3.0 * k_L * tau * constants.G * m_per * (M + m_per) * R**5) particles[2].check_for_physical_collision_or_orbit_crossing = True code = SecularMultiple(redirection='none') code.particles.add_particles(particles) code.parameters.relative_tolerance = 1.0e-14 channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e-5 | units.Myr tend = 1.0e-4 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() n_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() spin_print_array = quantities.AdaptingVectorQuantity() while (t < tend): t += dt code.evolve_model(t) print('flag', code.flag, t, 'a/AU', binaries[0].semimajor_axis, 'e', binaries[0].eccentricity) channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) n_print_array.append( numpy.sqrt(constants.G * (M + m) / (binaries[0].semimajor_axis**3))) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) spin_print_array.append( numpy.sqrt(particles[1].spin_vec_x**2 + particles[1].spin_vec_y**2 + particles[1].spin_vec_z**2)) binaries = particles[particles.is_binary] bodies = particles - binaries print('S_x', bodies.spin_vec_x.value_in(1.0 / units.day)) print('S_y', bodies.spin_vec_y.value_in(1.0 / units.day)) print('S_z', bodies.spin_vec_z.value_in(1.0 / units.day)) print('=' * 50) if HAS_MATPLOTLIB == True: fig = pyplot.figure() fontsize = 12 N_p = 4 plot1 = fig.add_subplot(N_p, 1, 1) plot1.plot(t_print_array.value_in(units.Myr), a_print_array.value_in(units.AU), color='r') plot1.set_ylabel("$a/\mathrm{AU}$", fontsize=fontsize) plot2 = fig.add_subplot(N_p, 1, 2) plot2.plot(t_print_array.value_in(units.Myr), e_print_array.value_in(units.none), color='k') plot2.set_ylabel("$e$", fontsize=fontsize) plot3 = fig.add_subplot(N_p, 1, 3, yscale="log") plot3.plot(t_print_array.value_in(units.Myr), a_print_array.value_in(units.AU) * (1.0 - e_print_array.value_in(units.none)**2), color='k') plot3.axhline(y=a0.value_in(units.AU) * (1.0 - e0**2), color='k') plot3.set_ylabel("$a(1-e^2)/\mathrm{AU}$", fontsize=fontsize) plot4 = fig.add_subplot(N_p, 1, 4) plot4.plot(t_print_array.value_in(units.Myr), spin_print_array / n_print_array) plot4.set_ylabel("$\Omega/n$", fontsize=fontsize) plot4.set_xlabel("$t/\mathrm{Myr}$", fontsize=fontsize) pyplot.show()
def test5(self): """ test precession due to tidal bulges """ M = 1.0 | units.MJupiter R = 1.0 | units.RJupiter m_per = 1.0 | units.MSun a0 = 30.0 | units.AU e0 = 0.999 P0 = 2.0 * numpy.pi * numpy.sqrt(a0**3 / (constants.G * (M + m_per))) n0 = 2.0 * numpy.pi / P0 particles = create_nested_multiple(2, [m_per, M], [a0], [e0], [0.01], [0.01], [0.01]) binaries = particles[particles.is_binary] particles[0].radius = 1.0 | units.RSun particles[1].radius = R k_L = 0.41 k_AM = k_L / 2.0 particles[1].tides_method = 0 particles[1].include_tidal_friction_terms = False particles[1].include_tidal_bulges_precession_terms = True particles[1].include_rotation_precession_terms = False particles[1].minimum_eccentricity_for_tidal_precession = 1.0e-5 particles[1].tides_apsidal_motion_constant = k_AM code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e1 | units.Myr tend = 1.0e2 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() AP_print_array = quantities.AdaptingVectorQuantity() g_dot_TB = (15.0 / 8.0) * n0 * (8.0 + 12.0 * e0**2 + e0**4) * ( m_per / M) * k_AM * pow(R / a0, 5.0) / pow(1.0 - e0**2, 5.0) t_TB = 2.0 * numpy.pi / g_dot_TB N = 0 while (t < tend): t += dt code.evolve_model(t) print 'flag', code.flag, t, binaries[0].semimajor_axis, binaries[ 0].eccentricity channel_from_code.copy() t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) AP_print_array.append(binaries[0].argument_of_pericenter | units.none) N += 1 if HAS_MATPLOTLIB == True: fig = pyplot.figure(figsize=(16, 10)) plot1 = fig.add_subplot(4, 1, 1) plot2 = fig.add_subplot(4, 1, 2, yscale="log") plot3 = fig.add_subplot(4, 1, 3, yscale="log") plot4 = fig.add_subplot(4, 1, 4, yscale="log") plot1.plot(t_print_array.value_in(units.Myr), AP_print_array.value_in(units.none), color='r') points = numpy.linspace(0.0, tend.value_in(units.Myr), N) AP = 0.01 + 2.0 * numpy.pi * points / (t_TB.value_in(units.Myr)) AP = (AP + numpy.pi) % (2.0 * numpy.pi) - numpy.pi ### -pi < AP < pi plot1.plot(points, AP, color='g') plot2.plot(t_print_array.value_in(units.Myr), numpy.fabs( (AP - AP_print_array.value_in(units.none)) / AP), color='r') plot3.plot(t_print_array.value_in(units.Myr), numpy.fabs((a0 - a_print_array) / a0), color='r') plot4.plot(t_print_array.value_in(units.Myr), numpy.fabs((e0 - e_print_array) / e0), color='r') fontsize = 15 plot1.set_ylabel("$\omega$", fontsize=fontsize) plot2.set_ylabel("$|(\omega_p-\omega)/\omega_p|$", fontsize=fontsize) plot3.set_ylabel("$|(a_0-a)/a_0|$", fontsize=fontsize) plot4.set_ylabel("$|(e_0-e)/e_0|$", fontsize=fontsize) pyplot.show()
def test7(self): """ test collision detection in 3-body system """ particles = create_nested_multiple( 3, [1.0 | units.MSun, 1.2 | units.MSun, 0.9 | units.MSun], [1.0 | units.AU, 100.0 | units.AU], [0.1, 0.5], [0.01, 80.0 * numpy.pi / 180.0], [0.01, 0.01], [0.01, 0.01]) binaries = particles[particles.is_binary] stars = particles - binaries binaries.check_for_physical_collision_or_orbit_crossing = True stars.radius = 0.03 | units.AU code = SecularMultiple(redirection='none') code.particles.add_particles(particles) channel_to_code = particles.new_channel_to(code.particles) channel_from_code = code.particles.new_channel_to(particles) channel_to_code.copy() t = 0.0 | units.Myr dt = 1.0e-2 | units.Myr tend = 1.0e-1 | units.Myr t_print_array = quantities.AdaptingVectorQuantity() a_print_array = quantities.AdaptingVectorQuantity() e_print_array = quantities.AdaptingVectorQuantity() while (t < tend): t += dt code.evolve_model(t) flag = code.flag channel_from_code.copy() print('secular_breakdown_has_occurred', binaries.secular_breakdown_has_occurred) print('dynamical_instability_has_occurred', binaries.dynamical_instability_has_occurred) print('physical_collision_or_orbit_crossing_has_occurred', binaries.physical_collision_or_orbit_crossing_has_occurred) print('minimum_periapse_distance_has_occurred', binaries.minimum_periapse_distance_has_occurred) print('RLOF_at_pericentre_has_occurred', binaries.RLOF_at_pericentre_has_occurred) if flag == 2: print('root found') break print('t_end', code.model_time.value_in(units.Myr)) t_print_array.append(t) a_print_array.append(binaries[0].semimajor_axis) e_print_array.append(binaries[0].eccentricity | units.none) if HAS_MATPLOTLIB == True: fig = pyplot.figure() plot = fig.add_subplot(2, 1, 1) plot.plot(t_print_array.value_in(units.Myr), e_print_array.value_in(units.none)) plot = fig.add_subplot(2, 1, 2) plot.plot( t_print_array.value_in(units.Myr), a_print_array.value_in(units.AU) * (1.0 - e_print_array.value_in(units.none))) plot.axhline(y=stars[0].radius.value_in(units.AU) + stars[1].radius.value_in(units.AU), color='k') pyplot.show()
def simulate_all_close_encounters(rootExecDir, **kwargs): ''' This function will run all scatters for a single cluster in serial. str rootExecDir -> The absolute root directory for all single cluster files. ''' max_number_of_rotations = kwargs.get("maxRotations", 100) max_runtime = kwargs.get("maxRunTime", 10**5) # Units Years delta_time = kwargs.get("dt", 10) # Units Years # Strip off Extra '/' if added by user to bring inline with os.cwd() if rootExecDir.endswith("/"): rootExecDir = rootExecDir[:-1] # Define the Cluster's Name cluster_name = rootExecDir.split("/")[-1] # Generate List of Scattering IC HDF5 Paths enc_dict = scattering.build_ClusterEncounterHistory(rootExecDir) # Find all Primary Star IDs star_IDs = enc_dict.keys() # Integer tied to StarID # Set Up Output Directory Structure output_MainDirectory = rootExecDir + "/Encounters" if not os.path.exists(output_MainDirectory): os.mkdir(output_MainDirectory) # Initialize the Necessary Worker Lists converter = nbody_system.nbody_to_si(1 | units.MSun, 100 | units.AU) KepW = [] for i in range(2): KepW.append(Kepler(unit_converter=converter, redirection='none')) KepW[-1].initialize_code() NBodyW = [ scattering.initialize_GravCode(ph4), scattering.initialize_isOverCode() ] SecW = SecularMultiple() SEVW = SSE() # Loop Over the Stars for star_ID in star_IDs: # Load the Close Encounter class for the Star EncounterHandler = scattering.CloseEncounters(enc_dict[star_ID], KeplerWorkerList = KepW, \ NBodyWorkerList = NBodyW, SecularWorker = SecW, SEVWorker = SEVW) # Simulate Encounter EncounterHandler.SimAllEncounters() # Prepare Data for Pickling file_name = output_MainDirectory + "/" + str( star_ID) + "_EncounterHandler.pk" p_file = open(file_name, "wb") # Remove Worker Lists from Class for Storage EncounterHandler.kep = None EncounterHandler.NBodyCodes = None EncounterHandler.SecularCode = None EncounterHandler.SEVCode = None # Pickle EncounterHandler Class # Note: This allows for ease-of-use when you want to revisit # a specific star's simulation set in detail. pickle.dump(EncounterHandler, p_file) p_file.close() # Note: Ensure the EncounterHandler class is deleted incase # of a memory leak is possible in future updates. del EncounterHandler # Stop all Workers for Worker in KepW + NBodyW + [SecW] + SEVW: Worker.stop()