示例#1
0
    def MasterBias(self, fitsdict, det):
        """
        Generate Master Bias frame for a given detector

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files
        det : int
          Index of the detector

        Returns
        -------
        boolean : bool
          Should other ScienceExposure classes be updated?
        """

        # If the master bias is already made, use it
        if self._msbias[det - 1] is not None:
            msgs.info("An identical master {0:s} frame already exists".format(
                settings.argflag['bias']['useframe']))
            return False
        elif settings.argflag['bias']['useframe'] in ['bias', 'dark']:
            try:
                msbias = armasters.get_master_frame(self, "bias")
            except IOError:
                msgs.info("Preparing a master {0:s} frame".format(
                    settings.argflag['bias']['useframe']))
                # Get all of the bias frames for this science frame
                ind = self._idx_bias
                # Load the Bias/Dark frames
                frames = arload.load_frames(
                    fitsdict,
                    ind,
                    det,
                    frametype=settings.argflag['bias']['useframe'])
                msbias = arcomb.comb_frames(
                    frames,
                    det,
                    'bias',
                    printtype=settings.argflag['bias']['useframe'])
                del frames
        elif settings.argflag['bias']['useframe'] == 'overscan':
            self.SetMasterFrame('overscan', "bias", det, mkcopy=False)
            return False
        elif settings.argflag['bias']['useframe'] == 'none':
            msgs.info("Not performing a bias/dark subtraction")
            self.SetMasterFrame(None, "bias", det, mkcopy=False)
            return False
        else:  # It must be the name of a file the user wishes to load
            msbias_name = settings.argflag['run']['directory'][
                'master'] + u'/' + settings.argflag['bias']['useframe']
            msbias, head = arload.load_master(msbias_name, frametype="bias")
            settings.argflag['reduce']['masters']['loaded'].append('bias')
        # Set and then delete the Master Bias frame
        self.SetMasterFrame(msbias, "bias", det)
        armasters.save_masters(self, det, mftype='bias')

        del msbias
        return True
示例#2
0
    def MasterPinhole(self, fitsdict, det, msbias):
        """
        Generate Master pinhole frame for a given detector

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files
        det : int
          Index of the detector

        Returns
        -------
        boolean : bool
          Should other ScienceExposure classes be updated?
        """
        dnum = settings.get_dnum(det)
        # If the master pinhole is already made, use it
        if self._mspinhole[det - 1] is not None:
            msgs.info("An identical master pinhole frame already exists")
            return False
        if settings.argflag['reduce']['slitcen']['useframe'] in ['trace', 'pinhole']:
            try:
                mspinhole = armasters.get_master_frame(self, "pinhole")
            except IOError:
                msgs.info("Preparing a master pinhole frame with {0:s}".format(
                    settings.argflag['reduce']['slitcen']['useframe']))
                ind = self._idx_cent
                # Load the pinhole frames
                frames = arload.load_frames(fitsdict, ind, det, frametype='pinhole', msbias=msbias, # self._msbias[det - 1],
                                            trim=settings.argflag['reduce']['trim'])
                if settings.argflag['pinhole']['combine']['match'] > 0.0:
                    sframes = arsort.match_frames(frames, settings.argflag['pinhole']['combine']['match'],
                                                  frametype='pinhole', satlevel=settings.spect[dnum]['saturation'] *
                                                  settings.spect['det'][det - 1]['nonlinear'])
                    subframes = np.zeros((frames.shape[0], frames.shape[1], len(sframes)))
                    numarr = np.array([])
                    for i in range(len(sframes)):
                        numarr = np.append(numarr, sframes[i].shape[2])
                        mspinhole = arcomb.comb_frames(sframes[i], det, 'pinhole')
                        subframes[:, :, i] = mspinhole.copy()
                    del sframes
                    # Combine all sub-frames
                    mspinhole = arcomb.comb_frames(subframes, det, 'pinhole', weights=numarr)
                    del subframes
                else:
                    mspinhole = arcomb.comb_frames(frames, det, 'pinhole')
                del frames
        else:  # It must be the name of a file the user wishes to load
            mspinhole_name = settings.argflag['run']['directory']['master'] + '/' + \
                              settings.argflag['reduce']['slitcen']['useframe']
            mspinhole, head = armasters.load_master(mspinhole_name, frametype=None)
            debugger.set_trace()  # NEED TO LOAD EXTRAS AS ABOVE
        # Set and then delete the Master Trace frame
        self.SetMasterFrame(mspinhole, "pinhole", det)
        #armasters.save_masters(self, det, mftype='pinhole')
        del mspinhole
        return True
示例#3
0
    def MasterBias(self, fitsdict, det):
        """
        Generate Master Bias frame for a given detector

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files
        det : int
          Index of the detector

        Returns
        -------
        boolean : bool
          Should other ScienceExposure classes be updated?
        """

        # If the master bias is already made, use it
        if self._msbias[det-1] is not None:
            msgs.info("An identical master {0:s} frame already exists".format(self._argflag['reduce']['usebias']))
            return False
        elif self._argflag['reduce']['usebias'] in ['bias', 'dark']:
            # Load from hard-drive?
            if self._argflag['masters']['use']:
                # Attempt to load the Master Frame
                msbias_name = armasters.master_name(self._argflag['run']['masterdir'],
                                                    'bias', self._argflag['masters']['setup'])
                try:
                    msbias, head = arload.load_master(msbias_name, frametype="bias")
                except IOError:
                    msgs.warn("No MasterBias frame found {:s}".format(msbias_name))
                else:
                    self._argflag['masters']['loaded'].append('bias'+self._argflag['masters']['setup'])
            if 'bias'+self._argflag['masters']['setup'] not in self._argflag['masters']['loaded']:
                msgs.info("Preparing a master {0:s} frame".format(self._argflag['reduce']['usebias']))
                # Get all of the bias frames for this science frame
                ind = self._idx_bias
                # Load the Bias/Dark frames
                frames = arload.load_frames(self, fitsdict, ind, det, frametype=self._argflag['reduce']['usebias'], transpose=self._transpose)
                msbias = arcomb.comb_frames(frames, det, spect=self._spect, frametype=self._argflag['reduce']['usebias'], **self._argflag['bias']['comb'])
                del frames
        elif self._argflag['reduce']['usebias'] == 'overscan':
            self.SetMasterFrame('overscan', "bias", det, copy=False)
            return False
        elif self._argflag['reduce']['usebias'] == 'none':
            msgs.info("Not performing a bias/dark subtraction")
            self.SetMasterFrame(None, "bias", det, copy=False)
            return False
        else: # It must be the name of a file the user wishes to load
            msbias_name = self._argflag['run']['masterdir']+'/'+self._argflag['reduce']['usebias']
            msbias, head = arload.load_master(msbias_name, frametype="bias")
            self._argflag['masters']['loaded'].append('bias')
        # Set and then delete the Master Bias frame
        self.SetMasterFrame(msbias, "bias", det)

        del msbias
        return True
示例#4
0
    def MasterStandard(self, scidx, fitsdict):
        """
        Generate Master Standard frame for a given detector
        and generates a sensitivity function
        Currently only uses first standard star exposure
        Currently takes brightest source on the mosaic

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files

        Returns
        -------
        boolean : bool
        """

        if len(self._msstd[0]) != 0:
            msgs.info("Using existing standard frame")
            return False
        #
        msgs.info("Preparing the standard")
        # Get all of the pixel flat frames for this science frame
        ind = self._idx_std
        msgs.warn("Taking only the first standard frame for now")
        ind = [ind[0]]
        # Extract
        all_specobj = []
        for kk in xrange(self._spect['mosaic']['ndet']):
            det = kk+1
            # Load the frame(s)
#            set_trace()
            frame = arload.load_frames(self, fitsdict, ind, det, frametype='standard',
                                   msbias=self._msbias[det-1],
                                   transpose=self._transpose)
#            msgs.warn("Taking only the first standard frame for now")
#            ind = ind[0]
            sciframe = frame[:, :, 0]
            # Save RA/DEC
            if kk == 0:
                self._msstd[det-1]['RA'] = fitsdict['ra'][ind[0]]
                self._msstd[det-1]['DEC'] = fitsdict['dec'][ind[0]]
            #debugger.set_trace()
            arproc.reduce_frame(self, sciframe, ind[0], fitsdict, det, standard=True)

            #
            all_specobj += self._msstd[det-1]['spobjs']
#        debugger.set_trace()
        # If standard, generate a sensitivity function
        sensfunc = arflux.generate_sensfunc(self, scidx, all_specobj, fitsdict)
        # Set the sensitivity function
        self.SetMasterFrame(sensfunc, "sensfunc", None, copy=False)
        return True
