Exemple #1
0
def evolve_cluster_in_galaxy(options_file):
    opt = options_reader(options_file)

    timestep = opt.options['timestep']  # in Myr
    tend = opt.options['tend']  # in Myr
    times = np.arange(0.0, tend, timestep) | units.Myr

    cluster = oc_code(opt)
    cluster_code = cluster.code
    galaxy_code = gizmo_interface(opt)

    snap_reader = snapshot_reader(opt, galaxy_code)

    stars = cluster_code.particles.copy()

    if opt.options['axisymmetric']:
        import astropy.units as u
        import gala.dynamics as gd
        import gala.potential as gp

        pos = [opt.options['axi_Rinit'], 0, 0] * u.kpc
        vel = [0, 0, 0] * u.km / u.s
        mw = gp.MilkyWayPotential()
        phase = gd.PhaseSpacePosition(pos, vel)
        vc = mw.circular_velocity(phase).to_value(u.km / u.s) | units.kms

        stars = cluster_code.particles.copy()
        stars.x += opt.options['axi_Rinit'] | units.kpc
        stars.vy += vc
        stars.z += opt.options['axi_zinit'] | units.kpc

    else:
        pos = galaxy_code.chosen_position_z0
        vel = galaxy_code.chosen_velocity_z0
        stars.x += pos[0] | units.kpc
        stars.y += pos[1] | units.kpc
        stars.z += pos[2] | units.kpc
        stars.vx += vel[0] | units.kms
        stars.vy += vel[1] | units.kms
        stars.vz += vel[2] | units.kms

    channel = stars.new_channel_to(cluster_code.particles)
    channel.copy_attributes(["x", "y", "z", "vx", "vy", "vz"])

    system = Bridge(timestep=timestep, use_threading=False)
    system.add_system(cluster_code, (galaxy_code, ))
    system.add_system(galaxy_code)

    converter = cluster_code.unit_converter

    for i, t in enumerate(tqdm(times)):
        system.evolve_model(t, timestep=timestep | units.Myr)

        bound_com = bound.center_of_mass().value_in(units.kpc)

        snap_reader.process_snapshot(system, galaxy_code, bound_com, i, t)

    snap_reader.finish_sim()

    cluster_code.stop()
Exemple #2
0
def local_relax(gas_particles,
                hydro,
                gravity_field=None,
                monitor_func=check_energy_conservation,
                bridge_options=dict()):
    """
    Relax a set of SPH particles by evolving it with a hydrodynamics code, while 
    imposing critical damping on the particle velocities.
    
    :argument gas_particles:  The set of SPH particles
    :argument hydro:          The hydrodynamics code
    :argument gravity_field   Background gravitational field, must support get_gravity_at_point
    :argument monitor_func    For monitoring progress each step. User-defined function or "energy"
    :argument bridge_options: Keyword options passed to Bridge
    """
    if monitor_func == "energy":
        monitor_func = monitor_energy
    t_end_in_t_dyn = 0.1  # Relax for this many dynamical timescales
    t_end = t_end_in_t_dyn \
              * gas_particles.dynamical_timescale(mass_fraction=0.9)
    n_steps = 10
    velocity_damp_factor = 1.0 - (2.0*numpy.pi*t_end_in_t_dyn) \
                                   /n_steps # Critical damping

    in_hydro = hydro.gas_particles.add_particles(gas_particles)
    if gravity_field is None:
        system = hydro
    else:
        system = Bridge(timestep=(t_end / n_steps).as_quantity_in(units.yr),
                        **bridge_options)
        system.add_system(hydro, [gravity_field])

    for i_step, time in enumerate(t_end *
                                  numpy.linspace(1.0 / n_steps, 1.0, n_steps)):
        system.evolve_model(time)
        hydro.gas_particles.velocity = velocity_damp_factor \
                                         * hydro.gas_particles.velocity
        monitor_func(system, i_step, time, n_steps)

    return in_hydro.copy()
Exemple #3
0
def gravity_and_stellar_evolution(number_of_stars,
                                  size,
                                  end_time,
                                  sync_timestep=1 | units.Myr,
                                  plot_timestep=10 | units.Myr):

    stars, converter = create_stars(number_of_stars, size)

    gravity = Hermite(converter)
    stellar = SeBa()
    bridge = Bridge()

    gravity.particles.add_particles(stars)
    stellar.particles.add_particles(stars)

    bridge.add_system(gravity)
    bridge.add_system(stellar)
    bridge.channels.add_channel(
        stellar.particles.new_channel_to(gravity.particles,
                                         attributes=["mass", "radius"]))

    bridge.timestep = sync_timestep

    plot_channels = Channels()
    plot_channels.add_channel(stellar.particles.new_channel_to(stars))
    plot_channels.add_channel(gravity.particles.new_channel_to(stars))

    time = 0 | units.Myr
    while time <= end_time:

        bridge.evolve_model(time)

        plot_channels.copy()
        plot_results(stars, time)

        time += plot_timestep
