Exemplo n.º 1
0
def generate_binaries(primary_mass,
                      secondary_mass,
                      semi_major_axis,
                      eccentricity=0 | units.rad,
                      true_anomaly=0 | units.rad,
                      inclination=0 | units.rad,
                      longitude_of_the_ascending_node=0 | units.rad,
                      argument_of_periapsis=0 | units.rad,
                      G=nbody_system.G):
    """
    returns two particlesets, which contain the primaries and the secondaries
    in binary pairs.
    """
    mass_unit = primary_mass.unit
    try:
        number_of_primaries = len(primary_mass)
    except:
        number_of_primaries = 1
        primary_mass = numpy.array([primary_mass.value_in(mass_unit)
                                    ]) | mass_unit
    try:
        number_of_secondaries = len(secondary_mass)
    except:
        number_of_secondaries = 1
        secondary_mass = numpy.array([secondary_mass.value_in(mass_unit)
                                      ]) | mass_unit

    # mass arrays need to be the same length
    if number_of_secondaries != number_of_primaries:
        raise Exception("The number of primaries is not the same as the number\
                of secondaries, this is not supported.")

    position_vector, velocity_vector = rel_posvel_arrays_from_orbital_elements(
        primary_mass,
        secondary_mass,
        semi_major_axis,
        eccentricity=eccentricity,
        true_anomaly=true_anomaly,
        inclination=inclination,
        longitude_of_the_ascending_node=longitude_of_the_ascending_node,
        argument_of_periapsis=argument_of_periapsis,
        G=G)
    number_of_primaries

    primaries = Particles(number_of_primaries)
    secondaries = Particles(number_of_secondaries)
    primaries.mass = primary_mass
    secondaries.mass = secondary_mass

    centers_of_mass = center_of_mass_array(position_vector, primary_mass,
                                           secondary_mass)
    centers_of_mass_velocity = center_of_mass_array(velocity_vector,
                                                    primary_mass,
                                                    secondary_mass)

    primaries.position = -centers_of_mass
    secondaries.position = position_vector - centers_of_mass
    primaries.velocity = -centers_of_mass_velocity
    secondaries.velocity = velocity_vector - centers_of_mass_velocity
    return primaries, secondaries
Exemplo n.º 2
0
 def test13(self):
     print "Test box_counting_dimension"
     # Particles distributed uniformly in 3D
     particles = Particles(4096)
     particles.position = numpy.mgrid[0:16.0, 0:16.0, 0:16.0].reshape(3, -1).transpose() | units.m
     dimension = particles.box_counting_dimension()
     self.assertAlmostRelativeEquals(dimension, 3.0, 1)
     # Fractal dimension is scale-free
     particles.position *= 1000
     self.assertAlmostRelativeEquals(dimension, particles.box_counting_dimension(), 10)
     
     # Particles distributed in the x-y plane
     particles.position = numpy.concatenate((numpy.mgrid[0:64.0, 0:64.0].reshape(2, -1), numpy.zeros((1, 4096)))).transpose() | units.m
     dimension = particles.box_counting_dimension()
     self.assertAlmostRelativeEquals(dimension, 2.0, 1)
     particles.position *= 1000
     self.assertAlmostRelativeEquals(dimension, particles.box_counting_dimension(), 10)
     
     # Particles distributed along a line
     particles.position = numpy.concatenate([numpy.arange(4096.0).reshape(1, -1)]*3).transpose() | units.m
     dimension = particles.box_counting_dimension()
     self.assertAlmostRelativeEquals(dimension, 1.0, 1)
     particles.position *= 1000
     self.assertAlmostRelativeEquals(dimension, particles.box_counting_dimension(), 10)
     
     # Particles on a Koch curve
     x, y = self.new_koch_star(level=7)
     numpy.random.seed(123456)
     sel = numpy.random.randint(len(x), size=4096)
     particles.position = numpy.hstack((x[sel], y[sel], numpy.zeros(4096))) | units.m
     dimension = particles.box_counting_dimension()
     self.assertAlmostRelativeEquals(dimension, 1.26186, 1)
     particles.position *= 1000
     self.assertAlmostRelativeEquals(dimension, particles.box_counting_dimension(), 10)
Exemplo n.º 3
0
def get_inclined_disk(disk, 
                      incl_deg=0., 
                      omega_deg=0.,
                      lon_deg=0.):
  """
  rotate particles by inclination, longitude of ascending node, and argument of pericenter
  """
  
  incl = incl_deg * pi_180
  omega = omega_deg * pi_180
  longitude = lon_deg * pi_180
  
  # get rotation matrix
  a1 = ([numpy.cos(longitude), -numpy.sin(longitude), 0.0], 
        [numpy.sin(longitude), numpy.cos(longitude), 0.0], 
        [0.0, 0.0, 1.0])
  a2 = ([1.0, 0.0, 0.0], [0.0, numpy.cos(incl), -numpy.sin(incl)], [0.0, numpy.sin(incl), numpy.cos(incl)])
  a3 = ([numpy.cos(omega), -numpy.sin(omega), 0.0], [numpy.sin(omega), numpy.cos(omega), 0.0], [0.0, 0.0, 1.0])
  rot = numpy.dot(numpy.dot(a1,a2),a3)
  
  # reshape positions and velocity vectors
  pos = disk.position.value_in(units.kpc)
  vel = disk.velocity.value_in(units.kpc/units.Myr)
  
  # rotate
  pos_rot = (numpy.dot(rot, pos.T)).T | units.kpc
  vel_rot = (numpy.dot(rot, vel.T)).T | (units.kpc/units.Myr)
  
  inclined_disk = Particles(len(disk))
  inclined_disk.mass = disk.mass
  inclined_disk.position = pos_rot
  inclined_disk.velocity = vel_rot
  inclined_disk.id = disk.id
  
  return inclined_disk
Exemplo n.º 4
0
    def test24(self):
        test_results_path = self.get_path_to_results()
        output_file = os.path.join(test_results_path,
                                   "test24" + self.store_version() + ".hdf5")
        if os.path.exists(output_file):
            os.remove(output_file)

        particles = Particles(20)
        #~        particles = Particles(1000000) # For testing memory usage
        particles.mass = 1.0 | units.kg
        particles.position = [0.0, 0.0, 0.0] | units.m

        for i in range(10):
            particles.position += [1.0, 2.0, 3.0] | units.m
            io.write_set_to_file(particles,
                                 output_file,
                                 format='amuse',
                                 version=self.store_version(),
                                 append_to_file=True)

        particles_from_file = io.read_set_from_file(
            output_file, format='amuse', version=self.store_version())
        os.remove(output_file)
        self.assertEqual(len(list(particles_from_file.history)), 10)
        for i, snap in enumerate(particles_from_file.history):
            self.assertEqual(len(snap), 20)
            self.assertEqual((i + 1) * ([1.0, 2.0, 3.0] | units.m),
                             snap.center_of_mass())
Exemplo n.º 5
0
    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
Exemplo n.º 6
0
 def test4(self):
     print "Testing Adaptb evolve_model, 2 particles"
     particles = Particles(2)
     particles.mass = 0.5 | units.MSun
     particles.radius = 1.0 | units.RSun
     particles.position = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]] | units.AU
     particles.velocity = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] | units.km / units.s
     particles[1].vy = (constants.G * (1.0 | units.MSun) / (1.0 | units.AU)).sqrt()
     particles.move_to_center()
     
     convert_nbody = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.AU)
     instance = self.new_instance_of_an_optional_code(Adaptb, convert_nbody)
     instance.initialize_code()
     instance.parameters.dt_print = 0.1 | units.yr
     instance.parameters.bs_tolerance = 1.0e-8
     instance.commit_parameters()
     instance.particles.add_particles(particles)
     instance.commit_particles()
     primary = instance.particles[0]
     
     P = 2 * math.pi * primary.x / primary.vy
     
     position_at_start = primary.position.x
     instance.evolve_model(P / 4.0)
     self.assertAlmostRelativeEqual(position_at_start, primary.position.y, 6)
     
     instance.evolve_model(P / 2.0)
     self.assertAlmostRelativeEqual(position_at_start, -primary.position.x, 6)
     
     instance.evolve_model(P)
     self.assertAlmostRelativeEqual(position_at_start, primary.position.x, 6)
     
     instance.cleanup_code()
     instance.stop()
