Exemple #1
0
def solar_system_in_time(time_JD=2457099.5|units.day):
  """
  Initial conditions of Solar system --
  particle set with the sun + eight planets,
  at the center-of-mass reference frame.

  Defined attributes: 
  name, mass, radius, x, y, z, vx, vy, vz
  """
  time_0 = 2457099.5 | units.day
  delta_JD = time_JD-time_0
  sun, planets = get_sun_and_planets(delta_JD=delta_JD)
  
  solar_system = Particles()
  solar_system.add_particle(sun)
  solar_system.add_particles(planets)
  solar_system.move_to_center()
  
  ### to compare with JPL, relative positions and velocities need to be corrected for the
  # Sun's vectors with respect to the barycenter
  #r_s = (3.123390770608490E-03, -4.370830943817017E-04, -1.443425433116342E-04) | units.AU
  #v_s = (3.421633816761503E-06,  5.767414405893875E-06, -8.878039607570240E-08) | (units.AU / units.day)
  #print sun
  #print planets.position.in_(units.AU) + r_s
  #print planets.velocity.in_(units.AU/units.day) + v_s
  
  return solar_system
Exemple #2
0
def sink_particles(sinks,sources,Raccretion=0.1 | units.AU):
  closest=numpy.array([-1]*len(sources))
  mind2=(numpy.array([Raccretion.number]*len(sources)) | Raccretion.unit)**2
  for i,s in enumerate(sinks):
     xs,ys,zs=s.x,s.y,s.z
     d2=(sources.x-xs)**2+(sources.y-ys)**2+(sources.z-zs)**2
     select=numpy.where( d2<mind2 )[0]
     mind2[select]=d2[select]
     closest[select]=i

  to_remove=Particles(0)
  for i,s in enumerate(sinks):
     insink=numpy.where(closest == i)[0]
     if len(insink) > 0:
       cm=s.position*s.mass
       p=s.velocity*s.mass
       insinkp=Particles(0)
       for ip in insink:
         insinkp.add_particle(sources[ip])
       s.mass+=insinkp.total_mass()
       s.position=(cm+insinkp.center_of_mass()*insinkp.total_mass())/s.mass
       s.velocity=(p+insinkp.total_momentum())/s.mass
# we lose angular momentum !    
       to_remove.add_particles(insinkp)   
       print len(insinkp),"particles accrete on star", i
  if len(to_remove)>0:
    sources.remove_particles(to_remove)
def get_stars_from_molecular_clous(parts):
    cutoff_density = 10000 | units.amu/units.cm**3
    stars = Particles(0)
    for ip in parts:
        if ip.rho>cutoff_density:
            local_stars = make_stars(ip)
            stars.add_particles(local_stars)
    return stars
Exemple #4
0
def get_stars_from_molecular_clous(parts):
    cutoff_density = 10000 | units.amu / units.cm**3
    stars = Particles(0)
    for ip in parts:
        if ip.rho > cutoff_density:
            local_stars = make_stars(ip)
            stars.add_particles(local_stars)
    return stars
Exemple #5
0
 def get_potential_at_point(self,radius,x,y,z):
     part=Particles(0)
     for s in self.systems:
       part.add_particles(s.particles)
     phi=AdaptingVectorQuantity()
     for rr,xx,yy,zz in zip(radius,x,y,z):
       dr2=((part.x-xx)**2+(part.y-yy)**2+(part.z-zz)**2+rr**2+part.radius**2)
       phi.append( (-self.G*part.mass/dr2**0.5).sum() )
     return phi  
Exemple #6
0
    def create_wind_particles(self):
        wind = Particles(0)

        for star in self.particles:
            if star.lost_mass > self.sph_particle_mass:
                new_particles = self.create_wind_particles_for_one_star(star)
                wind.add_particles(new_particles)
                star.wind_release_time = self.model_time

        return wind
Exemple #7
0
def accrete_gas(sink, gas):
    "Accrete gas within sink radius"
    accreted_gas = Particles()
    distance_to_sink_squared = (
        (gas.x - sink.x)**2
        + (gas.y - sink.y)**2
        + (gas.z - sink.z)**2
    )
    accreted_gas.add_particles(gas[
        numpy.where(distance_to_sink_squared < sink.radius**2)
    ])

    return accreted_gas
Exemple #8
0
 def get_gravity_at_point(self,radius,x,y,z):
     part=Particles(0)
     for s in self.systems:
       part.add_particles(s.particles)
     ax=AdaptingVectorQuantity()
     ay=AdaptingVectorQuantity()
     az=AdaptingVectorQuantity()
     for rr,xx,yy,zz in zip(radius,x,y,z):
       dr2=((part.x-xx)**2+(part.y-yy)**2+(part.z-zz)**2+rr**2+part.radius**2)
       ax.append( (self.G*part.mass*(part.x-xx)/dr2**1.5).sum() )
       ay.append( (self.G*part.mass*(part.y-yy)/dr2**1.5).sum() )
       az.append( (self.G*part.mass*(part.z-zz)/dr2**1.5).sum() )
     return ax,ay,az
Exemple #9
0
def initialize_globular_clusters(cluster_population, nstars):

    stars = Particles(0)
    for ci in cluster_population:
        converter = nbody_system.nbody_to_si(ci.mass, ci.radius)
        bodies = new_king_model(nstars, ci.King_W0, converter)
        bodies.parent = ci
        bodies.position += ci.position
        bodies.velocity += ci.velocity
        bodies.name = "star"
        ci.mass = bodies.mass.sum()
        bodies.scale_to_standard(converter)
        stars.add_particles(bodies)
    return stars
Exemple #10
0
def make_secondaries(center_of_masses, Nbin):

    resulting_binaries = Particles()
    singles_in_binaries = Particles()
    binaries = center_of_masses.random_sample(Nbin)
    mmin = center_of_masses.mass.min()
    for bi in binaries:
        mp = bi.mass
        ms = numpy.random.uniform(mmin.value_in(units.MSun),
                                  mp.value_in(units.MSun)) | units.MSun
        a = random_semimajor_axis_PPE(mp, ms)
        e = numpy.sqrt(numpy.random.random())

        nb = new_binary_orbit(mp, ms, a, e)
        nb.position += bi.position
        nb.velocity += bi.velocity
        nb = singles_in_binaries.add_particles(nb)
        nb.radius = 0.01 * a

        bi.radius = 3*a
        binary_particle = bi.copy()
        binary_particle.child1 = nb[0]
        binary_particle.child2 = nb[1]
        binary_particle.semi_major_axis = a
        binary_particle.eccentricity = e
        resulting_binaries.add_particle(binary_particle)

    single_stars = center_of_masses-binaries
    return single_stars, resulting_binaries, singles_in_binaries
def initialize_globular_clusters(cluster_population, nstars):

    mmean = new_kroupa_mass_distribution(1000).sum() / 1000.
    stars = Particles(0)
    for ci in cluster_population:
        nstars = max(1, int(ci.mass / mmean))
        masses = new_kroupa_mass_distribution(nstars)
        converter = nbody_system.nbody_to_si(masses.sum(), ci.radius)
        bodies = new_king_model(nstars, ci.King_W0, converter)
        bodies.parent = ci
        bodies.mass = masses
        bodies.position += ci.position
        bodies.velocity += ci.velocity
        bodies.name = "star"
        ci.mass = bodies.mass.sum()
        bodies.scale_to_standard(converter)
        stars.add_particles(bodies)
    return stars
Exemple #12
0
 def convert_stars(self, particles, stellar_evolution_code):
     n_particles = self.divide_number_of_particles(particles)
     se_colliders = particles.get_intersecting_subset_in(stellar_evolution_code.particles)
     if self.verbose:
         print("Converting stars of {0} to SPH models of {1} particles, respectively.".format(particles.mass, n_particles))
     sph_models = (
         self.relax(convert_stellar_model_to_SPH(se_colliders[0], n_particles[0], **self.star_to_sph_arguments)),
         self.relax(convert_stellar_model_to_SPH(se_colliders[1], n_particles[1], **self.star_to_sph_arguments))
     )
     gas_particles = Particles()
     for particle, sph_model in zip(particles, sph_models):
         sph_model.position += particle.position
         sph_model.velocity += particle.velocity
         gas_particles.add_particles(sph_model)
     if self.verbose:
         print("Converting stars to SPH particles done")
     if self.debug:
         print(gas_particles)
     return gas_particles
Exemple #13
0
 def all(self):
     parts = Particles()
     for parent in self:
         if parent.subsystem is None:
             parts.add_particle(parent)
         else:
             subsys = parts.add_particles(parent.subsystem)
             subsys.position += parent.position
             subsys.velocity += parent.velocity
     return parts
Exemple #14
0
 def convert_stars(self, particles, stellar_evolution_code):
     n_particles = self.divide_number_of_particles(particles)
     se_colliders = particles.get_intersecting_subset_in(stellar_evolution_code.particles)
     if self.verbose:
         print "Converting stars of {0} to SPH models of {1} particles, respectively.".format(particles.mass, n_particles)
     sph_models = (
         self.relax(convert_stellar_model_to_SPH(se_colliders[0], n_particles[0], **self.star_to_sph_arguments)),
         self.relax(convert_stellar_model_to_SPH(se_colliders[1], n_particles[1], **self.star_to_sph_arguments))
     )
     gas_particles = Particles()
     for particle, sph_model in zip(particles, sph_models):
         sph_model.position += particle.position
         sph_model.velocity += particle.velocity
         gas_particles.add_particles(sph_model)
     if self.verbose:
         print "Converting stars to SPH particles done"
     if self.debug:
         print gas_particles
     return gas_particles
Exemple #15
0
def plummer_w_binaries(N, f_bin=1.,logamin=-4,logamax=-0.5,seed=123454321):
  random.seed(seed)
  plummer=new_plummer_model(N)
  semi=10**random.uniform(logamin,logamax,N) | nbody_system.length
  inc=numpy.arccos(random.uniform(-1.,1.,N))/numpy.pi*180
  longi=random.uniform(0,2*numpy.pi,N)/numpy.pi*180
  binaries=Particles()
  tobin=plummer[:int(f_bin*N)]
  nobin=plummer-tobin
  if len(nobin)>0:
    binaries.add_particles(nobin)  
  for i,p in enumerate( tobin ):
    mass1=p.mass/2
    mass2=p.mass/2
    binary=new_binary_from_orbital_elements(mass1,mass2,semi[i],
              inclination=inc[i],longitude_of_the_ascending_node=longi[i])
    binary.position+=p.position
    binary.velocity+=p.velocity
    binaries.add_particles(binary)
  return binaries  
Exemple #16
0
def old_new_solar_system():
    """
    Create initial conditions describing the solar system. Returns a single 
    particle set containing the sun, planets and Pluto. The model is centered at 
    the origin (center-of-mass(-velocity) coordinates).
    
    Defined attributes: 
    name, mass, radius, x, y, z, vx, vy, vz
    """
    sun = Particle()
    sun.name = 'SUN'
    sun.mass = 1.0 | units.MSun
    sun.radius = 1.0 | units.RSun
    planets = _planets_only()
    
    particles = Particles()
    particles.add_particle(sun)
    particles.add_particles(planets)
    particles.move_to_center()
    return particles
