Beispiel #1
0
def check_gmos_image(filepath, calibrations=False):
    from astrodata import AstroData
    reason = "GMOS image"
    try:
        ad = AstroData(filepath)
    except:
        reason = "can't load file"
        return False, reason
    
    try:
        fp_mask = ad.focal_plane_mask().as_pytype()
    except:
        fp_mask = None

    if "GMOS" not in ad.types:
        reason = "not GMOS"
        return False, reason
    elif "GMOS_DARK" in ad.types:
        reason = "GMOS dark"
        return False, reason
    elif "GMOS_BIAS" in ad.types and not calibrations:
        reason = "GMOS bias"
        return False, reason
    elif "GMOS_IMAGE_FLAT" in ad.types and not calibrations:
        reason = "GMOS flat"
        return False, reason
    elif ("GMOS_IMAGE" in ad.types and
          fp_mask!="Imaging"):
        reason = "GMOS slit image"
        return False, reason
    elif (("GMOS_IMAGE" in ad.types and
           fp_mask == "Imaging" and
           "GMOS_DARK" not in ad.types) or
          "GMOS_BIAS" in ad.types or 
          "GMOS_IMAGE_FLAT" in ad.types):

        # Test for 3-amp mode with e2vDD CCDs
        # This mode has not been commissioned.
        dettype = ad.phu_get_key_value("DETTYPE")
        if dettype == "SDSU II e2v DD CCD42-90":
            namps = ad.phu_get_key_value("NAMPS")
            if namps is not None and int(namps)==1:
                reason = "uncommissioned 3-amp mode"
                return False, reason
            else:
                return True, reason
        else:
            return True, reason
    else:
        reason = "not GMOS image"
        return False, reason
Beispiel #2
0
def check_gmos_longslit(filepath):
    from astrodata import AstroData
    reason = "GMOS longslit"

    try:
        ad = AstroData(filepath)
    except:
        reason = "can't load file"
        return False, reason
    
    try:
        fp_mask = ad.focal_plane_mask().as_pytype()
    except:
        fp_mask = None

    if "GMOS" not in ad.types:
        reason = "not GMOS"
        return False, reason
    elif "GMOS_DARK" in ad.types:
        reason = "GMOS dark"
        return False, reason
    elif "GMOS_BIAS" in ad.types:
        reason = "GMOS bias"
        return False, reason
    elif "GMOS_NODANDSHUFFLE" in ad.types:
        reason = "GMOS nod and shuffle"
        return False, reason
    elif "GMOS_LS" in ad.types:

        # Test for 3-amp mode with e2vDD CCDs
        # This mode has not been commissioned.
        dettype = ad.phu_get_key_value("DETTYPE")
        if dettype == "SDSU II e2v DD CCD42-90":
            namps = ad.phu_get_key_value("NAMPS")
            if namps is not None and int(namps)==1:
                reason = "uncommissioned 3-amp mode"
                return False, reason
            else:
                return True, reason
        else:
            return True, reason
    else:
        reason = "not GMOS longslit"
        return False, reason
 def recover(self):
     log.debug("OutAtList recover()")
     adlist = []
     for i, tmpname in enumerate(self.diskoutlist):
         ad = AstroData(tmpname, mode="update")
         ad.filename = self.ad_name[i]
         ad = gemini_tools.obsmode_del(ad)
         # Read the database back in, if it exists
         try:
             ad = gemini_tools.read_database(
                 ad, database_name=self.database_name, 
                 input_name=self.tmpin_name[i], 
                 output_name=ad.phu_get_key_value("ORIGNAME"))
         except:
             pass
         adlist.append(ad)
         log.fullinfo(tmpname + " was loaded into memory")
     return adlist
