88
99import os
1010import warnings
11-
11+ import math
1212import numpy as np
1313from astropy .table import Table
1414
3232def get_vega_data (file ):
3333 """
3434 Load Vega spectrum
35+
36+ :param file: The path to the vega spectrum.
37+ :type file: str
38+ :returns: The wavelength and the flux from the vega spectrum.
39+ :rtype: numpy.array, numpy.array
3540 """
3641 vega = Table .read (file )
37- print (vega )
38- return vega ['WAVELENGTH' ], vega ['FLUX' ]
42+ return np .array (vega ['WAVELENGTH' ]), np .array (vega ['FLUX' ])
3943
4044try :
4145 vega_wavelength , vega_flux = get_vega_data (vega_file )
@@ -77,7 +81,7 @@ def _file_exists(name):
7781 return os .path .exists (name )
7882
7983
80- class GeneralSpectrum (object ):
84+ class Spectrum (object ):
8185 """
8286 General spectrum class
8387 """
@@ -149,14 +153,19 @@ def _wave_range(wb, ws):
149153 return wave_range
150154
151155
152- class StarSpectrum (GeneralSpectrum ):
156+ class StarSpectrum (Spectrum ):
153157 """
154- Load and operate on spectra
158+ StarSpectrum contains the wavelength and the flux of a source.
159+ It can load the data from a file directly or you can give the wavelengths and the fluxes as initial arguments.
160+ Together with :class:`Band` you can calculate the magnitudes from the spectra for different filters
155161
156162 :param file:
157163 indicates the name of a file with the spectrum to load.
158164 It accepts files with the FITS format or plain ASCII
159- with one (flux) or two columns.
165+ with two column. If it is a fits file the wavelength-column must have the name 'Wavelength' and
166+ the flux-column must have the name 'Flux'.
167+ If it is a ascii file, the first column must be the wavelength values and the second column must be
168+ the flux values.
160169 Default is None
161170 :type file: str
162171 :param wavelength: The wavelength as an array if no file is given
@@ -169,29 +178,23 @@ def __init__(self, file=None, wavelength=None, flux=None):
169178 """
170179
171180 """
172- GeneralSpectrum .__init__ (self )
181+ Spectrum .__init__ (self )
173182 self .wavelength = wavelength
174183 self .flux = flux
175184 self ._file = file
176185 self .__load__ ()
177186
178187 def __load__ (self ):
179188 if self ._file :
180- if _file_exists (self ._file ):
189+ if os . path . exists (self ._file ):
181190 f_name , f_extension = os .path .splitext (self ._file )
182- if f_extension == ".fits" or f_extension == ".FITS" :
191+ if '.fit' in f_extension :
183192 self .load_fits (self ._file )
184193 else :
185194 self .load_ascii (self ._file )
186195 else :
187196 warnings .warn ("Warning: Could not find file {} - no spectrum loaded" .format (self ._file ))
188197
189- def reflux (self , theta = None ):
190- """
191- Scale the flux by theta**2
192- """
193- self .flux = self .flux * theta ** 2.
194-
195198 def ap_mag (self , band , mag = 'Vega' , mag_zero = 0. ):
196199 """
197200 Compute an apparent magnitude in a given system
@@ -217,24 +220,27 @@ def ap_mag(self, band, mag='Vega', mag_zero=0.):
217220 r = _wave_range (band .wavelength , self .wavelength )
218221 wr = self .wavelength [r ]
219222 fr = self .flux [r ]
223+ band_interp = band .get_transmission (wr )
224+ band_interp_wr = band_interp * wr
225+ integrated_flux = np .trapz (fr * band_interp_wr , x = wr )
220226 if mag == 'AB' :
221- f = np . trapz ( fr * band ( wr ) * wr , x = wr ) / np .trapz (band ( wr ) / wr , x = wr ) * c
222- return - 2.5 * np .log10 (f ) + ab_zero
227+ f = integrated_flux / np .trapz (band_interp / wr , x = wr ) * c
228+ return - 2.5 * math .log10 (f ) + ab_zero
223229 elif mag == 'ST' :
224- f = np . trapz ( fr * band ( wr ) * wr , x = wr ) / np .trapz (band ( wr ) * wr , x = wr )
225- return - 2.5 * np .log10 (f ) + st_zero
230+ f = integrated_flux / np .trapz (band_interp_wr , x = wr )
231+ return - 2.5 * math .log10 (f ) + st_zero
226232 elif mag == 'Vega' :
227233 vega_r = _wave_range (band .wavelength , vega_wavelength )
228234 vega_wr = vega_wavelength [vega_r ]
229235 vega_fr = vega_flux [vega_r ]
230- f = np . trapz ( fr * band ( wr ) * wr , x = wr )
236+ f = integrated_flux
231237 vega_f = np .trapz (vega_fr * band (vega_wr ) * vega_wr , x = vega_wr )
232- return - 2.5 * np .log10 (f ) + 2.5 * np .log10 (vega_f ) + mag_zero
238+ return - 2.5 * math .log10 (f ) + 2.5 * np .log10 (vega_f ) + mag_zero
233239 else :
234240 raise ValueError ('Magnitude system is not a valid choice, check input string' )
235241
236242
237- class BandPass ( GeneralSpectrum ):
243+ class Band ( Spectrum ):
238244 """
239245 Band passes photometric response curves
240246
@@ -253,10 +259,10 @@ class BandPass(GeneralSpectrum):
253259
254260 def __init__ (self , band = None , wavelength = None , response = None , smt = 'slinear' ):
255261 """
256- Initialize a bandpass
262+ Initialize a band
257263
258264 """
259- GeneralSpectrum .__init__ (self )
265+ Spectrum .__init__ (self )
260266 self .wavelength = wavelength
261267 self .flux = None
262268 self .name = None
@@ -273,22 +279,19 @@ def __init__(self, band=None, wavelength=None, response=None, smt='slinear'):
273279 def _load_ (self , band ):
274280 # Check if input is a band part of our list or an existing file
275281 if band :
276- if band in list_filters :
277- self . load_ascii ( list_filters [ band ])
278- if self . _smt in [ 'linear' , 'nearest' , 'zero' , 'slinear' , 'quadratic' , 'cubic' ]:
279- self . smooth ( kind = self . _smt )
280- else :
281- raise ValueError ( 'Unknown type of smoothing' )
282+ if self . _smt in [ 'linear' , 'nearest' , 'zero' , 'slinear' , 'quadratic' , 'cubic' ] :
283+ if band in list_filters :
284+ self . load_ascii ( list_filters [ band ])
285+
286+ elif _file_exists ( band ) :
287+ self . load_ascii ( band )
282288
283- elif _file_exists (band ):
284- self .load_ascii (band )
285- if self ._smt in ['linear' , 'nearest' , 'zero' , 'slinear' , 'quadratic' , 'cubic' ]:
286- self .smooth (kind = self ._smt )
287289 else :
288- raise ValueError ('Unknown type of smoothing' )
290+ warnings .warn ("Warning: Could not find filter or file {} " .format (band ))
291+ self .smooth (kind = self ._smt )
289292
290293 else :
291- warnings . warn ( "Warning: Could not find filter or file {} " . format ( band ) )
294+ raise ValueError ( 'Unknown type of smoothing' )
292295 elif self .wavelength is not None and self .response is not None :
293296 self .smooth (self ._smt )
294297
@@ -306,23 +309,37 @@ def smooth(self, kind='linear'):
306309 warnings .warn ("Warning: Smoothing requires Scipy, returning a linear interpolation instead." )
307310 self .interpolated_response = lambda w : np .interp (w , self .wavelength , self .response , left = 0. , right = 0. )
308311
309- def __call__ (self , w ):
312+ def __call__ (self , spectra , mag_system = 'AB' ):
313+ """
314+ Returns the magnitude of the spectra in this filter
315+
316+ :param spectra: The spectra
317+ :type spectra: StarSpectrum
318+ :param mag_system: The magnitude system ('Vega', 'AB', 'ST')
319+ :type mag_system: str
320+ :return: The magnitude in the filter
321+ :rtype: float
322+ """
323+ return spectra .ap_mag (self , mag = mag_system )
324+
325+ def get_transmission (self , w ):
310326 """
311327 Returns the interpolated filter curve function for the wavelength range
312328
313329 :param w: The wavelengths of the requested area
314- :type w: numpy.array
330+ :type w: StarSpectrum
315331 :return: The values of the interpolated filter curve for these wavelength
316332 :rtype: numpy.array
317333 """
318334 return self .interpolated_response (w )
319335
320336
321- class BandPassSVO ( BandPass ):
337+ class BandSVO ( Band ):
322338 def __init__ (self , telescope , instrument , filt , smt = 'linear' ):
323339 """
324- A child class of BandPass. It does exactly the same but it will take
325- the filter transmission curves from the SVO web-page directly.
340+ A child class of :class:`Band`. It does exactly the same but it will take
341+ the filter transmission curves from the `SVO <http://svo2.cab.inta-csic.es/svo/theory/fps3/>`_
342+ web-page directly.
326343
327344 :param telescope: The name of the telescope/satellite
328345 :type telescope: str
@@ -333,8 +350,29 @@ def __init__(self, telescope, instrument, filt, smt='linear'):
333350 :param filt: The name of the band
334351 :type filt: str
335352 """
336- BandPass .__init__ (self , smt = smt )
353+ Band .__init__ (self , smt = smt )
337354 filter_curve = svo .get_filter_curve (telescope , instrument , filt )
338355 self .wavelength = filter_curve ['Wavelength' ]
339356 self .response = filter_curve ['Transmission' ]
340357 self .smooth (kind = self ._smt )
358+
359+
360+ class ColorSVO :
361+ """
362+ Class to calculate the photometric color of a spectra. It uses the filter curves from SVO.
363+
364+ :param telescope: The name of the telescope/satellite
365+ :type telescope: str
366+ :param instrument: The name of the instrument
367+ :type instrument: str
368+ :param band1: The name of the first filter
369+ :type band1: str
370+ :param band2: The name of the second filter
371+ :type band2: str
372+ """
373+ def __init__ (self , telescope , instrument , band1 , band2 ):
374+ self .filter1 = BandSVO (telescope , instrument , band1 )
375+ self .filter2 = BandSVO (telescope , instrument , band2 )
376+
377+ def __call__ (self , spec , mag_system = 'AB' ):
378+ return self .filter1 (spec )- self .filter2 (spec )
0 commit comments