Exemple #4
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)
Exemple #5
0
def evolve_coupled_system(binary_system, giant_system, t_end, n_steps, 
        do_energy_evolution_plot, previous_data=None):
    directsum = CalculateFieldForParticles(particles=giant_system.particles, gravity_constant=constants.G)
    directsum.smoothing_length_squared = giant_system.parameters.gas_epsilon**2
    coupled_system = Bridge(timestep=(t_end / (2 * n_steps)), verbose=False, use_threading=True)
    coupled_system.add_system(binary_system, (directsum,), False)
    coupled_system.add_system(giant_system, (binary_system,), False)
    
    times = (t_end * list(range(1, n_steps+1)) / n_steps).as_quantity_in(units.day)
    
    if previous_data:
        with open(previous_data, 'rb') as file:
            (all_times, potential_energies, kinetic_energies, thermal_energies, 
                giant_center_of_mass, ms1_position, ms2_position, 
                giant_center_of_mass_velocity, ms1_velocity, ms2_velocity) = pickle.load(file)
        all_times.extend(times + all_times[-1])
    else:
        all_times = times
        if do_energy_evolution_plot:
            potential_energies = coupled_system.particles.potential_energy().as_vector_with_length(1).as_quantity_in(units.erg)
            kinetic_energies = coupled_system.particles.kinetic_energy().as_vector_with_length(1).as_quantity_in(units.erg)
            thermal_energies = coupled_system.gas_particles.thermal_energy().as_vector_with_length(1).as_quantity_in(units.erg)
        else:
            potential_energies = kinetic_energies = thermal_energies = None
        
        giant_center_of_mass = [] | units.RSun
        ms1_position = [] | units.RSun
        ms2_position = [] | units.RSun
        giant_center_of_mass_velocity = [] | units.km / units.s
        ms1_velocity = [] | units.km / units.s
        ms2_velocity = [] | units.km / units.s
    i_offset = len(giant_center_of_mass)
    
    giant_total_mass = giant_system.particles.total_mass()
    ms1_mass = binary_system.particles[0].mass
    ms2_mass = binary_system.particles[1].mass
    
    print("   Evolving for", t_end)
    for i_step, time in enumerate(times):
        coupled_system.evolve_model(time)
        print("   Evolved to:", time, end=' ')
        
        if do_energy_evolution_plot:
            potential_energies.append(coupled_system.particles.potential_energy())
            kinetic_energies.append(coupled_system.particles.kinetic_energy())
            thermal_energies.append(coupled_system.gas_particles.thermal_energy())
        
        giant_center_of_mass.append(giant_system.particles.center_of_mass())
        ms1_position.append(binary_system.particles[0].position)
        ms2_position.append(binary_system.particles[1].position)
        giant_center_of_mass_velocity.append(giant_system.particles.center_of_mass_velocity())
        ms1_velocity.append(binary_system.particles[0].velocity)
        ms2_velocity.append(binary_system.particles[1].velocity)

        a_giant, e_giant = calculate_orbital_elements(ms1_mass, ms2_mass,
                                                      ms1_position, ms2_position,
                                                      ms1_velocity, ms2_velocity,
                                                      giant_total_mass,
                                                      giant_center_of_mass,
                                                      giant_center_of_mass_velocity)
        print("Outer Orbit:", time.in_(units.day),  a_giant[-1].in_(units.AU), e_giant[-1], ms1_mass.in_(units.MSun), ms2_mass.in_(units.MSun), giant_total_mass.in_(units.MSun))
        
        if i_step % 10 == 9:
            snapshotfile = os.path.join("snapshots", "hydro_triple_{0:=04}_gas.amuse".format(i_step + i_offset))
            write_set_to_file(giant_system.gas_particles, snapshotfile, format='amuse')
            snapshotfile = os.path.join("snapshots", "hydro_triple_{0:=04}_core.amuse".format(i_step + i_offset))
            write_set_to_file(giant_system.dm_particles, snapshotfile, format='amuse')
            snapshotfile = os.path.join("snapshots", "hydro_triple_{0:=04}_binary.amuse".format(i_step + i_offset))
            write_set_to_file(binary_system.particles, snapshotfile, format='amuse')
            
            datafile = os.path.join("snapshots", "hydro_triple_{0:=04}_info.amuse".format(i_step + i_offset))
            with open(datafile, 'wb') as outfile:
                pickle.dump((all_times[:len(giant_center_of_mass)], potential_energies, 
                    kinetic_energies, thermal_energies, giant_center_of_mass, 
                    ms1_position, ms2_position, giant_center_of_mass_velocity,
                    ms1_velocity, ms2_velocity), outfile)
       
        figname1 = os.path.join("plots", "hydro_triple_small{0:=04}.png".format(i_step + i_offset))
        figname2 = os.path.join("plots", "hydro_triple_large{0:=04}.png".format(i_step + i_offset))
        print("  -   Hydroplots are saved to: ", figname1, "and", figname2)
        for plot_range, plot_name in [(8|units.AU, figname1), (40|units.AU, figname2)]:
            if HAS_PYNBODY:
                pynbody_column_density_plot(coupled_system.gas_particles, width=plot_range, vmin=26, vmax=32)
                scatter(coupled_system.dm_particles.x, coupled_system.dm_particles.y, c="w")
            else:
                pyplot.figure(figsize = [16, 16])
                sph_particles_plot(coupled_system.gas_particles, gd_particles=coupled_system.dm_particles, 
                    view=plot_range*[-0.5, 0.5, -0.5, 0.5])
            pyplot.savefig(plot_name)
            pyplot.close()
        
    
    coupled_system.stop()
    
    make_movie()
    
    if do_energy_evolution_plot:
        energy_evolution_plot(all_times[:len(kinetic_energies)-1], kinetic_energies, 
            potential_energies, thermal_energies)
    
    print("   Calculating semimajor axis and eccentricity evolution for inner binary")
    # Some temporary variables to calculate semimajor_axis and eccentricity evolution
    total_mass = ms1_mass + ms2_mass
    rel_position = ms1_position - ms2_position
    rel_velocity = ms1_velocity - ms2_velocity
    separation_in = rel_position.lengths()
    speed_squared_in = rel_velocity.lengths_squared()
    
    # Now calculate the important quantities:
    semimajor_axis_binary = (constants.G * total_mass * separation_in / 
        (2 * constants.G * total_mass - separation_in * speed_squared_in)).as_quantity_in(units.AU)
    eccentricity_binary = numpy.sqrt(1.0 - (rel_position.cross(rel_velocity)**2).sum(axis=1) / 
        (constants.G * total_mass * semimajor_axis_binary))

    print("   Calculating semimajor axis and eccentricity evolution of the giant's orbit")
    # Some temporary variables to calculate semimajor_axis and eccentricity evolution
    rel_position = ((ms1_mass * ms1_position + ms2_mass * ms2_position)/total_mass - 
        giant_center_of_mass)
    rel_velocity = ((ms1_mass * ms1_velocity + ms2_mass * ms2_velocity)/total_mass - 
        giant_center_of_mass_velocity)
    total_mass += giant_total_mass
    separation = rel_position.lengths()
    speed_squared = rel_velocity.lengths_squared()
    
    # Now calculate the important quantities:
    semimajor_axis_giant = (constants.G * total_mass * separation / 
        (2 * constants.G * total_mass - separation * speed_squared)).as_quantity_in(units.AU)
    eccentricity_giant = numpy.sqrt(1.0 - (rel_position.cross(rel_velocity)**2).sum(axis=1) / 
        (constants.G * total_mass * semimajor_axis_giant))
    
    orbit_parameters_plot(semimajor_axis_binary, semimajor_axis_giant, all_times[:len(semimajor_axis_binary)])
    orbit_ecc_plot(eccentricity_binary, eccentricity_giant, all_times[:len(eccentricity_binary)])
    
    orbit_parameters_plot(separation_in.as_quantity_in(units.AU), 
        separation.as_quantity_in(units.AU), 
        all_times[:len(eccentricity_binary)], 
        par_symbol="r", par_name="separation")
    orbit_parameters_plot(speed_squared_in.as_quantity_in(units.km**2 / units.s**2), 
        speed_squared.as_quantity_in(units.km**2 / units.s**2), 
        all_times[:len(eccentricity_binary)], 
        par_symbol="v^2", par_name="speed_squared")