class AcquisitionImage(object):
    def __init__(self, filename, mosmask=None, mdfdir=None):
        self.ad = AstroData(filename)
        self.mosmask = mosmask
        self.mdfdir = mdfdir

        # Determine extension
        nsci = len(self.ad)
        debug("...nsci = ", nsci)
            
        if nsci > 1:
            l_sci_ext = 1 
        else:
            l_sci_ext = 0

        debug("...using extension [" + str(l_sci_ext) + "]")

        overscan_dv = self.ad[l_sci_ext].overscan_section()

        if self.is_mos_mode():
            self.box_coords = parse_box_coords(self, self.get_mdf_filename())
            self.box_mosaic = BoxMosaic(self, self.box_coords)
            self.scidata = self.box_mosaic.get_science_data()
        elif self.is_new_gmosn_ccd():
            # tile the 2 center parts of the new GMOS image
            self.scidata = gmultiamp(self.ad)
        elif not overscan_dv.is_none():
            # remove the overscan so we don't have to take it into account when guessing the slit location
            self.scidata = subtract_overscan(self.ad[l_sci_ext])

            # it still affects the center of rotation however
            ox1, ox2, oy1, oy2 = overscan_dv.as_list()
            correction = np.array([ox2 - ox1, 0])
            center = self.get_binned_data_center() - correction
            self.fieldcenter = center * self.detector_y_bin()
        else:
            self.scidata = self.ad[l_sci_ext].data

    @cache
    def instrument(self):
        return str(self.ad.instrument())

    def is_new_gmosn_ccd(self):
        header = self.ad.phu.header
        if "DETECTOR" not in header:
            return False
        
        if header["DETECTOR"] == "GMOS + e2v DD CCD42-90":
            return True
        return False

    def get_science_data(self):
        assert self.scidata is not None
        return self.scidata

    @cache
    def unbinned_pixel_scale(self):
        return float(self.ad.pixel_scale()) / self.detector_y_bin()

    @cache
    def binned_pixel_scale(self):
        return float(self.ad.pixel_scale())

    def _check_binning(self):
        if int(self.ad.detector_x_bin()) != int(self.ad.detector_y_bin()):
            error("ERROR: incorrect binning!")
            error("Sorry about that, better luck next time.")
            sys.exit(1)

    @cache
    def detector_x_bin(self):
        self._check_binning()
        return int(self.ad.detector_x_bin())

    @cache
    def detector_y_bin(self):
        self._check_binning()
        return int(self.ad.detector_y_bin())

    @cache
    def program_id(self):
        return str(self.ad.program_id())

    @cache
    def observation_id(self):
        return str(self.ad.observation_id())

    @cache
    def saturation_level(self):
        dv = self.ad.saturation_level()
        return min(dv.as_list())

    @cache
    def focal_plane_mask(self):
        return str(self.ad.focal_plane_mask())

    @cache
    def grating(self):
        return str(self.ad.grating())

    def get_detector_size(self):
        # mos mode acquisitions don't necessarily have the entire
        # field of view in their data sections, so we have to rely on
        # other tricks to figure out the center of rotation.

        detsize = self.ad.phu_get_key_value("DETSIZE")
        xmin, xdim, ymin, ydim = extract_dimensions(detsize)
        
        # adjust for chip gaps
        nccds = int(self.ad.phu_get_key_value("NCCDS"))
        xdim += ((nccds - 1) * _obtain_unbinned_arraygap(self.ad))

        # adjust for un-illuminated pixels
        if self.is_gmos():
            ydim -= 36 # magic number that should be replaced with a lookup table later

        return xdim, ydim
        

    def get_field_center(self):
        """ The center of rotation in pixels. """
        if hasattr(self, "fieldcenter"):
            return self.fieldcenter

        if self.is_mos_mode():
            xdim, ydim = self.get_detector_size()
            return np.array([float(xdim) / 2.0, float(ydim) / 2.0])

        return self.get_data_center()

    def get_data_center(self):
        ydim, xdim = self.get_science_data().shape
        return np.array([float(xdim) / 2.0, float(ydim) / 2.0]) * self.detector_y_bin()

    def get_binned_data_center(self):
        return self.get_data_center() / self.detector_y_bin()

    def set_goal_center(self, center):
        self.goal_center = np.array(center)

    def get_goal_center(self):
        default = self.get_data_center()
        return getattr(self, "goal_center", default)

    def set_binned_custom_center(self, center):
        self.set_binned_goal_center(center)
        self.custom_center = True

    def has_custom_center(self):
        return getattr(self, "custom_center", False)

    def get_binned_goal_center(self):
        return self.get_goal_center() / self.detector_y_bin()

    def set_binned_goal_center(self, center):
        center = np.array(center) * self.detector_y_bin()
        self.set_goal_center(center)

    def get_mask_width(self):
        debug("...finding slit dimensions...")
        
        slitxbin = self.detector_x_bin()
        slitybin = self.detector_y_bin()
        debug("...slit image binning = ", slitxbin, " x ", slitybin)
        if slitxbin > 1 or slitybin > 1:
            warning("! WARNING: Slit image is binned " + slitxbin + " x " + slitybin)

        slitmask = self.focal_plane_mask()
        return float(slitmask.replace("arcsec", ""))

    def get_mask_width_in_pixels(self):
        return self.get_mask_width() / self.unbinned_pixel_scale()

    def get_slit_size_in_pixels(self):
        xsize = self.get_mask_width_in_pixels()
        ysize = self.get_science_data().shape[0]
        return xsize, ysize

    def get_expected_slit_tilt(self):
        if self.is_gmos():
            return 0.0

        error("Instrument is not supported, need to know an expected slit tilt")
        sys.exit(1)

    @property
    def phu(self):
        return self.ad.phu

    @property
    def filename(self):
        return self.ad.filename

    def get_program_id_parts(self):
        gemprgid = str(self.ad.program_id())
        parts = gemprgid.split("-")
        if len(parts) != 4:
            msg = "Cannot parse program id '%s'" % gemprgid
            error(msg)
            raise ValueError(msg)
        observatory, semester, prgtype, queuenum = parts
        return observatory, semester, prgtype, int(queuenum)

    def get_semester(self):
        """ Return something in the form of '2006B' """
        observatory, semester, prgtype, queuenum = self.get_program_id_parts()
        return semester

    def get_observatory_prefix(self):
        """ Return something in the form of 'GN' """
        observatory, semester, prgtype, queuenum = self.get_program_id_parts()
        return observatory

    def is_mos_mode(self):
        return self.mosmask is not None or self.has_mos_mask()

    @cache
    def has_mos_mask(self):
        if not self.is_gmos() and not self.is_f2():
            return False

        maskname = self.focal_plane_mask()
        if ("Q" in maskname or   # Queue program
            "C" in maskname or   # Classical program
            "D" in maskname or   # DD program
            "V" in maskname):    # SV program

            xbin = self.detector_x_bin()
            ybin = self.detector_y_bin()
            if xbin != 1 or ybin != 1:
                error ("MOS acquisition image binning must be 1x1, found %ix%i binning." % (xbin, ybin))
                clean()

            return True
        return False

    def has_mask_in_beam(self):
        maskname = self.focal_plane_mask().lower()
        if "imag" in maskname:
            return False

        slitmask = self.focal_plane_mask()    
        if self.is_gmos() and "arcsec" in slitmask:
            return True
    
        if self.is_gnirs() and "arcsec" in slitmask:
            acqmir = slitimage_ad.phu.header["ACQMIR"]
            debug("...acqmir = ", acqmir)
            if acqmir == "In":
                return True
    
        if self.is_niri() and "cam" not in slitmask:
            return True
    
        if self.is_f2() and "slit" in slitmask:
            return True

        if self.is_f2() and "mos" in slitmask:
            return True

        return self.has_mos_mask()

    def get_mdf_filename(self):
        if hasattr(self, "mdffile"):
            return self.mdffile

        self.mdffile = self._get_mdf_filename()
        return self.mdffile

    def _get_mdf_filename(self):
        if self.mosmask is not None:
            mdffile = self.mosmask

            # Expand the MOS mask number
            if is_number(self.mosmask):
                observatory, semester, prgtype, queuenum = self.get_program_id_parts()
                mdffile = "%s%s%s%03i-%02i" % (observatory, semester, prgtype, queuenum, int(self.mosmask))
                debug("...mosmask =", mdffile)
        else:
            mdffile = self.focal_plane_mask()

        mdffile = fits_filename(mdffile)

        #-----------------------------------------------------------------------
        # Start searching around willy nilly for the MDF file
        if os.path.exists(mdffile):
            return mdffile

        # note, the order in which directories are added to this list gives priority
        dirs = []
        if self.mdfdir is not None:
            dirs.append(self.mdfdir)

        dname = os.path.dirname(self.filename)
        if dname and dname != ".":
            dirs.append(dname)

        dirs.append(os.getcwd())

        # search through semester directories as well
        semester_dir = self.get_observatory_prefix() + self.get_semester()
        directories_to_search = []
        for dname in dirs:
            directories_to_search.append(dname)
            dname = os.path.join(dname, semester_dir)
            directories_to_search.append(dname)

        # now search through the directories
        for dname in directories_to_search:
            fname = os.path.join(dname, mdffile)
            debug("...trying", fname)
            if os.path.exists(fname):
                return fname

        raise ValueError("Unable to find MDF file named '%s'" % mdffile)

    def get_num_mos_boxes(self):
        return self.box_mosaic.get_num_mos_boxes()

    def get_mos_boxes(self):
        return self.box_mosaic.get_boxes()

    def get_mos_box_borders(self):
        for border in self.box_mosaic.get_box_borders():
            yield border

    @cache
    def get_min_slitsize(self):
        mdffile_ad = AstroData(self.get_mdf_filename())

        xsize = Ellipsis
        ysize = Ellipsis
        for row in mdffile_ad["MDF"].data:
            # select the alignment boxes, designated by priority 0
            if row["priority"] not in ["1", "2", "3"]:
                continue

            xsize = min(xsize, row["slitsize_x"])
            ysize = min(ysize, row["slitsize_y"])

        return xsize, ysize

    def get_extensions(self):
        for ext in self.ad:
            yield ext

    def _get_lazy_detector_section_finder(self):
        if not hasattr(self, "detsec_finder"):
            self.detsec_finder = DetectorSectionFinder(self)
        return self.detsec_finder

    def get_box_size(self):
        return self._get_lazy_detector_section_finder().get_box_size()

    def find_detector_section(self, point):
        return self._get_lazy_detector_section_finder().find_detector_section(point)

    def get_full_field_of_view(self):
        return self._get_lazy_detector_section_finder().get_full_field_of_view()

    def is_altair(self):
        aofold = self.ad.phu.header["AOFOLD"]
        if aofold == "IN":
            return True
        return False

    def is_south_port(self):
        inportnum = int(self.ad.phu.header["INPORT"])
        if inportnum == 1:
            return True
        return False

    def is_type(self, typename):
        return self.ad.is_type(typename)

    def is_gmos(self):
        return self.is_type("GMOS")
    
    def is_gmosn(self):
        return self.is_type("GMOS_N")

    def is_gmoss(self):
        return self.is_type("GMOS_S")

    def is_gnirs(self):
        return self.is_type("GNIRS")

    def is_f2(self):
        return self.is_type("F2")

    def is_nifs(self):
        return self.is_type("NIFS")

    def is_niri(self):
        return self.is_type("NIRI")