示例#5
0
    def MasterTrace(self, fitsdict, det):
        """
        Generate Master Trace frame for a given detector

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files
        det : int
          Index of the detector

        Returns
        -------
        boolean : bool
          Should other ScienceExposure classes be updated?
        """

        # If the master trace is already made, use it
        if self._mstrace[det-1] is not None:
            msgs.info("An identical master trace frame already exists")
            return False
        if self._argflag['reduce']['usetrace'] in ['trace', 'blzflat']:
            if self._argflag['masters']['use']:
                # Attempt to load the Master Frame
                mstrace_name = armasters.master_name(self._argflag['run']['masterdir'],
                                                   'trace', self._argflag['masters']['setup'])
                try:
                    mstrace, head = arload.load_master(mstrace_name, frametype="trace")
                except IOError:
                    msgs.warn("No MasterTrace frame found {:s}".format(mstrace_name))
                else:
                    # Extras
                    lordloc, _ = arload.load_master(mstrace_name, frametype="trace", exten=1)
                    rordloc, _ = arload.load_master(mstrace_name, frametype="trace", exten=2)
                    pixcen, _ = arload.load_master(mstrace_name, frametype="trace", exten=3)
                    pixwid, _ = arload.load_master(mstrace_name, frametype="trace", exten=4)
                    lordpix, _ = arload.load_master(mstrace_name, frametype="trace", exten=5)
                    rordpix, _ = arload.load_master(mstrace_name, frametype="trace", exten=6)
                    self.SetFrame(self._lordloc, lordloc, det)
                    self.SetFrame(self._rordloc, rordloc, det)
                    self.SetFrame(self._pixcen, pixcen.astype(np.int), det)
                    self.SetFrame(self._pixwid, pixwid.astype(np.int), det)
                    self.SetFrame(self._lordpix, lordpix.astype(np.int), det)
                    self.SetFrame(self._rordpix, rordpix.astype(np.int), det)
                    #
                    self._argflag['masters']['loaded'].append('trace'+self._argflag['masters']['setup'])
            if 'trace'+self._argflag['masters']['setup'] not in self._argflag['masters']['loaded']:
                msgs.info("Preparing a master trace frame with {0:s}".format(self._argflag['reduce']['usetrace']))
                ind = self._idx_trace
                # Load the frames for tracing
                frames = arload.load_frames(self, fitsdict, ind, det, frametype='trace', msbias=self._msbias[det-1],
                                            trim=self._argflag['reduce']['trim'], transpose=self._transpose)
                if self._argflag['reduce']['flatmatch'] > 0.0:
                    sframes = arsort.match_frames(frames, self._argflag['reduce']['flatmatch'], msgs, frametype='trace', satlevel=self._spect['det'][det-1]['saturation']*self._spect['det'][det-1]['nonlinear'])
                    subframes = np.zeros((frames.shape[0], frames.shape[1], len(sframes)))
                    numarr = np.array([])
                    for i in xrange(len(sframes)):
                        numarr = np.append(numarr, sframes[i].shape[2])
                        mstrace = arcomb.comb_frames(sframes[i], det, spect=self._spect, frametype='trace', **self._argflag['trace']['comb'])
                        subframes[:,:,i] = mstrace.copy()
                    del sframes
                    # Combine all sub-frames
                    mstrace = arcomb.comb_frames(subframes, det, spect=self._spect, frametype='trace', weights=numarr, **self._argflag['trace']['comb'])
                    del subframes
                else:
                    mstrace = arcomb.comb_frames(frames, det, spect=self._spect, frametype='trace', **self._argflag['trace']['comb'])
                del frames
        elif self._argflag['reduce']['usetrace'] == 'science':
            msgs.error("Tracing with a science frame is not yet implemented")
        else: # It must be the name of a file the user wishes to load
            mstrace_name = self._argflag['run']['masterdir']+'/'+self._argflag['reduce']['usetrace']
            mstrace, head = arload.load_master(mstrace_name, frametype=None)
            debugger.set_trace()  # NEED TO LOAD EXTRAS AS ABOVE
        # Set and then delete the Master Trace frame
        self.SetMasterFrame(mstrace, "trace", det)
        del mstrace
        return True
示例#6
0
    def MasterFlatField(self, fitsdict, det):
        """
        Generate Master Flat-field frame for a given detector

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files
        det : int
          Index of the detector

        Returns
        -------
        boolean : bool
          Should other ScienceExposure classes be updated?
        """

        if self._argflag['reduce']['flatfield']:  # Only do it if the user wants to flat field
        # If the master pixflat is already made, use it
            if self._mspixflat[det-1] is not None:
                msgs.info("An identical master pixflat frame already exists")
                if self._mspixflatnrm[det-1] is None:
                    # Normalize the flat field
                    msgs.info("Normalizing the pixel flat")
                    mspixflatnrm, msblaze = arproc.flatnorm(self, det, self.GetMasterFrame("pixflat", det),
                                                            overpix=0, plotdesc="Blaze function")
                    self.SetFrame(self._msblaze, msblaze, det)
                    self.SetMasterFrame(mspixflatnrm, "normpixflat", det)
                return False
            ###############
            # Generate a master pixel flat frame
            if self._argflag['reduce']['useflat'] in ['pixflat', 'blzflat']:
                if self._argflag['masters']['use']:
                    # Attempt to load the Master Frame
                    msflat_name = armasters.master_name(self._argflag['run']['masterdir'],
                                                    'normpixflat', self._argflag['masters']['setup'])
                    try:
                        mspixflatnrm, head = arload.load_master(msflat_name, frametype="normpixflat")
                    except IOError:
                        msgs.warn("No MasterFlatField frame found {:s}".format(msflat_name))
                    else:
                        self._argflag['masters']['loaded'].append('normpixflat'+self._argflag['masters']['setup'])
                        mspixflat = mspixflatnrm
                if 'normpixflat'+self._argflag['masters']['setup'] not in self._argflag['masters']['loaded']:
                    msgs.info("Preparing a master pixel flat frame with {0:s}".format(self._argflag['reduce']['useflat']))
                    # Get all of the pixel flat frames for this science frame
                    ind = self._idx_flat
                    # Load the frames for tracing
                    frames = arload.load_frames(self, fitsdict, ind, det, frametype='pixel flat',
                                                msbias=self._msbias[det-1], transpose=self._transpose)
                    if self._argflag['reduce']['flatmatch'] > 0.0:
                        sframes = arsort.match_frames(frames, self._argflag['reduce']['flatmatch'],
                                                      frametype='pixel flat', satlevel=self._nonlinear)
                        subframes = np.zeros((frames.shape[0], frames.shape[1], len(sframes)))
                        numarr = np.array([])
                        for i in xrange(len(sframes)):
                            numarr = np.append(numarr, sframes[i].shape[2])
                            mspixflat = arcomb.comb_frames(sframes[i], det, spect=self._spect, frametype='pixel flat',
                                                           **self._argflag['pixflat']['comb'])
                            subframes[:,:,i] = mspixflat.copy()
                        del sframes
                        # Combine all sub-frames
                        mspixflat = arcomb.comb_frames(subframes, det, spect=self._spect, frametype='pixel flat',
                                                       weights=numarr, **self._argflag['pixflat']['comb'])
                        del subframes
                    else:
                        mspixflat = arcomb.comb_frames(frames, det, spect=self._spect, frametype='pixel flat',
                                                       **self._argflag['pixflat']['comb'])
                    del frames
                    # Apply gain (instead of ampsec scale)
                    mspixflat *= arproc.gain_frame(self, det)
                    # Normalize the flat field
                    mspixflatnrm, msblaze = arproc.flatnorm(self, det, mspixflat, overpix=0, plotdesc="Blaze function")
                    self.SetFrame(self._msblaze, msblaze, det)
            else:  # It must be the name of a file the user wishes to load
                mspixflat_name = armasters.user_master_name(self._argflag['run']['masterdir'],
                                                            self._argflag['reduce']['useflat'])
                mspixflatnrm, head = arload.load_master(mspixflat_name, exten=det, frametype=None)
                mspixflat = mspixflatnrm
            # Now that the combined, master flat field frame is loaded...
        else:
            msgs.work("Pixel Flat arrays need to be generated when not flat fielding")
            msgs.bug("Blaze is currently undefined")
            mspixflat = np.ones_like(self._msarc)
            mspixflatnrm = np.ones_like(self._msarc)
        # Set Master Frames
        self.SetMasterFrame(mspixflat, "pixflat", det)
        self.SetMasterFrame(mspixflatnrm, "normpixflat", det)
        return True
