def _check_IOL(self): """Check the presence of all grism images.""" IOL_list = [] # go over all inputs for one_input in self.axe_inputs: if one_input['objcat'] in IOL_list: continue # check the prism image if not os.path.isfile(config_util.getDATA(one_input['objcat'])): raise aXeError("{0:s}: The direct image: '{1:s}' does not " "exist!".format( self.taskname, config_util.getDATA(one_input['objcat']))) # load the IOL to check its format try: _log.info("reading {}".format( config_util.getDATA(one_input['objcat']))) Table.read(config_util.getDATA(one_input['objcat']), format='ascii.sextractor') except IORegistryError: raise aXeError("{0:s} is not in a known format".format( one_input['objcat'])) # put the IOL to the list IOL_list.append(one_input['objcat'])
def _check_dpps(self, back=False): # go over all inputs for one_input in self.axe_inputs: # load the config file and get the extension information conf = configfile.ConfigFile( config_util.getCONF(one_input['config'])) ext_info = config_util.get_ext_info( config_util.getDATA(one_input['grisim']), conf) # derive the aXe names axe_names = config_util.get_axe_names(one_input['grisim'], ext_info) # check the DPP file if not os.path.isfile(config_util.getOUTPUT(axe_names['DPP'])): # error and out err_msg = ( f"{self.taskname}: The DPP file: {config_util.getOUTPUT(axe_names['DPP'])}" f" does not exist!") raise aXeError(err_msg) # check for the background DPP file if back and not os.path.isfile( config_util.getOUTPUT(axe_names['BCK_DPP'])): # error and out err_msg = ( f"{self.taskname}: The DPP file: {config_util.getOUTPUT(axe_names['BCK_DPP'])}" f" does not exist!") raise aXeError(err_msg)
def check_axedrizzle(self, infwhm, outfwhm, back=False): """Comprises all file and file format checks for AXEDRIZZLE""" # check the DPP files self._check_dpps(back) # make sure that fabs(infwhm) and fabs(outfwhm) > 0.0 if ((math.fabs(infwhm) == 0.0) or (math.fabs(outfwhm) == 0.0)): err_msg = ( "{0:s}: fabs(infwhm) AND fabs(outfwhm) must be larger " "than 0.0, but infwhm={1:0.1f} and outfwhm={2:0.1f}!".format( self.taskname, infwhm, outfwhm)) raise aXeError(err_msg) # make sure that fabs(infwhm) > fabs(outfwhm) if (math.fabs(infwhm) < math.fabs(outfwhm)): err_msg = ("{0:s}: fabs(infwhm) MUST be larger than fabs(outfwhm)," " but infwhm={1:0.1f} and outfwhm={2:0.1f}!".format( self.taskname, infwhm, outfwhm)) raise aXeError(err_msg) # make sure that infwhm and outfwhm # have consistent sign if ((infwhm * outfwhm) < 0.0): err_msg = ("{0:s}: infwhm={1:0.1f} and outfwhm={2:0.1f} must BOTH" "be either positive or negative!".format( self.taskname, infwhm, outfwhm)) raise aXeError(err_msg)
def __setitem__(self, index, obj): """Setindex method for the class The operator method which is called when the index of a class instance is set to a value. kkk[0] = test Parameters ---------- index: int the index to address obj: list description of the object content """ # check whether the index exists if index > len(self.kvallist) - 1: # raise an exception err_msg = 'Index ' + str(index) + ' does not exist!' raise aXeError(err_msg) # check whether the input type is correct elif not (isinstance(type(self[0]), obj)): # raise an exception err_msg = ("Object: {0:s} has wrong type: {1:s}!".format( str(obj), str(type(obj)))) raise aXeError(err_msg) # set the index to the input object self.kvallist[index] = obj
def _set_coefficients(self): """Extracts the drizzle coefficients.""" try: self.imwcs = HSTWCS(self.image, ext=self.detector) #self.xcoeffs, self.ycoeffs = coeff_converter.sip2idc(self.imwcs) except ValueError: raise aXeError( "Could not determine distorsion coefficients from header.") # dictionary with the fixed names for the orders fixed_orders = { 1: 'constant', 2: 'linear', 3: 'quadratic', 4: 'cubic', 5: 'quintic' } self.xcoeffs = np.array([[0.0], [1.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0]]) self.ycoeffs = np.array([[0.0], [0.0], [1.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0]]) # return the order # for HST the a and b orders should always match # sip.ap_order is the inverse # if (self.imwcs.sip.a_order != self.imwcs.sip.b_order): # raise aXeError("SIP a and b orders don't match!") # self.order = fixed_orders[self.imwcs.sip.a_order] try: self.order = fixed_orders[len(self.xcoeffs) / 2] except KeyError: raise aXeError( f'Coefficient order not available: {self.order} in {fixed_orders}' )
def _validate_columns(self): """Identify columns according to the Input Image List format""" columns = self._inimlist.colnames # check for number of columns if len(columns) < 2: err_msg = ("Expected at least 2 columns in {self._inimlist}!") raise aXeError(err_msg) columns.reverse() name = columns.pop() if ((np.issubsctype(self._inimlist[name], np.str)) and ('fits' in self._inimlist[name][0])): self._inimlist.rename_column(name, 'grisim') else: err_msg = (f"Column 1 should be the names of the grism" " fits files: {self._inimlist}") raise aXeError(err_msg) # check whether second column has type string name = columns.pop() if np.issubsctype(self._inimlist[name], np.str): self._inimlist.rename_column(name, 'objcat') else: err_msg = ("Column 2 should be the names of the object catalogs" "{0}".format(self._inimlist)) raise aXeError(err_msg) # do a check on the first object catalog to make sure it's a format # that we can read try: _temp_cat = self._inimlist[0]['objcat'].split(',')[0] __ = Table.read(config_util.getDATA(_temp_cat), format='ascii.sextractor') except IORegistryError: raise aXeError( "Catalog format not recognized , checked for: {0:s}".format( self._inimlist[name][0])) # go over all remaining rows to find DMAG and DIRIM while columns: name = columns.pop() # assume if it's a number it's DMAG if np.issubsctype(self._inimlist[name], np.float): self._inimlist.rename_column(name, 'dmag') # assume if it's a string its the direct image elif np.issubsctype(self._inimlist.columns[0], np.str): if '.fits' in self._inimlist.columns[0][0]: self._inimlist.rename_column(name, 'dirim') else: err_msg = ("Problem identifying last columns in: {0}".format( self._inimlist)) raise aXeError(err_msg)
def _extend_asciidata(self): """Extend the table to one data set per line. This is where the association of files, catalogs, and configs for instruments that that contain more than one science chip in a file is done. The table is expanded so that each row has one file, one configuration, and one catalog associated with it. The rest of aXe is run based on no comma delimited lists. """ new_inimlist = deepcopy(self._inimlist) for row in self._inimlist: clist = row['config'].split(',') olist = row['objcat'].split(',') if len(olist) > 1: if (len(clist) != len(olist)): err_msg = ("Number of object cats in {0:s} " "is different from number of " "configs in {1:s}".format( row['objcat'], row['config'])) raise aXeError(err_msg) else: olist = olist * len( clist) # there can be one cat and multiple config if 'fringe' in row.colnames: flist = row['fringe'].split(',') if (len(clist) != len(flist)): err_msg = (f"Number of fringe configs " f"is different from number of aXe configs " f"in {row['config']}") raise aXeError(err_msg) new_inimlist[row.index]['fringe'] = flist.pop() new_inimlist[row.index]['config'] = clist.pop() new_inimlist[row.index]['objcat'] = olist.pop() if 'fringe' in row.colnames: for conf, objcat, fringe in zip(clist, olist, flist): new_row = [ row['grisim'], objcat, row['dirim'], conf, row['dmag'], fringe ] new_inimlist.add_row(new_row) else: for conf, objcat in zip(clist, olist): new_row = [ row['grisim'], objcat, row['dirim'], conf, row['dmag'] ] new_inimlist.add_row(new_row) self._inimlist = deepcopy(new_inimlist) del new_inimlist
def _check_global_backsub(self): """Check for global background subtraction""" # go over all inputs for one_input in self.axe_inputs: # load the config file and get the extension information conf = configfile.ConfigFile( config_util.getCONF(one_input['config'])) ext_info = config_util.get_ext_info( config_util.getDATA(one_input['grisim']), conf) # open the fits image gri_fits = fits.open(config_util.getDATA(one_input['grisim']), 'readonly') # go to the correct header act_header = gri_fits[ext_info['fits_ext']].header # make sure a sky background value is set if 'SKY_CPS' in act_header and act_header['SKY_CPS'] >= 0.0: # close the fits gri_fits.close() else: # close fits, complain and out gri_fits.close() err_msg = ( "{0:s}: The grism image: \n{1:s}\nhas no keyword " "SKY_CPS>=0.0 in the extension {2:d}. This means " "it had NO global\nsky subtraction, which is " "required for the CRR version of aXedrizzle!".format( self.taskname, config_util.getDATA(one_input['grisim']), ext_info['fits_ext'])) raise aXeError(err_msg)
def _transfer_coos(self): """Transfer coordinates from the IOL to the GOL""" # compose the WCS-term for the direct and grism images dir_term = getDATA("{0:s} [{1:d}]".format( self.dirname, self.dirname_extinfo['fits_ext'])) gri_term = getDATA("{0:s} [{1:d}]".format( self.grisim, self.grism_extinfo['fits_ext'])) # generate the WCS objects dir_wcs = wcsutil.WCSObject(dir_term) gri_wcs = wcsutil.WCSObject(gri_term) # go over each row in the catalog for row in self.gol: # make a position tuple try: xy_direct = (row['X_IMAGE'], row['Y_IMAGE']) except KeyError: # self._treat_NULL_table raise aXeError("No coordinate columns in catalog, empty?") # convert to RADEC using the direct image radec_pos = dir_wcs.xy2rd(xy_direct) # convert to XY on grism image xy_grism = gri_wcs.rd2xy(radec_pos) # store projected vals in the GOL row['X_IMAGE'] = float(xy_grism[0]) row['Y_IMAGE'] = float(xy_grism[1])
def __getitem__(self, index): """Getindex method for the class The operator method which is called when an index is requested on a class instace test = kkk[0] Parameters ---------- index: int the index to address Returns ------- obj: float the indexed object """ # check whether the index exists if index > len(self.kvallist) - 1: # raise an exception err_msg = 'Index: ' + str(index) + ' does not exist!' raise aXeError(err_msg) # return the indexed object return self.kvallist[index]
def _check_gfiles(self): """Checks whether all files exist The method checks whether the files whose names are within the class data do exist or not. An error is reported in case that the files do not exist. """ # list of the root of all # global keys indicating a file fkeys = ['FFNAME'] # go over all file keywords for key in fkeys: # identify the keyword in the list index = self._get_gkey_index(key) # check for existence if index > -1: # extract the keyvalue kvalue = self.gkeys[index].keyvalue # if the keyvalue is NOT None but the file does not exist if ((kvalue.upper() is not 'NONE') and (not os.path.isfile(config_util.getCONF(kvalue)))): # report an error err_msg = ("The file: {0:s} does not exist!".format( config_util.getCONF(kvalue))) raise aXeError(err_msg)
def _get_indims(self, fcube_info): """Get the dimensions of the image @param fcube_info: the fluxcube info @type fcube_info: dict @return: the image dimension @rtype: [int,int] """ # make sure the fits image exists if not os.path.isfile(fcube_info['fits']): msg = "Image: {0:s} does not exist!".format(fcube_info['fits']) raise aXeError(msg) # open the image and get the header in_img = fits.open(fcube_info['fits'], 'readonly') in_head = in_img[fcube_info['ext_nam'], fcube_info['ext_ver']].header # extract the keywords for the image size from # the header dims = [in_head['NAXIS1'], in_head['NAXIS2']] # close the image in_img.close() # return the list with the image dimension return dims
def __getitem__(self, index): """Getindex method for the class The operator method which is called when an index is requested on a class instace test = kkk[0] Parameters ---------- index: int the index to address Returns ------- key : ConfListKey the indexed object """ # check whether the index exists if index > len(self.twodkeys) - 1: # raise an exception err_msg = "Index: {0:s} does not exist!".format(str(index)) raise aXeError(err_msg) # return the indexed object return self.twodkeys[index]
def _check_gain_correction(self): """Check whether the gain correction had already been applied """ msg = ("AXEPREP: Non-NICMOS images such as: {self.grisim} usually are " "already gain corrected!") raise aXeError(msg)
def __init__(self, drizzle_image, input_cat, dim_term): """ Parameters ---------- drizzle_image: str the name of the drizzled image input_cat: str the name of the input catalogue made from the mosaic drizzled image, the master catalog dim_term: description of the additional rows/column for the Input Object Lists Returns ------- Nothing Notes ----- Basic checks on the input is done. The existence of the images is checked, also the data type of the various real or integer numbers. """ self.iol_list = [] self.dim_info = [] # check whether the drizzled image exists, # store the name if it exists if not os.path.isfile(drizzle_image): err_msg = "File: {0:s} does not exist!".format(drizzle_image) raise aXeError(err_msg) else: self.drizzle_image = drizzle_image # check whether the input catalogue exists, # store the name if it exists if not os.path.isfile(input_cat): err_msg = 'File: ' + input_cat + ' does not exist!' raise aXeError(err_msg) else: self.input_cat = Table.read(input_cat, format='ascii.sextractor') # resolve and get the dimension information self._set_dimension_info(dim_term) # create the list of Input Object Instances self._fill_iollist()
def _check_low_skyfrac(self, frac): """Check for a low fraction of background pixels""" msg = ( f"\nAXEPREP Image {self.grisim}: Only {frac*100.0} percent of the pixels " "were used in the background scaling!") raise aXeError(msg)
def _make_fluxim(self, img_name, wav_pivot, zeropoint, AB_zero): """Generate a flux image""" # check whether the first item is the name of an existing file if not os.path.isfile(img_name): raise aXeError("File {0:s} does not exist!".format(img_name)) # check whether the second item is a float if self._toFloat(wav_pivot) is None: raise aXeError("Expression {} must be a float!".format(wav_pivot)) # check whether the third item is a float if self._toFloat(zeropoint) is None: err_msg = 'Expression: ' + zeropoint + ' must be float!' raise aXeError(err_msg) # create a new fluximage and return it return FluxImage(img_name, float(wav_pivot), float(zeropoint), AB_zero)
def _check_second_normalization(self): """Check whether the data is already normalized. """ msg = ( f"AXEPREP: Image {self.grisim} has already been normalized! Will not renormalize" ) raise aXeError(msg)
def _check_second_gaincorr(self): """Check whether the gain correction had already been applied. """ msg = ( f"AXEPREP: Image: {self.grisim} has already been gain corrected! Will not reapply." ) raise aXeError(msg)
def check_axeprep(self, backgr, backims): """Comprises all file and file format checks for AXEPREP""" # check for background subtraction if backgr: if not backims: err_msg = ("{0:s}: A background image must be given for the " "background subtraction!".format(self.taskname)) raise aXeError(err_msg)
def _check_grisms(self): """Check the existence of the grism files.""" # go over all rows in the list for row in self._inimlist: # check the existence of the Input Image List if not os.path.isfile(row['grisim']): err_msg = ("Grism image: {0:s} does not exist!".format( row['grisim'])) raise aXeError(err_msg)
def _validate_columns(self): """Validate all required columns""" # the list of mandatory columns mand_colnames = [ "NUMBER", "X_IMAGE", "Y_IMAGE", "A_IMAGE", "B_IMAGE", "THETA_IMAGE", "X_WORLD", "Y_WORLD", "A_WORLD", "B_WORLD", "THETA_WORLD" ] # the list of optional columns # opt_colnames = ["MODSPEC", "MODIMAGE"] # go over all mandatory columns for colname in mand_colnames: if colname not in self.catalog.colnames: err_msg = ("Input Object List: {0:s} does not contain column " "{1:s}".format(self.filename, colname)) raise aXeError(err_msg) # check for the MAG_AUTO-column mauto_col = "MAG_AUTO" in self.catalog.colnames # get the columns with an encoded wavelength wav_cols = self.search_mcols() # check whether there is no mag-column if ((not mauto_col) and (len(wav_cols) == 0)): # complain and out err_msg = ("Catalogue: {0:s} does not contain any magnitude " "column!".format(self.filename)) raise aXeError(err_msg) # check whether there is only MAG_AUTO elif ((mauto_col) and (len(wav_cols) == 0)): wav_cols = [{'name': 'MAG_AUTO', 'lambda': None}] # check whether there is MAG_AUTO and magval columns elif ((mauto_col) and (len(wav_cols) > 1)): err_msg = ("Catalogue: {0:s} contains 'MAG_AUTO' and {1:i} other " "magnitude columns!".format(self.filename, len(wav_cols))) raise aXeError(err_msg)
def _check_subarray(self): """ check for and reject subarray images """ # go over all rows in the list for row in self._inimlist: # check the existence of the Input Image List image = config_util.getDATA(row['grisim']) subarray = fits.getval(image, "SUBARRAY", ext=0) if subarray: err_msg = ("Grism image: {0:s} is a subarray" " which is not supported".format(image)) raise aXeError(err_msg) if 'dirim' in self._inimlist.colnames: image = config_util.getDATA(row['dirim']) subarray = fits.getval(image, "SUBARRAY", ext=0) if subarray: err_msg = ("Direct image: {0:s} is a subarray" " which is not supported".format(image)) raise aXeError(err_msg)
def _check_files(self, dpp_list): """check for the existence of all DPP's""" for one_dpp in dpp_list: # make the full path name full_path = config_util.getOUTPUT(one_dpp) # check for existence if not os.path.isfile(full_path): # complain and out err_msg = 'Can not find the DPP file: %s!' % full_path raise aXeError(err_msg)
def getCONF(name=None): fullpath = __user_paths['AXE_CONFIG_PATH'] if fullpath in name: return name if name is None: raise aXeError("No name passed to getCONF") if len(name.split(',')) > 1: namesplit=name.split(',') newstring = [os.path.join(i,j) for i,j in zip([fullpath]*len(namesplit), namesplit) if fullpath not in j] return ','.join(newstring) else: return os.path.join(__user_paths['AXE_CONFIG_PATH'], name)
def _force_dirim(self): # go over all inputs for one_input in self.axe_inputs: # check whether there is a direct image if one_input['DIRIM'] is None: # error and out err_msg = ("{0:s}: The grism image: {1:s} does NOT have an " "associated direct image!".format( self.taskname, config_util.getDATA(one_input['grisim']))) raise aXeError(err_msg)
def check_axecrr(self, back): """ Comprises all checks for the CRR version of AXEDRIZZLE """ # make sure that background drizzling is off if back: err_msg = ("{0:s}: Background drizzling is NOT possible in the CRR" "version of aXedrizzle!".format(self.taskname)) raise aXeError(err_msg) # check for global background subtraction self._check_global_backsub()
def _get_dirname_information(self, dirname=None, config="", grisim="", grism_extinfo=None, dir_hdu=None): """Determine the direct image information. Parameters ---------- dirname : str Diretory name config : str The name of the config file grisim : str The name of the grisim image grism_extinfo : dict Dictionary of header information dir_hdu : fits.HDU FITS header data unit Returns ------- A tuple of the direct image name and a dictionary of extension information """ # check whether ANY direct image information exists if ((dirname is None) and (dir_hdu is None)): # set the grism image as direct image dirname = grisim dirname_extinfo = grism_extinfo elif ((dirname is not None) and (dir_hdu is None)): # load the configuration file; # determine the extension information conf = configfile.ConfigFile(getCONF(config)) dirname_extinfo = get_ext_info(getDATA(grisim), conf) del conf elif ((dirname is not None) and (dir_hdu is not None)): # make by hand the extension information dirname_extinfo = {'axe_ext': dir_hdu, 'fits_ext': dir_hdu - 1} else: # error and out err_msg = ("Specifying NO direct image but a direct image HDU: " "{0:d} makrs NO sense!".format(dir_hdu)) raise aXeError(err_msg) # return the name and the extension info return dirname, dirname_extinfo
def _set_dimension_info(self, dimension_term): """Get the dimension information""" # initialize the array # check the dimension input dim_entries = dimension_term.split(',') # is the number of items correct? if len(dim_entries) != 4: err_msg = ("There must be 4 entries in the term: {0:s}," "not {1:d}!".format(dimension_term, len(dim_entries))) raise aXeError(err_msg) # check whether each item is an integer for item in dim_entries: try: int_item = int(item.strip()) except ValueError: raise aXeError("Item: {} must be integer!".format(item)) # store the item self.dim_info.append(int_item)
def _resolve_list_names(self, dirname='', dirname_extinfo=None, grisim='', grism_extinfo=None, in_sex=None, out_sex=None): """Determine the lists for input and output. Parameters ---------- dirname : str The direct image name dirname_extinfo : dict A dictionary that contains the direct header and data information grisim : str The name of the grisim image grism_extinfo : dict A dictionary that contains the grism header and data information in_sex : str The name of the source extractor catalog that goes with the direct image out_sex : str The name of the output grism object list that is created using the input catalog Returns ------- A tuple of the names of the input and output catalog names """ # compose the default name if in_sex is None: # compose the filename from the direct image name in_sex = dirname.replace( ".fits", "_{0:d}.cat".format(dirname_extinfo['axe_ext'])) # check whether the explicitly given filename exists if not os.path.isfile(in_sex): err_msg = ( "The Input Object List: {0:s} does not exist!".format(in_sex)) raise aXeError(err_msg) if out_sex is None: # compose the name for the output GOL out_sex = os.path.basename(grisim).replace( ".fits", "_{0:d}.cat".format(grism_extinfo['axe_ext'])) # return the IOL and the GOL names return in_sex, out_sex