Exemple #17
0
def get_tt72_disk(m=10.e11|units.MSun,
                  r_min=25.|units.kpc,
                  n_rings=[12,15,18,21,24,27,30,33,36,39,42,45],
                  r_rings_rel=[0.2,0.25,0.3,0.35,0.4,0.45,0.5,0.55,0.6,0.65,0.7,0.75],
                  disk_id='a',
                  eps=0.|units.m):
  """
  initialize disk ala TT72 (see the first paragraphs of sec. II and III of the paper)
  positions and velocities with respect to the central particle of mass m
  """
  disk = Particles()
  
  for i,ri in enumerate(r_rings_rel):
    
    disk_rad_i = Particles(n_rings[i])
    
    a = ri*r_min
    phi_i = numpy.linspace(0., pipi, num=n_rings[i], endpoint=False)
    
    disk_rad_i.x = a * numpy.cos(phi_i)
    disk_rad_i.y = a * numpy.sin(phi_i)
    disk_rad_i.z = 0. * a
    
    x_r = disk_rad_i.x/a
    y_r = disk_rad_i.y/a
    
    #vc = (constants.G*m/a)**0.5
    vc = ( constants.G*m*a**2/(a**2 + eps**2)**1.5 )**0.5
    disk_rad_i.vx = -vc * y_r
    disk_rad_i.vy =  vc * x_r
    disk_rad_i.vz = 0.0 * vc
    
    disk.add_particles(disk_rad_i)
  
  # test particles
  disk.mass = 0.|units.MSun
  
  # identification of the disk
  disk.id = disk_id
  
  return disk
Exemple #18
0
    def run_instances_in_serial(self, end_time):
        # final particle set of stones
        stones_final = Particles(0)

        # list of final binary particles sets
        #  should be the same binary number_of_subsets-times
        list_binary_final = []

        for i, instance_i in enumerate(self.list_of_instances):
            instance_i.evolve_model(end_time)
            stones_final.add_particles(instance_i.particles[2:].copy())
            list_binary_final.append(instance_i.particles[:2].copy())

        # check if binary evolved the same in all subsets
        diff_flag = self.final_binary_diff(list_binary_final)
        if diff_flag != 0:
            print "\t binary of the first subset used for the evolution"

        # final particle set after evolve
        binary_and_stones_final = Particles(0)
        binary_and_stones_final.add_particles(list_binary_final[0])
        binary_and_stones_final.add_particles(stones_final)

        return binary_and_stones_final
Exemple #19
0
class StubInterface(object):

    def __init__(self, **options):
        self.maximum_density = 1 | units.kg / units.m**3
        self._gas_particles = Particles()
        self._dm_particles = Particles()
        self._all_particles = ParticlesSuperset([self._gas_particles, self._dm_particles])

    def before_get_parameter(self):
        pass

    def before_set_parameter(self):
        pass

    def initialize_code(self):
        return 0

    synchronize_model = commit_particles = recommit_particles = commit_parameters = initialize_code

    def new_particle(self, mass, x, y, z, vx, vy, vz, *args):
        next_id = len(self._dm_particles)
        temp = Particles(len(mass))
        temp.mass = mass
        temp.x = x
        temp.y = y
        temp.z = z
        temp.vx = vx
        temp.vy = vy
        temp.vz = vz
        temp.id = list(range(next_id, next_id + len(mass)))
        self._dm_particles.add_particles(temp)
        return [temp.id, temp.id]

    def new_gas_particle(self, mass, x, y, z, vx, vy, vz, *args):
        next_id = len(self._gas_particles) + 1000000
        temp = Particles(len(mass))
        temp.mass = mass
        temp.x = x
        temp.y = y
        temp.z = z
        temp.vx = vx
        temp.vy = vy
        temp.vz = vz
        temp.id = list(range(next_id, next_id + len(mass)))
        self._gas_particles.add_particles(temp)
        return [temp.id, temp.id]

    def delete_particle(self, indices):
        for index in indices:
            for id, particle in zip(self._all_particles.id, self._all_particles):
                if id == index:
                    self._all_particles.remove_particle(particle)
        return 0

    def get_mass(self, indices):
        return [[mass for index in indices for id, mass in zip(self._all_particles.id,
            self._all_particles.mass) if index == id], [0]*len(indices)]

    def set_mass(self, indices, masses):
        for index, mass in zip(indices, masses):
            for id, particle in zip(self._all_particles.id, self._all_particles):
                if id == index:
                    particle.mass = mass
                    break
        return 0

    def get_position(self, indices):
        return [[x for index in indices for id, x in zip(self._all_particles.id, self._all_particles.x) if index == id],
            [y for index in indices for id, y in zip(self._all_particles.id, self._all_particles.y) if index == id],
            [z for index in indices for id, z in zip(self._all_particles.id, self._all_particles.z) if index == id],
            [0]*len(indices)]

    def get_velocity(self, indices):
        return [[vx for index in indices for id, vx in zip(self._all_particles.id, self._all_particles.vx) if index == id],
            [vy for index in indices for id, vy in zip(self._all_particles.id, self._all_particles.vy) if index == id],
            [vz for index in indices for id, vz in zip(self._all_particles.id, self._all_particles.vz) if index == id],
            [0]*len(indices)]

    def has_stopping_condition(self, type):
        return 1 if type == 6 else 0

    def get_stopping_condition_maximum_density_parameter(self):
        return self.maximum_density

    def set_stopping_condition_maximum_density_parameter(self, value):
        self.maximum_density = value

    is_stopping_condition_set = is_stopping_condition_enabled = has_stopping_condition

    def get_number_of_stopping_conditions_set(self):
        return 3

    def get_stopping_condition_info(self, sc_indices):
        return [6]*len(sc_indices), [1]*len(sc_indices)

    def get_stopping_condition_particle_index(self, sc_index, sc_sub_index):
        return range(len(self._gas_particles) + 1000000 - len(sc_index), len(self._gas_particles) + 1000000)

    def enable_stopping_condition(self, type):
        pass

    def evolve_model(self, time):
        return 0
Exemple #20
0
 def handle_collisions(self, primaries, secondaries):
     result = Particles()
     for primary, secondary in zip(primaries.as_set(),
                                   secondaries.as_set()):
         result.add_particles(self.handle_collision(primary, secondary))
     return result
Exemple #21
0
class StubInterface(object):

    def __init__(self, **options):
        self.maximum_density = 1 | units.kg / units.m**3
        self._gas_particles = Particles()
        self._dm_particles = Particles()
        self._all_particles = ParticlesSuperset([self._gas_particles, self._dm_particles])

    def before_get_parameter(self):
        pass

    def before_set_parameter(self):
        pass

    def initialize_code(self):
        return 0

    synchronize_model = commit_particles = recommit_particles = commit_parameters = initialize_code

    def new_particle(self, mass, x, y, z, vx, vy, vz, *args):
        next_id = len(self._dm_particles)
        temp = Particles(len(mass))
        temp.mass = mass
        temp.x = x
        temp.y = y
        temp.z = z
        temp.vx = vx
        temp.vy = vy
        temp.vz = vz
        temp.id = list(range(next_id, next_id + len(mass)))
        self._dm_particles.add_particles(temp)
        return [temp.id, temp.id]

    def new_gas_particle(self, mass, x, y, z, vx, vy, vz, *args):
        next_id = len(self._gas_particles) + 1000000
        temp = Particles(len(mass))
        temp.mass = mass
        temp.x = x
        temp.y = y
        temp.z = z
        temp.vx = vx
        temp.vy = vy
        temp.vz = vz
        temp.id = list(range(next_id, next_id + len(mass)))
        self._gas_particles.add_particles(temp)
        return [temp.id, temp.id]

    def delete_particle(self, indices):
        for index in indices:
            for id, particle in zip(self._all_particles.id, self._all_particles):
                if id == index:
                    self._all_particles.remove_particle(particle)
        return 0

    def get_mass(self, indices):
        return [[mass for index in indices for id, mass in zip(self._all_particles.id,
            self._all_particles.mass) if index == id], [0]*len(indices)]

    def set_mass(self, indices, masses):
        for index, mass in zip(indices, masses):
            for id, particle in zip(self._all_particles.id, self._all_particles):
                if id == index:
                    particle.mass = mass
                    break
        return 0

    def get_position(self, indices):
        return [[x for index in indices for id, x in zip(self._all_particles.id, self._all_particles.x) if index == id],
            [y for index in indices for id, y in zip(self._all_particles.id, self._all_particles.y) if index == id],
            [z for index in indices for id, z in zip(self._all_particles.id, self._all_particles.z) if index == id],
            [0]*len(indices)]

    def get_velocity(self, indices):
        return [[vx for index in indices for id, vx in zip(self._all_particles.id, self._all_particles.vx) if index == id],
            [vy for index in indices for id, vy in zip(self._all_particles.id, self._all_particles.vy) if index == id],
            [vz for index in indices for id, vz in zip(self._all_particles.id, self._all_particles.vz) if index == id],
            [0]*len(indices)]

    def has_stopping_condition(self, type):
        return 1 if type == 6 else 0

    def get_stopping_condition_maximum_density_parameter(self):
        return self.maximum_density

    def set_stopping_condition_maximum_density_parameter(self, value):
        self.maximum_density = value

    is_stopping_condition_set = is_stopping_condition_enabled = has_stopping_condition

    def get_number_of_stopping_conditions_set(self):
        return 3

    def get_stopping_condition_info(self, sc_indices):
        return [6]*len(sc_indices), [1]*len(sc_indices)

    def get_stopping_condition_particle_index(self, sc_index, sc_sub_index):
        return list(range(len(self._gas_particles) + 1000000 - len(sc_index), len(self._gas_particles) + 1000000))

    def enable_stopping_condition(self, type):
        pass

    def evolve_model(self, time):
        return 0
Exemple #22
0
def run_diagnostics(
    model,
    logger=None,
    length_unit=units.pc,
    mass_unit=units.MSun,
    time_unit=units.Myr,
):
    """
    Run diagnostics on model
    """
    logger = logger or logging.getLogger(__name__)
    stars = model.star_particles
    sinks = model.sink_particles
    gas = model.gas_particles
    converter = model.star_converter

    if not sinks.is_empty():
        non_collisional_bodies = Particles()
        non_collisional_bodies.add_particles(stars)
        non_collisional_bodies.add_particles(sinks)
    else:
        non_collisional_bodies = stars
    groups = identify_subgroups(
        converter,
        non_collisional_bodies,
        peak_density_threshold=1e-16 | units.g * units.cm**-3,
    )
    n_groups = len(groups)
    if hasattr(stars, 'group_id'):
        group_id_offset = 1 + max(stars.group_id)
    else:
        group_id_offset = 1  # a group id of 0 would mean "no group found"
    logger.info("Found %i groups", n_groups)
    for i, group in enumerate(groups):
        group_id = i + group_id_offset
        if hasattr(group, 'group_id'):
            group.previous_group_id = group.group_id
        else:
            group.previous_group_id = 0
        group.group_id = group_id
        stars_in_group = len(group)
        if (stars_in_group > 100):
            mass_in_group = group.total_mass().in_(mass_unit)
            mass_fraction = [0.01, 0.02, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 1.0]
            radii, new_mass_fraction = group.LagrangianRadii(
                unit_converter=converter,
                mf=mass_fraction,
                cm=group.center_of_mass(),
            )
            assert (new_mass_fraction == mass_fraction)
            radii = radii.value_in(length_unit)

            x, y, z = group.center_of_mass().value_in(length_unit)
            median_previous_group_id = numpy.median(group.previous_group_id)
            logger.info(
                "step %i group %i nstars %i mass %s xyz %f %f %f %s origin %i "
                "LR %f %f %f %f %f %f %f %f %f %s",
                model.step,
                group_id,
                stars_in_group,
                mass_in_group,
                x,
                y,
                z,
                length_unit,
                median_previous_group_id,
                radii[0],
                radii[1],
                radii[2],
                radii[3],
                radii[4],
                radii[5],
                radii[6],
                radii[7],
                radii[8],
                length_unit,
            )
    groups = ParticlesSuperset(groups)
    group_identifiers = Particles(keys=groups.key)
    group_identifiers.group_id = groups.group_id
    group_identifiers.previous_group_id = groups.previous_group_id
    return group_identifiers