示例#7
0
    def MasterArc(self, fitsdict, det):
        """
        Generate Master Arc frame for a given detector

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files
        det : int
          Index of the detector

        Returns
        -------
        boolean : bool
          Should other ScienceExposure classes be updated?
        """

        if self._msarc[det-1] is not None:
            msgs.info("An identical master arc frame already exists")
            return False
        if self._argflag['reduce']['usearc'] in ['arc']:
            # Attempt to load the Master Frame
            if self._argflag['masters']['use']:
                msarc_name = armasters.master_name(self._argflag['run']['masterdir'],
                                                    'arc', self._argflag['masters']['setup'])
                try:
                    msarc, head = arload.load_master(msarc_name, frametype="arc")
                except IOError:
                    msgs.warn("No MasterArc frame found {:s}".format(msarc_name))
                else:
                    self._transpose = head['transp']
                    if self._transpose:  # Need to setup for flipping
                        self._argflag['trace']['disp']['direction'] = 1
                    else:
                        self._argflag['trace']['disp']['direction'] = 0
                    # Append as loaded
                    self._argflag['masters']['loaded'].append('arc'+self._argflag['masters']['setup'])
            if 'arc'+self._argflag['masters']['setup'] not in self._argflag['masters']['loaded']:
                msgs.info("Preparing a master arc frame")
                ind = self._idx_arcs
                # Load the arc frames
                frames = arload.load_frames(self, fitsdict, ind, det, frametype='arc',
                                            msbias=self._msbias[det-1])
                if self._argflag['reduce']['arcmatch'] > 0.0:
                    sframes = arsort.match_frames(frames, self._argflag['reduce']['arcmatch'], msgs, frametype='arc',
                                                  satlevel=self._spect['det']['saturation']*self._spect['det']['nonlinear'])
                    subframes = np.zeros((frames.shape[0], frames.shape[1], len(sframes)))
                    numarr = np.array([])
                    for i in xrange(len(sframes)):
                        numarr = np.append(numarr, sframes[i].shape[2])
                        msarc = arcomb.comb_frames(sframes[i], det, spect=self._spect,
                                                   frametype='arc', **self._argflag['arc']['comb'])
                        # Send the data away to be saved
                        subframes[:,:,i] = msarc.copy()
                    del sframes
                    # Combine all sub-frames
                    msarc = arcomb.comb_frames(subframes, det, spect=self._spect,
                                               frametype='arc', weights=numarr, **self._argflag['arc']['comb'])
                    del subframes
                else:
                    msarc = arcomb.comb_frames(frames, det, spect=self._spect,
                                           frametype='arc', **self._argflag['arc']['comb'])
                del frames
            # # Derive a suitable name for the master arc frame
            # msarc_name = "{0:s}/{1:s}/msarc{2:s}_{3:03d}.fits".format(os.getcwd(),self._argflag['run']['masterdir'],self._spect["det"][det-1]["suffix"],len(self._done_arcs))
            # self._tltprefix = os.path.splitext(os.path.basename(msarc_name))[0]
            # # Send the data away to be saved
            # arsave.save_master(self, msarc, filename=msarc_name, frametype='arc', ind=ind)
            # # Store the files used and the master bias name in case it can be used during the later reduction processes
            # self._done_arcs.append(ind)
            # self._name_arcs.append(msarc_name)
        else:
            msarc_name = self._argflag['run']['masterdir']+'/'+self._argflag['reduce']['usearc']
            msarc, head = arload.load_master(msarc_name, frametype=None)
        # Set and then delete the Master Arc frame
        self.SetMasterFrame(msarc, "arc", det)
        del msarc
        return True
