source: trunk/skygenerator.py@ 38

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

TestLine added

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