Exemple #23
0
def new_binary_distribution(
        primary_mass,
        secondary_mass=None,
        binaries=None,
        min_mass=0.08 | units.MSun,
        ):
    """
    Takes primary masses, and returns a set of stars and a set of binaries
    formed by these stars.
    Secondary masses are given by a uniform random mass ratio with the primary
    masses. If optional secondary masses are given, these are used instead.
    binaries is an optional particleset used for the binary pairs, with given
    positions and velocities. Other parameters are ignored.
    """
    N = len(primary_mass)
    if binaries is None:
        binaries = Particles(N)
        # Should give some position/velocity as well?
    elif len(binaries) != N:
        print("binaries must be None or have the same lenght as primary_mass")
        return -1
    if secondary_mass is None:
        # Now, we need to specify the mass ratio in the binaries.
        # A flat distribution seems to be OK.
        mass_ratio = uniform(N)
        # This gives us the secondaries' masses
        secondary_mass = mass_ratio * primary_mass
        # secondaries are min_mass at least
        secondary_mass = numpy.maximum(secondary_mass, min_mass)
    elif len(secondary_mass) != N:
        print("Number of secondaries is unequal to number of primaries!")
        return -1
    else:
        # Make sure primary_mass is the larger of the two, and secondary_mass
        # the smaller.
        pm = primary_mass.maximum(secondary_mass)
        sm = primary_mass.minimum(secondary_mass)
        primary_mass = pm
        secondary_mass = sm
        del(pm, sm)
    # Now, we need to calculate the semi-major axes for the binaries. Since the
    # observed quantity is orbital periods, we start from there.
    mean_log_orbital_period = 5  # 10log of the period in days, (Duchene&Kraus)
    sigma_log_orbital_period = 2.3
    orbital_period = numpy.random.lognormal(
            size=N,
            mean=numpy.log(10) * mean_log_orbital_period,
            sigma=numpy.log(10) * sigma_log_orbital_period,
            ) | units.day
    # We need the masses to calculate the corresponding semi-major axes.
    semi_major_axis = orbital_period_to_semi_major_axis(
            orbital_period,
            primary_mass,
            secondary_mass,
            )
    # Eccentricity: square root of random value
    eccentricity = numpy.sqrt(random(N))
    # Other orbital elements at random
    inclination = pi * random(N) | units.rad
    true_anomaly = 2 * pi * random(N) | units.rad
    longitude_of_the_ascending_node = 2 * pi * random(N) | units.rad
    argument_of_periapsis = 2 * pi * random(N) | units.rad
    primaries, secondaries = generate_binaries(
            primary_mass,
            secondary_mass,
            semi_major_axis,
            eccentricity=eccentricity,
            inclination=inclination,
            true_anomaly=true_anomaly,
            longitude_of_the_ascending_node=longitude_of_the_ascending_node,
            argument_of_periapsis=argument_of_periapsis,
            G=constants.G,
            )
    stars = Particles()

    primaries.position += binaries.position
    secondaries.position += binaries.position
    primaries.velocity += binaries.velocity
    secondaries.velocity += binaries.velocity
    primaries = stars.add_particles(primaries)
    secondaries = stars.add_particles(secondaries)

    binaries.eccentricity = eccentricity
    binaries.semi_major_axis = semi_major_axis
    for i in range(len(primaries)):
        binaries[i].child1 = primaries[i]
        binaries[i].child2 = secondaries[i]
        # Probably needed
        binaries[i].mass = primaries[i].mass + secondaries[i].mass
    return stars, binaries
Exemple #24
0
def iliev_test_7_ic(N=10000, Ns=10, L=6.6 | units.kpc):
    print "Initializing iliev_test_7"

    mp = rhoinit * (2 * L)**3 / N
    Nc = ((rhoclump * 4 * constants.pi / 3 * (0.8 | units.kpc)**3) / mp)
    Nc = int(Nc)

    print Nc

    try:
        f = open("glass%9.9i.pkl" % N, "rb")
        x, y, z = cPickle.load(f)
        f.close()
    except:
        x, y, z = glass_unit_cube(N, target_rms=0.05).make_xyz()
        f = open("glass%9.9i.pkl" % N, "wb")
        cPickle.dump((x, y, z), f)
        f.close()

    sel = numpy.where(((x -
                        (5. / 6.6))**2 + y**2 + z**2)**0.5 > (0.8 / 6.6))[0]

    x = x[sel]
    y = y[sel]
    z = z[sel]

    p = Particles(len(x))
    print len(x)
    # set particles homogeneously in space
    p.x = L * x
    p.y = L * y
    p.z = L * z

    # set other properties
    p.h_smooth = 0. | units.parsec
    p.vx = 0. | (units.km / units.s)
    p.vy = 0. | (units.km / units.s)
    p.vz = 0. | (units.km / units.s)
    p.u = uinit
    p.rho = rhoinit
    p.mass = mp
    p.flux = 0. | (units.s**-1)
    p.xion = 0. | units.none

    sources = Particles(Ns)
    x, y, z = uniform_unit_sphere(Ns).make_xyz()
    if Ns == 1:
        x, y, z = 0., 0., 0.

    sources.x = -(5. | units.kpc) + L * x * (1. / N)**(1. / 3) / 10
    sources.y = L * y * (1. / N)**(1. / 3) / 10
    sources.z = L * z * (1. / N)**(1. / 3) / 10
    sources.luminosity = (1.2e52 / Ns) | (units.s**-1)
    sources.SpcType = 1.

    clump = Particles(Nc)
    x, y, z = uniform_unit_sphere(Nc).make_xyz()

    clump.x = (5. | units.kpc) + (0.8 | units.kpc) * x
    clump.y = (0.8 | units.kpc) * y
    clump.z = (0.8 | units.kpc) * z

    clump.h_smooth = 0. | units.parsec
    clump.vx = 0. | (units.km / units.s)
    clump.vy = 0. | (units.km / units.s)
    clump.vz = 0. | (units.km / units.s)
    clump.u = uclump
    clump.rho = rhoclump
    clump.mass = mp
    clump.flux = 0. | (units.s**-1)
    clump.xion = 0. | units.none

    p.add_particles(clump)

    return p, sources
Exemple #25
0
	def run(self, run_num):
		print("Setting up run %d..." % (run_num))

		# Create group for run
		run_group = self.hdf5_file.create_group(str(run_num))

		# create nbody converter thing?
	 	convert_nbody = nbody_system.nbody_to_si(100.0 | units.MSun, 1 | units.parsec)

		# initialize particle datamodel
		stars = Particles()
		
		print("		Initializing and populating clusters...")
		# populate/initialize clusters, add to particle model
		for c in self.clusters:
			c.populate()
			stars.add_particles(c.plummer)
		print("		Done!")

		# initialize codes
		# initialize hermite
		print("		Initializing hermite...")
		hermite_code = Hermite(convert_nbody)
		hermite_code.particles.add_particles(stars)
		detect_coll = hermite_code.stopping_conditions.collision_detection
		detect_coll.enable()
		print("		Done!")

		print("		Initializing SSE...")
		sse_code = SSE()
		sse_code.particles.add_particles(stars)

		print("Done!\n")

		# actually run the simulation!
		print("===== Run #%d =====" % (run_num))

		t = 0 # time
		i = 1 # iteration num
		c = 1 # collision num
		while(t < self.runtime):
			print("		Time (Myr): %d" % (t))

			print("			Simulating...")

			# evolve model
			hermite_code.evolve_model(t | units.Myr)
			sse_code.evolve_model(t | units.Myr)

			hermite_code.particles.copy_values_of_attribute_to("position", sse_code.particles)
			sse_code.particles.synchronize_to(hermite_code.particles)

			if detect_coll.is_set():
				print("Detected a collision!!")
				print(detect_coll.particles(0))
				coll_f = open(sub_folder + "/collision-" + str(c) + "_time" + str(t) + ".txt")
				coll_f.write( detect_coll.particles(0) )
				coll_f.close()
				c += 1
				# somehow put a log
				# also... eventually, "pause" the rest of the simulation and simulate the collision somehow

			#sse_code.particles.copy_values_of_attribute_to("mass", hermite_code.particles)
			#sse_code.particles.copy_values_of_attribute_to("stellar_type", hermite_code.particles)
			#sse_code.particles.copy_values_of_attribute_to("age", hermite_code.particles)
			#sse_code.particles.copy_values_of_attribute_to("luminosity", hermite_code.particles)
			#sse_code.particles.copy_values_of_attribute_to("temperature", hermite_code.particles)
			#sse_code.particles.copy_values_of_attribute_to("radius", hermite_code.particles)

			hermite_code.particles.mass = sse_code.particles.mass

			print("			Done.")

			# output to csv
			print("			Outputting to HDF5...")
			#file_name = sub_folder + "/data-" + str(i) + "_time-" + str(t) + ".txt"
			self.write_to_hdf5_file(run_group, i, t, stars)
			print("			Done.")

			#print("			Creating plot...")
			#plot_name = "System at " + str(t) + " Myr"
			#plot_path = sub_folder + "/plot-" + str(i) + "_time-" + str(t) + ".png"
			#plot_data(plot_name, plot_path, hermite_code.particles)
			#print("			Done.")

			t += self.timestep
			i += 1

		print("Run complete.\n")
Exemple #26
0
 def handle_collisions(self, primaries, secondaries):
     result = Particles()
     for primary, secondary in zip(primaries.as_set(), secondaries.as_set()):
         result.add_particles(self.handle_collision(primary, secondary))
     return result
class MinimalWorkingExample(object):
    def __init__(self,     
                 total_N=16000, #total number of disc particles
                 tend=250. | units.yr, #End time of the simulation
                 Mstar=1. | units.MSun, #Mass of the accreting star
                 dt = 1. | units.yr, #timestep
                 temp = 25. | units.K, #temperature of the ISM
                 v_ism = 3.0 | units.kms, #Velocity of the ISM with respect to the star
                 n_core = 4, #Number of cores used by the community codes
                 mu = 2.3, #mean molecular weight
                 theta = 0., #angle of the disc with respect to the flow, 0 means disc rotation axis is parallel with flow direction
                 n_dens = 5e6 | (units.cm)**(-3.), #Number density of the ism
                 dirname = './'):
        
        self.disc_N = total_N 
        self.tend = tend
        self.Mstar = Mstar
        self.dt = dt
        self.mu = mu * constants.proton_mass
        self.T = temp 
        self.cs = ((temp*constants.kB)/self.mu).sqrt()