示例#8
0
def ARMED(fitsdict, reuseMaster=False, reloadMaster=True):
    """
    Automatic Reduction and Modeling of Echelle Data

    Parameters
    ----------
    fitsdict : dict
      Contains relevant information from fits header files
    reuseMaster : bool
      If True, a master frame that will be used for another science frame
      will not be regenerated after it is first made.
      This setting comes with a price, and if a large number of science frames are
      being generated, it may be more efficient to simply regenerate the master
      calibrations on the fly.

    Returns
    -------
    status : int
      Status of the reduction procedure
      0 = Successful execution
      1 = ...
    """
    status = 0

    # Create a list of science exposure classes
    sciexp, setup_dict = armbase.SetupScience(fitsdict)
    if sciexp == 'setup':
        status = 1
        return status
    elif sciexp == 'calcheck':
        status = 2
        return status
    else:
        numsci = len(sciexp)

    # Create a list of master calibration frames
    #masters = armasters.MasterFrames(settings.spect['mosaic']['ndet'])

    # Masters
    #settings.argflag['reduce']['masters']['file'] = setup_file

    # Start reducing the data
    for sc in range(numsci):
        slf = sciexp[sc]
        scidx = slf._idx_sci[0]
        msgs.info("Reducing file {0:s}, target {1:s}".format(fitsdict['filename'][scidx], slf._target_name))
        msgs.sciexp = slf  # For QA writing on exit, if nothing else.  Could write Masters too
        if reloadMaster and (sc > 0):
            settings.argflag['reduce']['masters']['reuse'] = True
        # Loop on Detectors
        for kk in range(settings.spect['mosaic']['ndet']):
            det = kk + 1  # Detectors indexed from 1
            if settings.argflag['reduce']['detnum'] is not None:
                if det != settings.argflag['reduce']['detnum']:
                    continue
                else:
                    msgs.warn("Restricting the reduction to detector {:d}".format(det))
            slf.det = det
            ###############
            # Get data sections
            arproc.get_datasec_trimmed(slf, fitsdict, det, scidx)
            # Setup
            setup = arsort.instr_setup(slf, det, fitsdict, setup_dict, must_exist=True)
            settings.argflag['reduce']['masters']['setup'] = setup
            slf.setup = setup
            ###############
            # Generate master bias frame
            update = slf.MasterBias(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="bias")
            ###############
            # Generate a bad pixel mask (should not repeat)
            update = slf.BadPixelMask(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc")
            ###############
            # Estimate gain and readout noise for the amplifiers
            msgs.work("Estimate Gain and Readout noise from the raw frames...")
            ###############
            # Generate a master arc frame
            update = slf.MasterArc(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc")
            ###############
            # Set the number of spectral and spatial pixels, and the bad pixel mask is it does not exist
            slf._nspec[det-1], slf._nspat[det-1] = slf._msarc[det-1].shape
            if slf._bpix[det-1] is None:
                slf.SetFrame(slf._bpix, np.zeros((slf._nspec[det-1], slf._nspat[det-1])), det)
            ###############
            # Generate a master trace frame
            update = slf.MasterTrace(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="trace")
            ###############
            # Generate a master pinhole frame
            update = slf.MasterPinhole(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="pinhole")
            ###############
            # Generate an array that provides the physical pixel locations on the detector
            slf.GetPixelLocations(det)
            ###############
            # Determine the edges of the spectrum (spatial)
            if ('trace'+settings.argflag['reduce']['masters']['setup'] not in settings.argflag['reduce']['masters']['loaded']):
                if True:#not msgs._debug['develop']:
                    msgs.info("Tracing slit edges with a {0:s} frame".format(settings.argflag['trace']['useframe']))
                    if settings.argflag['trace']['useframe'] == 'pinhole':
                        ###############
                        # Determine the centroid of the spectrum (spatial)
                        lordloc, rordloc, extord = artrace.trace_slits(slf, slf._mspinhole[det-1], det,
                                                                       pcadesc="PCA trace of the slit edges")

                        # Using the order centroid, expand the order edges until the edge of the science slit is found
                        if settings.argflag['trace']['slits']['expand']:
                            lordloc, rordloc = artrace.expand_slits(slf, slf._mstrace[det-1], det,
                                                                    0.5*(lordloc+rordloc), extord)
                    elif settings.argflag['trace']['useframe'] == 'trace':
                        ###############
                        # Determine the edges of the slit using a trace frame
                        lordloc, rordloc, extord = artrace.trace_slits(slf, slf._mstrace[det-1], det,
                                                                       pcadesc="PCA trace of the slit edges")
                    else:
                        msgs.error("Cannot trace slit edges using {0:s}".format(settings.argflag['trace']['useframe']))
                else:
                    lordloc, rordloc, extord = np.load("lordloc.npy"), np.load("rordloc.npy"), np.load("extord.npy")

                # Save the locations of the order edges
                slf.SetFrame(slf._lordloc, lordloc, det)
                slf.SetFrame(slf._rordloc, rordloc, det)

                # Convert physical trace into a pixel trace
                msgs.info("Converting physical trace locations to nearest pixel")
                pixcen = artrace.phys_to_pix(0.5 * (slf._lordloc[det - 1] + slf._rordloc[det - 1]), slf._pixlocn[det - 1], 1)
                pixwid = (slf._rordloc[det - 1] - slf._lordloc[det - 1]).mean(0).astype(np.int)
                lordpix = artrace.phys_to_pix(slf._lordloc[det - 1], slf._pixlocn[det - 1], 1)
                rordpix = artrace.phys_to_pix(slf._rordloc[det - 1], slf._pixlocn[det - 1], 1)
                slf.SetFrame(slf._pixcen, pixcen, det)
                slf.SetFrame(slf._pixwid, pixwid, det)
                slf.SetFrame(slf._lordpix, lordpix, det)
                slf.SetFrame(slf._rordpix, rordpix, det)
                msgs.info("Identifying the pixels belonging to each slit")
                slitpix = arproc.slit_pixels(slf, slf._mstrace[det-1].shape, det)
                slf.SetFrame(slf._slitpix, slitpix, det)
                # Save to disk
                armasters.save_masters(slf, det, mftype='trace')
                # Save QA for slit traces
                arqa.slit_trace_qa(slf, slf._mstrace[det-1], slf._lordpix[det-1], slf._rordpix[det - 1], extord,
                                       desc="Trace of the slit edges", normalize=False)
                armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="trace")

            ###############
            # Generate the 1D wavelength solution
            update = slf.MasterWaveCalib(fitsdict, sc, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc", chktype="trace")

            ###############
            # Derive the spectral tilt
            if slf._tilts[det-1] is None:
                try:
                    tilts = armasters.get_master_frame(slf, "tilts")
                except IOError:
                    # First time tilts are derived for this arc frame --> derive the order tilts
                    tilts, satmask, outpar = artrace.echelle_tilt(slf, slf._msarc[det - 1], det)
                    slf.SetFrame(slf._tilts, tilts, det)
                    slf.SetFrame(slf._satmask, satmask, det)
                    slf.SetFrame(slf._tiltpar, outpar, det)
                armasters.save_masters(slf, det, mftype='tilts')
            else:
                slf.SetFrame(slf._tilts, tilts, det)

            ###############
            # Prepare the pixel flat field frame
            update = slf.MasterFlatField(fitsdict, det)
            if update and reuseMaster: armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="pixelflat")

            ###############
            # Derive the spatial profile and blaze function
            if slf._slitprof[det-1] is None:
                if settings.argflag['reduce']['masters']['reuse']:
                    msslitprof_name = armasters.master_name('slitprof', settings.argflag['reduce']['masters']['setup'])
                    try:
                        slit_profiles, head = arload.load_master(msslitprof_name, frametype="slit profile")
                    except IOError:
                        pass
                    else:
                        slf.SetFrame(slf._slitprof, slit_profiles, det)
                        settings.argflag['reduce']['masters']['loaded'].append('slitprof'+settings.argflag['reduce']['masters']['setup'])
                if 'slitprof'+settings.argflag['reduce']['masters']['setup'] not in settings.argflag['reduce']['masters']['loaded']:
                    # First time slit profile is derived
                    msgs.info("Calculating slit profile from master trace frame")
                    slit_profiles, mstracenrm, msblaze, flat_ext1d, extrap_slit = arproc.slit_profile(slf, slf._mstrace[det - 1], det)
                    # If some slit profiles/blaze functions need to be extrapolated, do that now
                    if np.sum(extrap_slit) != 0.0:
                        slit_profiles, mstracenrm, msblaze = arproc.slit_profile_pca(slf, slf._mstrace[det - 1], det, msblaze, extrap_slit)
                    slf.SetFrame(slf._slitprof, slit_profiles, det)
                    slf.SetFrame(slf._msblaze, msblaze, det)
                    # Prepare some QA for the average slit profile along the slit
                    msgs.info("Preparing QA of each slit profile")
                    arqa.slit_profile(slf, mstracenrm, slit_profiles, slf._lordloc[det - 1], slf._rordloc[det - 1],
                                      slf._slitpix[det - 1], desc="Slit profile")
                    msgs.info("Saving blaze function QA")
                    arqa.plot_orderfits(slf, msblaze, flat_ext1d, desc="Blaze function", textplt="Order")

            ###############
            # Generate/load a master wave frame
            update = slf.MasterWave(fitsdict, sc, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc", chktype="wave")

            ###############
            # Check if the user only wants to prepare the calibrations only
            msgs.info("All calibration frames have been prepared")
            if settings.argflag['run']['preponly']:
                msgs.info("If you would like to continue with the reduction, disable the command:" + msgs.newline() +
                          "run preponly False")
                continue

            ###############
            # Write setup
            #setup = arsort.calib_setup(sc, det, fitsdict, setup_dict, write=True)
            # Write MasterFrames (currently per detector)
            #armasters.save_masters(slf, det, setup)

            ###############
            # Load the science frame and from this generate a Poisson error frame
            msgs.info("Loading science frame")
            sciframe = arload.load_frames(fitsdict, [scidx], det,
                                          frametype='science',
                                          msbias=slf._msbias[det - 1])
            sciframe = sciframe[:, :, 0]
            # Extract
            msgs.info("Processing science frame")
            arproc.reduce_echelle(slf, sciframe, scidx, fitsdict, det)

        # Write 1D spectra
        save_format = 'fits'
        if save_format == 'fits':
            arsave.save_1d_spectra_fits(slf, fitsdict)
        elif save_format == 'hdf5':
            arsave.save_1d_spectra_hdf5(slf)
        else:
            msgs.error(save_format + ' is not a recognized output format!')
        # Write 2D images for the Science Frame
        arsave.save_2d_images(slf, fitsdict)
        # Free up some memory by replacing the reduced ScienceExposure class
        sciexp[sc] = None
    return status
示例#9
0
def ARMLSD(argflag, spect, fitsdict, reuseMaster=False):
    """
    Automatic Reduction and Modeling of Long Slit Data

    Parameters
    ----------
    argflag : dict
      Arguments and flags used for reduction
    spect : dict
      Properties of the spectrograph.
    fitsdict : dict
      Contains relevant information from fits header files
    reuseMaster : bool
      If True, a master frame that will be used for another science frame
      will not be regenerated after it is first made.
      This setting comes with a price, and if a large number of science frames are
      being generated, it may be more efficient to simply regenerate the master
      calibrations on the fly.

    Returns
    -------
    status : int
      Status of the reduction procedure
      0 = Successful execution
      1 = ...
    """
    status = 0

    # Create a list of science exposure classes
    sciexp = armbase.SetupScience(argflag, spect, fitsdict)
    numsci = len(sciexp)

    # Create a list of master calibration frames
    masters = armasters.MasterFrames(spect['mosaic']['ndet'])

    # Use Masters?  Requires setup file
    setup_file = argflag['out']['sorted'] + '.setup'
    try:
        calib_dict = ltu.loadjson(setup_file)
    except:
        msgs.info("No setup file {:s} for MasterFrames".format(setup_file))
        calib_dict = {}
    else:
        argflag['masters']['setup_file'] = setup_file

    # Start reducing the data
    for sc in range(numsci):
        slf = sciexp[sc]
        scidx = slf._idx_sci[0]
        msgs.info("Reducing file {0:s}, target {1:s}".format(
            fitsdict['filename'][scidx], slf._target_name))
        msgs.sciexp = slf  # For QA writing on exit, if nothing else.  Could write Masters too
        # Loop on Detectors
        for kk in xrange(slf._spect['mosaic']['ndet']):
            det = kk + 1  # Detectors indexed from 1
            slf.det = det
            ###############
            # Get amplifier sections
            arproc.get_ampsec_trimmed(slf, fitsdict, det, scidx)
            # Setup
            setup = arsort.calib_setup(slf,
                                       sc,
                                       det,
                                       fitsdict,
                                       calib_dict,
                                       write=False)
            slf._argflag['masters']['setup'] = setup
            ###############
            # Generate master bias frame
            update = slf.MasterBias(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="bias")
            ###############
            # Generate a bad pixel mask (should not repeat)
            update = slf.BadPixelMask(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc")
            ###############
            # Generate a master arc frame
            update = slf.MasterArc(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc")
            ###############
            # Determine the dispersion direction (and transpose if necessary)
            slf.GetDispersionDirection(fitsdict, det, scidx)
            if slf._bpix[
                    det -
                    1] is None:  # Needs to be done here after nspec is set
                slf.SetFrame(
                    slf._bpix,
                    np.zeros((slf._nspec[det - 1], slf._nspat[det - 1])), det)
            '''
            ###############
            # Estimate gain and readout noise for the amplifiers
            msgs.work("Estimate Gain and Readout noise from the raw frames...")
            update = slf.MasterRN(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="readnoise")
            '''
            ###############
            # Generate a master trace frame
            update = slf.MasterTrace(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp,
                                      sc,
                                      det,
                                      ftype="flat",
                                      chktype="trace")
            ###############
            # Generate an array that provides the physical pixel locations on the detector
            slf.GetPixelLocations(det)
            # Determine the edges of the spectrum (spatial)
            if 'trace' + slf._argflag['masters']['setup'] not in slf._argflag[
                    'masters']['loaded']:
                ###############
                # Determine the edges of the spectrum (spatial)
                lordloc, rordloc, extord = artrace.trace_orders(
                    slf,
                    slf._mstrace[det - 1],
                    det,
                    singleSlit=True,
                    pcadesc="PCA trace of the slit edges")
                slf.SetFrame(slf._lordloc, lordloc, det)
                slf.SetFrame(slf._rordloc, rordloc, det)

                # Convert physical trace into a pixel trace
                msgs.info(
                    "Converting physical trace locations to nearest pixel")
                pixcen = artrace.phys_to_pix(
                    0.5 * (slf._lordloc[det - 1] + slf._rordloc[det - 1]),
                    slf._pixlocn[det - 1], 1)
                pixwid = (slf._rordloc[det - 1] -
                          slf._lordloc[det - 1]).mean(0).astype(np.int)
                lordpix = artrace.phys_to_pix(slf._lordloc[det - 1],
                                              slf._pixlocn[det - 1], 1)
                rordpix = artrace.phys_to_pix(slf._rordloc[det - 1],
                                              slf._pixlocn[det - 1], 1)
                slf.SetFrame(slf._pixcen, pixcen, det)
                slf.SetFrame(slf._pixwid, pixwid, det)
                slf.SetFrame(slf._lordpix, lordpix, det)
                slf.SetFrame(slf._rordpix, rordpix, det)
                # Save QA for slit traces
                arqa.slit_trace_qa(slf,
                                   slf._mstrace[det - 1],
                                   slf._lordpix[det - 1],
                                   slf._rordpix[det - 1],
                                   extord,
                                   desc="Trace of the slit edges")

            ###############
            # Prepare the pixel flat field frame
            update = slf.MasterFlatField(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp,
                                      sc,
                                      det,
                                      ftype="flat",
                                      chktype="pixflat")
            ###############
            # Generate the 1D wavelength solution
            update = slf.MasterWaveCalib(fitsdict, sc, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp,
                                      sc,
                                      det,
                                      ftype="arc",
                                      chktype="trace")
            ###############
            # Derive the spectral tilt
            if slf._tilts[det - 1] is None:
                if slf._argflag['masters']['use']:
                    mstilt_name = armasters.master_name(
                        slf._argflag['run']['masterdir'], 'tilts',
                        slf._argflag['masters']['setup'])
                    try:
                        tilts, head = arload.load_master(mstilt_name,
                                                         frametype="tilts")
                    except IOError:
                        pass
                    else:
                        slf.SetFrame(slf._tilts, tilts, det)
                        slf._argflag['masters']['loaded'].append(
                            'tilts' + slf._argflag['masters']['setup'])
                if 'tilts' + slf._argflag['masters'][
                        'setup'] not in slf._argflag['masters']['loaded']:
                    # First time tilts are derived for this arc frame --> derive the order tilts
                    tilts, satmask, outpar = artrace.model_tilt(
                        slf, det, slf._msarc[det - 1])
                    slf.SetFrame(slf._tilts, tilts, det)
                    slf.SetFrame(slf._satmask, satmask, det)
                    slf.SetFrame(slf._tiltpar, outpar, det)

            ###############
            # Generate/load a master wave frame
            update = slf.MasterWave(fitsdict, sc, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp,
                                      sc,
                                      det,
                                      ftype="arc",
                                      chktype="wave")

            # Check if the user only wants to prepare the calibrations only
            msgs.info("All calibration frames have been prepared")
            if slf._argflag['run']['preponly']:
                msgs.info("If you would like to continue with the reduction," +
                          msgs.newline() + "disable the run+preponly command")
                continue

            # Write setup
            setup = arsort.calib_setup(slf,
                                       sc,
                                       det,
                                       fitsdict,
                                       calib_dict,
                                       write=True)
            # Write MasterFrames (currently per detector)
            armasters.save_masters(slf, det, setup)

            ###############
            # Load the science frame and from this generate a Poisson error frame
            msgs.info("Loading science frame")
            sciframe = arload.load_frames(slf,
                                          fitsdict, [scidx],
                                          det,
                                          frametype='science',
                                          msbias=slf._msbias[det - 1],
                                          transpose=slf._transpose)
            sciframe = sciframe[:, :, 0]
            # Extract
            msgs.info("Processing science frame")
            arproc.reduce_frame(slf, sciframe, scidx, fitsdict, det)

            #continue
            #msgs.error("UP TO HERE")
            ###############
            # Perform a velocity correction
            if (slf._argflag['reduce']['heliocorr'] == True) & False:
                if slf._argflag['science']['load']['extracted'] == True:
                    msgs.warn(
                        "Heliocentric correction will not be applied if an extracted science frame exists, and is used"
                    )
                msgs.work("Perform a full barycentric correction")
                msgs.work(
                    "Include the facility to correct for gravitational redshifts and time delays (see Pulsar timing work)"
                )
                msgs.info("Performing a heliocentric correction")
                # Load the header for the science frame
                slf._waveids = arvcorr.helio_corr(slf, scidx[0])
            else:
                msgs.info("A heliocentric correction will not be performed")

            ###############
            # Using model sky, calculate a flexure correction

        # Close the QA for this object
        slf._qa.close()

        ###############
        # Flux
        ###############
        # Standard star (is this a calibration, e.g. goes above?)
        msgs.info("Processing standard star")
        msgs.info("Assuming one star per detector mosaic")
        msgs.info("Waited until last detector to process")

        msgs.work("Need to check for existing sensfunc")
        update = slf.MasterStandard(scidx, fitsdict)
        if update and reuseMaster:
            armbase.UpdateMasters(sciexp, sc, 0, ftype="standard")
        #
        msgs.work("Consider using archived sensitivity if not found")
        msgs.info("Fluxing with {:s}".format(slf._sensfunc['std']['name']))
        for kk in xrange(slf._spect['mosaic']['ndet']):
            det = kk + 1  # Detectors indexed from 1
            arflux.apply_sensfunc(slf, det, scidx, fitsdict)

        # Write 1D spectra
        arsave.save_1d_spectra(slf)
        # Write 2D images for the Science Frame
        arsave.save_2d_images(slf)
        # Free up some memory by replacing the reduced ScienceExposure class
        sciexp[sc] = None
    return status
示例#10
0
文件: armlsd.py 项目: adwasser/PYPIT
def ARMLSD(argflag, spect, fitsdict, reuseMaster=False):
    """
    Automatic Reduction and Modeling of Long Slit Data

    Parameters
    ----------
    argflag : dict
      Arguments and flags used for reduction
    spect : dict
      Properties of the spectrograph.
    fitsdict : dict
      Contains relevant information from fits header files
    reuseMaster : bool
      If True, a master frame that will be used for another science frame
      will not be regenerated after it is first made.
      This setting comes with a price, and if a large number of science frames are
      being generated, it may be more efficient to simply regenerate the master
      calibrations on the fly.

    Returns
    -------
    status : int
      Status of the reduction procedure
      0 = Successful execution
      1 = ...
    """
    status = 0

    # Create a list of science exposure classes
    sciexp = armbase.SetupScience(argflag, spect, fitsdict)
    numsci = len(sciexp)

    # Create a list of master calibration frames
    masters = armasters.MasterFrames(spect['mosaic']['ndet'])

    # Use Masters?  Requires setup file
    setup_file = argflag['out']['sorted']+'.setup'
    try:
        calib_dict = ltu.loadjson(setup_file)
    except:
        msgs.info("No setup file {:s} for MasterFrames".format(setup_file))
        calib_dict = {}
    else:
        argflag['masters']['setup_file'] = setup_file

    # Start reducing the data
    for sc in range(numsci):
        slf = sciexp[sc]
        scidx = slf._idx_sci[0]
        msgs.info("Reducing file {0:s}, target {1:s}".format(fitsdict['filename'][scidx], slf._target_name))
        msgs.sciexp = slf  # For QA writing on exit, if nothing else.  Could write Masters too
        # Loop on Detectors
        for kk in xrange(slf._spect['mosaic']['ndet']):
            det = kk + 1  # Detectors indexed from 1
            slf.det = det
            ###############
            # Get amplifier sections
            arproc.get_ampsec_trimmed(slf, fitsdict, det, scidx)
            # Setup
            setup = arsort.calib_setup(slf, sc, det, fitsdict, calib_dict, write=False)
            slf._argflag['masters']['setup'] = setup
            ###############
            # Generate master bias frame
            update = slf.MasterBias(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="bias")
            ###############
            # Generate a bad pixel mask (should not repeat)
            update = slf.BadPixelMask(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc")
            ###############
            # Generate a master arc frame
            update = slf.MasterArc(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc")
            ###############
            # Determine the dispersion direction (and transpose if necessary)
            slf.GetDispersionDirection(fitsdict, det, scidx)
            if slf._bpix[det-1] is None:  # Needs to be done here after nspec is set
                slf.SetFrame(slf._bpix, np.zeros((slf._nspec[det-1], slf._nspat[det-1])), det)
            '''
            ###############
            # Estimate gain and readout noise for the amplifiers
            msgs.work("Estimate Gain and Readout noise from the raw frames...")
            update = slf.MasterRN(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="readnoise")
            '''
            ###############
            # Generate a master trace frame
            update = slf.MasterTrace(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="trace")
            ###############
            # Generate an array that provides the physical pixel locations on the detector
            slf.GetPixelLocations(det)
            # Determine the edges of the spectrum (spatial)
            if 'trace'+slf._argflag['masters']['setup'] not in slf._argflag['masters']['loaded']:
                ###############
                # Determine the edges of the spectrum (spatial)
                lordloc, rordloc, extord = artrace.trace_orders(slf, slf._mstrace[det-1], det, singleSlit=True, pcadesc="PCA trace of the slit edges")
                slf.SetFrame(slf._lordloc, lordloc, det)
                slf.SetFrame(slf._rordloc, rordloc, det)

                # Convert physical trace into a pixel trace
                msgs.info("Converting physical trace locations to nearest pixel")
                pixcen = artrace.phys_to_pix(0.5*(slf._lordloc[det-1]+slf._rordloc[det-1]), slf._pixlocn[det-1], 1)
                pixwid = (slf._rordloc[det-1]-slf._lordloc[det-1]).mean(0).astype(np.int)
                lordpix = artrace.phys_to_pix(slf._lordloc[det-1], slf._pixlocn[det-1], 1)
                rordpix = artrace.phys_to_pix(slf._rordloc[det-1], slf._pixlocn[det-1], 1)
                slf.SetFrame(slf._pixcen, pixcen, det)
                slf.SetFrame(slf._pixwid, pixwid, det)
                slf.SetFrame(slf._lordpix, lordpix, det)
                slf.SetFrame(slf._rordpix, rordpix, det)
                # Save QA for slit traces
                arqa.slit_trace_qa(slf, slf._mstrace[det-1], slf._lordpix[det-1], slf._rordpix[det-1], extord, desc="Trace of the slit edges")

            ###############
            # Prepare the pixel flat field frame
            update = slf.MasterFlatField(fitsdict, det)
            if update and reuseMaster: armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="pixflat")
            ###############
            # Generate the 1D wavelength solution
            update = slf.MasterWaveCalib(fitsdict, sc, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc", chktype="trace")
            ###############
            # Derive the spectral tilt
            if slf._tilts[det-1] is None:
                if slf._argflag['masters']['use']:
                    mstilt_name = armasters.master_name(slf._argflag['run']['masterdir'],
                                                        'tilts', slf._argflag['masters']['setup'])
                    try:
                        tilts, head = arload.load_master(mstilt_name, frametype="tilts")
                    except IOError:
                        pass
                    else:
                        slf.SetFrame(slf._tilts, tilts, det)
                        slf._argflag['masters']['loaded'].append('tilts'+slf._argflag['masters']['setup'])
                if 'tilts'+slf._argflag['masters']['setup'] not in slf._argflag['masters']['loaded']:
                    # First time tilts are derived for this arc frame --> derive the order tilts
                    tilts, satmask, outpar = artrace.model_tilt(slf, det, slf._msarc[det-1])
                    slf.SetFrame(slf._tilts, tilts, det)
                    slf.SetFrame(slf._satmask, satmask, det)
                    slf.SetFrame(slf._tiltpar, outpar, det)

            ###############
            # Generate/load a master wave frame
            update = slf.MasterWave(fitsdict, sc, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc", chktype="wave")

            # Check if the user only wants to prepare the calibrations only
            msgs.info("All calibration frames have been prepared")
            if slf._argflag['run']['preponly']:
                msgs.info("If you would like to continue with the reduction,"
                          +msgs.newline()+"disable the run+preponly command")
                continue

            # Write setup
            setup = arsort.calib_setup(slf, sc, det, fitsdict, calib_dict, write=True)
            # Write MasterFrames (currently per detector)
            armasters.save_masters(slf, det, setup)

            ###############
            # Load the science frame and from this generate a Poisson error frame
            msgs.info("Loading science frame")
            sciframe = arload.load_frames(slf, fitsdict, [scidx], det,
                                          frametype='science',
                                          msbias=slf._msbias[det-1],
                                          transpose=slf._transpose)
            sciframe = sciframe[:, :, 0]
            # Extract
            msgs.info("Processing science frame")
            arproc.reduce_frame(slf, sciframe, scidx, fitsdict, det)

            #continue
            #msgs.error("UP TO HERE")
            ###############
            # Perform a velocity correction
            if (slf._argflag['reduce']['heliocorr'] == True) & False:
                if slf._argflag['science']['load']['extracted'] == True:
                    msgs.warn("Heliocentric correction will not be applied if an extracted science frame exists, and is used")
                msgs.work("Perform a full barycentric correction")
                msgs.work("Include the facility to correct for gravitational redshifts and time delays (see Pulsar timing work)")
                msgs.info("Performing a heliocentric correction")
                # Load the header for the science frame
                slf._waveids = arvcorr.helio_corr(slf, scidx[0])
            else:
                msgs.info("A heliocentric correction will not be performed")

            ###############
            # Using model sky, calculate a flexure correction

        # Close the QA for this object
        slf._qa.close()

        ###############
        # Flux
        ###############
        # Standard star (is this a calibration, e.g. goes above?)
        msgs.info("Processing standard star")
        msgs.info("Assuming one star per detector mosaic")
        msgs.info("Waited until last detector to process")

        msgs.work("Need to check for existing sensfunc")
        update = slf.MasterStandard(scidx, fitsdict)
        if update and reuseMaster:
            armbase.UpdateMasters(sciexp, sc, 0, ftype="standard")
        #
        msgs.work("Consider using archived sensitivity if not found")
        msgs.info("Fluxing with {:s}".format(slf._sensfunc['std']['name']))
        for kk in xrange(slf._spect['mosaic']['ndet']):
            det = kk + 1  # Detectors indexed from 1
            arflux.apply_sensfunc(slf, det, scidx, fitsdict)

        # Write 1D spectra
        arsave.save_1d_spectra(slf)
        # Write 2D images for the Science Frame
        arsave.save_2d_images(slf)
        # Free up some memory by replacing the reduced ScienceExposure class
        sciexp[sc] = None
    return status
示例#11
0
def ARMLSD(fitsdict, reuseMaster=False, reloadMaster=True):
    """
    Automatic Reduction and Modeling of Long Slit Data

    Parameters
    ----------
    fitsdict : dict
      Contains relevant information from fits header files
    reuseMaster : bool
      If True, a master frame that will be used for another science frame
      will not be regenerated after it is first made.
      This setting comes with a price, and if a large number of science frames are
      being generated, it may be more efficient to simply regenerate the master
      calibrations on the fly.

    Returns
    -------
    status : int
      Status of the reduction procedure
      0 = Successful full execution
      1 = Successful processing of setup or calcheck
    """
    status = 0

    # Create a list of science exposure classes
    sciexp, setup_dict = armbase.SetupScience(fitsdict)
    if sciexp == 'setup':
        status = 1
        return status
    elif sciexp == 'calcheck':
        status = 2
        return status
    else:
        numsci = len(sciexp)

    # Create a list of master calibration frames
    #masters = armasters.MasterFrames(settings.spect['mosaic']['ndet'])

    # Masters
    #settings.argflag['reduce']['masters']['file'] = setup_file

    # Start reducing the data
    for sc in range(numsci):
        slf = sciexp[sc]
        scidx = slf._idx_sci[0]
        msgs.info("Reducing file {0:s}, target {1:s}".format(fitsdict['filename'][scidx], slf._target_name))
        msgs.sciexp = slf  # For QA writing on exit, if nothing else.  Could write Masters too
        if reloadMaster and (sc > 0):
            settings.argflag['reduce']['masters']['reuse'] = True
        # Loop on Detectors
        for kk in range(settings.spect['mosaic']['ndet']):
            det = kk + 1  # Detectors indexed from 1
            if settings.argflag['reduce']['detnum'] is not None:
                if det != settings.argflag['reduce']['detnum']:
                    continue
                else:
                    msgs.warn("Restricting the reduction to detector {:d}".format(det))
            slf.det = det
            ###############
            # Get data sections
            arproc.get_datasec_trimmed(slf, fitsdict, det, scidx)
            # Setup
            setup = arsort.instr_setup(slf, det, fitsdict, setup_dict, must_exist=True)
            settings.argflag['reduce']['masters']['setup'] = setup
            slf.setup = setup
            ###############
            # Generate master bias frame
            update = slf.MasterBias(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="bias")
            ###############
            # Generate a bad pixel mask (should not repeat)
            update = slf.BadPixelMask(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc")
            ###############
            # Generate a master arc frame
            update = slf.MasterArc(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc")
            ###############
            # Set the number of spectral and spatial pixels, and the bad pixel mask is it does not exist
            slf._nspec[det-1], slf._nspat[det-1] = slf._msarc[det-1].shape
            if slf._bpix[det-1] is None:
                slf.SetFrame(slf._bpix, np.zeros((slf._nspec[det-1], slf._nspat[det-1])), det)
            '''
            ###############
            # Estimate gain and readout noise for the amplifiers
            msgs.work("Estimate Gain and Readout noise from the raw frames...")
            update = slf.MasterRN(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="readnoise")
            '''
            ###############
            # Generate a master trace frame
            update = slf.MasterTrace(fitsdict, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="trace")
            ###############
            # Generate an array that provides the physical pixel locations on the detector
            slf.GetPixelLocations(det)
            # Determine the edges of the spectrum (spatial)
            if ('trace'+settings.argflag['reduce']['masters']['setup'] not in settings.argflag['reduce']['masters']['loaded']):
                ###############
                # Determine the edges of the spectrum (spatial)
                lordloc, rordloc, extord = artrace.trace_slits(slf, slf._mstrace[det-1], det, pcadesc="PCA trace of the slit edges")
                slf.SetFrame(slf._lordloc, lordloc, det)
                slf.SetFrame(slf._rordloc, rordloc, det)

                # Convert physical trace into a pixel trace
                msgs.info("Converting physical trace locations to nearest pixel")
                pixcen = artrace.phys_to_pix(0.5*(slf._lordloc[det-1]+slf._rordloc[det-1]), slf._pixlocn[det-1], 1)
                pixwid = (slf._rordloc[det-1]-slf._lordloc[det-1]).mean(0).astype(np.int)
                lordpix = artrace.phys_to_pix(slf._lordloc[det-1], slf._pixlocn[det-1], 1)
                rordpix = artrace.phys_to_pix(slf._rordloc[det-1], slf._pixlocn[det-1], 1)
                slf.SetFrame(slf._pixcen, pixcen, det)
                slf.SetFrame(slf._pixwid, pixwid, det)
                slf.SetFrame(slf._lordpix, lordpix, det)
                slf.SetFrame(slf._rordpix, rordpix, det)
                msgs.info("Identifying the pixels belonging to each slit")
                slitpix = arproc.slit_pixels(slf, slf._mstrace[det-1].shape, det)
                slf.SetFrame(slf._slitpix, slitpix, det)
                # Save to disk
                armasters.save_masters(slf, det, mftype='trace')
                # Save QA for slit traces
                arqa.slit_trace_qa(slf, slf._mstrace[det-1], slf._lordpix[det-1],
                                       slf._rordpix[det-1], extord,
                                       desc="Trace of the slit edges D{:02d}".format(det), use_slitid=det)
                armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="trace")

            ###############
            # Generate the 1D wavelength solution
            update = slf.MasterWaveCalib(fitsdict, sc, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc", chktype="trace")

            ###############
            # Derive the spectral tilt
            if slf._tilts[det-1] is None:
                try:
                    tilts = armasters.get_master_frame(slf, "tilts")
                except IOError:
                    # First time tilts are derived for this arc frame --> derive the order tilts
                    tilts, satmask, outpar = artrace.multislit_tilt(slf, slf._msarc[det-1], det)
                    slf.SetFrame(slf._tilts, tilts, det)
                    slf.SetFrame(slf._satmask, satmask, det)
                    slf.SetFrame(slf._tiltpar, outpar, det)
                    armasters.save_masters(slf, det, mftype='tilts')
                else:
                    slf.SetFrame(slf._tilts, tilts, det)

            ###############
            # Prepare the pixel flat field frame
            update = slf.MasterFlatField(fitsdict, det)
            if update and reuseMaster: armbase.UpdateMasters(sciexp, sc, det, ftype="flat", chktype="pixelflat")

            ###############
            # Generate/load a master wave frame
            update = slf.MasterWave(fitsdict, sc, det)
            if update and reuseMaster:
                armbase.UpdateMasters(sciexp, sc, det, ftype="arc", chktype="wave")

            ###############
            # Check if the user only wants to prepare the calibrations only
            msgs.info("All calibration frames have been prepared")
            if settings.argflag['run']['preponly']:
                msgs.info("If you would like to continue with the reduction, disable the command:" + msgs.newline() +
                          "run preponly False")
                continue

            ###############
            # Write setup
            #setup = arsort.calib_setup(sc, det, fitsdict, setup_dict, write=True)
            # Write MasterFrames (currently per detector)
            #armasters.save_masters(slf, det, setup)

            ###############
            # Load the science frame and from this generate a Poisson error frame
            msgs.info("Loading science frame")
            sciframe = arload.load_frames(fitsdict, [scidx], det,
                                          frametype='science',
                                          msbias=slf._msbias[det-1])
            sciframe = sciframe[:, :, 0]
            # Extract
            msgs.info("Processing science frame")
            arproc.reduce_multislit(slf, sciframe, scidx, fitsdict, det)

            ###############
            # Using model sky, calculate a flexure correction

        ###############
        # Flux
        ###############
        # Standard star (is this a calibration, e.g. goes above?)
        msgs.info("Processing standard star")
        msgs.info("Assuming one star per detector mosaic")
        msgs.info("Waited until last detector to process")

        update = slf.MasterStandard(fitsdict)
        if update and reuseMaster:
            armbase.UpdateMasters(sciexp, sc, 0, ftype="standard")
        #
        msgs.work("Consider using archived sensitivity if not found")
        msgs.info("Fluxing with {:s}".format(slf._sensfunc['std']['name']))
        for kk in range(settings.spect['mosaic']['ndet']):
            det = kk + 1  # Detectors indexed from 1
            if slf._specobjs[det-1] is not None:
                arflux.apply_sensfunc(slf, det, scidx, fitsdict)
            else:
                msgs.info("There are no objects on detector {0:d} to apply a flux calibration".format(det))

        # Write 1D spectra
        save_format = 'fits'
        if save_format == 'fits':
            arsave.save_1d_spectra_fits(slf, fitsdict)
        elif save_format == 'hdf5':
            arsave.save_1d_spectra_hdf5(slf)
        else:
            msgs.error(save_format + ' is not a recognized output format!')
        arsave.save_obj_info(slf, fitsdict)
        # Write 2D images for the Science Frame
        arsave.save_2d_images(slf, fitsdict)
        # Free up some memory by replacing the reduced ScienceExposure class
        sciexp[sc] = None
    return status
示例#12
0
    def MasterStandard(self, fitsdict):
        """
        Generate Master Standard frame for a given detector
        and generates a sensitivity function
        Currently only uses first standard star exposure
        Currently takes brightest source on the mosaic

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files

        Returns
        -------
        boolean : bool
        """
        if self._sensfunc is not None:
            msgs.info("Using existing sensitivity function.")
            return False
        # Attempt to load the Master Frame
        try:
            sensfunc = armasters.get_master_frame(self, "sensfunc")
        except IOError:
            # Grab the standard star frames
            msgs.info("Preparing the standard")
            ind = self._idx_std
            msgs.warn("Taking only the first standard frame for now")
            ind = [ind[0]]
            # Extract
            all_specobj = []
            for kk in range(settings.spect['mosaic']['ndet']):
                det = kk + 1
                # Load the frame(s)
                frame = arload.load_frames(fitsdict,
                                           ind,
                                           det,
                                           frametype='standard',
                                           msbias=self._msbias[det - 1])
                sciframe = frame[:, :, 0]  # First exposure
                # Save RA/DEC
                self._msstd[det - 1]['RA'] = fitsdict['ra'][ind[0]]
                self._msstd[det - 1]['DEC'] = fitsdict['dec'][ind[0]]
                self._msstd[det - 1]['spobjs'] = None
                # Use this detector? Need to check this after setting RA/DEC above
                if settings.argflag['reduce']['detnum'] is not None:
                    msgs.warn(
                        "If your standard wasnt on this detector, you will have trouble.."
                    )
                    if det != settings.argflag['reduce']['detnum']:
                        continue
                if settings.spect["mosaic"]["reduction"] == "ARMLSD":
                    arproc.reduce_multislit(self,
                                            sciframe,
                                            ind[0],
                                            fitsdict,
                                            det,
                                            standard=True)
                elif settings.spect["mosaic"]["reduction"] == "ARMED":
                    arproc.reduce_echelle(self,
                                          sciframe,
                                          ind[0],
                                          fitsdict,
                                          det,
                                          standard=True)
                else:
                    msgs.error("Not ready for reduction type {0:s}".format(
                        settings.spect["mosaic"]["reduction"]))

                if self._msstd[det - 1]['spobjs'] is not None:
                    all_specobj += self._msstd[det - 1]['spobjs']
            # If standard, generate a sensitivity function
            sensfunc = arflux.generate_sensfunc(self, ind[0], all_specobj,
                                                fitsdict)
            # Set the sensitivity function
            self.SetMasterFrame(sensfunc, "sensfunc", None, mkcopy=False)
            # Apply to Standard
            for kk in range(settings.spect['mosaic']['ndet']):
                det = kk + 1  # Detectors indexed from 1
                arflux.apply_sensfunc(self,
                                      det,
                                      ind[0],
                                      fitsdict,
                                      standard=True)
            # Save
            armasters.save_sensfunc(
                self, settings.argflag['reduce']['masters']['setup'])
            # Save standard star spectrum to disk
            outfile = settings.argflag['run']['directory'][
                'science'] + '/spec1d_{:s}.fits'.format(
                    fitsdict['filename'][ind[0]].split('.')[0])
            arsave.save_1d_spectra_fits(self,
                                        fitsdict,
                                        standard=True,
                                        outfile=outfile)
            return True
        else:
            self._sensfunc = sensfunc.copy()
            return True
示例#13
0
    def MasterFlatField(self, fitsdict, det):
        """
        Generate Master Flat-field frame for a given detector

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files
        det : int
          Index of the detector

        Returns
        -------
        boolean : bool
          Should other ScienceExposure classes be updated?
        """
        from pypit import arqa

        if settings.argflag['reduce']['flatfield'][
                'perform']:  # Only do it if the user wants to flat field
            # If the master pixelflat is already made, use it
            if self._mspixelflat[det - 1] is not None:
                msgs.info("An identical master pixelflat frame already exists")
                if self._mspixelflatnrm[det - 1] is None:
                    # Normalize the flat field
                    msgs.info("Normalizing the pixel flat")
                    slit_profiles, mstracenrm, msblaze, flat_ext1d, extrap_slit = \
                        arproc.slit_profile(self, self.GetMasterFrame("pixelflat", det),
                                            det, ntcky=settings.argflag['reduce']['flatfield']['params'][0])
                    # If some slit profiles/blaze functions need to be extrapolated, do that now
                    if np.sum(extrap_slit) != 0.0:
                        slit_profiles, mstracenrm, msblaze = arproc.slit_profile_pca(
                            self, self.GetMasterFrame("pixelflat", det), det,
                            msblaze, extrap_slit, slit_profiles)
                    mspixelflatnrm = mstracenrm.copy()
                    winpp = np.where(slit_profiles != 0.0)
                    mspixelflatnrm[winpp] /= slit_profiles[winpp]
                    self.SetMasterFrame(mspixelflatnrm, "normpixelflat", det)
                    armasters.save_masters(self, det, mftype='normpixelflat')
                    if np.array_equal(self._idx_flat, self._idx_trace):
                        # The flat field frame is also being used to trace the slit edges and determine the slit
                        # profile. Avoid recalculating the slit profile and blaze function and save them here.
                        self.SetFrame(self._msblaze, msblaze, det)
                        self.SetFrame(self._slitprof, slit_profiles, det)
                        armasters.save_masters(self, det, mftype='slitprof')
                        if settings.argflag["reduce"]["slitprofile"][
                                "perform"]:
                            msgs.info("Preparing QA of each slit profile")
                            arqa.slit_profile(self,
                                              mstracenrm,
                                              slit_profiles,
                                              self._lordloc[det - 1],
                                              self._rordloc[det - 1],
                                              self._slitpix[det - 1],
                                              desc="Slit profile")
                        msgs.info("Saving blaze function QA")
                        arqa.plot_orderfits(self,
                                            msblaze,
                                            flat_ext1d,
                                            desc="Blaze function")
                return False
            ###############
            # Generate/load a master pixel flat frame
            if settings.argflag['reduce']['flatfield']['useframe'] in [
                    'pixelflat', 'trace'
            ]:
                try:
                    mspixelflatnrm = armasters.get_master_frame(
                        self, "normpixelflat")
                except IOError:
                    msgs.info("Preparing a master pixel flat frame with {0:s}".
                              format(settings.argflag['reduce']['flatfield']
                                     ['useframe']))
                    # Get all of the pixel flat frames for this science frame
                    ind = self._idx_flat
                    # Load the frames for tracing
                    frames = arload.load_frames(fitsdict,
                                                ind,
                                                det,
                                                frametype='pixel flat',
                                                msbias=self._msbias[det - 1])
                    if settings.argflag['pixelflat']['combine']['match'] > 0.0:
                        sframes = arsort.match_frames(
                            frames,
                            settings.argflag['pixelflat']['combine']['match'],
                            frametype='pixel flat',
                            satlevel=self._nonlinear)
                        subframes = np.zeros(
                            (frames.shape[0], frames.shape[1], len(sframes)))
                        numarr = np.array([])
                        for i in range(len(sframes)):
                            numarr = np.append(numarr, sframes[i].shape[2])
                            mspixelflat = arcomb.comb_frames(
                                sframes[i],
                                det,
                                'pixelflat',
                                printtype='pixel flat')
                            subframes[:, :, i] = mspixelflat.copy()
                        del sframes
                        # Combine all sub-frames
                        mspixelflat = arcomb.comb_frames(
                            subframes,
                            det,
                            'pixelflat',
                            weights=numarr,
                            printtype='pixel flat')
                        del subframes
                    else:
                        mspixelflat = arcomb.comb_frames(
                            frames, det, 'pixelflat', printtype='pixel flat')
                    del frames
                    # Apply gain (instead of ampsec scale)
                    mspixelflat *= arproc.gain_frame(self, det)
                    # Normalize the flat field
                    msgs.info("Normalizing the pixel flat")
                    slit_profiles, mstracenrm, msblaze, flat_ext1d, extrap_slit = \
                        arproc.slit_profile(self, mspixelflat, det, ntcky=settings.argflag['reduce']['flatfield']['params'][0])
                    # If some slit profiles/blaze functions need to be extrapolated, do that now
                    if np.sum(extrap_slit) != 0.0:
                        slit_profiles, mstracenrm, msblaze = arproc.slit_profile_pca(
                            self, mspixelflat, det, msblaze, extrap_slit,
                            slit_profiles)
                    mspixelflatnrm = mstracenrm.copy()
                    winpp = np.where(slit_profiles != 0.0)
                    mspixelflatnrm[winpp] /= slit_profiles[winpp]
                    if np.array_equal(self._idx_flat, self._idx_trace):
                        # The flat field frame is also being used to trace the slit edges and determine the slit
                        # profile. Avoid recalculating the slit profile and blaze function and save them here.
                        self.SetFrame(self._msblaze, msblaze, det)
                        self.SetFrame(self._slitprof, slit_profiles, det)
                        armasters.save_masters(self, det, mftype='slitprof')
                        if settings.argflag["reduce"]["slitprofile"][
                                "perform"]:
                            msgs.info("Preparing QA of each slit profile")
                            arqa.slit_profile(self,
                                              mstracenrm,
                                              slit_profiles,
                                              self._lordloc[det - 1],
                                              self._rordloc[det - 1],
                                              self._slitpix[det - 1],
                                              desc="Slit profile")
                        msgs.info("Saving blaze function QA")
                        arqa.plot_orderfits(self,
                                            msblaze,
                                            flat_ext1d,
                                            desc="Blaze function")
                else:
                    mspixelflat = mspixelflatnrm
            else:  # It must be the name of a file the user wishes to load
                mspixelflat_name = armasters.user_master_name(
                    settings.argflag['run']['directory']['master'],
                    settings.argflag['reduce']['flatfield']['useframe'])
                mspixelflatnrm, head = arload.load_master(mspixelflat_name,
                                                          exten=det,
                                                          frametype=None)
                mspixelflat = mspixelflatnrm
            # Now that the combined, master flat field frame is loaded...
        else:
            msgs.work(
                "Pixel Flat arrays need to be generated when not flat fielding"
            )
            msgs.bug("Blaze is currently undefined")
            mspixelflat = np.ones_like(self._msarc)
            mspixelflatnrm = np.ones_like(self._msarc)
        # Set Master Frames
        self.SetMasterFrame(mspixelflat, "pixelflat", det)
        self.SetMasterFrame(mspixelflatnrm, "normpixelflat", det)
        armasters.save_masters(self, det, mftype='normpixelflat')
        return True
示例#14
0
    def MasterArc(self, fitsdict, det):
        """
        Generate Master Arc frame for a given detector

        Parameters
        ----------
        fitsdict : dict
          Contains relevant information from fits header files
        det : int
          Index of the detector

        Returns
        -------
        boolean : bool
          Should other ScienceExposure classes be updated?
        """
        dnum = settings.get_dnum(det)

        if self._msarc[det - 1] is not None:
            msgs.info("A master arc frame already exists for this frame")
            return False
        if settings.argflag['arc']['useframe'] in ['arc']:
            # Master Frame
            try:
                msarc = armasters.get_master_frame(self, "arc")
            except IOError:
                msgs.info("Preparing a master arc frame")
                ind = self._idx_arcs
                # Load the arc frames
                frames = arload.load_frames(fitsdict,
                                            ind,
                                            det,
                                            frametype='arc',
                                            msbias=self._msbias[det - 1])
                if settings.argflag['arc']['combine']['match'] > 0.0:
                    sframes = arsort.match_frames(
                        frames,
                        settings.argflag['arc']['combine']['match'],
                        frametype='arc',
                        satlevel=settings.spect[dnum]['saturation'] *
                        settings.spect[dnum]['nonlinear'])
                    subframes = np.zeros(
                        (frames.shape[0], frames.shape[1], len(sframes)))
                    numarr = np.array([])
                    for i in range(len(sframes)):
                        numarr = np.append(numarr, sframes[i].shape[2])
                        msarc = arcomb.comb_frames(sframes[i], det, 'arc')
                        # Send the data away to be saved
                        subframes[:, :, i] = msarc.copy()
                    del sframes
                    # Combine all sub-frames
                    msarc = arcomb.comb_frames(subframes,
                                               det,
                                               'arc',
                                               weights=numarr)
                    del subframes
                else:
                    msarc = arcomb.comb_frames(frames, det, 'arc')
                del frames
        else:  # Use input frame name located in MasterFrame directory
            msarc_name = settings.argflag['run']['directory'][
                'master'] + '/' + settings.argflag['arc']['useframe']
            msarc, _ = arload.load_master(msarc_name, frametype=None)

        # Set and then delete the Master Arc frame
        self.SetMasterFrame(msarc, "arc", det)
        armasters.save_masters(self, det, mftype='arc')
        del msarc
        return True