def test5(self): print("Testing SinkParticles accrete, one particle within two sinks' radii") particles = Particles(10) particles.radius = 42.0 | units.RSun particles.mass = list(range(1,11)) | units.MSun particles.position = [[i, 2*i, 3*i] for i in range(10)] | units.parsec particles.velocity = [[i, 0, -i] for i in range(10)] | units.km/units.s particles.age = list(range(10)) | units.Myr copy = particles.copy() sinks = SinkParticles(particles[[3, 7]], sink_radius=[4,12]|units.parsec,looping_over=self.looping_over) self.assertEqual(sinks.sink_radius, [4.0, 12.0] | units.parsec) self.assertEqual(sinks.mass, [4.0, 8.0] | units.MSun) self.assertEqual(sinks.position, [[3, 6, 9], [7, 14, 21]] | units.parsec) sinks.accrete(particles) self.assertEqual(len(particles), 4) # 6 particles were accreted self.assertEqual(sinks.mass, [12.0, 40.0] | units.MSun) # mass of sinks increased self.assertEqual(sinks.get_intersecting_subset_in(particles).mass, [12.0, 40.0] | units.MSun) # original particles' masses match self.assertEqual(particles.total_mass(), copy.total_mass()) # total mass is conserved self.assertEqual(particles.center_of_mass(), copy.center_of_mass()) # center of mass is conserved self.assertEqual(particles.center_of_mass_velocity(), copy.center_of_mass_velocity()) # center of mass velocity is conserved self.assertEqual(particles.total_momentum(), copy.total_momentum()) # momentum is conserved self.assertEqual(particles.total_angular_momentum()+sinks.angular_momentum.sum(axis=0), copy.total_angular_momentum()) # angular_momentum is conserved
class comsystem(baseclass): def __init__(self, *args, **kwargs): self.particles_accessed = True self._particles = Particles(0) baseclass.__init__(self, *args, **kwargs) def evolve_model(self, *args, **kwargs): if self.particles_accessed: self.com_position = self._particles.center_of_mass() self.com_velocity = self._particles.center_of_mass_velocity() com_time = self.model_time self._particles.synchronize_to(self.overridden().particles) self._particles.new_channel_to( self.overridden().particles).copy_attributes( ["mass", "radius"]) self.overridden( ).particles.position = self._particles.position - self.com_position self.overridden( ).particles.velocity = self._particles.velocity - self.com_velocity self.overridden().evolve_model(*args, **kwargs) self.com_position += self.com_velocity * (self.model_time - com_time) self.particles_accessed = False @property def particles(self): if not self.particles_accessed: self._particles = self.overridden().particles.copy() self._particles.position += self.com_position self._particles.velocity += self.com_velocity self.particles_accessed = True return self._particles
class comsystem(baseclass): def __init__(self,*args,**kwargs): self.particles_accessed=True self._particles=Particles(0) baseclass.__init__(self,*args,**kwargs) def evolve_model(self,*args,**kwargs): if self.particles_accessed: self.com_position=self._particles.center_of_mass() self.com_velocity=self._particles.center_of_mass_velocity() com_time=self.model_time self._particles.synchronize_to(self.overridden().particles) self._particles.new_channel_to(self.overridden().particles).copy_attributes(["mass","radius"]) self.overridden().particles.position=self._particles.position-self.com_position self.overridden().particles.velocity=self._particles.velocity-self.com_velocity self.overridden().evolve_model(*args,**kwargs) self.com_position+=self.com_velocity*(self.model_time-com_time) self.particles_accessed=False @property def particles(self): if not self.particles_accessed: self._particles=self.overridden().particles.copy() self._particles.position+=self.com_position self._particles.velocity+=self.com_velocity self.particles_accessed=True return self._particles
def test10(self): particles = Particles(2) particles.position = [[1, 0, 0], [2,0,0]] | units.m particles.velocity = [[3, 0, 0], [4,0,0]] | units.m / units.s particles.mass = 1 | units.kg self.assertEquals(particles.total_mass(), 2 | units.kg) self.assertEquals(particles.total_momentum(), [7, 0, 0] | units.kg * units.m / units.s) self.assertEquals(particles.total_momentum(), particles.total_mass() * particles.center_of_mass_velocity()) self.assertEquals(particles.total_radius(), 0.5 | units.m) convert_nbody = nbody_system.nbody_to_si(1000 | units.kg, 1e-6 | units.m) numpy.random.seed(123) field = new_plummer_sphere(10000, convert_nbody) # small clump of particles, can be regarded as point mass self.assertAlmostRelativeEquals(particles.potential_energy_in_field(field), -constants.G * (1500 | units.kg**2 / units.m), 5) self.assertAlmostEquals(particles.potential_energy_in_field(field), -1.001142 | 1e-7 * units.kg * units.m**2 / units.s**2, 5) field.position *= ((5 | units.m) / field.position.lengths()).reshape((-1, 1)) # spherical shell around particles potential_energy = particles.potential_energy_in_field(field) particles.position += [0, 1, 2] | units.m # as long as particles remain inside the shell, the potential doesn't change self.assertAlmostEquals(particles.potential_energy_in_field(field), potential_energy, 5) particles.mass = [1, 2] | units.kg self.assertAlmostRelativeEquals(particles.potential(), -constants.G * ([2, 1] | units.kg / units.m)) self.assertAlmostRelativeEquals(particles.potential()[0], particles[0].potential()) self.assertAlmostRelativeEquals(particles.potential()[1], particles[1].potential())
def test5(self): print "Testing SinkParticles accrete, one particle within two sinks' radii" particles = Particles(10) particles.radius = 42.0 | units.RSun particles.mass = range(1,11) | units.MSun particles.position = [[i, 2*i, 3*i] for i in range(10)] | units.parsec particles.velocity = [[i, 0, -i] for i in range(10)] | units.km/units.s particles.age = range(10) | units.Myr copy = particles.copy() sinks = SinkParticles(particles[[3, 7]], sink_radius=[4,12]|units.parsec,looping_over=self.looping_over) self.assertEqual(sinks.sink_radius, [4.0, 12.0] | units.parsec) self.assertEqual(sinks.mass, [4.0, 8.0] | units.MSun) self.assertEqual(sinks.position, [[3, 6, 9], [7, 14, 21]] | units.parsec) sinks.accrete(particles) self.assertEqual(len(particles), 4) # 6 particles were accreted self.assertEqual(sinks.mass, [12.0, 40.0] | units.MSun) # mass of sinks increased self.assertEqual(sinks.get_intersecting_subset_in(particles).mass, [12.0, 40.0] | units.MSun) # original particles' masses match self.assertEqual(particles.total_mass(), copy.total_mass()) # total mass is conserved self.assertEqual(particles.center_of_mass(), copy.center_of_mass()) # center of mass is conserved self.assertEqual(particles.center_of_mass_velocity(), copy.center_of_mass_velocity()) # center of mass velocity is conserved self.assertEqual(particles.total_momentum(), copy.total_momentum()) # momentum is conserved self.assertEqual(particles.total_angular_momentum()+sinks.angular_momentum.sum(axis=0), copy.total_angular_momentum()) # angular_momentum is conserved
def make_planets(central_particle, masses, radii, density=3 | units.g / units.cm**3, phi=None, theta=None, eccentricity=0.0, kepler=None, rng=None): volumes = masses / density planet_radii = (3.0 * volumes / (4.0 * numpy.pi))**(1.0 / 3.0) n = len(masses) planet_particles = Particles(n) planet_particles.semimajor_axis = radii if eccentricity is None: eccentricity = numpy.abs(rng.normal(-0.00001, 0.00001, n)) planet_particles.eccentricity = eccentricity planet_particles.mass = masses planet_particles.radius = planet_radii if phi is None: phi = numpy.radians(rng.uniform(0.0, 90.0, 1)[0]) #rotate under x if theta is None: theta0 = numpy.radians((rng.normal(-90.0, 90.0, 1)[0])) #rotate under y theta0 = 0 theta_inclination = numpy.radians(rng.normal(0, 1.0, n)) theta_inclination[0] = 0 theta = theta0 + theta_inclination #psi = numpy.radians(rng.uniform(0, 180, 1))[0] #0 # numpy.radians(90) # numpy.radians(rng.uniform(0, 180, 1))[0] psi = numpy.radians(rng.uniform(0.0, 180.0, 1))[ 0] #0 # numpy.radians(90) # numpy.radians(rng.uniform(0, 180, 1))[0] com_particle = central_particle.copy() for x, t in zip(iter(planet_particles), theta): pos, vel = posvel_from_orbital_elements(com_particle.mass + x.mass, x.semimajor_axis, x.eccentricity, kepler, rng) pos, vel = rotate(pos, vel, 0, 0, psi) # theta and phi in radians pos, vel = rotate(pos, vel, 0, t, 0) # theta and phi in radians pos, vel = rotate(pos, vel, phi, 0, 0) # theta and phi in radians x.position = pos + com_particle.position x.velocity = vel + com_particle.velocity if False: two_body = Particles(particles=[com_particle, x]) print "dp:", (com_particle.position - two_body.center_of_mass()).as_quantity_in(units.AU) com_particle.mass = two_body.mass.sum() com_particle.position = two_body.center_of_mass() com_particle.velocity = two_body.center_of_mass_velocity() #planet_particles.position += central_particle.position #planet_particles.velocity += central_particle.velocity return planet_particles
def merge_two_stars(primary, secondary): "Merge two colliding stars into one new one" colliders = Particles() colliders.add_particle(primary) colliders.add_particle(secondary) new_particle = Particle() new_particle.mass = colliders.mass.sum() new_particle.position = colliders.center_of_mass() new_particle.velocity = colliders.center_of_mass_velocity() return new_particle
def test1(self): colliders = Particles(2) colliders.mass = [5, 2] | units.kg colliders.position = [[0.0, 0.0, 0.0], [0.7, 1.4, -0.35]] | units.m colliders.velocity = [[0.4, -0.6, 0.0], [0.0, 0.0, -3.0]] | units.m / units.s self.assertAlmostEqual(colliders.center_of_mass_velocity().length(), 1.0 | units.m / units.s) merged = StickySpheres().handle_collision(colliders[0], colliders[1]) self.assertTrue(isinstance(merged, Particles)) self.assertEqual(merged.mass, 7 | units.kg) self.assertAlmostEqual(merged.position, [0.2, 0.4, -0.1] | units.m) self.assertAlmostEqual(merged.velocity, ([2.0, -3.0, -6.0] | units.m / units.s) / 7.0) self.assertAlmostEqual(merged.velocity.length(), 1.0 | units.m / units.s) copy = colliders.copy() copy.move_to_center() self.assertAlmostEqual(colliders.kinetic_energy(), merged.as_set().kinetic_energy() + copy.kinetic_energy())
def test1(self): colliders = Particles(2) colliders.mass = [5, 2] | units.kg colliders.position = [[0.0, 0.0, 0.0], [0.7, 1.4, -0.35]] | units.m colliders.velocity = [[0.4, -0.6, 0.0], [0.0, 0.0, -3.0]] | units.m / units.s self.assertAlmostEqual(colliders.center_of_mass_velocity().length(), 1.0 | units.m / units.s) merged = StickySpheres().handle_collision(colliders[0], colliders[1]) self.assertTrue(isinstance(merged, Particles)) self.assertEqual(merged.mass, 7 | units.kg) self.assertAlmostEqual(merged.position, [0.2, 0.4, -0.1] | units.m) self.assertAlmostEqual(merged.velocity, ([2.0, -3.0, -6.0] | units.m / units.s) / 7.0) self.assertAlmostEqual(merged.velocity.length(), 1.0 | units.m / units.s) copy = colliders.copy() copy.move_to_center() self.assertAlmostEqual(colliders.kinetic_energy(), merged.as_set().kinetic_energy() + copy.kinetic_energy())
def test10(self): particles = Particles(2) particles.position = [[1, 0, 0], [2, 0, 0]] | units.m particles.velocity = [[3, 0, 0], [4, 0, 0]] | units.m / units.s particles.mass = 1 | units.kg self.assertEquals(particles.total_mass(), 2 | units.kg) self.assertEquals(particles.total_momentum(), [7, 0, 0] | units.kg * units.m / units.s) self.assertEquals( particles.total_momentum(), particles.total_mass() * particles.center_of_mass_velocity()) self.assertEquals(particles.total_radius(), 0.5 | units.m) convert_nbody = nbody_system.nbody_to_si(1000 | units.kg, 1e-6 | units.m) numpy.random.seed(123) field = new_plummer_sphere( 10000, convert_nbody ) # small clump of particles, can be regarded as point mass self.assertAlmostRelativeEquals( particles.potential_energy_in_field(field), -constants.G * (1500 | units.kg**2 / units.m), 5) self.assertAlmostEquals( particles.potential_energy_in_field(field), -1.001142 | 1e-7 * units.kg * units.m**2 / units.s**2, 5) field.position *= ((5 | units.m) / field.position.lengths()).reshape( (-1, 1)) # spherical shell around particles potential_energy = particles.potential_energy_in_field(field) particles.position += [ 0, 1, 2 ] | units.m # as long as particles remain inside the shell, the potential doesn't change self.assertAlmostEquals(particles.potential_energy_in_field(field), potential_energy, 5) particles.mass = [1, 2] | units.kg self.assertAlmostRelativeEquals( particles.potential(), -constants.G * ([2, 1] | units.kg / units.m)) self.assertAlmostRelativeEquals(particles.potential()[0], particles[0].potential()) self.assertAlmostRelativeEquals(particles.potential()[1], particles[1].potential())
def make_planets(central_particle, masses, radii, density = 3 | units.g/units.cm**3, phi=None, theta=None, eccentricity = 0.0, kepler = None, rng = None): volumes = masses / density planet_radii = (3.0 * volumes / (4.0 * numpy.pi))**(1.0/3.0) n = len(masses) planet_particles = Particles(n) planet_particles.semimajor_axis = radii if eccentricity is None: eccentricity = numpy.abs(rng.normal(-0.00001,0.00001,n)) planet_particles.eccentricity = eccentricity planet_particles.mass = masses planet_particles.radius = planet_radii if phi is None: phi = numpy.radians(rng.uniform(0.0, 90.0, 1)[0])#rotate under x if theta is None: theta0 = numpy.radians((rng.normal(-90.0,90.0,1)[0]))#rotate under y theta0 = 0 theta_inclination = numpy.radians(rng.normal(0, 1.0, n )) theta_inclination[0] = 0 theta = theta0 + theta_inclination #psi = numpy.radians(rng.uniform(0, 180, 1))[0] #0 # numpy.radians(90) # numpy.radians(rng.uniform(0, 180, 1))[0] psi = numpy.radians(rng.uniform(0.0, 180.0, 1))[0] #0 # numpy.radians(90) # numpy.radians(rng.uniform(0, 180, 1))[0] com_particle = central_particle.copy() for x, t in zip(iter(planet_particles), theta): pos,vel = posvel_from_orbital_elements(com_particle.mass + x.mass, x.semimajor_axis, x.eccentricity, kepler, rng) pos,vel = rotate(pos, vel, 0, 0, psi) # theta and phi in radians pos,vel = rotate(pos, vel, 0, t, 0) # theta and phi in radians pos,vel = rotate(pos, vel, phi, 0, 0) # theta and phi in radians x.position = pos + com_particle.position x.velocity = vel + com_particle.velocity if False: two_body = Particles(particles=[com_particle, x]) print "dp:", (com_particle.position - two_body.center_of_mass()).as_quantity_in(units.AU) com_particle.mass = two_body.mass.sum() com_particle.position = two_body.center_of_mass() com_particle.velocity = two_body.center_of_mass_velocity() #planet_particles.position += central_particle.position #planet_particles.velocity += central_particle.velocity return planet_particles