#        print "cs=", self.cs.in_(units.kms)
        self.v_ism = v_ism
        self.ism_n_dens = n_dens #number density of the ism
        self.ism_dens = self.mu*self.ism_n_dens #mass density of the ism
        self.converter = nbody_system.nbody_to_si(self.Mstar, 1. | units.AU)
       
        self.disc_angle = numpy.radians(theta)
        self.n_core = n_core 
        self.dirname = dirname
        self.discfraction = 0.01
        self.disc_Rmin = self.converter.to_generic(10.| units.AU).value_in(nbody_system.length)
        self.disc_Rmax = self.converter.to_generic(100.| units.AU).value_in(nbody_system.length)
        self.filename = "DiskWind.h5"
    
        print('Files will be saved in ', self.dirname)


    def initialize_star(self):
        
        self.star=Particles(1)
        self.star.mass=self.Mstar
        self.star.radius= 1. | units.AU
        self.star.x=0.|units.AU
        self.star.y=0.|units.AU
        self.star.z=0.|units.AU
        self.star.vx=0.|units.kms
        self.star.vy=0.|units.kms
        self.star.vz=0.|units.kms


    def initialize_data(self):
        

        self.cylinder_radius = 500. | units.AU 
        self.cylinder_length = 2.*self.cylinder_radius
        self.cylinder_vol = self.cylinder_length*numpy.pi*self.cylinder_radius**2.
        self.sph_particle_dens = self.ism_dens/(0.01*self.Mstar/self.disc_N)
        self.initialize_star()
        self.initialize_ism()


    def initialize_ism(self):

        #specific internal energy of the ism, i.e. internal energy per unit mass
        #In case of an isothermal EOS, Gadget requires the sound-speed squared as input parameter instead of the thermal energy per unit mass
        self.ism_u = self.cs**2.
        
        self.ism_slice_length = self.v_ism*self.dt
        self.ism_slice_vol = self.ism_slice_length*numpy.pi*self.cylinder_radius**2.0
    
        self.ism_slice_mass = self.ism_dens*self.ism_slice_vol
        self.ism_mass = self.ism_dens*self.cylinder_vol
        
        #The x-coordinate of the inflow
        self.offset = self.cylinder_radius 
        
        self.ism_slice_N = int(round(self.sph_particle_dens*self.ism_slice_vol))    
        self.total_N = self.ism_slice_N*(self.cylinder_length/self.ism_slice_length)
        

    def make_slice(self):
    
        new_slice = Particles(self.ism_slice_N)
    
        rho = numpy.sqrt(numpy.random.uniform(0,1,self.ism_slice_N))*self.cylinder_radius.value_in(units.AU)
        phi = numpy.random.uniform(0,2.0*numpy.pi, self.ism_slice_N)
    

        new_slice.x = numpy.random.uniform(self.ism_slice_length.value_in(units.AU), 0, self.ism_slice_N) - self.offset.value_in(units.AU) | units.AU
        new_slice.y = rho*numpy.sin(phi) | units.AU
        new_slice.z = rho*numpy.cos(phi) | units.AU
    
        new_slice.vx = 1000*self.v_ism
        new_slice.vy = 0.0 | units.kms
        new_slice.vz = 0.0 | units.kms    
    
        new_slice.mass = self.ism_slice_mass/self.ism_slice_N
        new_slice.u = self.ism_u

        return new_slice
    

    def create_disc(self):
                
        #The following line makes sure masses for ISM and disc particles are equal:
        self.discfraction = (self.disc_N*(self.ism_slice_mass/self.ism_slice_N))/self.Mstar
        
        T_disc = self.T
        cs_disc = ((T_disc*constants.kB)/self.mu).sqrt()
        densitypower = 1.5
        g2=2-densitypower
        k_out=((1+self.discfraction)/self.disc_Rmax**3)**0.5
        sigma_out=g2*self.discfraction/(2*numpy.pi*self.disc_Rmax**densitypower*(self.disc_Rmax**g2-self.disc_Rmin**g2))
        q_out = self.converter.to_generic(cs_disc).value_in(nbody_system.length/nbody_system.time)/(numpy.pi*sigma_out/k_out)
        
        print("Number of disk particles:", self.disc_N)
        
        proto=ProtoPlanetaryDisk(self.disc_N,
                                 convert_nbody=self.converter,
                                 discfraction=self.discfraction,
                                 densitypower=1.5,
                                 thermalpower=0,
                                 Rmin=self.disc_Rmin,
                                 Rmax=self.disc_Rmax,
                                 q_out=q_out)
        disc=proto.result
    
        print("The mass of a disc particle = ", disc.mass[0].value_in(units.kg))
    
        #Rotate 90 degrees with respect to the z-axis and then theta degrees with respect to the y-axis
        
        temp_x = disc[:].x
        temp_y = disc[:].y
        temp_z = disc[:].z
        temp_vx = disc[:].vx
        temp_vy = disc[:].vy
        temp_vz = disc[:].vz
    
    
        disc.x = temp_z*numpy.cos(self.disc_angle) - temp_y*numpy.sin(self.disc_angle)
        disc.y = temp_z*numpy.sin(self.disc_angle) + temp_y*numpy.cos(self.disc_angle)
        disc.z = -temp_x
    
        disc.vx = temp_vz*numpy.cos(self.disc_angle) - temp_vy*numpy.sin(self.disc_angle)
        disc.vy = temp_vz*numpy.sin(self.disc_angle) + temp_vy*numpy.cos(self.disc_angle)
        disc.vz = -temp_vx
             
        return disc

 
    def evolve_model(self):
        self.initialize_data()

        self.ism_code = Gadget2(self.converter, number_of_workers=self.n_core)#, debugger='gdb')
        self.ism_code.parameters.time_max = 1024*self.dt       
        self.ism_code.parameters.n_smooth = 64 
        self.ism_code.parameters.n_smooth_tol = 2./64.   
        self.ism_code.parameters.artificial_viscosity_alpha = 0.1 
        self.ism_code.parameters.epsilon_squared = (1. | units.AU)**2.

        self.all_particles = Particles()
        write_set_to_file(self.star, self.filename, "hdf5", append_to_file=False)
        write_set_to_file(self.all_particles, self.filename, "hdf5", append_to_file=False)
        
        self.initial_disc_particles = self.create_disc()
        self.all_particles.add_particles(self.initial_disc_particles)
        self.ism_code.gas_particles.add_particles(self.initial_disc_particles)
        
        #You can only add a sink after adding gas particles
        #starinsph refers to the corresponding particle set/id in the community code
        starinsph = self.ism_code.dm_particles.add_particles(self.star)
        #Use the build-in sink particle routine from amuse.ext.sink. Sink_radius needs to be defined manually otherwise the particle radius in gadget is taken,
        #which does not corresponding to the particle radius in the framework (since 'particles' in gadget do not have a radius, it is set to 0.01 | generic_unit_system.length
        #and corresponds to the gas gravitational smoothing epsilon.           
        sink = new_sink_particles(starinsph, sink_radius= self.star.radius)
       
        self.channel_from_ismcode_to_framework = self.ism_code.gas_particles.new_channel_to(self.all_particles)
    
        time = 0. | units.yr
    
        while time <= (self.tend+self.dt/2.):
 
 
            print("Adding new slice of ISM...")
            newslice=self.make_slice()
            self.ism_code.gas_particles.add_particles(newslice)
            self.all_particles.add_particles(newslice)

                
            start = timing.time()
            print("=======================================================")
            print("Evolving to time = ", time.value_in(units.yr), " of ", self.tend.value_in(units.yr)," years...")    
            self.ism_code.evolve_model(time)
            print("This took ", (timing.time() - start), " s")
            
            out_of_bounds = self.ism_code.gas_particles.select_array(lambda x,y,z:(x > self.cylinder_radius)|((z**2+y**2).sqrt() >= self.cylinder_radius), ["x","y","z"]) 
            if len(out_of_bounds)>0:
                print("Removing ", len(out_of_bounds), " particles from the code because they were out of bounds")
                
                self.ism_code.gas_particles.remove_particles(out_of_bounds)
            
            
            self.ism_code.gas_particles.synchronize_to(self.all_particles)  
            sink.accrete(self.ism_code.gas_particles)

            write_set_to_file(self.star, self.filename, "hdf5")
            write_set_to_file(self.all_particles, self.filename, "hdf5")
            
            time += self.dt
            
        print("=======================================================")
        self.ism_code.stop()