Exemple #6
0
    
# Send the Initial Stellear Mass to init_mass Attribute of the Master Set
# This is for FRESCO Compatibility as SEBA is Odd about Ages ...
    MasterSet.init_mass = MasterSet.mass
    
# Copies over the SEV Desired Stellar Traits to the Master Set
    sev_code.evolve_model(1 | units.yr)
    sev_to_MS_channel.copy()
    bridge_code.channels.copy()

# Begin Evolving the Cluster
    while time < end_time:
        sys.stdout.flush()
    # Kick the Gravity Bridge
        time += delta_t
        bridge_code.evolve_model(time)
        util.update_MasterSet(gravity, multiples_code, sev_code)
    # Copy the index (ID) as used in the module to the id field in
    # memory.  The index is not copied by default, as different
    # codes may have different indices for the same particle and
    # we don't want to overwrite silently.
        grav_to_MS_channel.copy_attribute("index_in_code", "id")

    # Copy values from the module to the set in memory.
        grav_to_MS_channel.copy()
    # Copies over the SEV Desired Stellar Traits to the Master Set
        sev_to_MS_channel.copy()

    # Write Out the Data Every 5 Time Steps
        if step_index%5 == 0:
            write.write_time_step(MasterSet, time, cluster_name)
Exemple #7
0
        util.resolve_supernova(supernova_detection, Stellar_Bodies, t_start)

    channel_from_sev_to_stellar.copy_attributes(
        ["mass", "luminosity", "stellar_type", "temperature", "age"])
    channel_from_gravitating_to_multi.copy_attributes(
        ["mass", "vx", "vy", "vz"])

    # Ensuring that Multiples Picks up All Desired Systems
    gravity_code.parameters.begin_time = t_start
    gravity_code.parameters.zero_step_mode = 1
    multiples_code.evolve_model(gravity_code.model_time)
    gravity_code.parameters.zero_step_mode = 0

    # Ensuring the Gravity Code Starts at the Right Time
    t_current = t_start
    bridge_code.evolve_model(t_current, timestep=t_start / 4.)

    min_r = LargeScaleConverter.to_nbody(1000 | units.AU)

    print(
        [r for r in gravity_code.particles.radius if r.number <= min_r.number])

    # ------------------------------------- #
    #          Evolving the Cluster         #
    # ------------------------------------- #

    # TODO: Implement Leap-Frog Coupling of Stellar Evolution & Gravity
    step_index = 0
    #t_catch = t_start + (2000 | units.yr)
    E0 = print_diagnostics(multiples_code)
