33
44import matplotlib .pyplot as plt
55import numpy as np
6- from astropy import constants as const
6+ from astropy import constants
77from astropy import units as u
88from astropy .coordinates import SkyCoord
99from astropy import coordinates as coord
1414
1515from .normalization import normalize_spectrum_general
1616
17+ SOL_kms = constants .c .value / 1000
18+
1719
1820def datetime2jd (datetime = '2018-10-24T05:07:06.0' , format = "isot" , tz_correction = 8 ):
1921 jd = Time (datetime , format = format ).jd - tz_correction / 24.
@@ -35,7 +37,7 @@ def eval_ltt(ra=180., dec=40., jd=2456326.4583333, site=None):
3537 return ltt_helio .jd
3638
3739
38- def debad (wave , fluxnorm , nsigma = (3 , 6 ), mfarg = 21 , gfarg = (51 , 9 ), maskconv = 7 , maxiter = 10 ):
40+ def debad (wave , fluxnorm , nsigma = (4 , 8 ), mfarg = 21 , gfarg = (51 , 9 ), maskconv = 7 , maxiter = 3 ):
3941 """
4042 Parameters
4143 ----------
@@ -47,17 +49,16 @@ def debad(wave, fluxnorm, nsigma=(3, 6), mfarg=21, gfarg=(51, 9), maskconv=7, ma
4749 lower & upper sigma levels
4850 mfarg:
4951 median filter width / pixel
50- gkarg :
52+ gfarg :
5153 Gaussian filter length & width / pixel
5254 maskconv:
5355 mask convolution --> cushion
5456 maxiter:
5557 max iteration
5658
57- Return:
58- -------
59+ Return
60+ ------
5961 fluxnorm
60-
6162 """
6263 npix = len (fluxnorm )
6364 indclip = np .zeros_like (fluxnorm , dtype = bool )
@@ -90,12 +91,14 @@ def debad(wave, fluxnorm, nsigma=(3, 6), mfarg=21, gfarg=(51, 9), maskconv=7, ma
9091
9192class MrsSpec :
9293 """ MRS spectrum """
94+ name = ""
9395 # original quantities
9496 wave = np .array ([], dtype = np .float )
9597 flux = np .array ([], dtype = np .float )
9698 ivar = np .array ([], dtype = np .float )
9799 mask = np .array ([], dtype = np .bool ) # True for problematic
98100 flux_err = np .array ([], dtype = np .float )
101+ indcr = np .array ([], dtype = np .float ) # cosmic ray index
99102
100103 # normalized quantities
101104 flux_norm = np .array ([], dtype = np .float )
@@ -225,7 +228,7 @@ def from_hdu(hdu=None, norm_type=None, **norm_kwargs):
225228 wave = 10 ** spec ["LOGLAM" ].data
226229 flux = spec ["FLUX" ].data
227230 ivar = spec ["IVAR" ].data
228- mask = spec ["ORMASK" ].data > 0 # use ormask for coadded spec
231+ mask = spec ["ORMASK" ].data # use ormask for coadded spec
229232 info = dict (name = hdu .header ["EXTNAME" ],
230233 lmjmlist = hdu .header ["LMJMLIST" ], # not universal
231234 snr = np .float (hdu .header ["SNR" ]),
@@ -235,7 +238,7 @@ def from_hdu(hdu=None, norm_type=None, **norm_kwargs):
235238 wave = 10 ** spec ["LOGLAM" ].data
236239 flux = spec ["FLUX" ].data
237240 ivar = spec ["IVAR" ].data
238- mask = spec ["PIXMASK" ].data > 0 # use pixmask for epoch spec
241+ mask = spec ["PIXMASK" ].data # use pixmask for epoch spec
239242 info = dict (name = hdu .header ["EXTNAME" ],
240243 lmjm = np .int (hdu .header ["LMJM" ]),
241244 exptime = np .float (hdu .header ["EXPTIME" ]),
@@ -263,8 +266,8 @@ def from_lrs(fp_lrs, norm_type="poly", **norm_kwargs):
263266 obsid = hdr ["OBSID" ],
264267 ra = hdr ["RA" ],
265268 dec = hdr ["DEC" ],
266- rv = hdr ["Z" ] * const . c . value / 1000. ,
267- rv_err = hdr ["Z_ERR" ] * const . c . value / 1000. ,
269+ rv = hdr ["Z" ] * SOL_kms ,
270+ rv_err = hdr ["Z_ERR" ] * SOL_kms ,
268271 subclass = hdr ["SUBCLASS" ],
269272 tsource = hdr ["TSOURCE" ],
270273 snr = hdr ["SNRG" ],
@@ -316,7 +319,7 @@ def wave_rv(self, rv=None):
316319 """
317320 if rv is None :
318321 rv = self .rv
319- return self .wave / (1 + rv * 1000 / const . c . value )
322+ return self .wave / (1 + rv / SOL_kms )
320323
321324 def plot (self ):
322325 plt .plot (self .wave , self .flux )
@@ -333,6 +336,100 @@ def plot_err(self):
333336 def plot_norm_err (self ):
334337 plt .plot (self .wave , self .flux_norm_err )
335338
339+ def reduce (self , wave_new = None , rv = 0 , npix_cushion = 50 , cr = True , nsigma = (4 , 8 ), maxiter = 5 ,
340+ norm_type = "spline" , niter = 3 ):
341+ """
342+
343+ Parameters
344+ ----------
345+ wave_new:
346+ if specified, spectrum is interpolated to wave_new
347+ rv:
348+ if specified, radial velocity is corrected
349+ npix_cushion: int
350+ if speficied, cut the two ends
351+ cr:
352+ if True, remove cosmic rays using the *debad* function
353+ nsigma:
354+ sigma levels used in removing cosmic rays
355+ maxiter:
356+ max number of iterations used in removing cosmic rays
357+ norm_type:
358+ "spline" | None
359+ niter:
360+ number iterations in normalization
361+
362+ Returns
363+ -------
364+ wave_new, flux_norm, flux_norm_err
365+ """
366+ # determine the chunk range
367+ if npix_cushion > 0 :
368+ npix0 = npix_cushion
369+ npix1 = - npix_cushion
370+ else :
371+ npix0 = 0
372+ npix1 = len (self .wave )
373+
374+ # cut spectrum
375+ wave_obs = self .wave [npix0 :npix1 ]
376+ flux_err = self .flux_err [npix0 :npix1 ]
377+ mask = self .mask [npix0 :npix1 ] > 0
378+ # remove cosmic rays if cr is True
379+ if cr :
380+ flux_obs = debad (self .wave , self .flux , nsigma = nsigma , maxiter = maxiter )[npix0 :npix1 ]
381+ indcr = (np .abs (flux_obs - self .flux [npix0 :npix1 ]) > 1e-5 ) * 1
382+ else :
383+ flux_obs = self .flux [npix0 :npix1 ]
384+ indcr = np .zeros (flux_obs .shape , dtype = int )
385+
386+ # use new wavelength grid if wave_new is specified
387+ wave_obsz0 = wave_obs / (1 + rv / SOL_kms )
388+ if wave_new is None :
389+ wave_new = wave_obs
390+ flux_obs = np .interp (wave_new , wave_obsz0 , flux_obs )
391+ flux_err = np .interp (wave_new , wave_obsz0 , flux_err )
392+ mask = 1 * (np .interp (wave_new , wave_obsz0 , mask ) > 0 )
393+
394+ msr = MrsSpec ()
395+ msr .wave = wave_new
396+ msr .flux = flux_obs
397+ msr .ivar = flux_err ** - 2
398+ msr .flux_err = flux_err
399+ msr .mask = mask
400+ msr .indcr = indcr
401+ msr .name = self .name
402+ msr .isempty = self .isempty
403+
404+ # other information (optional)
405+ msr .info = self .info
406+ msr .rv = self .rv
407+
408+ # time and position info
409+ msr .filename = self .filename
410+ msr .snr = self .snr
411+ msr .exptime = self .exptime
412+ msr .lmjm = self .lmjm
413+ msr .lmjmlist = self .lmjmlist
414+ msr .obsid = self .obsid
415+ msr .seeing = self .seeing
416+ msr .lamplist = self .lamplist
417+ msr .ra = self .ra
418+ msr .dec = self .dec
419+ msr .fibertype = self .fibertype
420+ msr .fibermask = self .fibermask
421+ msr .jdbeg = self .jdbeg
422+ msr .jdend = self .jdend
423+ msr .jdmid = self .jdmid
424+ msr .jdltt = self .jdltt
425+ msr .hjdmid = self .hjdmid
426+
427+ # normalize spectrum if norm_type is specified
428+ if norm_type is not None :
429+ msr .normalize (norm_type = norm_type , niter = niter )
430+
431+ return msr
432+
336433
337434class MrsEpoch :
338435 """ MRS epoch spcetrum """
@@ -480,7 +577,7 @@ def wave_rv(self, rv=None):
480577 """
481578 if rv is None :
482579 rv = self .rv
483- return self .wave / (1 + rv * 1000 / const . c . value )
580+ return self .wave / (1 + rv / SOL_kms )
484581
485582 def flux_norm_dbd (self , ** kwargs ):
486583 """ return fixed flux_norm """
@@ -501,6 +598,54 @@ def plot_err(self):
501598 def plot_norm_err (self ):
502599 plt .plot (self .wave , self .flux_norm_err )
503600
601+ def plot_reduce (self ):
602+ for i in range (self .nspec ):
603+ msr = self .speclist [i ].reduce (norm_type = None )
604+ msr .plot ()
605+
606+ def plot_norm_reduce (self ):
607+ for i in range (self .nspec ):
608+ msr = self .speclist [i ].reduce (norm_type = "spline" )
609+ msr .plot_norm ()
610+
611+ def reduce (self , norm_type = "spline" , niter = 3 ):
612+ """
613+
614+ Parameters
615+ ----------
616+ norm_type:
617+ type of normalization
618+ niter:
619+ number of iteration in normalization
620+
621+ Returns
622+ -------
623+ mer: MrsEpoch
624+ reduced epoch spectrum
625+
626+ """
627+ mer = MrsEpoch ([_ .reduce () for _ in self .speclist ], specnames = self .specnames , norm_type = norm_type , niter = niter )
628+ # header info
629+ mer .epoch = self .epoch
630+ mer .lmjm = self .lmjm
631+ mer .snr = self .snr
632+ mer .rv = self .rv
633+ # time and position info
634+ mer .filename = self .filename
635+ mer .obsid = self .obsid
636+ mer .seeing = self .seeing
637+ mer .ra = self .ra
638+ mer .dec = self .dec
639+ mer .fibertype = self .fibertype
640+ mer .fibermask = self .fibermask
641+ mer .jdbeg = self .jdbeg
642+ mer .jdend = self .jdend
643+ mer .jdmid = self .jdmid
644+ mer .jdltt = self .jdltt
645+ mer .jdmid_delta = self .jdmid_delta
646+ mer .hjdmid = self .hjdmid
647+ return mer
648+
504649 @property
505650 def exptime (self ):
506651 return np .array ([_ .exptime for _ in self .speclist ])
@@ -775,11 +920,14 @@ def test_meta():
775920
776921
777922if __name__ == "__main__" :
923+ import os
778924 os .chdir ("/Users/cham/PycharmProjects/laspec/laspec/" )
779925 fp_lrs = "./data/KIC8098300/DR6_low/spec-57287-KP193637N444141V03_sp10-161.fits.gz"
780926 fp_mrs = "./data/KIC8098300/DR7_medium/med-58625-TD192102N424113K01_sp12-076.fits.gz"
927+ import glob
781928 fps = glob .glob ("./data/KIC8098300/DR7_medium/*.fits.gz" )
782929 # read fits
930+ from laspec .mrs import MrsFits , MrsSpec , MrsEpoch , MrsSource
783931 mf = MrsFits (fp_mrs )
784932
785933 # print info
@@ -803,17 +951,25 @@ def test_meta():
803951 # a short way of doing this:
804952 me = mf .get_one_epoch (84420148 )
805953 print (me )
806- me = mf .get_one_epoch ("COADD" )
954+ me = mf .get_one_epoch ("COADD" , norm_type = "spline" )
807955 print (me , me .snr )
808956 mes = mf .get_all_epochs (including_coadd = False )
809957 print (mes )
810958
811959 msrc = MrsSource (mes )
812960 msrc1 = MrsSource .read (fps )
813961
962+ import matplotlib .pyplot as plt
814963 fig = plt .figure ()
815- plt .plot (me .wave , me .flux_norm )
964+ me .plot_norm ()
965+ me .plot_norm_reduce ()
816966
967+ print (me , me .reduce ())
817968 # test lrs
818969 ls = MrsSpec .from_lrs (fp_lrs )
819970 ls .snr
971+
972+ # test reduce
973+ fig = plt .figure ()
974+ msr = msB .reduce ()
975+ msr .plot_norm ()
0 commit comments