def form_stars_from_group_older_version(
        group_index,
        sink_particles,
        newly_removed_gas,
        lower_mass_limit=settings.stars_lower_mass_limit,
        upper_mass_limit=settings.stars_upper_mass_limit,
        local_sound_speed=0.2 | units.kms,
        minimum_sink_mass=0.01 | units.MSun,
        logger=None,
        randomseed=None,
        shrink_sinks=True,
        **keyword_arguments):
    """
    Form stars from specific group of sinks.

    NOTE: This is the older version where removed gas is
    considered as star-forming region. This is now being
    updated to the above latest version.
    """
    logger = logger or logging.getLogger(__name__)
    logger.info("Using form_stars_from_group on group %i", group_index)
    if randomseed is not None:
        logger.info("Setting random seed to %i", randomseed)
        numpy.random.seed(randomseed)

    # Sanity check: each sink particle must be in a group.
    ungrouped_sinks = sink_particles.select_array(lambda x: x <= 0,
                                                  ['in_group'])
    if not ungrouped_sinks.is_empty():
        logger.info(
            "WARNING: There exist ungrouped sinks. Something is wrong!")
        return None

    # Consider only group with input group index from here onwards.
    group = sink_particles[sink_particles.in_group == group_index]

    # Sanity check: group must have at least a sink
    if group.is_empty():
        logger.info(
            "WARNING: There is no sink in the group: Something is wrong!")
        return None

    number_of_sinks = len(group)
    logger.info("%i sinks found in group #%i: %s", number_of_sinks,
                group_index, group.key)
    group_mass = group.total_mass()
    logger.info("Group mass: %s", group_mass.in_(units.MSun))

    next_mass = generate_next_mass(
        initial_mass_function=initial_mass_function,
        lower_mass_limit=lower_mass_limit,
        upper_mass_limit=upper_mass_limit,
    )[0][0]
    try:
        # Within a group, group_next_primary_mass values are either
        # a mass, or 0 MSun. If all values are 0 MSun, this is a
        # new group. Else, only interested on the non-zero value. The
        # non-zero values are the same.
        logger.info('SANITY CHECK: group_next_primary_mass %s',
                    group.group_next_primary_mass)
        if group.group_next_primary_mass.max() == 0 | units.MSun:
            logger.info('Initiate group #%i for star formation', group_index)
            group.group_next_primary_mass = next_mass
        else:
            next_mass = group.group_next_primary_mass.max()
    # This happens for the first ever assignment of this attribute
    except AttributeError:
        logger.info(
            'AttributeError exception: Initiate group #%i for star formation',
            group_index)
        group.group_next_primary_mass = next_mass

    logger.info("Next mass is %s", next_mass)

    if group_mass < next_mass:
        logger.info("Group #%i is not massive enough for the next star",
                    group_index)
        return None

    # Form stars from the leftover group sink mass
    mass_left = group_mass - next_mass
    masses = new_masses(
        stellar_mass=mass_left,
        lower_mass_limit=lower_mass_limit,
        upper_mass_limit=upper_mass_limit,
        initial_mass_function=settings.stars_initial_mass_function,
    )
    number_of_stars = len(masses)

    logger.info("%i stars created in group #%i with %i sinks", number_of_stars,
                group_index, number_of_sinks)

    new_stars = Particles(number_of_stars)
    new_stars.age = 0 | units.Myr
    new_stars[0].mass = next_mass
    new_stars[1:].mass = masses[:-1]
    group.group_next_primary_mass = masses[-1]
    new_stars = new_stars.sorted_by_attribute("mass").reversed()

    logger.info("Group's next primary mass is %s",
                group.group_next_primary_mass[0])

    # Create placeholders for attributes of new_stars
    new_stars.position = [0, 0, 0] | units.pc
    new_stars.velocity = [0, 0, 0] | units.kms
    new_stars.origin_cloud = group[0].key
    new_stars.star_forming_radius = 0 | units.pc
    new_stars.star_forming_u = local_sound_speed**2

    # Find the newly removed gas in the group
    removed_gas = Particles()
    if not newly_removed_gas.is_empty():
        for s in group:
            removed_gas_by_this_sink = (
                newly_removed_gas[newly_removed_gas.accreted_by_sink == s.key])
            removed_gas.add_particles(removed_gas_by_this_sink)

    logger.info("%i removed gas found in this group", len(removed_gas))

    # Star forming regions that contain the removed gas and the group
    # of sinks
    if not removed_gas.is_empty():
        removed_gas.radius = removed_gas.h_smooth
    star_forming_regions = group.copy()
    star_forming_regions.density = (
        star_forming_regions.initial_density / 1000
    )  # /1000 to reduce likelihood of forming stars in sinks
    star_forming_regions.accreted_by_sink = star_forming_regions.key
    try:
        star_forming_regions.u = star_forming_regions.u
    except AttributeError:
        star_forming_regions.u = local_sound_speed**2
    star_forming_regions.add_particles(removed_gas.copy())
    star_forming_regions.sorted_by_attribute("density").reversed()

    # Generate a probability list of star forming region indices the
    # stars should associate to
    probabilities = (star_forming_regions.density /
                     star_forming_regions.density.sum())
    probabilities /= probabilities.sum()  # Ensure sum is exactly 1
    logger.info("Max & min probabilities: %s, %s", probabilities.max(),
                probabilities.min())

    logger.info("%i star forming regions", len(star_forming_regions))

    def delta_positions_and_velocities(new_stars, star_forming_regions,
                                       probabilities):
        """
        Assign positions and velocities of stars in the star forming regions
        according to the probability distribution
        """
        number_of_stars = len(new_stars)

        # Create an index list of removed gas from probability list
        sample = numpy.random.choice(len(star_forming_regions),
                                     number_of_stars,
                                     p=probabilities)

        # Assign the stars to the removed gas according to the sample
        star_forming_regions_sampled = star_forming_regions[sample]
        new_stars.position = star_forming_regions_sampled.position
        new_stars.velocity = star_forming_regions_sampled.velocity
        new_stars.origin_cloud = star_forming_regions_sampled.accreted_by_sink
        new_stars.star_forming_radius = star_forming_regions_sampled.radius
        try:
            new_stars.star_forming_u = star_forming_regions_sampled.u
        except AttributeError:
            new_stars.star_forming_u = local_sound_speed**2

        # Random position of stars within the sink radius they assigned to
        rho = (numpy.random.random(number_of_stars) *
               new_stars.star_forming_radius)
        theta = (numpy.random.random(number_of_stars) *
                 (2 * numpy.pi | units.rad))
        phi = (numpy.random.random(number_of_stars) * numpy.pi | units.rad)
        x = (rho * sin(phi) * cos(theta)).value_in(units.pc)
        y = (rho * sin(phi) * sin(theta)).value_in(units.pc)
        z = (rho * cos(phi)).value_in(units.pc)

        X = list(zip(*[x, y, z])) | units.pc

        # Random velocity, sample magnitude from gaussian with local sound
        # speed like Wall et al (2019)
        # temperature = 10 | units.K

        # or (gamma * local_pressure / density).sqrt()
        velocity_magnitude = numpy.random.normal(
            # loc=0.0,  # <- since we already added the velocity of the sink
            scale=new_stars.star_forming_u.sqrt().value_in(units.kms),
            size=number_of_stars,
        ) | units.kms
        velocity_theta = (numpy.random.random(number_of_stars) *
                          (2 * numpy.pi | units.rad))
        velocity_phi = (numpy.random.random(number_of_stars) *
                        (numpy.pi | units.rad))
        vx = (velocity_magnitude * sin(velocity_phi) *
              cos(velocity_theta)).value_in(units.kms)
        vy = (velocity_magnitude * sin(velocity_phi) *
              sin(velocity_theta)).value_in(units.kms)
        vz = (velocity_magnitude * cos(velocity_phi)).value_in(units.kms)

        V = list(zip(*[vx, vy, vz])) | units.kms

        return X, V

    dX, dV = delta_positions_and_velocities(new_stars, star_forming_regions,
                                            probabilities)
    logger.info("Updating new stars...")
    new_stars.position += dX
    new_stars.velocity += dV

    # For Pentacle, this is the PP radius
    new_stars.radius = 0.05 | units.parsec

    # mass_ratio = 1 - new_stars.total_mass()/group.total_mass()
    # group.mass *= mass_ratio

    excess_star_mass = 0 | units.MSun
    for s in group:
        logger.info('Sink mass before reduction: %s', s.mass.in_(units.MSun))
        total_star_mass_nearby = (
            new_stars[new_stars.origin_cloud == s.key]).total_mass()

        # To prevent sink mass becomes negative
        if s.mass > minimum_sink_mass:
            if (s.mass - total_star_mass_nearby) <= minimum_sink_mass:
                excess_star_mass += (total_star_mass_nearby - s.mass +
                                     minimum_sink_mass)
                logger.info('Sink mass goes below %s; excess mass is now %s',
                            minimum_sink_mass.in_(units.MSun),
                            excess_star_mass.in_(units.MSun))
                s.mass = minimum_sink_mass
            else:
                s.mass -= total_star_mass_nearby
        else:
            excess_star_mass += total_star_mass_nearby
            logger.info(
                'Sink mass is already <= minimum mass allowed; '
                'excess mass is now %s', excess_star_mass.in_(units.MSun))

        logger.info('Sink mass after reduction: %s', s.mass.in_(units.MSun))

    # Reduce all sinks in group equally with the excess star mass
    logger.info('Reducing all sink mass equally with excess star mass...')
    mass_ratio = 1 - excess_star_mass / group.total_mass()
    group.mass *= mass_ratio

    logger.info("Total sink mass in group: %s",
                group.total_mass().in_(units.MSun))

    if shrink_sinks:
        group.radius = ((group.mass / group.initial_density) /
                        (4 / 3 * numpy.pi))**(1 / 3)
        logger.info("New radii: %s", group.radius.in_(units.pc))

    return new_stars
Exemple #29
0
def rgb_frame(
    stars,
    dryrun=False,
    vmax=None,
    percentile=0.9995,
    multi_psf=False,
    sourcebands="ubvri",
    image_width=12. | units.parsec,
    image_size=[1024, 1024],
    mapper_factory=None,
    gas=None,
    mapper_code=None,
    zoom_factor=1.0,
    psf_type="hubble",
    psf_sigma=1.0,
    verbose=True,
):

    if gas is None:
        gas = Particles()

    if verbose:
        print("luminosities..")

    for band in sourcebands:
        setattr(
            stars,
            band + "_band",
            4 * numpy.pi * stars.radius**2 * filter_band_flux(
                "bess-" + band + ".pass",
                lambda x: B_lambda(x, stars.temperature),
            ),
        )
    if verbose:
        print("..raw images..")

    if mapper_code != "gridify":
        # Use mapper to make raw (pre-convolved) images
        mapper = mapper_factory()
        stars_in_mapper = mapper.particles.add_particles(stars)
        gas_in_mapper = mapper.particles.add_particles(gas)

        mapper.parameters.projection_direction = [0, 0, 1]
        mapper.parameters.upvector = [0, -1, 0]

        raw_images = dict()
        for band in sourcebands:
            assign_weights_and_opacities(
                band,
                stars_in_mapper,
                gas_in_mapper,
                stars,
                gas,
                Nstar=500,
            )
            # mapper.particles.weight = getattr(
            #         stars,
            #         band+"_band"
            #         ).value_in(units.LSun)
            im = mapper.image.pixel_value
            raw_images[band] = numpy.fliplr(im)

        mapper.stop()
    else:
        # Use simpler python mapping script
        from .gridify import map_to_grid
        stars_in_mapper = stars.copy()
        gas_in_mapper = gas.copy()
        raw_images = dict()

        for band in sourcebands:
            assign_weights_and_opacities(
                band,
                stars_in_mapper,
                gas_in_mapper,
                stars,
                gas,
                Nstar=500,
            )
            allparticles = Particles()
            allparticles.add_particles(stars_in_mapper)
            allparticles.add_particles(gas_in_mapper)
            im = map_to_grid(
                allparticles.x,
                allparticles.y,
                weights=allparticles.weight,
                image_size=image_size,
                image_width=image_width,
            )
            raw_images[band] = im

    convolved_images = dict()

    if verbose:
        print("..convolving..")

    if psf_type == "hubble":
        psf = get_psf(zoom_factor=zoom_factor)
        if multi_psf:
            a = numpy.arange(image_size[0]) / float(image_size[0] - 1)
            b = numpy.arange(image_size[1]) / float(image_size[1] - 1)
            w1 = numpy.outer(a, b)
            w2 = numpy.outer(1. - a, b)
            w3 = numpy.outer(a, 1. - b)
            w4 = numpy.outer(1. - a, 1. - b)
            for key, val in list(raw_images.items()):
                im1 = Convolve(val, psf[key + '0'])
                im2 = Convolve(val, psf[key + '1'])
                im3 = Convolve(val, psf[key + '2'])
                im4 = Convolve(val, psf[key + '3'])
                convolved_images[key] = (w1 * im1 + w2 * im2 + w3 * im3 +
                                         w4 * im4)
        else:
            for key, val in list(raw_images.items()):
                im1 = Convolve(val, psf[key + '0'])
                convolved_images[key] = im1
    elif psf_type == "gaussian":
        for key, val in list(raw_images.items()):
            im1 = gaussian_filter(val, sigma=psf_sigma, order=0)
            convolved_images[key] = im1

    if verbose:
        print("..conversion to rgb")
    filter_data = get_filter_data()
    source = [filter_data['bess-' + x + '.pass'] for x in sourcebands]

    target = [xyz_data['x'], xyz_data['y'], xyz_data['z']]

    conv = ColorConverter(source, target)

    ubv = numpy.array([convolved_images[x] for x in sourcebands])

    xyz = numpy.tensordot(conv.conversion_matrix, ubv, axes=(1, 0))

    conv_xyz_to_lin = XYZ_to_sRGB_linear()

    srgb_l = numpy.tensordot(
        conv_xyz_to_lin.conversion_matrix,
        xyz,
        axes=(1, 0),
    )

    if dryrun or vmax is None:
        flat_sorted = numpy.sort(srgb_l.flatten())
        n = len(flat_sorted)
        vmax = flat_sorted[int(1. - 3 * (1. - percentile) * n)]
        print(("vmax:", vmax))
    if dryrun:
        return vmax

    conv_lin_to_sRGB = sRGB_linear_to_sRGB()

    srgb = conv_lin_to_sRGB.convert(srgb_l / vmax)

    # r = numpy.fliplr(srgb[0, :, :])
    # g = numpy.fliplr(srgb[1, :, :])
    # b = numpy.fliplr(srgb[2, :, :])

    rgb = numpy.zeros(image_size[0] * image_size[1] * 3)
    rgb = rgb.reshape(image_size[0], image_size[1], 3)
    rgb[:, :, 0] = srgb[0, :, :].T
    rgb[:, :, 1] = srgb[1, :, :].T
    rgb[:, :, 2] = srgb[2, :, :].T

    image = dict(
        pixels=rgb,
        size=rgb.size,
    )

    return vmax, image
class MinimalWorkingExample(object):
    def __init__(self,     
                 total_N=16000, #total number of disc particles
                 tend=250. | units.yr, #End time of the simulation
                 Mstar=1. | units.MSun, #Mass of the accreting star
                 dt = 1. | units.yr, #timestep
                 temp = 25. | units.K, #temperature of the ISM
                 v_ism = 3.0 | units.kms, #Velocity of the ISM with respect to the star
                 n_core = 4, #Number of cores used by the community codes
                 mu = 2.3, #mean molecular weight
                 theta = 0., #angle of the disc with respect to the flow, 0 means disc rotation axis is parallel with flow direction
                 n_dens = 5e6 | (units.cm)**(-3.), #Number density of the ism
                 dirname = './'):
        
        self.disc_N = total_N 
        self.tend = tend
        self.Mstar = Mstar
        self.dt = dt
        self.mu = mu * constants.proton_mass
        self.T = temp 
        self.cs = ((temp*constants.kB)/self.mu).sqrt()