Exemple #8
0
class grav_gas_sse(object):
    def __init__(self,
                 grav_code,
                 gas_code,
                 se_code,
                 grav_couple_code,
                 conv,
                 mgas,
                 star_parts,
                 gas_parts,
                 dt_feedback,
                 dt_fast,
                 grav_parameters=(),
                 gas_parameters=(),
                 couple_parameters=(),
                 feedback_efficiency=.01,
                 feedback_radius=0.01 | units.parsec,
                 total_feedback_energy=zero,
                 evo_particles=None,
                 star_particles_addition=None,
                 start_time_offset=zero,
                 feedback_safety=1.e-4 * 1.e51 | units.erg,
                 feedback_dt=(10. | units.yr, 7500. | units.yr),
                 feedback_period=20000. | units.yr,
                 feedback_lasttime=None,
                 grav_code_extra=dict(mode='gpu', redirection='none'),
                 gas_code_extra=dict(number_of_workers=3,
                                     use_gl=False,
                                     redirection='none'),
                 se_code_extra=dict(redirection='none'),
                 grav_couple_code_extra=dict()):

        self.codes = (gas_code, grav_code, se_code, grav_couple_code)
        self.parameters = (grav_parameters, gas_parameters, couple_parameters)
        self.conv = conv
        self.sph = sys_from_parts(gas_code,
                                  gasparts=gas_parts,
                                  parameters=gas_parameters,
                                  converter=conv,
                                  extra=gas_code_extra)
        self.grav = sys_from_parts(grav_code,
                                   parts=star_parts,
                                   parameters=grav_parameters,
                                   converter=conv,
                                   extra=grav_code_extra)
        print gas_parameters
        print
        print self.sph.parameters

        #~self.sph_grav=reinitializecopycat(grav_couple_code, (self.sph,self.grav), conv,
        #~parameters=couple_parameters, extra=grav_couple_code_extra)
        #~self.star_grav=reinitializecopycat(grav_couple_code, (self.sph,), conv,
        #~parameters=couple_parameters, extra=grav_couple_code_extra)
        new_couple_code1 = grav_couple_code(conv, **grav_couple_code_extra)
        for param, value in couple_parameters:
            new_couple_code1.parameters.__setattr__(param, value)
        self.sph_grav = CalculateFieldForCodesUsingReinitialize(
            new_couple_code1, (self.sph, self.grav))
        new_couple_code2 = grav_couple_code(conv, **grav_couple_code_extra)
        for param, value in couple_parameters:
            new_couple_code2.parameters.__setattr__(param, value)
        self.star_grav = CalculateFieldForCodesUsingReinitialize(
            new_couple_code2, (self.sph, ))

        self.fast = Bridge(verbose=True, timestep=dt_fast)
        self.fast.add_system(self.sph, (self.sph_grav, ), False)
        self.fast.add_system(self.grav, (self.star_grav, ), False)

        self.evo = se_code(**se_code_extra)
        self.evo.initialize_module_with_default_parameters()
        if evo_particles is None:
            self.evo.particles.add_particles(star_parts)
        else:
            if len(evo_particles) != len(star_parts):
                print "evo parts != star parts"
                raise Exception
            self.evo.particles.add_particles(evo_particles)

        self.total_feedback_energy = total_feedback_energy
        self.dt_feedback = dt_feedback
        self.dt_fast = dt_fast
        self.mgas = mgas

        self.time = self.fast.model_time + start_time_offset
        self.time_offset = start_time_offset
        if star_particles_addition is None:
            self.star_particles_addition = star_parts.empty_copy()
            self.star_particles_addition.Emech_last_feedback = 0. | units.erg
        else:
            self.star_particles_addition = star_particles_addition

        self.feedback_efficiency = feedback_efficiency
        self.feedback_radius = feedback_radius

        self.feedback_safety = feedback_safety
        self.feedback_dt = feedback_dt
        self.feedback_period = feedback_period
        if self.feedback_period < 1.0001 * self.dt_feedback:
            print "feedback_period < dt_feedback, resetting to dt_feedback=", \
              self.dt_feedback.in_(units.yr)
            self.feedback_period = 1.0001 * self.dt_feedback
        if feedback_lasttime is None:
            self.feedback_lasttime = self.time - 2 * self.feedback_period
        else:
            self.feedback_lasttime = feedback_lasttime

    def evolve_model(self, tend):
        dt = self.dt_feedback
        time = self.time

        while time < tend - dt / 2:
            time += dt
            print self.feedback_lasttime.in_(units.yr), time.in_(
                units.yr), self.feedback_period.in_(units.yr)
            #      if time > self.feedback_lasttime+self.feedback_period:
            #        self.sph.parameters.max_size_timestep=self.feedback_dt[1]
            #        print "long timestep"
            #      else:
            #        self.sph.parameters.max_size_timestep=self.feedback_dt[0]
            #        print "short timestep"

            self.fast.evolve_model(time - self.time_offset)
            print self.fast.model_time, ',', self.sph.model_time, self.grav.model_time
            self.evo.evolve_model(self.fast.model_time)
            energy_added = self.mechanical_feedback()

            print energy_added.in_(units.erg), self.feedback_safety.in_(
                units.erg)
            print self.feedback_lasttime.in_(units.yr), time.in_(units.yr)
            if energy_added > self.feedback_safety:
                self.feedback_lasttime = time

        self.time = self.fast.model_time + self.time_offset

    def mechanical_feedback(self):

        star_particles = self.star_particles.copy_to_memory()

        channel = self.particles.new_channel_to(star_particles)

        channel.copy_attributes(["x", "y", "z", "vx", "vy", "vz"])
        channel.copy_attribute("mass", "grav_mass")
        del channel

        channel = self.star_particles_addition.new_channel_to(star_particles)
        channel.copy_attribute("Emech_last_feedback")
        del channel

        new_sph = datamodel.Particles(0)

        star_particles.dmass = star_particles.grav_mass - star_particles.mass
        star_particles.u = (
            star_particles.Emech -
            star_particles.Emech_last_feedback) / star_particles.dmass
        if numpy.any((star_particles.Emech -
                      star_particles.Emech_last_feedback) < zero):
            print "feedback error"
            raise Exception

        losers = star_particles.select_array(lambda x: x > self.mgas,
                                             ["dmass"])
        while len(losers) > 0:
            add = datamodel.Particles(len(losers))
            add.mass = self.mgas
            add.h_smooth = 0. | units.parsec
            dx, dy, dz = uniform_unit_sphere(len(losers)).make_xyz()
            add.x = losers.x + self.feedback_radius * dx
            add.y = losers.y + self.feedback_radius * dy
            add.z = losers.z + self.feedback_radius * dz
            add.vx = losers.vx
            add.vy = losers.vy
            add.vz = losers.vz
            add.u = self.feedback_efficiency * losers.u
            losers.grav_mass -= self.mgas
            losers.Emech_last_feedback += self.mgas * losers.u
            new_sph.add_particles(add)
            losers = star_particles.select_array(
                lambda x, y: x - y > self.mgas, ["grav_mass", "mass"])

        print "gas particles added:", len(new_sph)
        if len(new_sph) == 0:
            return zero
        self.sph.gas_particles.add_particles(new_sph)
        feedback_energy_added = (new_sph.mass * new_sph.u).sum()
        self.total_feedback_energy = self.total_feedback_energy + feedback_energy_added

        channel = star_particles.new_channel_to(self.particles)
        channel.copy_attribute("grav_mass", "mass")
        del channel

        channel = star_particles.new_channel_to(self.star_particles_addition)
        channel.copy_attribute("Emech_last_feedback")
        del channel

        return feedback_energy_added

    def synchronize_model(self):
        return self.fast.synchronize_model()

    @property
    def kinetic_energy(self):
        return self.fast.kinetic_energy

    @property
    def potential_energy(self):
        return self.fast.potential_energy

    @property
    def thermal_energy(self):
        return self.fast.thermal_energy

    @property
    def feedback_energy(self):
        return self.total_feedback_energy

    @property
    def model_time(self):
        return self.time

    @property
    def particles(self):
        return self.fast.particles

    @property
    def gas_particles(self):
        return self.fast.gas_particles

    @property
    def star_particles(self):
        return self.evo.particles

    def dump_system_state(self, filename):
        from amuse.io import write_set_to_file
        import cPickle
        write_set_to_file(self.grav.particles,
                          filename + ".grav",
                          "amuse",
                          append_to_file=False)
        write_set_to_file(self.gas_particles,
                          filename + ".gas",
                          "amuse",
                          append_to_file=False)
        write_set_to_file(self.star_particles,
                          filename + ".evo",
                          "amuse",
                          append_to_file=False)
        write_set_to_file(self.star_particles_addition,
                          filename + ".add",
                          "amuse",
                          append_to_file=False)
        f = open(filename + ".data", 'wb')
        print self.total_feedback_energy
        cPickle.dump(
            (self.codes, self.conv, self.parameters, self.mgas,
             self.feedback_efficiency, self.feedback_radius, self.time,
             self.dt_feedback, self.dt_fast,
             self.total_feedback_energy.in_(
                 1.e51 * units.erg), self.feedback_safety, self.feedback_dt,
             self.feedback_period, self.feedback_lasttime), f)
        f.close()

    @classmethod
    def load_system_state(cls,
                          filename,
                          new_gas_options=(),
                          grav_code_extra=dict(mode='gpu', redirection='none'),
                          gas_code_extra=dict(number_of_workers=3,
                                              use_gl=False,
                                              redirection='none'),
                          se_code_extra=dict(redirection='none'),
                          grav_couple_code_extra=dict()):
        from amuse.io import read_set_from_file
        import cPickle
        star_parts = read_set_from_file(filename + ".grav", 'amuse')
        gas_parts = read_set_from_file(filename + ".gas", 'amuse')
        evo = read_set_from_file(filename + ".evo", 'amuse')
        add = read_set_from_file(filename + ".add", 'amuse')
        f = open(filename + ".data", 'r')
        data = cPickle.load(f)
        f.close()
        gas_code = data[0][0]
        grav_code = data[0][1]
        se_code = data[0][2]
        grav_couple_code = data[0][3]
        conv = data[1]
        gravp = data[2][0]
        gasp = data[2][1]
        cp = data[2][2]
        mgas = data[3]
        fe = data[4]
        fr = data[5]
        to = data[6]
        dt_feedback = data[7]
        dt_fast = data[8]
        tfe = data[9]
        fs = data[10]
        fdt = data[11]
        fp = data[12]
        flt = data[13]

        gasp = gasp + new_gas_options

        return conv, cls(grav_code,
                         gas_code,
                         se_code,
                         grav_couple_code,
                         conv,
                         mgas,
                         star_parts,
                         gas_parts,
                         dt_feedback,
                         dt_fast,
                         grav_parameters=gravp,
                         gas_parameters=gasp,
                         couple_parameters=cp,
                         feedback_efficiency=fe,
                         feedback_radius=fr,
                         total_feedback_energy=tfe,
                         evo_particles=evo,
                         star_particles_addition=add,
                         start_time_offset=to,
                         feedback_safety=fs,
                         feedback_dt=fdt,
                         feedback_period=fp,
                         feedback_lasttime=flt,
                         grav_code_extra=grav_code_extra,
                         gas_code_extra=gas_code_extra,
                         se_code_extra=se_code_extra,
                         grav_couple_code_extra=grav_couple_code_extra)