Exemplo n.º 7
0
    def test3(self):
        self.assertRaises(
            AmuseException,
            StickySpheres,
            mass_loss=-0.1,
            expected_message="Mass-loss fraction must be in the range [0, 1)")
        self.assertRaises(
            AmuseException,
            StickySpheres,
            mass_loss=1.0,
            expected_message="Mass-loss fraction must be in the range [0, 1)")

        particles = Particles(6)
        particles.mass = range(1, 7) | units.kg
        particles.position = [[i, 1.0, 2.0] for i in range(1, 7)] | units.m
        particles.velocity = [[1.0, 0.0, 1.0], [0.0, -1.0, -1.0]
                              ] | units.m / units.s

        for fraction in [0.01, 0.1, 0.5]:
            sticky_spheres = StickySpheres(mass_loss=fraction)
            for i in range(0, 6, 2):
                colliders = particles[i:i + 2]
                merged = sticky_spheres.handle_collision(
                    colliders[0], colliders[1])
                self.assertTrue(isinstance(merged, Particles))
                self.assertAlmostEqual(merged.mass, (2 * i + 3.0) *
                                       (1 - fraction) | units.kg)
                self.assertAlmostEqual(merged.position,
                                       [((i + 1)**2 + (i + 2)**2) /
                                        (2 * i + 3.0), 1.0, 2.0] | units.m)
                self.assertAlmostEqual(
                    merged.velocity,
                    ([i + 1, -(i + 2), -1.0] | units.m / units.s) /
                    (2 * i + 3.0))
Exemplo n.º 8
0
def set_up_initial_conditions(orbital_period, kinetic_to_potential_ratio):
    print("Setting up initial conditions")
    stars = Particles(2)
    stars.mass = [10.0, 1.0] | units.MSun
    stars.radius = 0 | units.RSun
    stars.position = [0.0, 0.0, 0.0] | units.AU
    stars.velocity = [0.0, 0.0, 0.0] | units.km / units.s

    print("Binary with masses: " + str(stars.mass) +
          ", and orbital period: ", orbital_period)
    semimajor_axis = ((constants.G * stars.total_mass() *
                       (orbital_period / (2 * pi))**2.0)**(1.0 / 3.0))
    separation = 2 * semimajor_axis * (1 - kinetic_to_potential_ratio)
    print("Initial separation:", separation.as_quantity_in(units.AU))
    relative_velocity = (
        (kinetic_to_potential_ratio / (1.0 - kinetic_to_potential_ratio))
        * constants.G * stars.total_mass() / semimajor_axis
    ).sqrt()
    print("Initial relative velocity:",
          relative_velocity.as_quantity_in(units.km / units.s))

    stars[0].x = separation
    stars[0].vy = relative_velocity
    stars.move_to_center()
    return stars
 def result(self):
     masses, position_vectors, velocity_vectors = self.new_model()
     result = Particles(self.targetN)
     result.mass = masses
     result.position = position_vectors
     result.velocity = velocity_vectors
     return result
Exemplo n.º 10
0
    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
Exemplo n.º 11
0
def make_galaxies():
    if os.path.exists('disk_galactICs.amuse'):
        galaxy1 = read_set_from_file('disk_galactICs.amuse', 'amuse')
    else:
        halo_number_of_particles = NHALO
        converter = nbody_system.nbody_to_si(1.0e9 | units.MSun,
                                             1. | units.kpc)
        galaxy1 = new_galactics_model(halo_number_of_particles,
                                      disk_number_of_particles=NDISK,
                                      generate_bulge_flag=False,
                                      unit_system_converter=converter,
                                      disk_random_seed=12345)
        write_set_to_file(galaxy1, 'disk_galactICs.amuse', 'amuse')

    galaxy2 = Particles(len(galaxy1))
    galaxy2.mass = galaxy1.mass
    galaxy2.position = galaxy1.position
    galaxy2.velocity = galaxy1.velocity

    galaxy1.rotate(0.0, numpy.pi / 4, 0.0)
    galaxy2.rotate(numpy.pi / 6, 0.0, 0.0)
    galaxy1.position += [100.0, 0, 0] | units.kpc
    galaxy2.position -= [100.0, 0, 0] | units.kpc
    galaxy1.velocity += [0.0, 50.0, 0] | units.km / units.s
    galaxy2.velocity -= [0.0, 50.0, 0] | units.km / units.s
    return galaxy1, galaxy2
Exemplo n.º 12
0
 def test4(self):
     print "Testing Pikachu evolve_model, 2 particles"
     particles = Particles(2)
     particles.mass = 1.0 | units.MSun
     particles.radius = 1.0 | units.RSun
     particles.position = [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]] | units.AU
     particles.velocity = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] | units.km / units.s
     particles[1].vy = (constants.G * (2.0 | units.MSun) / (2.0 | units.AU)).sqrt()
     particles.move_to_center()
     
     converter = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.AU)
     instance = self.new_instance_of_an_optional_code(Pikachu, converter, **default_options)
     instance.initialize_code()
     instance.parameters.timestep = 0.0125 * math.pi * particles[0].x / particles[0].vy
     instance.parameters.rcut_out_star_star = 10.0 | units.AU
     instance.commit_parameters()
     instance.particles.add_particles(particles)
     instance.commit_particles()
     primary = instance.particles[0]
     
     P = 2 * math.pi * primary.x / primary.vy
     
     position_at_start = primary.position.x
     instance.evolve_model(P / 4.0)
     self.assertAlmostRelativeEqual(position_at_start, primary.position.y, 3)
     
     instance.evolve_model(P / 2.0)
     self.assertAlmostRelativeEqual(position_at_start, -primary.position.x, 3)
     
     instance.evolve_model(P)
     self.assertAlmostRelativeEqual(position_at_start, primary.position.x, 3)
     
     instance.cleanup_code()
     instance.stop()
Exemplo n.º 13
0
    def test25(self):
        test_results_path = self.get_path_to_results()
        output_file = os.path.join(test_results_path,
                                   "test25" + self.store_version() + ".hdf5")
        if os.path.exists(output_file):
            os.remove(output_file)

        particles = Particles(20)
        #~        particles = Particles(1000000) # For testing memory usage
        particles.mass = 1.0 | units.kg
        particles.position = [0.0, 0.0, 0.0] | units.m

        for i in range(10):
            particles.position += [1.0, 2.0, 3.0] | units.m
            io.write_set_to_file(particles,
                                 output_file,
                                 format='amuse',
                                 version=self.store_version())

        particles_from_file = io.read_set_from_file(
            output_file,
            format='amuse',
            version=self.store_version(),
            copy_history=True,
            close_file=True)

        history = list(particles_from_file.history)
        self.assertEqual(len(history), 10)
        self.assertFalse(
            "HDF" in str(type(history[1]._private.attribute_storage)))
        for i, snap in enumerate(particles_from_file.history):
            self.assertEqual(len(snap), 20)
            self.assertEqual((i + 1) * ([1.0, 2.0, 3.0] | units.m),
                             snap.center_of_mass())
        os.remove(output_file)
Exemplo n.º 14
0
 def new_sun_earth_system(self):
     particles = Particles(2)
     particles.mass = [1.0, 3.0037e-6] | units.MSun
     particles.position = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]] | units.AU
     particles.velocity = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] | units.km / units.s
     particles[1].vy = (constants.G * particles.total_mass() / (1.0 | units.AU)).sqrt()
     return particles
Exemplo n.º 15
0
def make_galaxies():
    # File 'disk_galactICs.amuse' contains 30k particles, (10k disk, no bulge, 20k halo)
    if os.path.exists('disk_galactICs.amuse'):
        galaxy1 = read_set_from_file('disk_galactICs.amuse', 'amuse')
    else:
        halo_number_of_particles = 20000
        converter = generic_unit_converter.ConvertBetweenGenericAndSiUnits(
            constants.G, 1.0e12 | units.MSun, 50.0 | units.kpc)
        galaxy1 = new_galactics_model(halo_number_of_particles,
                                      disk_number_of_particles=10000,
                                      generate_bulge_flag=False,
                                      do_scale=True,
                                      unit_system_converter=converter)
        write_set_to_file(galaxy1, 'disk_galactICs.amuse', 'amuse')

    galaxy2 = Particles(len(galaxy1))
    galaxy2.mass = galaxy1.mass
    galaxy2.position = galaxy1.position
    galaxy2.velocity = galaxy1.velocity

    galaxy1.rotate(0.0, numpy.pi / 4, 0.0)
    galaxy2.rotate(numpy.pi / 6, 0.0, 0.0)
    galaxy1.position += [100.0, 0, 0] | units.kpc
    galaxy2.position -= [100.0, 0, 0] | units.kpc
    galaxy1.velocity += [0.0, 50.0, 0] | units.km / units.s
    galaxy2.velocity -= [0.0, 50.0, 0] | units.km / units.s
    return galaxy1, galaxy2