#        print "cs=", self.cs.in_(units.kms)
        self.v_ism = v_ism
        self.ism_n_dens = n_dens #number density of the ism
        self.ism_dens = self.mu*self.ism_n_dens #mass density of the ism
        self.converter = nbody_system.nbody_to_si(self.Mstar, 1. | units.AU)
       
        self.disc_angle = numpy.radians(theta)
        self.n_core = n_core 
        self.dirname = dirname
        self.discfraction = 0.01
        self.disc_Rmin = self.converter.to_generic(10.| units.AU).value_in(nbody_system.length)
        self.disc_Rmax = self.converter.to_generic(100.| units.AU).value_in(nbody_system.length)
        self.filename = "DiskWind.h5"
    
        print 'Files will be saved in ', self.dirname


    def initialize_star(self):
        
        self.star=Particles(1)
        self.star.mass=self.Mstar
        self.star.radius= 1. | units.AU
        self.star.x=0.|units.AU
        self.star.y=0.|units.AU
        self.star.z=0.|units.AU
        self.star.vx=0.|units.kms
        self.star.vy=0.|units.kms
        self.star.vz=0.|units.kms


    def initialize_data(self):
        

        self.cylinder_radius = 500. | units.AU 
        self.cylinder_length = 2.*self.cylinder_radius
        self.cylinder_vol = self.cylinder_length*numpy.pi*self.cylinder_radius**2.
        self.sph_particle_dens = self.ism_dens/(0.01*self.Mstar/self.disc_N)
        self.initialize_star()
        self.initialize_ism()


    def initialize_ism(self):

        #specific internal energy of the ism, i.e. internal energy per unit mass
        #In case of an isothermal EOS, Gadget requires the sound-speed squared as input parameter instead of the thermal energy per unit mass
        self.ism_u = self.cs**2.
        
        self.ism_slice_length = self.v_ism*self.dt
        self.ism_slice_vol = self.ism_slice_length*numpy.pi*self.cylinder_radius**2.0
    
        self.ism_slice_mass = self.ism_dens*self.ism_slice_vol
        self.ism_mass = self.ism_dens*self.cylinder_vol
        
        #The x-coordinate of the inflow
        self.offset = self.cylinder_radius 
        
        self.ism_slice_N = int(round(self.sph_particle_dens*self.ism_slice_vol))    
        self.total_N = self.ism_slice_N*(self.cylinder_length/self.ism_slice_length)
        

    def make_slice(self):
    
        new_slice = Particles(self.ism_slice_N)
    
        rho = numpy.sqrt(numpy.random.uniform(0,1,self.ism_slice_N))*self.cylinder_radius.value_in(units.AU)
        phi = numpy.random.uniform(0,2.0*numpy.pi, self.ism_slice_N)
    

        new_slice.x = numpy.random.uniform(self.ism_slice_length.value_in(units.AU), 0, self.ism_slice_N) - self.offset.value_in(units.AU) | units.AU
        new_slice.y = rho*numpy.sin(phi) | units.AU
        new_slice.z = rho*numpy.cos(phi) | units.AU
    
        new_slice.vx = 1000*self.v_ism
        new_slice.vy = 0.0 | units.kms
        new_slice.vz = 0.0 | units.kms    
    
        new_slice.mass = self.ism_slice_mass/self.ism_slice_N
        new_slice.u = self.ism_u

        return new_slice
    

    def create_disc(self):
                
        #The following line makes sure masses for ISM and disc particles are equal:
        self.discfraction = (self.disc_N*(self.ism_slice_mass/self.ism_slice_N))/self.Mstar
        
        T_disc = self.T
        cs_disc = ((T_disc*constants.kB)/self.mu).sqrt()
        densitypower = 1.5
        g2=2-densitypower
        k_out=((1+self.discfraction)/self.disc_Rmax**3)**0.5
        sigma_out=g2*self.discfraction/(2*numpy.pi*self.disc_Rmax**densitypower*(self.disc_Rmax**g2-self.disc_Rmin**g2))
        q_out = self.converter.to_generic(cs_disc).value_in(nbody_system.length/nbody_system.time)/(numpy.pi*sigma_out/k_out)
        
        print "Number of disk particles:", self.disc_N
        
        proto=ProtoPlanetaryDisk(self.disc_N,
                                 convert_nbody=self.converter,
                                 discfraction=self.discfraction,
                                 densitypower=1.5,
                                 thermalpower=0,
                                 Rmin=self.disc_Rmin,
                                 Rmax=self.disc_Rmax,
                                 q_out=q_out)
        disc=proto.result
    
        print "The mass of a disc particle = ", disc.mass[0].value_in(units.kg)
    
        #Rotate 90 degrees with respect to the z-axis and then theta degrees with respect to the y-axis
        
        temp_x = disc[:].x
        temp_y = disc[:].y
        temp_z = disc[:].z
        temp_vx = disc[:].vx
        temp_vy = disc[:].vy
        temp_vz = disc[:].vz
    
    
        disc.x = temp_z*numpy.cos(self.disc_angle) - temp_y*numpy.sin(self.disc_angle)
        disc.y = temp_z*numpy.sin(self.disc_angle) + temp_y*numpy.cos(self.disc_angle)
        disc.z = -temp_x
    
        disc.vx = temp_vz*numpy.cos(self.disc_angle) - temp_vy*numpy.sin(self.disc_angle)
        disc.vy = temp_vz*numpy.sin(self.disc_angle) + temp_vy*numpy.cos(self.disc_angle)
        disc.vz = -temp_vx
             
        return disc

 
    def evolve_model(self):
        self.initialize_data()

        self.ism_code = Gadget2(self.converter, number_of_workers=self.n_core)#, debugger='gdb')
        self.ism_code.parameters.time_max = 1024*self.dt       
        self.ism_code.parameters.n_smooth = 64 
        self.ism_code.parameters.n_smooth_tol = 2./64.   
        self.ism_code.parameters.artificial_viscosity_alpha = 0.1 
        self.ism_code.parameters.epsilon_squared = (1. | units.AU)**2.

        self.all_particles = Particles()
        write_set_to_file(self.star, self.filename, "hdf5", append_to_file=False)
        write_set_to_file(self.all_particles, self.filename, "hdf5", append_to_file=False)
        
        self.initial_disc_particles = self.create_disc()
        self.all_particles.add_particles(self.initial_disc_particles)
        self.ism_code.gas_particles.add_particles(self.initial_disc_particles)
        
        #You can only add a sink after adding gas particles
        #starinsph refers to the corresponding particle set/id in the community code
        starinsph = self.ism_code.dm_particles.add_particles(self.star)
        #Use the build-in sink particle routine from amuse.ext.sink. Sink_radius needs to be defined manually otherwise the particle radius in gadget is taken,
        #which does not corresponding to the particle radius in the framework (since 'particles' in gadget do not have a radius, it is set to 0.01 | generic_unit_system.length
        #and corresponds to the gas gravitational smoothing epsilon.           
        sink = new_sink_particles(starinsph, sink_radius= self.star.radius)
       
        self.channel_from_ismcode_to_framework = self.ism_code.gas_particles.new_channel_to(self.all_particles)
    
        time = 0. | units.yr
    
        while time <= (self.tend+self.dt/2.):
 
 
            print "Adding new slice of ISM..."
            newslice=self.make_slice()
            self.ism_code.gas_particles.add_particles(newslice)
            self.all_particles.add_particles(newslice)

                
            start = timing.time()
            print "======================================================="
            print "Evolving to time = ", time.value_in(units.yr), " of ", self.tend.value_in(units.yr)," years..."    
            self.ism_code.evolve_model(time)
            print "This took ", (timing.time() - start), " s"
            
            out_of_bounds = self.ism_code.gas_particles.select_array(lambda x,y,z:(x > self.cylinder_radius)|((z**2+y**2).sqrt() >= self.cylinder_radius), ["x","y","z"]) 
            if len(out_of_bounds)>0:
                print "Removing ", len(out_of_bounds), " particles from the code because they were out of bounds"
                
                self.ism_code.gas_particles.remove_particles(out_of_bounds)
            
            
            self.ism_code.gas_particles.synchronize_to(self.all_particles)  
            sink.accrete(self.ism_code.gas_particles)

            write_set_to_file(self.star, self.filename, "hdf5")
            write_set_to_file(self.all_particles, self.filename, "hdf5")
            
            time += self.dt
            
        print "======================================================="
        self.ism_code.stop()
Exemple #31
0
def main():
    "Make a star cluster"
    set_printing_strategy(
        "custom",
        preferred_units=[units.MSun, units.parsec, units.yr, units.kms],
        precision=5,
    )
    clustertemplate = "TESTCluster_%08i"

    args = new_argument_parser()
    sinks = args.sinks
    cluster_model_number = args.cluster_model_number
    star_distribution = args.star_distribution
    # gas_distribution = args.gas_distribution
    king_parameter_w0 = args.king_parameter_w0
    fractal_parameter_fd = args.fractal_parameter_fd
    initial_mass_function = args.initial_mass_function.lower()

    number_of_stars = args.number_of_stars
    if args.cluster_mass != 0:
        cluster_mass = args.cluster_mass | units.MSun
    else:
        cluster_mass = False
    upper_mass_limit = args.upper_mass_limit | units.MSun
    lower_mass_limit = args.lower_mass_limit | units.MSun
    effective_radius = args.effective_radius | units.parsec
    metallicity = args.metallicity
    # virial_ratio = args.virial_ratio
    filetype = args.filetype

    # not implemented yet
    # initial_binary_fraction = args.initial_binary_fraction

    np.random.seed(cluster_model_number)

    if not (number_of_stars or cluster_mass or sinks):
        print(
            "no number of stars, cluster mass or origin sinks given, exiting"
        )
        exit()

    if sinks is not None:
        sinks = read_set_from_file(sinks, "amuse")
        stars = Particles()
        for sink in sinks:
            try:
                velocity_dispersion = sink.u.sqrt()
            except AttributeError:
                velocity_dispersion = args.velocity_dispersion | units.kms
            new_stars = new_stars_from_sink(
                sink,
                upper_mass_limit=upper_mass_limit,
                lower_mass_limit=lower_mass_limit,
                default_radius=effective_radius,
                velocity_dispersion=velocity_dispersion,
                initial_mass_function=initial_mass_function,
                # logger=logger,
            )
            stars.add_particles(
                new_stars
            )
    else:
        stars = new_star_cluster(
            stellar_mass=cluster_mass,
            initial_mass_function=initial_mass_function,
            upper_mass_limit=upper_mass_limit,
            lower_mass_limit=lower_mass_limit,
            number_of_stars=number_of_stars,
            effective_radius=effective_radius,
            star_distribution=star_distribution,
            star_distribution_w0=king_parameter_w0,
            star_distribution_fd=fractal_parameter_fd,
            star_metallicity=metallicity,
        )

    print(
        "%i stars generated (%s)"
        % (len(stars), stars.total_mass().in_(units.MSun))
    )

    if args.clustername != "auto":
        clustertemplate = args.clustername + "%s"

    stars_file_exists = True
    sinks_file_exists = True
    N = -1
    while (stars_file_exists or sinks_file_exists):
        N += 1
        starsfilename = (
            clustertemplate % N
            + "-stars." + filetype
        )
        stars_file_exists = os.path.isfile(starsfilename)
        sinksfilename = (
            clustertemplate % N
            + "-sinks." + filetype
        )
        sinks_file_exists = os.path.isfile(sinksfilename)

    write_set_to_file(stars, starsfilename, filetype)
    if sinks is not None:
        write_set_to_file(sinks, sinksfilename, filetype)