Exemple #9
0
    gravity_code.parameters.begin_time = t_start

    # ------------------------------------- #
    #          Evolving the Cluster         #
    # ------------------------------------- #

    # TODO: Implement Leap-Frog Coupling of Stellar Evolution & Gravity
    t_current = t_start
    step_index = 0
    E0 = print_diagnostics(multiples_code)
    while t_current <= t_end:
        # Increase the Current Time by the Time-Step
        t_current += delta_t

        # Evolve the Gravitational Codes ( via Bridge Code)
        bridge_code.evolve_model(t_current)

        # Sync the Gravitational Codes w/ the "Gravitating_Bodies" Superset
        channel_from_multi_to_gravitating.copy_attributes(
            ['x', 'y', 'z', 'vx', 'vy', 'vz'])

        # (On a Copy) Recursively Expand All Top-Level Parent Particles & Update Subsets
        # Note: This Updates the Children's Positions Relative to their Top-Level Parent's Position
        subset_sync = ChildUpdater()
        subset_sync.update_children_bodies(multiples_code, Individual_Stars,
                                           Planets)

        # Evolve the Stellar Codes (via SEV Code with Channels)
        # TODO: Ensure Binaries are Evolved Correctly (See Section 3.2.8)
        sev_code.evolve_model(t_current)