Beispiel #5
0
def test_method_phu_get_key_val_6():
    ad = AstroData(TESTFILE2)
    with pytest.raises(TypeError):
        assert ad.phu_get_key_value()
Beispiel #6
0
def test_method_phu_get_key_val_5():
    ad = AstroData(TESTFILE2)
    assert ad.phu_get_key_value('FOO') is None
Beispiel #7
0
def test_method_phu_get_key_val_3():
    ad = AstroData(TESTFILE2)
    assert isinstance(ad.phu_get_key_value('RA'), float)
Beispiel #8
0
def test_method_phu_get_key_val_2():
    ad = AstroData(TESTFILE2)
    assert isinstance(ad.phu_get_key_value('BITPIX'), int)
Beispiel #9
0
def test_method_phu_get_key_val_1():
    ad = AstroData(TESTFILE2)
    assert isinstance(ad.phu_get_key_value('SIMPLE'), bool)
Beispiel #10
0
def test_method_phu_get_key_val_3():
    ad = AstroData(TESTFILE2)
    assert isinstance(ad.phu_get_key_value('RA'), float)
Beispiel #11
0
def test_method_phu_get_key_val_2():
    ad = AstroData(TESTFILE2)
    assert isinstance(ad.phu_get_key_value('BITPIX'), int)
