1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
|
# -*- coding: utf-8 -*-
# vispy: testskip
# -----------------------------------------------------------------------------
# A Galaxy Simulator based on the density wave theory
# (c) 2012 Ingo Berg
#
# Simulating a Galaxy with the density wave theory
# http://beltoforion.de/galaxy/galaxy_en.html
#
# Python version(c) 2014 Nicolas P.Rougier
# -----------------------------------------------------------------------------
import math
import numpy as np
class Galaxy(object):
""" Galaxy simulation using the density wave theory """
def __init__(self, n=20000):
""" Initialize galaxy """
# Eccentricity of the innermost ellipse
self._inner_eccentricity = 0.8
# Eccentricity of the outermost ellipse
self._outer_eccentricity = 1.0
# Velocity at the innermost core in km/s
self._center_velocity = 30
# Velocity at the core edge in km/s
self._inner_velocity = 200
# Velocity at the edge of the disk in km/s
self._outer_velocity = 300
# Angular offset per parsec
self._angular_offset = 0.019
# Inner core radius
self._core_radius = 6000
# Galaxy radius
self._galaxy_radius = 15000
# The radius after which all density waves must have circular shape
self._distant_radius = 0
# Distribution of stars
self._star_distribution = 0.45
# Angular velocity of the density waves
self._angular_velocity = 0.000001
# Number of stars
self._stars_count = n
# Number of dust particles
self._dust_count = int(self._stars_count * 0.75)
# Number of H-II regions
self._h2_count = 200
# Particles
dtype = [('theta', np.float32),
('velocity', np.float32),
('angle', np.float32),
('m_a', np.float32),
('m_b', np.float32),
('size', np.float32),
('type', np.float32),
('temperature', np.float32),
('brightness', np.float32),
('position', np.float32, 2)]
n = self._stars_count + self._dust_count + 2*self._h2_count
self._particles = np.zeros(n, dtype=dtype)
i0 = 0
i1 = i0 + self._stars_count
self._stars = self._particles[i0:i1]
self._stars['size'] = 3.
self._stars['type'] = 0
i0 = i1
i1 = i0 + self._dust_count
self._dust = self._particles[i0:i1]
self._dust['size'] = 64
self._dust['type'] = 1
i0 = i1
i1 = i0 + self._h2_count
self._h2a = self._particles[i0:i1]
self._h2a['size'] = 0
self._h2a['type'] = 2
i0 = i1
i1 = i0 + self._h2_count
self._h2b = self._particles[i0:i1]
self._h2b['size'] = 0
self._h2b['type'] = 3
def __len__(self):
""" Number of particles """
if self._particles is not None:
return len(self._particles)
return 0
def __getitem__(self, key):
""" x.__getitem__(y) <==> x[y] """
if self._particles is not None:
return self._particles[key]
return None
def reset(self, rad, radCore, deltaAng,
ex1, ex2, sigma, velInner, velOuter):
# Initialize parameters
# ---------------------
self._inner_eccentricity = ex1
self._outer_eccentricity = ex2
self._inner_velocity = velInner
self._outer_velocity = velOuter
self._angular_offset = deltaAng
self._core_radius = radCore
self._galaxy_radius = rad
self._distant_radius = self._galaxy_radius * 2
self.m_sigma = sigma
# Initialize stars
# ----------------
stars = self._stars
R = np.random.normal(0, sigma, len(stars)) * self._galaxy_radius
stars['m_a'] = R
stars['angle'] = 90 - R * self._angular_offset
stars['theta'] = np.random.uniform(0, 360, len(stars))
stars['temperature'] = np.random.uniform(3000, 9000, len(stars))
stars['brightness'] = np.random.uniform(0.05, 0.25, len(stars))
stars['velocity'] = 0.000005
for i in range(len(stars)):
stars['m_b'][i] = R[i] * self.eccentricity(R[i])
# Initialize dust
# ---------------
dust = self._dust
X = np.random.uniform(0, 2*self._galaxy_radius, len(dust))
Y = np.random.uniform(-self._galaxy_radius, self._galaxy_radius,
len(dust))
R = np.sqrt(X*X+Y*Y)
dust['m_a'] = R
dust['angle'] = R * self._angular_offset
dust['theta'] = np.random.uniform(0, 360, len(dust))
dust['velocity'] = 0.000005
dust['temperature'] = 6000 + R/4
dust['brightness'] = np.random.uniform(0.01, 0.02)
for i in range(len(dust)):
dust['m_b'][i] = R[i] * self.eccentricity(R[i])
# Initialise H-II
# ---------------
h2a, h2b = self._h2a, self._h2b
X = np.random.uniform(-self._galaxy_radius, self._galaxy_radius,
len(h2a))
Y = np.random.uniform(-self._galaxy_radius, self._galaxy_radius,
len(h2a))
R = np.sqrt(X*X+Y*Y)
h2a['m_a'] = R
h2b['m_a'] = R + 1000
h2a['angle'] = R * self._angular_offset
h2b['angle'] = h2a['angle']
h2a['theta'] = np.random.uniform(0, 360, len(h2a))
h2b['theta'] = h2a['theta']
h2a['velocity'] = 0.000005
h2b['velocity'] = 0.000005
h2a['temperature'] = np.random.uniform(3000, 9000, len(h2a))
h2b['temperature'] = h2a['temperature']
h2a['brightness'] = np.random.uniform(0.005, 0.010, len(h2a))
h2b['brightness'] = h2a['brightness']
for i in range(len(h2a)):
h2a['m_b'][i] = R[i] * self.eccentricity(R[i])
h2b['m_b'] = h2a['m_b']
def update(self, timestep=100000):
""" Update simulation """
self._particles['theta'] += self._particles['velocity'] * timestep
P = self._particles
a, b = P['m_a'], P['m_b']
theta, beta = P['theta'], -P['angle']
alpha = theta * math.pi / 180.0
cos_alpha = np.cos(alpha)
sin_alpha = np.sin(alpha)
cos_beta = np.cos(beta)
sin_beta = np.sin(beta)
P['position'][:, 0] = a*cos_alpha*cos_beta - b*sin_alpha*sin_beta
P['position'][:, 1] = a*cos_alpha*sin_beta + b*sin_alpha*cos_beta
D = np.sqrt(((self._h2a['position'] -
self._h2b['position'])**2).sum(axis=1))
S = np.maximum(1, ((1000-D)/10) - 50)
self._h2a['size'] = 2.0*S
self._h2b['size'] = S/6.0
def eccentricity(self, r):
# Core region of the galaxy. Innermost part is round
# eccentricity increasing linear to the border of the core.
if r < self._core_radius:
return 1 + (r / self._core_radius) * (self._inner_eccentricity-1)
elif r > self._core_radius and r <= self._galaxy_radius:
a = self._galaxy_radius - self._core_radius
b = self._outer_eccentricity - self._inner_eccentricity
return self._inner_eccentricity + (r - self._core_radius) / a * b
# Eccentricity is slowly reduced to 1.
elif r > self._galaxy_radius and r < self._distant_radius:
a = self._distant_radius - self._galaxy_radius
b = 1 - self._outer_eccentricity
return self._outer_eccentricity + (r - self._galaxy_radius) / a * b
else:
return 1
|