Exemple #10
0
class GravityHydroStellar(object):
    def __init__(self,
                 gravity,
                 hydro,
                 stellar,
                 gravity_to_hydro,
                 hydro_to_gravity,
                 time_step_bridge,
                 time_step_feedback,
                 feedback_gas_particle_mass,
                 feedback_efficiency=0.01,
                 feedback_radius=0.01 | units.parsec,
                 verbose=True):
        self.gravity = gravity
        self.hydro = hydro
        self.stellar = stellar
        self.gravity_to_hydro = gravity_to_hydro
        self.hydro_to_gravity = hydro_to_gravity

        self.time_step_bridge = time_step_bridge
        self.time_step_feedback = time_step_feedback
        self.feedback_gas_particle_mass = feedback_gas_particle_mass

        self.feedback_efficiency = feedback_efficiency
        self.feedback_radius = feedback_radius
        self.verbose = verbose

        self.bridge = Bridge(verbose=verbose,
                             timestep=self.time_step_bridge,
                             use_threading=False)
        self.bridge.add_system(self.hydro, (self.gravity_to_hydro, ))
        self.bridge.add_system(self.gravity, (self.hydro_to_gravity, ))

        self.star_particles = self.stars_with_mechanical_luminosity(
            self.stellar.particles)
        self.total_feedback_energy = zero
        self.current_time = 0.0 | units.Myr

    def stars_with_mechanical_luminosity(self, particles):
        result = ParticlesOverlay(particles)

        def lmech_function(temperature, mass, luminosity, radius):
            T = temperature.value_in(units.K)
            M = mass.value_in(units.MSun)
            L = luminosity.value_in(units.LSun)
            R = radius.value_in(units.RSun)

            # Reimers wind below 8000K
            mass_loss = (4.0e-13 | units.MSun / units.yr) * L * R / M
            # ... wind above 8000K
            i = numpy.where(temperature > 8000 | units.K)[0]
            mass_loss[i] = (10**-24.06 | units.MSun / units.yr) * (
                L**2.45 * M**(-1.1) * T.clip(1000, 8.0e4)**(1.31))

            t4 = numpy.log10(T * 1.0e-4).clip(0.0, 1.0)
            v_terminal = (30 + 4000 * t4) | units.km / units.s
            return 0.5 * mass_loss * v_terminal**2

        result.add_calculated_attribute(
            "mechanical_luminosity",
            lmech_function,
            attributes_names=["temperature", "mass", "luminosity", "radius"])
        result.L_mech = result.mechanical_luminosity
        result.E_mech = (0.0 | units.Myr) * result.L_mech
        result.E_mech_last_feedback = result.E_mech
        result.previous_mass = result.mass  # Store the mass of the star at the last moment of feedback
        return result

    def evolve_model(self, end_time):
        while self.current_time < end_time - 0.5 * self.time_step_feedback:
            self.current_time += self.time_step_feedback
            if self.verbose:
                time_begin = time.time()
                print
                print "GravityHydroStellar: Start evolving..."
            self.bridge.evolve_model(self.current_time)
            self.stellar.evolve_model(self.current_time)
            if self.verbose:
                print "GravityHydroStellar: Evolved to:", self.current_time
                model_times = [
                    getattr(self, code).model_time.as_quantity_in(units.Myr)
                    for code in ["stellar", "bridge", "gravity", "hydro"]
                ]
                print "   (Stellar: {0}, Bridge: {1}, Gravity: {2}, Hydro: {3})".format(
                    *model_times)
                print "GravityHydroStellar: Call mechanical_feedback"
            self.mechanical_feedback(self.time_step_feedback)
            if self.verbose:
                print "GravityHydroStellar: store system state"
            self.store_system_state()
            if self.verbose:
                print "GravityHydroStellar: Iteration took {0} seconds.".format(
                    time.time() - time_begin)

    def mechanical_feedback(self, time_step):
        L_mech_new = self.star_particles.mechanical_luminosity
        self.star_particles.E_mech += time_step * 0.5 * (
            self.star_particles.L_mech + L_mech_new)
        self.star_particles.L_mech = L_mech_new
        self.star_particles.dmass = self.star_particles.previous_mass - self.star_particles.mass
        self.star_particles.n_feedback_particles = numpy.array(
            self.star_particles.dmass /
            self.feedback_gas_particle_mass).astype(int)

        losers = self.star_particles.select_array(lambda x: x > 0,
                                                  ["n_feedback_particles"])
        if self.verbose:
            print "GravityHydroStellar: Number of particles providing mechanical feedback during this step:", len(
                losers)
        if len(losers) == 0:
            return
        channel = self.gravity.particles.new_channel_to(losers)
        channel.copy_attributes(["x", "y", "z", "vx", "vy", "vz"])
        number_of_new_particles = losers.n_feedback_particles.sum()
        new_sph_all = Particles(number_of_new_particles)
        new_sph_all.mass = self.feedback_gas_particle_mass
        new_sph_all.h_smooth = 0.0 | units.parsec
        offsets = self.draw_random_position_offsets(number_of_new_particles)

        i = 0
        for loser in losers:
            i_next = i + loser.n_feedback_particles
            new = new_sph_all[i:i_next]
            new.position = loser.position + offsets[i:i_next]
            new.velocity = loser.velocity
            new.u = self.feedback_efficiency * (
                loser.E_mech - loser.E_mech_last_feedback) / loser.dmass
            i = i_next

        losers.previous_mass -= self.feedback_gas_particle_mass * losers.n_feedback_particles
        losers.E_mech_last_feedback = losers.E_mech
        channel = losers.new_channel_to(self.gravity.particles)
        channel.copy_attribute("previous_mass", "mass")
        if self.verbose:
            print "GravityHydroStellar: New SPH particles:"
            print new_sph_all
        self.hydro.gas_particles.add_particles(new_sph_all)
        self.total_feedback_energy += (new_sph_all.mass * new_sph_all.u).sum()

    def draw_random_position_offsets(self, number_of_new_particles):
        r = numpy.random.uniform(0.0, 1.0, number_of_new_particles)
        theta = numpy.random.uniform(0.0, numpy.pi, number_of_new_particles)
        phi = numpy.random.uniform(0.0, 2 * numpy.pi, number_of_new_particles)
        return self.feedback_radius * numpy.array(
            (r * sin(theta) * cos(phi), r * sin(theta) * sin(phi),
             r * cos(theta))).transpose()

    @property
    def kinetic_energy(self):
        return self.bridge.kinetic_energy

    @property
    def potential_energy(self):
        return self.bridge.potential_energy

    @property
    def thermal_energy(self):
        return self.bridge.thermal_energy

    @property
    def feedback_energy(self):
        return self.total_feedback_energy

    @property
    def model_time(self):
        return self.bridge.model_time

    @property
    def particles(self):
        return self.bridge.particles

    @property
    def gas_particles(self):
        return self.bridge.gas_particles

    def store_system_state(self):
        snapshot_number = int(0.5 +
                              self.current_time / self.time_step_feedback)
        filename = os.path.join(
            "snapshots", "cluster_snapshot_{0:=06}_".format(snapshot_number))
        stars = Particles(keys=self.star_particles.key)
        self.star_particles.copy_values_of_attributes_to([
            "mass", "temperature", "stellar_type", "radius", "luminosity",
            "age", "L_mech", "E_mech", "E_mech_last_feedback", "previous_mass"
        ], stars)
        self.gravity.particles.copy_values_of_attributes_to(
            ["x", "y", "z", "vx", "vy", "vz"], stars)
        write_set_to_file(stars, filename + "stars.amuse", "amuse")
        write_set_to_file(self.hydro.gas_particles, filename + "gas.amuse",
                          "amuse")
        with open(filename + "info.pkl", "wb") as outfile:
            cPickle.dump(
                (self.gravity.unit_converter, self.hydro.unit_converter,
                 self.time_step_bridge, self.time_step_feedback,
                 self.feedback_gas_particle_mass, self.feedback_efficiency,
                 self.feedback_radius, self.verbose,
                 self.total_feedback_energy, self.current_time), outfile)

    def load_system_state(self, info_file, stars_file):
        stars = read_set_from_file(stars_file, 'amuse')
        channel = stars.new_channel_to(self.star_particles)
        channel.copy_attributes(
            ["L_mech", "E_mech", "E_mech_last_feedback", "previous_mass"])

        with open(info_file, "rb") as infile:
            (tmp1, tmp2, self.time_step_bridge, self.time_step_feedback,
             self.feedback_gas_particle_mass, self.feedback_efficiency,
             self.feedback_radius, self.verbose, self.total_feedback_energy,
             self.current_time) = cPickle.load(infile)

    def stop(self):
        print "STOP fieldcode"
        self.bridge.codes[0].field_codes[0].code.stop()
        print "STOP fieldcode"
        self.bridge.codes[1].field_codes[0].code.stop()
        print "STOP bridge"
        self.bridge.stop()
        print "STOP stellar"
        self.stellar.stop()