Exemple #32
0
def main():
    # Fixed settings
    stellar_evolution = True
    se_code = "SeBa"
    length_unit = units.parsec
    dpi = 600
    percentile = 0.9995  # for determining vmax

    # Parse arguments
    args = new_argument_parser()
    starsfilename = args.starsfilename
    gasfilename = args.gasfilename
    followfilename = args.followfilename
    imagefilename = args.imagefilename
    imagetype = args.imagetype
    vmax = args.vmax if args.vmax > 0 else None
    n_fieldstars = args.n_fieldstars
    filetype = args.filetype
    contours = args.contours
    np.random.seed(args.seed)
    plot_axes = args.plot_axes
    angle_x = args.angle_x | units.deg
    angle_y = args.angle_y | units.deg
    angle_z = args.angle_z | units.deg
    sourcebands = args.sourcebands
    psf_type = args.psf_type.lower()
    psf_sigma = args.psf_sigma
    age = args.age | units.Myr
    image_width = args.width | units.parsec
    pixels = args.pixels
    frames = args.frames
    if followfilename is not None:
        use_com = True
    else:
        use_com = args.use_com
    x_offset = args.x_offset | units.parsec
    y_offset = args.y_offset | units.parsec
    z_offset = args.z_offset | units.parsec
    extinction = args.calculate_extinction

    # Derived settings
    if psf_type not in ["hubble", "gaussian"]:
        print(("Invalid PSF type: %s" % psf_type))
        exit()
    image_size = [pixels, pixels]
    # If the nr of pixels is changed, zoom the PSF accordingly.
    zoom_factor = pixels / 2048.

    if starsfilename:
        stars = read_set_from_file(
            starsfilename,
            filetype,
            close_file=True,
        )
        if stellar_evolution and (age > 0 | units.Myr):
            print((
                "Calculating luminosity/temperature for %s old stars..."
                % (age)
            ))
            evolve_to_age(stars, age, stellar_evolution=se_code)
        if use_com:
            if followfilename is not None:
                followstars = read_set_from_file(
                    followfilename, filetype, close_file=True,
                )
                center_on_these_stars = followstars.get_intersecting_subset_in(
                    stars,
                )
            else:
                center_on_these_stars = stars
            com = center_on_these_stars.center_of_mass()
            x_offset, y_offset, z_offset = com
        stars.x -= x_offset
        stars.y -= y_offset
        stars.z -= z_offset
    else:
        stars = Particles()

    if n_fieldstars:
        minage = 400 | units.Myr
        maxage = 12 | units.Gyr
        fieldstars = new_field_stars(
            n_fieldstars,
            width=image_width,
            height=image_width,
        )
        fieldstars.age = (
            minage
            + (
                np.random.sample(n_fieldstars)
                * (maxage - minage)
            )
        )
        evolve_to_age(fieldstars, 0 | units.yr, stellar_evolution=se_code)
        stars.add_particles(fieldstars)

    if gasfilename:
        gas = read_set_from_file(
            gasfilename,
            filetype,
            close_file=True,
        )
        if use_com:
            if stars.is_empty():
                com = gas.center_of_mass()
                x_offset, y_offset, z_offset = com
        gas.x -= x_offset
        gas.y -= y_offset
        gas.z -= z_offset
        # Gadget and Fi disagree on the definition of h_smooth.
        # For gadget, need to divide by 2 to get the Fi value (??)
        gas.h_smooth *= 0.5
        gas.radius = gas.h_smooth

        # Select only the relevant gas particles (plus a margin)
        minx = (1.1 * -image_width/2)
        maxx = (1.1 * image_width/2)
        miny = (1.1 * -image_width/2)
        maxy = (1.1 * image_width/2)
        gas_ = gas.select(
            lambda x, y:
            x > minx
            and x < maxx
            and y > miny
            and y < maxy,
            ["x", "y"]
        )
        gas = gas_
    else:
        gas = Particles()
    # gas.h_smooth = 0.05 | units.parsec

    converter = nbody_system.nbody_to_si(
        stars.total_mass() if not stars.is_empty() else gas.total_mass(),
        image_width,
    )

    # Initialise figure and axes
    fig = initialise_image(
        dpi=dpi,
        image_size=image_size,
        length_unit=length_unit,
        image_width=image_width,
        plot_axes=plot_axes,
        x_offset=x_offset,
        y_offset=y_offset,
        z_offset=z_offset,
    )
    ax = fig.get_axes()[0]
    xmin, xmax = ax.get_xlim()
    ymin, ymax = ax.get_ylim()

    for frame in range(frames):
        fig = initialise_image(fig)

        if (frame != 0) or (frames == 1):
            if not stars.is_empty():
                rotate(stars, angle_x, angle_y, angle_z)
            if not gas.is_empty():
                rotate(gas, angle_x, angle_y, angle_z)

        image, vmax = make_image(
            stars=stars if not stars.is_empty() else None,
            gas=gas if not gas.is_empty() else None,
            converter=converter,
            image_width=image_width,
            image_size=image_size,
            percentile=percentile,
            calc_temperature=True,
            age=age,
            vmax=vmax,
            sourcebands=sourcebands,
            zoom_factor=zoom_factor,
            psf_type=psf_type,
            psf_sigma=psf_sigma,
            return_vmax=True,
            extinction=extinction,
        )

        if not stars.is_empty():
            ax.imshow(
                image,
                origin='lower',
                extent=[
                    xmin,
                    xmax,
                    ymin,
                    ymax,
                ],
            )
            if contours and not gas.is_empty():
                gascontours = column_density_map(
                    gas,
                    zoom_factor=zoom_factor,
                    image_width=image_width,
                    image_size=image_size,
                )
                gascontours[np.isnan(gascontours)] = 0.0
                vmax = np.max(gascontours) / 2
                # vmin = np.min(image[np.where(image > 0.0)])
                vmin = vmax / 100
                levels = 10**(
                    np.linspace(
                        np.log10(vmin),
                        np.log10(vmax),
                        num=5,
                    )
                )[1:]
                # print(vmin, vmax)
                # print(levels)
                ax.contour(
                    origin='lower',
                    levels=levels,
                    colors="white",
                    linewidths=0.1,
                    extent=[
                        xmin,
                        xmax,
                        ymin,
                        ymax,
                    ],
                )
        else:
            image = column_density_map(
                gas,
                image_width=image_width,
                image_size=image_size,
            )

            ax.imshow(
                image,
                origin='lower',
                extent=[
                    xmin,
                    xmax,
                    ymin,
                    ymax,
                ],
                cmap="gray",
            )

        if frames > 1:
            savefilename = "%s-%06i.%s" % (
                imagefilename if imagefilename is not None else "test",
                frame,
                imagetype,
            )
        else:
            savefilename = "%s.%s" % (
                imagefilename if imagefilename is not None else "test",
                imagetype,
            )
        plt.savefig(
            savefilename,
            dpi=dpi,
        )
Exemple #33
0
def main():
    mode = []

    # Fixed settings
    stellar_evolution = True
    se_code = "SeBa"
    length_unit = units.parsec
    dpi = 600
    percentile = 0.9995  # for determining vmax

    # Parse arguments
    args = new_argument_parser()
    starsfilename = args.starsfilename
    gasfilename = args.gasfilename
    imagefilename = args.imagefilename
    imagetype = args.imagetype
    vmax = args.vmax if args.vmax > 0 else None
    n_fieldstars = args.n_fieldstars
    filetype = args.filetype
    contours = args.contours
    np.random.seed(args.seed)
    plot_axes = args.plot_axes
    angle_x = args.angle_x | units.deg
    angle_y = args.angle_y | units.deg
    angle_z = args.angle_z | units.deg
    sourcebands = args.sourcebands
    psf_type = args.psf_type.lower()
    psf_sigma = args.psf_sigma
    age = args.age | units.Myr
    image_width = args.width | units.parsec
    pixels = args.pixels
    frames = args.frames

    # Derived settings
    if args.calculate_extinction:
        mode.append("extinction")
    if psf_type not in ["hubble", "gaussian"]:
        print(("Invalid PSF type: %s" % psf_type))
        exit()
    image_size = [pixels, pixels]
    # If the nr of pixels is changed, zoom the PSF accordingly.
    zoom_factor = pixels / 2048.

    if starsfilename:
        stars = read_set_from_file(
            starsfilename,
            filetype,
            close_file=True,
        )
        if stellar_evolution and (age > 0 | units.Myr):
            print(("Calculating luminosity/temperature for %s old stars..." %
                   (age)))
            evolve_to_age(stars, age, stellar_evolution=se_code)
        com = stars.center_of_mass()
        stars.position -= com
    else:
        stars = Particles()

    if n_fieldstars:
        minage = 400 | units.Myr
        maxage = 12 | units.Gyr
        fieldstars = new_field_stars(
            n_fieldstars,
            width=image_width,
            height=image_width,
        )
        fieldstars.age = (minage + (np.random.sample(n_fieldstars) *
                                    (maxage - minage)))
        evolve_to_age(fieldstars, 0 | units.yr, stellar_evolution=se_code)
        stars.add_particles(fieldstars)
    if not stars.is_empty():
        mode.append("stars")

    if gasfilename:
        gas = read_set_from_file(
            gasfilename,
            filetype,
            close_file=True,
        )
        if "stars" not in mode:
            com = gas.center_of_mass()
        gas.position -= com
        # Gadget and Fi disagree on the definition of h_smooth.
        # For gadget, need to divide by 2 to get the Fi value (??)
        gas.h_smooth *= 0.5
        gas.radius = gas.h_smooth
    else:
        gas = Particles()
    if not gas.is_empty():
        mode.append("gas")
        if contours:
            mode.append("contours")
    # gas.h_smooth = 0.05 | units.parsec

    converter = nbody_system.nbody_to_si(
        stars.total_mass() if "stars" in mode else gas.total_mass(),
        image_width,
    )

    # Initialise figure and axes
    fig = initialise_image(
        dpi=dpi,
        image_size=image_size,
        length_unit=length_unit,
        image_width=image_width,
        plot_axes=plot_axes,
    )
    ax = fig.get_axes()[0]
    xmin, xmax = ax.get_xlim()
    ymin, ymax = ax.get_ylim()

    for frame in range(frames):
        fig = initialise_image(fig)

        if (frame != 0) or (frames == 1):
            if not stars.is_empty():
                rotate(stars, angle_x, angle_y, angle_z)
            if not gas.is_empty():
                rotate(gas, angle_x, angle_y, angle_z)

        image, vmax = make_image(
            stars,
            gas,
            mode=mode,
            converter=converter,
            image_width=image_width,
            image_size=image_size,
            percentile=percentile,
            calc_temperature=True,
            age=age,
            vmax=vmax,
            sourcebands=sourcebands,
            zoom_factor=zoom_factor,
            psf_type=psf_type,
            psf_sigma=psf_sigma,
            return_vmax=True,
        )

        if "stars" in mode:
            ax.imshow(
                image,
                origin='lower',
                extent=[
                    xmin,
                    xmax,
                    ymin,
                    ymax,
                ],
            )
            if ("contours" in mode) and ("gas" in mode):
                gascontours = column_density_map(
                    gas,
                    zoom_factor=zoom_factor,
                    image_width=image_width,
                    image_size=image_size,
                )
                gascontours[np.isnan(gascontours)] = 0.0
                vmax = np.max(gascontours) / 2
                # vmin = np.min(image[np.where(image > 0.0)])
                vmin = vmax / 100
                levels = 10**(np.linspace(
                    np.log10(vmin),
                    np.log10(vmax),
                    num=5,
                ))[1:]
                # print(vmin, vmax)
                # print(levels)
                ax.contour(
                    gascontours,
                    origin='lower',
                    levels=levels,
                    colors="white",
                    linewidths=0.1,
                    extent=[
                        xmin,
                        xmax,
                        ymin,
                        ymax,
                    ],
                )
        else:
            image = column_density_map(
                gas,
                image_width=image_width,
                image_size=image_size,
            )

            ax.imshow(
                image,
                origin='lower',
                extent=[
                    xmin,
                    xmax,
                    ymin,
                    ymax,
                ],
                cmap="gray",
            )

        plt.savefig(
            "%s-%06i.%s" % (
                imagefilename,
                frame,
                imagetype,
            ),
            dpi=dpi,
        )