Exemplo n.º 16
0
    def test7(self):
        instance = self.new_fastkick_instance()
        instance.parameters.epsilon_squared = 0.00001 | nbody_system.length**2
        
        particles = Particles(2)
        particles.mass = [1.0, 1.0] | nbody_system.mass
        particles.position = [[0.0,0.0,0.0], [2.0,0.0,0.0]] | nbody_system.length
        instance.particles.add_particles(particles)
        
        zero = 0.0 | nbody_system.length
        ax, ay, az = instance.get_gravity_at_point(zero, 1.0 | nbody_system.length, zero, zero)
        self.assertAlmostEqual(ax, 0.0 | nbody_system.acceleration, 6)
        self.assertAlmostEqual(ay, 0.0 | nbody_system.acceleration, 6)
        self.assertAlmostEqual(az, 0.0 | nbody_system.acceleration, 6)

        for x in (0.25, 0.5, 0.75):
            x0 = x | nbody_system.length
            x1 = (2.0 - x) | nbody_system.length
            potential0 = instance.get_potential_at_point(zero, x0, zero, zero)
            potential1 = instance.get_potential_at_point(zero, x1, zero, zero)
            ax0, ay0, az0 = instance.get_gravity_at_point(zero, x0, zero, zero)
            ax1, ay1, az1 = instance.get_gravity_at_point(zero, x1, zero, zero)
            
            self.assertAlmostEqual(ay0, 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(az0, 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(ay1, 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(az1, 0.0 | nbody_system.acceleration, 6)
            
            self.assertAlmostEqual(ax0, -ax1, 5)
            ax = (-1.0 / (x0**2) + 1.0 / (x1**2)) * (1.0 | nbody_system.length**3 / nbody_system.time**2)
            self.assertAlmostEqual(ax, ax0, 2)
            self.assertAlmostEqual(potential0, potential1, 5)
        instance.stop()
Exemplo n.º 17
0
    def test3(self):
        print("Testing SinkParticles initialization from existing particles in set")
        particles = Particles(10)
        self.assertRaises(AttributeError, SinkParticles, particles[[4, 7]], expected_message=
            "You tried to access attribute 'radius' but this attribute is not defined for this set.")
        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

        sinks = SinkParticles(particles[[4]])
        self.assertEqual(sinks.mass, 5.0 | units.MSun)
        self.assertEqual(sinks.sink_radius, 42.0 | units.RSun)
        self.assertEqual(sinks.radius, 42.0 | units.RSun)
        self.assertEqual(sinks.position, [4.0, 8.0, 12.0] | units.parsec)

        sinks = SinkParticles(particles[[4, 7]], sink_radius=[1,2]|units.AU)
        self.assertEqual(sinks.sink_radius, [1.0, 2.0] | units.AU)
        self.assertEqual(sinks.radius, 42.0 | units.RSun)
        self.assertEqual(sinks.mass, [5.0, 8.0] | units.MSun)
        self.assertEqual(sinks.position, [[4, 8, 12], [7, 14, 21]] | units.parsec)

        self.assertEqual(set(['key', 'mass', 'radius', 'x', 'y', 'z', 'sink_radius', 'vx','vy','vz','lx','ly','lz']),
            set(str(sinks).split("\n")[0].split()))
        self.assertEqual(set(['key', 'mass', 'radius', 'x', 'y', 'z']),
            set(str(particles).split("\n")[0].split()))
Exemplo n.º 18
0
    def test1(self):
        particles = Particles(2)
        particles.mass = [1.0, 1.0] | nbody_system.mass
        particles.radius = [0.0001, 0.0001] | nbody_system.length
        particles.position = [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]] | nbody_system.length
        particles.velocity = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] | nbody_system.speed

        instance = bridge.CalculateFieldForParticles(particles=particles, gravity_constant=nbody_system.G)

        zero = 0.0 | nbody_system.length
        print instance.get_gravity_at_point([zero], [1.0] | nbody_system.length, [zero], [zero])
        fx, fy, fz = instance.get_gravity_at_point([zero], [1.0] | nbody_system.length, [zero], [zero])
        self.assertAlmostEqual(fx, [0.0] | nbody_system.acceleration, 6)
        self.assertAlmostEqual(fy, [0.0] | nbody_system.acceleration, 6)
        self.assertAlmostEqual(fz, [0.0] | nbody_system.acceleration, 6)

        for x in (0.25, 0.5, 0.75):
            x0 = x | nbody_system.length
            x1 = (2.0 - x) | nbody_system.length
            potential0 = instance.get_potential_at_point([zero], [x0], [zero], [zero])
            potential1 = instance.get_potential_at_point([zero], [x1], [zero], [zero])
            fx0, fy0, fz0 = instance.get_gravity_at_point([zero], [x0], [zero], [zero])
            fx1, fy1, fz1 = instance.get_gravity_at_point([zero], [x1], [zero], [zero])

            self.assertAlmostEqual(fy0[0], 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(fz0[0], 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(fy1[0], 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(fz1[0], 0.0 | nbody_system.acceleration, 6)

            self.assertAlmostEqual(fx0, -1.0 * fx1, 5)
            fx = (-1.0 / (x0 ** 2) + 1.0 / (x1 ** 2)) * (1.0 | nbody_system.length ** 3 / nbody_system.time ** 2)
            self.assertAlmostEqual(fx, fx0[0], 5)
            self.assertAlmostEqual(potential0, potential1, 6)
Exemplo n.º 19
0
def new_sun_earth_system():
    particles = Particles(2)
    particles.mass = [1, 0.2] | units.MSun
    particles.position = [[0, 0, 0], [1.0, 0, 0]] | units.AU
    particles.velocity = [0, 0, 0] | units.km / units.s
    particles[1].vy = (constants.G * particles.total_mass() / particles[1].x).sqrt()
    return particles
Exemplo n.º 20
0
def merge_two_stars(bodies, particles_in_encounter):
    """
    Merge two stars into one
    """
    com_pos = particles_in_encounter.center_of_mass()
    com_vel = particles_in_encounter.center_of_mass_velocity()
    star_0 = particles_in_encounter[0]
    star_1 = particles_in_encounter[1]

    new_particle = Particles(1)
    new_particle.birth_age = particles_in_encounter.birth_age.min()
    new_particle.mass = particles_in_encounter.total_mass()
    new_particle.age = min(particles_in_encounter.age) \
        * max(particles_in_encounter.mass)/new_particle.mass
    new_particle.position = com_pos
    new_particle.velocity = com_vel
    new_particle.name = "Star"
    new_particle.radius = particles_in_encounter.radius.max()
    print("# old radius:", particles_in_encounter.radius.in_(units.AU))
    print("# new radius:", new_particle.radius.in_(units.AU))
    bodies.add_particles(new_particle)
    print("# Two stars (M=", particles_in_encounter.mass.in_(units.MSun),
          ") collided at d=",
          (star_0.position - star_1.position).length().in_(units.AU))
    bodies.remove_particles(particles_in_encounter)
Exemplo n.º 21
0
 def test9(self):
     print "Testing FastKick for Bridge: evolving a binary"
     particles = Particles(2)
     particles.mass = [3.0, 1.0] | units.MSun
     particles.position = [0, 0, 0] | units.AU
     particles.velocity = [0, 0, 0] | units.km / units.s
     particles[1].x = 2.0 | units.AU
     particles[1].vy = (constants.G * (4.0 | units.MSun) / (2.0 | units.AU)).sqrt()
     particles.move_to_center()
     
     primary_sys = new_gravity_code(particles[:1])
     secondary_sys = new_gravity_code(particles[1:])
     
     primary = primary_sys.particles[0]
     P = 2 * math.pi * primary.x / primary.vy
     
     converter = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.AU)
     kick_from_primary = CalculateFieldForCodesUsingReinitialize(self.new_fastkick_instance(converter), (primary_sys,))
     kick_from_secondary = CalculateFieldForCodesUsingReinitialize(self.new_fastkick_instance(converter), (secondary_sys,))
     
     bridgesys = Bridge(timestep = P / 64.0)
     bridgesys.add_system(primary_sys, (kick_from_secondary,))
     bridgesys.add_system(secondary_sys, (kick_from_primary,))
     
     position_at_start = primary.position.x
     bridgesys.evolve_model(P / 4.0)
     self.assertAlmostRelativeEqual(position_at_start, primary.position.y, 2)
     
     bridgesys.evolve_model(P / 2.0)
     self.assertAlmostRelativeEqual(position_at_start, -primary.position.x, 2)
     
     bridgesys.evolve_model(P)
     kick_from_primary.code.stop()
     kick_from_secondary.code.stop()
     self.assertAlmostRelativeEqual(position_at_start, primary.position.x, 2)
Exemplo n.º 22
0
 def test2(self):
     print("Testing SinkParticles initialization from existing particles")
     original = Particles(3)
     self.assertRaises(
         AttributeError,
         SinkParticles,
         original,
         expected_message=
         "You tried to access attribute 'radius' but this attribute is not defined for this set."
     )
     original.radius = 42.0 | units.RSun
     original.mass = 10.0 | units.MSun
     original.position = [[i, -i, 2 * i] for i in range(3)] | units.parsec
     sinks = SinkParticles(original)
     self.assertEqual(sinks.sink_radius, 42.0 | units.RSun)
     self.assertEqual(sinks.mass, 10.0 | units.MSun)
     self.assertEqual(sinks.position,
                      [[0, 0, 0], [1, -1, 2], [2, -2, 4]] | units.parsec)
     self.assertRaises(
         AttributeError,
         getattr,
         sinks,
         "bogus",
         expected_message=
         "You tried to access attribute 'bogus' but this attribute is not defined for this set."
     )
Exemplo n.º 23
0
 def new_colliders(self):
     colliders = Particles(2)
     colliders.mass = [5, 2] | units.MSun
     colliders.position = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]] | units.RSun
     colliders.velocity = [[0.0, 0.0, 0.0], [0.0, 2000.0, 0.0]] | units.km / units.s
     colliders.move_to_center()
     return colliders
Exemplo n.º 24
0
 def result(self):
   masses, position_vectors, velocity_vectors = self.new_model()
   result = Particles(self.targetN)
   result.mass = masses
   result.position = position_vectors
   result.velocity = velocity_vectors
   return result
Exemplo n.º 25
0
    def test1(self):
        particles = Particles(2)
        particles.mass = [1.0, 1.0] | nbody_system.mass
        particles.radius =  [0.0001, 0.0001] | nbody_system.length
        particles.position = [[0.0,0.0,0.0], [2.0,0.0,0.0]] | nbody_system.length
        particles.velocity = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] | nbody_system.speed
        
        instance = bridge.CalculateFieldForParticles(particles = particles, gravity_constant = nbody_system.G)
        
        zero = 0.0 | nbody_system.length
        print(instance.get_gravity_at_point([zero], [1.0] | nbody_system.length, [zero], [zero]))
        fx, fy, fz = instance.get_gravity_at_point([zero], [1.0] | nbody_system.length, [zero], [zero])
        self.assertAlmostEqual(fx, [0.0] | nbody_system.acceleration, 6)
        self.assertAlmostEqual(fy, [0.0] | nbody_system.acceleration, 6)
        self.assertAlmostEqual(fz, [0.0] | nbody_system.acceleration, 6)

        for x in (0.25, 0.5, 0.75):
            x0 = x | nbody_system.length
            x1 = (2.0 - x) | nbody_system.length
            potential0 = instance.get_potential_at_point([zero], [x0], [zero], [zero])
            potential1 = instance.get_potential_at_point([zero], [x1], [zero], [zero])
            fx0, fy0, fz0 = instance.get_gravity_at_point([zero], [x0], [zero], [zero])
            fx1, fy1, fz1 = instance.get_gravity_at_point([zero], [x1], [zero], [zero])
            
            self.assertAlmostEqual(fy0[0], 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(fz0[0], 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(fy1[0], 0.0 | nbody_system.acceleration, 6)
            self.assertAlmostEqual(fz1[0], 0.0 | nbody_system.acceleration, 6)
            
            self.assertAlmostEqual(fx0, -1.0 * fx1, 5)
            fx = (-1.0 / (x0**2) + 1.0 / (x1**2)) * (1.0 | nbody_system.length ** 3 / nbody_system.time ** 2)
            self.assertAlmostEqual(fx, fx0[0], 5)
            self.assertAlmostEqual(potential0, potential1, 6)
Exemplo n.º 26
0
def make_galaxies():
    if os.path.exists('disk_galactICs.amuse'):
        galaxy1 = read_set_from_file('disk_galactICs.amuse', 'amuse')
    else:
        halo_number_of_particles = NHALO
        converter = nbody_system.nbody_to_si(
            1.0e9 | units.MSun, 1. | units.kpc)
        galaxy1 = new_galactics_model(
                halo_number_of_particles,
                disk_number_of_particles=NDISK,
                generate_bulge_flag=False,
                unit_system_converter=converter,
                disk_random_seed=12345)
        write_set_to_file(galaxy1, 'disk_galactICs.amuse', 'amuse')

    galaxy2 = Particles(len(galaxy1))
    galaxy2.mass = galaxy1.mass
    galaxy2.position = galaxy1.position
    galaxy2.velocity = galaxy1.velocity

    galaxy1.rotate(0.0, numpy.pi/4, 0.0)
    galaxy2.rotate(numpy.pi/6, 0.0, 0.0)
    galaxy1.position += [100.0, 0, 0] | units.kpc
    galaxy2.position -= [100.0, 0, 0] | units.kpc
    galaxy1.velocity += [0.0, 50.0, 0] | units.km/units.s
    galaxy2.velocity -= [0.0, 50.0, 0] | units.km/units.s
    return galaxy1, galaxy2
Exemplo n.º 27
0
 def test5(self):
     print "Testing MI6 evolve_model, 2 particles, no SMBH"
     particles = Particles(2)
     particles.mass = 1.0 | units.MSun
     particles.radius = 1.0 | units.RSun
     particles.position = [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]] | units.AU
     particles.velocity = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] | units.km / units.s
     particles[1].vy = (constants.G * (2.0 | units.MSun) / (2.0 | units.AU)).sqrt()
     particles.move_to_center()
     print particles
     
     converter = nbody_system.nbody_to_si(1.0 | units.MSun, 1.0 | units.AU)
     instance = MI6(converter, **default_options)
     instance.initialize_code()
     instance.parameters.smbh_mass = 0.0 | units.MSun
     instance.commit_parameters()
     instance.particles.add_particles(particles)
     instance.commit_particles()
     primary = instance.particles[0]
     
     P = 2 * math.pi * primary.x / primary.vy
     
     position_at_start = primary.position.x
     instance.evolve_model(P / 4.0)
     self.assertAlmostRelativeEqual(position_at_start, primary.position.y, 3)
     
     instance.evolve_model(P / 2.0)
     self.assertAlmostRelativeEqual(position_at_start, -primary.position.x, 3)
     
     instance.evolve_model(P)
     self.assertAlmostRelativeEqual(position_at_start, primary.position.x, 3)
     
     instance.cleanup_code()
     instance.stop()
