def test1(self): convert = nbody_system.nbody_to_si(1.e5 | units.MSun, 1.0 | units.parsec) eps=2.e-4 | nbody_system.length test_class=PhiGRAPE number_of_particles = 50 stars = new_king_model(number_of_particles, W0=7, convert_nbody=convert) stars.radius = 0.0 | units.RSun cluster=test_class(convert) cluster.parameters.epsilon_squared = eps**2 cluster.particles.add_particles(stars) cluster.synchronize_model() Ep1=convert.to_nbody(cluster.potential_energy).number Ek1=convert.to_nbody(cluster.kinetic_energy).number parts=cluster.particles.copy() parts1=parts.select_array(lambda x: (x > 0 | units.m), ['x'] ) parts2=parts.select_array(lambda x: (x < 0 | units.m), ['x'] ) cluster1=sys_from_parts(test_class, parts1, convert, eps) cluster2=sys_from_parts(test_class, parts2, convert, eps) cluster1.synchronize_model() cluster2.synchronize_model() bridgesys=bridge() bridgesys.add_system(cluster1, (cluster2,) ) bridgesys.add_system(cluster2, (cluster1,) ) Ep2=convert.to_nbody(bridgesys.potential_energy).number Ek2=convert.to_nbody(bridgesys.kinetic_energy).number self.assertAlmostEqual(Ek1,Ek2,12) self.assertAlmostEqual(Ep1,Ep2,12)
def evolve_cluster_in_galaxy(N, W0, Rinit, tend, timestep, M, R): galaxy_code = MilkyWay_galaxy() converter = nbody_system.nbody_to_si(M, R) cluster_code = drift_without_gravity(convert_nbody=converter) bodies = new_king_model(N, W0, convert_nbody=converter) cluster_code.particles.add_particles(bodies) stars = cluster_code.particles.copy() stars.x += Rinit stars.vy = 0.8*galaxy_code.circular_velocity(Rinit) channel = stars.new_channel_to(cluster_code.particles) channel.copy_attributes(["x","y","z","vx","vy","vz"]) system = bridge(verbose=False) system.add_system(cluster_code, (galaxy_code,)) times = quantities.arange(0|units.Myr, tend, 100*timestep) for i,t in enumerate(times): print "Time=", t.in_(units.Myr) system.evolve_model(t, timestep=timestep) x = system.particles.x.value_in(units.kpc) y = system.particles.y.value_in(units.kpc) cluster_code.stop() return x, y
def evolve_cluster_in_galaxy(N, W0, Rinit, tend, timestep, M, R): galaxy_code = MilkyWay_galaxy() converter = nbody_system.nbody_to_si(M, R) cluster_code = drift_without_gravity(convert_nbody=converter) bodies = new_king_model(N, W0, convert_nbody=converter) cluster_code.particles.add_particles(bodies) stars = cluster_code.particles.copy() stars.x += Rinit stars.vy = 0.8 * galaxy_code.circular_velocity(Rinit) channel = stars.new_channel_to(cluster_code.particles) channel.copy_attributes(["x", "y", "z", "vx", "vy", "vz"]) system = bridge(verbose=False) system.add_system(cluster_code, (galaxy_code, )) times = quantities.arange(0 | units.Myr, tend, 100 * timestep) for i, t in enumerate(times): print("Time=", t.in_(units.Myr)) system.evolve_model(t, timestep=timestep) x = system.particles.x.value_in(units.kpc) y = system.particles.y.value_in(units.kpc) cluster_code.stop() return x, y
def test1(self): print "First test: making a King model." number_of_particles = 10 particles = new_king_model(number_of_particles, 6.0) self.assertAlmostEqual(particles.mass.sum(), 1 | nbody_system.mass) self.assertAlmostEqual(particles[0].mass , 0.1 | nbody_system.mass) print particles self.assertFalse(particles[0].mass.is_vector())
def test1(self): print "First test: making a King model." number_of_particles = 10 particles = new_king_model(number_of_particles, 6.0) self.assertAlmostEqual(particles.mass.sum(), 1 | nbody_system.mass) self.assertAlmostEqual(particles[0].mass, 0.1 | nbody_system.mass) print particles self.assertFalse(particles[0].mass.is_vector())
def test2(self): print "Testing kinetic and potential energy of a King model realisation." convert_nbody = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.AU) number_of_particles = 500 particles = new_king_model(number_of_particles, 6.0, convert_nbody, do_scale = True) self.assertEquals(len(particles), number_of_particles) self.assertAlmostEqual(particles[0].mass, (1.0|units.MSun)/number_of_particles, 3, in_units=units.MSun) self.assertAlmostEqual(convert_nbody.to_nbody(particles.kinetic_energy()), 0.25 | nbody_system.energy) self.assertAlmostEqual(convert_nbody.to_nbody(particles.potential_energy()), -0.5 | nbody_system.energy)
def test2(self): print("Testing kinetic and potential energy of a King model realisation.") convert_nbody = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.AU) number_of_particles = 500 particles = new_king_model(number_of_particles, 6.0, convert_nbody, do_scale = True) self.assertEqual(len(particles), number_of_particles) self.assertAlmostEqual(particles[0].mass, (1.0|units.MSun)/number_of_particles, 3, in_units=units.MSun) self.assertAlmostEqual(convert_nbody.to_nbody(particles.kinetic_energy()), 0.25 | nbody_system.energy) self.assertAlmostEqual(convert_nbody.to_nbody(particles.potential_energy()), -0.5 | nbody_system.energy)
def king_cluster(num_stars, filename_cluster, w0=2.5, IBF=0.5, rand_seed=0): ''' Creates an open cluster according to the King Model & Kroupa IMF num_stars: The total number of stellar systems. seed: The random seed used for cluster generation. filename_cluster: The filename used when saving the cluster. w0: The King density parameter. IBF: The Initial Binary Fraction. ''' # TODO: Have rand_seed actually do something ... # Creates a List of Masses (in SI Units) Drawn from the Kroupa IMF masses_SI = new_kroupa_mass_distribution(num_stars) # Creates the SI-NBody Converter converter = nbody_system.nbody_to_si(masses_SI.sum(), 1 | units.parsec) # Creates a AMUS Particle Set Consisting of Positions (King) and Masses (Kroupa) stars_SI = new_king_model(num_stars, w0, convert_nbody=converter) stars_SI.mass = masses_SI print stars_SI.mass.as_quantity_in(units.MSun) # Assigning IDs to the Stars stars_SI.id = np.arange(num_stars) + 1 stars_SI.type = "star" # Moving Stars to Virial Equilibrium stars_SI.move_to_center() if num_stars == 1: pass else: stars_SI.scale_to_standard(convert_nbody=converter) if int(IBF) != 0: # Creating a Temporary Particle Set to Store Binaries binaries=Particles() # Selects the Indices of Stars that will be converted to Binaries num_binaries = int(IBF*num_stars) select_stars_indices_for_binaries = rp.sample(xrange(0, num_stars), num_binaries) select_stars_indices_for_binaries.sort() delete_star_indices = [] # Creates a decending list of Star Indicies to make deletion easier. for y in xrange(0, num_binaries): delete_star_indices.append(select_stars_indices_for_binaries[(num_binaries-1)-y]) # Creates the Binaries and assigns IDs for j in xrange(0, num_binaries): q = select_stars_indices_for_binaries[j] binaries.add_particles(binary_system(stars_SI[q], converter)) binaries.id = np.arange(num_binaries*2) + 2000000 # Deletes the Stars that were converted to Binaries for k in xrange(0, num_binaries): b = delete_star_indices[k] stars_SI.remove_particle(stars_SI[b]) # Merges the Binaries into to the Master Particle set stars_SI.add_particle(binaries) # Assigning SOI Estimate for Interaction Radius if num_stars == 1: stars_SI.radius = 1000 | units.AU else: stars_SI.radius = util.calc_SOI(stars_SI.mass, np.var(stars_SI.velocity), G=units.constants.G) # Returns the Cluster & Converter return stars_SI, converter
def __init__(self, options_reader): options_reader.set_options(self) # self.N, self.W0, self.Mcluster, self.Rcluster, self.ncpu # self.gpu_enabled, self.ngpu, self.softening if self.use_kroupa is True: m = new_kroupa_mass_distribution(self.N, self.kroupa_max | units.MSun) tot_m = np.sum(m.value_in(units.MSun)) self.converter = \ nbody_system.nbody_to_si(tot_m | units.MSun, self.Rcluster | units.parsec) self.bodies = new_king_model(self.N, self.W0, convert_nbody=self.converter) self.bodies.mass = m self.bodies.scale_to_standard(convert_nbody=self.converter) self.bodies.move_to_center() else: self.converter = \ nbody_system.nbody_to_si(self.Mcluster | units.MSun, self.Rcluster | units.parsec) self.bodies = new_king_model(self.N, self.W0, convert_nbody=self.converter) if self.gpu_enabled: self.code = self.nbodycode(self.converter, number_of_workers=self.ngpu, mode='gpu') else: self.code = self.nbodycode(self.converter, number_of_workers=self.ncpu) parameters = {'epsilon_squared': (self.softening | units.parsec)**2} for name, value in parameters.items(): setattr(self.code.parameters, name, value) self.code.particles.add_particles(self.bodies)
def make_king_model_cluster(nbodycode, N, W0, Mcluster, Rcluster, parameters = []): converter=nbody_system.nbody_to_si(Mcluster,Rcluster) bodies=new_king_model(N,W0,convert_nbody=converter) code=nbodycode(converter) for name,value in parameters: setattr(code.parameters, name, value) code.particles.add_particles(bodies) return code
def test5(self): print("Testing a specific King model realisation.") numpy.random.seed(345672) convert_nbody = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.AU) particles = new_king_model(500, 6.0, convert_nbody) self.assertEqual(len(particles), 500) self.assertAlmostEqual(particles.total_mass(), 1.0 | units.MSun) self.assertAlmostEqual(particles.mass, 1.0 / 500 | units.MSun) self.assertAlmostEqual(particles.center_of_mass(), [0,0,0] | units.AU) self.assertAlmostEqual(particles.center_of_mass_velocity(), [0,0,0] | units.km / units.s) self.assertAlmostEqual(particles[:3].position, [[-0.23147381,-0.19421449,-0.01165137], [-0.09283025,-0.06444658,-0.07922396], [-0.44189946,0.23786357,0.39115629]] | units.AU)
def test5(self): print "Testing a specific King model realisation." numpy.random.seed(345672) convert_nbody = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.AU) particles = new_king_model(500, 6.0, convert_nbody) self.assertEquals(len(particles), 500) self.assertAlmostEqual(particles.total_mass(), 1.0 | units.MSun) self.assertAlmostEqual(particles.mass, 1.0 / 500 | units.MSun) self.assertAlmostEqual(particles.center_of_mass(), [0,0,0] | units.AU) self.assertAlmostEqual(particles.center_of_mass_velocity(), [0,0,0] | units.km / units.s) self.assertAlmostEqual(particles[:3].position, [[-0.23147381,-0.19421449,-0.01165137], [-0.09283025,-0.06444658,-0.07922396], [-0.44189946,0.23786357,0.39115629]] | units.AU)
def sys_from_king(base_class, N, W, converter, eps=None, timestep=None, usegl=False, mode=None): parts = new_king_model(N, W0=W, convert_nbody=converter) parts.radius = 0. | nbody_system.length return sys_from_parts(base_class, parts, converter, eps, timestep, usegl, mode)
def evolve_cluster_in_galaxy(N, W0, Rinit, tend, timestep, M, R): R_galaxy=0.1 | units.kpc M_galaxy=1.6e10 | units.MSun converter=nbody_system.nbody_to_si(M_galaxy, R_galaxy) galaxy=new_plummer_model(10000,convert_nbody=converter) print "com:", galaxy.center_of_mass().in_(units.kpc) print "comv:", galaxy.center_of_mass_velocity().in_(units.kms) print len(galaxy) galaxy_code = BHTree(converter, number_of_workers=2) galaxy_code.parameters.epsilon_squared = (0.01 | units.kpc)**2 channe_to_galaxy = galaxy_code.particles.new_channel_to(galaxy) channe_to_galaxy.copy() galaxy_code.particles.add_particles(galaxy) inner_stars = galaxy.select(lambda r: r.length()<Rinit,["position"]) Minner = inner_stars.mass.sum() print "Minner=", Minner.in_(units.MSun) print "Ninner=", len(inner_stars) vc_inner = (constants.G*Minner/Rinit).sqrt() converter=nbody_system.nbody_to_si(Mcluster,Rcluster) stars=new_king_model(N,W0,convert_nbody=converter) masses = new_powerlaw_mass_distribution(N, 0.1|units.MSun, 100|units.MSun, -2.35) stars.mass = masses stars.scale_to_standard(converter) stars.x += Rinit stars.vy += 0.8*vc_inner cluster_code=ph4(converter, number_of_workers=2) cluster_code.particles.add_particles(stars) channel_to_stars=cluster_code.particles.new_channel_to(stars) system=bridge(verbose=False) system.add_system(cluster_code, (galaxy_code,)) system.add_system(galaxy_code, (cluster_code,)) system.timestep = 0.1*timestep times = quantities.arange(0|units.Myr, tend, timestep) for i,t in enumerate(times): print "Time=", t.in_(units.Myr) channe_to_galaxy.copy() channel_to_stars.copy() inner_stars = galaxy.select(lambda r: r.length()<Rinit,["position"]) print "Minner=", inner_stars.mass.sum().in_(units.MSun) system.evolve_model(t,timestep=timestep) plot_galaxy_and_stars(galaxy, stars) galaxy_code.stop() cluster_code.stop()
def king_model_cluster(interface,N=1024,W0=3, Mcluster=4.e4 | units.MSun, Rcluster= .7 | units.parsec,parameters=[]): converter=nbody_system.nbody_to_si(Mcluster,Rcluster) parts=new_king_model(N,W0,convert_nbody=converter) parts.radius=0.0| units.parsec nb=interface(converter) for name,value in parameters: setattr(nb.parameters, name, value) nb.particles.add_particles(parts) return nb
def generate_cluster(): m = new_kroupa_mass_distribution(N, kroupa_max) tot_m = np.sum(m) converter = nbody_system.nbody_to_si(tot_m, Rcluster) bodies = new_king_model(N, W0, convert_nbody=converter) bodies.mass = m bodies.scale_to_standard(convert_nbody=converter) bodies.move_to_center() code = ph4(converter, mode='gpu') parameters = {'epsilon_squared': (softening)**2} for name, value in parameters.items(): setattr(code.parameters, name, value) code.particles.add_particles(bodies) return code
def king_model_cluster(interface, N=1024, W0=3, Mcluster=4.e4 | units.MSun, Rcluster=.7 | units.parsec, parameters=[]): """ helper function to setup an nbody king model cluster (returns code with particles) """ converter = nbody_system.nbody_to_si(Mcluster, Rcluster) parts = new_king_model(N, W0, convert_nbody=converter) parts.radius = 0.0 | units.parsec nb = interface(converter) for name, value in parameters: setattr(nb.parameters, name, value) nb.particles.add_particles(parts) return nb
def __init__(self, name, Mtot=(1e15 | units.MSun), Rvir=(500 | units.kpc), Ndm=1e2, Ngas=1e3): self.name = name self.converter = nbody_system.nbody_to_si(Mtot, Rvir) self.Mtot = Mtot self.Rvir = Rvir self.Ndm = int(Ndm) self.Ngas = int(Ngas) # Set up numerical smoothing fractions. self.dm_smoothing_fraction = 0.001 self.gas_smoothing_fraction = 0.05 self.dm_epsilon = self.dm_smoothing_fraction * self.Rvir self.gas_epsilon = self.gas_smoothing_fraction * self.Rvir # Set up gas and dark matter fractions and gas/dm mass. self.gas_fraction = 0.1 self.dm_fraction = 1.0 - self.gas_fraction self.dm_mass = self.dm_fraction * self.Mtot self.gas_mass = self.gas_fraction * self.Mtot # Set up King Sphere for the gas # Second parameter W0: Dimension-less depth of the King potential W0 = 3 self.gas = new_king_model(self.Ngas, W0, convert_nbody=self.converter) self.gas.h_smooth = self.gas_epsilon self.gas.mass = (1.0 / self.Ngas) * self.gas_mass self.gas.move_to_center() # Set up NFW profile for the Dark Matter (TODO: now plummer sphere!) self.dm = new_plummer_model(self.Ndm, convert_nbody=self.converter) self.dm.radius = self.dm_epsilon self.dm.mass = (1.0 / self.Ndm) * self.dm_mass self.dm.move_to_center() print "Succesfuly created a Sub Cluster with the following properties" print self print self.gas
def test1(self): convert = nbody_system.nbody_to_si(1.e5 | units.MSun, 1.0 | units.parsec) eps = 2.e-4 | nbody_system.length test_class = PhiGRAPE number_of_particles = 50 stars = new_king_model(number_of_particles, W0=7, convert_nbody=convert) stars.radius = 0.0 | units.RSun cluster = test_class(convert) cluster.parameters.epsilon_squared = eps**2 cluster.particles.add_particles(stars) cluster.synchronize_model() Ep1 = convert.to_nbody(cluster.potential_energy).number Ek1 = convert.to_nbody(cluster.kinetic_energy).number parts = cluster.particles.copy() parts1 = parts.select_array(lambda x: (x > 0 | units.m), ['x']) parts2 = parts.select_array(lambda x: (x < 0 | units.m), ['x']) cluster1 = sys_from_parts(test_class, parts1, convert, eps) cluster2 = sys_from_parts(test_class, parts2, convert, eps) cluster1.synchronize_model() cluster2.synchronize_model() bridgesys = bridge() bridgesys.add_system(cluster1, (cluster2, )) bridgesys.add_system(cluster2, (cluster1, )) Ep2 = convert.to_nbody(bridgesys.potential_energy).number Ek2 = convert.to_nbody(bridgesys.kinetic_energy).number self.assertAlmostEqual(Ek1, Ek2, 12) self.assertAlmostEqual(Ep1, Ep2, 12)
def slowtest3(self): print "King models with varying King dimensionless depth W0." number_of_particles = 10 for w_0 in [1.0, 6.0, 11.0, 16.0]: particles = new_king_model(number_of_particles, W0=w_0) self.assertEquals(len(particles), number_of_particles)
from matplotlib import pyplot from amuse.ic.kingmodel import new_king_model if __name__ in ('__main__', '__plot__'): # set up parameters: N = 100 W0 = 3 Rinit = 50. | units.parsec timestep = 0.01 | units.Myr Mcluster = 4.e4 | units.MSun Rcluster = 0.7 | units.parsec converter = nbody_system.nbody_to_si(Mcluster,Rcluster) # create a globular cluster model particles = new_king_model(N, W0, convert_nbody=converter) particles.radius = 0.0| units.parsec cluster = PhiGRAPE(converter, parameters=[("epsilon_squared", (0.01 | units.parsec)**2)]) # create the external potential of the Galaxy galaxy = Agama(converter, type="Dehnen", gamma=1.8, \ rscale=1000.| units.parsec, mass=1.6e10 | units.MSun, channel_type='sockets') # shift the cluster to an orbit around Galactic center acc,_,_ = galaxy.get_gravity_at_point(0|units.kpc, Rinit, 0|units.kpc, 0|units.kpc) vcirc = (-acc * Rinit)**0.5 print "Vcirc=", vcirc.value_in(units.kms), "km/s" particles.x += Rinit particles.vy += vcirc cluster.particles.add_particles(particles)
def new_cluster(number_of_particles, W0, converter): particles = new_king_model(N, W0, convert_nbody=converter) particles.radius = 0.0 | units.parsec return particles
def sys_from_king(base_class, N, W, converter, eps=None, timestep=None, usegl=False, mode=None): parts = new_king_model(N, W0=W, convert_nbody=converter) parts.radius = 0. | nbody_system.length return sys_from_parts( base_class, parts, converter, eps, timestep, usegl, mode)
def slowtest3(self): print "King models with varying King dimensionless depth W0." number_of_particles = 10 for w_0 in [1.0, 6.0, 11.0, 16.0]: particles = new_king_model(number_of_particles, W0 = w_0) self.assertEquals(len(particles), number_of_particles)
def king_cluster_v2(num_stars, **kwargs): ''' Creates an open cluster according to the King Model & Kroupa IMF num_stars: The total number of stellar systems. w0: The King density parameter. vradius: The virial radius of the cluster. seed: The random seed used for cluster generation. do_binaries: Turn on/off binary creation. binary_recursions: The number of times a star is tested to be a binary. split_binaries: Turn on/off splitting Binary CoM into individual Companions. ''' # Check Keyword Arguments w0 = kwargs.get("w0", 2.5) virial_radius = kwargs.get("vradius", 2 | units.parsec) rand_seed = kwargs.get("seed", 7) do_binaries = kwargs.get("do_binaries", True) binary_recursions = kwargs.get("binary_recursions", 1) split_binaries = kwargs.get("split_binaries", True) # Check if rand_seed is a integer or not. Convert it if it isn't. if not type(rand_seed) == type(1): rand_seed = util.new_seed_from_string(rand_seed) # Apply the Seed for the Cluster rs = RandomState(MT19937(SeedSequence(rand_seed))) np.random.seed(rand_seed) random.seed(rand_seed) min_stellar_mass = 100 | units.MJupiter max_stellar_mass = 10 | units.MSun # Creates a List of Primary Masses (in SI Units) Drawn from the Kroupa IMF Masses_SI = util.new_truncated_kroupa(num_stars) # If Primordial Binaries are Desired, Start the Conversion Process if do_binaries: # Find Sutable CoM Objects to Turn into Binaries, Update the System # Mass, and record the CoM's Index to Remove it Later. Masses_SI, ids_to_become_binaries = find_possible_binaries_v2( Masses_SI, binary_recursions=binary_recursions) # Creates the SI-to-NBody Converter converter = nbody_system.nbody_to_si(Masses_SI.sum(), virial_radius) # Creates a AMUS Particle Set Consisting of Positions (King) and Masses (Kroupa) stars_SI = new_king_model(num_stars, w0, convert_nbody=converter) stars_SI.mass = Masses_SI # Assigning Type of System ('star' or 'primordial binary') stars_SI.type = "star" if do_binaries: for com_index in ids_to_become_binaries: stars_SI[com_index].type = "primordial binary" # Shifts Cluster's CoM to the Origin Before Scaling to Virial Equilibrium stars_SI.move_to_center() if num_stars == 1: pass else: stars_SI.scale_to_standard(convert_nbody=converter) # Assigning SOI Estimate for Interaction Radius if num_stars == 1: stars_SI.radius = 2000 * stars_SI.mass / (1.0 | units.MSun) | units.AU else: # Temporary Solution stars_SI.radius = 2000 * stars_SI.mass / (1.0 | units.MSun) | units.AU # Need to think of a better way to calculate the SOI # stars_SI.radius = 100*util.calc_SOI(stars_SI.mass, np.var(stars_SI.velocity), G=units.constants.G) # If Requested, Split Binary Systems into Seperate Particles if do_binaries: # Define the Binary Set binaries = Particles() singles_in_binaries = Particles() com_to_remove = Particles() # Create a Kepler Worker to Ensure the Binaries are Approaching BinaryConverter = nbody_system.nbody_to_si( 2 * np.mean(stars_SI.mass), 2 * np.mean(stars_SI.radius)) kep = Kepler(unit_converter=BinaryConverter, redirection='none') # Split the Binary into its Companions & Store in Seperate Sets for com_index in ids_to_become_binaries: stars_SI[com_index].id = com_index binary_particle, singles_in_binary = binary_system_v2( stars_SI[com_index], stars_SI, kepler_worker=kep) binaries.add_particle(binary_particle) singles_in_binaries.add_particle(singles_in_binary) com_to_remove.add_particle(stars_SI[com_index]) # If Desired, Remove the CoM and Replace it with the Single Companions. # Note: Default is to do this until we get multiples.py and encounters.py # to match functionality exactly plus Kira.py features. if split_binaries: stars_SI.remove_particles(com_to_remove) stars_SI.add_particles(singles_in_binaries) # Set Particle Ids for Easy Referencing stars_SI.id = np.arange(len(stars_SI)) + 1 # Final Radius Setting (Ensuring that the Interaction Distance is not Small) min_stellar_radius = 1000 | units.AU for star in stars_SI: if star.radius < min_stellar_radius: star.radius = min_stellar_radius # Return the Desired Particle Sets and Required Converter if do_binaries: kep.stop() return stars_SI, converter, binaries, singles_in_binaries else: return stars_SI, converter
def king_cluster(num_stars, **kwargs): ''' Creates an open cluster according to the King Model & Kroupa IMF num_stars: The total number of stellar systems. w0: The King density parameter. seed: The random seed used for cluster generation. num_binaries: The number of binary systems desired. ''' # Check Keyword Arguments w0 = kwargs.get("w0", 2.5) #rand_seed = int(str(kwargs.get("seed", 7)).encode('hex'), 32) rand_seed = util.new_seed_from_string(kwargs.get("seed", 7)) num_binaries = kwargs.get("num_binaries", int(num_stars*0.25)) # Apply the Seed for the Cluster np.random.seed(rand_seed) #rp.seed(rand_seed) # Creates a List of Primary Masses (in SI Units) Drawn from the Kroupa IMF SMasses_SI = new_kroupa_mass_distribution(num_stars, mass_max = 10 | units.MSun) # Creates a List of Binary Companion Masses (in SI_Units) Drawn from the Kroupa IMF BMasses_SI = new_kroupa_mass_distribution(num_binaries, mass_max = 10 | units.MSun) # Creates the SI-NBody Converter converter = nbody_system.nbody_to_si(SMasses_SI.sum()+BMasses_SI.sum(), 1 | units.parsec) # Creates a AMUS Particle Set Consisting of Positions (King) and Masses (Kroupa) stars_SI = new_king_model(num_stars, w0, convert_nbody=converter) stars_SI.mass = SMasses_SI #print stars_SI.mass.as_quantity_in(units.MSun) # Assigning IDs to the Stars stars_SI.id = np.arange(num_stars) + 1 stars_SI.type = "star" # If Requested, Search for Possible Binary Systems if int(num_binaries) != 0: # Search for all Stars Able to Become Binary Systems & Update stars_SI Masses for Correct Scaling stars_SI, stars_to_become_binaries = find_possible_binaries(stars_SI, num_binaries, BMasses_SI) # Update the Number of Binaries (Safety Check) num_binaries = len(stars_to_become_binaries) # Moving Stars to Virial Equilibrium stars_SI.move_to_center() if num_stars == 1: pass else: stars_SI.scale_to_standard(convert_nbody=converter) # Assigning SOI Estimate for Interaction Radius if num_stars == 1: stars_SI.radius = 2000*stars_SI.mass/(1.0 | units.MSun) | units.AU else: stars_SI.radius = 2000*stars_SI.mass/(1.0 | units.MSun) | units.AU # Temporary Solution # Need to think of a better way to calculate the SOI # stars_SI.radius = 100*util.calc_SOI(stars_SI.mass, np.var(stars_SI.velocity), G=units.constants.G) # If Requested, Creates Binary Systems if int(num_binaries) != 0: # Loop the Creation of Binary Systems binaries=Particles() for j in xrange(0, num_binaries): binaries.add_particles(binary_system(stars_to_become_binaries[j])) # Adjust the ID for each Binary Component Particle binaries.id = np.arange(num_binaries*2) + num_stars + 1 # Remove Old Place-Holder Particles stars_SI.remove_particles(stars_to_become_binaries) # Merge the Two Sets stars_SI.add_particles(binaries) # Fix the ID Problem stars_SI.id = np.arange(len(stars_SI.id)) + 1 # Final Radius Setting (Ensuring that the Interaction Distance is not Small) min_stellar_radius = 1000 | units.AU for star in stars_SI: if star.radius < min_stellar_radius: star.radius = min_stellar_radius # Returns the Cluster & Converter return stars_SI, converter
def king_cluster_v2(num_stars, **kwargs): ''' Creates an open cluster according to the King Model & Kroupa IMF num_stars: The total number of stellar systems. w0: The King density parameter. vradius: The virial radius of the cluster. seed: The random seed used for cluster generation. do_binaries: Turn on/off binary creation. binary_recursions: The number of times a star is tested to be a binary. split_binaries: Turn on/off splitting Binary CoM into individual Companions. ''' # Check Keyword Arguments w0 = kwargs.get("w0", 2.5) virial_radius = kwargs.get("vradius", 2 | units.parsec) rand_seed = util.new_seed_from_string(kwargs.get("seed", 7)) do_binaries = kwargs.get("do_binaries", True) binary_recursions = kwargs.get("binary_recursions", 1) split_binaries = kwargs.get("split_binaries", True) # Apply the Seed for the Cluster np.random.seed(rand_seed) min_stellar_mass = 100 | units.MJupiter max_stellar_mass = 10 | units.MSun # Creates a List of Primary Masses (in SI Units) Drawn from the Kroupa IMF Masses_SI = util.new_truncated_kroupa(num_stars) # If Primordial Binaries are Desired, Start the Conversion Process if do_binaries: # Find Sutable CoM Objects to Turn into Binaries, Update the System # Mass, and record the CoM's Index to Remove it Later. Masses_SI, ids_to_become_binaries = find_possible_binaries_v2(Masses_SI, binary_recursions = binary_recursions) # Creates the SI-to-NBody Converter converter = nbody_system.nbody_to_si(Masses_SI.sum(), virial_radius) # Creates a AMUS Particle Set Consisting of Positions (King) and Masses (Kroupa) stars_SI = new_king_model(num_stars, w0, convert_nbody=converter) stars_SI.mass = Masses_SI # Assigning Type of System ('star' or 'primordial binary') stars_SI.type = "star" if do_binaries: for com_index in ids_to_become_binaries: stars_SI[com_index].type = "primordial binary" # Shifts Cluster's CoM to the Origin Before Scaling to Virial Equilibrium stars_SI.move_to_center() if num_stars == 1: pass else: stars_SI.scale_to_standard(convert_nbody=converter) # Assigning SOI Estimate for Interaction Radius if num_stars == 1: stars_SI.radius = 2000*stars_SI.mass/(1.0 | units.MSun) | units.AU else: # Temporary Solution stars_SI.radius = 2000*stars_SI.mass/(1.0 | units.MSun) | units.AU # Need to think of a better way to calculate the SOI # stars_SI.radius = 100*util.calc_SOI(stars_SI.mass, np.var(stars_SI.velocity), G=units.constants.G) # If Requested, Split Binary Systems into Seperate Particles if do_binaries: # Define the Binary Set binaries = Particles() singles_in_binaries = Particles() com_to_remove = Particles() # Split the Binary into its Companions & Store in Seperate Sets for com_index in ids_to_become_binaries: stars_SI[com_index].id = com_index binary_particle, singles_in_binary = binary_system_v2(stars_SI[com_index]) binaries.add_particle(binary_particle) singles_in_binaries.add_particle(singles_in_binary) com_to_remove.add_particle(stars_SI[com_index]) # If Desired, Remove the CoM and Replace it with the Single Companions. # Note: Default is to do this until we get multiples.py and encounters.py # to match functionality exactly plus Kira.py features. if split_binaries: stars_SI.remove_particles(com_to_remove) stars_SI.add_particles(singles_in_binaries) # Set Particle Ids for Easy Referencing stars_SI.id = np.arange(len(stars_SI)) + 1 # Final Radius Setting (Ensuring that the Interaction Distance is not Small) min_stellar_radius = 1000 | units.AU for star in stars_SI: if star.radius < min_stellar_radius: star.radius = min_stellar_radius # Return the Desired Particle Sets and Required Converter if do_binaries: return stars_SI, converter, binaries, singles_in_binaries else: return stars_SI, converter
def make_king_model_cluster(r_init, phi_init, z_init, vr_init, vphi_init, vz_init, W0, Mcluster, star_masses, radius, Mgalaxy, Rgalaxy, code_name, parameters=[]): ''' sets up a cluster with mass M and radius R which nbodycode would you like to use? ''' converter = nbody_system.nbody_to_si(star_masses.sum(), radius | units.parsec) bodies = new_king_model(len(star_masses), W0, convert_nbody=converter) bodies.mass = star_masses ''' takes in R, Z value returns VR, Vphi, VZ values should get appropriate 6D initial phase space conditions ''' #convert from galpy/cylindrical to AMUSE/Cartesian units x_init = r_init * np.cos(phi_init) | units.kpc y_init = r_init * np.sin(phi_init) | units.kpc z_init = z_init | units.kpc #vphi = R \dot{\phi}? assuming yes for now vx_init = (vr_init * np.cos(phi_init) - vphi_init * np.sin(phi_init)) | units.kms vy_init = (vr_init * np.sin(phi_init) + vphi_init * np.cos(phi_init)) | units.kms vz_init = vz_init | units.kms pos_vec, vel_vec = (x_init, y_init, z_init), (vx_init, vy_init, vz_init) #initializing phase space coordinates bodies.x += x_init bodies.y += y_init bodies.z += z_init bodies.vx += vx_init bodies.vy += vy_init bodies.vz += vz_init #sub_worker in Nemesis if code_name == 'Nbody': code = Hermite(converter) code.particles.add_particles(bodies) code.commit_particles() if code_name == 'tree': code = BHTree(converter) code.particles.add_particles(bodies) code.commit_particles() return bodies, code
def Create_King_Cluster(number_of_stars, number_of_binaries, w, write_file=True, cluster_name=None): """ This is a function created to create a King's Model Cluster and write the HDF5 File if requested. The Function Returns: The Set of Stars, AMUSE Nbody Converter, Cluster Name, & King's Model W0 Value """ # Creates a List of Masses Drawn from the Salpeter Mass Distribution & Prints the Total Mass salpeter_masses = new_salpeter_mass_distribution(number_of_stars, mass_max = (15 | units.MSun)) total_mass = salpeter_masses.sum() print "Total Mass of the Cluster:", total_mass.value_in(units.MSun), "Solar Masses" # This converter is set so that [1 mass = Cluster's Total Mass] & [1 length = 1 parsec]. converter = nbody_system.nbody_to_si(total_mass, 1 | units.parsec) # Creates a AMUSE Particle Set Consisting of Stars from the King Model & Sets Their Masses stars = new_king_model(number_of_stars, w) stars.mass = converter.to_nbody(salpeter_masses) #stars.radius = stars.mass.number | nbody_system.length stars.radius = converter.to_nbody(1000 | units.AU) stars.id = np.arange(number_of_stars) + 1 # Moving Stars to Virial Equilibrium stars.move_to_center() if number_of_stars == 1: pass else: stars.scale_to_standard() # Creates the AMUSE Paricle set for the Binaries binaries = Particles() # Selects the Indices of Stars that will be converted to Binaries select_stars_indices_for_binaries = random.sample(xrange(0, number_of_stars), number_of_binaries) select_stars_indices_for_binaries.sort() delete_star_indices = [] # Creates a decending list of Star Indicies to make deletion easier. for y in xrange(0, number_of_binaries): delete_star_indices.append(select_stars_indices_for_binaries[(number_of_binaries-1)-y]) # Creates the Binaries and assigns IDs for j in xrange(0, number_of_binaries): q = select_stars_indices_for_binaries[j] binaries.add_particles(makeBinary(stars[q], converter)) binaries.id = np.arange(number_of_binaries*2) + 2000000 # Deletes the Stars that were converted to Binaries for k in xrange(0, number_of_binaries): b = delete_star_indices[k] stars.remove_particle(stars[b]) # Adds in the Binaries to the Master Particle set stars.add_particle(binaries) # Assigns a Name to the Cluster if Not Provided if cluster_name == None: cluster_name = "OC"+tp.strftime("%y%m%d-%H%M%S", tp.gmtime()) # Optionally Write the Cluster to a File if write_file: file_format = "hdf5" # Generates a File Name Given the Cluster Name file_name = "kingcluster_%s_w%.2f_N%i_M%.6f.%s" %(cluster_name, w, number_of_stars, total_mass.value_in(units.MSun), file_format) # Sets the File Path and Writes the Particle Set to a hdf5 File file_dir = os.getcwd()+"/Clusters" if not os.path.exists(file_dir): os.makedirs(file_dir) file_path = file_dir+"/"+file_name write_set_to_file(stars, file_path, format=file_format, close_file=True) else: pass # Return the Particle Set of Stars and the Unit Converter return stars, converter, cluster_name, w
def new_star_cluster( stellar_mass=False, initial_mass_function="salpeter", upper_mass_limit=125. | units.MSun, lower_mass_limit=0.1 | units.MSun, number_of_stars=1024, effective_radius=3.0 | units.parsec, star_distribution="plummer", star_distribution_w0=7.0, star_distribution_fd=2.0, star_metallicity=0.01, # initial_binary_fraction=0, **kwargs): """ Create stars. When using an IMF, either the stellar mass is fixed (within stochastic error) or the number of stars is fixed. When using equal-mass stars, both are fixed. """ imf_name = initial_mass_function.lower() if imf_name == "salpeter": from amuse.ic.salpeter import new_salpeter_mass_distribution initial_mass_function = new_salpeter_mass_distribution elif imf_name == "kroupa": from amuse.ic.brokenimf import new_kroupa_mass_distribution initial_mass_function = new_kroupa_mass_distribution elif imf_name == "flat": from amuse.ic.flatimf import new_flat_mass_distribution initial_mass_function = new_flat_mass_distribution elif imf_name == "fixed": from amuse.ic.flatimf import new_flat_mass_distribution def new_fixed_mass_distribution(number_of_particles, *list_arguments, **keyword_arguments): return new_flat_mass_distribution( number_of_particles, mass_min=stellar_mass / number_of_stars, mass_max=stellar_mass / number_of_stars, ) initial_mass_function = new_fixed_mass_distribution if stellar_mass: # Add stars to cluster, until mass limit reached (inclusive!) mass = initial_mass_function( 0, mass_min=lower_mass_limit, mass_max=upper_mass_limit, ) while mass.sum() < stellar_mass: mass.append( initial_mass_function( 1, mass_min=lower_mass_limit, mass_max=upper_mass_limit, )[0]) total_mass = mass.sum() number_of_stars = len(mass) else: # Give stars their mass mass = initial_mass_function( number_of_stars, mass_min=lower_mass_limit, mass_max=upper_mass_limit, ) total_mass = mass.sum() converter = generic_unit_converter.ConvertBetweenGenericAndSiUnits( total_mass, 1. | units.kms, effective_radius, ) # Give stars a position and velocity, based on the distribution model. if star_distribution == "plummer": stars = new_plummer_sphere( number_of_stars, convert_nbody=converter, ) elif star_distribution == "king": stars = new_king_model( number_of_stars, star_distribution_w0, convert_nbody=converter, ) elif star_distribution == "fractal": stars = new_fractal_cluster_model( number_of_stars, fractal_dimension=star_distribution_fd, convert_nbody=converter, ) else: return -1, "No stellar distribution" # set the stellar mass. stars.mass = mass # set other stellar parameters. stars.metallicity = star_metallicity # Virialize the star cluster if > 1 star if len(stars) > 1: stars.move_to_center() stars.scale_to_standard( convert_nbody=converter, # virial_ratio=virial_ratio, # smoothing_length_squared= ..., ) # Record the cluster's initial parameters to the particle distribution stars.collection_attributes.initial_mass_function = imf_name stars.collection_attributes.upper_mass_limit = upper_mass_limit stars.collection_attributes.lower_mass_limit = lower_mass_limit stars.collection_attributes.number_of_stars = number_of_stars stars.collection_attributes.effective_radius = effective_radius stars.collection_attributes.star_distribution = star_distribution stars.collection_attributes.star_distribution_w0 = star_distribution_w0 stars.collection_attributes.star_distribution_fd = star_distribution_fd stars.collection_attributes.star_metallicity = star_metallicity # Derived/legacy values stars.collection_attributes.converter_mass = \ converter.to_si(1 | nbody_system.mass) stars.collection_attributes.converter_length =\ converter.to_si(1 | nbody_system.length) stars.collection_attributes.converter_speed =\ converter.to_si(1 | nbody_system.speed) return stars