Exemple #34
0
class StellarDynamicsCode:
    """Wraps around stellar dynamics code, supports collisions"""
    def __init__(
            self,
            converter=None,
            # star_code=ph4,
            star_code=Petar,
            # star_code=Hermite,
            logger=None,
            handle_stopping_conditions=False,
            # mode="cpu",
            time_offset=0 | nbody_system.time,
            stop_after_each_step=False,
            number_of_workers=8,
            settings=None,
            **kwargs):
        self.__name__ = "StellarDynamics"
        self.logger = logger or logging.getLogger(__name__)
        if settings is None:
            from ekster_settings import settings
            print("WARNING: using default settings!")
            logger.info("WARNING: using default settings!")
        self.settings = settings
        epsilon_squared = settings.epsilon_stars**2
        self.typestr = "Nbody"
        self.star_code = star_code
        try:
            self.namestr = self.star_code.__name__
        except AttributeError:
            self.namestr = "unknown name"
        self.handle_stopping_conditions = \
            handle_stopping_conditions
        self.__current_state = "stopped"
        self.__state = {}
        self.__particles = Particles()
        self.__stop_after_each_step = (stop_after_each_step if self.star_code
                                       is not Petar else False)
        if converter is not None:
            self.unit_converter = converter
        else:
            self.unit_converter = nbody_system.nbody_to_si(
                settings.star_mscale,
                settings.star_rscale,
            )
            # TODO: modify to allow N-body units

        if time_offset is None:
            time_offset = 0. | units.Myr
        self.__time_offset = self.unit_converter.to_si(time_offset)

        self.code = self.new_code(converter=self.unit_converter,
                                  star_code=star_code,
                                  epsilon_squared=epsilon_squared,
                                  number_of_workers=number_of_workers,
                                  **kwargs)
        self.parameters_to_default(star_code=star_code, )
        if self.__stop_after_each_step:
            # self.code.commit_particles()
            self.stop(save_state=True)
            # print("Stopped/saved")
        else:
            self.save_state()

    def new_code(
            self,
            converter=None,
            star_code=Hermite,
            redirection="null",
            mode="cpu",
            number_of_workers=8,
            # handle_stopping_conditions=False,
            **kwargs):
        if hasattr(available_codes, star_code):
            star_code = getattr(available_codes, star_code)
        if star_code is ph4:
            code = star_code(converter,
                             mode=mode,
                             redirection=redirection,
                             number_of_workers=number_of_workers,
                             **kwargs)
        elif star_code is Hermite:
            code = star_code(
                converter,
                number_of_workers=number_of_workers,
                redirection=redirection,
            )
        elif star_code is PhiGRAPE:
            code = star_code(
                converter,
                number_of_workers=number_of_workers,
                redirection=redirection,
            )
        elif star_code is BHTree:
            code = star_code(
                converter,
                redirection=redirection,
            )
        elif star_code is Pentacle:
            code = star_code(
                converter,
                # redirection=redirection,
                redirection="none",
            )
        elif star_code is Petar:
            code = star_code(
                converter,
                mode=mode,
                # redirection=redirection,
                redirection="none",
                # number_of_workers=number_of_workers,
                **kwargs)
        else:
            raise Exception("Code not found: %s" % star_code)
        self.__current_state = "started"
        return code

    def parameters_to_default(
        self,
        star_code=Hermite,
    ):
        "Set default parameters"
        settings = self.settings
        epsilon_squared = settings.epsilon_stars**2
        logger = self.logger
        param = self.code.parameters
        param.epsilon_squared = epsilon_squared
        if star_code is ph4:
            # Set the parameters explicitly to some default
            # param.block_steps = False

            # Force ph4 to synchronise to the exact time requested - important
            # for Bridge!
            param.force_sync = True

            # param.gpu_id = something
            param.initial_timestep_fac = 0.0625
            param.initial_timestep_limit = 0.03125
            # param.initial_timestep_median = 8.0
            # param.manage_encounters = 4
            # # We won't use these stopping conditions anyway
            # param.stopping_condition_maximum_density = some HUGE number
            # param.stopping_condition_maximum_internal_energy = inf
            # param.stopping_condition_minimum_density = - huge
            # param.stopping_condition_minimum_internal_energy = - big number
            # param.stopping_conditions_number_of_steps = 1
            # param.stopping_conditions_out_of_box_size = 0 | units.m
            # param.stopping_conditions_out_of_box_use_center_of_mass = True
            # param.stopping_conditions_timeout = 4.0 | units.s
            # param.sync_time = 0.0 | units.s
            # param.timestep_parameter = 0.0
            # param.total_steps = False
            # param.use_gpu = False
            # param.zero_step_mode = False
        elif star_code is Hermite:
            # Force Hermite to sync to the exact time requested - see
            # force_sync for ph4
            param.end_time_accuracy_factor = 0
        elif star_code is Petar:
            # Set the parameters explicitly to some default
            param.theta = settings.stellar_dynamics_theta
            logger.info("Old r_out value: %s", param.r_out.in_(units.pc))
            param.r_out = settings.stellar_dynamics_r_out
            param.ratio_r_cut = settings.stellar_dynamics_ratio_r_cut
            logger.info("Old r_bin value: %s", param.r_bin.in_(units.pc))
            param.r_bin = settings.stellar_dynamics_r_bin
            # param.r_search_min = 0 | units.pc

            # very small = technically disabled
            param.r_search_min = settings.stellar_dynamics_r_search_min

            param.dt_soft = settings.stellar_dynamics_dt_soft
            # param.dt_soft = self.unit_converter.to_si(
            #     2**-8 | nbody_system.time
            # )
            # settings.timestep_bridge / 4  # 0 | units.Myr
            # param.r_out = 10 * settings.epsilon_stars

            # dt_soft: 9.765625e-06 Myr default: 0.0 Myr
            # epsilon_squared: 0.0001 parsec**2 default: 0.0 parsec**2
            # r_bin: 0.000137167681417 parsec default: 0.0 parsec
            # r_out: 0.00171459601771 parsec default: 0.0 parsec
            # r_search_min: 0.00206443388608 parsec default: 0.0 parsec
            # ratio_r_cut: 0.1 default: 0.1
            #   r_in         = 0.00043686
            #   r_out        = 0.0043686
            #   r_bin        = 0.00034949
            #   r_search_min = 0.0056792
            #   vel_disp     = 0.89469
            #   dt_soft      = 0.00048828

    def evolve_model(self, end_time):
        """
        Evolve model, handle collisions when they occur
        """
        if self.__stop_after_each_step:
            # print("Code will be stopped after each step")
            if self.__current_state == "stopped":
                # print("Code is currently stopped - restarting")
                self.restart()
        result = 0
        time_unit = end_time.unit
        time_fraction = 1 | units.s
        print("START model time: %s -> end_time: %s" % (
            self.model_time.in_(units.Myr),
            end_time.in_(units.Myr),
        ))
        self.logger.info(
            "Starting evolve of %s, model time is %s, end time is %s",
            self.__name__,
            self.model_time.in_(time_unit),
            end_time.in_(time_unit),
        )
        while self.model_time < end_time:
            print("%s < %s, continuing" % (
                self.model_time.in_(time_unit),
                end_time.in_(time_unit),
            ))
            if self.model_time >= (end_time - time_fraction):
                print("but %s >= (%s-%s), not continuing" %
                      (self.model_time.in_(time_unit), end_time.in_(time_unit),
                       time_fraction.in_(time_unit)))
                break
            if not self.code.particles.is_empty():
                print("Starting evolve_model of stellar_dynamics")
                result = self.code.evolve_model(end_time - self.__time_offset)
                print("Finished evolve_model of stellar_dynamics")
            else:
                self.logger.info(
                    "No particles, skipping evolve and readjusting time offset"
                )
                print(
                    "Skipping evolve_model of stellar_dynamics, no particles!")
                self.__time_offset = end_time
                result = 0

        if self.__stop_after_each_step:
            # print("Now stopping code")
            self.stop(save_state=True)
        print("FINISH model time: %s > end_time: %s" % (
            self.model_time.in_(units.Myr),
            end_time.in_(units.Myr),
        ))
        self.logger.info(
            "Finishing evolve of %s, model time is %s, end time is %s",
            self.__name__,
            self.model_time.in_(time_unit),
            end_time.in_(time_unit),
        )
        return result

    @property
    def model_time(self):
        """Return code model_time"""
        if self.__current_state != "stopped":
            time = self.code.model_time + self.__time_offset
            return time
        time = self.__last_time
        return time

    @property
    def particles(self):
        """Return particles"""
        if self.__stop_after_each_step:
            return self.__particles
        # if self.__current_state is not "stopped":
        #     return self.code.particles
        else:
            return self.code.particles

    @property
    def parameters(self):
        """Return code parameters"""
        if self.__current_state != "stopped":
            parameters = self.code.parameters
        else:
            parameters = self.__state["parameters"]
        return parameters

    # TODO: make sure this parameter set is synchronised with code.parameters
    # def parameters(self):
    #     """Return code parameters"""
    #     self.__parameters = self.code.parameters.copy()
    #     return self.__parameters

    @property
    def stopping_conditions(self):
        """Return stopping conditions for dynamics code"""
        return self.code.stopping_conditions

    @property
    def commit_particles(self):
        return self.code.commit_particles

    def get_gravity_at_point(self, *list_arguments, **keyword_arguments):
        """Return gravity at specified point"""
        return self.code.get_gravity_at_point(*list_arguments,
                                              **keyword_arguments)

    def get_potential_at_point(self, *list_arguments, **keyword_arguments):
        """Return potential at specified point"""
        return self.code.get_potential_at_point(*list_arguments,
                                                **keyword_arguments)

    def save_state(self):
        """
        Store current settings
        """
        self.__state["parameters"] = self.code.parameters.copy()
        self.__state["converter"] = self.unit_converter
        self.__state["star_code"] = self.star_code
        self.__state["model_time"] = self.code.model_time
        self.__state["redirection"] = "null"  # FIXME
        self.__state["mode"] = "cpu"  # FIXME
        self.__state["handle_stopping_conditions"] = \
            self.handle_stopping_conditions
        self.__last_time = self.model_time

    def save_particles(self):
        """
        Store the current particleset, but keep the same particleset!
        """
        self.__particles.remove_particles(self.__particles)
        self.__particles.add_particles(self.code.particles)

    def stop_and_restart(self):
        """
        Store current settings and restart gravity code from saved state
        """
        self.stop(save_state=True)
        self.restart()

    def restart(self):
        """
        Restart gravity code from saved state
        """
        # print("Restarting")
        self.code = self.new_code(
            converter=self.__state["converter"],
            star_code=self.__state["star_code"],
            redirection=self.__state["redirection"],
            mode=self.__state["mode"],
            handle_stopping_conditions=self.
            __state["handle_stopping_conditions"],
        )
        self.code.particles.add_particles(self.__particles)
        print(self.__state["parameters"])
        if self.star_code is Petar:
            for name in self.__state["parameters"].names():
                if name != "timestep":
                    setattr(self.code.parameters, name,
                            getattr(self.__state["parameters"], name))
        else:
            self.code.parameters.reset_from_memento(self.__state["parameters"])
        self.__current_state = "restarted"

    def stop(self, save_state=True, **keyword_arguments):
        """Stop code"""
        if save_state:
            self.save_state(**keyword_arguments)
            self.save_particles(**keyword_arguments)
        stopcode = self.code.stop(**keyword_arguments)
        self.__current_state = "stopped"
        return stopcode