Exemplo n.º 28
0
 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())
Exemplo n.º 29
0
def integrate_amuse(orb,pot,tmax,vo,ro):
    """Integrate a snapshot in infile until tmax in Gyr, save to outfile"""

    time=0.0 | tmax.unit
    dt = tmax/10001.

    orbit = Particles(1)

    orbit.mass= 1. | units.MSun
    orbit.radius = 1. |units.RSun

    orbit.position=[orb.x(),orb.y(),orb.z()] | units.kpc
    orbit.velocity=[orb.vx(),orb.vy(),orb.vz()] | units.kms
    galaxy_code = to_amuse(pot,ro=ro,vo=vo)
    
    orbit_gravity=drift_without_gravity(orbit)
    orbit_gravity.particles.add_particles(orbit)
    channel_from_gravity_to_orbit= orbit_gravity.particles.new_channel_to(orbit)

    gravity = bridge.Bridge(use_threading=False)
    gravity.add_system(orbit_gravity, (galaxy_code,))
    gravity.add_system(galaxy_code,)
    gravity.timestep = dt

    while time <= tmax:
        time += dt
        gravity.evolve_model(time)

    channel_from_gravity_to_orbit.copy()
    gravity.stop()

    return orbit.x[0].value_in(units.kpc),orbit.y[0].value_in(units.kpc),orbit.z[0].value_in(units.kpc),orbit.vx[0].value_in(units.kms),orbit.vy[0].value_in(units.kms),orbit.vz[0].value_in(units.kms)