Beispiel #12
0
def test_method_phu_get_key_val_1():
    ad = AstroData(TESTFILE2)
    assert isinstance(ad.phu_get_key_value('SIMPLE'), bool)
Beispiel #13
0
def test_method_phu_get_key_val_6():
    ad = AstroData(TESTFILE2)
    with pytest.raises(TypeError):
        assert ad.phu_get_key_value()
Beispiel #14
0
def test_method_phu_get_key_val_5():
    ad = AstroData(TESTFILE2)
    assert ad.phu_get_key_value('FOO') is None
Beispiel #15
0
def main():
    options, args, parser = handleClArgs()

    # If clean, call superclean to clear out cache and kill old reduce
    # and adcc processes.
    if options.clean:
        print "\nRestoring redux to default state:" + \
              "\nall stack and calibration associations will be lost;" + \
              "\nall temporary files will be removed.\n"
        subprocess.call(["superclean", "--safe"])
        print
        sys.exit()

    # Get local site
    if time.timezone / 3600 == 10:      # HST = UTC + 10
        localsite = GEMINI_NORTH
    elif time.timezone / 3600 == 4:     # CST = UTC + 4
        localsite = GEMINI_SOUTH
    else:
        print "ERROR - timezone is not HST or CST. Local site cannot " + \
              "be determined"
        sys.exit()

    # Check arguments
    if len(args) < 1:
        print "ERROR - No input file specified"
        parser.print_help()
        sys.exit()
    elif len(args) > 2:
        print "ERROR - Too many arguments"
        parser.print_help()
        sys.exit()
    elif len(args) == 2:
        date = gemini_date(args[0])
        if date != "":
            prefix = OBSPREF[localsite] + date + "S"
        else:
            print "ERROR - Date %s not recognized." % args[0]
            parser.print_help()
            sys.exit()

        filenm = prefix + "%04i" % int(args[1])
    else:
        filenm = args[0]

    # Get file prefix from user; otherwise, use auto    
    prefix = "auto"
    if options.prefix:
        prefix = options.prefix

    # Get data directory from user or from site defaults
    directory = "."
    if options.directory:
        directory = options.directory
    else:
        if os.path.exists(OPSDATAPATH[localsite]):
            directory = OPSDATAPATH[localsite]
        elif os.path.exists(OPSDATAPATHBKUP[localsite]):
            directory = OPSDATAPATHBKUP[localsite]
        else:
            print "Cannot find %s or %s. Please specify a directory." % \
                  (OPSDATAPATH[localsite], OPSDATAPATHBKUP[localsite])
    directory = directory.rstrip("/") + "/"

    # Check for stacking option
    recipe = None
    if options.stack:

        # Check for _forStack image in local directory
        if os.path.exists(filenm):
            stack_filenm = os.path.basename(filenm)
        else:
            stack_filenm = filenm

        imgpath = image_path(stack_filenm, ".", 
                             prefix=prefix, localsite=localsite,
                             suffix="_forStack")
        if imgpath is None:
            # If not found, check for raw image in specified directory
            # and use full reduction recipe
            imgpath = image_path(filenm, directory, 
                                 prefix=prefix, localsite=localsite)
            recipe = "qaReduceAndStack"
        else:
            # If found, just use stacking recipe
            recipe = "qaStack"
    else:
        imgpath = image_path(filenm, directory, 
                             prefix=prefix, localsite=localsite)

    if imgpath is None:
        print "\nFile %s was not found.\n" % filenm
        sys.exit()

    imgname = os.path.basename(imgpath)
    print "Image path: "+imgpath

    # Check that file is GMOS LONGSLIT or IMAGE; other types are not yet supported
    # (but do allow biases and flats, too)
    try:
        ad = AstroData(imgpath)
    except IOError:
        print "\nProblem accessing file %s.\n" % filenm
        sys.exit()

    try:
        fp_mask = ad.focal_plane_mask()
    except:
        fp_mask = None

    if "RAW" not in ad.types and "PREPARED" in ad.types:
        print "AstroDataType 'RAW'  not found in types."
        print "AstroDataType 'PREPARED' found in types."
        print "\nFile %s appears to have been processed." % imgname
        print "redux halting ..."
        sys.exit()
    if "GMOS" not in ad.types:
        print "\nFile %s is not a GMOS file." % imgname
        print "Only GMOS longslit and images can be reduced at this time.\n"
        sys.exit()
    elif "GMOS_DARK" in ad.types:
        print "\nFile %s is a GMOS dark." % imgname
        print "Only GMOS longslit and images can be reduced at this time.\n"
        sys.exit()
    elif ("GMOS_IMAGE" in ad.types and
          fp_mask!="Imaging"):
        print "\nFile %s is a slit image." % imgname
        print "Only GMOS longslit and images can be reduced at this time.\n"
        sys.exit()
    elif (("GMOS_IMAGE" in ad.types and
           fp_mask=="Imaging" and 
           "GMOS_DARK" not in ad.types) or 
          "GMOS_BIAS" in ad.types or 
          "GMOS_IMAGE_FLAT" in ad.types or 
          "GMOS_LS" in ad.types):

        # Test for 3-amp mode with e2vDD CCDs. NOT commissioned.
        dettype = ad.phu_get_key_value("DETTYPE")
        if dettype=="SDSU II e2v DD CCD42-90":
            namps = ad.phu_get_key_value("NAMPS")
            if namps is not None and int(namps)==1:
                print "\nERROR: The GMOS e2v detectors should " \
                      "not use 3-amp mode!"
                print "Please set the GMOS CCD Readout Characteristics " \
                      "to use 6 amplifiers.\n"
                sys.exit()

        print "\nBeginning reduction for file %s, %s\n" % (imgname,
                                                           ad.data_label()) 
        if options.upload:
            context = "QA,upload"
        else:
            context = "QA"

        # Check for an alternate recipe for science reductions
        if ("GMOS_IMAGE" in ad.types and
            "GMOS_BIAS" not in ad.types and 
            "GMOS_IMAGE_FLAT" not in ad.types and
            recipe is not None):
            reduce_cmd = ["reduce",
                          "-r", recipe,
                          "--context",context,
                          "--loglevel","stdinfo",
                          "--logfile","gemini.log",
                          "-p", "clobber=True",
                          imgpath]
        else:
            # Otherwise call reduce with auto-selected reduction recipe
            reduce_cmd = ["reduce", 
                          "--context",context,
                          "--loglevel","stdinfo",
                          "--logfile","gemini.log",
                          "-p", "clobber=True",
                          imgpath]
            
        subprocess.call(reduce_cmd)

        print ""

    else:
        print "\nFile %s is not a supported type." % imgname
        print "Only GMOS longslit and images can be reduced at this time.\n"
        sys.exit()