source: trunk/skygenerator.py@ 17

Last change on this file since 17 was 17, checked in by JohnLightfoot, 10 years ago

initial import

File size: 5.9 KB
Line 
1from __future__ import absolute_import
2
3import collections
4import math
5import numpy as np
6import scipy.constants as sc
7
8def black_body(temperature, wavenumber):
9 """Function to calculate Planck function.
10 temperature - Kelvin
11 wavenumber - frequency in cm-1
12 """
13 freq = wavenumber * sc.c * 100.0
14 jnu = 2.0 * sc.h * pow(freq,3) / (pow(sc.c,2) *
15 (math.exp((sc.h * freq) / (sc.k * temperature)) - 1.0))
16
17 return jnu
18
19
20class SkyGenerator(object):
21 """Class to generate a model sky.
22 """
23
24 def __init__(self, parameters, previous_results):
25 self.parameters = parameters
26 self.previous_results = previous_results
27 self.result = collections.OrderedDict()
28
29 def run(self):
30 print 'SkyGenerator.run'
31
32 fts = self.previous_results['fts']
33 frequency_axis = fts['fts_wn']
34 nspec = len(frequency_axis)
35
36 beamsgenerator = self.previous_results['beamsgenerator']
37 npix = beamsgenerator['npix']
38 spatial_axis = beamsgenerator['spatial axis [arcsec]']
39
40 # oversampling factor
41# oversample = 10
42 oversample = 1
43
44# print 'creating sky model with spatial dims [%s,%s] spectral dim %s',\
45# (oversample * npix, oversample * npix, nspec)
46# print 'spatial oversampling: %s' % oversample
47 skymodel = np.zeros([npix, npix, nspec], np.float)
48
49 sky = self.parameters['substages']['Sky']
50 columns = sky['SourceNum'].keys()
51
52 self.result['sources'] = collections.OrderedDict()
53
54 for column in columns:
55 temp = sky['SourceNum'][column]
56 sourcenum = int(round(temp))
57 if sourcenum not in self.result['sources'].keys():
58 self.result['sources'][sourcenum] = {}
59
60 type = sky['Type'][column]
61
62 temp = sky['x pos [asec]'][column]
63 xpos = float(temp)
64
65 temp = sky['y pos [asec]'][column]
66 ypos = float(temp)
67
68 temp = sky['Temp'][column]
69 temperature = float(temp)
70
71 temp = sky['cutoffmin'][column]
72 cutoffmin = float(temp)
73
74 temp = sky['cutoffmax'][column]
75 cutoffmax = float(temp)
76
77 temp = sky['emissivity'][column]
78 emissivity = float(temp)
79
80 print 'generating source:%s type:%s xpos:%s ypos:%s temperature:%s cutoffmin:%s cutoffmax:%s e:%s' % (
81 sourcenum, type, xpos, ypos, temperature, cutoffmin, cutoffmax,
82 emissivity)
83
84 if type.upper().strip() == 'POINT':
85 print 'creating point source'
86 source_spectrum = self._create_point_source(xpos, ypos,
87 temperature,
88 cutoffmin, cutoffmax, emissivity, skymodel,
89 spatial_axis, frequency_axis)
90 else:
91 source_spectrum = None
92 print "source type '%s' not yet implemented" % type
93
94 self.result['sources'][sourcenum]['spectrum'] = source_spectrum
95
96 print 'sources', self.result['sources']
97 self.result['sky model'] = skymodel
98 self.result['spatial axis'] = spatial_axis
99 self.result['frequency axis'] = frequency_axis
100
101 return self.result
102
103 def _create_point_source(self, xpos, ypos, temperature, cutoffmin,
104 cutoffmax, emissivity, skymodel, spatial_axis, frequency_axis):
105 """Create a point source.
106 """
107
108 # calculate xpos, ypos in units of pixel - numpy arrays [row,col]
109 nx = len(spatial_axis)
110 colpos = float(nx-1) * float (xpos - spatial_axis[0]) / (spatial_axis[-1] - spatial_axis[0])
111 rowpos = float(nx-1) * float (ypos - spatial_axis[0]) / (spatial_axis[-1] - spatial_axis[0])
112
113 if colpos < 0 or colpos > (nx-1) or rowpos < 0 or rowpos > (nx-1):
114 # point source is outside modelled area
115 return
116
117 # calculate fourier phase shift to move point at [0,0] to [rowpos, colpos]
118 shiftx = np.zeros([nx], np.complex)
119 shiftx[:nx/2] = np.arange(nx/2, dtype=np.complex)
120 shiftx[nx/2:] = np.arange(-nx/2, 0, dtype=np.complex)
121 shiftx = np.exp((-2.0j * np.pi * colpos * shiftx) / float(nx))
122
123 shifty = np.zeros([nx], np.complex)
124 shifty[:nx/2] = np.arange(nx/2, dtype=np.complex)
125 shifty[nx/2:] = np.arange(-nx/2, 0, dtype=np.complex)
126 shifty = np.exp((-2.0j * np.pi * rowpos * shifty) / float(nx))
127
128 shift = np.ones([nx,nx], np.complex)
129 for j in range(nx):
130 shift[j,:] *= shiftx
131 for i in range(nx):
132 shift[:,i] *= shifty
133
134 # calculate black-body spectrum, modified for cutoffs in
135 # sensitivity and source emissivity
136 bbmod = np.zeros(np.shape(frequency_axis))
137 print 'frequency axis', frequency_axis
138 # ignore floating point errors
139 old_settings = np.seterr(all='ignore')
140 for iwn,wn in enumerate(frequency_axis):
141 # simulate real-life 'rounded' cutoffs numerically
142 f1 = 1.0 / (1.0 + pow(cutoffmin/wn, 18) + pow(wn/cutoffmax, 24))
143 print pow(cutoffmin/wn,18), pow(wn/cutoffmax,24)
144 print temperature, wn, black_body(temperature, wn), f1, emissivity
145 bbmod[iwn] = black_body(temperature, wn) * f1 * emissivity
146 # restore fp behaviour
147 ignore = np.seterr(**old_settings)
148
149 # go through freq planes and add point source to each
150 for iwn,wn in enumerate(frequency_axis):
151 # create point in frequency space
152 temp = np.zeros([nx,nx])
153 temp[0,0] = bbmod[iwn]
154 # 2d fft
155 temp = np.fft.fft2(temp)
156 # apply phase shift to move point to required offset
157 temp *= shift
158 # transform back
159 temp = np.fft.ifft2(temp)
160 temp = np.real(temp)
161
162 # add to sky model
163 skymodel[:,:,iwn] += temp
164
165 return bbmod
166
167 def __repr__(self):
168 return 'SkyGenerator'
169
Note: See TracBrowser for help on using the repository browser.