Exemplo n.º 30
0
 def test2(self):
     print "Test basic particle attributes and scale_to_standard - SI units"
     convert_nbody = nbody_system.nbody_to_si(1 | units.MSun, 1 | units.parsec)
     particles = Particles(2)
     particles.position = [[-1, 0, 0], [1,0,0]] | units.parsec
     particles.velocity = [[-1, 0, 0], [1,0,0]] | units.parsec / units.Myr
     particles.mass = 0.5 | units.MSun 
     
     self.assertAlmostRelativeEquals(particles.total_mass(), 1.0 | units.MSun)
     self.assertAlmostRelativeEquals(particles.kinetic_energy(), 1.0 * (0.5 | units.MSun) * (1 |units.parsec / units.Myr) **2 )
     self.assertAlmostRelativeEquals(particles.potential_energy(), -constants.G *  (0.5 | units.MSun) ** 2  / ([2,0,0] | units.parsec).length() )
     self.assertAlmostRelativeEquals(particles.virial_radius(), 4.0 | units.parsec)
     
     particles.scale_to_standard(convert_nbody)
     self.assertAlmostRelativeEquals(particles.total_mass(), convert_nbody.to_si(1.0 | nbody_system.mass))
     self.assertAlmostRelativeEquals(particles.kinetic_energy(), convert_nbody.to_si(0.25 | nbody_system.energy))
     self.assertAlmostRelativeEquals(particles.potential_energy().as_quantity_in(units.J), convert_nbody.to_si(-0.5 | nbody_system.energy).as_quantity_in(units.J), 12)
     self.assertAlmostRelativeEquals(particles.virial_radius(), convert_nbody.to_si(1.0 | nbody_system.length))
     
     particles.scale_to_standard(convert_nbody, virial_ratio=1) # unbound
     self.assertAlmostRelativeEquals(particles.kinetic_energy(), 0.5 * constants.G * (1 | units.MSun**2 / units.parsec), 13)
     self.assertAlmostRelativeEquals(particles.potential_energy(), -0.5 * constants.G * (1 | units.MSun**2 / units.parsec))
     particles.scale_to_standard(convert_nbody, virial_ratio=0) # velocities zeroed
     self.assertAlmostRelativeEquals(particles.kinetic_energy(), 0 | units.J)
     self.assertAlmostRelativeEquals(particles.potential_energy(), -0.5 * constants.G * (1 | units.MSun**2 / units.parsec))
Exemplo n.º 31
0
 def new_colliders(self):
     colliders = Particles(2)
     colliders.mass = [5, 2] | units.MSun
     colliders.position = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]] | units.RSun
     colliders.velocity = [[0.0, 0.0, 0.0], [0.0, 2000.0, 0.0]] | units.km / units.s
     colliders.move_to_center()
     return colliders
Exemplo n.º 32
0
def set_up_initial_conditions(orbital_period, kinetic_to_potential_ratio):
    print("Setting up initial conditions")
    stars = Particles(2)
    stars.mass = [10.0, 1.0] | units.MSun
    stars.radius = 0 | units.RSun
    stars.position = [0.0, 0.0, 0.0] | units.AU
    stars.velocity = [0.0, 0.0, 0.0] | units.km / units.s

    print("Binary with masses: "+str(stars.mass) +
          ", and orbital period: ", orbital_period)
    semimajor_axis = ((constants.G * stars.total_mass() *
                       (orbital_period / (2 * pi))**2.0)**(1.0/3.0))
    separation = 2 * semimajor_axis * (1 - kinetic_to_potential_ratio)
    print("Initial separation:", separation.as_quantity_in(units.AU))
    relative_velocity = (
            (kinetic_to_potential_ratio / (1.0 - kinetic_to_potential_ratio))
            * constants.G * stars.total_mass() / semimajor_axis
            ).sqrt()
    print("Initial relative velocity:",
          relative_velocity.as_quantity_in(units.km / units.s))

    stars[0].x = separation
    stars[0].vy = relative_velocity
    stars.move_to_center()
    return stars
Exemplo n.º 33
0
    def test3(self):
        print "Testing SinkParticles initialization from existing particles in set"
        particles = Particles(10)
        self.assertRaises(AttributeError, SinkParticles, particles[[4, 7]], expected_message=
            "You tried to access attribute 'radius' but this attribute is not defined for this set.")
        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

        sinks = SinkParticles(particles[[4]])
        self.assertEqual(sinks.mass, 5.0 | units.MSun)
        self.assertEqual(sinks.sink_radius, 42.0 | units.RSun)
        self.assertEqual(sinks.radius, 42.0 | units.RSun)
        self.assertEqual(sinks.position, [4.0, 8.0, 12.0] | units.parsec)

        sinks = SinkParticles(particles[[4, 7]], sink_radius=[1,2]|units.AU)
        self.assertEqual(sinks.sink_radius, [1.0, 2.0] | units.AU)
        self.assertEqual(sinks.radius, 42.0 | units.RSun)
        self.assertEqual(sinks.mass, [5.0, 8.0] | units.MSun)
        self.assertEqual(sinks.position, [[4, 8, 12], [7, 14, 21]] | units.parsec)

        self.assertEqual(set(['key', 'mass', 'radius', 'x', 'y', 'z', 'sink_radius', 'vx','vy','vz','lx','ly','lz']),
            set(str(sinks).split("\n")[0].split()))
        self.assertEqual(set(['key', 'mass', 'radius', 'x', 'y', 'z']),
            set(str(particles).split("\n")[0].split()))
Exemplo n.º 34
0
def make_amuse_fresco_stars_only(x,
                                 mstar,
                                 age_yr,
                                 L,
                                 res=512,
                                 p=5e-4,
                                 mass_limits=[0, 0],
                                 mass_rescale=1.,
                                 filename=None,
                                 vmax=None):
    number_of_stars = len(mstar)

    # print(np.max(mstar))
    # ind = mstar>30
    # x=x[ind]
    # mstar=mstar[ind]
    # age_yr=age_yr[ind]
    # number_of_stars = len(mstar)

    if (mass_limits[0] != 0.0) or (mass_limits[1] != 0.0):
        if (mass_limits[0] == 0.0): mass_limits[0] = np.min(mstar)
        if (mass_limits[1] == 0.0): mass_limits[1] = np.max(mstar)
        mstar_new = np.clip(mstar, mass_limits[0], mass_limits[1])
        #small correction to make them stand apart (e.g. instea of clipping both 100 and 50 msun to 50, we get 50 and 60  so they don't look identical)
        mstar_new = mstar_new + (mstar - mstar_new) * 0.1
        ##limits masses of star
        #logm = np.log10(mstar); logm0 = np.max(logm) + np.min(logm);
        #mstar_new = 10**( (logm - logm0)/mass_limits + logm0 )
    mstar_new = mstar**mass_rescale
    new_stars = Particles(number_of_stars)
    new_stars.age = age_yr | units.yr
    new_stars.mass = mstar_new | units.MSun
    new_stars.position = x | units.pc
    stars = new_stars
    gas = Particles()

    #inspectvar(units)
    stars.luminosity = lum_MS(mstar_new) | units.LSun
    #stars.main_sequence_lifetime = [450.0, 420.0] | units.Myr
    stars.radius = rad_MS(mstar_new) | units.RSun
    #stars.spin = [4700, 4700] | units.yr**-1
    # stars.stellar_type = [1, 1] | units.stellar_type

    # se = SSE()
    # se.particles.add_particles(stars)
    # from_se = se.particles.new_channel_to(stars)
    # from_se.copy()
    # inspectvar(stars)
    image, _ = make_fresco_image( stars, gas, return_vmax=True,\
        image_width=[L | units.pc,L | units.pc], image_size=[res,res],percentile=1-p,vmax=vmax)
    #image: (2048,2048,3) RGB
    if not (filename is None):
        #Save image to file
        plt.imshow(image[::-1], extent=(-L / 2.0, L / 2.0, -L / 2.0, L / 2.0))
        plt.xlim(-L / 2.0, L / 2.0)
        plt.ylim(-L / 2.0, L / 2.0)
        plt.imsave(filename, image[::-1])

    return image[::-1]
Exemplo n.º 35
0
 def new_sun_earth_system(self):
     particles = Particles(2)
     particles.mass = [1.0, 3.0037e-6] | units.MSun
     particles.radius = 1.0 | units.RSun
     particles.position = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]] | units.AU
     particles.velocity = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] | units.km / units.s
     particles[1].vy = (constants.G * particles.total_mass() / (1.0 | units.AU)).sqrt()
     return particles
