User:Geek3/Cosmos-animation
Jump to navigation
Jump to search
Cosmos-animation is a python script to create schematic animations of fixed-size galaxies in an expanding space. Different models are implemented according to the Friedmann equations.
Code[edit]
The python script generates an ensemble of randomly placed dots to represent galaxies. Their distances are then scaled with a time-varying parameter.
- Drawing is done with the cairo library.
- The mathematics to solve the differential equations is done with scipy.
- For image format conversion the convert command of ImageMagick is used.
- The animations are assembled with gifsicle.
source code (132 lines) |
---|
#!/usr/bin/python3
# -*- coding: utf8 -*-
# Python script from http://commons.wikimedia.org/wiki/User:Geek3/Cosmos-animation
# Creates animations of galaxies in a universe evolving according to the http://en.wikipedia.org/wiki/Friedmann_equations
try:
import cairo as C
except ImportError:
print('You need to install the cairo library')
exit(1)
try:
import scipy.optimize as op
except ImportError:
print('You need to install SciPy: http://scipy.org/Download')
exit(1)
import os
import random
from scipy.integrate import odeint
from math import *
width, height = 220, 160
cx, cy = (width - 1) / 2, (height - 1) / 2
bgcolor = (1, 1, 1)
circlecolor = (0.3, 0.3, 0.3)
radius = 5
models = []
def a_static_universe(t):
# Steady state solution http://en.wikipedia.org/wiki/Static_universe
return 1.
models.append({'name':'Cosmos-animation_Static', 'a':a_static_universe,
'steps':1, 'tmax':0, 'a0':1., 'ngalaxies':80})
def a_empty_universe(t):
# Evolution of an empty universe, Omega=0
return t
models.append({'name':'Cosmos-animation_Empty', 'a':a_empty_universe,
'steps':80, 'tmax':1, 'a0':a_empty_universe(1./79.), 'ngalaxies':8000})
def a_De_Sitter(t):
# Omega_m=0, Omega_r=0, k=0, Lambda=1, http://en.wikipedia.org/wiki/De_Sitter_universe
return exp(t)
models.append({'name':'Cosmos-animation_De-Sitter', 'a':a_De_Sitter,
'steps':80, 'tmax':3.5, 'a0':1., 'ngalaxies':5000})
def a_Einstein_de_Sitter(t):
# Omega_m=1, Omega_r=0, k=0, Lambda=0, http://en.wikipedia.org/wiki/Einstein–de_Sitter_universe
return t**(2./3.)
models.append({'name':'Cosmos-animation_Einstein-De-Sitter', 'a':a_Einstein_de_Sitter,
'steps':80, 'tmax':1, 'a0':a_Einstein_de_Sitter(1./79.), 'ngalaxies':1500})
def a_Friedmann_open(t):
# Omega_m<1, Omega_r=0, k=-1, Lambda=0
psi = op.brentq(lambda p: sinh(p) - p - t, 0, 5)
return cosh(psi) - 1.0
models.append({'name':'Cosmos-animation_Friedmann-open', 'a':a_Friedmann_open,
'steps':80, 'tmax':2, 'a0':a_Friedmann_open(2./79.), 'ngalaxies':1500})
def a_Friedmann_closed(t):
# Omega_m>1, Omega_r=0, k=1, Lambda=0
psi = op.brentq(lambda p: p - sin(p) - t, 0, 2 * pi)
return 1.0 - cos(psi)
models.append({'name':'Cosmos-animation_Friedmann-closed', 'a':a_Friedmann_closed,
'steps':80, 'tmax':2*pi, 'a0':a_Friedmann_closed(2*pi/79), 'ngalaxies':500})
def a_Friedmann_radiation_dominated(t):
# Omega_m=0, Omega_r=1, k=0, Lambda=0
return sqrt(t)
models.append({'name':'Cosmos-animation_Friedmann-radiation', 'a':a_Friedmann_radiation_dominated,
'steps':80, 'tmax':1, 'a0':a_Einstein_de_Sitter(1/79), 'ngalaxies':1000})
def a_lambda_CDM(t):
# Omega_m=0.3, Omega_r=0, k=0, Lambda=0.7, http://en.wikipedia.org/wiki/Lambda-CDM_model
return odeint(lambda y, t0: (.3/y + .7*y**2)**.5, 1e-8, [0, t])[1,0]
models.append({'name':'Cosmos-animation_Lambda-CDM', 'a':a_lambda_CDM,
'steps':80, 'tmax':2, 'a0':a_lambda_CDM(2./79.), 'ngalaxies':2000})
def a_bouncing_universe(t):
# Omega_m=0.5, Omega_r=0, k=1.3, Lambda=0.8
return odeint(lambda y, t0: (.5/y + .8*y**2 - 1.3)**.5, 1+1e-7, [0, fabs(t-6)])[1,0]
models.append({'name':'Cosmos-animation_Bouncing', 'a':a_bouncing_universe,
'steps':80, 'tmax':12., 'a0':1., 'ngalaxies':400})
for model in models:
galaxies = [(width * random.random() - 0.5, height * random.random() - 0.5)
for i in range(model['ngalaxies'])]
for frame in range(model['steps']):
if (model['steps'] > 1):
t = frame / (model['steps'] - 1) * model['tmax']
else:
t = model['tmax']
a = model['a'](t) / model['a0']
# create an image
surf = C.ImageSurface(C.FORMAT_RGB24, width, height)
ctx = C.Context(surf)
# background
ctx.new_path()
ctx.set_source_rgb(*bgcolor)
ctx.rectangle(0, 0, width, height)
ctx.fill()
if (a < 1e-6):
ctx.new_path()
ctx.set_source_rgb(*circlecolor)
ctx.rectangle(0, 0, width, height)
ctx.fill()
else:
# draw individual galaxies
for x0, y0 in galaxies:
x = cx + (x0 - cx) * a
y = cy + (y0 - cy) * a
ctx.new_path()
ctx.set_source_rgb(*circlecolor)
ctx.arc(x, y, radius, 0, 2*pi)
ctx.fill() # stroke current path
# save as PNG
ofname = model['name'] + '_{:0>2d}'.format(frame)
surf.write_to_png(ofname + '.png')
os.system('convert ' + ofname + '.png ' + ofname + '.gif && rm ' + ofname + '.png')
os.system('gifsicle -d5 -l0 --colors 256 --careful ' + model['name'] + '_*.gif > ' + model['name'] + '.gif')
os.system('rm ' + model['name'] + '_*.gif')
|
Images created with this script[edit]
-
Closed Friedmann universe
-
Radiation dominated Friedmann universe
-
Empty universe
-
Open Friedmann universe