Exemplo n.º 36
0
    def wind_sphere(self, star, Ngas):
        wind=Particles(Ngas)

        r_max = self.r_max or self.r_max_ratio * star.radius
        wind.position, direction = random_positions(Ngas, star.radius, r_max)
        wind.velocity = [0, 0, 0] | units.kms

        return wind
Exemplo n.º 37
0
    def wind_sphere(self, star, Ngas):
        wind = Particles(Ngas)

        r_max = self.r_max or self.r_max_ratio * star.radius
        wind.position, direction = self.generate_positions(Ngas, star.radius,
                                                           r_max)
        wind.velocity = [0, 0, 0] | units.kms

        return wind
Exemplo n.º 38
0
 def test2(self):
     particles = Particles(4)
     particles.mass = [1, 2, 3, 6] | kg
     particles.position = [[0, 0, 0], [3, 0, 0], [0, 4, 0], [3, 4, 0]] | m
     self.assertEqual(particles.center_of_mass(), [2, 3, 0] | m)
     pickled_particles = pickle.dumps(particles)
     unpickled_particles = pickle.loads(pickled_particles)
     self.assertAlmostRelativeEquals(unpickled_particles.mass, [1, 2, 3, 6] | kg)
     self.assertEqual(unpickled_particles.center_of_mass(), [2, 3, 0] | m)
Exemplo n.º 39
0
 def test2(self):
     particles = Particles(4)
     particles.mass = [1, 2, 3, 6] | kg
     particles.position = [[0, 0, 0], [3, 0, 0], [0, 4, 0], [3, 4, 0]] | m
     self.assertEqual(particles.center_of_mass(), [2, 3, 0] | m)
     pickled_particles = pickle.dumps(particles)
     unpickled_particles = pickle.loads(pickled_particles)
     self.assertAlmostRelativeEquals(unpickled_particles.mass, [1, 2, 3, 6] | kg)
     self.assertEqual(unpickled_particles.center_of_mass(), [2, 3, 0] | m)
Exemplo n.º 40
0
 def handle_collision(self, primary, secondary):
     colliders = primary + secondary
     result = Particles(1)
     result.mass = colliders.total_mass() * (1 - self.mass_loss)
     result.position = colliders.center_of_mass()
     result.velocity = colliders.center_of_mass_velocity()
     if hasattr(colliders, "radius"):
         result.radius = colliders.radius.amax()
     return result
Exemplo n.º 41
0
 def handle_collision(self, primary, secondary):
     colliders = primary + secondary
     result = Particles(1)
     result.mass = colliders.total_mass() * (1 - self.mass_loss)
     result.position = colliders.center_of_mass()
     result.velocity = colliders.center_of_mass_velocity()
     if hasattr(colliders, "radius"):
         result.radius = colliders.radius.amax()
     return result
Exemplo n.º 42
0
    def test13(self):
        print "Test box_counting_dimension"
        # Particles distributed uniformly in 3D
        particles = Particles(4096)
        particles.position = numpy.mgrid[0:16.0, 0:16.0, 0:16.0].reshape(
            3, -1).transpose() | units.m
        dimension = particles.box_counting_dimension()
        self.assertAlmostRelativeEquals(dimension, 3.0, 1)
        # Fractal dimension is scale-free
        particles.position *= 1000
        self.assertAlmostRelativeEquals(dimension,
                                        particles.box_counting_dimension(), 10)

        # Particles distributed in the x-y plane
        particles.position = numpy.concatenate(
            (numpy.mgrid[0:64.0, 0:64.0].reshape(2, -1), numpy.zeros(
                (1, 4096)))).transpose() | units.m
        dimension = particles.box_counting_dimension()
        self.assertAlmostRelativeEquals(dimension, 2.0, 1)
        particles.position *= 1000
        self.assertAlmostRelativeEquals(dimension,
                                        particles.box_counting_dimension(), 10)

        # Particles distributed along a line
        particles.position = numpy.concatenate(
            [numpy.arange(4096.0).reshape(1, -1)] * 3).transpose() | units.m
        dimension = particles.box_counting_dimension()
        self.assertAlmostRelativeEquals(dimension, 1.0, 1)
        particles.position *= 1000
        self.assertAlmostRelativeEquals(dimension,
                                        particles.box_counting_dimension(), 10)

        # Particles on a Koch curve
        x, y = self.new_koch_star(level=7)
        numpy.random.seed(123456)
        sel = numpy.random.randint(len(x), size=4096)
        particles.position = numpy.hstack(
            (x[sel], y[sel], numpy.zeros(4096))) | units.m
        dimension = particles.box_counting_dimension()
        self.assertAlmostRelativeEquals(dimension, 1.26186, 1)
        particles.position *= 1000
        self.assertAlmostRelativeEquals(dimension,
                                        particles.box_counting_dimension(), 10)
Exemplo n.º 43
0
    def wind_sphere(self, star, Ngas):
        wind=Particles(Ngas)

        wind_velocity = self.initial_wind_velocity(star)
        outer_wind_distance = wind_velocity * (self.model_time - star.wind_release_time)

        wind.position, direction = random_positions(Ngas, star.radius, outer_wind_distance)
        wind.velocity = direction * wind_velocity

        return wind
Exemplo n.º 44
0
 def test7(self):
     print "Test minimum_spanning_tree_length"
     particles = Particles(6)
     particles.position = [[-5,0,0], [-1,0,0], [0,0,0], [0,1,0], [0,-2,0], [-1,0.1,0]] | units.m
     self.assertEqual(particles[:1].minimum_spanning_tree_length(), 0 | units.m)
     self.assertEqual(particles[:2].minimum_spanning_tree_length(), 4 | units.m)
     self.assertEqual(particles[:3].minimum_spanning_tree_length(), 5 | units.m)
     self.assertEqual(particles[:4].minimum_spanning_tree_length(), 6 | units.m)
     self.assertEqual(particles[:5].minimum_spanning_tree_length(), 8 | units.m)
     self.assertEqual(particles[:6].minimum_spanning_tree_length(), 8.1 | units.m)
Exemplo n.º 45
0
def evolve_gravity(bodies, converter, t_end, dt_integration):

    #Positions and velocities centered on the center of mass
    bodies.move_to_center()
    
    gravity = initialize_code(bodies, timestep_parameter = dt_integration.value_in(nbody_system.time))
    channel_from_gr_to_framework = gravity.particles.new_channel_to(bodies)

    if(t_end != 0.0 | nbody_system.time):
        
        #Evolve it        
        gravity.evolve_model(t_end)
        channel_from_gr_to_framework.copy()
        
        #Orbital Elements
        star = bodies[0]
        ffp = bodies[1]
        bp = bodies[2]
    
        #Star+BP and FFP
        cm_x = (star.mass*star.x + bp.mass*bp.x)/(star.mass+bp.mass)
        cm_y = (star.mass*star.y + bp.mass*bp.y)/(star.mass+bp.mass)
        cm_vx = (star.mass*star.vx + bp.mass*bp.vx)/(star.mass+bp.mass)
        cm_vy = (star.mass*star.vy + bp.mass*bp.vy)/(star.mass+bp.mass)
    
        star_bp = Particles(1)
        star_bp.mass = star.mass + bp.mass
        star_bp.position = [cm_x, cm_y, 0.0 | nbody_system.length]
        star_bp.velocity = [cm_vx, cm_vy, 0.0 | nbody_system.speed]
    
        binary = [star_bp[0], ffp]
        sma_starbp_ffp, e_starbp_ffp, inc_starbp_ffp, lan_starbp_ffp, ap_starbp_ffp = my_orbital_elements_from_binary(binary)
        bodies[1].eccentricity = e_starbp_ffp
        bodies[1].semimajoraxis = sma_starbp_ffp
    
        #Star and BP
        binary = [star, bp]
        sma_star_bp, e_star_bp, inc_star_bp, lan_star_bp, ap_star_bp = my_orbital_elements_from_binary(binary)
        bodies[2].eccentricity = e_star_bp
        bodies[2].semimajoraxis = sma_star_bp
        
        is_stable = is_hill_stable(bodies.mass, bodies.semimajoraxis, bodies.eccentricity, converter)
    
        #Star and FFP
        binary = [star, ffp]
        sma_star_ffp, e_star_ffp, inc_star_ffp, lan_star_ffp, ap_star_ffp = my_orbital_elements_from_binary(binary)
    
        max_energy_change = 0.0 
    
        gravity.stop()
        
        return max_energy_change, is_stable, e_star_ffp, e_star_bp, sma_star_ffp, sma_star_bp, inc_star_ffp, inc_star_bp, lan_star_ffp, lan_star_bp, ap_star_ffp, ap_star_bp
    
    else:
        return 1.0, False, 0.0, 0.0, 1.0 | nbody_system.length, 1.0 | nbody_system.length, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
Exemplo n.º 46
0
 def new_particles_with_internal_structure_from_models(self):
     def get_internal_structure(set, particle=None):
         return self.models[(set.key == particle.key).nonzero()[0]]
     
     result = Particles(len(self.models))
     result.add_function_attribute("get_internal_structure", None, get_internal_structure)
     result.mass = [model.dmass.sum().as_quantity_in(self.mass_unit) for model in self.models]
     result.radius = [model.radius[-1].as_quantity_in(self.radius_unit) for model in self.models]
     result.position = (self.original_center_of_mass + self.stars_after_encounter.position).as_quantity_in(self.position_unit)
     result.velocity = (self.original_center_of_mass_velocity + self.stars_after_encounter.velocity).as_quantity_in(self.velocity_unit)
     return result
Exemplo n.º 47
0
 def new_particles_with_internal_structure_from_models(self):
     def get_internal_structure(set, particle=None):
         return self.models[(set.key == particle.key).nonzero()[0]]
     
     result = Particles(len(self.models))
     result.add_function_attribute("get_internal_structure", None, get_internal_structure)
     result.mass = [model.dmass.sum().as_quantity_in(self.mass_unit) for model in self.models]
     result.radius = [model.radius[-1].as_quantity_in(self.radius_unit) for model in self.models]
     result.position = (self.original_center_of_mass + self.stars_after_encounter.position).as_quantity_in(self.position_unit)
     result.velocity = (self.original_center_of_mass_velocity + self.stars_after_encounter.velocity).as_quantity_in(self.velocity_unit)
     return result
Exemplo n.º 48
0
def new_particles():
    particles = Particles(3)

    particles.mass = [3., 4., 5.] | nbody_system.mass
    particles.position = [
        [1, 3, 0],
        [-2, -1, 0],
        [1, -1, 0],
    ] | nbody_system.length

    particles.velocity = [0., 0., 0.] | nbody_system.speed
    particles.radius = 0 | nbody_system.length

    return particles
Exemplo n.º 49
0
 def test2(self):
     colliders = Particles(2)
     colliders.mass = [5, 5] | units.kg
     colliders.position = [[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]] | units.m
     colliders.velocity = [[0.0, 0.0, 0.0], [2.0, 2.0, 2.0]] | units.m / units.s
     
     merged = StickySpheres(mass_loss=0.2).handle_collision(colliders[0], colliders[1])
     self.assertTrue(isinstance(merged, Particles))
     self.assertEqual(merged.mass, 8 | units.kg)
     self.assertAlmostEqual(merged.position, [0.5, 0.5, 0.5] | units.m)
     self.assertAlmostEqual(merged.velocity, [1.0, 1.0, 1.0] | units.m / units.s)
     copy = colliders.copy()
     copy.move_to_center()
     self.assertAlmostEqual(colliders.kinetic_energy(), merged.as_set().kinetic_energy() / 0.8 + copy.kinetic_energy())
Exemplo n.º 50
0
 def test2(self):
     print "Testing SinkParticles initialization from existing particles"
     original = Particles(3)
     self.assertRaises(AttributeError, SinkParticles, original, expected_message=
         "You tried to access attribute 'radius' but this attribute is not defined for this set.")
     original.radius = 42.0 | units.RSun
     original.mass = 10.0 | units.MSun
     original.position = [[i, -i, 2*i] for i in range(3)] | units.parsec
     sinks = SinkParticles(original)
     self.assertEqual(sinks.sink_radius, 42.0 | units.RSun)
     self.assertEqual(sinks.mass, 10.0 | units.MSun)
     self.assertEqual(sinks.position, [[0,0,0], [1,-1,2], [2,-2,4]] | units.parsec)
     self.assertRaises(AttributeError, getattr, sinks, "bogus", expected_message=
         "You tried to access attribute 'bogus' but this attribute is not defined for this set.")
Exemplo n.º 51
0
    def test2(self):
        print(
            "Test basic particle attributes and scale_to_standard - SI units")
        convert_nbody = nbody_system.nbody_to_si(1 | units.MSun,
                                                 1 | units.parsec)
        particles = Particles(2)
        particles.position = [[-1, 0, 0], [1, 0, 0]] | units.parsec
        particles.velocity = [[-1, 0, 0], [1, 0, 0]] | units.parsec / units.Myr
        particles.mass = 0.5 | units.MSun

        self.assertAlmostRelativeEquals(particles.total_mass(),
                                        1.0 | units.MSun)
        self.assertAlmostRelativeEquals(
            particles.kinetic_energy(),
            1.0 * (0.5 | units.MSun) * (1 | units.parsec / units.Myr)**2)
        self.assertAlmostRelativeEquals(
            particles.potential_energy(), -constants.G *
            (0.5 | units.MSun)**2 / ([2, 0, 0] | units.parsec).length())
        self.assertAlmostRelativeEquals(particles.virial_radius(),
                                        4.0 | units.parsec)

        particles.scale_to_standard(convert_nbody)
        self.assertAlmostRelativeEquals(
            particles.total_mass(),
            convert_nbody.to_si(1.0 | nbody_system.mass))
        self.assertAlmostRelativeEquals(
            particles.kinetic_energy(),
            convert_nbody.to_si(0.25 | nbody_system.energy))
        self.assertAlmostRelativeEquals(
            particles.potential_energy().as_quantity_in(units.J),
            convert_nbody.to_si(-0.5 | nbody_system.energy).as_quantity_in(
                units.J), 12)
        self.assertAlmostRelativeEquals(
            particles.virial_radius(),
            convert_nbody.to_si(1.0 | nbody_system.length))

        particles.scale_to_standard(convert_nbody, virial_ratio=1)  # unbound
        self.assertAlmostRelativeEquals(
            particles.kinetic_energy(),
            0.5 * constants.G * (1 | units.MSun**2 / units.parsec), 13)
        self.assertAlmostRelativeEquals(
            particles.potential_energy(),
            -0.5 * constants.G * (1 | units.MSun**2 / units.parsec))
        particles.scale_to_standard(convert_nbody,
                                    virial_ratio=0)  # velocities zeroed
        self.assertAlmostRelativeEquals(particles.kinetic_energy(),
                                        0 | units.J)
        self.assertAlmostRelativeEquals(
            particles.potential_energy(),
            -0.5 * constants.G * (1 | units.MSun**2 / units.parsec))
def new_particles():
    particles = Particles(3)

    particles.mass=[3.,4.,5.] | nbody_system.mass
    particles.position = [
        [1, 3, 0],
        [-2, -1, 0],
        [1, -1, 0],
    ] | nbody_system.length

    particles.velocity = [0.,0.,0.] | nbody_system.speed
    particles.radius = 0 | nbody_system.length

    return particles
Exemplo n.º 53
0
    def test2(self):
        print("Demonstrate new_sink_particles usage")
        cloud = Particles(100)
        cloud.mass = 1 | units.MSun
        cloud.position = [[0, 0, 0], [100, 100, 100], [200, 200, 200],
                          [300, 300, 300]] * 25 | units.parsec
        cloud.velocity = [[0, 0, 0], [1, 1, 1]] * 50 | units.km / units.s
        unit_converter = ConvertBetweenGenericAndSiUnits(
            1 | units.m, 1 | units.kg, 1 | units.s)
        sph_code = Stub(unit_converter)
        sph_code.parameters.stopping_condition_maximum_density = 1 | units.kg / units.m**3
        sph_code.gas_particles.add_particles(cloud)
        density_limit_detection = sph_code.stopping_conditions.density_limit_detection
        density_limit_detection.enable()

        sph_code.evolve_model(1 | units.Myr)
        self.assertTrue(density_limit_detection.is_set())
        self.assertEqual(len(density_limit_detection.particles()), 3)
        self.assertEqual(density_limit_detection.particles().position,
                         [[100, 100, 100], [200, 200, 200], [300, 300, 300]]
                         | units.parsec)
        print(density_limit_detection.particles())

        clumps = density_limit_detection.particles().copy()
        sph_code.gas_particles.remove_particles(clumps)

        sinks = new_sink_particles(clumps,
                                   sink_radius=1 | units.parsec,
                                   looping_over=self.looping_over)
        self.assertEqual(sinks.sink_radius, 1.0 | units.parsec)
        self.assertEqual(sinks.mass, 1.0 | units.MSun)
        self.assertEqual(sinks.position,
                         [[100, 100, 100], [200, 200, 200], [300, 300, 300]]
                         | units.parsec)
        self.assertEqual(len(sph_code.gas_particles), 97)
        self.assertAlmostRelativeEqual(
            sph_code.gas_particles.total_mass() + clumps.total_mass(),
            100 | units.MSun, 10)
        self.assertAlmostRelativeEqual(sph_code.gas_particles.total_mass(),
                                       97 | units.MSun, 10)

        sinks.accrete(sph_code.gas_particles)
        self.assertAlmostRelativeEqual(sinks.mass, [25, 25, 25] | units.MSun,
                                       10)
        self.assertEqual(len(sph_code.gas_particles), 25)
        self.assertAlmostRelativeEqual(
            sph_code.gas_particles.total_mass() + clumps.total_mass(),
            100 | units.MSun, 10)
        self.assertAlmostRelativeEqual(sph_code.gas_particles.total_mass(),
                                       25 | units.MSun, 10)
Exemplo n.º 54
0
 def test2(self):
     colliders = Particles(2)
     colliders.mass = [5, 5] | units.kg
     colliders.position = [[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]] | units.m
     colliders.velocity = [[0.0, 0.0, 0.0], [2.0, 2.0, 2.0]] | units.m / units.s
     
     merged = StickySpheres(mass_loss=0.2).handle_collision(colliders[0], colliders[1])
     self.assertTrue(isinstance(merged, Particles))
     self.assertEqual(merged.mass, 8 | units.kg)
     self.assertAlmostEqual(merged.position, [0.5, 0.5, 0.5] | units.m)
     self.assertAlmostEqual(merged.velocity, [1.0, 1.0, 1.0] | units.m / units.s)
     copy = colliders.copy()
     copy.move_to_center()
     self.assertAlmostEqual(colliders.kinetic_energy(), merged.as_set().kinetic_energy() / 0.8 + copy.kinetic_energy())
Exemplo n.º 55
0
def get_bodies_in_orbit(m0, m_ffp, m_bp, a_bp, e_bp, phi_bp, lan_bp, b_ffp, r_inf):

    #Bodies
    bodies = Particles()

    ##Get BP in orbit
    #Binary
    star_planet = new_binary_from_orbital_elements(m0, m_bp, a_bp, e_bp, true_anomaly=phi_bp, inclination = 28, longitude_of_the_ascending_node = lan_bp)
    #Planet attributes
    star_planet.eccentricity = e_bp
    star_planet.semimajoraxis = a_bp
    #Center on the star
    star_planet.position -= star_planet[0].position
    star_planet.velocity -= star_planet[0].velocity
    cm_p = star_planet.center_of_mass()
    cm_v = star_planet.center_of_mass_velocity()

    ##Get FFP in orbit
    #Particle set
    m0_ffp = Particles(2)
    #Zeros and parabolic velocity
    zero_p = 0.0 | nbody_system.length
    zero_v = 0.0 | nbody_system.speed
    parabolic_velocity = get_parabolic_velocity(m0, m_ffp, b_ffp, r_inf, m_bp, a_bp, phi_bp)
    #Central star
    m0_ffp[0].mass = m0
    m0_ffp[0].position = (zero_p,zero_p,zero_p)
    m0_ffp[0].velocity = (zero_v,zero_v,zero_v)
    #Free-floating planet
    m0_ffp[1].mass = m_ffp
    m0_ffp[1].position = (-r_inf-cm_p[0],-b_ffp-cm_p[1],zero_p)
    m0_ffp[1].velocity = (parabolic_velocity,zero_v,zero_v)
    #Orbital Elements
    star_planet_as_one = Particles(1)
    star_planet_as_one.mass = m0 + m_bp
    star_planet_as_one.position = cm_p
    star_planet_as_one.velocity = cm_v
    binary = [star_planet_as_one[0], m0_ffp[1]]
    m1, m2, sma, e = my_orbital_elements_from_binary(binary)
    #For the star it sets the initial values of semimajoraxis and eccentricity of the ffp around star+bp
    m0_ffp.eccentricity = e
    m0_ffp.semimajoraxis = sma

    #Order: star, ffp, bp
    bodies.add_particle(m0_ffp[0])
    bodies.add_particle(m0_ffp[1])
    bodies.add_particle(star_planet[1])

    return bodies
Exemplo n.º 56
0
 def result(self):
     self.setup_lookup_tables()
     self.setup_variates()
     
     sph_particles = Particles(self.number_of_sph_particles)
     sph_particles.position = self.new_particle_positions()
     sph_particles.velocity = self.new_particle_velocities()
     sph_particles.u = self.new_particle_specific_internal_energies()
     sph_particles.rho = self.new_particle_densities()
     
     sph_particles.mass = (self.mass.number * 1.0 / self.number_of_sph_particles) | self.mass.unit
     # Crude estimate of the smoothing length; the SPH code will calculate the true value itself.
     sph_particles.h_smooth = (self.grid.get_volume() * 50.0/self.number_of_sph_particles)**(1/3.0)
     
     return sph_particles
Exemplo n.º 57
0
def set_up_inner_binary(inclination):
    semimajor_axis = triple_parameters["a_in"]
    masses = triple_parameters["masses_in"]
    print "   Initializing inner binary"
    stars = Particles(2)
    stars.mass = masses
    stars.position = [0.0, 0.0, 0.0] | units.AU
    stars.velocity = [0.0, 0.0, 0.0] | units.km / units.s
    stars[0].y = semimajor_axis
    stars[0].vx = -math.cos(inclination) * get_relative_velocity_at_apastron(
        stars.total_mass(), semimajor_axis, 0)
    stars[0].vz = math.sin(inclination) * get_relative_velocity_at_apastron(
        stars.total_mass(), semimajor_axis, 0)
    stars.move_to_center()
    return stars
Exemplo n.º 58
0
    def xtest08(self):
        if MODULES_MISSING:
            self.skip("Failed to import a module required for Sakura")
        print("Testing Sakura get_gravity_at_point and get_potential_at_point")
        instance = self.new_instance_of_an_optional_code(
            Sakura, **default_options)
        instance.initialize_code()
        instance.parameters.epsilon_squared = 0.0 | nbody_system.length**2
        #        instance.parameters.smbh_mass = 0.0 | nbody_system.mass

        particles = Particles(2)
        particles.mass = 1.0 | nbody_system.mass
        particles.radius = 0.0 | nbody_system.length
        particles.position = [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]
                              ] | nbody_system.length
        particles.velocity = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]
                              ] | nbody_system.speed
        instance.particles.add_particles(particles)

        zero = 0.0 | nbody_system.length
        fx, fy, fz = instance.get_gravity_at_point(zero,
                                                   1.0 | nbody_system.length,
                                                   zero, zero)
        self.assertAlmostEqual(fx, 0.0 | nbody_system.acceleration)
        self.assertAlmostEqual(fy, 0.0 | nbody_system.acceleration)
        self.assertAlmostEqual(fz, 0.0 | nbody_system.acceleration)

        for x in (0.25, 0.5, 0.75):
            x0 = x | nbody_system.length
            x1 = (2.0 - x) | nbody_system.length
            potential0 = instance.get_potential_at_point(zero, x0, zero, zero)
            potential1 = instance.get_potential_at_point(zero, x1, zero, zero)
            fx0, fy0, fz0 = instance.get_gravity_at_point(zero, x0, zero, zero)
            fx1, fy1, fz1 = instance.get_gravity_at_point(zero, x1, zero, zero)

            self.assertAlmostEqual(fy0, 0.0 | nbody_system.acceleration)
            self.assertAlmostEqual(fz0, 0.0 | nbody_system.acceleration)
            self.assertAlmostEqual(fy1, 0.0 | nbody_system.acceleration)
            self.assertAlmostEqual(fz1, 0.0 | nbody_system.acceleration)

            self.assertAlmostEqual(fx0, -1.0 * fx1)
            fx = (-1.0 / (x0**2) + 1.0 /
                  (x1**2)) * (1.0
                              | nbody_system.length**3 / nbody_system.time**2)
            self.assertAlmostEqual(fx, fx0)
            self.assertAlmostEqual(potential0, potential1)

        instance.stop()
Exemplo n.º 59
0
 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())